mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' into tsconfig_canonicalpath
This commit is contained in:
+55
-41
@@ -234,13 +234,17 @@ 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 and assignment declarations
|
||||
symbol.valueDeclaration = node;
|
||||
}
|
||||
setValueDeclaration(symbol, node);
|
||||
}
|
||||
}
|
||||
|
||||
function setValueDeclaration(symbol: Symbol, node: Declaration): void {
|
||||
const { valueDeclaration } = symbol;
|
||||
if (!valueDeclaration ||
|
||||
(isAssignmentDeclaration(valueDeclaration) && !isAssignmentDeclaration(node)) ||
|
||||
(valueDeclaration.kind !== node.kind && isEffectiveModuleDeclaration(valueDeclaration))) {
|
||||
// other kinds of value declarations take precedence over modules and assignment declarations
|
||||
symbol.valueDeclaration = node;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,7 +292,7 @@ namespace ts {
|
||||
// module.exports = ...
|
||||
return InternalSymbolName.ExportEquals;
|
||||
case SyntaxKind.BinaryExpression:
|
||||
if (getSpecialPropertyAssignmentKind(node as BinaryExpression) === SpecialPropertyAssignmentKind.ModuleExports) {
|
||||
if (getAssignmentDeclarationKind(node as BinaryExpression) === AssignmentDeclarationKind.ModuleExports) {
|
||||
// module.exports = ...
|
||||
return InternalSymbolName.ExportEquals;
|
||||
}
|
||||
@@ -374,8 +378,8 @@ namespace ts {
|
||||
// prototype symbols like methods.
|
||||
symbolTable.set(name, symbol = createSymbol(SymbolFlags.None, name));
|
||||
}
|
||||
else if (!(includes & SymbolFlags.Variable && symbol.flags & SymbolFlags.JSContainer)) {
|
||||
// JSContainers are allowed to merge with variables, no matter what other flags they have.
|
||||
else if (!(includes & SymbolFlags.Variable && symbol.flags & SymbolFlags.Assignment)) {
|
||||
// Assignment declarations are allowed to merge with variables, no matter what other flags they have.
|
||||
if (isNamedDeclaration(node)) {
|
||||
node.name.parent = node;
|
||||
}
|
||||
@@ -461,7 +465,7 @@ namespace ts {
|
||||
// during global merging in the checker. Why? The only case when ambient module is permitted inside another module is module augmentation
|
||||
// and this case is specially handled. Module augmentations should only be merged with original module definition
|
||||
// and should never be merged directly with other augmentation, and the latter case would be possible if automatic merge is allowed.
|
||||
if (isJSDocTypeAlias(node)) Debug.assert(isInJavaScriptFile(node)); // We shouldn't add symbols for JSDoc nodes if not in a JS file.
|
||||
if (isJSDocTypeAlias(node)) Debug.assert(isInJSFile(node)); // We shouldn't add symbols for JSDoc nodes if not in a JS file.
|
||||
if ((!isAmbientModule(node) && (hasExportModifier || container.flags & NodeFlags.ExportContext)) || isJSDocTypeAlias(node)) {
|
||||
if (hasModifier(node, ModifierFlags.Default) && !getDeclarationName(node)) {
|
||||
return declareSymbol(container.symbol.exports!, container.symbol, node, symbolFlags, symbolExcludes); // No local symbol for an unnamed default!
|
||||
@@ -735,6 +739,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;
|
||||
}
|
||||
@@ -2007,7 +2013,7 @@ namespace ts {
|
||||
|
||||
function bindJSDoc(node: Node) {
|
||||
if (hasJSDocNodes(node)) {
|
||||
if (isInJavaScriptFile(node)) {
|
||||
if (isInJSFile(node)) {
|
||||
for (const j of node.jsDoc!) {
|
||||
bind(j);
|
||||
}
|
||||
@@ -2073,7 +2079,7 @@ namespace ts {
|
||||
if (isSpecialPropertyDeclaration(node as PropertyAccessExpression)) {
|
||||
bindSpecialPropertyDeclaration(node as PropertyAccessExpression);
|
||||
}
|
||||
if (isInJavaScriptFile(node) &&
|
||||
if (isInJSFile(node) &&
|
||||
file.commonJsModuleIndicator &&
|
||||
isModuleExportsPropertyAccessExpression(node as PropertyAccessExpression) &&
|
||||
!lookupSymbolForNameWorker(blockScopeContainer, "module" as __String)) {
|
||||
@@ -2082,27 +2088,27 @@ namespace ts {
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.BinaryExpression:
|
||||
const specialKind = getSpecialPropertyAssignmentKind(node as BinaryExpression);
|
||||
const specialKind = getAssignmentDeclarationKind(node as BinaryExpression);
|
||||
switch (specialKind) {
|
||||
case SpecialPropertyAssignmentKind.ExportsProperty:
|
||||
case AssignmentDeclarationKind.ExportsProperty:
|
||||
bindExportsPropertyAssignment(node as BinaryExpression);
|
||||
break;
|
||||
case SpecialPropertyAssignmentKind.ModuleExports:
|
||||
case AssignmentDeclarationKind.ModuleExports:
|
||||
bindModuleExportsAssignment(node as BinaryExpression);
|
||||
break;
|
||||
case SpecialPropertyAssignmentKind.PrototypeProperty:
|
||||
case AssignmentDeclarationKind.PrototypeProperty:
|
||||
bindPrototypePropertyAssignment((node as BinaryExpression).left as PropertyAccessEntityNameExpression, node);
|
||||
break;
|
||||
case SpecialPropertyAssignmentKind.Prototype:
|
||||
case AssignmentDeclarationKind.Prototype:
|
||||
bindPrototypeAssignment(node as BinaryExpression);
|
||||
break;
|
||||
case SpecialPropertyAssignmentKind.ThisProperty:
|
||||
case AssignmentDeclarationKind.ThisProperty:
|
||||
bindThisPropertyAssignment(node as BinaryExpression);
|
||||
break;
|
||||
case SpecialPropertyAssignmentKind.Property:
|
||||
case AssignmentDeclarationKind.Property:
|
||||
bindSpecialPropertyAssignment(node as BinaryExpression);
|
||||
break;
|
||||
case SpecialPropertyAssignmentKind.None:
|
||||
case AssignmentDeclarationKind.None:
|
||||
// Nothing to do
|
||||
break;
|
||||
default:
|
||||
@@ -2182,7 +2188,7 @@ namespace ts {
|
||||
return bindFunctionExpression(<FunctionExpression>node);
|
||||
|
||||
case SyntaxKind.CallExpression:
|
||||
if (isInJavaScriptFile(node)) {
|
||||
if (isInJSFile(node)) {
|
||||
bindCallExpression(<CallExpression>node);
|
||||
}
|
||||
break;
|
||||
@@ -2284,14 +2290,19 @@ namespace ts {
|
||||
bindAnonymousDeclaration(node, SymbolFlags.Alias, getDeclarationName(node)!);
|
||||
}
|
||||
else {
|
||||
const flags = node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(node)
|
||||
const flags = exportAssignmentIsAlias(node)
|
||||
// An export default clause with an EntityNameExpression or a class expression exports all meanings of that identifier or expression;
|
||||
? SymbolFlags.Alias
|
||||
// An export default clause with any other expression exports a value
|
||||
: SymbolFlags.Property;
|
||||
// If there is an `export default x;` alias declaration, can't `export default` anything else.
|
||||
// (In contrast, you can still have `export default function f() {}` and `export default interface I {}`.)
|
||||
declareSymbol(container.symbol.exports, container.symbol, node, flags, SymbolFlags.All);
|
||||
const symbol = declareSymbol(container.symbol.exports, container.symbol, node, flags, SymbolFlags.All);
|
||||
|
||||
if (node.isExportEquals) {
|
||||
// Will be an error later, since the module already has other exports. Just make sure this has a valueDeclaration set.
|
||||
setValueDeclaration(symbol, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2359,7 +2370,7 @@ namespace ts {
|
||||
const lhs = node.left as PropertyAccessEntityNameExpression;
|
||||
const symbol = forEachIdentifierInEntityName(lhs.expression, /*parent*/ undefined, (id, symbol) => {
|
||||
if (symbol) {
|
||||
addDeclarationToSymbol(symbol, id, SymbolFlags.Module | SymbolFlags.JSContainer);
|
||||
addDeclarationToSymbol(symbol, id, SymbolFlags.Module | SymbolFlags.Assignment);
|
||||
}
|
||||
return symbol;
|
||||
});
|
||||
@@ -2392,7 +2403,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function bindThisPropertyAssignment(node: BinaryExpression | PropertyAccessExpression) {
|
||||
Debug.assert(isInJavaScriptFile(node));
|
||||
Debug.assert(isInJSFile(node));
|
||||
const thisContainer = getThisContainer(node, /*includeArrowFunctions*/ false);
|
||||
switch (thisContainer.kind) {
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
@@ -2480,7 +2491,7 @@ namespace ts {
|
||||
const lhs = node.left as PropertyAccessEntityNameExpression;
|
||||
// Class declarations in Typescript do not allow property declarations
|
||||
const parentSymbol = lookupSymbolForPropertyAccess(lhs.expression);
|
||||
if (!isInJavaScriptFile(node) && !isFunctionSymbol(parentSymbol)) {
|
||||
if (!isInJSFile(node) && !isFunctionSymbol(parentSymbol)) {
|
||||
return;
|
||||
}
|
||||
// Fix up parent pointers since we're going to use these nodes before we bind into them
|
||||
@@ -2513,19 +2524,21 @@ namespace ts {
|
||||
: propertyAccess.parent.parent.kind === SyntaxKind.SourceFile;
|
||||
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;
|
||||
const flags = SymbolFlags.Module | SymbolFlags.Assignment;
|
||||
const excludeFlags = SymbolFlags.ValueModuleExcludes & ~SymbolFlags.Assignment;
|
||||
namespaceSymbol = forEachIdentifierInEntityName(propertyAccess.expression, namespaceSymbol, (id, symbol, parent) => {
|
||||
if (symbol) {
|
||||
addDeclarationToSymbol(symbol, id, flags);
|
||||
return symbol;
|
||||
}
|
||||
else {
|
||||
return declareSymbol(parent ? parent.exports! : container.locals!, parent, id, flags, excludeFlags);
|
||||
const table = parent ? parent.exports! :
|
||||
file.jsGlobalAugmentations || (file.jsGlobalAugmentations = createSymbolTable());
|
||||
return declareSymbol(table, parent, id, flags, excludeFlags);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!namespaceSymbol || !isJavascriptContainer(namespaceSymbol)) {
|
||||
if (!namespaceSymbol || !isExpandoSymbol(namespaceSymbol)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2534,14 +2547,14 @@ namespace ts {
|
||||
(namespaceSymbol.members || (namespaceSymbol.members = createSymbolTable())) :
|
||||
(namespaceSymbol.exports || (namespaceSymbol.exports = createSymbolTable()));
|
||||
|
||||
const isMethod = isFunctionLikeDeclaration(getAssignedJavascriptInitializer(propertyAccess)!);
|
||||
const isMethod = isFunctionLikeDeclaration(getAssignedExpandoInitializer(propertyAccess)!);
|
||||
const includes = isMethod ? SymbolFlags.Method : SymbolFlags.Property;
|
||||
const excludes = isMethod ? SymbolFlags.MethodExcludes : SymbolFlags.PropertyExcludes;
|
||||
declareSymbol(symbolTable, namespaceSymbol, propertyAccess, includes | SymbolFlags.JSContainer, excludes & ~SymbolFlags.JSContainer);
|
||||
declareSymbol(symbolTable, namespaceSymbol, propertyAccess, includes | SymbolFlags.Assignment, excludes & ~SymbolFlags.Assignment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Javascript containers are:
|
||||
* Javascript expando values are:
|
||||
* - Functions
|
||||
* - classes
|
||||
* - namespaces
|
||||
@@ -2550,7 +2563,7 @@ namespace ts {
|
||||
* - with empty object literals
|
||||
* - with non-empty object literals if assigned to the prototype property
|
||||
*/
|
||||
function isJavascriptContainer(symbol: Symbol): boolean {
|
||||
function isExpandoSymbol(symbol: Symbol): boolean {
|
||||
if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Class | SymbolFlags.NamespaceModule)) {
|
||||
return true;
|
||||
}
|
||||
@@ -2563,7 +2576,7 @@ namespace ts {
|
||||
init = init && getRightMostAssignedExpression(init);
|
||||
if (init) {
|
||||
const isPrototypeAssignment = isPrototypeAccess(isVariableDeclaration(node) ? node.name : isBinaryExpression(node) ? node.left : node);
|
||||
return !!getJavascriptInitializer(isBinaryExpression(init) && init.operatorToken.kind === SyntaxKind.BarBarToken ? init.right : init, isPrototypeAssignment);
|
||||
return !!getExpandoInitializer(isBinaryExpression(init) && init.operatorToken.kind === SyntaxKind.BarBarToken ? init.right : init, isPrototypeAssignment);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -2655,7 +2668,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (!isBindingPattern(node.name)) {
|
||||
const isEnum = !!getJSDocEnumTag(node);
|
||||
const isEnum = isInJSFile(node) && !!getJSDocEnumTag(node);
|
||||
const enumFlags = (isEnum ? SymbolFlags.RegularEnum : SymbolFlags.None);
|
||||
const enumExcludes = (isEnum ? SymbolFlags.RegularEnumExcludes : SymbolFlags.None);
|
||||
if (isBlockOrCatchScoped(node)) {
|
||||
@@ -2802,9 +2815,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;
|
||||
@@ -2849,7 +2860,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));
|
||||
}
|
||||
@@ -2892,6 +2903,9 @@ namespace ts {
|
||||
if (local) {
|
||||
return local.exportSymbol || local;
|
||||
}
|
||||
if (isSourceFile(container) && container.jsGlobalAugmentations && container.jsGlobalAugmentations.has(name)) {
|
||||
return container.jsGlobalAugmentations.get(name);
|
||||
}
|
||||
return container.symbol && container.symbol.exports && container.symbol.exports.get(name);
|
||||
}
|
||||
|
||||
|
||||
+18
-11
@@ -294,7 +294,7 @@ namespace ts {
|
||||
configFileParsingDiagnostics: ReadonlyArray<Diagnostic>;
|
||||
}
|
||||
|
||||
export function getBuilderCreationParameters(newProgramOrRootNames: Program | ReadonlyArray<string> | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: BuilderProgram | CompilerHost, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray<Diagnostic> | BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): BuilderCreationParameters {
|
||||
export function getBuilderCreationParameters(newProgramOrRootNames: Program | ReadonlyArray<string> | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: BuilderProgram | CompilerHost, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray<Diagnostic> | BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference>): BuilderCreationParameters {
|
||||
let host: BuilderProgramHost;
|
||||
let newProgram: Program;
|
||||
let oldProgram: BuilderProgram;
|
||||
@@ -307,7 +307,14 @@ namespace ts {
|
||||
}
|
||||
else if (isArray(newProgramOrRootNames)) {
|
||||
oldProgram = configFileParsingDiagnosticsOrOldProgram as BuilderProgram;
|
||||
newProgram = createProgram(newProgramOrRootNames, hostOrOptions as CompilerOptions, oldProgramOrHost as CompilerHost, oldProgram && oldProgram.getProgram(), configFileParsingDiagnostics);
|
||||
newProgram = createProgram({
|
||||
rootNames: newProgramOrRootNames,
|
||||
options: hostOrOptions as CompilerOptions,
|
||||
host: oldProgramOrHost as CompilerHost,
|
||||
oldProgram: oldProgram && oldProgram.getProgram(),
|
||||
configFileParsingDiagnostics,
|
||||
projectReferences
|
||||
});
|
||||
host = oldProgramOrHost as CompilerHost;
|
||||
}
|
||||
else {
|
||||
@@ -623,9 +630,9 @@ namespace ts {
|
||||
* Create the builder to manage semantic diagnostics and cache them
|
||||
*/
|
||||
export function createSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): SemanticDiagnosticsBuilderProgram;
|
||||
export function createSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): SemanticDiagnosticsBuilderProgram;
|
||||
export function createSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | ReadonlyArray<string> | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | SemanticDiagnosticsBuilderProgram, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray<Diagnostic> | SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) {
|
||||
return createBuilderProgram(BuilderProgramKind.SemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics));
|
||||
export function createSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference>): SemanticDiagnosticsBuilderProgram;
|
||||
export function createSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | ReadonlyArray<string> | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | SemanticDiagnosticsBuilderProgram, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray<Diagnostic> | SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference>) {
|
||||
return createBuilderProgram(BuilderProgramKind.SemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics, projectReferences));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -633,18 +640,18 @@ namespace ts {
|
||||
* to emit the those files and manage semantic diagnostics cache as well
|
||||
*/
|
||||
export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): EmitAndSemanticDiagnosticsBuilderProgram;
|
||||
export function createEmitAndSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): EmitAndSemanticDiagnosticsBuilderProgram;
|
||||
export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | ReadonlyArray<string> | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray<Diagnostic> | EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) {
|
||||
return createBuilderProgram(BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics));
|
||||
export function createEmitAndSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference>): EmitAndSemanticDiagnosticsBuilderProgram;
|
||||
export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | ReadonlyArray<string> | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray<Diagnostic> | EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference>) {
|
||||
return createBuilderProgram(BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics, projectReferences));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a builder thats just abstraction over program and can be used with watch
|
||||
*/
|
||||
export function createAbstractBuilder(newProgram: Program, host: BuilderProgramHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): BuilderProgram;
|
||||
export function createAbstractBuilder(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): BuilderProgram;
|
||||
export function createAbstractBuilder(newProgramOrRootNames: Program | ReadonlyArray<string> | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | BuilderProgram, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray<Diagnostic> | BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): BuilderProgram {
|
||||
const { newProgram: program } = getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics);
|
||||
export function createAbstractBuilder(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference>): BuilderProgram;
|
||||
export function createAbstractBuilder(newProgramOrRootNames: Program | ReadonlyArray<string> | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | BuilderProgram, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray<Diagnostic> | BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference>): BuilderProgram {
|
||||
const { newProgram: program } = getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics, projectReferences);
|
||||
return {
|
||||
// Only return program, all other methods are not implemented
|
||||
getProgram: () => program,
|
||||
|
||||
+690
-325
File diff suppressed because it is too large
Load Diff
@@ -62,7 +62,8 @@ namespace ts {
|
||||
/* @internal */
|
||||
export const libMap = createMapFromEntries(libEntries);
|
||||
|
||||
const commonOptionsWithBuild: CommandLineOption[] = [
|
||||
/* @internal */
|
||||
export const commonOptionsWithBuild: CommandLineOption[] = [
|
||||
{
|
||||
name: "help",
|
||||
shortName: "h",
|
||||
@@ -83,6 +84,18 @@ namespace ts {
|
||||
category: Diagnostics.Command_line_Options,
|
||||
description: Diagnostics.Whether_to_keep_outdated_console_output_in_watch_mode_instead_of_clearing_the_screen,
|
||||
},
|
||||
{
|
||||
name: "listFiles",
|
||||
type: "boolean",
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.Print_names_of_files_part_of_the_compilation
|
||||
},
|
||||
{
|
||||
name: "listEmittedFiles",
|
||||
type: "boolean",
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.Print_names_of_generated_files_part_of_the_compilation
|
||||
},
|
||||
{
|
||||
name: "watch",
|
||||
shortName: "w",
|
||||
@@ -561,18 +574,6 @@ namespace ts {
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.Include_modules_imported_with_json_extension
|
||||
},
|
||||
{
|
||||
name: "listFiles",
|
||||
type: "boolean",
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.Print_names_of_files_part_of_the_compilation
|
||||
},
|
||||
{
|
||||
name: "listEmittedFiles",
|
||||
type: "boolean",
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.Print_names_of_generated_files_part_of_the_compilation
|
||||
},
|
||||
|
||||
{
|
||||
name: "out",
|
||||
@@ -903,17 +904,27 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
export function parseCommandLine(commandLine: ReadonlyArray<string>, readFile?: (path: string) => string | undefined): ParsedCommandLine {
|
||||
const options: CompilerOptions = {};
|
||||
/* @internal */
|
||||
export interface OptionsBase {
|
||||
[option: string]: CompilerOptionsValue | undefined;
|
||||
}
|
||||
|
||||
/** Tuple with error messages for 'unknown compiler option', 'option requires type' */
|
||||
type ParseCommandLineWorkerDiagnostics = [DiagnosticMessage, DiagnosticMessage];
|
||||
|
||||
function parseCommandLineWorker(
|
||||
getOptionNameMap: () => OptionNameMap,
|
||||
[unknownOptionDiagnostic, optionTypeMismatchDiagnostic]: ParseCommandLineWorkerDiagnostics,
|
||||
commandLine: ReadonlyArray<string>,
|
||||
readFile?: (path: string) => string | undefined) {
|
||||
const options = {} as OptionsBase;
|
||||
const fileNames: string[] = [];
|
||||
const projectReferences: ProjectReference[] | undefined = undefined;
|
||||
const errors: Diagnostic[] = [];
|
||||
|
||||
parseStrings(commandLine);
|
||||
return {
|
||||
options,
|
||||
fileNames,
|
||||
projectReferences,
|
||||
errors
|
||||
};
|
||||
|
||||
@@ -926,7 +937,7 @@ namespace ts {
|
||||
parseResponseFile(s.slice(1));
|
||||
}
|
||||
else if (s.charCodeAt(0) === CharacterCodes.minus) {
|
||||
const opt = getOptionFromName(s.slice(s.charCodeAt(1) === CharacterCodes.minus ? 2 : 1), /*allowShort*/ true);
|
||||
const opt = getOptionDeclarationFromName(getOptionNameMap, s.slice(s.charCodeAt(1) === CharacterCodes.minus ? 2 : 1), /*allowShort*/ true);
|
||||
if (opt) {
|
||||
if (opt.isTSConfigOnly) {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Option_0_can_only_be_specified_in_tsconfig_json_file, opt.name));
|
||||
@@ -934,7 +945,7 @@ namespace ts {
|
||||
else {
|
||||
// Check to see if no argument was provided (e.g. "--locale" is the last command-line argument).
|
||||
if (!args[i] && opt.type !== "boolean") {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_expects_an_argument, opt.name));
|
||||
errors.push(createCompilerDiagnostic(optionTypeMismatchDiagnostic, opt.name));
|
||||
}
|
||||
|
||||
switch (opt.type) {
|
||||
@@ -971,7 +982,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
else {
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Unknown_compiler_option_0, s));
|
||||
errors.push(createCompilerDiagnostic(unknownOptionDiagnostic, s));
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1014,13 +1025,19 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
export function parseCommandLine(commandLine: ReadonlyArray<string>, readFile?: (path: string) => string | undefined): ParsedCommandLine {
|
||||
return parseCommandLineWorker(getOptionNameMap, [
|
||||
Diagnostics.Unknown_compiler_option_0,
|
||||
Diagnostics.Compiler_option_0_expects_an_argument
|
||||
], commandLine, readFile);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
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 {
|
||||
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.
|
||||
@@ -1044,25 +1061,11 @@ namespace ts {
|
||||
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);
|
||||
}
|
||||
}
|
||||
const { options, fileNames: projects, errors } = parseCommandLineWorker(returnBuildOptionNameMap, [
|
||||
Diagnostics.Unknown_build_option_0,
|
||||
Diagnostics.Build_option_0_requires_a_value_of_type_1
|
||||
], args);
|
||||
const buildOptions = options as BuildOptions;
|
||||
|
||||
if (projects.length === 0) {
|
||||
// tsc -b invoked with no extra arguments; act as if invoked with "tsc -b ."
|
||||
@@ -1071,19 +1074,19 @@ namespace ts {
|
||||
|
||||
// Nonsensical combinations
|
||||
if (buildOptions.clean && buildOptions.force) {
|
||||
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "force"));
|
||||
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"));
|
||||
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"));
|
||||
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"));
|
||||
errors.push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "watch", "dry"));
|
||||
}
|
||||
|
||||
return { buildOptions, projects, errors: errors || emptyArray };
|
||||
return { buildOptions, projects, errors };
|
||||
}
|
||||
|
||||
function getDiagnosticText(_message: DiagnosticMessage, ..._args: any[]): string {
|
||||
@@ -1825,7 +1828,8 @@ namespace ts {
|
||||
const options = extend(existingOptions, parsedConfig.options || {});
|
||||
options.configFilePath = configFileName && normalizeSlashes(configFileName);
|
||||
setConfigFileInOptions(options, sourceFile);
|
||||
const { fileNames, wildcardDirectories, spec, projectReferences } = getFileNames();
|
||||
let projectReferences: ProjectReference[] | undefined;
|
||||
const { fileNames, wildcardDirectories, spec } = getFileNames();
|
||||
return {
|
||||
options,
|
||||
fileNames,
|
||||
@@ -1843,8 +1847,21 @@ namespace ts {
|
||||
if (hasProperty(raw, "files") && !isNullOrUndefined(raw.files)) {
|
||||
if (isArray(raw.files)) {
|
||||
filesSpecs = <ReadonlyArray<string>>raw.files;
|
||||
if (filesSpecs.length === 0) {
|
||||
createCompilerDiagnosticOnlyIfJson(Diagnostics.The_files_list_in_config_file_0_is_empty, configFileName || "tsconfig.json");
|
||||
const hasReferences = hasProperty(raw, "references") && !isNullOrUndefined(raw.references);
|
||||
const hasZeroOrNoReferences = !hasReferences || raw.references.length === 0;
|
||||
if (filesSpecs.length === 0 && hasZeroOrNoReferences) {
|
||||
if (sourceFile) {
|
||||
const fileName = configFileName || "tsconfig.json";
|
||||
const diagnosticMessage = Diagnostics.The_files_list_in_config_file_0_is_empty;
|
||||
const nodeValue = firstDefined(getTsConfigPropArray(sourceFile, "files"), property => property.initializer);
|
||||
const error = nodeValue
|
||||
? createDiagnosticForNodeInSourceFile(sourceFile, nodeValue, diagnosticMessage, fileName)
|
||||
: createCompilerDiagnostic(diagnosticMessage, fileName);
|
||||
errors.push(error);
|
||||
}
|
||||
else {
|
||||
createCompilerDiagnosticOnlyIfJson(Diagnostics.The_files_list_in_config_file_0_is_empty, configFileName || "tsconfig.json");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -1891,13 +1908,12 @@ namespace ts {
|
||||
|
||||
if (hasProperty(raw, "references") && !isNullOrUndefined(raw.references)) {
|
||||
if (isArray(raw.references)) {
|
||||
const references: ProjectReference[] = [];
|
||||
for (const ref of raw.references) {
|
||||
if (typeof ref.path !== "string") {
|
||||
createCompilerDiagnosticOnlyIfJson(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "reference.path", "string");
|
||||
}
|
||||
else {
|
||||
references.push({
|
||||
(projectReferences || (projectReferences = [])).push({
|
||||
path: getNormalizedAbsolutePath(ref.path, basePath),
|
||||
originalPath: ref.path,
|
||||
prepend: ref.prepend,
|
||||
@@ -1905,7 +1921,6 @@ namespace ts {
|
||||
});
|
||||
}
|
||||
}
|
||||
result.projectReferences = references;
|
||||
}
|
||||
else {
|
||||
createCompilerDiagnosticOnlyIfJson(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "references", "Array");
|
||||
@@ -2067,11 +2082,6 @@ namespace ts {
|
||||
createDiagnosticForNodeInSourceFile(sourceFile, valueNode, message, arg0)
|
||||
);
|
||||
return;
|
||||
case "files":
|
||||
if ((<ReadonlyArray<string>>value).length === 0) {
|
||||
errors.push(createDiagnosticForNodeInSourceFile(sourceFile, valueNode, Diagnostics.The_files_list_in_config_file_0_is_empty, configFileName || "tsconfig.json"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
},
|
||||
onSetUnknownOptionKeyValueInRoot(key: string, keyNode: PropertyName, _value: CompilerOptionsValue, _valueNode: Expression) {
|
||||
@@ -2081,6 +2091,7 @@ namespace ts {
|
||||
}
|
||||
};
|
||||
const json = convertToObjectWorker(sourceFile, errors, /*returnValue*/ true, getTsconfigRootOptionsMap(), optionsIterator);
|
||||
|
||||
if (!typeAcquisition) {
|
||||
if (typingOptionstypeAcquisition) {
|
||||
typeAcquisition = (typingOptionstypeAcquisition.enableAutoDiscovery !== undefined) ?
|
||||
@@ -2398,7 +2409,7 @@ namespace ts {
|
||||
// new entries in these paths.
|
||||
const wildcardDirectories = getWildcardDirectories(validatedIncludeSpecs, validatedExcludeSpecs, basePath, host.useCaseSensitiveFileNames);
|
||||
|
||||
const spec: ConfigFileSpecs = { filesSpecs, referencesSpecs: undefined, includeSpecs, excludeSpecs, validatedIncludeSpecs, validatedExcludeSpecs, wildcardDirectories };
|
||||
const spec: ConfigFileSpecs = { filesSpecs, includeSpecs, excludeSpecs, validatedIncludeSpecs, validatedExcludeSpecs, wildcardDirectories };
|
||||
return getFileNamesFromConfigSpecs(spec, basePath, options, host, extraFileExtensions);
|
||||
}
|
||||
|
||||
@@ -2469,16 +2480,9 @@ namespace ts {
|
||||
|
||||
const literalFiles = arrayFrom(literalFileMap.values());
|
||||
const wildcardFiles = arrayFrom(wildcardFileMap.values());
|
||||
const projectReferences = spec.referencesSpecs && spec.referencesSpecs.map((r): ProjectReference => {
|
||||
return {
|
||||
...r,
|
||||
path: getNormalizedAbsolutePath(r.path, basePath)
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
fileNames: literalFiles.concat(wildcardFiles),
|
||||
projectReferences,
|
||||
wildcardDirectories,
|
||||
spec
|
||||
};
|
||||
|
||||
@@ -65,6 +65,7 @@ namespace ts {
|
||||
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export const emptyArray: never[] = [] as never[];
|
||||
|
||||
/** Create a MapLike with good performance. */
|
||||
function createDictionaryObject<T>(): MapLike<T> {
|
||||
@@ -789,11 +790,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 +800,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];
|
||||
|
||||
@@ -835,7 +835,7 @@
|
||||
"category": "Error",
|
||||
"code": 1253
|
||||
},
|
||||
"A 'const' initializer in an ambient context must be a string or numeric literal.": {
|
||||
"A 'const' initializer in an ambient context must be a string or numeric literal or literal enum reference.": {
|
||||
"category": "Error",
|
||||
"code": 1254
|
||||
},
|
||||
@@ -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",
|
||||
@@ -2072,6 +2088,30 @@
|
||||
"category": "Error",
|
||||
"code": 2577
|
||||
},
|
||||
"Cannot find name '{0}'. Do you need to install type definitions for node? Try `npm i @types/node`.": {
|
||||
"category": "Error",
|
||||
"code": 2580
|
||||
},
|
||||
"Cannot find name '{0}'. Do you need to install type definitions for jQuery? Try `npm i @types/jquery`.": {
|
||||
"category": "Error",
|
||||
"code": 2581
|
||||
},
|
||||
"Cannot find name '{0}'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha`.": {
|
||||
"category": "Error",
|
||||
"code": 2582
|
||||
},
|
||||
"Cannot find name '{0}'. Do you need to change your target library? Try changing the `lib` compiler option to es2015 or later.": {
|
||||
"category": "Error",
|
||||
"code": 2583
|
||||
},
|
||||
"Cannot find name '{0}'. Do you need to change your target library? Try changing the `lib` compiler option to include 'dom'.": {
|
||||
"category": "Error",
|
||||
"code": 2584
|
||||
},
|
||||
"'{0}' only refers to a type, but is being used as a value here. Do you need to change your target library? Try changing the `lib` compiler option to es2015 or later.": {
|
||||
"category": "Error",
|
||||
"code": 2585
|
||||
},
|
||||
"JSX element attributes type '{0}' may not be a union type.": {
|
||||
"category": "Error",
|
||||
"code": 2600
|
||||
@@ -2437,6 +2477,14 @@
|
||||
"category": "Error",
|
||||
"code": 2732
|
||||
},
|
||||
"Index '{0}' is out-of-bounds in tuple of length {1}.": {
|
||||
"category": "Error",
|
||||
"code": 2733
|
||||
},
|
||||
"It is highly likely that you are missing a semicolon.": {
|
||||
"category": "Error",
|
||||
"code": 2734
|
||||
},
|
||||
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
@@ -2892,7 +2940,7 @@
|
||||
"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
|
||||
},
|
||||
@@ -2900,7 +2948,10 @@
|
||||
"category": "Error",
|
||||
"code": 5072
|
||||
},
|
||||
|
||||
"Build option '{0}' requires a value of type {1}.": {
|
||||
"category": "Error",
|
||||
"code": 5073
|
||||
},
|
||||
|
||||
"Generates a sourcemap for each corresponding '.d.ts' file.": {
|
||||
"category": "Message",
|
||||
@@ -3274,7 +3325,7 @@
|
||||
"category": "Message",
|
||||
"code": 6104
|
||||
},
|
||||
"Expected type of '{0}' field in 'package.json' to be 'string', got '{1}'.": {
|
||||
"Expected type of '{0}' field in 'package.json' to be '{1}', got '{2}'.": {
|
||||
"category": "Message",
|
||||
"code": 6105
|
||||
},
|
||||
@@ -3672,6 +3723,38 @@
|
||||
"category": "Error",
|
||||
"code": 6205
|
||||
},
|
||||
"'package.json' has a 'typesVersions' field with version-specific path mappings.": {
|
||||
"category": "Message",
|
||||
"code": 6206
|
||||
},
|
||||
"'package.json' does not have a 'typesVersions' entry that matches version '{0}'.": {
|
||||
"category": "Message",
|
||||
"code": 6207
|
||||
},
|
||||
"'package.json' has a 'typesVersions' entry '{0}' that matches compiler version '{1}', looking for a pattern to match module name '{2}'.": {
|
||||
"category": "Message",
|
||||
"code": 6208
|
||||
},
|
||||
"'package.json' has a 'typesVersions' entry '{0}' that is not a valid semver range.": {
|
||||
"category": "Message",
|
||||
"code": 6209
|
||||
},
|
||||
"An argument for '{0}' was not provided.": {
|
||||
"category": "Message",
|
||||
"code": 6210
|
||||
},
|
||||
"An argument matching this binding pattern was not provided.": {
|
||||
"category": "Message",
|
||||
"code": 6211
|
||||
},
|
||||
"Did you mean to call this expression?": {
|
||||
"category": "Message",
|
||||
"code": 6212
|
||||
},
|
||||
"Did you mean to use 'new' with this expression?": {
|
||||
"category": "Message",
|
||||
"code": 6213
|
||||
},
|
||||
|
||||
"Projects to reference": {
|
||||
"category": "Message",
|
||||
@@ -3794,10 +3877,6 @@
|
||||
"category": "Error",
|
||||
"code": 6370
|
||||
},
|
||||
"Skipping clean because not all projects could be located": {
|
||||
"category": "Error",
|
||||
"code": 6371
|
||||
},
|
||||
|
||||
"The expected type comes from property '{0}' which is declared here on type '{1}'": {
|
||||
"category": "Message",
|
||||
@@ -4564,7 +4643,7 @@
|
||||
"category": "Message",
|
||||
"code": 95062
|
||||
},
|
||||
|
||||
|
||||
"Add missing enum member '{0}'": {
|
||||
"category": "Message",
|
||||
"code": 95063
|
||||
@@ -4573,12 +4652,12 @@
|
||||
"category": "Message",
|
||||
"code": 95064
|
||||
},
|
||||
"Convert to async function":{
|
||||
"Convert to async function": {
|
||||
"category": "Message",
|
||||
"code": 95065
|
||||
"code": 95065
|
||||
},
|
||||
"Convert all to async functions": {
|
||||
"category": "Message",
|
||||
"code": 95066
|
||||
"category": "Message",
|
||||
"code": 95066
|
||||
}
|
||||
}
|
||||
|
||||
+11
-8
@@ -52,7 +52,7 @@ namespace ts {
|
||||
const jsFilePath = getOwnEmitOutputFilePath(sourceFile.fileName, host, getOutputExtension(sourceFile, options));
|
||||
const sourceMapFilePath = isJsonSourceFile(sourceFile) ? undefined : getSourceMapFilePath(jsFilePath, options);
|
||||
// For legacy reasons (ie, we have baselines capturing the behavior), js files don't report a .d.ts output path - this would only matter if `declaration` and `allowJs` were both on, which is currently an error
|
||||
const isJs = isSourceFileJavaScript(sourceFile);
|
||||
const isJs = isSourceFileJS(sourceFile);
|
||||
const declarationFilePath = ((forceDtsPaths || getEmitDeclarations(options)) && !isJs) ? getDeclarationEmitOutputFilePath(sourceFile.fileName, host) : undefined;
|
||||
const declarationMapPath = getAreDeclarationMapsEnabled(options) ? declarationFilePath + ".map" : undefined;
|
||||
return { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, bundleInfoPath: undefined };
|
||||
@@ -80,7 +80,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (options.jsx === JsxEmit.Preserve) {
|
||||
if (isSourceFileJavaScript(sourceFile)) {
|
||||
if (isSourceFileJS(sourceFile)) {
|
||||
if (fileExtensionIs(sourceFile.fileName, Extension.Jsx)) {
|
||||
return Extension.Jsx;
|
||||
}
|
||||
@@ -187,12 +187,12 @@ namespace ts {
|
||||
}
|
||||
|
||||
function emitDeclarationFileOrBundle(sourceFileOrBundle: SourceFile | Bundle, declarationFilePath: string | undefined, declarationMapPath: string | undefined) {
|
||||
if (!(declarationFilePath && !isInJavaScriptFile(sourceFileOrBundle))) {
|
||||
if (!(declarationFilePath && !isInJSFile(sourceFileOrBundle))) {
|
||||
return;
|
||||
}
|
||||
const sourceFiles = isSourceFile(sourceFileOrBundle) ? [sourceFileOrBundle] : sourceFileOrBundle.sourceFiles;
|
||||
// Setup and perform the transformation to retrieve declarations from the input files
|
||||
const nonJsFiles = filter(sourceFiles, isSourceFileNotJavaScript);
|
||||
const nonJsFiles = filter(sourceFiles, isSourceFileNotJS);
|
||||
const inputListOrBundle = (compilerOptions.outFile || compilerOptions.out) ? [createBundle(nonJsFiles, !isSourceFile(sourceFileOrBundle) ? sourceFileOrBundle.prepends : undefined)] : nonJsFiles;
|
||||
if (emitOnlyDtsFiles && !getEmitDeclarations(compilerOptions)) {
|
||||
// Checker wont collect the linked aliases since thats only done when declaration is enabled.
|
||||
@@ -1015,7 +1015,7 @@ namespace ts {
|
||||
writeLines(helper.text);
|
||||
}
|
||||
else {
|
||||
writeLines(helper.text(makeFileLevelOptmiisticUniqueName));
|
||||
writeLines(helper.text(makeFileLevelOptimisticUniqueName));
|
||||
}
|
||||
helpersEmitted = true;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -2816,7 +2818,8 @@ namespace ts {
|
||||
const parameter = singleOrUndefined(parameters);
|
||||
return parameter
|
||||
&& parameter.pos === parentNode.pos // may not have parsed tokens between parent and parameter
|
||||
&& !(isArrowFunction(parentNode) && parentNode.type) // arrow function may not have return type annotation
|
||||
&& isArrowFunction(parentNode) // only arrow functions may have simple arrow head
|
||||
&& !parentNode.type // arrow function may not have return type annotation
|
||||
&& !some(parentNode.decorators) // parent may not have decorators
|
||||
&& !some(parentNode.modifiers) // parent may not have modifiers
|
||||
&& !some(parentNode.typeParameters) // parent may not have type parameters
|
||||
@@ -3585,7 +3588,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function makeFileLevelOptmiisticUniqueName(name: string) {
|
||||
function makeFileLevelOptimisticUniqueName(name: string) {
|
||||
return makeUniqueName(name, isFileLevelUniqueName, /*optimistic*/ true);
|
||||
}
|
||||
|
||||
|
||||
+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(
|
||||
|
||||
+333
-225
@@ -24,6 +24,13 @@ namespace ts {
|
||||
return withPackageId(/*packageId*/ undefined, r);
|
||||
}
|
||||
|
||||
function removeIgnoredPackageId(r: Resolved | undefined): PathAndExtension | undefined {
|
||||
if (r) {
|
||||
Debug.assert(r.packageId === undefined);
|
||||
return { path: r.path, ext: r.extension };
|
||||
}
|
||||
}
|
||||
|
||||
/** Result of trying to resolve a module. */
|
||||
interface Resolved {
|
||||
path: string;
|
||||
@@ -67,7 +74,7 @@ namespace ts {
|
||||
if (!resolved) {
|
||||
return undefined;
|
||||
}
|
||||
Debug.assert(extensionIsTypeScript(resolved.extension));
|
||||
Debug.assert(extensionIsTS(resolved.extension));
|
||||
return { fileName: resolved.path, packageId: resolved.packageId };
|
||||
}
|
||||
|
||||
@@ -82,12 +89,14 @@ namespace ts {
|
||||
host: ModuleResolutionHost;
|
||||
compilerOptions: CompilerOptions;
|
||||
traceEnabled: boolean;
|
||||
failedLookupLocations: Push<string>;
|
||||
}
|
||||
|
||||
/** Just the fields that we use for module resolution. */
|
||||
interface PackageJsonPathFields {
|
||||
typings?: string;
|
||||
types?: string;
|
||||
typesVersions?: MapLike<MapLike<string[]>>;
|
||||
main?: string;
|
||||
}
|
||||
|
||||
@@ -96,48 +105,111 @@ namespace ts {
|
||||
version?: string;
|
||||
}
|
||||
|
||||
/** Reads from "main" or "types"/"typings" depending on `extensions`. */
|
||||
function tryReadPackageJsonFields(readTypes: boolean, jsonContent: PackageJsonPathFields, baseDirectory: string, state: ModuleResolutionState): string | undefined {
|
||||
return readTypes ? tryReadFromField("typings") || tryReadFromField("types") : tryReadFromField("main");
|
||||
type MatchingKeys<TRecord, TMatch, K extends keyof TRecord = keyof TRecord> = K extends (TRecord[K] extends TMatch ? K : never) ? K : never;
|
||||
|
||||
function tryReadFromField(fieldName: "typings" | "types" | "main"): string | undefined {
|
||||
if (!hasProperty(jsonContent, fieldName)) {
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.package_json_does_not_have_a_0_field, fieldName);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const fileName = jsonContent[fieldName];
|
||||
if (!isString(fileName)) {
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_string_got_1, fieldName, typeof fileName);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const path = normalizePath(combinePaths(baseDirectory, fileName));
|
||||
function readPackageJsonField<TMatch, K extends MatchingKeys<PackageJson, string | undefined>>(jsonContent: PackageJson, fieldName: K, typeOfTag: "string", state: ModuleResolutionState): PackageJson[K] | undefined;
|
||||
function readPackageJsonField<K extends MatchingKeys<PackageJson, object | undefined>>(jsonContent: PackageJson, fieldName: K, typeOfTag: "object", state: ModuleResolutionState): PackageJson[K] | undefined;
|
||||
function readPackageJsonField<K extends keyof PackageJson>(jsonContent: PackageJson, fieldName: K, typeOfTag: "string" | "object", state: ModuleResolutionState): PackageJson[K] | undefined {
|
||||
if (!hasProperty(jsonContent, fieldName)) {
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.package_json_has_0_field_1_that_references_2, fieldName, fileName, path);
|
||||
trace(state.host, Diagnostics.package_json_does_not_have_a_0_field, fieldName);
|
||||
}
|
||||
return path;
|
||||
return;
|
||||
}
|
||||
const value = jsonContent[fieldName];
|
||||
if (typeof value !== typeOfTag || value === null) {
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_1_got_2, fieldName, typeOfTag, value === null ? "null" : typeof value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function readJson(path: string, host: { readFile(fileName: string): string | undefined }): object {
|
||||
try {
|
||||
const jsonText = host.readFile(path);
|
||||
if (!jsonText) return {};
|
||||
const result = parseConfigFileTextToJson(path, jsonText);
|
||||
if (result.error) {
|
||||
return {};
|
||||
}
|
||||
return result.config;
|
||||
function readPackageJsonPathField<K extends "typings" | "types" | "main">(jsonContent: PackageJson, fieldName: K, baseDirectory: string, state: ModuleResolutionState): PackageJson[K] | undefined {
|
||||
const fileName = readPackageJsonField(jsonContent, fieldName, "string", state);
|
||||
if (fileName === undefined) return;
|
||||
const path = normalizePath(combinePaths(baseDirectory, fileName));
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.package_json_has_0_field_1_that_references_2, fieldName, fileName, path);
|
||||
}
|
||||
catch (e) {
|
||||
// gracefully handle if readFile fails or returns not JSON
|
||||
return {};
|
||||
return path;
|
||||
}
|
||||
|
||||
function readPackageJsonTypesFields(jsonContent: PackageJson, baseDirectory: string, state: ModuleResolutionState) {
|
||||
return readPackageJsonPathField(jsonContent, "typings", baseDirectory, state)
|
||||
|| readPackageJsonPathField(jsonContent, "types", baseDirectory, state);
|
||||
}
|
||||
|
||||
function readPackageJsonMainField(jsonContent: PackageJson, baseDirectory: string, state: ModuleResolutionState) {
|
||||
return readPackageJsonPathField(jsonContent, "main", baseDirectory, state);
|
||||
}
|
||||
|
||||
function readPackageJsonTypesVersionsField(jsonContent: PackageJson, state: ModuleResolutionState) {
|
||||
const typesVersions = readPackageJsonField(jsonContent, "typesVersions", "object", state);
|
||||
if (typesVersions === undefined) return;
|
||||
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.package_json_has_a_typesVersions_field_with_version_specific_path_mappings);
|
||||
}
|
||||
|
||||
return typesVersions;
|
||||
}
|
||||
|
||||
interface VersionPaths {
|
||||
version: string;
|
||||
paths: MapLike<string[]>;
|
||||
}
|
||||
|
||||
function readPackageJsonTypesVersionPaths(jsonContent: PackageJson, state: ModuleResolutionState): VersionPaths | undefined {
|
||||
const typesVersions = readPackageJsonTypesVersionsField(jsonContent, state);
|
||||
if (typesVersions === undefined) return;
|
||||
|
||||
if (state.traceEnabled) {
|
||||
for (const key in typesVersions) {
|
||||
if (hasProperty(typesVersions, key) && !VersionRange.tryParse(key)) {
|
||||
trace(state.host, Diagnostics.package_json_has_a_typesVersions_entry_0_that_is_not_a_valid_semver_range, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const result = getPackageJsonTypesVersionsPaths(typesVersions);
|
||||
if (!result) {
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.package_json_does_not_have_a_typesVersions_entry_that_matches_version_0, versionMajorMinor);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const { version: bestVersionKey, paths: bestVersionPaths } = result;
|
||||
if (typeof bestVersionPaths !== "object") {
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_1_got_2, `typesVersions['${bestVersionKey}']`, "object", typeof bestVersionPaths);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
let typeScriptVersion: Version | undefined;
|
||||
|
||||
/* @internal */
|
||||
export function getPackageJsonTypesVersionsPaths(typesVersions: MapLike<MapLike<string[]>>) {
|
||||
if (!typeScriptVersion) typeScriptVersion = new Version(version);
|
||||
|
||||
for (const key in typesVersions) {
|
||||
if (!hasProperty(typesVersions, key)) continue;
|
||||
|
||||
const keyRange = VersionRange.tryParse(key);
|
||||
if (keyRange === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// return the first entry whose range matches the current compiler version.
|
||||
if (keyRange.test(typeScriptVersion)) {
|
||||
return { version: key, paths: typesVersions[key] };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,7 +260,8 @@ namespace ts {
|
||||
*/
|
||||
export function resolveTypeReferenceDirective(typeReferenceDirectiveName: string, containingFile: string | undefined, options: CompilerOptions, host: ModuleResolutionHost): ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
|
||||
const traceEnabled = isTraceEnabled(options, host);
|
||||
const moduleResolutionState: ModuleResolutionState = { compilerOptions: options, host, traceEnabled };
|
||||
const failedLookupLocations: string[] = [];
|
||||
const moduleResolutionState: ModuleResolutionState = { compilerOptions: options, host, traceEnabled, failedLookupLocations };
|
||||
|
||||
const typeRoots = getEffectiveTypeRoots(options, host);
|
||||
if (traceEnabled) {
|
||||
@@ -210,8 +283,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
const failedLookupLocations: string[] = [];
|
||||
|
||||
let resolved = primaryLookup();
|
||||
let primary = true;
|
||||
if (!resolved) {
|
||||
@@ -247,7 +318,7 @@ namespace ts {
|
||||
trace(host, Diagnostics.Directory_0_does_not_exist_skipping_all_lookups_in_it, candidateDirectory);
|
||||
}
|
||||
return resolvedTypeScriptOnly(
|
||||
loadNodeModuleFromDirectory(Extensions.DtsOnly, candidate, failedLookupLocations,
|
||||
loadNodeModuleFromDirectory(Extensions.DtsOnly, candidate,
|
||||
!directoryExists, moduleResolutionState));
|
||||
});
|
||||
}
|
||||
@@ -266,7 +337,7 @@ namespace ts {
|
||||
if (traceEnabled) {
|
||||
trace(host, Diagnostics.Looking_up_in_node_modules_folder_initial_location_0, initialLocationForSecondaryLookup);
|
||||
}
|
||||
const result = loadModuleFromNodeModules(Extensions.DtsOnly, typeReferenceDirectiveName, initialLocationForSecondaryLookup, failedLookupLocations, moduleResolutionState, /*cache*/ undefined);
|
||||
const result = loadModuleFromNearestNodeModulesDirectory(Extensions.DtsOnly, typeReferenceDirectiveName, initialLocationForSecondaryLookup, moduleResolutionState, /*cache*/ undefined);
|
||||
const resolvedFile = resolvedTypeScriptOnly(result && result.value);
|
||||
if (!resolvedFile && traceEnabled) {
|
||||
trace(host, Diagnostics.Type_reference_directive_0_was_not_resolved, typeReferenceDirectiveName);
|
||||
@@ -304,7 +375,7 @@ namespace ts {
|
||||
if (host.directoryExists(root)) {
|
||||
for (const typeDirectivePath of host.getDirectories(root)) {
|
||||
const normalized = normalizePath(typeDirectivePath);
|
||||
const packageJsonPath = pathToPackageJson(combinePaths(root, normalized));
|
||||
const packageJsonPath = combinePaths(root, normalized, "package.json");
|
||||
// `types-publisher` sometimes creates packages with `"typings": null` for packages that don't provide their own types.
|
||||
// See `createNotNeededPackageJSON` in the types-publisher` repo.
|
||||
// tslint:disable-next-line:no-null-keyword
|
||||
@@ -527,7 +598,7 @@ namespace ts {
|
||||
* 'typings' entry or file 'index' with some supported extension
|
||||
* - Classic loader will only try to interpret '/a/b/c' as file.
|
||||
*/
|
||||
type ResolutionKindSpecificLoader = (extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState) => Resolved | undefined;
|
||||
type ResolutionKindSpecificLoader = (extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState) => Resolved | undefined;
|
||||
|
||||
/**
|
||||
* Any module resolution kind can be augmented with optional settings: 'baseUrl', 'paths' and 'rootDirs' - they are used to
|
||||
@@ -590,18 +661,18 @@ namespace ts {
|
||||
* entries in 'rootDirs', use them to build absolute path out of (*) and try to resolve module from this location.
|
||||
*/
|
||||
function tryLoadModuleUsingOptionalResolutionSettings(extensions: Extensions, moduleName: string, containingDirectory: string, loader: ResolutionKindSpecificLoader,
|
||||
failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
|
||||
state: ModuleResolutionState): Resolved | undefined {
|
||||
|
||||
if (!isExternalModuleNameRelative(moduleName)) {
|
||||
return tryLoadModuleUsingBaseUrl(extensions, moduleName, loader, failedLookupLocations, state);
|
||||
return tryLoadModuleUsingBaseUrl(extensions, moduleName, loader, state);
|
||||
}
|
||||
else {
|
||||
return tryLoadModuleUsingRootDirs(extensions, moduleName, containingDirectory, loader, failedLookupLocations, state);
|
||||
return tryLoadModuleUsingRootDirs(extensions, moduleName, containingDirectory, loader, state);
|
||||
}
|
||||
}
|
||||
|
||||
function tryLoadModuleUsingRootDirs(extensions: Extensions, moduleName: string, containingDirectory: string, loader: ResolutionKindSpecificLoader,
|
||||
failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
|
||||
state: ModuleResolutionState): Resolved | undefined {
|
||||
|
||||
if (!state.compilerOptions.rootDirs) {
|
||||
return undefined;
|
||||
@@ -646,7 +717,7 @@ namespace ts {
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.Loading_0_from_the_root_dir_1_candidate_location_2, suffix, matchedNormalizedPrefix, candidate);
|
||||
}
|
||||
const resolvedFileName = loader(extensions, candidate, failedLookupLocations, !directoryProbablyExists(containingDirectory, state.host), state);
|
||||
const resolvedFileName = loader(extensions, candidate, !directoryProbablyExists(containingDirectory, state.host), state);
|
||||
if (resolvedFileName) {
|
||||
return resolvedFileName;
|
||||
}
|
||||
@@ -665,7 +736,7 @@ namespace ts {
|
||||
trace(state.host, Diagnostics.Loading_0_from_the_root_dir_1_candidate_location_2, suffix, rootDir, candidate);
|
||||
}
|
||||
const baseDirectory = getDirectoryPath(candidate);
|
||||
const resolvedFileName = loader(extensions, candidate, failedLookupLocations, !directoryProbablyExists(baseDirectory, state.host), state);
|
||||
const resolvedFileName = loader(extensions, candidate, !directoryProbablyExists(baseDirectory, state.host), state);
|
||||
if (resolvedFileName) {
|
||||
return resolvedFileName;
|
||||
}
|
||||
@@ -677,60 +748,28 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function tryLoadModuleUsingBaseUrl(extensions: Extensions, moduleName: string, loader: ResolutionKindSpecificLoader, failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
|
||||
if (!state.compilerOptions.baseUrl) {
|
||||
function tryLoadModuleUsingBaseUrl(extensions: Extensions, moduleName: string, loader: ResolutionKindSpecificLoader, state: ModuleResolutionState): Resolved | undefined {
|
||||
const { baseUrl, paths } = state.compilerOptions;
|
||||
if (!baseUrl) {
|
||||
return undefined;
|
||||
}
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.baseUrl_option_is_set_to_0_using_this_value_to_resolve_non_relative_module_name_1, state.compilerOptions.baseUrl, moduleName);
|
||||
trace(state.host, Diagnostics.baseUrl_option_is_set_to_0_using_this_value_to_resolve_non_relative_module_name_1, baseUrl, moduleName);
|
||||
}
|
||||
|
||||
// string is for exact match
|
||||
let matchedPattern: Pattern | string | undefined;
|
||||
if (state.compilerOptions.paths) {
|
||||
if (paths) {
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.paths_option_is_specified_looking_for_a_pattern_to_match_module_name_0, moduleName);
|
||||
}
|
||||
matchedPattern = matchPatternOrExact(getOwnKeys(state.compilerOptions.paths), moduleName);
|
||||
}
|
||||
|
||||
if (matchedPattern) {
|
||||
const matchedStar = isString(matchedPattern) ? undefined : matchedText(matchedPattern, moduleName);
|
||||
const matchedPatternText = isString(matchedPattern) ? matchedPattern : patternText(matchedPattern);
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.Module_name_0_matched_pattern_1, moduleName, matchedPatternText);
|
||||
const resolved = tryLoadModuleUsingPaths(extensions, moduleName, baseUrl, paths, loader, /*onlyRecordFailures*/ false, state);
|
||||
if (resolved) {
|
||||
return resolved.value;
|
||||
}
|
||||
return forEach(state.compilerOptions.paths![matchedPatternText], subst => {
|
||||
const path = matchedStar ? subst.replace("*", matchedStar) : subst;
|
||||
const candidate = normalizePath(combinePaths(state.compilerOptions.baseUrl!, path));
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.Trying_substitution_0_candidate_module_location_Colon_1, subst, path);
|
||||
}
|
||||
// A path mapping may have an extension, in contrast to an import, which should omit it.
|
||||
const extension = tryGetExtensionFromPath(candidate);
|
||||
if (extension !== undefined) {
|
||||
const path = tryFile(candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state);
|
||||
if (path !== undefined) {
|
||||
return noPackageId({ path, ext: extension });
|
||||
}
|
||||
}
|
||||
|
||||
return loader(extensions, candidate, failedLookupLocations, !directoryProbablyExists(getDirectoryPath(candidate), state.host), state);
|
||||
});
|
||||
}
|
||||
else {
|
||||
const candidate = normalizePath(combinePaths(state.compilerOptions.baseUrl, moduleName));
|
||||
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.Resolving_module_name_0_relative_to_base_url_1_2, moduleName, state.compilerOptions.baseUrl, candidate);
|
||||
}
|
||||
|
||||
return loader(extensions, candidate, failedLookupLocations, !directoryProbablyExists(getDirectoryPath(candidate), state.host), state);
|
||||
const candidate = normalizePath(combinePaths(baseUrl, moduleName));
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.Resolving_module_name_0_relative_to_base_url_1_2, moduleName, baseUrl, candidate);
|
||||
}
|
||||
}
|
||||
|
||||
export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache): ResolvedModuleWithFailedLookupLocations {
|
||||
return nodeModuleNameResolverWorker(moduleName, getDirectoryPath(containingFile), compilerOptions, host, cache, /*jsOnly*/ false);
|
||||
return loader(extensions, candidate, !directoryProbablyExists(getDirectoryPath(candidate), state.host), state);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -739,7 +778,7 @@ namespace ts {
|
||||
* Throws an error if the module can't be resolved.
|
||||
*/
|
||||
/* @internal */
|
||||
export function resolveJavaScriptModule(moduleName: string, initialDir: string, host: ModuleResolutionHost): string {
|
||||
export function resolveJSModule(moduleName: string, initialDir: string, host: ModuleResolutionHost): string {
|
||||
const { resolvedModule, failedLookupLocations } =
|
||||
nodeModuleNameResolverWorker(moduleName, initialDir, { moduleResolution: ModuleResolutionKind.NodeJs, allowJs: true }, host, /*cache*/ undefined, /*jsOnly*/ true);
|
||||
if (!resolvedModule) {
|
||||
@@ -748,11 +787,15 @@ namespace ts {
|
||||
return resolvedModule.resolvedFileName;
|
||||
}
|
||||
|
||||
export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache): ResolvedModuleWithFailedLookupLocations {
|
||||
return nodeModuleNameResolverWorker(moduleName, getDirectoryPath(containingFile), compilerOptions, host, cache, /*jsOnly*/ false);
|
||||
}
|
||||
|
||||
function nodeModuleNameResolverWorker(moduleName: string, containingDirectory: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache: ModuleResolutionCache | undefined, jsOnly: boolean): ResolvedModuleWithFailedLookupLocations {
|
||||
const traceEnabled = isTraceEnabled(compilerOptions, host);
|
||||
|
||||
const failedLookupLocations: string[] = [];
|
||||
const state: ModuleResolutionState = { compilerOptions, host, traceEnabled };
|
||||
const state: ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations };
|
||||
|
||||
const result = jsOnly ?
|
||||
tryResolve(Extensions.JavaScript) :
|
||||
@@ -766,8 +809,8 @@ namespace ts {
|
||||
return { resolvedModule: undefined, failedLookupLocations };
|
||||
|
||||
function tryResolve(extensions: Extensions): SearchResult<{ resolved: Resolved, isExternalLibraryImport: boolean }> {
|
||||
const loader: ResolutionKindSpecificLoader = (extensions, candidate, failedLookupLocations, onlyRecordFailures, state) => nodeLoadModuleByRelativeName(extensions, candidate, failedLookupLocations, onlyRecordFailures, state, /*considerPackageJson*/ true);
|
||||
const resolved = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loader, failedLookupLocations, state);
|
||||
const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => nodeLoadModuleByRelativeName(extensions, candidate, onlyRecordFailures, state, /*considerPackageJson*/ true);
|
||||
const resolved = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loader, state);
|
||||
if (resolved) {
|
||||
return toSearchResult({ resolved, isExternalLibraryImport: stringContains(resolved.path, nodeModulesPathPart) });
|
||||
}
|
||||
@@ -776,7 +819,7 @@ namespace ts {
|
||||
if (traceEnabled) {
|
||||
trace(host, Diagnostics.Loading_module_0_from_node_modules_folder_target_file_type_1, moduleName, Extensions[extensions]);
|
||||
}
|
||||
const resolved = loadModuleFromNodeModules(extensions, moduleName, containingDirectory, failedLookupLocations, state, cache);
|
||||
const resolved = loadModuleFromNearestNodeModulesDirectory(extensions, moduleName, containingDirectory, state, cache);
|
||||
if (!resolved) return undefined;
|
||||
|
||||
let resolvedValue = resolved.value;
|
||||
@@ -790,7 +833,7 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
const { path: candidate, parts } = normalizePathAndParts(combinePaths(containingDirectory, moduleName));
|
||||
const resolved = nodeLoadModuleByRelativeName(extensions, candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state, /*considerPackageJson*/ true);
|
||||
const resolved = nodeLoadModuleByRelativeName(extensions, candidate, /*onlyRecordFailures*/ false, state, /*considerPackageJson*/ true);
|
||||
// Treat explicit "node_modules" import as an external library import.
|
||||
return resolved && toSearchResult({ resolved, isExternalLibraryImport: contains(parts, "node_modules") });
|
||||
}
|
||||
@@ -810,7 +853,7 @@ namespace ts {
|
||||
return real;
|
||||
}
|
||||
|
||||
function nodeLoadModuleByRelativeName(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson: boolean): Resolved | undefined {
|
||||
function nodeLoadModuleByRelativeName(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson: boolean): Resolved | undefined {
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.Loading_module_as_file_Slash_folder_candidate_module_location_0_target_file_type_1, candidate, Extensions[extensions]);
|
||||
}
|
||||
@@ -824,10 +867,11 @@ namespace ts {
|
||||
onlyRecordFailures = true;
|
||||
}
|
||||
}
|
||||
const resolvedFromFile = loadModuleFromFile(extensions, candidate, failedLookupLocations, onlyRecordFailures, state);
|
||||
const resolvedFromFile = loadModuleFromFile(extensions, candidate, onlyRecordFailures, state);
|
||||
if (resolvedFromFile) {
|
||||
const nm = considerPackageJson ? parseNodeModuleFromPath(resolvedFromFile) : undefined;
|
||||
const packageId = nm && getPackageJsonInfo(nm.packageDirectory, nm.subModuleName, failedLookupLocations, /*onlyRecordFailures*/ false, state).packageId;
|
||||
const packageInfo = nm && getPackageJsonInfo(nm.packageDirectory, nm.subModuleName, /*onlyRecordFailures*/ false, state);
|
||||
const packageId = packageInfo && packageInfo.packageId;
|
||||
return withPackageId(packageId, resolvedFromFile);
|
||||
}
|
||||
}
|
||||
@@ -840,7 +884,7 @@ namespace ts {
|
||||
onlyRecordFailures = true;
|
||||
}
|
||||
}
|
||||
return loadNodeModuleFromDirectory(extensions, candidate, failedLookupLocations, onlyRecordFailures, state, considerPackageJson);
|
||||
return loadNodeModuleFromDirectory(extensions, candidate, onlyRecordFailures, state, considerPackageJson);
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
@@ -886,52 +930,46 @@ namespace ts {
|
||||
if (endsWith(path, ".d.ts")) {
|
||||
return path;
|
||||
}
|
||||
if (endsWith(path, "/index")) {
|
||||
if (path === "index" || endsWith(path, "/index")) {
|
||||
return path + ".d.ts";
|
||||
}
|
||||
return path + "/index.d.ts";
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function directoryProbablyExists(directoryName: string, host: { directoryExists?: (directoryName: string) => boolean }): boolean {
|
||||
// if host does not support 'directoryExists' assume that directory will exist
|
||||
return !host.directoryExists || host.directoryExists(directoryName);
|
||||
}
|
||||
|
||||
function loadModuleFromFileNoPackageId(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved | undefined {
|
||||
return noPackageId(loadModuleFromFile(extensions, candidate, failedLookupLocations, onlyRecordFailures, state));
|
||||
function loadModuleFromFileNoPackageId(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved | undefined {
|
||||
return noPackageId(loadModuleFromFile(extensions, candidate, onlyRecordFailures, state));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} onlyRecordFailures - if true then function won't try to actually load files but instead record all attempts as failures. This flag is necessary
|
||||
* in cases when we know upfront that all load attempts will fail (because containing folder does not exists) however we still need to record all failed lookup locations.
|
||||
*/
|
||||
function loadModuleFromFile(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
|
||||
function loadModuleFromFile(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
|
||||
if (extensions === Extensions.Json) {
|
||||
const extensionLess = tryRemoveExtension(candidate, Extension.Json);
|
||||
return extensionLess === undefined ? undefined : tryAddingExtensions(extensionLess, extensions, failedLookupLocations, onlyRecordFailures, state);
|
||||
return extensionLess === undefined ? undefined : tryAddingExtensions(extensionLess, extensions, onlyRecordFailures, state);
|
||||
}
|
||||
|
||||
// First, try adding an extension. An import of "foo" could be matched by a file "foo.ts", or "foo.js" by "foo.js.ts"
|
||||
const resolvedByAddingExtension = tryAddingExtensions(candidate, extensions, failedLookupLocations, onlyRecordFailures, state);
|
||||
const resolvedByAddingExtension = tryAddingExtensions(candidate, extensions, onlyRecordFailures, state);
|
||||
if (resolvedByAddingExtension) {
|
||||
return resolvedByAddingExtension;
|
||||
}
|
||||
|
||||
// If that didn't work, try stripping a ".js" or ".jsx" extension and replacing it with a TypeScript one;
|
||||
// e.g. "./foo.js" can be matched by "./foo.ts" or "./foo.d.ts"
|
||||
if (hasJavaScriptFileExtension(candidate)) {
|
||||
if (hasJSFileExtension(candidate)) {
|
||||
const extensionless = removeFileExtension(candidate);
|
||||
if (state.traceEnabled) {
|
||||
const extension = candidate.substring(extensionless.length);
|
||||
trace(state.host, Diagnostics.File_name_0_has_a_1_extension_stripping_it, candidate, extension);
|
||||
}
|
||||
return tryAddingExtensions(extensionless, extensions, failedLookupLocations, onlyRecordFailures, state);
|
||||
return tryAddingExtensions(extensionless, extensions, onlyRecordFailures, state);
|
||||
}
|
||||
}
|
||||
|
||||
/** Try to return an existing file that adds one of the `extensions` to `candidate`. */
|
||||
function tryAddingExtensions(candidate: string, extensions: Extensions, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
|
||||
function tryAddingExtensions(candidate: string, extensions: Extensions, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
|
||||
if (!onlyRecordFailures) {
|
||||
// check if containing folder exists - if it doesn't then just record failures for all supported extensions without disk probing
|
||||
const directory = getDirectoryPath(candidate);
|
||||
@@ -952,13 +990,13 @@ namespace ts {
|
||||
}
|
||||
|
||||
function tryExtension(ext: Extension): PathAndExtension | undefined {
|
||||
const path = tryFile(candidate + ext, failedLookupLocations, onlyRecordFailures, state);
|
||||
const path = tryFile(candidate + ext, onlyRecordFailures, state);
|
||||
return path === undefined ? undefined : { path, ext };
|
||||
}
|
||||
}
|
||||
|
||||
/** Return the file if it exists. */
|
||||
function tryFile(fileName: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): string | undefined {
|
||||
function tryFile(fileName: string, onlyRecordFailures: boolean, state: ModuleResolutionState): string | undefined {
|
||||
if (!onlyRecordFailures) {
|
||||
if (state.host.fileExists(fileName)) {
|
||||
if (state.traceEnabled) {
|
||||
@@ -972,48 +1010,49 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
failedLookupLocations.push(fileName);
|
||||
state.failedLookupLocations.push(fileName);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function loadNodeModuleFromDirectory(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson = true) {
|
||||
const { packageJsonContent, packageId } = considerPackageJson
|
||||
? getPackageJsonInfo(candidate, "", failedLookupLocations, onlyRecordFailures, state)
|
||||
: { packageJsonContent: undefined, packageId: undefined };
|
||||
return withPackageId(packageId, loadNodeModuleFromDirectoryWorker(extensions, candidate, failedLookupLocations, onlyRecordFailures, state, packageJsonContent));
|
||||
function loadNodeModuleFromDirectory(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson = true) {
|
||||
const packageInfo = considerPackageJson ? getPackageJsonInfo(candidate, "", onlyRecordFailures, state) : undefined;
|
||||
const packageId = packageInfo && packageInfo.packageId;
|
||||
const packageJsonContent = packageInfo && packageInfo.packageJsonContent;
|
||||
const versionPaths = packageJsonContent && readPackageJsonTypesVersionPaths(packageJsonContent, state);
|
||||
return withPackageId(packageId, loadNodeModuleFromDirectoryWorker(extensions, candidate, onlyRecordFailures, state, packageJsonContent, versionPaths));
|
||||
}
|
||||
|
||||
function loadNodeModuleFromDirectoryWorker(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState, packageJsonContent: PackageJsonPathFields | undefined): PathAndExtension | undefined {
|
||||
const fromPackageJson = packageJsonContent && loadModuleFromPackageJson(packageJsonContent, extensions, candidate, failedLookupLocations, state);
|
||||
function loadNodeModuleFromDirectoryWorker(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState, packageJsonContent: PackageJsonPathFields | undefined, versionPaths: VersionPaths | undefined): PathAndExtension | undefined {
|
||||
const fromPackageJson = packageJsonContent && loadModuleFromPackageJson(packageJsonContent, versionPaths, extensions, candidate, state);
|
||||
if (fromPackageJson) {
|
||||
return fromPackageJson;
|
||||
}
|
||||
const directoryExists = !onlyRecordFailures && directoryProbablyExists(candidate, state.host);
|
||||
return loadModuleFromFile(extensions, combinePaths(candidate, "index"), failedLookupLocations, !directoryExists, state);
|
||||
return loadModuleFromFile(extensions, combinePaths(candidate, "index"), !directoryExists, state);
|
||||
}
|
||||
|
||||
function getPackageJsonInfo(
|
||||
nodeModuleDirectory: string,
|
||||
subModuleName: string,
|
||||
failedLookupLocations: Push<string>,
|
||||
onlyRecordFailures: boolean,
|
||||
state: ModuleResolutionState,
|
||||
): { found: boolean, packageJsonContent: PackageJsonPathFields | undefined, packageId: PackageId | undefined } {
|
||||
interface PackageJsonInfo {
|
||||
packageJsonContent: PackageJsonPathFields | undefined;
|
||||
packageId: PackageId | undefined;
|
||||
versionPaths: VersionPaths | undefined;
|
||||
}
|
||||
|
||||
function getPackageJsonInfo(packageDirectory: string, subModuleName: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PackageJsonInfo | undefined {
|
||||
const { host, traceEnabled } = state;
|
||||
const directoryExists = !onlyRecordFailures && directoryProbablyExists(nodeModuleDirectory, host);
|
||||
const packageJsonPath = pathToPackageJson(nodeModuleDirectory);
|
||||
const directoryExists = !onlyRecordFailures && directoryProbablyExists(packageDirectory, host);
|
||||
const packageJsonPath = combinePaths(packageDirectory, "package.json");
|
||||
if (directoryExists && host.fileExists(packageJsonPath)) {
|
||||
const packageJsonContent = readJson(packageJsonPath, host) as PackageJson;
|
||||
if (subModuleName === "") { // looking up the root - need to handle types/typings/main redirects for subModuleName
|
||||
const path = tryReadPackageJsonFields(/*readTypes*/ true, packageJsonContent, nodeModuleDirectory, state);
|
||||
const path = readPackageJsonTypesFields(packageJsonContent, packageDirectory, state);
|
||||
if (typeof path === "string") {
|
||||
subModuleName = addExtensionAndIndex(path.substring(nodeModuleDirectory.length + 1));
|
||||
subModuleName = addExtensionAndIndex(path.substring(packageDirectory.length + 1));
|
||||
}
|
||||
else {
|
||||
const jsPath = tryReadPackageJsonFields(/*readTypes*/ false, packageJsonContent, nodeModuleDirectory, state);
|
||||
if (typeof jsPath === "string" && jsPath.length > nodeModuleDirectory.length) {
|
||||
const potentialSubModule = jsPath.substring(nodeModuleDirectory.length + 1);
|
||||
subModuleName = (forEach(supportedJavascriptExtensions, extension =>
|
||||
const jsPath = readPackageJsonMainField(packageJsonContent, packageDirectory, state);
|
||||
if (typeof jsPath === "string" && jsPath.length > packageDirectory.length) {
|
||||
const potentialSubModule = jsPath.substring(packageDirectory.length + 1);
|
||||
subModuleName = (forEach(supportedJSExtensions, extension =>
|
||||
tryRemoveExtension(potentialSubModule, extension)) || potentialSubModule) + Extension.Dts;
|
||||
}
|
||||
else {
|
||||
@@ -1021,9 +1060,12 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!endsWith(subModuleName, Extension.Dts)) {
|
||||
subModuleName = addExtensionAndIndex(subModuleName);
|
||||
}
|
||||
|
||||
const versionPaths = readPackageJsonTypesVersionPaths(packageJsonContent, state);
|
||||
const packageId: PackageId | undefined = typeof packageJsonContent.name === "string" && typeof packageJsonContent.version === "string"
|
||||
? { name: packageJsonContent.name, subModuleName, version: packageJsonContent.version }
|
||||
: undefined;
|
||||
@@ -1035,24 +1077,27 @@ namespace ts {
|
||||
trace(host, Diagnostics.Found_package_json_at_0, packageJsonPath);
|
||||
}
|
||||
}
|
||||
return { found: true, packageJsonContent, packageId };
|
||||
|
||||
return { packageJsonContent, packageId, versionPaths };
|
||||
}
|
||||
else {
|
||||
if (directoryExists && traceEnabled) {
|
||||
trace(host, Diagnostics.File_0_does_not_exist, packageJsonPath);
|
||||
}
|
||||
|
||||
// record package json as one of failed lookup locations - in the future if this file will appear it will invalidate resolution results
|
||||
failedLookupLocations.push(packageJsonPath);
|
||||
return { found: false, packageJsonContent: undefined, packageId: undefined };
|
||||
state.failedLookupLocations.push(packageJsonPath);
|
||||
}
|
||||
}
|
||||
|
||||
function loadModuleFromPackageJson(jsonContent: PackageJsonPathFields, extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, state: ModuleResolutionState): PathAndExtension | undefined {
|
||||
let file = tryReadPackageJsonFields(extensions !== Extensions.JavaScript && extensions !== Extensions.Json, jsonContent, candidate, state);
|
||||
function loadModuleFromPackageJson(jsonContent: PackageJsonPathFields, versionPaths: VersionPaths | undefined, extensions: Extensions, candidate: string, state: ModuleResolutionState): PathAndExtension | undefined {
|
||||
let file = extensions !== Extensions.JavaScript && extensions !== Extensions.Json
|
||||
? readPackageJsonTypesFields(jsonContent, candidate, state)
|
||||
: readPackageJsonMainField(jsonContent, candidate, state);
|
||||
if (!file) {
|
||||
if (extensions === Extensions.TypeScript) {
|
||||
// When resolving typescript modules, try resolving using main field as well
|
||||
file = tryReadPackageJsonFields(/*readTypes*/ false, jsonContent, candidate, state);
|
||||
file = readPackageJsonMainField(jsonContent, candidate, state);
|
||||
if (!file) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -1062,27 +1107,39 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
const onlyRecordFailures = !directoryProbablyExists(getDirectoryPath(file), state.host);
|
||||
const fromFile = tryFile(file, failedLookupLocations, onlyRecordFailures, state);
|
||||
if (fromFile) {
|
||||
const resolved = resolvedIfExtensionMatches(extensions, fromFile);
|
||||
if (resolved) {
|
||||
return resolved;
|
||||
const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => {
|
||||
const fromFile = tryFile(candidate, onlyRecordFailures, state);
|
||||
if (fromFile) {
|
||||
const resolved = resolvedIfExtensionMatches(extensions, fromFile);
|
||||
if (resolved) {
|
||||
return noPackageId(resolved);
|
||||
}
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.File_0_has_an_unsupported_extension_so_skipping_it, fromFile);
|
||||
}
|
||||
}
|
||||
|
||||
// Even if extensions is DtsOnly, we can still look up a .ts file as a result of package.json "types"
|
||||
const nextExtensions = extensions === Extensions.DtsOnly ? Extensions.TypeScript : extensions;
|
||||
// Don't do package.json lookup recursively, because Node.js' package lookup doesn't.
|
||||
return nodeLoadModuleByRelativeName(nextExtensions, candidate, onlyRecordFailures, state, /*considerPackageJson*/ false);
|
||||
};
|
||||
|
||||
const onlyRecordFailures = !directoryProbablyExists(getDirectoryPath(file), state.host);
|
||||
|
||||
if (versionPaths && containsPath(candidate, file)) {
|
||||
const moduleName = getRelativePathFromDirectory(candidate, file, /*ignoreCase*/ false);
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.File_0_has_an_unsupported_extension_so_skipping_it, fromFile);
|
||||
trace(state.host, Diagnostics.package_json_has_a_typesVersions_entry_0_that_matches_compiler_version_1_looking_for_a_pattern_to_match_module_name_2, versionPaths.version, version, moduleName);
|
||||
}
|
||||
const result = tryLoadModuleUsingPaths(extensions, moduleName, candidate, versionPaths.paths, loader, onlyRecordFailures, state);
|
||||
if (result) {
|
||||
return removeIgnoredPackageId(result.value);
|
||||
}
|
||||
}
|
||||
|
||||
// Even if extensions is DtsOnly, we can still look up a .ts file as a result of package.json "types"
|
||||
const nextExtensions = extensions === Extensions.DtsOnly ? Extensions.TypeScript : extensions;
|
||||
// Don't do package.json lookup recursively, because Node.js' package lookup doesn't.
|
||||
const result = nodeLoadModuleByRelativeName(nextExtensions, file, failedLookupLocations, onlyRecordFailures, state, /*considerPackageJson*/ false);
|
||||
if (result) {
|
||||
// It won't have a `packageId` set, because we disabled `considerPackageJson`.
|
||||
Debug.assert(result.packageId === undefined);
|
||||
return { path: result.path, ext: result.extension };
|
||||
}
|
||||
// It won't have a `packageId` set, because we disabled `considerPackageJson`.
|
||||
return removeIgnoredPackageId(loader(extensions, file, onlyRecordFailures, state));
|
||||
}
|
||||
|
||||
/** Resolve from an arbitrarily specified file. Return `undefined` if it has an unsupported extension. */
|
||||
@@ -1105,34 +1162,8 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function pathToPackageJson(directory: string): string {
|
||||
return combinePaths(directory, "package.json");
|
||||
}
|
||||
|
||||
function loadModuleFromNodeModulesFolder(extensions: Extensions, moduleName: string, nodeModulesFolder: string, nodeModulesFolderExists: boolean, failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
|
||||
const candidate = normalizePath(combinePaths(nodeModulesFolder, moduleName));
|
||||
// First look for a nested package.json, as in `node_modules/foo/bar/package.json`.
|
||||
let packageJsonContent: PackageJsonPathFields | undefined;
|
||||
let packageId: PackageId | undefined;
|
||||
const packageInfo = getPackageJsonInfo(candidate, "", failedLookupLocations, /*onlyRecordFailures*/ !nodeModulesFolderExists, state);
|
||||
if (packageInfo.found) {
|
||||
({ packageJsonContent, packageId } = packageInfo);
|
||||
}
|
||||
else {
|
||||
const { packageName, rest } = getPackageName(moduleName);
|
||||
if (rest !== "") { // If "rest" is empty, we just did this search above.
|
||||
const packageRootPath = combinePaths(nodeModulesFolder, packageName);
|
||||
// Don't use a "types" or "main" from here because we're not loading the root, but a subdirectory -- just here for the packageId.
|
||||
packageId = getPackageJsonInfo(packageRootPath, rest, failedLookupLocations, !nodeModulesFolderExists, state).packageId;
|
||||
}
|
||||
}
|
||||
const pathAndExtension = loadModuleFromFile(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state) ||
|
||||
loadNodeModuleFromDirectoryWorker(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state, packageJsonContent);
|
||||
return withPackageId(packageId, pathAndExtension);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function getPackageName(moduleName: string): { packageName: string, rest: string } {
|
||||
export function parsePackageName(moduleName: string): { packageName: string, rest: string } {
|
||||
let idx = moduleName.indexOf(directorySeparator);
|
||||
if (moduleName[0] === "@") {
|
||||
idx = moduleName.indexOf(directorySeparator, idx + 1);
|
||||
@@ -1140,36 +1171,36 @@ namespace ts {
|
||||
return idx === -1 ? { packageName: moduleName, rest: "" } : { packageName: moduleName.slice(0, idx), rest: moduleName.slice(idx + 1) };
|
||||
}
|
||||
|
||||
function loadModuleFromNodeModules(extensions: Extensions, moduleName: string, directory: string, failedLookupLocations: Push<string>, state: ModuleResolutionState, cache: NonRelativeModuleNameResolutionCache | undefined): SearchResult<Resolved> {
|
||||
return loadModuleFromNodeModulesWorker(extensions, moduleName, directory, failedLookupLocations, state, /*typesOnly*/ false, cache);
|
||||
}
|
||||
function loadModuleFromNodeModulesAtTypes(moduleName: string, directory: string, failedLookupLocations: Push<string>, state: ModuleResolutionState): SearchResult<Resolved> {
|
||||
// Extensions parameter here doesn't actually matter, because typesOnly ensures we're just doing @types lookup, which is always DtsOnly.
|
||||
return loadModuleFromNodeModulesWorker(Extensions.DtsOnly, moduleName, directory, failedLookupLocations, state, /*typesOnly*/ true, /*cache*/ undefined);
|
||||
function loadModuleFromNearestNodeModulesDirectory(extensions: Extensions, moduleName: string, directory: string, state: ModuleResolutionState, cache: NonRelativeModuleNameResolutionCache | undefined): SearchResult<Resolved> {
|
||||
return loadModuleFromNearestNodeModulesDirectoryWorker(extensions, moduleName, directory, state, /*typesScopeOnly*/ false, cache);
|
||||
}
|
||||
|
||||
function loadModuleFromNodeModulesWorker(extensions: Extensions, moduleName: string, directory: string, failedLookupLocations: Push<string>, state: ModuleResolutionState, typesOnly: boolean, cache: NonRelativeModuleNameResolutionCache | undefined): SearchResult<Resolved> {
|
||||
function loadModuleFromNearestNodeModulesDirectoryTypesScope(moduleName: string, directory: string, state: ModuleResolutionState): SearchResult<Resolved> {
|
||||
// Extensions parameter here doesn't actually matter, because typesOnly ensures we're just doing @types lookup, which is always DtsOnly.
|
||||
return loadModuleFromNearestNodeModulesDirectoryWorker(Extensions.DtsOnly, moduleName, directory, state, /*typesScopeOnly*/ true, /*cache*/ undefined);
|
||||
}
|
||||
|
||||
function loadModuleFromNearestNodeModulesDirectoryWorker(extensions: Extensions, moduleName: string, directory: string, state: ModuleResolutionState, typesScopeOnly: boolean, cache: NonRelativeModuleNameResolutionCache | undefined): SearchResult<Resolved> {
|
||||
const perModuleNameCache = cache && cache.getOrCreateCacheForModuleName(moduleName);
|
||||
return forEachAncestorDirectory(normalizeSlashes(directory), ancestorDirectory => {
|
||||
if (getBaseFileName(ancestorDirectory) !== "node_modules") {
|
||||
const resolutionFromCache = tryFindNonRelativeModuleNameInCache(perModuleNameCache, moduleName, ancestorDirectory, state.traceEnabled, state.host, failedLookupLocations);
|
||||
const resolutionFromCache = tryFindNonRelativeModuleNameInCache(perModuleNameCache, moduleName, ancestorDirectory, state);
|
||||
if (resolutionFromCache) {
|
||||
return resolutionFromCache;
|
||||
}
|
||||
return toSearchResult(loadModuleFromNodeModulesOneLevel(extensions, moduleName, ancestorDirectory, failedLookupLocations, state, typesOnly));
|
||||
return toSearchResult(loadModuleFromImmediateNodeModulesDirectory(extensions, moduleName, ancestorDirectory, state, typesScopeOnly));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Load a module from a single node_modules directory, but not from any ancestors' node_modules directories. */
|
||||
function loadModuleFromNodeModulesOneLevel(extensions: Extensions, moduleName: string, directory: string, failedLookupLocations: Push<string>, state: ModuleResolutionState, typesOnly = false): Resolved | undefined {
|
||||
function loadModuleFromImmediateNodeModulesDirectory(extensions: Extensions, moduleName: string, directory: string, state: ModuleResolutionState, typesScopeOnly: boolean): Resolved | undefined {
|
||||
const nodeModulesFolder = combinePaths(directory, "node_modules");
|
||||
const nodeModulesFolderExists = directoryProbablyExists(nodeModulesFolder, state.host);
|
||||
if (!nodeModulesFolderExists && state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.Directory_0_does_not_exist_skipping_all_lookups_in_it, nodeModulesFolder);
|
||||
}
|
||||
|
||||
const packageResult = typesOnly ? undefined : loadModuleFromNodeModulesFolder(extensions, moduleName, nodeModulesFolder, nodeModulesFolderExists, failedLookupLocations, state);
|
||||
const packageResult = typesScopeOnly ? undefined : loadModuleFromSpecificNodeModulesDirectory(extensions, moduleName, nodeModulesFolder, nodeModulesFolderExists, state);
|
||||
if (packageResult) {
|
||||
return packageResult;
|
||||
}
|
||||
@@ -1182,7 +1213,84 @@ namespace ts {
|
||||
}
|
||||
nodeModulesAtTypesExists = false;
|
||||
}
|
||||
return loadModuleFromNodeModulesFolder(Extensions.DtsOnly, mangleScopedPackage(moduleName, state), nodeModulesAtTypes, nodeModulesAtTypesExists, failedLookupLocations, state);
|
||||
return loadModuleFromSpecificNodeModulesDirectory(Extensions.DtsOnly, mangleScopedPackageNameWithTrace(moduleName, state), nodeModulesAtTypes, nodeModulesAtTypesExists, state);
|
||||
}
|
||||
}
|
||||
|
||||
function loadModuleFromSpecificNodeModulesDirectory(extensions: Extensions, moduleName: string, nodeModulesDirectory: string, nodeModulesDirectoryExists: boolean, state: ModuleResolutionState): Resolved | undefined {
|
||||
const candidate = normalizePath(combinePaths(nodeModulesDirectory, moduleName));
|
||||
|
||||
// First look for a nested package.json, as in `node_modules/foo/bar/package.json`.
|
||||
let packageJsonContent: PackageJsonPathFields | undefined;
|
||||
let packageId: PackageId | undefined;
|
||||
let versionPaths: VersionPaths | undefined;
|
||||
|
||||
const packageInfo = getPackageJsonInfo(candidate, "", !nodeModulesDirectoryExists, state);
|
||||
if (packageInfo) {
|
||||
({ packageJsonContent, packageId, versionPaths } = packageInfo);
|
||||
const fromFile = loadModuleFromFile(extensions, candidate, !nodeModulesDirectoryExists, state);
|
||||
if (fromFile) {
|
||||
return noPackageId(fromFile);
|
||||
}
|
||||
|
||||
const fromDirectory = loadNodeModuleFromDirectoryWorker(extensions, candidate, !nodeModulesDirectoryExists, state, packageJsonContent, versionPaths);
|
||||
return withPackageId(packageId, fromDirectory);
|
||||
}
|
||||
|
||||
const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => {
|
||||
const pathAndExtension =
|
||||
loadModuleFromFile(extensions, candidate, onlyRecordFailures, state) ||
|
||||
loadNodeModuleFromDirectoryWorker(extensions, candidate, onlyRecordFailures, state, packageJsonContent, versionPaths);
|
||||
return withPackageId(packageId, pathAndExtension);
|
||||
};
|
||||
|
||||
const { packageName, rest } = parsePackageName(moduleName);
|
||||
if (rest !== "") { // If "rest" is empty, we just did this search above.
|
||||
const packageDirectory = combinePaths(nodeModulesDirectory, packageName);
|
||||
|
||||
// Don't use a "types" or "main" from here because we're not loading the root, but a subdirectory -- just here for the packageId and path mappings.
|
||||
const packageInfo = getPackageJsonInfo(packageDirectory, rest, !nodeModulesDirectoryExists, state);
|
||||
if (packageInfo) ({ packageId, versionPaths } = packageInfo);
|
||||
if (versionPaths) {
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.package_json_has_a_typesVersions_entry_0_that_matches_compiler_version_1_looking_for_a_pattern_to_match_module_name_2, versionPaths.version, version, rest);
|
||||
}
|
||||
const packageDirectoryExists = nodeModulesDirectoryExists && directoryProbablyExists(packageDirectory, state.host);
|
||||
const fromPaths = tryLoadModuleUsingPaths(extensions, rest, packageDirectory, versionPaths.paths, loader, !packageDirectoryExists, state);
|
||||
if (fromPaths) {
|
||||
return fromPaths.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return loader(extensions, candidate, !nodeModulesDirectoryExists, state);
|
||||
}
|
||||
|
||||
function tryLoadModuleUsingPaths(extensions: Extensions, moduleName: string, baseDirectory: string, paths: MapLike<string[]>, loader: ResolutionKindSpecificLoader, onlyRecordFailures: boolean, state: ModuleResolutionState): SearchResult<Resolved> {
|
||||
const matchedPattern = matchPatternOrExact(getOwnKeys(paths), moduleName);
|
||||
if (matchedPattern) {
|
||||
const matchedStar = isString(matchedPattern) ? undefined : matchedText(matchedPattern, moduleName);
|
||||
const matchedPatternText = isString(matchedPattern) ? matchedPattern : patternText(matchedPattern);
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.Module_name_0_matched_pattern_1, moduleName, matchedPatternText);
|
||||
}
|
||||
const resolved = forEach(paths[matchedPatternText], subst => {
|
||||
const path = matchedStar ? subst.replace("*", matchedStar) : subst;
|
||||
const candidate = normalizePath(combinePaths(baseDirectory, path));
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.Trying_substitution_0_candidate_module_location_Colon_1, subst, path);
|
||||
}
|
||||
// A path mapping may have an extension, in contrast to an import, which should omit it.
|
||||
const extension = tryGetExtensionFromPath(candidate);
|
||||
if (extension !== undefined) {
|
||||
const path = tryFile(candidate, onlyRecordFailures, state);
|
||||
if (path !== undefined) {
|
||||
return noPackageId({ path, ext: extension });
|
||||
}
|
||||
}
|
||||
return loader(extensions, candidate, onlyRecordFailures || !directoryProbablyExists(getDirectoryPath(candidate), state.host), state);
|
||||
});
|
||||
return { value: resolved };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1190,8 +1298,8 @@ namespace ts {
|
||||
const mangledScopedPackageSeparator = "__";
|
||||
|
||||
/** For a scoped package, we must look in `@types/foo__bar` instead of `@types/@foo/bar`. */
|
||||
function mangleScopedPackage(packageName: string, state: ModuleResolutionState): string {
|
||||
const mangled = getMangledNameForScopedPackage(packageName);
|
||||
function mangleScopedPackageNameWithTrace(packageName: string, state: ModuleResolutionState): string {
|
||||
const mangled = mangleScopedPackageName(packageName);
|
||||
if (state.traceEnabled && mangled !== packageName) {
|
||||
trace(state.host, Diagnostics.Scoped_package_detected_looking_in_0, mangled);
|
||||
}
|
||||
@@ -1200,11 +1308,11 @@ namespace ts {
|
||||
|
||||
/* @internal */
|
||||
export function getTypesPackageName(packageName: string): string {
|
||||
return `@types/${getMangledNameForScopedPackage(packageName)}`;
|
||||
return `@types/${mangleScopedPackageName(packageName)}`;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function getMangledNameForScopedPackage(packageName: string): string {
|
||||
export function mangleScopedPackageName(packageName: string): string {
|
||||
if (startsWith(packageName, "@")) {
|
||||
const replaceSlash = packageName.replace(directorySeparator, mangledScopedPackageSeparator);
|
||||
if (replaceSlash !== packageName) {
|
||||
@@ -1215,36 +1323,36 @@ namespace ts {
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function getPackageNameFromAtTypesDirectory(mangledName: string): string {
|
||||
export function getPackageNameFromTypesPackageName(mangledName: string): string {
|
||||
const withoutAtTypePrefix = removePrefix(mangledName, "@types/");
|
||||
if (withoutAtTypePrefix !== mangledName) {
|
||||
return getUnmangledNameForScopedPackage(withoutAtTypePrefix);
|
||||
return unmangleScopedPackageName(withoutAtTypePrefix);
|
||||
}
|
||||
return mangledName;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function getUnmangledNameForScopedPackage(typesPackageName: string): string {
|
||||
export function unmangleScopedPackageName(typesPackageName: string): string {
|
||||
return stringContains(typesPackageName, mangledScopedPackageSeparator) ?
|
||||
"@" + typesPackageName.replace(mangledScopedPackageSeparator, directorySeparator) :
|
||||
typesPackageName;
|
||||
}
|
||||
|
||||
function tryFindNonRelativeModuleNameInCache(cache: PerModuleNameCache | undefined, moduleName: string, containingDirectory: string, traceEnabled: boolean, host: ModuleResolutionHost, failedLookupLocations: Push<string>): SearchResult<Resolved> {
|
||||
function tryFindNonRelativeModuleNameInCache(cache: PerModuleNameCache | undefined, moduleName: string, containingDirectory: string, state: ModuleResolutionState): SearchResult<Resolved> {
|
||||
const result = cache && cache.get(containingDirectory);
|
||||
if (result) {
|
||||
if (traceEnabled) {
|
||||
trace(host, Diagnostics.Resolution_for_module_0_was_found_in_cache_from_location_1, moduleName, containingDirectory);
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.Resolution_for_module_0_was_found_in_cache_from_location_1, moduleName, containingDirectory);
|
||||
}
|
||||
failedLookupLocations.push(...result.failedLookupLocations);
|
||||
state.failedLookupLocations.push(...result.failedLookupLocations);
|
||||
return { value: result.resolvedModule && { path: result.resolvedModule.resolvedFileName, originalPath: result.resolvedModule.originalPath || true, extension: result.resolvedModule.extension, packageId: result.resolvedModule.packageId } };
|
||||
}
|
||||
}
|
||||
|
||||
export function classicNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: NonRelativeModuleNameResolutionCache): ResolvedModuleWithFailedLookupLocations {
|
||||
const traceEnabled = isTraceEnabled(compilerOptions, host);
|
||||
const state: ModuleResolutionState = { compilerOptions, host, traceEnabled };
|
||||
const failedLookupLocations: string[] = [];
|
||||
const state: ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations };
|
||||
const containingDirectory = getDirectoryPath(containingFile);
|
||||
|
||||
const resolved = tryResolve(Extensions.TypeScript) || tryResolve(Extensions.JavaScript);
|
||||
@@ -1252,7 +1360,7 @@ namespace ts {
|
||||
return createResolvedModuleWithFailedLookupLocations(resolved && resolved.value, /*isExternalLibraryImport*/ false, failedLookupLocations);
|
||||
|
||||
function tryResolve(extensions: Extensions): SearchResult<Resolved> {
|
||||
const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loadModuleFromFileNoPackageId, failedLookupLocations, state);
|
||||
const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loadModuleFromFileNoPackageId, state);
|
||||
if (resolvedUsingSettings) {
|
||||
return { value: resolvedUsingSettings };
|
||||
}
|
||||
@@ -1261,24 +1369,24 @@ namespace ts {
|
||||
const perModuleNameCache = cache && cache.getOrCreateCacheForModuleName(moduleName);
|
||||
// Climb up parent directories looking for a module.
|
||||
const resolved = forEachAncestorDirectory(containingDirectory, directory => {
|
||||
const resolutionFromCache = tryFindNonRelativeModuleNameInCache(perModuleNameCache, moduleName, directory, traceEnabled, host, failedLookupLocations);
|
||||
const resolutionFromCache = tryFindNonRelativeModuleNameInCache(perModuleNameCache, moduleName, directory, state);
|
||||
if (resolutionFromCache) {
|
||||
return resolutionFromCache;
|
||||
}
|
||||
const searchName = normalizePath(combinePaths(directory, moduleName));
|
||||
return toSearchResult(loadModuleFromFileNoPackageId(extensions, searchName, failedLookupLocations, /*onlyRecordFailures*/ false, state));
|
||||
return toSearchResult(loadModuleFromFileNoPackageId(extensions, searchName, /*onlyRecordFailures*/ false, state));
|
||||
});
|
||||
if (resolved) {
|
||||
return resolved;
|
||||
}
|
||||
if (extensions === Extensions.TypeScript) {
|
||||
// If we didn't find the file normally, look it up in @types.
|
||||
return loadModuleFromNodeModulesAtTypes(moduleName, containingDirectory, failedLookupLocations, state);
|
||||
return loadModuleFromNearestNodeModulesDirectoryTypesScope(moduleName, containingDirectory, state);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const candidate = normalizePath(combinePaths(containingDirectory, moduleName));
|
||||
return toSearchResult(loadModuleFromFileNoPackageId(extensions, candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state));
|
||||
return toSearchResult(loadModuleFromFileNoPackageId(extensions, candidate, /*onlyRecordFailures*/ false, state));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1293,9 +1401,9 @@ namespace ts {
|
||||
if (traceEnabled) {
|
||||
trace(host, Diagnostics.Auto_discovery_for_typings_is_enabled_in_project_0_Running_extra_resolution_pass_for_module_1_using_cache_location_2, projectName, moduleName, globalCache);
|
||||
}
|
||||
const state: ModuleResolutionState = { compilerOptions, host, traceEnabled };
|
||||
const failedLookupLocations: string[] = [];
|
||||
const resolved = loadModuleFromNodeModulesOneLevel(Extensions.DtsOnly, moduleName, globalCache, failedLookupLocations, state);
|
||||
const state: ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations };
|
||||
const resolved = loadModuleFromImmediateNodeModulesDirectory(Extensions.DtsOnly, moduleName, globalCache, state, /*typesScopeOnly*/ false);
|
||||
return createResolvedModuleWithFailedLookupLocations(resolved, /*isExternalLibraryImport*/ true, failedLookupLocations);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace ts.moduleSpecifiers {
|
||||
function getPreferencesForUpdate(compilerOptions: CompilerOptions, oldImportSpecifier: string): Preferences {
|
||||
return {
|
||||
relativePreference: isExternalModuleNameRelative(oldImportSpecifier) ? RelativePreference.Relative : RelativePreference.NonRelative,
|
||||
ending: hasJavaScriptOrJsonFileExtension(oldImportSpecifier) ? Ending.JsExtension
|
||||
ending: hasJSOrJsonFileExtension(oldImportSpecifier) ? Ending.JsExtension
|
||||
: getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeJs || endsWith(oldImportSpecifier, "index") ? Ending.Index : Ending.Minimal,
|
||||
};
|
||||
}
|
||||
@@ -148,7 +148,7 @@ namespace ts.moduleSpecifiers {
|
||||
}
|
||||
|
||||
function usesJsExtensionOnImports({ imports }: SourceFile): boolean {
|
||||
return firstDefined(imports, ({ text }) => pathIsRelative(text) ? hasJavaScriptOrJsonFileExtension(text) : undefined) || false;
|
||||
return firstDefined(imports, ({ text }) => pathIsRelative(text) ? hasJSOrJsonFileExtension(text) : undefined) || false;
|
||||
}
|
||||
|
||||
function stringsEqual(a: string, b: string, getCanonicalFileName: GetCanonicalFileName): boolean {
|
||||
@@ -235,7 +235,8 @@ namespace ts.moduleSpecifiers {
|
||||
const suffix = pattern.substr(indexOfStar + 1);
|
||||
if (relativeToBaseUrl.length >= prefix.length + suffix.length &&
|
||||
startsWith(relativeToBaseUrl, prefix) &&
|
||||
endsWith(relativeToBaseUrl, suffix)) {
|
||||
endsWith(relativeToBaseUrl, suffix) ||
|
||||
!suffix && relativeToBaseUrl === removeTrailingDirectorySeparator(prefix)) {
|
||||
const matchedStar = relativeToBaseUrl.substr(prefix.length, relativeToBaseUrl.length - suffix.length);
|
||||
return key.replace("*", matchedStar);
|
||||
}
|
||||
@@ -264,6 +265,26 @@ namespace ts.moduleSpecifiers {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const packageRootPath = moduleFileName.substring(0, parts.packageRootIndex);
|
||||
const packageJsonPath = combinePaths(packageRootPath, "package.json");
|
||||
const packageJsonContent = host.fileExists!(packageJsonPath)
|
||||
? JSON.parse(host.readFile!(packageJsonPath)!)
|
||||
: undefined;
|
||||
const versionPaths = packageJsonContent && packageJsonContent.typesVersions
|
||||
? getPackageJsonTypesVersionsPaths(packageJsonContent.typesVersions)
|
||||
: undefined;
|
||||
if (versionPaths) {
|
||||
const subModuleName = moduleFileName.slice(parts.packageRootIndex + 1);
|
||||
const fromPaths = tryGetModuleNameFromPaths(
|
||||
removeFileExtension(subModuleName),
|
||||
removeExtensionAndIndexPostFix(subModuleName, Ending.Minimal, options),
|
||||
versionPaths.paths
|
||||
);
|
||||
if (fromPaths !== undefined) {
|
||||
moduleFileName = combinePaths(moduleFileName.slice(0, parts.packageRootIndex), fromPaths);
|
||||
}
|
||||
}
|
||||
|
||||
// Simplify the full file path to something that can be resolved by Node.
|
||||
|
||||
// If the module could be imported by a directory name, use that directory's name
|
||||
@@ -274,23 +295,18 @@ namespace ts.moduleSpecifiers {
|
||||
|
||||
// If the module was found in @types, get the actual Node package name
|
||||
const nodeModulesDirectoryName = moduleSpecifier.substring(parts.topLevelPackageNameIndex + 1);
|
||||
const packageName = getPackageNameFromAtTypesDirectory(nodeModulesDirectoryName);
|
||||
const packageName = getPackageNameFromTypesPackageName(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
|
||||
const packageRootPath = path.substring(0, parts.packageRootIndex);
|
||||
const packageJsonPath = combinePaths(packageRootPath, "package.json");
|
||||
if (host.fileExists!(packageJsonPath)) { // TODO: GH#18217
|
||||
const packageJsonContent = JSON.parse(host.readFile!(packageJsonPath)!);
|
||||
if (packageJsonContent) {
|
||||
const mainFileRelative = packageJsonContent.typings || packageJsonContent.types || packageJsonContent.main;
|
||||
if (mainFileRelative) {
|
||||
const mainExportFile = toPath(mainFileRelative, packageRootPath, getCanonicalFileName);
|
||||
if (removeFileExtension(mainExportFile) === removeFileExtension(getCanonicalFileName(path))) {
|
||||
return packageRootPath;
|
||||
}
|
||||
if (packageJsonContent) {
|
||||
const mainFileRelative = packageJsonContent.typings || packageJsonContent.types || packageJsonContent.main;
|
||||
if (mainFileRelative) {
|
||||
const mainExportFile = toPath(mainFileRelative, packageRootPath, getCanonicalFileName);
|
||||
if (removeFileExtension(mainExportFile) === removeFileExtension(getCanonicalFileName(path))) {
|
||||
return packageRootPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -399,13 +415,13 @@ namespace ts.moduleSpecifiers {
|
||||
case Ending.Index:
|
||||
return noExtension;
|
||||
case Ending.JsExtension:
|
||||
return noExtension + getJavaScriptExtensionForFile(fileName, options);
|
||||
return noExtension + getJSExtensionForFile(fileName, options);
|
||||
default:
|
||||
return Debug.assertNever(ending);
|
||||
}
|
||||
}
|
||||
|
||||
function getJavaScriptExtensionForFile(fileName: string, options: CompilerOptions): Extension {
|
||||
function getJSExtensionForFile(fileName: string, options: CompilerOptions): Extension {
|
||||
const ext = extensionFromPath(fileName);
|
||||
switch (ext) {
|
||||
case Extension.Ts:
|
||||
|
||||
+28
-26
@@ -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) ||
|
||||
@@ -4713,8 +4715,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);
|
||||
}
|
||||
@@ -6513,7 +6517,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function skipWhitespaceOrAsterisk(): void {
|
||||
function skipWhitespaceOrAsterisk(next: () => void): void {
|
||||
if (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) {
|
||||
if (lookAhead(isNextNonwhitespaceTokenEndOfFile)) {
|
||||
return; // Don't skip whitespace prior to EoF (or end of comment) - that shouldn't be included in any node's range
|
||||
@@ -6528,7 +6532,7 @@ namespace ts {
|
||||
else if (token() === SyntaxKind.AsteriskToken) {
|
||||
precedingLineBreak = false;
|
||||
}
|
||||
nextJSDocToken();
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6538,8 +6542,9 @@ namespace ts {
|
||||
atToken.end = scanner.getTextPos();
|
||||
nextJSDocToken();
|
||||
|
||||
const tagName = parseJSDocIdentifierName();
|
||||
skipWhitespaceOrAsterisk();
|
||||
// Use 'nextToken' instead of 'nextJsDocToken' so we can parse a type like 'number' in `@enum number`
|
||||
const tagName = parseJSDocIdentifierName(/*message*/ undefined, nextToken);
|
||||
skipWhitespaceOrAsterisk(nextToken);
|
||||
|
||||
let tag: JSDocTag | undefined;
|
||||
switch (tagName.escapedText) {
|
||||
@@ -6683,7 +6688,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function tryParseTypeExpression(): JSDocTypeExpression | undefined {
|
||||
skipWhitespaceOrAsterisk();
|
||||
skipWhitespaceOrAsterisk(nextJSDocToken);
|
||||
return token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined;
|
||||
}
|
||||
|
||||
@@ -6720,10 +6725,10 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function parseParameterOrPropertyTag(atToken: AtToken, tagName: Identifier, target: PropertyLikeParse, indent: number | undefined): JSDocParameterTag | JSDocPropertyTag {
|
||||
function parseParameterOrPropertyTag(atToken: AtToken, tagName: Identifier, target: PropertyLikeParse, indent: number): JSDocParameterTag | JSDocPropertyTag {
|
||||
let typeExpression = tryParseTypeExpression();
|
||||
let isNameFirst = !typeExpression;
|
||||
skipWhitespaceOrAsterisk();
|
||||
skipWhitespaceOrAsterisk(nextJSDocToken);
|
||||
|
||||
const { name, isBracketed } = parseBracketNameInPropertyAndParamTag();
|
||||
skipWhitespace();
|
||||
@@ -6735,9 +6740,8 @@ namespace ts {
|
||||
const result = target === PropertyLikeParse.Property ?
|
||||
<JSDocPropertyTag>createNode(SyntaxKind.JSDocPropertyTag, atToken.pos) :
|
||||
<JSDocParameterTag>createNode(SyntaxKind.JSDocParameterTag, atToken.pos);
|
||||
let comment: string | undefined;
|
||||
if (indent !== undefined) comment = parseTagComments(indent + scanner.getStartPos() - atToken.pos);
|
||||
const nestedTypeLiteral = target !== PropertyLikeParse.CallbackParameter && parseNestedTypeLiteral(typeExpression, name, target);
|
||||
const comment = parseTagComments(indent + scanner.getStartPos() - atToken.pos);
|
||||
const nestedTypeLiteral = target !== PropertyLikeParse.CallbackParameter && parseNestedTypeLiteral(typeExpression, name, target, indent);
|
||||
if (nestedTypeLiteral) {
|
||||
typeExpression = nestedTypeLiteral;
|
||||
isNameFirst = true;
|
||||
@@ -6752,14 +6756,14 @@ namespace ts {
|
||||
return finishNode(result);
|
||||
}
|
||||
|
||||
function parseNestedTypeLiteral(typeExpression: JSDocTypeExpression | undefined, name: EntityName, target: PropertyLikeParse) {
|
||||
function parseNestedTypeLiteral(typeExpression: JSDocTypeExpression | undefined, name: EntityName, target: PropertyLikeParse, indent: number) {
|
||||
if (typeExpression && isObjectOrObjectArrayTypeReference(typeExpression.type)) {
|
||||
const typeLiteralExpression = <JSDocTypeExpression>createNode(SyntaxKind.JSDocTypeExpression, scanner.getTokenPos());
|
||||
let child: JSDocPropertyLikeTag | JSDocTypeTag | false;
|
||||
let jsdocTypeLiteral: JSDocTypeLiteral;
|
||||
const start = scanner.getStartPos();
|
||||
let children: JSDocPropertyLikeTag[] | undefined;
|
||||
while (child = tryParse(() => parseChildParameterOrPropertyTag(target, name))) {
|
||||
while (child = tryParse(() => parseChildParameterOrPropertyTag(target, indent, name))) {
|
||||
if (child.kind === SyntaxKind.JSDocParameterTag || child.kind === SyntaxKind.JSDocPropertyTag) {
|
||||
children = append(children, child);
|
||||
}
|
||||
@@ -6858,7 +6862,7 @@ namespace ts {
|
||||
|
||||
function parseTypedefTag(atToken: AtToken, tagName: Identifier, indent: number): JSDocTypedefTag {
|
||||
const typeExpression = tryParseTypeExpression();
|
||||
skipWhitespaceOrAsterisk();
|
||||
skipWhitespaceOrAsterisk(nextJSDocToken);
|
||||
|
||||
const typedefTag = <JSDocTypedefTag>createNode(SyntaxKind.JSDocTypedefTag, atToken.pos);
|
||||
typedefTag.atToken = atToken;
|
||||
@@ -6875,7 +6879,7 @@ namespace ts {
|
||||
let jsdocTypeLiteral: JSDocTypeLiteral | undefined;
|
||||
let childTypeTag: JSDocTypeTag | undefined;
|
||||
const start = atToken.pos;
|
||||
while (child = tryParse(() => parseChildPropertyTag())) {
|
||||
while (child = tryParse(() => parseChildPropertyTag(indent))) {
|
||||
if (!jsdocTypeLiteral) {
|
||||
jsdocTypeLiteral = <JSDocTypeLiteral>createNode(SyntaxKind.JSDocTypeLiteral, start);
|
||||
}
|
||||
@@ -6941,7 +6945,7 @@ namespace ts {
|
||||
const start = scanner.getStartPos();
|
||||
const jsdocSignature = createNode(SyntaxKind.JSDocSignature, start) as JSDocSignature;
|
||||
jsdocSignature.parameters = [];
|
||||
while (child = tryParse(() => parseChildParameterOrPropertyTag(PropertyLikeParse.CallbackParameter) as JSDocParameterTag)) {
|
||||
while (child = tryParse(() => parseChildParameterOrPropertyTag(PropertyLikeParse.CallbackParameter, indent) as JSDocParameterTag)) {
|
||||
jsdocSignature.parameters = append(jsdocSignature.parameters as MutableNodeArray<JSDocParameterTag>, child);
|
||||
}
|
||||
const returnTag = tryParse(() => {
|
||||
@@ -6984,18 +6988,18 @@ namespace ts {
|
||||
return a.escapedText === b.escapedText;
|
||||
}
|
||||
|
||||
function parseChildPropertyTag() {
|
||||
return parseChildParameterOrPropertyTag(PropertyLikeParse.Property) as JSDocTypeTag | JSDocPropertyTag | false;
|
||||
function parseChildPropertyTag(indent: number) {
|
||||
return parseChildParameterOrPropertyTag(PropertyLikeParse.Property, indent) as JSDocTypeTag | JSDocPropertyTag | false;
|
||||
}
|
||||
|
||||
function parseChildParameterOrPropertyTag(target: PropertyLikeParse, name?: EntityName): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false {
|
||||
function parseChildParameterOrPropertyTag(target: PropertyLikeParse, indent: number, name?: EntityName): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false {
|
||||
let canParseTag = true;
|
||||
let seenAsterisk = false;
|
||||
while (true) {
|
||||
switch (nextJSDocToken()) {
|
||||
case SyntaxKind.AtToken:
|
||||
if (canParseTag) {
|
||||
const child = tryParseChildTag(target);
|
||||
const child = tryParseChildTag(target, indent);
|
||||
if (child && (child.kind === SyntaxKind.JSDocParameterTag || child.kind === SyntaxKind.JSDocPropertyTag) &&
|
||||
target !== PropertyLikeParse.CallbackParameter &&
|
||||
name && (ts.isIdentifier(child.name) || !escapedTextsEqual(name, child.name.left))) {
|
||||
@@ -7024,7 +7028,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function tryParseChildTag(target: PropertyLikeParse): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false {
|
||||
function tryParseChildTag(target: PropertyLikeParse, indent: number): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false {
|
||||
Debug.assert(token() === SyntaxKind.AtToken);
|
||||
const atToken = <AtToken>createNode(SyntaxKind.AtToken);
|
||||
atToken.end = scanner.getTextPos();
|
||||
@@ -7051,9 +7055,7 @@ namespace ts {
|
||||
if (!(target & t)) {
|
||||
return false;
|
||||
}
|
||||
const tag = parseParameterOrPropertyTag(atToken, tagName, target, /*indent*/ undefined);
|
||||
tag.comment = parseTagComments(tag.end - tag.pos);
|
||||
return tag;
|
||||
return parseParameterOrPropertyTag(atToken, tagName, target, indent);
|
||||
}
|
||||
|
||||
function parseTemplateTag(atToken: AtToken, tagName: Identifier): JSDocTemplateTag {
|
||||
@@ -7113,7 +7115,7 @@ namespace ts {
|
||||
return entity;
|
||||
}
|
||||
|
||||
function parseJSDocIdentifierName(message?: DiagnosticMessage): Identifier {
|
||||
function parseJSDocIdentifierName(message?: DiagnosticMessage, next: () => void = nextJSDocToken): Identifier {
|
||||
if (!tokenIsIdentifierOrKeyword(token())) {
|
||||
return createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ !message, message || Diagnostics.Identifier_expected);
|
||||
}
|
||||
@@ -7124,7 +7126,7 @@ namespace ts {
|
||||
result.escapedText = escapeLeadingUnderscores(scanner.getTokenText());
|
||||
finishNode(result, end);
|
||||
|
||||
nextJSDocToken();
|
||||
next();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
+67
-47
@@ -250,7 +250,7 @@ namespace ts {
|
||||
Blue = "\u001b[94m",
|
||||
Cyan = "\u001b[96m"
|
||||
}
|
||||
const gutterStyleSequence = "\u001b[30;47m";
|
||||
const gutterStyleSequence = "\u001b[7m";
|
||||
const gutterSeparator = " ";
|
||||
const resetEscapeSequence = "\u001b[0m";
|
||||
const ellipsis = "...";
|
||||
@@ -442,6 +442,7 @@ namespace ts {
|
||||
fileExists: (fileName: string) => boolean,
|
||||
hasInvalidatedResolution: HasInvalidatedResolution,
|
||||
hasChangedAutomaticTypeDirectiveNames: boolean,
|
||||
projectReferences: ReadonlyArray<ProjectReference> | undefined
|
||||
): boolean {
|
||||
// If we haven't created a program yet or have changed automatic type directives, then it is not up-to-date
|
||||
if (!program || hasChangedAutomaticTypeDirectiveNames) {
|
||||
@@ -453,6 +454,11 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If project references dont match
|
||||
if (!arrayIsEqualTo(program.getProjectReferences(), projectReferences)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If any file is not up-to-date, then the whole program is not up-to-date
|
||||
if (program.getSourceFiles().some(sourceFileNotUptoDate)) {
|
||||
return false;
|
||||
@@ -759,7 +765,8 @@ namespace ts {
|
||||
isEmittedFile,
|
||||
getConfigFileParsingDiagnostics,
|
||||
getResolvedModuleWithFailedLookupLocationsFromCache,
|
||||
getProjectReferences
|
||||
getProjectReferences,
|
||||
getResolvedProjectReferences
|
||||
};
|
||||
|
||||
verifyCompilerOptions();
|
||||
@@ -953,8 +960,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.
|
||||
@@ -962,16 +972,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;
|
||||
@@ -1009,15 +1014,22 @@ namespace ts {
|
||||
}
|
||||
|
||||
// Check if any referenced project tsconfig files are different
|
||||
const oldRefs = oldProgram.getProjectReferences();
|
||||
|
||||
// If array of references is changed, we cant resue old program
|
||||
const oldProjectReferences = oldProgram.getProjectReferences();
|
||||
if (!arrayIsEqualTo(oldProjectReferences!, projectReferences, projectReferenceIsEqualTo)) {
|
||||
return oldProgram.structureIsReused = StructureIsReused.Not;
|
||||
}
|
||||
|
||||
// Check the json files for the project references
|
||||
const oldRefs = oldProgram.getResolvedProjectReferences();
|
||||
if (projectReferences) {
|
||||
if (!oldRefs) {
|
||||
return oldProgram.structureIsReused = StructureIsReused.Not;
|
||||
}
|
||||
// Resolved project referenced should be array if projectReferences provided are array
|
||||
Debug.assert(!!oldRefs);
|
||||
for (let i = 0; i < projectReferences.length; i++) {
|
||||
const oldRef = oldRefs[i];
|
||||
const oldRef = oldRefs![i];
|
||||
const newRef = parseProjectReferenceConfigFile(projectReferences[i]);
|
||||
if (oldRef) {
|
||||
const newRef = parseProjectReferenceConfigFile(projectReferences[i]);
|
||||
if (!newRef || newRef.sourceFile !== oldRef.sourceFile) {
|
||||
// Resolved project reference has gone missing or changed
|
||||
return oldProgram.structureIsReused = StructureIsReused.Not;
|
||||
@@ -1025,16 +1037,15 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
// A previously-unresolved reference may be resolved now
|
||||
if (parseProjectReferenceConfigFile(projectReferences[i]) !== undefined) {
|
||||
if (newRef !== undefined) {
|
||||
return oldProgram.structureIsReused = StructureIsReused.Not;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (oldRefs) {
|
||||
return oldProgram.structureIsReused = StructureIsReused.Not;
|
||||
}
|
||||
// Resolved project referenced should be undefined if projectReferences is undefined
|
||||
Debug.assert(!oldRefs);
|
||||
}
|
||||
|
||||
// check if program source files has changed in the way that can affect structure of the program
|
||||
@@ -1180,7 +1191,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);
|
||||
@@ -1220,7 +1232,7 @@ namespace ts {
|
||||
fileProcessingDiagnostics.reattachFileDiagnostics(modifiedFile.newFile);
|
||||
}
|
||||
resolvedTypeReferenceDirectives = oldProgram.getResolvedTypeReferenceDirectives();
|
||||
resolvedProjectReferences = oldProgram.getProjectReferences();
|
||||
resolvedProjectReferences = oldProgram.getResolvedProjectReferences();
|
||||
|
||||
sourceFileToPackageName = oldProgram.sourceFileToPackageName;
|
||||
redirectTargetsMap = oldProgram.redirectTargetsMap;
|
||||
@@ -1258,10 +1270,14 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
function getProjectReferences() {
|
||||
function getResolvedProjectReferences() {
|
||||
return resolvedProjectReferences;
|
||||
}
|
||||
|
||||
function getProjectReferences() {
|
||||
return projectReferences;
|
||||
}
|
||||
|
||||
function getPrependNodes(): InputFiles[] {
|
||||
if (!projectReferences) {
|
||||
return emptyArray;
|
||||
@@ -1439,9 +1455,9 @@ namespace ts {
|
||||
function getSyntacticDiagnosticsForFile(sourceFile: SourceFile): ReadonlyArray<DiagnosticWithLocation> {
|
||||
// For JavaScript files, we report semantic errors for using TypeScript-only
|
||||
// constructs from within a JavaScript file as syntactic errors.
|
||||
if (isSourceFileJavaScript(sourceFile)) {
|
||||
if (isSourceFileJS(sourceFile)) {
|
||||
if (!sourceFile.additionalSyntacticDiagnostics) {
|
||||
sourceFile.additionalSyntacticDiagnostics = getJavaScriptSyntacticDiagnosticsForFile(sourceFile);
|
||||
sourceFile.additionalSyntacticDiagnostics = getJSSyntacticDiagnosticsForFile(sourceFile);
|
||||
}
|
||||
return concatenate(sourceFile.additionalSyntacticDiagnostics, sourceFile.parseDiagnostics);
|
||||
}
|
||||
@@ -1539,7 +1555,7 @@ namespace ts {
|
||||
return true;
|
||||
}
|
||||
|
||||
function getJavaScriptSyntacticDiagnosticsForFile(sourceFile: SourceFile): DiagnosticWithLocation[] {
|
||||
function getJSSyntacticDiagnosticsForFile(sourceFile: SourceFile): DiagnosticWithLocation[] {
|
||||
return runWithCancellationToken(() => {
|
||||
const diagnostics: DiagnosticWithLocation[] = [];
|
||||
let parent: Node = sourceFile;
|
||||
@@ -1802,7 +1818,7 @@ namespace ts {
|
||||
return;
|
||||
}
|
||||
|
||||
const isJavaScriptFile = isSourceFileJavaScript(file);
|
||||
const isJavaScriptFile = isSourceFileJS(file);
|
||||
const isExternalModuleFile = isExternalModule(file);
|
||||
|
||||
// file.imports may not be undefined if there exists dynamic import
|
||||
@@ -2274,7 +2290,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
const isFromNodeModulesSearch = resolution.isExternalLibraryImport;
|
||||
const isJsFile = !resolutionExtensionIsTypeScriptOrJson(resolution.extension);
|
||||
const isJsFile = !resolutionExtensionIsTSOrJson(resolution.extension);
|
||||
const isJsFileFromNodeModules = isFromNodeModulesSearch && isJsFile;
|
||||
const resolvedFileName = resolution.resolvedFileName;
|
||||
|
||||
@@ -2296,7 +2312,7 @@ namespace ts {
|
||||
&& i < file.imports.length
|
||||
&& !elideImport
|
||||
&& !(isJsFile && !options.allowJs)
|
||||
&& (isInJavaScriptFile(file.imports[i]) || !(file.imports[i].flags & NodeFlags.JSDoc));
|
||||
&& (isInJSFile(file.imports[i]) || !(file.imports[i].flags & NodeFlags.JSDoc));
|
||||
|
||||
if (elideImport) {
|
||||
modulesWithElidedImports.set(file.path, true);
|
||||
@@ -2342,7 +2358,7 @@ namespace ts {
|
||||
|
||||
function parseProjectReferenceConfigFile(ref: ProjectReference): { commandLine: ParsedCommandLine, sourceFile: SourceFile } | undefined {
|
||||
// The actual filename (i.e. add "/tsconfig.json" if necessary)
|
||||
const refPath = resolveProjectReferencePath(host, ref);
|
||||
const refPath = resolveProjectReferencePath(ref);
|
||||
// An absolute path pointing to the containing directory of the config file
|
||||
const basePath = getNormalizedAbsolutePath(getDirectoryPath(refPath), host.getCurrentDirectory());
|
||||
const sourceFile = host.getSourceFile(refPath, ScriptTarget.JSON) as JsonSourceFile | undefined;
|
||||
@@ -2432,12 +2448,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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2549,9 +2567,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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2793,7 +2811,7 @@ namespace ts {
|
||||
return containsPath(options.outDir, filePath, currentDirectory, !host.useCaseSensitiveFileNames());
|
||||
}
|
||||
|
||||
if (fileExtensionIsOneOf(filePath, supportedJavascriptExtensions) || fileExtensionIs(filePath, Extension.Dts)) {
|
||||
if (fileExtensionIsOneOf(filePath, supportedJSExtensions) || fileExtensionIs(filePath, Extension.Dts)) {
|
||||
// Otherwise just check if sourceFile with the name exists
|
||||
const filePathWithoutExtension = removeFileExtension(filePath);
|
||||
return !!getSourceFileByPath((filePathWithoutExtension + Extension.Ts) as Path) ||
|
||||
@@ -2819,18 +2837,20 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
export interface ResolveProjectReferencePathHost {
|
||||
// For backward compatibility
|
||||
/** @deprecated */ export interface ResolveProjectReferencePathHost {
|
||||
fileExists(fileName: string): boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the target config filename of a project reference.
|
||||
* Note: The file might not exist.
|
||||
*/
|
||||
export function resolveProjectReferencePath(host: ResolveProjectReferencePathHost, ref: ProjectReference): ResolvedConfigFileName {
|
||||
if (!host.fileExists(ref.path)) {
|
||||
return combinePaths(ref.path, "tsconfig.json") as ResolvedConfigFileName;
|
||||
}
|
||||
return ref.path as ResolvedConfigFileName;
|
||||
export function resolveProjectReferencePath(ref: ProjectReference): ResolvedConfigFileName;
|
||||
/** @deprecated */ export function resolveProjectReferencePath(host: ResolveProjectReferencePathHost, ref: ProjectReference): ResolvedConfigFileName;
|
||||
export function resolveProjectReferencePath(hostOrRef: ResolveProjectReferencePathHost | ProjectReference, ref?: ProjectReference): ResolvedConfigFileName {
|
||||
const passedInRef = ref ? ref : hostOrRef as ProjectReference;
|
||||
return resolveConfigFileProjectName(passedInRef.path);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
||||
@@ -226,7 +226,7 @@ namespace ts {
|
||||
|
||||
// otherwise try to load typings from @types
|
||||
const globalCache = resolutionHost.getGlobalCache();
|
||||
if (globalCache !== undefined && !isExternalModuleNameRelative(moduleName) && !(primaryResult.resolvedModule && extensionIsTypeScript(primaryResult.resolvedModule.extension))) {
|
||||
if (globalCache !== undefined && !isExternalModuleNameRelative(moduleName) && !(primaryResult.resolvedModule && extensionIsTS(primaryResult.resolvedModule.extension))) {
|
||||
// create different collection of failed lookup locations for second pass
|
||||
// if it will fail and we've already found something during the first pass - we don't want to pollute its results
|
||||
const { resolvedModule, failedLookupLocations } = loadModuleFromGlobalCache(moduleName, resolutionHost.projectName, compilerOptions, host, globalCache);
|
||||
|
||||
@@ -1396,6 +1396,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;
|
||||
|
||||
@@ -0,0 +1,391 @@
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
// https://semver.org/#spec-item-2
|
||||
// > A normal version number MUST take the form X.Y.Z where X, Y, and Z are non-negative
|
||||
// > integers, and MUST NOT contain leading zeroes. X is the major version, Y is the minor
|
||||
// > version, and Z is the patch version. Each element MUST increase numerically.
|
||||
//
|
||||
// NOTE: We differ here in that we allow X and X.Y, with missing parts having the default
|
||||
// value of `0`.
|
||||
const versionRegExp = /^(0|[1-9]\d*)(?:\.(0|[1-9]\d*)(?:\.(0|[1-9]\d*)(?:\-([a-z0-9-.]+))?(?:\+([a-z0-9-.]+))?)?)?$/i;
|
||||
|
||||
// https://semver.org/#spec-item-9
|
||||
// > A pre-release version MAY be denoted by appending a hyphen and a series of dot separated
|
||||
// > identifiers immediately following the patch version. Identifiers MUST comprise only ASCII
|
||||
// > alphanumerics and hyphen [0-9A-Za-z-]. Identifiers MUST NOT be empty. Numeric identifiers
|
||||
// > MUST NOT include leading zeroes.
|
||||
const prereleaseRegExp = /^(?:0|[1-9]\d*|[a-z-][a-z0-9-]*)(?:\.(?:0|[1-9]\d*|[a-z-][a-z0-9-]*))*$/i;
|
||||
|
||||
// https://semver.org/#spec-item-10
|
||||
// > Build metadata MAY be denoted by appending a plus sign and a series of dot separated
|
||||
// > identifiers immediately following the patch or pre-release version. Identifiers MUST
|
||||
// > comprise only ASCII alphanumerics and hyphen [0-9A-Za-z-]. Identifiers MUST NOT be empty.
|
||||
const buildRegExp = /^[a-z0-9-]+(?:\.[a-z0-9-]+)*$/i;
|
||||
|
||||
// https://semver.org/#spec-item-9
|
||||
// > Numeric identifiers MUST NOT include leading zeroes.
|
||||
const numericIdentifierRegExp = /^(0|[1-9]\d*)$/;
|
||||
|
||||
/**
|
||||
* Describes a precise semantic version number, https://semver.org
|
||||
*/
|
||||
export class Version {
|
||||
static readonly zero = new Version(0, 0, 0);
|
||||
|
||||
readonly major: number;
|
||||
readonly minor: number;
|
||||
readonly patch: number;
|
||||
readonly prerelease: ReadonlyArray<string>;
|
||||
readonly build: ReadonlyArray<string>;
|
||||
|
||||
constructor(text: string);
|
||||
constructor(major: number, minor?: number, patch?: number, prerelease?: string, build?: string);
|
||||
constructor(major: number | string, minor = 0, patch = 0, prerelease = "", build = "") {
|
||||
if (typeof major === "string") {
|
||||
const result = Debug.assertDefined(tryParseComponents(major), "Invalid version");
|
||||
({ major, minor, patch, prerelease, build } = result);
|
||||
}
|
||||
|
||||
Debug.assert(major >= 0, "Invalid argument: major");
|
||||
Debug.assert(minor >= 0, "Invalid argument: minor");
|
||||
Debug.assert(patch >= 0, "Invalid argument: patch");
|
||||
Debug.assert(!prerelease || prereleaseRegExp.test(prerelease), "Invalid argument: prerelease");
|
||||
Debug.assert(!build || buildRegExp.test(build), "Invalid argument: build");
|
||||
this.major = major;
|
||||
this.minor = minor;
|
||||
this.patch = patch;
|
||||
this.prerelease = prerelease ? prerelease.split(".") : emptyArray;
|
||||
this.build = build ? build.split(".") : emptyArray;
|
||||
}
|
||||
|
||||
static tryParse(text: string) {
|
||||
const result = tryParseComponents(text);
|
||||
if (!result) return undefined;
|
||||
|
||||
const { major, minor, patch, prerelease, build } = result;
|
||||
return new Version(major, minor, patch, prerelease, build);
|
||||
}
|
||||
|
||||
compareTo(other: Version | undefined) {
|
||||
// https://semver.org/#spec-item-11
|
||||
// > Precedence is determined by the first difference when comparing each of these
|
||||
// > identifiers from left to right as follows: Major, minor, and patch versions are
|
||||
// > always compared numerically.
|
||||
//
|
||||
// https://semver.org/#spec-item-11
|
||||
// > Precedence for two pre-release versions with the same major, minor, and patch version
|
||||
// > MUST be determined by comparing each dot separated identifier from left to right until
|
||||
// > a difference is found [...]
|
||||
//
|
||||
// https://semver.org/#spec-item-11
|
||||
// > Build metadata does not figure into precedence
|
||||
if (this === other) return Comparison.EqualTo;
|
||||
if (other === undefined) return Comparison.GreaterThan;
|
||||
return compareValues(this.major, other.major)
|
||||
|| compareValues(this.minor, other.minor)
|
||||
|| compareValues(this.patch, other.patch)
|
||||
|| comparePrerelaseIdentifiers(this.prerelease, other.prerelease);
|
||||
}
|
||||
|
||||
increment(field: "major" | "minor" | "patch") {
|
||||
switch (field) {
|
||||
case "major": return new Version(this.major + 1, 0, 0);
|
||||
case "minor": return new Version(this.major, this.minor + 1, 0);
|
||||
case "patch": return new Version(this.major, this.minor, this.patch + 1);
|
||||
default: return Debug.assertNever(field);
|
||||
}
|
||||
}
|
||||
|
||||
toString() {
|
||||
let result = `${this.major}.${this.minor}.${this.patch}`;
|
||||
if (some(this.prerelease)) result += `-${this.prerelease.join(".")}`;
|
||||
if (some(this.build)) result += `+${this.build.join(".")}`;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
function tryParseComponents(text: string) {
|
||||
const match = versionRegExp.exec(text);
|
||||
if (!match) return undefined;
|
||||
|
||||
const [, major, minor = "0", patch = "0", prerelease = "", build = ""] = match;
|
||||
if (prerelease && !prereleaseRegExp.test(prerelease)) return undefined;
|
||||
if (build && !buildRegExp.test(build)) return undefined;
|
||||
return {
|
||||
major: parseInt(major, 10),
|
||||
minor: parseInt(minor, 10),
|
||||
patch: parseInt(patch, 10),
|
||||
prerelease,
|
||||
build
|
||||
};
|
||||
}
|
||||
|
||||
function comparePrerelaseIdentifiers(left: ReadonlyArray<string>, right: ReadonlyArray<string>) {
|
||||
// https://semver.org/#spec-item-11
|
||||
// > When major, minor, and patch are equal, a pre-release version has lower precedence
|
||||
// > than a normal version.
|
||||
if (left === right) return Comparison.EqualTo;
|
||||
if (left.length === 0) return right.length === 0 ? Comparison.EqualTo : Comparison.GreaterThan;
|
||||
if (right.length === 0) return Comparison.LessThan;
|
||||
|
||||
// https://semver.org/#spec-item-11
|
||||
// > Precedence for two pre-release versions with the same major, minor, and patch version
|
||||
// > MUST be determined by comparing each dot separated identifier from left to right until
|
||||
// > a difference is found [...]
|
||||
const length = Math.min(left.length, right.length);
|
||||
for (let i = 0; i < length; i++) {
|
||||
const leftIdentifier = left[i];
|
||||
const rightIdentifier = right[i];
|
||||
if (leftIdentifier === rightIdentifier) continue;
|
||||
|
||||
const leftIsNumeric = numericIdentifierRegExp.test(leftIdentifier);
|
||||
const rightIsNumeric = numericIdentifierRegExp.test(rightIdentifier);
|
||||
if (leftIsNumeric || rightIsNumeric) {
|
||||
// https://semver.org/#spec-item-11
|
||||
// > Numeric identifiers always have lower precedence than non-numeric identifiers.
|
||||
if (leftIsNumeric !== rightIsNumeric) return leftIsNumeric ? Comparison.LessThan : Comparison.GreaterThan;
|
||||
|
||||
// https://semver.org/#spec-item-11
|
||||
// > identifiers consisting of only digits are compared numerically
|
||||
const result = compareValues(+leftIdentifier, +rightIdentifier);
|
||||
if (result) return result;
|
||||
}
|
||||
else {
|
||||
// https://semver.org/#spec-item-11
|
||||
// > identifiers with letters or hyphens are compared lexically in ASCII sort order.
|
||||
const result = compareStringsCaseSensitive(leftIdentifier, rightIdentifier);
|
||||
if (result) return result;
|
||||
}
|
||||
}
|
||||
|
||||
// https://semver.org/#spec-item-11
|
||||
// > A larger set of pre-release fields has a higher precedence than a smaller set, if all
|
||||
// > of the preceding identifiers are equal.
|
||||
return compareValues(left.length, right.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes a semantic version range, per https://github.com/npm/node-semver#ranges
|
||||
*/
|
||||
export class VersionRange {
|
||||
private _alternatives: ReadonlyArray<ReadonlyArray<Comparator>>;
|
||||
|
||||
constructor(spec: string) {
|
||||
this._alternatives = spec ? Debug.assertDefined(parseRange(spec), "Invalid range spec.") : emptyArray;
|
||||
}
|
||||
|
||||
static tryParse(text: string) {
|
||||
const sets = parseRange(text);
|
||||
if (sets) {
|
||||
const range = new VersionRange("");
|
||||
range._alternatives = sets;
|
||||
return range;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
test(version: Version | string) {
|
||||
if (typeof version === "string") version = new Version(version);
|
||||
return testDisjunction(version, this._alternatives);
|
||||
}
|
||||
|
||||
toString() {
|
||||
return formatDisjunction(this._alternatives);
|
||||
}
|
||||
}
|
||||
|
||||
interface Comparator {
|
||||
readonly operator: "<" | "<=" | ">" | ">=" | "=";
|
||||
readonly operand: Version;
|
||||
}
|
||||
|
||||
// https://github.com/npm/node-semver#range-grammar
|
||||
//
|
||||
// range-set ::= range ( logical-or range ) *
|
||||
// range ::= hyphen | simple ( ' ' simple ) * | ''
|
||||
// logical-or ::= ( ' ' ) * '||' ( ' ' ) *
|
||||
const logicalOrRegExp = /\s*\|\|\s*/g;
|
||||
const whitespaceRegExp = /\s+/g;
|
||||
|
||||
// https://github.com/npm/node-semver#range-grammar
|
||||
//
|
||||
// partial ::= xr ( '.' xr ( '.' xr qualifier ? )? )?
|
||||
// xr ::= 'x' | 'X' | '*' | nr
|
||||
// nr ::= '0' | ['1'-'9'] ( ['0'-'9'] ) *
|
||||
// qualifier ::= ( '-' pre )? ( '+' build )?
|
||||
// pre ::= parts
|
||||
// build ::= parts
|
||||
// parts ::= part ( '.' part ) *
|
||||
// part ::= nr | [-0-9A-Za-z]+
|
||||
const partialRegExp = /^([xX*0]|[1-9]\d*)(?:\.([xX*0]|[1-9]\d*)(?:\.([xX*0]|[1-9]\d*)(?:-([a-z0-9-.]+))?(?:\+([a-z0-9-.]+))?)?)?$/i;
|
||||
|
||||
// https://github.com/npm/node-semver#range-grammar
|
||||
//
|
||||
// hyphen ::= partial ' - ' partial
|
||||
const hyphenRegExp = /^\s*([a-z0-9-+.*]+)\s+-\s+([a-z0-9-+.*]+)\s*$/i;
|
||||
|
||||
// https://github.com/npm/node-semver#range-grammar
|
||||
//
|
||||
// simple ::= primitive | partial | tilde | caret
|
||||
// primitive ::= ( '<' | '>' | '>=' | '<=' | '=' ) partial
|
||||
// tilde ::= '~' partial
|
||||
// caret ::= '^' partial
|
||||
const rangeRegExp = /^\s*(~|\^|<|<=|>|>=|=)?\s*([a-z0-9-+.*]+)$/i;
|
||||
|
||||
function parseRange(text: string) {
|
||||
const alternatives: Comparator[][] = [];
|
||||
for (const range of text.trim().split(logicalOrRegExp)) {
|
||||
if (!range) continue;
|
||||
const comparators: Comparator[] = [];
|
||||
const match = hyphenRegExp.exec(range);
|
||||
if (match) {
|
||||
if (!parseHyphen(match[1], match[2], comparators)) return undefined;
|
||||
}
|
||||
else {
|
||||
for (const simple of range.split(whitespaceRegExp)) {
|
||||
const match = rangeRegExp.exec(simple);
|
||||
if (!match || !parseComparator(match[1], match[2], comparators)) return undefined;
|
||||
}
|
||||
}
|
||||
alternatives.push(comparators);
|
||||
}
|
||||
return alternatives;
|
||||
}
|
||||
|
||||
function parsePartial(text: string) {
|
||||
const match = partialRegExp.exec(text);
|
||||
if (!match) return undefined;
|
||||
|
||||
const [, major, minor = "*", patch = "*", prerelease, build] = match;
|
||||
const version = new Version(
|
||||
isWildcard(major) ? 0 : parseInt(major, 10),
|
||||
isWildcard(major) || isWildcard(minor) ? 0 : parseInt(minor, 10),
|
||||
isWildcard(major) || isWildcard(minor) || isWildcard(patch) ? 0 : parseInt(patch, 10),
|
||||
prerelease,
|
||||
build);
|
||||
|
||||
return { version, major, minor, patch };
|
||||
}
|
||||
|
||||
function parseHyphen(left: string, right: string, comparators: Comparator[]) {
|
||||
const leftResult = parsePartial(left);
|
||||
if (!leftResult) return false;
|
||||
|
||||
const rightResult = parsePartial(right);
|
||||
if (!rightResult) return false;
|
||||
|
||||
if (!isWildcard(leftResult.major)) {
|
||||
comparators.push(createComparator(">=", leftResult.version));
|
||||
}
|
||||
|
||||
if (!isWildcard(rightResult.major)) {
|
||||
comparators.push(
|
||||
isWildcard(rightResult.minor) ? createComparator("<", rightResult.version.increment("major")) :
|
||||
isWildcard(rightResult.patch) ? createComparator("<", rightResult.version.increment("minor")) :
|
||||
createComparator("<=", rightResult.version));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function parseComparator(operator: string, text: string, comparators: Comparator[]) {
|
||||
const result = parsePartial(text);
|
||||
if (!result) return false;
|
||||
|
||||
const { version, major, minor, patch } = result;
|
||||
if (!isWildcard(major)) {
|
||||
switch (operator) {
|
||||
case "~":
|
||||
comparators.push(createComparator(">=", version));
|
||||
comparators.push(createComparator("<", version.increment(
|
||||
isWildcard(minor) ? "major" :
|
||||
"minor")));
|
||||
break;
|
||||
case "^":
|
||||
comparators.push(createComparator(">=", version));
|
||||
comparators.push(createComparator("<", version.increment(
|
||||
version.major > 0 || isWildcard(minor) ? "major" :
|
||||
version.minor > 0 || isWildcard(patch) ? "minor" :
|
||||
"patch")));
|
||||
break;
|
||||
case "<":
|
||||
case ">=":
|
||||
comparators.push(createComparator(operator, version));
|
||||
break;
|
||||
case "<=":
|
||||
case ">":
|
||||
comparators.push(
|
||||
isWildcard(minor) ? createComparator(operator === "<=" ? "<" : ">=", version.increment("major")) :
|
||||
isWildcard(patch) ? createComparator(operator === "<=" ? "<" : ">=", version.increment("minor")) :
|
||||
createComparator(operator, version));
|
||||
break;
|
||||
case "=":
|
||||
case undefined:
|
||||
if (isWildcard(minor) || isWildcard(patch)) {
|
||||
comparators.push(createComparator(">=", version));
|
||||
comparators.push(createComparator("<", version.increment(isWildcard(minor) ? "major" : "minor")));
|
||||
}
|
||||
else {
|
||||
comparators.push(createComparator("=", version));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// unrecognized
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (operator === "<" || operator === ">") {
|
||||
comparators.push(createComparator("<", Version.zero));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function isWildcard(part: string) {
|
||||
return part === "*" || part === "x" || part === "X";
|
||||
}
|
||||
|
||||
function createComparator(operator: Comparator["operator"], operand: Version) {
|
||||
return { operator, operand };
|
||||
}
|
||||
|
||||
function testDisjunction(version: Version, alternatives: ReadonlyArray<ReadonlyArray<Comparator>>) {
|
||||
// an empty disjunction is treated as "*" (all versions)
|
||||
if (alternatives.length === 0) return true;
|
||||
for (const alternative of alternatives) {
|
||||
if (testAlternative(version, alternative)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function testAlternative(version: Version, comparators: ReadonlyArray<Comparator>) {
|
||||
for (const comparator of comparators) {
|
||||
if (!testComparator(version, comparator.operator, comparator.operand)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function testComparator(version: Version, operator: Comparator["operator"], operand: Version) {
|
||||
const cmp = version.compareTo(operand);
|
||||
switch (operator) {
|
||||
case "<": return cmp < 0;
|
||||
case "<=": return cmp <= 0;
|
||||
case ">": return cmp > 0;
|
||||
case ">=": return cmp >= 0;
|
||||
case "=": return cmp === 0;
|
||||
default: return Debug.assertNever(operator);
|
||||
}
|
||||
}
|
||||
|
||||
function formatDisjunction(alternatives: ReadonlyArray<ReadonlyArray<Comparator>>) {
|
||||
return map(alternatives, formatAlternative).join(" || ") || "*";
|
||||
}
|
||||
|
||||
function formatAlternative(comparators: ReadonlyArray<Comparator>) {
|
||||
return map(comparators, formatComparator).join(" ");
|
||||
}
|
||||
|
||||
function formatComparator(comparator: Comparator) {
|
||||
return `${comparator.operator}${comparator.operand}`;
|
||||
}
|
||||
}
|
||||
+10
-6
@@ -317,18 +317,22 @@ namespace ts {
|
||||
const newTime = modifiedTime.getTime();
|
||||
if (oldTime !== newTime) {
|
||||
watchedFile.mtime = modifiedTime;
|
||||
const eventKind = oldTime === 0
|
||||
? FileWatcherEventKind.Created
|
||||
: newTime === 0
|
||||
? FileWatcherEventKind.Deleted
|
||||
: FileWatcherEventKind.Changed;
|
||||
watchedFile.callback(watchedFile.fileName, eventKind);
|
||||
watchedFile.callback(watchedFile.fileName, getFileWatcherEventKind(oldTime, newTime));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function getFileWatcherEventKind(oldTime: number, newTime: number) {
|
||||
return oldTime === 0
|
||||
? FileWatcherEventKind.Created
|
||||
: newTime === 0
|
||||
? FileWatcherEventKind.Deleted
|
||||
: FileWatcherEventKind.Changed;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export interface RecursiveDirectoryWatcherHost {
|
||||
watchDirectory: HostWatchDirectory;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/*@internal*/
|
||||
namespace ts {
|
||||
export function getDeclarationDiagnostics(host: EmitHost, resolver: EmitResolver, file: SourceFile | undefined): DiagnosticWithLocation[] | undefined {
|
||||
if (file && isSourceFileJavaScript(file)) {
|
||||
if (file && isSourceFileJS(file)) {
|
||||
return []; // No declaration diagnostics for js for now
|
||||
}
|
||||
const compilerOptions = host.getCompilerOptions();
|
||||
const result = transformNodes(resolver, host, compilerOptions, file ? [file] : filter(host.getSourceFiles(), isSourceFileNotJavaScript), [transformDeclarations], /*allowDtsFiles*/ false);
|
||||
const result = transformNodes(resolver, host, compilerOptions, file ? [file] : filter(host.getSourceFiles(), isSourceFileNotJS), [transformDeclarations], /*allowDtsFiles*/ false);
|
||||
return result.diagnostics;
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ namespace ts {
|
||||
function transformRoot(node: SourceFile): SourceFile;
|
||||
function transformRoot(node: SourceFile | Bundle): SourceFile | Bundle;
|
||||
function transformRoot(node: SourceFile | Bundle) {
|
||||
if (node.kind === SyntaxKind.SourceFile && (node.isDeclarationFile || isSourceFileJavaScript(node))) {
|
||||
if (node.kind === SyntaxKind.SourceFile && (node.isDeclarationFile || isSourceFileJS(node))) {
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@ namespace ts {
|
||||
let hasNoDefaultLib = false;
|
||||
const bundle = createBundle(map(node.sourceFiles,
|
||||
sourceFile => {
|
||||
if (sourceFile.isDeclarationFile || isSourceFileJavaScript(sourceFile)) return undefined!; // Omit declaration files from bundle results, too // TODO: GH#18217
|
||||
if (sourceFile.isDeclarationFile || isSourceFileJS(sourceFile)) return undefined!; // Omit declaration files from bundle results, too // TODO: GH#18217
|
||||
hasNoDefaultLib = hasNoDefaultLib || sourceFile.hasNoDefaultLib;
|
||||
currentSourceFile = sourceFile;
|
||||
enclosingDeclaration = sourceFile;
|
||||
@@ -289,6 +289,13 @@ namespace ts {
|
||||
if (startsWith(fileName, "./") && hasExtension(fileName)) {
|
||||
fileName = fileName.substring(2);
|
||||
}
|
||||
|
||||
// omit references to files from node_modules (npm may disambiguate module
|
||||
// references when installing this package, making the path is unreliable).
|
||||
if (startsWith(fileName, "node_modules/") || fileName.indexOf("/node_modules/") !== -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
references.push({ pos: -1, end: -1, fileName });
|
||||
}
|
||||
};
|
||||
@@ -296,7 +303,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function collectReferences(sourceFile: SourceFile, ret: Map<SourceFile>) {
|
||||
if (noResolve || isSourceFileJavaScript(sourceFile)) return ret;
|
||||
if (noResolve || isSourceFileJS(sourceFile)) return ret;
|
||||
forEach(sourceFile.referencedFiles, f => {
|
||||
const elem = tryResolveScriptReference(host, sourceFile, f);
|
||||
if (elem) {
|
||||
@@ -982,7 +989,7 @@ namespace ts {
|
||||
ensureType(input, input.type),
|
||||
/*body*/ undefined
|
||||
));
|
||||
if (clean && resolver.isJSContainerFunctionDeclaration(input)) {
|
||||
if (clean && resolver.isExpandoFunctionDeclaration(input)) {
|
||||
const declarations = mapDefined(resolver.getPropertiesOfContainerFunction(input), p => {
|
||||
if (!isPropertyAccessExpression(p.valueDeclaration)) {
|
||||
return undefined;
|
||||
@@ -1324,12 +1331,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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
+476
-446
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,7 @@
|
||||
"files": [
|
||||
"core.ts",
|
||||
"performance.ts",
|
||||
"semver.ts",
|
||||
|
||||
"types.ts",
|
||||
"sys.ts",
|
||||
|
||||
+25
-12
@@ -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;
|
||||
}
|
||||
|
||||
@@ -2590,6 +2593,8 @@ namespace ts {
|
||||
/* @internal */ externalModuleIndicator?: Node;
|
||||
// The first node that causes this file to be a CommonJS module
|
||||
/* @internal */ commonJsModuleIndicator?: Node;
|
||||
// JS identifier-declarations that are intended to merge with globals
|
||||
/* @internal */ jsGlobalAugmentations?: SymbolTable;
|
||||
|
||||
/* @internal */ identifiers: Map<string>; // Map from a string to an interned string
|
||||
/* @internal */ nodeCount: number;
|
||||
@@ -2812,7 +2817,8 @@ namespace ts {
|
||||
|
||||
/* @internal */ getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string): ResolvedModuleWithFailedLookupLocations | undefined;
|
||||
|
||||
getProjectReferences(): (ResolvedProjectReference | undefined)[] | undefined;
|
||||
getProjectReferences(): ReadonlyArray<ProjectReference> | undefined;
|
||||
getResolvedProjectReferences(): (ResolvedProjectReference | undefined)[] | undefined;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -3031,8 +3037,8 @@ namespace ts {
|
||||
/* @internal */ getStringType(): Type;
|
||||
/* @internal */ getNumberType(): Type;
|
||||
/* @internal */ getBooleanType(): Type;
|
||||
/* @internal */ getFalseType(): Type;
|
||||
/* @internal */ getTrueType(): Type;
|
||||
/* @internal */ getFalseType(fresh?: boolean): Type;
|
||||
/* @internal */ getTrueType(fresh?: boolean): Type;
|
||||
/* @internal */ getVoidType(): Type;
|
||||
/* @internal */ getUndefinedType(): Type;
|
||||
/* @internal */ getNullType(): Type;
|
||||
@@ -3380,7 +3386,7 @@ namespace ts {
|
||||
isImplementationOfOverload(node: FunctionLike): boolean | undefined;
|
||||
isRequiredInitializedParameter(node: ParameterDeclaration): boolean;
|
||||
isOptionalUninitializedParameterProperty(node: ParameterDeclaration): boolean;
|
||||
isJSContainerFunctionDeclaration(node: FunctionDeclaration): boolean;
|
||||
isExpandoFunctionDeclaration(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;
|
||||
@@ -3432,7 +3438,7 @@ namespace ts {
|
||||
ExportStar = 1 << 23, // Export * declaration
|
||||
Optional = 1 << 24, // Optional property
|
||||
Transient = 1 << 25, // Transient symbol (created during type check)
|
||||
JSContainer = 1 << 26, // Contains Javascript special declarations
|
||||
Assignment = 1 << 26, // Assignment treated as declaration (eg `this.prop = 1`)
|
||||
ModuleExports = 1 << 27, // Symbol for CommonJS `module` of `module.exports`
|
||||
|
||||
/* @internal */
|
||||
@@ -3441,8 +3447,8 @@ namespace ts {
|
||||
|
||||
Enum = RegularEnum | ConstEnum,
|
||||
Variable = FunctionScopedVariable | BlockScopedVariable,
|
||||
Value = Variable | Property | EnumMember | ObjectLiteral | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor | JSContainer,
|
||||
Type = Class | Interface | Enum | EnumMember | TypeLiteral | TypeParameter | TypeAlias | JSContainer,
|
||||
Value = Variable | Property | EnumMember | ObjectLiteral | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor | Assignment,
|
||||
Type = Class | Interface | Enum | EnumMember | TypeLiteral | TypeParameter | TypeAlias | Assignment,
|
||||
Namespace = ValueModule | NamespaceModule | Enum,
|
||||
Module = ValueModule | NamespaceModule,
|
||||
Accessor = GetAccessor | SetAccessor,
|
||||
@@ -3463,7 +3469,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 | JSContainer),
|
||||
ValueModuleExcludes = Value & ~(Function | Class | RegularEnum | ValueModule | Assignment),
|
||||
NamespaceModuleExcludes = 0,
|
||||
MethodExcludes = Value & ~Method,
|
||||
GetAccessorExcludes = Value & ~SetAccessor,
|
||||
@@ -3728,7 +3734,7 @@ namespace ts {
|
||||
Unit = Literal | UniqueESSymbol | Nullable,
|
||||
StringOrNumberLiteral = StringLiteral | NumberLiteral,
|
||||
/* @internal */
|
||||
StringOrNumberLiteralOrUnique = StringOrNumberLiteral | UniqueESSymbol,
|
||||
StringOrNumberLiteralOrUnique = StringLiteral | NumberLiteral | UniqueESSymbol,
|
||||
/* @internal */
|
||||
DefinitelyFalsy = StringLiteral | NumberLiteral | BooleanLiteral | Void | Undefined | Null,
|
||||
PossiblyFalsy = DefinitelyFalsy | String | Number | Boolean,
|
||||
@@ -3799,6 +3805,15 @@ namespace ts {
|
||||
intrinsicName: string; // Name of intrinsic type
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface FreshableIntrinsicType extends IntrinsicType {
|
||||
freshType: IntrinsicType; // Fresh version of type
|
||||
regularType: IntrinsicType; // Regular version of type
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export type FreshableType = LiteralType | FreshableIntrinsicType;
|
||||
|
||||
// String literal types (TypeFlags.StringLiteral)
|
||||
// Numeric literal types (TypeFlags.NumberLiteral)
|
||||
export interface LiteralType extends Type {
|
||||
@@ -4216,7 +4231,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export const enum SpecialPropertyAssignmentKind {
|
||||
export const enum AssignmentDeclarationKind {
|
||||
None,
|
||||
/// exports.name = expr
|
||||
ExportsProperty,
|
||||
@@ -4513,7 +4528,6 @@ namespace ts {
|
||||
/* @internal */
|
||||
export interface ConfigFileSpecs {
|
||||
filesSpecs: ReadonlyArray<string> | undefined;
|
||||
referencesSpecs: ReadonlyArray<ProjectReference> | undefined;
|
||||
/**
|
||||
* Present to report errors (user specified specs), validatedIncludeSpecs are used for file name matching
|
||||
*/
|
||||
@@ -4529,7 +4543,6 @@ namespace ts {
|
||||
|
||||
export interface ExpandResult {
|
||||
fileNames: string[];
|
||||
projectReferences: ReadonlyArray<ProjectReference> | undefined;
|
||||
wildcardDirectories: MapLike<WatchDirectoryFlags>;
|
||||
/* @internal */ spec: ConfigFileSpecs;
|
||||
}
|
||||
|
||||
+142
-91
@@ -14,7 +14,6 @@ namespace ts {
|
||||
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export const emptyArray: never[] = [] as never[];
|
||||
export const resolvingEmptyArray: never[] = [] as never[];
|
||||
export const emptyMap = createMap<never>() as ReadonlyMap<never> & ReadonlyPragmaMap;
|
||||
export const emptyUnderscoreEscapedMap: ReadonlyUnderscoreEscapedMap<never> = emptyMap as ReadonlyUnderscoreEscapedMap<never>;
|
||||
@@ -250,6 +249,12 @@ namespace ts {
|
||||
sourceFile.resolvedTypeReferenceDirectiveNames.set(typeReferenceDirectiveName, resolvedTypeReferenceDirective);
|
||||
}
|
||||
|
||||
export function projectReferenceIsEqualTo(oldRef: ProjectReference, newRef: ProjectReference) {
|
||||
return oldRef.path === newRef.path &&
|
||||
!oldRef.prepend === !newRef.prepend &&
|
||||
!oldRef.circular === !newRef.circular;
|
||||
}
|
||||
|
||||
export function moduleResolutionIsEqualTo(oldResolution: ResolvedModuleFull, newResolution: ResolvedModuleFull): boolean {
|
||||
return oldResolution.isExternalLibraryImport === newResolution.isExternalLibraryImport &&
|
||||
oldResolution.extension === newResolution.extension &&
|
||||
@@ -1679,15 +1684,15 @@ namespace ts {
|
||||
return node.kind === SyntaxKind.ImportEqualsDeclaration && (<ImportEqualsDeclaration>node).moduleReference.kind !== SyntaxKind.ExternalModuleReference;
|
||||
}
|
||||
|
||||
export function isSourceFileJavaScript(file: SourceFile): boolean {
|
||||
return isInJavaScriptFile(file);
|
||||
export function isSourceFileJS(file: SourceFile): boolean {
|
||||
return isInJSFile(file);
|
||||
}
|
||||
|
||||
export function isSourceFileNotJavaScript(file: SourceFile): boolean {
|
||||
return !isInJavaScriptFile(file);
|
||||
export function isSourceFileNotJS(file: SourceFile): boolean {
|
||||
return !isInJSFile(file);
|
||||
}
|
||||
|
||||
export function isInJavaScriptFile(node: Node | undefined): boolean {
|
||||
export function isInJSFile(node: Node | undefined): boolean {
|
||||
return !!node && !!(node.flags & NodeFlags.JavaScriptFile);
|
||||
}
|
||||
|
||||
@@ -1739,14 +1744,14 @@ namespace ts {
|
||||
return getSourceTextOfNodeFromSourceFile(sourceFile, str).charCodeAt(0) === CharacterCodes.doubleQuote;
|
||||
}
|
||||
|
||||
export function getDeclarationOfJSInitializer(node: Node): Node | undefined {
|
||||
export function getDeclarationOfExpando(node: Node): Node | undefined {
|
||||
if (!node.parent) {
|
||||
return undefined;
|
||||
}
|
||||
let name: Expression | BindingName | undefined;
|
||||
let decl: Node | undefined;
|
||||
if (isVariableDeclaration(node.parent) && node.parent.initializer === node) {
|
||||
if (!isInJavaScriptFile(node) && !isVarConst(node.parent)) {
|
||||
if (!isInJSFile(node) && !isVarConst(node.parent)) {
|
||||
return undefined;
|
||||
}
|
||||
name = node.parent.name;
|
||||
@@ -1771,7 +1776,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
if (!name || !getJavascriptInitializer(node, isPrototypeAccess(name))) {
|
||||
if (!name || !getExpandoInitializer(node, isPrototypeAccess(name))) {
|
||||
return undefined;
|
||||
}
|
||||
return decl;
|
||||
@@ -1783,7 +1788,7 @@ namespace ts {
|
||||
|
||||
/** Get the initializer, taking into account defaulted Javascript initializers */
|
||||
export function getEffectiveInitializer(node: HasExpressionInitializer) {
|
||||
if (isInJavaScriptFile(node) && node.initializer &&
|
||||
if (isInJSFile(node) && node.initializer &&
|
||||
isBinaryExpression(node.initializer) && node.initializer.operatorToken.kind === SyntaxKind.BarBarToken &&
|
||||
node.name && isEntityNameExpression(node.name) && isSameEntityName(node.name, node.initializer.left)) {
|
||||
return node.initializer.right;
|
||||
@@ -1791,26 +1796,26 @@ namespace ts {
|
||||
return node.initializer;
|
||||
}
|
||||
|
||||
/** Get the declaration initializer when it is container-like (See getJavascriptInitializer). */
|
||||
export function getDeclaredJavascriptInitializer(node: HasExpressionInitializer) {
|
||||
/** Get the declaration initializer when it is container-like (See getExpandoInitializer). */
|
||||
export function getDeclaredExpandoInitializer(node: HasExpressionInitializer) {
|
||||
const init = getEffectiveInitializer(node);
|
||||
return init && getJavascriptInitializer(init, isPrototypeAccess(node.name));
|
||||
return init && getExpandoInitializer(init, isPrototypeAccess(node.name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the assignment 'initializer' -- the righthand side-- when the initializer is container-like (See getJavascriptInitializer).
|
||||
* Get the assignment 'initializer' -- the righthand side-- when the initializer is container-like (See getExpandoInitializer).
|
||||
* We treat the right hand side of assignments with container-like initalizers as declarations.
|
||||
*/
|
||||
export function getAssignedJavascriptInitializer(node: Node) {
|
||||
export function getAssignedExpandoInitializer(node: Node) {
|
||||
if (node && node.parent && isBinaryExpression(node.parent) && node.parent.operatorToken.kind === SyntaxKind.EqualsToken) {
|
||||
const isPrototypeAssignment = isPrototypeAccess(node.parent.left);
|
||||
return getJavascriptInitializer(node.parent.right, isPrototypeAssignment) ||
|
||||
getDefaultedJavascriptInitializer(node.parent.left as EntityNameExpression, node.parent.right, isPrototypeAssignment);
|
||||
return getExpandoInitializer(node.parent.right, isPrototypeAssignment) ||
|
||||
getDefaultedExpandoInitializer(node.parent.left as EntityNameExpression, node.parent.right, isPrototypeAssignment);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recognized Javascript container-like initializers are:
|
||||
* Recognized expando initializers are:
|
||||
* 1. (function() {})() -- IIFEs
|
||||
* 2. function() { } -- Function expressions
|
||||
* 3. class { } -- Class expressions
|
||||
@@ -1819,7 +1824,7 @@ namespace ts {
|
||||
*
|
||||
* This function returns the provided initializer, or undefined if it is not valid.
|
||||
*/
|
||||
export function getJavascriptInitializer(initializer: Node, isPrototypeAssignment: boolean): Expression | undefined {
|
||||
export function getExpandoInitializer(initializer: Node, isPrototypeAssignment: boolean): Expression | undefined {
|
||||
if (isCallExpression(initializer)) {
|
||||
const e = skipParentheses(initializer.expression);
|
||||
return e.kind === SyntaxKind.FunctionExpression || e.kind === SyntaxKind.ArrowFunction ? initializer : undefined;
|
||||
@@ -1835,29 +1840,29 @@ namespace ts {
|
||||
}
|
||||
|
||||
/**
|
||||
* A defaulted Javascript initializer matches the pattern
|
||||
* `Lhs = Lhs || JavascriptInitializer`
|
||||
* or `var Lhs = Lhs || JavascriptInitializer`
|
||||
* A defaulted expando initializer matches the pattern
|
||||
* `Lhs = Lhs || ExpandoInitializer`
|
||||
* or `var Lhs = Lhs || ExpandoInitializer`
|
||||
*
|
||||
* The second Lhs is required to be the same as the first except that it may be prefixed with
|
||||
* 'window.', 'global.' or 'self.' The second Lhs is otherwise ignored by the binder and checker.
|
||||
*/
|
||||
function getDefaultedJavascriptInitializer(name: EntityNameExpression, initializer: Expression, isPrototypeAssignment: boolean) {
|
||||
const e = isBinaryExpression(initializer) && initializer.operatorToken.kind === SyntaxKind.BarBarToken && getJavascriptInitializer(initializer.right, isPrototypeAssignment);
|
||||
function getDefaultedExpandoInitializer(name: EntityNameExpression, initializer: Expression, isPrototypeAssignment: boolean) {
|
||||
const e = isBinaryExpression(initializer) && initializer.operatorToken.kind === SyntaxKind.BarBarToken && getExpandoInitializer(initializer.right, isPrototypeAssignment);
|
||||
if (e && isSameEntityName(name, (initializer as BinaryExpression).left as EntityNameExpression)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
export function isDefaultedJavascriptInitializer(node: BinaryExpression) {
|
||||
export function isDefaultedExpandoInitializer(node: BinaryExpression) {
|
||||
const name = isVariableDeclaration(node.parent) ? node.parent.name :
|
||||
isBinaryExpression(node.parent) && node.parent.operatorToken.kind === SyntaxKind.EqualsToken ? node.parent.left :
|
||||
undefined;
|
||||
return name && getJavascriptInitializer(node.right, isPrototypeAccess(name)) && isEntityNameExpression(name) && isSameEntityName(name, node.left);
|
||||
return name && getExpandoInitializer(node.right, isPrototypeAccess(name)) && isEntityNameExpression(name) && isSameEntityName(name, node.left);
|
||||
}
|
||||
|
||||
/** Given a Javascript initializer, return the outer name. That is, the lhs of the assignment or the declaration name. */
|
||||
export function getOuterNameOfJsInitializer(node: Declaration): DeclarationName | undefined {
|
||||
/** Given an expando initializer, return its declaration name, or the left-hand side of the assignment if it's part of an assignment declaration. */
|
||||
export function getNameOfExpando(node: Declaration): DeclarationName | undefined {
|
||||
if (isBinaryExpression(node.parent)) {
|
||||
const parent = (node.parent.operatorToken.kind === SyntaxKind.BarBarToken && isBinaryExpression(node.parent.parent)) ? node.parent.parent : node.parent;
|
||||
if (parent.operatorToken.kind === SyntaxKind.EqualsToken && isIdentifier(parent.left)) {
|
||||
@@ -1913,36 +1918,36 @@ namespace ts {
|
||||
|
||||
/// Given a BinaryExpression, returns SpecialPropertyAssignmentKind for the various kinds of property
|
||||
/// assignments we treat as special in the binder
|
||||
export function getSpecialPropertyAssignmentKind(expr: BinaryExpression): SpecialPropertyAssignmentKind {
|
||||
const special = getSpecialPropertyAssignmentKindWorker(expr);
|
||||
return special === SpecialPropertyAssignmentKind.Property || isInJavaScriptFile(expr) ? special : SpecialPropertyAssignmentKind.None;
|
||||
export function getAssignmentDeclarationKind(expr: BinaryExpression): AssignmentDeclarationKind {
|
||||
const special = getAssignmentDeclarationKindWorker(expr);
|
||||
return special === AssignmentDeclarationKind.Property || isInJSFile(expr) ? special : AssignmentDeclarationKind.None;
|
||||
}
|
||||
|
||||
function getSpecialPropertyAssignmentKindWorker(expr: BinaryExpression): SpecialPropertyAssignmentKind {
|
||||
function getAssignmentDeclarationKindWorker(expr: BinaryExpression): AssignmentDeclarationKind {
|
||||
if (expr.operatorToken.kind !== SyntaxKind.EqualsToken ||
|
||||
!isPropertyAccessExpression(expr.left)) {
|
||||
return SpecialPropertyAssignmentKind.None;
|
||||
return AssignmentDeclarationKind.None;
|
||||
}
|
||||
const lhs = expr.left;
|
||||
if (isEntityNameExpression(lhs.expression) && lhs.name.escapedText === "prototype" && isObjectLiteralExpression(getInitializerOfBinaryExpression(expr))) {
|
||||
// F.prototype = { ... }
|
||||
return SpecialPropertyAssignmentKind.Prototype;
|
||||
return AssignmentDeclarationKind.Prototype;
|
||||
}
|
||||
return getSpecialPropertyAccessKind(lhs);
|
||||
return getAssignmentDeclarationPropertyAccessKind(lhs);
|
||||
}
|
||||
|
||||
export function getSpecialPropertyAccessKind(lhs: PropertyAccessExpression): SpecialPropertyAssignmentKind {
|
||||
export function getAssignmentDeclarationPropertyAccessKind(lhs: PropertyAccessExpression): AssignmentDeclarationKind {
|
||||
if (lhs.expression.kind === SyntaxKind.ThisKeyword) {
|
||||
return SpecialPropertyAssignmentKind.ThisProperty;
|
||||
return AssignmentDeclarationKind.ThisProperty;
|
||||
}
|
||||
else if (isIdentifier(lhs.expression) && lhs.expression.escapedText === "module" && lhs.name.escapedText === "exports") {
|
||||
// module.exports = expr
|
||||
return SpecialPropertyAssignmentKind.ModuleExports;
|
||||
return AssignmentDeclarationKind.ModuleExports;
|
||||
}
|
||||
else if (isEntityNameExpression(lhs.expression)) {
|
||||
if (isPrototypeAccess(lhs.expression)) {
|
||||
// F.G....prototype.x = expr
|
||||
return SpecialPropertyAssignmentKind.PrototypeProperty;
|
||||
return AssignmentDeclarationKind.PrototypeProperty;
|
||||
}
|
||||
|
||||
let nextToLast = lhs;
|
||||
@@ -1954,13 +1959,13 @@ namespace ts {
|
||||
if (id.escapedText === "exports" ||
|
||||
id.escapedText === "module" && nextToLast.name.escapedText === "exports") {
|
||||
// exports.name = expr OR module.exports.name = expr
|
||||
return SpecialPropertyAssignmentKind.ExportsProperty;
|
||||
return AssignmentDeclarationKind.ExportsProperty;
|
||||
}
|
||||
// F.G...x = expr
|
||||
return SpecialPropertyAssignmentKind.Property;
|
||||
return AssignmentDeclarationKind.Property;
|
||||
}
|
||||
|
||||
return SpecialPropertyAssignmentKind.None;
|
||||
return AssignmentDeclarationKind.None;
|
||||
}
|
||||
|
||||
export function getInitializerOfBinaryExpression(expr: BinaryExpression) {
|
||||
@@ -1971,11 +1976,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function isPrototypePropertyAssignment(node: Node): boolean {
|
||||
return isBinaryExpression(node) && getSpecialPropertyAssignmentKind(node) === SpecialPropertyAssignmentKind.PrototypeProperty;
|
||||
return isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.PrototypeProperty;
|
||||
}
|
||||
|
||||
export function isSpecialPropertyDeclaration(expr: PropertyAccessExpression): boolean {
|
||||
return isInJavaScriptFile(expr) &&
|
||||
return isInJSFile(expr) &&
|
||||
expr.parent && expr.parent.kind === SyntaxKind.ExpressionStatement &&
|
||||
!!getJSDocTypeTag(expr.parent);
|
||||
}
|
||||
@@ -2083,7 +2088,7 @@ namespace ts {
|
||||
function getSourceOfDefaultedAssignment(node: Node): Node | undefined {
|
||||
return isExpressionStatement(node) &&
|
||||
isBinaryExpression(node.expression) &&
|
||||
getSpecialPropertyAssignmentKind(node.expression) !== SpecialPropertyAssignmentKind.None &&
|
||||
getAssignmentDeclarationKind(node.expression) !== AssignmentDeclarationKind.None &&
|
||||
isBinaryExpression(node.expression.right) &&
|
||||
node.expression.right.operatorToken.kind === SyntaxKind.BarBarToken
|
||||
? node.expression.right.right
|
||||
@@ -2384,29 +2389,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 &&
|
||||
getAssignmentDeclarationKind(binExp) !== AssignmentDeclarationKind.None &&
|
||||
(binExp.left.symbol || binExp.symbol) &&
|
||||
getNameOfDeclaration(binExp) === name;
|
||||
getNameOfDeclaration(binExp) === name
|
||||
? binExp
|
||||
: undefined;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2468,7 +2477,7 @@ namespace ts {
|
||||
node.kind === SyntaxKind.ImportSpecifier ||
|
||||
node.kind === SyntaxKind.ExportSpecifier ||
|
||||
node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(<ExportAssignment>node) ||
|
||||
isBinaryExpression(node) && getSpecialPropertyAssignmentKind(node) === SpecialPropertyAssignmentKind.ModuleExports;
|
||||
isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ModuleExports;
|
||||
}
|
||||
|
||||
export function exportAssignmentIsAlias(node: ExportAssignment | BinaryExpression): boolean {
|
||||
@@ -2477,7 +2486,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function getEffectiveBaseTypeNode(node: ClassLikeDeclaration | InterfaceDeclaration) {
|
||||
if (isInJavaScriptFile(node)) {
|
||||
if (isInJSFile(node)) {
|
||||
// Prefer an @augments tag because it may have type parameters.
|
||||
const tag = getJSDocAugmentsTag(node);
|
||||
if (tag) {
|
||||
@@ -3283,7 +3292,7 @@ namespace ts {
|
||||
|
||||
/** Don't call this for `--outFile`, just for `--outDir` or plain emit. `--outFile` needs additional checks. */
|
||||
export function sourceFileMayBeEmitted(sourceFile: SourceFile, options: CompilerOptions, isSourceFileFromExternalLibrary: (file: SourceFile) => boolean) {
|
||||
return !(options.noEmitForJsFiles && isSourceFileJavaScript(sourceFile)) && !sourceFile.isDeclarationFile && !isSourceFileFromExternalLibrary(sourceFile);
|
||||
return !(options.noEmitForJsFiles && isSourceFileJS(sourceFile)) && !sourceFile.isDeclarationFile && !isSourceFileFromExternalLibrary(sourceFile);
|
||||
}
|
||||
|
||||
export function getSourceFilePathInNewDir(fileName: string, host: EmitHost, newDirPath: string): string {
|
||||
@@ -3407,7 +3416,7 @@ namespace ts {
|
||||
*/
|
||||
export function getEffectiveTypeAnnotationNode(node: Node): TypeNode | undefined {
|
||||
const type = (node as HasType).type;
|
||||
if (type || !isInJavaScriptFile(node)) return type;
|
||||
if (type || !isInJSFile(node)) return type;
|
||||
return isJSDocPropertyLikeTag(node) ? node.typeExpression && node.typeExpression.type : getJSDocType(node);
|
||||
}
|
||||
|
||||
@@ -3422,7 +3431,7 @@ namespace ts {
|
||||
export function getEffectiveReturnTypeNode(node: SignatureDeclaration | JSDocSignature): TypeNode | undefined {
|
||||
return isJSDocSignature(node) ?
|
||||
node.type && node.type.typeExpression && node.type.typeExpression.type :
|
||||
node.type || (isInJavaScriptFile(node) ? getJSDocReturnType(node) : undefined);
|
||||
node.type || (isInJSFile(node) ? getJSDocReturnType(node) : undefined);
|
||||
}
|
||||
|
||||
export function getJSDocTypeParameterDeclarations(node: DeclarationWithTypeParameters): ReadonlyArray<TypeParameterDeclaration> {
|
||||
@@ -3815,8 +3824,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
/** Return ".ts", ".d.ts", or ".tsx", if that is the extension. */
|
||||
export function tryExtractTypeScriptExtension(fileName: string): string | undefined {
|
||||
return find(supportedTypescriptExtensionsForExtractExtension, extension => fileExtensionIs(fileName, extension));
|
||||
export function tryExtractTSExtension(fileName: string): string | undefined {
|
||||
return find(supportedTSExtensionsForExtractExtension, extension => fileExtensionIs(fileName, extension));
|
||||
}
|
||||
/**
|
||||
* Replace each instance of non-ascii characters by one, two, three, or four escape sequences
|
||||
@@ -3970,6 +3979,27 @@ namespace ts {
|
||||
return getStringFromExpandedCharCodes(expandedCharCodes);
|
||||
}
|
||||
|
||||
export function readJson(path: string, host: { readFile(fileName: string): string | undefined }): object {
|
||||
try {
|
||||
const jsonText = host.readFile(path);
|
||||
if (!jsonText) return {};
|
||||
const result = parseConfigFileTextToJson(path, jsonText);
|
||||
if (result.error) {
|
||||
return {};
|
||||
}
|
||||
return result.config;
|
||||
}
|
||||
catch (e) {
|
||||
// gracefully handle if readFile fails or returns not JSON
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
export function directoryProbablyExists(directoryName: string, host: { directoryExists?: (directoryName: string) => boolean }): boolean {
|
||||
// if host does not support 'directoryExists' assume that directory will exist
|
||||
return !host.directoryExists || host.directoryExists(directoryName);
|
||||
}
|
||||
|
||||
const carriageReturnLineFeed = "\r\n";
|
||||
const lineFeed = "\n";
|
||||
export function getNewLineCharacter(options: CompilerOptions | PrinterOptions, getNewLine?: () => string): string {
|
||||
@@ -4305,7 +4335,7 @@ namespace ts {
|
||||
/**
|
||||
* clears already present map by calling onDeleteExistingValue callback before deleting that key/value
|
||||
*/
|
||||
export function clearMap<T>(map: Map<T>, onDeleteValue: (valueInMap: T, key: string) => void) {
|
||||
export function clearMap<T>(map: { forEach: Map<T>["forEach"]; clear: Map<T>["clear"]; }, onDeleteValue: (valueInMap: T, key: string) => void) {
|
||||
// Remove all
|
||||
map.forEach(onDeleteValue);
|
||||
map.clear();
|
||||
@@ -4962,11 +4992,11 @@ namespace ts {
|
||||
}
|
||||
case SyntaxKind.BinaryExpression: {
|
||||
const expr = declaration as BinaryExpression;
|
||||
switch (getSpecialPropertyAssignmentKind(expr)) {
|
||||
case SpecialPropertyAssignmentKind.ExportsProperty:
|
||||
case SpecialPropertyAssignmentKind.ThisProperty:
|
||||
case SpecialPropertyAssignmentKind.Property:
|
||||
case SpecialPropertyAssignmentKind.PrototypeProperty:
|
||||
switch (getAssignmentDeclarationKind(expr)) {
|
||||
case AssignmentDeclarationKind.ExportsProperty:
|
||||
case AssignmentDeclarationKind.ThisProperty:
|
||||
case AssignmentDeclarationKind.Property:
|
||||
case AssignmentDeclarationKind.PrototypeProperty:
|
||||
return (expr.left as PropertyAccessExpression).name;
|
||||
default:
|
||||
return undefined;
|
||||
@@ -5183,7 +5213,7 @@ namespace ts {
|
||||
if (node.typeParameters) {
|
||||
return node.typeParameters;
|
||||
}
|
||||
if (isInJavaScriptFile(node)) {
|
||||
if (isInJSFile(node)) {
|
||||
const decls = getJSDocTypeParameterDeclarations(node);
|
||||
if (decls.length) {
|
||||
return decls;
|
||||
@@ -6589,7 +6619,7 @@ namespace ts {
|
||||
/* @internal */
|
||||
export function isDeclaration(node: Node): node is NamedDeclaration {
|
||||
if (node.kind === SyntaxKind.TypeParameter) {
|
||||
return node.parent.kind !== SyntaxKind.JSDocTemplateTag || isInJavaScriptFile(node);
|
||||
return node.parent.kind !== SyntaxKind.JSDocTemplateTag || isInJSFile(node);
|
||||
}
|
||||
|
||||
return isDeclarationKind(node.kind);
|
||||
@@ -7033,6 +7063,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;
|
||||
}
|
||||
@@ -7635,6 +7677,15 @@ namespace ts {
|
||||
// It may be inefficient (we could just match (/[-[\]{}()*+?.,\\^$|#\s]/g), but this is future
|
||||
// proof.
|
||||
const reservedCharacterPattern = /[^\w\s\/]/g;
|
||||
|
||||
export function regExpEscape(text: string) {
|
||||
return text.replace(reservedCharacterPattern, escapeRegExpCharacter);
|
||||
}
|
||||
|
||||
function escapeRegExpCharacter(match: string) {
|
||||
return "\\" + match;
|
||||
}
|
||||
|
||||
const wildcardCharCodes = [CharacterCodes.asterisk, CharacterCodes.question];
|
||||
|
||||
export function hasExtension(fileName: string): boolean {
|
||||
@@ -7965,42 +8016,42 @@ namespace ts {
|
||||
/**
|
||||
* List of supported extensions in order of file resolution precedence.
|
||||
*/
|
||||
export const supportedTypeScriptExtensions: ReadonlyArray<Extension> = [Extension.Ts, Extension.Tsx, Extension.Dts];
|
||||
export const supportedTSExtensions: ReadonlyArray<Extension> = [Extension.Ts, Extension.Tsx, Extension.Dts];
|
||||
/** Must have ".d.ts" first because if ".ts" goes first, that will be detected as the extension instead of ".d.ts". */
|
||||
export const supportedTypescriptExtensionsForExtractExtension: 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 const supportedTSExtensionsForExtractExtension: ReadonlyArray<Extension> = [Extension.Dts, Extension.Ts, Extension.Tsx];
|
||||
export const supportedJSExtensions: ReadonlyArray<Extension> = [Extension.Js, Extension.Jsx];
|
||||
export const supportedJSAndJsonExtensions: ReadonlyArray<Extension> = [Extension.Js, Extension.Jsx, Extension.Json];
|
||||
const allSupportedExtensions: ReadonlyArray<Extension> = [...supportedTSExtensions, ...supportedJSExtensions];
|
||||
|
||||
export function getSupportedExtensions(options?: CompilerOptions, extraFileExtensions?: ReadonlyArray<FileExtensionInfo>): ReadonlyArray<string> {
|
||||
const needJsExtensions = options && options.allowJs;
|
||||
|
||||
if (!extraFileExtensions || extraFileExtensions.length === 0) {
|
||||
return needJsExtensions ? allSupportedExtensions : supportedTypeScriptExtensions;
|
||||
return needJsExtensions ? allSupportedExtensions : supportedTSExtensions;
|
||||
}
|
||||
|
||||
const extensions = [
|
||||
...needJsExtensions ? allSupportedExtensions : supportedTypeScriptExtensions,
|
||||
...mapDefined(extraFileExtensions, x => x.scriptKind === ScriptKind.Deferred || needJsExtensions && isJavaScriptLike(x.scriptKind) ? x.extension : undefined)
|
||||
...needJsExtensions ? allSupportedExtensions : supportedTSExtensions,
|
||||
...mapDefined(extraFileExtensions, x => x.scriptKind === ScriptKind.Deferred || needJsExtensions && isJSLike(x.scriptKind) ? x.extension : undefined)
|
||||
];
|
||||
|
||||
return deduplicate<string>(extensions, equateStringsCaseSensitive, compareStringsCaseSensitive);
|
||||
}
|
||||
|
||||
function isJavaScriptLike(scriptKind: ScriptKind | undefined): boolean {
|
||||
function isJSLike(scriptKind: ScriptKind | undefined): boolean {
|
||||
return scriptKind === ScriptKind.JS || scriptKind === ScriptKind.JSX;
|
||||
}
|
||||
|
||||
export function hasJavaScriptFileExtension(fileName: string): boolean {
|
||||
return some(supportedJavascriptExtensions, extension => fileExtensionIs(fileName, extension));
|
||||
export function hasJSFileExtension(fileName: string): boolean {
|
||||
return some(supportedJSExtensions, extension => fileExtensionIs(fileName, extension));
|
||||
}
|
||||
|
||||
export function hasJavaScriptOrJsonFileExtension(fileName: string): boolean {
|
||||
return supportedJavaScriptAndJsonExtensions.some(ext => fileExtensionIs(fileName, ext));
|
||||
export function hasJSOrJsonFileExtension(fileName: string): boolean {
|
||||
return supportedJSAndJsonExtensions.some(ext => fileExtensionIs(fileName, ext));
|
||||
}
|
||||
|
||||
export function hasTypeScriptFileExtension(fileName: string): boolean {
|
||||
return some(supportedTypeScriptExtensions, extension => fileExtensionIs(fileName, extension));
|
||||
export function hasTSFileExtension(fileName: string): boolean {
|
||||
return some(supportedTSExtensions, extension => fileExtensionIs(fileName, extension));
|
||||
}
|
||||
|
||||
export function isSupportedSourceFileName(fileName: string, compilerOptions?: CompilerOptions, extraFileExtensions?: ReadonlyArray<FileExtensionInfo>) {
|
||||
@@ -8136,12 +8187,12 @@ namespace ts {
|
||||
}
|
||||
|
||||
/** True if an extension is one of the supported TypeScript extensions. */
|
||||
export function extensionIsTypeScript(ext: Extension): boolean {
|
||||
export function extensionIsTS(ext: Extension): boolean {
|
||||
return ext === Extension.Ts || ext === Extension.Tsx || ext === Extension.Dts;
|
||||
}
|
||||
|
||||
export function resolutionExtensionIsTypeScriptOrJson(ext: Extension) {
|
||||
return extensionIsTypeScript(ext) || ext === Extension.Json;
|
||||
export function resolutionExtensionIsTSOrJson(ext: Extension) {
|
||||
return extensionIsTS(ext) || ext === Extension.Json;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+17
-12
@@ -101,7 +101,7 @@ namespace ts {
|
||||
getGlobalDiagnostics(): ReadonlyArray<Diagnostic>;
|
||||
getSemanticDiagnostics(): ReadonlyArray<Diagnostic>;
|
||||
getConfigFileParsingDiagnostics(): ReadonlyArray<Diagnostic>;
|
||||
emit(): EmitResult;
|
||||
emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback): EmitResult;
|
||||
}
|
||||
|
||||
export type ReportEmitErrorSummary = (errorCount: number) => void;
|
||||
@@ -109,7 +109,7 @@ namespace ts {
|
||||
/**
|
||||
* Helper that emit files, report diagnostics and lists emitted and/or source files depending on compiler options
|
||||
*/
|
||||
export function emitFilesAndReportErrors(program: ProgramToEmitFilesAndReportErrors, reportDiagnostic: DiagnosticReporter, writeFileName?: (s: string) => void, reportSummary?: ReportEmitErrorSummary) {
|
||||
export function emitFilesAndReportErrors(program: ProgramToEmitFilesAndReportErrors, reportDiagnostic: DiagnosticReporter, writeFileName?: (s: string) => void, reportSummary?: ReportEmitErrorSummary, writeFile?: WriteFileCallback) {
|
||||
// First get and report any syntactic errors.
|
||||
const diagnostics = program.getConfigFileParsingDiagnostics().slice();
|
||||
const configFileParsingDiagnosticsLength = diagnostics.length;
|
||||
@@ -128,7 +128,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
// Emit and report any errors we ran into.
|
||||
const { emittedFiles, emitSkipped, diagnostics: emitDiagnostics } = program.emit();
|
||||
const { emittedFiles, emitSkipped, diagnostics: emitDiagnostics } = program.emit(/*targetSourceFile*/ undefined, writeFile);
|
||||
addRange(diagnostics, emitDiagnostics);
|
||||
|
||||
if (reportSemanticDiagnostics) {
|
||||
@@ -263,10 +263,11 @@ namespace ts {
|
||||
/**
|
||||
* Creates the watch compiler host from system for compiling root files and options in watch mode
|
||||
*/
|
||||
export function createWatchCompilerHostOfFilesAndCompilerOptions<T extends BuilderProgram = EmitAndSemanticDiagnosticsBuilderProgram>(rootFiles: string[], options: CompilerOptions, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfFilesAndCompilerOptions<T> {
|
||||
export function createWatchCompilerHostOfFilesAndCompilerOptions<T extends BuilderProgram = EmitAndSemanticDiagnosticsBuilderProgram>(rootFiles: string[], options: CompilerOptions, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter, projectReferences?: ReadonlyArray<ProjectReference>): WatchCompilerHostOfFilesAndCompilerOptions<T> {
|
||||
const host = createWatchCompilerHost(system, createProgram, reportDiagnostic || createDiagnosticReporter(system), reportWatchStatus) as WatchCompilerHostOfFilesAndCompilerOptions<T>;
|
||||
host.rootFiles = rootFiles;
|
||||
host.options = options;
|
||||
host.projectReferences = projectReferences;
|
||||
return host;
|
||||
}
|
||||
}
|
||||
@@ -274,7 +275,7 @@ namespace ts {
|
||||
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 type CreateProgram<T extends BuilderProgram> = (rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference> | undefined) => T;
|
||||
/** 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 */
|
||||
@@ -360,6 +361,9 @@ namespace ts {
|
||||
|
||||
/** Compiler options */
|
||||
options: CompilerOptions;
|
||||
|
||||
/** Project References */
|
||||
projectReferences?: ReadonlyArray<ProjectReference>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -413,11 +417,11 @@ namespace ts {
|
||||
/**
|
||||
* Create the watch compiler host for either configFile or fileNames and its options
|
||||
*/
|
||||
export function createWatchCompilerHost<T extends BuilderProgram>(rootFiles: string[], options: CompilerOptions, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfFilesAndCompilerOptions<T>;
|
||||
export function createWatchCompilerHost<T extends BuilderProgram>(configFileName: string, optionsToExtend: CompilerOptions | undefined, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfConfigFile<T>;
|
||||
export function createWatchCompilerHost<T extends BuilderProgram>(rootFilesOrConfigFileName: string | string[], options: CompilerOptions | undefined, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfFilesAndCompilerOptions<T> | WatchCompilerHostOfConfigFile<T> {
|
||||
export function createWatchCompilerHost<T extends BuilderProgram>(rootFiles: string[], options: CompilerOptions, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter, projectReferences?: ReadonlyArray<ProjectReference>): WatchCompilerHostOfFilesAndCompilerOptions<T>;
|
||||
export function createWatchCompilerHost<T extends BuilderProgram>(rootFilesOrConfigFileName: string | string[], options: CompilerOptions | undefined, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter, projectReferences?: ReadonlyArray<ProjectReference>): WatchCompilerHostOfFilesAndCompilerOptions<T> | WatchCompilerHostOfConfigFile<T> {
|
||||
if (isArray(rootFilesOrConfigFileName)) {
|
||||
return createWatchCompilerHostOfFilesAndCompilerOptions(rootFilesOrConfigFileName, options!, system, createProgram, reportDiagnostic, reportWatchStatus); // TODO: GH#18217
|
||||
return createWatchCompilerHostOfFilesAndCompilerOptions(rootFilesOrConfigFileName, options!, system, createProgram, reportDiagnostic, reportWatchStatus, projectReferences); // TODO: GH#18217
|
||||
}
|
||||
else {
|
||||
return createWatchCompilerHostOfConfigFile(rootFilesOrConfigFileName, options, system, createProgram, reportDiagnostic, reportWatchStatus);
|
||||
@@ -463,7 +467,7 @@ namespace ts {
|
||||
const getCurrentDirectory = () => currentDirectory;
|
||||
const readFile: (path: string, encoding?: string) => string | undefined = (path, encoding) => host.readFile(path, encoding);
|
||||
const { configFileName, optionsToExtend: optionsToExtendForConfigFile = {}, createProgram } = host;
|
||||
let { rootFiles: rootFileNames, options: compilerOptions } = host;
|
||||
let { rootFiles: rootFileNames, options: compilerOptions, projectReferences } = host;
|
||||
let configFileSpecs: ConfigFileSpecs;
|
||||
let configFileParsingDiagnostics: ReadonlyArray<Diagnostic> | undefined;
|
||||
let hasChangedConfigFileParsingErrors = false;
|
||||
@@ -589,9 +593,9 @@ namespace ts {
|
||||
|
||||
// All resolutions are invalid if user provided resolutions
|
||||
const hasInvalidatedResolution = resolutionCache.createHasInvalidatedResolution(userProvidedResolution);
|
||||
if (isProgramUptoDate(getCurrentProgram(), rootFileNames, compilerOptions, getSourceVersion, fileExists, hasInvalidatedResolution, hasChangedAutomaticTypeDirectiveNames)) {
|
||||
if (isProgramUptoDate(getCurrentProgram(), rootFileNames, compilerOptions, getSourceVersion, fileExists, hasInvalidatedResolution, hasChangedAutomaticTypeDirectiveNames, projectReferences)) {
|
||||
if (hasChangedConfigFileParsingErrors) {
|
||||
builderProgram = createProgram(/*rootNames*/ undefined, /*options*/ undefined, compilerHost, builderProgram, configFileParsingDiagnostics);
|
||||
builderProgram = createProgram(/*rootNames*/ undefined, /*options*/ undefined, compilerHost, builderProgram, configFileParsingDiagnostics, projectReferences);
|
||||
hasChangedConfigFileParsingErrors = false;
|
||||
}
|
||||
}
|
||||
@@ -620,7 +624,7 @@ namespace ts {
|
||||
resolutionCache.startCachingPerDirectoryResolution();
|
||||
compilerHost.hasInvalidatedResolution = hasInvalidatedResolution;
|
||||
compilerHost.hasChangedAutomaticTypeDirectiveNames = hasChangedAutomaticTypeDirectiveNames;
|
||||
builderProgram = createProgram(rootFileNames, compilerOptions, compilerHost, builderProgram, configFileParsingDiagnostics);
|
||||
builderProgram = createProgram(rootFileNames, compilerOptions, compilerHost, builderProgram, configFileParsingDiagnostics, projectReferences);
|
||||
resolutionCache.finishCachingPerDirectoryResolution();
|
||||
|
||||
// Update watches
|
||||
@@ -861,6 +865,7 @@ namespace ts {
|
||||
rootFileNames = configFileParseResult.fileNames;
|
||||
compilerOptions = configFileParseResult.options;
|
||||
configFileSpecs = configFileParseResult.configFileSpecs!; // TODO: GH#18217
|
||||
projectReferences = configFileParseResult.projectReferences;
|
||||
configFileParsingDiagnostics = getConfigFileParsingDiagnostics(configFileParseResult);
|
||||
hasChangedConfigFileParsingErrors = true;
|
||||
}
|
||||
|
||||
@@ -397,6 +397,7 @@ namespace ts.server {
|
||||
|
||||
return this.lastRenameEntry = {
|
||||
canRename: body.info.canRename,
|
||||
fileToRename: body.info.fileToRename,
|
||||
displayName: body.info.displayName,
|
||||
fullDisplayName: body.info.fullDisplayName,
|
||||
kind: body.info.kind,
|
||||
|
||||
+30
-20
@@ -420,12 +420,12 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
public goToEachRange(action: () => void) {
|
||||
public goToEachRange(action: (range: Range) => void) {
|
||||
const ranges = this.getRanges();
|
||||
assert(ranges.length);
|
||||
for (const range of ranges) {
|
||||
this.selectRange(range);
|
||||
action();
|
||||
action(range);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -593,7 +593,7 @@ namespace FourSlash {
|
||||
public verifyNoErrors() {
|
||||
ts.forEachKey(this.inputFiles, fileName => {
|
||||
if (!ts.isAnySupportedFileExtension(fileName)
|
||||
|| !this.getProgram().getCompilerOptions().allowJs && !ts.extensionIsTypeScript(ts.extensionFromPath(fileName))) return;
|
||||
|| !this.getProgram().getCompilerOptions().allowJs && !ts.extensionIsTS(ts.extensionFromPath(fileName))) return;
|
||||
const errors = this.getDiagnostics(fileName).filter(e => e.category !== ts.DiagnosticCategory.Suggestion);
|
||||
if (errors.length) {
|
||||
this.printErrorLog(/*expectErrors*/ false, errors);
|
||||
@@ -908,8 +908,8 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
private verifyCompletionEntry(actual: ts.CompletionEntry, expected: FourSlashInterface.ExpectedCompletionEntry) {
|
||||
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 }
|
||||
const { insertText, replacementSpan, hasAction, isRecommended, kind, text, documentation, tags, source, sourceDisplay } = typeof expected === "string"
|
||||
? { insertText: undefined, replacementSpan: undefined, hasAction: undefined, isRecommended: undefined, kind: undefined, text: undefined, documentation: undefined, tags: undefined, source: undefined, sourceDisplay: undefined }
|
||||
: expected;
|
||||
|
||||
if (actual.insertText !== insertText) {
|
||||
@@ -929,7 +929,7 @@ namespace FourSlash {
|
||||
assert.equal(actual.isRecommended, isRecommended);
|
||||
assert.equal(actual.source, source);
|
||||
|
||||
if (text) {
|
||||
if (text !== undefined) {
|
||||
const actualDetails = this.getCompletionEntryDetails(actual.name, actual.source)!;
|
||||
assert.equal(ts.displayPartsToString(actualDetails.displayParts), text);
|
||||
assert.equal(ts.displayPartsToString(actualDetails.documentation), documentation || "");
|
||||
@@ -937,9 +937,10 @@ namespace FourSlash {
|
||||
// assert.equal(actualDetails.kind, actual.kind);
|
||||
assert.equal(actualDetails.kindModifiers, actual.kindModifiers);
|
||||
assert.equal(actualDetails.source && ts.displayPartsToString(actualDetails.source), sourceDisplay);
|
||||
assert.deepEqual(actualDetails.tags, tags);
|
||||
}
|
||||
else {
|
||||
assert(documentation === undefined && sourceDisplay === undefined, "If specifying completion details, should specify 'text'");
|
||||
assert(documentation === undefined && tags === undefined && sourceDisplay === undefined, "If specifying completion details, should specify 'text'");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1363,7 +1364,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
public verifyQuickInfoDisplayParts(kind: string, kindModifiers: string, textSpan: TextSpan,
|
||||
displayParts: ts.SymbolDisplayPart[],
|
||||
documentation: ts.SymbolDisplayPart[],
|
||||
tags: ts.JSDocTagInfo[]
|
||||
tags: ts.JSDocTagInfo[] | undefined
|
||||
) {
|
||||
|
||||
const actualQuickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition)!;
|
||||
@@ -1372,11 +1373,16 @@ Actual: ${stringify(fullActual)}`);
|
||||
assert.equal(JSON.stringify(actualQuickInfo.textSpan), JSON.stringify(textSpan), this.messageAtLastKnownMarker("QuickInfo textSpan"));
|
||||
assert.equal(TestState.getDisplayPartsJson(actualQuickInfo.displayParts), TestState.getDisplayPartsJson(displayParts), this.messageAtLastKnownMarker("QuickInfo displayParts"));
|
||||
assert.equal(TestState.getDisplayPartsJson(actualQuickInfo.documentation), TestState.getDisplayPartsJson(documentation), this.messageAtLastKnownMarker("QuickInfo documentation"));
|
||||
assert.equal(actualQuickInfo.tags!.length, tags.length, this.messageAtLastKnownMarker("QuickInfo tags"));
|
||||
ts.zipWith(tags, actualQuickInfo.tags!, (expectedTag, actualTag) => {
|
||||
assert.equal(expectedTag.name, actualTag.name);
|
||||
assert.equal(expectedTag.text, actualTag.text, this.messageAtLastKnownMarker("QuickInfo tag " + actualTag.name));
|
||||
});
|
||||
if (!actualQuickInfo.tags || !tags) {
|
||||
assert.equal(actualQuickInfo.tags, tags, this.messageAtLastKnownMarker("QuickInfo tags"));
|
||||
}
|
||||
else {
|
||||
assert.equal(actualQuickInfo.tags.length, tags.length, this.messageAtLastKnownMarker("QuickInfo tags"));
|
||||
ts.zipWith(tags, actualQuickInfo.tags, (expectedTag, actualTag) => {
|
||||
assert.equal(expectedTag.name, actualTag.name);
|
||||
assert.equal(expectedTag.text, actualTag.text, this.messageAtLastKnownMarker("QuickInfo tag " + actualTag.name));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public verifyRangesAreRenameLocations(options?: Range[] | { findInStrings?: boolean, findInComments?: boolean, ranges?: Range[] }) {
|
||||
@@ -1525,7 +1531,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
}
|
||||
|
||||
public verifyRenameInfoSucceeded(displayName?: string, fullDisplayName?: string, kind?: string, kindModifiers?: string) {
|
||||
public verifyRenameInfoSucceeded(displayName: string | undefined, fullDisplayName: string | undefined, kind: string | undefined, kindModifiers: string | undefined, fileToRename: string | undefined, expectedRange: Range | undefined): void {
|
||||
const renameInfo = this.languageService.getRenameInfo(this.activeFile.fileName, this.currentCaretPosition);
|
||||
if (!renameInfo.canRename) {
|
||||
this.raiseError("Rename did not succeed");
|
||||
@@ -1535,12 +1541,15 @@ Actual: ${stringify(fullActual)}`);
|
||||
this.validate("fullDisplayName", fullDisplayName, renameInfo.fullDisplayName);
|
||||
this.validate("kind", kind, renameInfo.kind);
|
||||
this.validate("kindModifiers", kindModifiers, renameInfo.kindModifiers);
|
||||
this.validate("fileToRename", fileToRename, renameInfo.fileToRename);
|
||||
|
||||
if (this.getRanges().length !== 1) {
|
||||
this.raiseError("Expected a single range to be selected in the test file.");
|
||||
if (!expectedRange) {
|
||||
if (this.getRanges().length !== 1) {
|
||||
this.raiseError("Expected a single range to be selected in the test file.");
|
||||
}
|
||||
expectedRange = this.getRanges()[0];
|
||||
}
|
||||
|
||||
const expectedRange = this.getRanges()[0];
|
||||
if (renameInfo.triggerSpan.start !== expectedRange.pos ||
|
||||
ts.textSpanEnd(renameInfo.triggerSpan) !== expectedRange.end) {
|
||||
this.raiseError("Expected triggerSpan [" + expectedRange.pos + "," + expectedRange.end + "). Got [" +
|
||||
@@ -3977,7 +3986,7 @@ namespace FourSlashInterface {
|
||||
this.state.goToRangeStart(range);
|
||||
}
|
||||
|
||||
public eachRange(action: () => void) {
|
||||
public eachRange(action: (range: FourSlash.Range) => void) {
|
||||
this.state.goToEachRange(action);
|
||||
}
|
||||
|
||||
@@ -4456,8 +4465,8 @@ namespace FourSlashInterface {
|
||||
this.state.verifySemanticClassifications(classifications);
|
||||
}
|
||||
|
||||
public renameInfoSucceeded(displayName?: string, fullDisplayName?: string, kind?: string, kindModifiers?: string) {
|
||||
this.state.verifyRenameInfoSucceeded(displayName, fullDisplayName, kind, kindModifiers);
|
||||
public renameInfoSucceeded(displayName?: string, fullDisplayName?: string, kind?: string, kindModifiers?: string, fileToRename?: string, expectedRange?: FourSlash.Range) {
|
||||
this.state.verifyRenameInfoSucceeded(displayName, fullDisplayName, kind, kindModifiers, fileToRename, expectedRange);
|
||||
}
|
||||
|
||||
public renameInfoFailed(message?: string) {
|
||||
@@ -4799,6 +4808,7 @@ namespace FourSlashInterface {
|
||||
readonly text: string;
|
||||
readonly documentation: string;
|
||||
readonly sourceDisplay?: string;
|
||||
readonly tags?: ReadonlyArray<ts.JSDocTagInfo>;
|
||||
};
|
||||
export interface CompletionsAtOptions extends Partial<ts.UserPreferences> {
|
||||
triggerCharacter?: ts.CompletionsTriggerCharacter;
|
||||
|
||||
@@ -268,7 +268,7 @@ namespace Harness.LanguageService {
|
||||
getHost(): LanguageServiceAdapterHost { return this.host; }
|
||||
getLanguageService(): ts.LanguageService { return ts.createLanguageService(this.host); }
|
||||
getClassifier(): ts.Classifier { return ts.createClassifier(); }
|
||||
getPreProcessedFileInfo(fileName: string, fileContents: string): ts.PreProcessedFileInfo { return ts.preProcessFile(fileContents, /* readImportFiles */ true, ts.hasJavaScriptFileExtension(fileName)); }
|
||||
getPreProcessedFileInfo(fileName: string, fileContents: string): ts.PreProcessedFileInfo { return ts.preProcessFile(fileContents, /* readImportFiles */ true, ts.hasJSFileExtension(fileName)); }
|
||||
}
|
||||
|
||||
/// Shim adapter
|
||||
|
||||
@@ -7,6 +7,21 @@ namespace utils {
|
||||
return text !== undefined ? text.replace(testPathPrefixRegExp, (_, scheme) => scheme || (retainTrailingDirectorySeparator ? "/" : "")) : undefined!; // TODO: GH#18217
|
||||
}
|
||||
|
||||
function createDiagnosticMessageReplacer<R extends (messageArgs: string[], ...args: string[]) => string[]>(diagnosticMessage: ts.DiagnosticMessage, replacer: R) {
|
||||
const messageParts = diagnosticMessage.message.split(/{\d+}/g);
|
||||
const regExp = new RegExp(`^(?:${messageParts.map(ts.regExpEscape).join("(.*?)")})$`);
|
||||
type Args<R> = R extends (messageArgs: string[], ...args: infer A) => string[] ? A : [];
|
||||
return (text: string, ...args: Args<R>) => text.replace(regExp, (_, ...fixedArgs) => ts.formatStringFromArgs(diagnosticMessage.message, replacer(fixedArgs, ...args)));
|
||||
}
|
||||
|
||||
const replaceTypesVersionsMessage = createDiagnosticMessageReplacer(
|
||||
ts.Diagnostics.package_json_has_a_typesVersions_entry_0_that_matches_compiler_version_1_looking_for_a_pattern_to_match_module_name_2,
|
||||
([entry, , moduleName], compilerVersion) => [entry, compilerVersion, moduleName]);
|
||||
|
||||
export function sanitizeTraceResolutionLogEntry(text: string) {
|
||||
return text && removeTestPathPrefixes(replaceTypesVersionsMessage(text, "3.1.0-dev"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes leading indentation from a template literal string.
|
||||
*/
|
||||
@@ -82,4 +97,16 @@ namespace utils {
|
||||
export function addUTF8ByteOrderMark(text: string) {
|
||||
return getByteOrderMarkLength(text) === 0 ? "\u00EF\u00BB\u00BF" + text : text;
|
||||
}
|
||||
|
||||
export function theory<T extends any[]>(name: string, cb: (...args: T) => void, data: T[]) {
|
||||
for (const entry of data) {
|
||||
it(`${name}(${entry.map(formatTheoryDatum).join(", ")})`, () => cb(...entry));
|
||||
}
|
||||
}
|
||||
|
||||
function formatTheoryDatum(value: any) {
|
||||
return typeof value === "function" ? value.name || "<anonymous function>" :
|
||||
value === undefined ? "undefined" :
|
||||
JSON.stringify(value);
|
||||
}
|
||||
}
|
||||
@@ -21,8 +21,8 @@ namespace vpath {
|
||||
export import relative = ts.getRelativePathFromDirectory;
|
||||
export import beneath = ts.containsPath;
|
||||
export import changeExtension = ts.changeAnyExtension;
|
||||
export import isTypeScript = ts.hasTypeScriptFileExtension;
|
||||
export import isJavaScript = ts.hasJavaScriptFileExtension;
|
||||
export import isTypeScript = ts.hasTSFileExtension;
|
||||
export import isJavaScript = ts.hasJSFileExtension;
|
||||
|
||||
const invalidRootComponentRegExp = /^(?!(\/|\/\/\w+\/|[a-zA-Z]:\/?|)$)/;
|
||||
const invalidNavigableComponentRegExp = /[:*?"<>|]/;
|
||||
@@ -133,4 +133,4 @@ namespace vpath {
|
||||
export function isTsConfigFile(path: string): boolean {
|
||||
return path.indexOf("tsconfig") !== -1 && path.indexOf("json") !== -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,13 +21,13 @@ namespace ts.JsTyping {
|
||||
|
||||
export interface CachedTyping {
|
||||
typingLocation: string;
|
||||
version: Semver;
|
||||
version: Version;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function isTypingUpToDate(cachedTyping: CachedTyping, availableTypingVersions: MapLike<string>) {
|
||||
const availableVersion = Semver.parse(getProperty(availableTypingVersions, `ts${versionMajorMinor}`) || getProperty(availableTypingVersions, "latest")!);
|
||||
return !availableVersion.greaterThan(cachedTyping.version);
|
||||
const availableVersion = new Version(getProperty(availableTypingVersions, `ts${versionMajorMinor}`) || getProperty(availableTypingVersions, "latest")!);
|
||||
return availableVersion.compareTo(cachedTyping.version) <= 0;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -122,7 +122,7 @@ namespace ts.JsTyping {
|
||||
// Only infer typings for .js and .jsx files
|
||||
fileNames = mapDefined(fileNames, fileName => {
|
||||
const path = normalizePath(fileName);
|
||||
if (hasJavaScriptFileExtension(path)) {
|
||||
if (hasJSFileExtension(path)) {
|
||||
return path;
|
||||
}
|
||||
});
|
||||
@@ -218,7 +218,7 @@ namespace ts.JsTyping {
|
||||
*/
|
||||
function getTypingNamesFromSourceFileNames(fileNames: string[]) {
|
||||
const fromFileNames = mapDefined(fileNames, j => {
|
||||
if (!hasJavaScriptFileExtension(j)) return undefined;
|
||||
if (!hasJSFileExtension(j)) return undefined;
|
||||
|
||||
const inferredTypingName = removeFileExtension(getBaseFileName(j.toLowerCase()));
|
||||
const cleanedTypingName = removeMinAndVersionNumbers(inferredTypingName);
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
function stringToInt(str: string): number {
|
||||
const n = parseInt(str, 10);
|
||||
if (isNaN(n)) {
|
||||
throw new Error(`Error in parseInt(${JSON.stringify(str)})`);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
const isPrereleaseRegex = /^(.*)-next.\d+/;
|
||||
const prereleaseSemverRegex = /^(\d+)\.(\d+)\.0-next.(\d+)$/;
|
||||
const semverRegex = /^(\d+)\.(\d+)\.(\d+)$/;
|
||||
|
||||
export class Semver {
|
||||
static parse(semver: string): Semver {
|
||||
const isPrerelease = isPrereleaseRegex.test(semver);
|
||||
const result = Semver.tryParse(semver, isPrerelease);
|
||||
if (!result) {
|
||||
throw new Error(`Unexpected semver: ${semver} (isPrerelease: ${isPrerelease})`);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static fromRaw({ major, minor, patch, isPrerelease }: Semver): Semver {
|
||||
return new Semver(major, minor, patch, isPrerelease);
|
||||
}
|
||||
|
||||
// This must parse the output of `versionString`.
|
||||
private static tryParse(semver: string, isPrerelease: boolean): Semver | undefined {
|
||||
// Per the semver spec <http://semver.org/#spec-item-2>:
|
||||
// "A normal version number MUST take the form X.Y.Z where X, Y, and Z are non-negative integers, and MUST NOT contain leading zeroes."
|
||||
const rgx = isPrerelease ? prereleaseSemverRegex : semverRegex;
|
||||
const match = rgx.exec(semver);
|
||||
return match ? new Semver(stringToInt(match[1]), stringToInt(match[2]), stringToInt(match[3]), isPrerelease) : undefined;
|
||||
}
|
||||
|
||||
private constructor(
|
||||
readonly major: number, readonly minor: number, readonly patch: number,
|
||||
/**
|
||||
* If true, this is `major.minor.0-next.patch`.
|
||||
* If false, this is `major.minor.patch`.
|
||||
*/
|
||||
readonly isPrerelease: boolean) { }
|
||||
|
||||
get versionString(): string {
|
||||
return this.isPrerelease ? `${this.major}.${this.minor}.0-next.${this.patch}` : `${this.major}.${this.minor}.${this.patch}`;
|
||||
}
|
||||
|
||||
equals(sem: Semver): boolean {
|
||||
return this.major === sem.major && this.minor === sem.minor && this.patch === sem.patch && this.isPrerelease === sem.isPrerelease;
|
||||
}
|
||||
|
||||
greaterThan(sem: Semver): boolean {
|
||||
return this.major > sem.major || this.major === sem.major
|
||||
&& (this.minor > sem.minor || this.minor === sem.minor
|
||||
&& (!this.isPrerelease && sem.isPrerelease || this.isPrerelease === sem.isPrerelease
|
||||
&& this.patch > sem.patch));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
"files": [
|
||||
"shared.ts",
|
||||
"types.ts",
|
||||
"jsTyping.ts",
|
||||
"semver.ts"
|
||||
"jsTyping.ts"
|
||||
]
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -7,7 +7,7 @@ interface PromiseConstructor {
|
||||
/**
|
||||
* Creates a new Promise.
|
||||
* @param executor A callback used to initialize the promise. This callback is passed two arguments:
|
||||
* a resolve callback used resolve the promise with a value or the result of another promise,
|
||||
* a resolve callback used to resolve the promise with a value or the result of another promise,
|
||||
* and a reject callback used to reject the promise with a provided reason or error.
|
||||
*/
|
||||
new <T>(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): Promise<T>;
|
||||
@@ -193,4 +193,4 @@ interface PromiseConstructor {
|
||||
resolve(): Promise<void>;
|
||||
}
|
||||
|
||||
declare var Promise: PromiseConstructor;
|
||||
declare var Promise: PromiseConstructor;
|
||||
|
||||
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
+105
-16
@@ -291,7 +291,8 @@ namespace ts.server {
|
||||
ClosedScriptInfo = "Closed Script info",
|
||||
ConfigFileForInferredRoot = "Config file for the inferred project root",
|
||||
FailedLookupLocation = "Directory of Failed lookup locations in module resolution",
|
||||
TypeRoots = "Type root directory"
|
||||
TypeRoots = "Type root directory",
|
||||
NodeModulesForClosedScriptInfo = "node_modules for closed script infos in them",
|
||||
}
|
||||
|
||||
const enum ConfigFileWatcherStatus {
|
||||
@@ -353,10 +354,18 @@ namespace ts.server {
|
||||
return !!(infoOrFileName as ScriptInfo).containingProjects;
|
||||
}
|
||||
|
||||
interface ScriptInfoInNodeModulesWatcher extends FileWatcher {
|
||||
refCount: number;
|
||||
}
|
||||
|
||||
function getDetailWatchInfo(watchType: WatchType, project: Project | undefined) {
|
||||
return `Project: ${project ? project.getProjectName() : ""} WatchType: ${watchType}`;
|
||||
}
|
||||
|
||||
function isScriptInfoWatchedFromNodeModules(info: ScriptInfo) {
|
||||
return !info.isScriptOpen() && info.mTime !== undefined;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function updateProjectIfDirty(project: Project) {
|
||||
return project.dirty && project.updateGraph();
|
||||
@@ -380,6 +389,7 @@ namespace ts.server {
|
||||
* Container of all known scripts
|
||||
*/
|
||||
private readonly filenameToScriptInfo = createMap<ScriptInfo>();
|
||||
private readonly scriptInfoInNodeModulesWatchers = createMap <ScriptInfoInNodeModulesWatcher>();
|
||||
/**
|
||||
* Contains all the deleted script info's version information so that
|
||||
* it does not reset when creating script info again
|
||||
@@ -487,7 +497,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");
|
||||
@@ -1447,14 +1457,14 @@ namespace ts.server {
|
||||
|
||||
for (const f of fileNames) {
|
||||
const fileName = propertyReader.getFileName(f);
|
||||
if (hasTypeScriptFileExtension(fileName)) {
|
||||
if (hasTSFileExtension(fileName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
totalNonTsFileSize += this.host.getFileSize(fileName);
|
||||
|
||||
if (totalNonTsFileSize > maxProgramSizeForNonTsFiles || totalNonTsFileSize > availableSpace) {
|
||||
this.logger.info(getExceedLimitMessage({ propertyReader, hasTypeScriptFileExtension, host: this.host }, totalNonTsFileSize));
|
||||
this.logger.info(getExceedLimitMessage({ propertyReader, hasTSFileExtension, host: this.host }, totalNonTsFileSize));
|
||||
// Keep the size as zero since it's disabled
|
||||
return fileName;
|
||||
}
|
||||
@@ -1464,14 +1474,14 @@ namespace ts.server {
|
||||
|
||||
return;
|
||||
|
||||
function getExceedLimitMessage(context: { propertyReader: FilePropertyReader<any>, hasTypeScriptFileExtension: (filename: string) => boolean, host: ServerHost }, totalNonTsFileSize: number) {
|
||||
function getExceedLimitMessage(context: { propertyReader: FilePropertyReader<any>, hasTSFileExtension: (filename: string) => boolean, host: ServerHost }, totalNonTsFileSize: number) {
|
||||
const files = getTop5LargestFiles(context);
|
||||
|
||||
return `Non TS file size exceeded limit (${totalNonTsFileSize}). Largest files: ${files.map(file => `${file.name}:${file.size}`).join(", ")}`;
|
||||
}
|
||||
function getTop5LargestFiles({ propertyReader, hasTypeScriptFileExtension, host }: { propertyReader: FilePropertyReader<any>, hasTypeScriptFileExtension: (filename: string) => boolean, host: ServerHost }) {
|
||||
function getTop5LargestFiles({ propertyReader, hasTSFileExtension, host }: { propertyReader: FilePropertyReader<any>, hasTSFileExtension: (filename: string) => boolean, host: ServerHost }) {
|
||||
return fileNames.map(f => propertyReader.getFileName(f))
|
||||
.filter(name => hasTypeScriptFileExtension(name))
|
||||
.filter(name => hasTSFileExtension(name))
|
||||
.map(name => ({ name, size: host.getFileSize!(name) })) // TODO: GH#18217
|
||||
.sort((a, b) => b.size - a.size)
|
||||
.slice(0, 5);
|
||||
@@ -1923,18 +1933,97 @@ namespace ts.server {
|
||||
if (!info.isDynamicOrHasMixedContent() &&
|
||||
(!this.globalCacheLocationDirectoryPath ||
|
||||
!startsWith(info.path, this.globalCacheLocationDirectoryPath))) {
|
||||
const { fileName } = info;
|
||||
info.fileWatcher = this.watchFactory.watchFilePath(
|
||||
this.host,
|
||||
fileName,
|
||||
(fileName, eventKind, path) => this.onSourceFileChanged(fileName, eventKind, path),
|
||||
PollingInterval.Medium,
|
||||
info.path,
|
||||
WatchType.ClosedScriptInfo
|
||||
);
|
||||
const indexOfNodeModules = info.path.indexOf("/node_modules/");
|
||||
if (!this.host.getModifiedTime || indexOfNodeModules === -1) {
|
||||
info.fileWatcher = this.watchFactory.watchFilePath(
|
||||
this.host,
|
||||
info.fileName,
|
||||
(fileName, eventKind, path) => this.onSourceFileChanged(fileName, eventKind, path),
|
||||
PollingInterval.Medium,
|
||||
info.path,
|
||||
WatchType.ClosedScriptInfo
|
||||
);
|
||||
}
|
||||
else {
|
||||
info.mTime = this.getModifiedTime(info);
|
||||
info.fileWatcher = this.watchClosedScriptInfoInNodeModules(info.path.substr(0, indexOfNodeModules) as Path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private watchClosedScriptInfoInNodeModules(dir: Path): ScriptInfoInNodeModulesWatcher {
|
||||
// Watch only directory
|
||||
const existing = this.scriptInfoInNodeModulesWatchers.get(dir);
|
||||
if (existing) {
|
||||
existing.refCount++;
|
||||
return existing;
|
||||
}
|
||||
|
||||
const watchDir = dir + "/node_modules" as Path;
|
||||
const watcher = this.watchFactory.watchDirectory(
|
||||
this.host,
|
||||
watchDir,
|
||||
(fileOrDirectory) => {
|
||||
const fileOrDirectoryPath = this.toPath(fileOrDirectory);
|
||||
// Has extension
|
||||
Debug.assert(result.refCount > 0);
|
||||
if (watchDir === fileOrDirectoryPath) {
|
||||
this.refreshScriptInfosInDirectory(watchDir);
|
||||
}
|
||||
else {
|
||||
const info = this.getScriptInfoForPath(fileOrDirectoryPath);
|
||||
if (info) {
|
||||
if (isScriptInfoWatchedFromNodeModules(info)) {
|
||||
this.refreshScriptInfo(info);
|
||||
}
|
||||
}
|
||||
// Folder
|
||||
else if (!hasExtension(fileOrDirectoryPath)) {
|
||||
this.refreshScriptInfosInDirectory(fileOrDirectoryPath);
|
||||
}
|
||||
}
|
||||
},
|
||||
WatchDirectoryFlags.Recursive,
|
||||
WatchType.NodeModulesForClosedScriptInfo
|
||||
);
|
||||
const result: ScriptInfoInNodeModulesWatcher = {
|
||||
close: () => {
|
||||
if (result.refCount === 1) {
|
||||
watcher.close();
|
||||
this.scriptInfoInNodeModulesWatchers.delete(dir);
|
||||
}
|
||||
else {
|
||||
result.refCount--;
|
||||
}
|
||||
},
|
||||
refCount: 1
|
||||
};
|
||||
this.scriptInfoInNodeModulesWatchers.set(dir, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private getModifiedTime(info: ScriptInfo) {
|
||||
return (this.host.getModifiedTime!(info.path) || missingFileModifiedTime).getTime();
|
||||
}
|
||||
|
||||
private refreshScriptInfo(info: ScriptInfo) {
|
||||
const mTime = this.getModifiedTime(info);
|
||||
if (mTime !== info.mTime) {
|
||||
const eventKind = getFileWatcherEventKind(info.mTime!, mTime);
|
||||
info.mTime = mTime;
|
||||
this.onSourceFileChanged(info.fileName, eventKind, info.path);
|
||||
}
|
||||
}
|
||||
|
||||
private refreshScriptInfosInDirectory(dir: Path) {
|
||||
dir = dir + directorySeparator as Path;
|
||||
this.filenameToScriptInfo.forEach(info => {
|
||||
if (isScriptInfoWatchedFromNodeModules(info) && startsWith(info.path, dir)) {
|
||||
this.refreshScriptInfo(info);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private stopWatchingScriptInfo(info: ScriptInfo) {
|
||||
if (info.fileWatcher) {
|
||||
info.fileWatcher.close();
|
||||
|
||||
@@ -574,7 +574,7 @@ namespace ts.server {
|
||||
for (const f of this.program.getSourceFiles()) {
|
||||
this.detachScriptInfoIfNotRoot(f.fileName);
|
||||
}
|
||||
const projectReferences = this.program.getProjectReferences();
|
||||
const projectReferences = this.program.getResolvedProjectReferences();
|
||||
if (projectReferences) {
|
||||
for (const ref of projectReferences) {
|
||||
if (ref) {
|
||||
@@ -1390,7 +1390,7 @@ namespace ts.server {
|
||||
/*@internal*/
|
||||
getResolvedProjectReferences() {
|
||||
const program = this.getCurrentProgram();
|
||||
return program && program.getProjectReferences();
|
||||
return program && program.getResolvedProjectReferences();
|
||||
}
|
||||
|
||||
enablePlugins() {
|
||||
|
||||
@@ -1093,6 +1093,12 @@ namespace ts.server.protocol {
|
||||
*/
|
||||
canRename: boolean;
|
||||
|
||||
/**
|
||||
* File or directory to rename.
|
||||
* If set, `getEditsForFileRename` should be called instead of `findRenameLocations`.
|
||||
*/
|
||||
fileToRename?: string;
|
||||
|
||||
/**
|
||||
* Error message if item can not be renamed.
|
||||
*/
|
||||
|
||||
@@ -167,7 +167,7 @@ namespace ts.server {
|
||||
const fileName = tempFileName || this.fileName;
|
||||
const getText = () => text === undefined ? (text = this.host.readFile(fileName) || "") : text;
|
||||
// Only non typescript files have size limitation
|
||||
if (!hasTypeScriptFileExtension(this.fileName)) {
|
||||
if (!hasTSFileExtension(this.fileName)) {
|
||||
const fileSize = this.host.getFileSize ? this.host.getFileSize(fileName) : getText().length;
|
||||
if (fileSize > maxFileSize) {
|
||||
Debug.assert(!!this.info.containingProjects.length);
|
||||
@@ -250,6 +250,9 @@ namespace ts.server {
|
||||
/*@internal*/
|
||||
cacheSourceFile: DocumentRegistrySourceFileCache;
|
||||
|
||||
/*@internal*/
|
||||
mTime?: number;
|
||||
|
||||
constructor(
|
||||
private readonly host: ServerHost,
|
||||
readonly fileName: NormalizedPath,
|
||||
|
||||
@@ -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) {
|
||||
@@ -1101,7 +1096,7 @@ namespace ts.server {
|
||||
return projectInfo;
|
||||
}
|
||||
|
||||
private getRenameInfo(args: protocol.FileLocationRequestArgs) {
|
||||
private getRenameInfo(args: protocol.FileLocationRequestArgs): RenameInfo {
|
||||
const { file, project } = this.getFileAndProject(args);
|
||||
const position = this.getPositionInFile(args, file);
|
||||
return project.getLanguageService().getRenameInfo(file, position);
|
||||
|
||||
@@ -138,7 +138,7 @@ namespace ts.codefix {
|
||||
|
||||
default: {
|
||||
// Don't try to declare members in JavaScript files
|
||||
if (isSourceFileJavaScript(sourceFile)) {
|
||||
if (isSourceFileJS(sourceFile)) {
|
||||
return;
|
||||
}
|
||||
const prop = createProperty(/*decorators*/ undefined, modifiers, memberDeclaration.name, /*questionToken*/ undefined,
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
namespace ts.codefix {
|
||||
const fixId = "convertToAsyncFunction";
|
||||
const errorCodes = [Diagnostics.This_may_be_converted_to_an_async_function.code];
|
||||
let codeActionSucceeded = true;
|
||||
registerCodeFix({
|
||||
errorCodes,
|
||||
getCodeActions(context: CodeFixContext) {
|
||||
codeActionSucceeded = true;
|
||||
const changes = textChanges.ChangeTracker.with(context, (t) => convertToAsyncFunction(t, context.sourceFile, context.span.start, context.program.getTypeChecker(), context));
|
||||
return [createCodeFixAction(fixId, changes, Diagnostics.Convert_to_async_function, fixId, Diagnostics.Convert_all_to_async_functions)];
|
||||
return codeActionSucceeded ? [createCodeFixAction(fixId, changes, Diagnostics.Convert_to_async_function, fixId, Diagnostics.Convert_all_to_async_functions)] : [];
|
||||
},
|
||||
fixIds: [fixId],
|
||||
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, err) => convertToAsyncFunction(changes, err.file, err.start, context.program.getTypeChecker(), context)),
|
||||
@@ -61,12 +63,12 @@ namespace ts.codefix {
|
||||
const synthNamesMap: Map<SynthIdentifier> = createMap();
|
||||
const originalTypeMap: Map<Type> = createMap();
|
||||
const allVarNames: SymbolAndIdentifier[] = [];
|
||||
const isInJSFile = isInJavaScriptFile(functionToConvert);
|
||||
const isInJavascript = isInJSFile(functionToConvert);
|
||||
const setOfExpressionsToReturn = getAllPromiseExpressionsToReturn(functionToConvert, checker);
|
||||
const functionToConvertRenamed: FunctionLikeDeclaration = renameCollidingVarNames(functionToConvert, checker, synthNamesMap, context, setOfExpressionsToReturn, originalTypeMap, allVarNames);
|
||||
const constIdentifiers = getConstIdentifiers(synthNamesMap);
|
||||
const returnStatements = getReturnStatementsWithPromiseHandlers(functionToConvertRenamed);
|
||||
const transformer = { checker, synthNamesMap, allVarNames, setOfExpressionsToReturn, constIdentifiers, originalTypeMap, isInJSFile };
|
||||
const transformer = { checker, synthNamesMap, allVarNames, setOfExpressionsToReturn, constIdentifiers, originalTypeMap, isInJSFile: isInJavascript };
|
||||
|
||||
if (!returnStatements.length) {
|
||||
return;
|
||||
@@ -81,19 +83,14 @@ namespace ts.codefix {
|
||||
}
|
||||
|
||||
for (const statement of returnStatements) {
|
||||
if (isCallExpression(statement)) {
|
||||
startTransformation(statement, statement);
|
||||
}
|
||||
else {
|
||||
forEachChild(statement, function visit(node: Node) {
|
||||
if (isCallExpression(node)) {
|
||||
startTransformation(node, statement);
|
||||
}
|
||||
else if (!isFunctionLike(node)) {
|
||||
forEachChild(node, visit);
|
||||
}
|
||||
});
|
||||
}
|
||||
forEachChild(statement, function visit(node) {
|
||||
if (isCallExpression(node)) {
|
||||
startTransformation(node, statement);
|
||||
}
|
||||
else if (!isFunctionLike(node)) {
|
||||
forEachChild(node, visit);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,6 +162,7 @@ namespace ts.codefix {
|
||||
function renameCollidingVarNames(nodeToRename: FunctionLikeDeclaration, checker: TypeChecker, synthNamesMap: Map<SynthIdentifier>, context: CodeFixContextBase, setOfAllExpressionsToReturn: Map<true>, originalType: Map<Type>, allVarNames: SymbolAndIdentifier[]): FunctionLikeDeclaration {
|
||||
|
||||
const identsToRenameMap: Map<Identifier> = createMap(); // key is the symbol id
|
||||
const collidingSymbolMap: Map<Symbol[]> = createMap();
|
||||
forEachChild(nodeToRename, function visit(node: Node) {
|
||||
if (!isIdentifier(node)) {
|
||||
forEachChild(node, visit);
|
||||
@@ -182,19 +180,25 @@ namespace ts.codefix {
|
||||
// if the identifier refers to a function we want to add the new synthesized variable for the declaration (ex. blob in let blob = res(arg))
|
||||
// Note - the choice of the last call signature is arbitrary
|
||||
if (lastCallSignature && lastCallSignature.parameters.length && !synthNamesMap.has(symbolIdString)) {
|
||||
const synthName = getNewNameIfConflict(createIdentifier(lastCallSignature.parameters[0].name), allVarNames);
|
||||
const firstParameter = lastCallSignature.parameters[0];
|
||||
const ident = isParameter(firstParameter.valueDeclaration) && tryCast(firstParameter.valueDeclaration.name, isIdentifier) || createOptimisticUniqueName("result");
|
||||
const synthName = getNewNameIfConflict(ident, collidingSymbolMap);
|
||||
synthNamesMap.set(symbolIdString, synthName);
|
||||
allVarNames.push({ identifier: synthName.identifier, symbol });
|
||||
addNameToFrequencyMap(collidingSymbolMap, ident.text, symbol);
|
||||
}
|
||||
// we only care about identifiers that are parameters and declarations (don't care about other uses)
|
||||
else if (node.parent && (isParameter(node.parent) || isVariableDeclaration(node.parent))) {
|
||||
const originalName = node.text;
|
||||
const collidingSymbols = collidingSymbolMap.get(originalName);
|
||||
|
||||
// if the identifier name conflicts with a different identifier that we've already seen
|
||||
if (allVarNames.some(ident => ident.identifier.text === node.text && ident.symbol !== symbol)) {
|
||||
const newName = getNewNameIfConflict(node, allVarNames);
|
||||
if (collidingSymbols && collidingSymbols.some(prevSymbol => prevSymbol !== symbol)) {
|
||||
const newName = getNewNameIfConflict(node, collidingSymbolMap);
|
||||
identsToRenameMap.set(symbolIdString, newName.identifier);
|
||||
synthNamesMap.set(symbolIdString, newName);
|
||||
allVarNames.push({ identifier: newName.identifier, symbol });
|
||||
addNameToFrequencyMap(collidingSymbolMap, originalName, symbol);
|
||||
}
|
||||
else {
|
||||
const identifier = getSynthesizedDeepClone(node);
|
||||
@@ -202,6 +206,7 @@ namespace ts.codefix {
|
||||
synthNamesMap.set(symbolIdString, { identifier, types: [], numberOfAssignmentsOriginal: allVarNames.filter(elem => elem.identifier.text === node.text).length/*, numberOfAssignmentsSynthesized: 0*/ });
|
||||
if ((isParameter(node.parent) && isExpressionOrCallOnTypePromise(node.parent.parent)) || isVariableDeclaration(node.parent)) {
|
||||
allVarNames.push({ identifier, symbol });
|
||||
addNameToFrequencyMap(collidingSymbolMap, originalName, symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -244,14 +249,24 @@ namespace ts.codefix {
|
||||
|
||||
}
|
||||
|
||||
function getNewNameIfConflict(name: Identifier, allVarNames: SymbolAndIdentifier[]): SynthIdentifier {
|
||||
const numVarsSameName = allVarNames.filter(elem => elem.identifier.text === name.text).length;
|
||||
function addNameToFrequencyMap(renamedVarNameFrequencyMap: Map<Symbol[]>, originalName: string, symbol: Symbol) {
|
||||
if (renamedVarNameFrequencyMap.has(originalName)) {
|
||||
renamedVarNameFrequencyMap.get(originalName)!.push(symbol);
|
||||
}
|
||||
else {
|
||||
renamedVarNameFrequencyMap.set(originalName, [symbol]);
|
||||
}
|
||||
}
|
||||
|
||||
function getNewNameIfConflict(name: Identifier, originalNames: Map<Symbol[]>): SynthIdentifier {
|
||||
const numVarsSameName = (originalNames.get(name.text) || []).length;
|
||||
const numberOfAssignmentsOriginal = 0;
|
||||
const identifier = numVarsSameName === 0 ? name : createIdentifier(name.text + "_" + numVarsSameName);
|
||||
return { identifier, types: [], numberOfAssignmentsOriginal };
|
||||
}
|
||||
|
||||
// dispatch function to recursively build the refactoring
|
||||
// should be kept up to date with isFixablePromiseHandler in suggestionDiagnostics.ts
|
||||
function transformExpression(node: Expression, transformer: Transformer, outermostParent: CallExpression, prevArgName?: SynthIdentifier): Statement[] {
|
||||
if (!node) {
|
||||
return [];
|
||||
@@ -273,6 +288,7 @@ namespace ts.codefix {
|
||||
return transformPromiseCall(node, transformer, prevArgName);
|
||||
}
|
||||
|
||||
codeActionSucceeded = false;
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -290,13 +306,14 @@ namespace ts.codefix {
|
||||
prevArgName.numberOfAssignmentsOriginal = 2; // Try block and catch block
|
||||
transformer.synthNamesMap.forEach((val, key) => {
|
||||
if (val.identifier.text === prevArgName.identifier.text) {
|
||||
transformer.synthNamesMap.set(key, getNewNameIfConflict(prevArgName.identifier, transformer.allVarNames));
|
||||
const newSynthName = createUniqueSynthName(prevArgName);
|
||||
transformer.synthNamesMap.set(key, newSynthName);
|
||||
}
|
||||
});
|
||||
|
||||
// update the constIdentifiers list
|
||||
if (transformer.constIdentifiers.some(elem => elem.text === prevArgName.identifier.text)) {
|
||||
transformer.constIdentifiers.push(getNewNameIfConflict(prevArgName.identifier, transformer.allVarNames).identifier);
|
||||
transformer.constIdentifiers.push(createUniqueSynthName(prevArgName).identifier);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,6 +339,12 @@ namespace ts.codefix {
|
||||
return varDeclList ? [varDeclList, tryStatement] : [tryStatement];
|
||||
}
|
||||
|
||||
function createUniqueSynthName(prevArgName: SynthIdentifier) {
|
||||
const renamedPrevArg = createOptimisticUniqueName(prevArgName.identifier.text);
|
||||
const newSynthName = { identifier: renamedPrevArg, types: [], numberOfAssignmentsOriginal: 0 };
|
||||
return newSynthName;
|
||||
}
|
||||
|
||||
function transformThen(node: CallExpression, transformer: Transformer, outermostParent: CallExpression, prevArgName?: SynthIdentifier): Statement[] {
|
||||
const [res, rej] = node.arguments;
|
||||
|
||||
@@ -344,11 +367,8 @@ namespace ts.codefix {
|
||||
|
||||
return [createTry(tryBlock, catchClause, /* finallyBlock */ undefined) as Statement];
|
||||
}
|
||||
else {
|
||||
return transformExpression(node.expression, transformer, node, argNameRes).concat(transformationBody);
|
||||
}
|
||||
|
||||
return [];
|
||||
return transformExpression(node.expression, transformer, node, argNameRes).concat(transformationBody);
|
||||
}
|
||||
|
||||
function getFlagOfIdentifier(node: Identifier, constIdentifiers: Identifier[]): NodeFlags {
|
||||
@@ -381,13 +401,18 @@ namespace ts.codefix {
|
||||
(createVariableDeclarationList([createVariableDeclaration(getSynthesizedDeepClone(prevArgName.identifier), /*type*/ undefined, rightHandSide)], getFlagOfIdentifier(prevArgName.identifier, transformer.constIdentifiers))))]);
|
||||
}
|
||||
|
||||
// should be kept up to date with isFixablePromiseArgument in suggestionDiagnostics.ts
|
||||
function getTransformationBody(func: Node, prevArgName: SynthIdentifier | undefined, argName: SynthIdentifier, parent: CallExpression, transformer: Transformer): NodeArray<Statement> {
|
||||
|
||||
const hasPrevArgName = prevArgName && prevArgName.identifier.text.length > 0;
|
||||
const hasArgName = argName && argName.identifier.text.length > 0;
|
||||
const shouldReturn = transformer.setOfExpressionsToReturn.get(getNodeId(parent).toString());
|
||||
switch (func.kind) {
|
||||
case SyntaxKind.NullKeyword:
|
||||
// do not produce a transformed statement for a null argument
|
||||
break;
|
||||
case SyntaxKind.Identifier:
|
||||
// identifier includes undefined
|
||||
if (!hasArgName) break;
|
||||
|
||||
const synthCall = createCall(getSynthesizedDeepClone(func) as Identifier, /*typeArguments*/ undefined, [argName.identifier]);
|
||||
@@ -410,8 +435,13 @@ namespace ts.codefix {
|
||||
// Arrow functions with block bodies { } will enter this control flow
|
||||
if (isFunctionLikeDeclaration(func) && func.body && isBlock(func.body) && func.body.statements) {
|
||||
let refactoredStmts: Statement[] = [];
|
||||
let seenReturnStatement = false;
|
||||
|
||||
for (const statement of func.body.statements) {
|
||||
if (isReturnStatement(statement)) {
|
||||
seenReturnStatement = true;
|
||||
}
|
||||
|
||||
if (getReturnStatementsWithPromiseHandlers(statement).length) {
|
||||
refactoredStmts = refactoredStmts.concat(getInnerTransformationBody(transformer, [statement], prevArgName));
|
||||
}
|
||||
@@ -421,7 +451,7 @@ namespace ts.codefix {
|
||||
}
|
||||
|
||||
return shouldReturn ? getSynthesizedDeepClones(createNodeArray(refactoredStmts)) :
|
||||
removeReturns(createNodeArray(refactoredStmts), prevArgName!.identifier, transformer.constIdentifiers);
|
||||
removeReturns(createNodeArray(refactoredStmts), prevArgName!.identifier, transformer.constIdentifiers, seenReturnStatement);
|
||||
}
|
||||
else {
|
||||
const funcBody = (<ArrowFunction>func).body;
|
||||
@@ -434,7 +464,7 @@ namespace ts.codefix {
|
||||
|
||||
if (hasPrevArgName && !shouldReturn) {
|
||||
const type = transformer.checker.getTypeAtLocation(func);
|
||||
const returnType = getLastCallSignature(type, transformer.checker).getReturnType();
|
||||
const returnType = getLastCallSignature(type, transformer.checker)!.getReturnType();
|
||||
const varDeclOrAssignment = createVariableDeclarationOrAssignment(prevArgName!, getSynthesizedDeepClone(funcBody) as Expression, transformer);
|
||||
prevArgName!.types.push(returnType);
|
||||
return varDeclOrAssignment;
|
||||
@@ -443,18 +473,21 @@ namespace ts.codefix {
|
||||
return createNodeArray([createReturn(getSynthesizedDeepClone(funcBody) as Expression)]);
|
||||
}
|
||||
}
|
||||
default:
|
||||
// We've found a transformation body we don't know how to handle, so the refactoring should no-op to avoid deleting code.
|
||||
codeActionSucceeded = false;
|
||||
break;
|
||||
}
|
||||
return createNodeArray([]);
|
||||
}
|
||||
|
||||
function getLastCallSignature(type: Type, checker: TypeChecker): Signature {
|
||||
const callSignatures = type && checker.getSignaturesOfType(type, SignatureKind.Call);
|
||||
return callSignatures && callSignatures[callSignatures.length - 1];
|
||||
function getLastCallSignature(type: Type, checker: TypeChecker): Signature | undefined {
|
||||
const callSignatures = checker.getSignaturesOfType(type, SignatureKind.Call);
|
||||
return lastOrUndefined(callSignatures);
|
||||
}
|
||||
|
||||
|
||||
function removeReturns(stmts: NodeArray<Statement>, prevArgName: Identifier, constIdentifiers: Identifier[]): NodeArray<Statement> {
|
||||
function removeReturns(stmts: NodeArray<Statement>, prevArgName: Identifier, constIdentifiers: Identifier[], seenReturnStatement: boolean): NodeArray<Statement> {
|
||||
const ret: Statement[] = [];
|
||||
for (const stmt of stmts) {
|
||||
if (isReturnStatement(stmt)) {
|
||||
@@ -468,6 +501,12 @@ namespace ts.codefix {
|
||||
}
|
||||
}
|
||||
|
||||
// if block has no return statement, need to define prevArgName as undefined to prevent undeclared variables
|
||||
if (!seenReturnStatement) {
|
||||
ret.push(createVariableStatement(/*modifiers*/ undefined,
|
||||
(createVariableDeclarationList([createVariableDeclaration(prevArgName, /*type*/ undefined, createIdentifier("undefined"))], getFlagOfIdentifier(prevArgName, constIdentifiers)))));
|
||||
}
|
||||
|
||||
return createNodeArray(ret);
|
||||
}
|
||||
|
||||
@@ -492,14 +531,6 @@ namespace ts.codefix {
|
||||
return innerCbBody;
|
||||
}
|
||||
|
||||
function hasPropertyAccessExpressionWithName(node: CallExpression, funcName: string): boolean {
|
||||
if (!isPropertyAccessExpression(node.expression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return node.expression.name.text === funcName;
|
||||
}
|
||||
|
||||
function getArgName(funcNode: Node, transformer: Transformer): SynthIdentifier {
|
||||
|
||||
const numberOfAssignmentsOriginal = 0;
|
||||
@@ -513,9 +544,6 @@ namespace ts.codefix {
|
||||
name = getMapEntryIfExists(param);
|
||||
}
|
||||
}
|
||||
else if (isCallExpression(funcNode) && funcNode.arguments.length > 0 && isIdentifier(funcNode.arguments[0])) {
|
||||
name = { identifier: funcNode.arguments[0] as Identifier, types, numberOfAssignmentsOriginal };
|
||||
}
|
||||
else if (isIdentifier(funcNode)) {
|
||||
name = getMapEntryIfExists(funcNode);
|
||||
}
|
||||
@@ -546,4 +574,4 @@ namespace ts.codefix {
|
||||
return node.original ? node.original : node;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace ts.codefix {
|
||||
getCodeActions(context) {
|
||||
const { sourceFile, program, span, host, formatContext } = context;
|
||||
|
||||
if (!isInJavaScriptFile(sourceFile) || !isCheckJsEnabledForFile(sourceFile, program.getCompilerOptions())) {
|
||||
if (!isInJSFile(sourceFile) || !isCheckJsEnabledForFile(sourceFile, program.getCompilerOptions())) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace ts.codefix {
|
||||
const { parentDeclaration, declSourceFile, inJs, makeStatic, token, call } = info;
|
||||
const methodCodeAction = call && getActionForMethodDeclaration(context, declSourceFile, parentDeclaration, token, call, makeStatic, inJs, context.preferences);
|
||||
const addMember = inJs && !isInterfaceDeclaration(parentDeclaration) ?
|
||||
singleElementArray(getActionsForAddMissingMemberInJavaScriptFile(context, declSourceFile, parentDeclaration, token.text, makeStatic)) :
|
||||
singleElementArray(getActionsForAddMissingMemberInJavascriptFile(context, declSourceFile, parentDeclaration, token.text, makeStatic)) :
|
||||
getActionsForAddMissingMemberInTypeScriptFile(context, declSourceFile, parentDeclaration, token, makeStatic);
|
||||
return concatenate(singleElementArray(methodCodeAction), addMember);
|
||||
},
|
||||
@@ -131,7 +131,7 @@ namespace ts.codefix {
|
||||
if (classOrInterface) {
|
||||
const makeStatic = ((leftExpressionType as TypeReference).target || leftExpressionType) !== checker.getDeclaredTypeOfSymbol(symbol);
|
||||
const declSourceFile = classOrInterface.getSourceFile();
|
||||
const inJs = isSourceFileJavaScript(declSourceFile);
|
||||
const inJs = isSourceFileJS(declSourceFile);
|
||||
const call = tryCast(parent.parent, isCallExpression);
|
||||
return { kind: InfoKind.ClassOrInterface, token, parentDeclaration: classOrInterface, makeStatic, declSourceFile, inJs, call };
|
||||
}
|
||||
@@ -142,7 +142,7 @@ namespace ts.codefix {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getActionsForAddMissingMemberInJavaScriptFile(context: CodeFixContext, declSourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, tokenName: string, makeStatic: boolean): CodeFixAction | undefined {
|
||||
function getActionsForAddMissingMemberInJavascriptFile(context: CodeFixContext, declSourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, tokenName: string, makeStatic: boolean): CodeFixAction | undefined {
|
||||
const changes = textChanges.ChangeTracker.with(context, t => addMissingMemberInJs(t, declSourceFile, classDeclaration, tokenName, makeStatic));
|
||||
return changes.length === 0 ? undefined
|
||||
: createCodeFixAction(fixName, changes, [makeStatic ? Diagnostics.Initialize_static_property_0 : Diagnostics.Initialize_property_0_in_the_constructor, tokenName], fixId, Diagnostics.Add_all_missing_members);
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace ts.codefix {
|
||||
|
||||
function getTypesPackageNameToInstall(host: LanguageServiceHost, sourceFile: SourceFile, pos: number, diagCode: number): string | undefined {
|
||||
const moduleName = cast(getTokenAtPosition(sourceFile, pos), isStringLiteral).text;
|
||||
const { packageName } = getPackageName(moduleName);
|
||||
const { packageName } = parsePackageName(moduleName);
|
||||
return diagCode === errorCodeCannotFindModule
|
||||
? (JsTyping.nodeCoreModules.has(packageName) ? "@types/node" : undefined)
|
||||
: (host.isKnownTypesPackageName!(packageName) ? getTypesPackageName(packageName) : undefined); // TODO: GH#18217
|
||||
|
||||
@@ -110,7 +110,7 @@ namespace ts.codefix {
|
||||
|
||||
function getDefaultValueFromType (checker: TypeChecker, type: Type): Expression | undefined {
|
||||
if (type.flags & TypeFlags.BooleanLiteral) {
|
||||
return type === checker.getFalseType() ? createFalse() : createTrue();
|
||||
return (type === checker.getFalseType() || type === checker.getFalseType(/*fresh*/ true)) ? createFalse() : createTrue();
|
||||
}
|
||||
else if (type.isLiteral()) {
|
||||
return createLiteral(type.value);
|
||||
|
||||
@@ -267,7 +267,7 @@ namespace ts.codefix {
|
||||
|
||||
function getExistingImportDeclarations({ moduleSymbol, importKind, exportedSymbolIsTypeOnly }: SymbolExportInfo, checker: TypeChecker, sourceFile: SourceFile): ReadonlyArray<FixAddToExistingImportInfo> {
|
||||
// Can't use an es6 import for a type in JS.
|
||||
return exportedSymbolIsTypeOnly && isSourceFileJavaScript(sourceFile) ? emptyArray : mapDefined<StringLiteralLike, FixAddToExistingImportInfo>(sourceFile.imports, moduleSpecifier => {
|
||||
return exportedSymbolIsTypeOnly && isSourceFileJS(sourceFile) ? emptyArray : mapDefined<StringLiteralLike, FixAddToExistingImportInfo>(sourceFile.imports, moduleSpecifier => {
|
||||
const i = importFromModuleSpecifier(moduleSpecifier);
|
||||
return (i.kind === SyntaxKind.ImportDeclaration || i.kind === SyntaxKind.ImportEqualsDeclaration)
|
||||
&& checker.getSymbolAtLocation(moduleSpecifier) === moduleSymbol ? { declaration: i, importKind } : undefined;
|
||||
@@ -282,7 +282,7 @@ namespace ts.codefix {
|
||||
host: LanguageServiceHost,
|
||||
preferences: UserPreferences,
|
||||
): ReadonlyArray<FixAddNewImport | FixUseImportType> {
|
||||
const isJs = isSourceFileJavaScript(sourceFile);
|
||||
const isJs = isSourceFileJS(sourceFile);
|
||||
const choicesForEachExportingModule = flatMap(moduleSymbols, ({ moduleSymbol, importKind, exportedSymbolIsTypeOnly }) =>
|
||||
moduleSpecifiers.getModuleSpecifiers(moduleSymbol, program.getCompilerOptions(), sourceFile, host, program.getSourceFiles(), preferences, program.redirectTargetsMap)
|
||||
.map((moduleSpecifier): FixAddNewImport | FixUseImportType =>
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace ts.codefix {
|
||||
errorCodes,
|
||||
getCodeActions(context) {
|
||||
const { sourceFile, program, span: { start }, errorCode, cancellationToken } = context;
|
||||
if (isSourceFileJavaScript(sourceFile)) {
|
||||
if (isSourceFileJS(sourceFile)) {
|
||||
return undefined; // TODO: GH#20113
|
||||
}
|
||||
|
||||
|
||||
+38
-18
@@ -134,7 +134,7 @@ namespace ts.Completions {
|
||||
|
||||
if (isUncheckedFile(sourceFile, compilerOptions)) {
|
||||
const uniqueNames = getCompletionEntriesFromSymbols(symbols, entries, location, sourceFile, typeChecker, compilerOptions.target!, log, completionKind, preferences, propertyAccessToConvert, isJsxInitializer, recommendedCompletion, symbolToOriginInfoMap);
|
||||
getJavaScriptCompletionEntries(sourceFile, location!.pos, uniqueNames, compilerOptions.target!, entries); // TODO: GH#18217
|
||||
getJSCompletionEntries(sourceFile, location!.pos, uniqueNames, compilerOptions.target!, entries); // TODO: GH#18217
|
||||
}
|
||||
else {
|
||||
if ((!symbols || symbols.length === 0) && keywordFilters === KeywordCompletionFilters.None) {
|
||||
@@ -144,7 +144,14 @@ namespace ts.Completions {
|
||||
getCompletionEntriesFromSymbols(symbols, entries, location, sourceFile, typeChecker, compilerOptions.target!, log, completionKind, preferences, propertyAccessToConvert, isJsxInitializer, recommendedCompletion, symbolToOriginInfoMap);
|
||||
}
|
||||
|
||||
addRange(entries, getKeywordCompletions(keywordFilters));
|
||||
if (keywordFilters !== KeywordCompletionFilters.None) {
|
||||
const entryNames = arrayToSet(entries, e => e.name);
|
||||
for (const keywordEntry of getKeywordCompletions(keywordFilters)) {
|
||||
if (!entryNames.has(keywordEntry.name)) {
|
||||
entries.push(keywordEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const literal of literals) {
|
||||
entries.push(createCompletionEntryForLiteral(literal));
|
||||
@@ -154,7 +161,7 @@ namespace ts.Completions {
|
||||
}
|
||||
|
||||
function isUncheckedFile(sourceFile: SourceFile, compilerOptions: CompilerOptions): boolean {
|
||||
return isSourceFileJavaScript(sourceFile) && !isCheckJsEnabledForFile(sourceFile, compilerOptions);
|
||||
return isSourceFileJS(sourceFile) && !isCheckJsEnabledForFile(sourceFile, compilerOptions);
|
||||
}
|
||||
|
||||
function isMemberCompletionKind(kind: CompletionKind): boolean {
|
||||
@@ -168,7 +175,7 @@ namespace ts.Completions {
|
||||
}
|
||||
}
|
||||
|
||||
function getJavaScriptCompletionEntries(
|
||||
function getJSCompletionEntries(
|
||||
sourceFile: SourceFile,
|
||||
position: number,
|
||||
uniqueNames: Map<true>,
|
||||
@@ -180,7 +187,7 @@ namespace ts.Completions {
|
||||
return;
|
||||
}
|
||||
const realName = unescapeLeadingUnderscores(name);
|
||||
if (addToSeen(uniqueNames, realName) && isIdentifierText(realName, target) && !isStringANonContextualKeyword(realName)) {
|
||||
if (addToSeen(uniqueNames, realName) && isIdentifierText(realName, target)) {
|
||||
entries.push({
|
||||
name: realName,
|
||||
kind: ScriptElementKind.warning,
|
||||
@@ -383,11 +390,12 @@ namespace ts.Completions {
|
||||
}
|
||||
type StringLiteralCompletion = { readonly kind: StringLiteralCompletionKind.Paths, readonly paths: ReadonlyArray<PathCompletions.PathCompletion> } | StringLiteralCompletionsFromProperties | StringLiteralCompletionsFromTypes;
|
||||
function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringLiteralLike, position: number, typeChecker: TypeChecker, compilerOptions: CompilerOptions, host: LanguageServiceHost): StringLiteralCompletion | undefined {
|
||||
switch (node.parent.kind) {
|
||||
const { parent } = node;
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.LiteralType:
|
||||
switch (node.parent.parent.kind) {
|
||||
switch (parent.parent.kind) {
|
||||
case SyntaxKind.TypeReference:
|
||||
return { kind: StringLiteralCompletionKind.Types, types: getStringLiteralTypes(typeChecker.getTypeArgumentConstraint(node.parent as LiteralTypeNode)), isNewIdentifier: false };
|
||||
return { kind: StringLiteralCompletionKind.Types, types: getStringLiteralTypes(typeChecker.getTypeArgumentConstraint(parent as LiteralTypeNode)), isNewIdentifier: false };
|
||||
case SyntaxKind.IndexedAccessType:
|
||||
// Get all apparent property names
|
||||
// i.e. interface Foo {
|
||||
@@ -395,17 +403,21 @@ namespace ts.Completions {
|
||||
// bar: string;
|
||||
// }
|
||||
// let x: Foo["/*completion position*/"]
|
||||
return stringLiteralCompletionsFromProperties(typeChecker.getTypeFromTypeNode((node.parent.parent as IndexedAccessTypeNode).objectType));
|
||||
return stringLiteralCompletionsFromProperties(typeChecker.getTypeFromTypeNode((parent.parent as IndexedAccessTypeNode).objectType));
|
||||
case SyntaxKind.ImportType:
|
||||
return { kind: StringLiteralCompletionKind.Paths, paths: PathCompletions.getStringLiteralCompletionsFromModuleNames(sourceFile, node, compilerOptions, host, typeChecker) };
|
||||
case SyntaxKind.UnionType:
|
||||
return isTypeReferenceNode(node.parent.parent.parent) ? { kind: StringLiteralCompletionKind.Types, types: getStringLiteralTypes(typeChecker.getTypeArgumentConstraint(node.parent.parent as UnionTypeNode)), isNewIdentifier: false } : undefined;
|
||||
case SyntaxKind.UnionType: {
|
||||
if (!isTypeReferenceNode(parent.parent.parent)) return undefined;
|
||||
const alreadyUsedTypes = getAlreadyUsedTypesInStringLiteralUnion(parent.parent as UnionTypeNode, parent as LiteralTypeNode);
|
||||
const types = getStringLiteralTypes(typeChecker.getTypeArgumentConstraint(parent.parent as UnionTypeNode)).filter(t => !contains(alreadyUsedTypes, t.value));
|
||||
return { kind: StringLiteralCompletionKind.Types, types, isNewIdentifier: false };
|
||||
}
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
if (isObjectLiteralExpression(node.parent.parent) && (<PropertyAssignment>node.parent).name === node) {
|
||||
if (isObjectLiteralExpression(parent.parent) && (<PropertyAssignment>parent).name === node) {
|
||||
// Get quoted name of properties of the object literal expression
|
||||
// i.e. interface ConfigFiles {
|
||||
// 'jspm:dev': string
|
||||
@@ -418,12 +430,12 @@ namespace ts.Completions {
|
||||
// foo({
|
||||
// '/*completion position*/'
|
||||
// });
|
||||
return stringLiteralCompletionsFromProperties(typeChecker.getContextualType(node.parent.parent));
|
||||
return stringLiteralCompletionsFromProperties(typeChecker.getContextualType(parent.parent));
|
||||
}
|
||||
return fromContextualType();
|
||||
|
||||
case SyntaxKind.ElementAccessExpression: {
|
||||
const { expression, argumentExpression } = node.parent as ElementAccessExpression;
|
||||
const { expression, argumentExpression } = parent as ElementAccessExpression;
|
||||
if (node === argumentExpression) {
|
||||
// Get all names of properties on the expression
|
||||
// i.e. interface A {
|
||||
@@ -438,7 +450,7 @@ namespace ts.Completions {
|
||||
|
||||
case SyntaxKind.CallExpression:
|
||||
case SyntaxKind.NewExpression:
|
||||
if (!isRequireCall(node.parent, /*checkArgumentIsStringLiteralLike*/ false) && !isImportCall(node.parent)) {
|
||||
if (!isRequireCall(parent, /*checkArgumentIsStringLiteralLike*/ false) && !isImportCall(parent)) {
|
||||
const argumentInfo = SignatureHelp.getArgumentInfoForCompletions(node, position, sourceFile);
|
||||
// Get string literal completions from specialized signatures of the target
|
||||
// i.e. declare function f(a: 'A');
|
||||
@@ -469,6 +481,11 @@ namespace ts.Completions {
|
||||
}
|
||||
}
|
||||
|
||||
function getAlreadyUsedTypesInStringLiteralUnion(union: UnionTypeNode, current: LiteralTypeNode): ReadonlyArray<string> {
|
||||
return mapDefined(union.types, type =>
|
||||
type !== current && isLiteralTypeNode(type) && isStringLiteral(type.literal) ? type.literal.text : undefined);
|
||||
}
|
||||
|
||||
function getStringLiteralCompletionsFromSignature(argumentInfo: SignatureHelp.ArgumentInfoForCompletions, checker: TypeChecker): StringLiteralCompletionsFromTypes {
|
||||
let isNewIdentifier = false;
|
||||
|
||||
@@ -986,7 +1003,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;
|
||||
}
|
||||
}
|
||||
@@ -1258,10 +1278,10 @@ namespace ts.Completions {
|
||||
if (sourceFile.externalModuleIndicator) return true;
|
||||
// If already using commonjs, don't introduce ES6.
|
||||
if (sourceFile.commonJsModuleIndicator) return false;
|
||||
// If some file is using ES6 modules, assume that it's OK to add more.
|
||||
if (programContainsEs6Modules(program)) return true;
|
||||
// For JS, stay on the safe side.
|
||||
if (isUncheckedFile) return false;
|
||||
// If some file is using ES6 modules, assume that it's OK to add more.
|
||||
if (programContainsEs6Modules(program)) return true;
|
||||
// If module transpilation is enabled or we're targeting es6 or above, or not emitting, OK.
|
||||
return compilerOptionsIndicateEs6Modules(program.getCompilerOptions());
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -196,15 +196,23 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getSourceFileToImportFromResolved(resolved: ResolvedModuleWithFailedLookupLocations | undefined, oldToNew: PathUpdater, host: LanguageServiceHost): ToImport | undefined {
|
||||
return resolved && (
|
||||
(resolved.resolvedModule && getIfExists(resolved.resolvedModule.resolvedFileName)) || firstDefined(resolved.failedLookupLocations, getIfExists));
|
||||
// Search through all locations looking for a moved file, and only then test already existing files.
|
||||
// This is because if `a.ts` is compiled to `a.js` and `a.ts` is moved, we don't want to resolve anything to `a.js`, but to `a.ts`'s new location.
|
||||
return tryEach(tryGetNewFile) || tryEach(tryGetOldFile);
|
||||
|
||||
function getIfExists(oldLocation: string): ToImport | undefined {
|
||||
const newLocation = oldToNew(oldLocation);
|
||||
function tryEach(cb: (oldFileName: string) => ToImport | undefined): ToImport | undefined {
|
||||
return resolved && (
|
||||
(resolved.resolvedModule && cb(resolved.resolvedModule.resolvedFileName)) || firstDefined(resolved.failedLookupLocations, cb));
|
||||
}
|
||||
|
||||
return host.fileExists!(oldLocation) || newLocation !== undefined && host.fileExists!(newLocation) // TODO: GH#18217
|
||||
? newLocation !== undefined ? { newFileName: newLocation, updated: true } : { newFileName: oldLocation, updated: false }
|
||||
: undefined;
|
||||
function tryGetNewFile(oldFileName: string): ToImport | undefined {
|
||||
const newFileName = oldToNew(oldFileName);
|
||||
return newFileName !== undefined && host.fileExists!(newFileName) ? { newFileName, updated: true } : undefined; // TODO: GH#18217
|
||||
}
|
||||
|
||||
function tryGetOldFile(oldFileName: string): ToImport | undefined {
|
||||
const newFileName = oldToNew(oldFileName);
|
||||
return host.fileExists!(oldFileName) ? newFileName !== undefined ? { newFileName, updated: true } : { newFileName: oldFileName, updated: false } : undefined; // TODO: GH#18217
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -502,11 +502,11 @@ namespace ts.FindAllReferences {
|
||||
|
||||
function getSpecialPropertyExport(node: BinaryExpression, useLhsSymbol: boolean): ExportedSymbol | undefined {
|
||||
let kind: ExportKind;
|
||||
switch (getSpecialPropertyAssignmentKind(node)) {
|
||||
case SpecialPropertyAssignmentKind.ExportsProperty:
|
||||
switch (getAssignmentDeclarationKind(node)) {
|
||||
case AssignmentDeclarationKind.ExportsProperty:
|
||||
kind = ExportKind.Named;
|
||||
break;
|
||||
case SpecialPropertyAssignmentKind.ModuleExports:
|
||||
case AssignmentDeclarationKind.ModuleExports:
|
||||
kind = ExportKind.ExportEquals;
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -208,7 +208,7 @@ namespace ts.JsDoc {
|
||||
kindModifiers: "",
|
||||
displayParts: [textPart(name)],
|
||||
documentation: emptyArray,
|
||||
tags: emptyArray,
|
||||
tags: undefined,
|
||||
codeActions: undefined,
|
||||
};
|
||||
}
|
||||
@@ -242,7 +242,7 @@ namespace ts.JsDoc {
|
||||
kindModifiers: "",
|
||||
displayParts: [textPart(name)],
|
||||
documentation: emptyArray,
|
||||
tags: emptyArray,
|
||||
tags: undefined,
|
||||
codeActions: undefined,
|
||||
};
|
||||
}
|
||||
@@ -312,7 +312,7 @@ namespace ts.JsDoc {
|
||||
const preamble = "/**" + newLine + indentationStr + " * ";
|
||||
const result =
|
||||
preamble + newLine +
|
||||
parameterDocComments(parameters, hasJavaScriptFileExtension(sourceFile.fileName), indentationStr, newLine) +
|
||||
parameterDocComments(parameters, hasJSFileExtension(sourceFile.fileName), indentationStr, newLine) +
|
||||
indentationStr + " */" +
|
||||
(tokenStart === position ? newLine + indentationStr : "");
|
||||
|
||||
@@ -383,7 +383,7 @@ namespace ts.JsDoc {
|
||||
|
||||
case SyntaxKind.BinaryExpression: {
|
||||
const be = commentOwner as BinaryExpression;
|
||||
if (getSpecialPropertyAssignmentKind(be) === SpecialPropertyAssignmentKind.None) {
|
||||
if (getAssignmentDeclarationKind(be) === AssignmentDeclarationKind.None) {
|
||||
return "quit";
|
||||
}
|
||||
const parameters = isFunctionLike(be.right) ? be.right.parameters : emptyArray;
|
||||
|
||||
@@ -270,17 +270,17 @@ namespace ts.NavigationBar {
|
||||
break;
|
||||
|
||||
case SyntaxKind.BinaryExpression: {
|
||||
const special = getSpecialPropertyAssignmentKind(node as BinaryExpression);
|
||||
const special = getAssignmentDeclarationKind(node as BinaryExpression);
|
||||
switch (special) {
|
||||
case SpecialPropertyAssignmentKind.ExportsProperty:
|
||||
case SpecialPropertyAssignmentKind.ModuleExports:
|
||||
case SpecialPropertyAssignmentKind.PrototypeProperty:
|
||||
case SpecialPropertyAssignmentKind.Prototype:
|
||||
case AssignmentDeclarationKind.ExportsProperty:
|
||||
case AssignmentDeclarationKind.ModuleExports:
|
||||
case AssignmentDeclarationKind.PrototypeProperty:
|
||||
case AssignmentDeclarationKind.Prototype:
|
||||
addNodeWithRecursiveChild(node, (node as BinaryExpression).right);
|
||||
return;
|
||||
case SpecialPropertyAssignmentKind.ThisProperty:
|
||||
case SpecialPropertyAssignmentKind.Property:
|
||||
case SpecialPropertyAssignmentKind.None:
|
||||
case AssignmentDeclarationKind.ThisProperty:
|
||||
case AssignmentDeclarationKind.Property:
|
||||
case AssignmentDeclarationKind.None:
|
||||
break;
|
||||
default:
|
||||
Debug.assertNever(special);
|
||||
|
||||
@@ -151,11 +151,41 @@ namespace ts.Completions.PathCompletions {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check for a version redirect
|
||||
const packageJsonPath = findPackageJson(baseDirectory, host);
|
||||
if (packageJsonPath) {
|
||||
const packageJson = readJson(packageJsonPath, host as { readFile: (filename: string) => string | undefined });
|
||||
const typesVersions = (packageJson as any).typesVersions;
|
||||
if (typeof typesVersions === "object") {
|
||||
const versionResult = getPackageJsonTypesVersionsPaths(typesVersions);
|
||||
const versionPaths = versionResult && versionResult.paths;
|
||||
const rest = absolutePath.slice(ensureTrailingDirectorySeparator(baseDirectory).length);
|
||||
if (versionPaths) {
|
||||
addCompletionEntriesFromPaths(result, rest, baseDirectory, extensions, versionPaths, host);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function addCompletionEntriesFromPaths(result: NameAndKind[], fragment: string, baseDirectory: string, fileExtensions: ReadonlyArray<string>, paths: MapLike<string[]>, host: LanguageServiceHost) {
|
||||
for (const path in paths) {
|
||||
if (!hasProperty(paths, path)) continue;
|
||||
const patterns = paths[path];
|
||||
if (patterns) {
|
||||
for (const { name, kind } of getCompletionsForPathMapping(path, patterns, fragment, baseDirectory, fileExtensions, host)) {
|
||||
// Path mappings may provide a duplicate way to get to something we've already added, so don't add again.
|
||||
if (!result.some(entry => entry.name === name)) {
|
||||
result.push(nameAndKind(name, kind));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check all of the declared modules and those in node modules. Possible sources of modules:
|
||||
* Modules that are found by the type checker
|
||||
@@ -171,19 +201,10 @@ namespace ts.Completions.PathCompletions {
|
||||
const fileExtensions = getSupportedExtensionsForModuleResolution(compilerOptions);
|
||||
if (baseUrl) {
|
||||
const projectDir = compilerOptions.project || host.getCurrentDirectory();
|
||||
const absolute = isRootedDiskPath(baseUrl) ? baseUrl : combinePaths(projectDir, baseUrl);
|
||||
getCompletionEntriesForDirectoryFragment(fragment, normalizePath(absolute), fileExtensions, /*includeExtensions*/ false, host, /*exclude*/ undefined, result);
|
||||
|
||||
for (const path in paths!) {
|
||||
const patterns = paths![path];
|
||||
if (paths!.hasOwnProperty(path) && patterns) {
|
||||
for (const { name, kind } of getCompletionsForPathMapping(path, patterns, fragment, baseUrl, fileExtensions, host)) {
|
||||
// Path mappings may provide a duplicate way to get to something we've already added, so don't add again.
|
||||
if (!result.some(entry => entry.name === name)) {
|
||||
result.push(nameAndKind(name, kind));
|
||||
}
|
||||
}
|
||||
}
|
||||
const absolute = normalizePath(combinePaths(projectDir, baseUrl));
|
||||
getCompletionEntriesForDirectoryFragment(fragment, absolute, fileExtensions, /*includeExtensions*/ false, host, /*exclude*/ undefined, result);
|
||||
if (paths) {
|
||||
addCompletionEntriesFromPaths(result, fragment, absolute, fileExtensions, paths, host);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,7 +350,7 @@ namespace ts.Completions.PathCompletions {
|
||||
const seen = createMap<true>();
|
||||
if (options.types) {
|
||||
for (const typesName of options.types) {
|
||||
const moduleName = getUnmangledNameForScopedPackage(typesName);
|
||||
const moduleName = unmangleScopedPackageName(typesName);
|
||||
pushResult(moduleName);
|
||||
}
|
||||
}
|
||||
@@ -363,7 +384,7 @@ namespace ts.Completions.PathCompletions {
|
||||
for (let typeDirectory of directories) {
|
||||
typeDirectory = normalizePath(typeDirectory);
|
||||
const directoryName = getBaseFileName(typeDirectory);
|
||||
const moduleName = getUnmangledNameForScopedPackage(directoryName);
|
||||
const moduleName = unmangleScopedPackageName(directoryName);
|
||||
pushResult(moduleName);
|
||||
}
|
||||
}
|
||||
@@ -390,6 +411,18 @@ namespace ts.Completions.PathCompletions {
|
||||
return paths;
|
||||
}
|
||||
|
||||
function findPackageJson(directory: string, host: LanguageServiceHost): string | undefined {
|
||||
let packageJson: string | undefined;
|
||||
forEachAncestorDirectory(directory, ancestor => {
|
||||
if (ancestor === "node_modules") return true;
|
||||
packageJson = findConfigFile(ancestor, (f) => tryFileExists(host, f), "package.json");
|
||||
if (packageJson) {
|
||||
return true; // break out
|
||||
}
|
||||
});
|
||||
return packageJson;
|
||||
}
|
||||
|
||||
function enumerateNodeModulesVisibleToScript(host: LanguageServiceHost, scriptPath: string): ReadonlyArray<string> {
|
||||
if (!host.readFile || !host.fileExists) return emptyArray;
|
||||
|
||||
|
||||
@@ -719,7 +719,7 @@ namespace ts.refactor.extractSymbol {
|
||||
// Make a unique name for the extracted function
|
||||
const file = scope.getSourceFile();
|
||||
const functionNameText = getUniqueName(isClassLike(scope) ? "newMethod" : "newFunction", file);
|
||||
const isJS = isInJavaScriptFile(scope);
|
||||
const isJS = isInJSFile(scope);
|
||||
|
||||
const functionName = createIdentifier(functionNameText);
|
||||
|
||||
@@ -1006,7 +1006,7 @@ namespace ts.refactor.extractSymbol {
|
||||
// Make a unique name for the extracted variable
|
||||
const file = scope.getSourceFile();
|
||||
const localNameText = getUniqueName(isClassLike(scope) ? "newProperty" : "newLocal", file);
|
||||
const isJS = isInJavaScriptFile(scope);
|
||||
const isJS = isInJSFile(scope);
|
||||
|
||||
const variableType = isJS || !checker.isContextSensitive(node)
|
||||
? undefined
|
||||
@@ -1424,7 +1424,7 @@ namespace ts.refactor.extractSymbol {
|
||||
if (expressionDiagnostic) {
|
||||
constantErrors.push(expressionDiagnostic);
|
||||
}
|
||||
if (isClassLike(scope) && isInJavaScriptFile(scope)) {
|
||||
if (isClassLike(scope) && isInJSFile(scope)) {
|
||||
constantErrors.push(createDiagnosticForNode(scope, Messages.cannotExtractToJSClass));
|
||||
}
|
||||
if (isArrowFunction(scope) && !isBlock(scope.body)) {
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor {
|
||||
const fieldInfo = getConvertibleFieldAtPosition(context);
|
||||
if (!fieldInfo) return undefined;
|
||||
|
||||
const isJS = isSourceFileJavaScript(file);
|
||||
const isJS = isSourceFileJS(file);
|
||||
const changeTracker = textChanges.ChangeTracker.fromContext(context);
|
||||
const { isStatic, isReadonly, fieldName, accessorName, originalName, type, container, declaration, renameAccessor } = fieldInfo;
|
||||
|
||||
|
||||
@@ -657,7 +657,7 @@ namespace ts.refactor {
|
||||
|
||||
case SyntaxKind.ExpressionStatement: {
|
||||
const { expression } = statement as ExpressionStatement;
|
||||
return isBinaryExpression(expression) && getSpecialPropertyAssignmentKind(expression) === SpecialPropertyAssignmentKind.ExportsProperty
|
||||
return isBinaryExpression(expression) && getAssignmentDeclarationKind(expression) === AssignmentDeclarationKind.ExportsProperty
|
||||
? cb(statement as TopLevelExpressionStatement)
|
||||
: undefined;
|
||||
}
|
||||
|
||||
+22
-2
@@ -25,8 +25,9 @@ namespace ts.Rename {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Can't rename a module name.
|
||||
if (isStringLiteralLike(node) && tryGetImportFromModuleSpecifier(node)) return undefined;
|
||||
if (isStringLiteralLike(node) && tryGetImportFromModuleSpecifier(node)) {
|
||||
return getRenameInfoForModule(node, sourceFile, symbol);
|
||||
}
|
||||
|
||||
const kind = SymbolDisplay.getSymbolKind(typeChecker, symbol, node);
|
||||
const specifierName = (isImportOrExportSpecifierName(node) || isStringOrNumericLiteralLike(node) && node.parent.kind === SyntaxKind.ComputedPropertyName)
|
||||
@@ -37,9 +38,28 @@ namespace ts.Rename {
|
||||
return getRenameInfoSuccess(displayName, fullDisplayName, kind, SymbolDisplay.getSymbolModifiers(symbol), node, sourceFile);
|
||||
}
|
||||
|
||||
function getRenameInfoForModule(node: StringLiteralLike, sourceFile: SourceFile, moduleSymbol: Symbol): RenameInfo | undefined {
|
||||
const moduleSourceFile = find(moduleSymbol.declarations, isSourceFile);
|
||||
if (!moduleSourceFile) return undefined;
|
||||
const withoutIndex = node.text.endsWith("/index") || node.text.endsWith("/index.js") ? undefined : tryRemoveSuffix(removeFileExtension(moduleSourceFile.fileName), "/index");
|
||||
const name = withoutIndex === undefined ? moduleSourceFile.fileName : withoutIndex;
|
||||
const kind = withoutIndex === undefined ? ScriptElementKind.moduleElement : ScriptElementKind.directory;
|
||||
return {
|
||||
canRename: true,
|
||||
fileToRename: name,
|
||||
kind,
|
||||
displayName: name,
|
||||
localizedErrorMessage: undefined,
|
||||
fullDisplayName: name,
|
||||
kindModifiers: ScriptElementKindModifier.none,
|
||||
triggerSpan: createTriggerSpanForNode(node, sourceFile),
|
||||
};
|
||||
}
|
||||
|
||||
function getRenameInfoSuccess(displayName: string, fullDisplayName: string, kind: ScriptElementKind, kindModifiers: string, node: Node, sourceFile: SourceFile): RenameInfo {
|
||||
return {
|
||||
canRename: true,
|
||||
fileToRename: undefined,
|
||||
kind,
|
||||
displayName,
|
||||
localizedErrorMessage: undefined,
|
||||
|
||||
@@ -760,7 +760,7 @@ namespace ts {
|
||||
break;
|
||||
|
||||
case SyntaxKind.BinaryExpression:
|
||||
if (getSpecialPropertyAssignmentKind(node as BinaryExpression) !== SpecialPropertyAssignmentKind.None) {
|
||||
if (getAssignmentDeclarationKind(node as BinaryExpression) !== AssignmentDeclarationKind.None) {
|
||||
addDeclaration(node as BinaryExpression);
|
||||
}
|
||||
// falls through
|
||||
@@ -1175,9 +1175,10 @@ namespace ts {
|
||||
const rootFileNames = hostCache.getRootFileNames();
|
||||
|
||||
const hasInvalidatedResolution: HasInvalidatedResolution = host.hasInvalidatedResolution || returnFalse;
|
||||
const projectReferences = hostCache.getProjectReferences();
|
||||
|
||||
// If the program is already up-to-date, we can reuse it
|
||||
if (isProgramUptoDate(program, rootFileNames, hostCache.compilationSettings(), path => hostCache!.getVersion(path), fileExists, hasInvalidatedResolution, !!host.hasChangedAutomaticTypeDirectiveNames)) {
|
||||
if (isProgramUptoDate(program, rootFileNames, hostCache.compilationSettings(), path => hostCache!.getVersion(path), fileExists, hasInvalidatedResolution, !!host.hasChangedAutomaticTypeDirectiveNames, projectReferences)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1240,7 +1241,7 @@ namespace ts {
|
||||
options: newSettings,
|
||||
host: compilerHost,
|
||||
oldProgram: program,
|
||||
projectReferences: hostCache.getProjectReferences()
|
||||
projectReferences
|
||||
};
|
||||
program = createProgram(options);
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace ts.SignatureHelp {
|
||||
if (!candidateInfo) {
|
||||
// We didn't have any sig help items produced by the TS compiler. If this is a JS
|
||||
// file, then see if we can figure out anything better.
|
||||
return isSourceFileJavaScript(sourceFile) ? createJavaScriptSignatureHelpItems(argumentInfo, program, cancellationToken) : undefined;
|
||||
return isSourceFileJS(sourceFile) ? createJSSignatureHelpItems(argumentInfo, program, cancellationToken) : undefined;
|
||||
}
|
||||
|
||||
return typeChecker.runWithCancellationToken(cancellationToken, typeChecker =>
|
||||
@@ -115,7 +115,7 @@ namespace ts.SignatureHelp {
|
||||
}
|
||||
}
|
||||
|
||||
function createJavaScriptSignatureHelpItems(argumentInfo: ArgumentListInfo, program: Program, cancellationToken: CancellationToken): SignatureHelpItems | undefined {
|
||||
function createJSSignatureHelpItems(argumentInfo: ArgumentListInfo, program: Program, cancellationToken: CancellationToken): SignatureHelpItems | undefined {
|
||||
if (argumentInfo.invocation.kind === InvocationKind.Contextual) return undefined;
|
||||
// See if we can find some symbol with the call expression name that has call signatures.
|
||||
const expression = getExpressionFromInvocation(argumentInfo.invocation);
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace ts {
|
||||
diags.push(createDiagnosticForNode(getErrorNodeFromCommonJsIndicator(sourceFile.commonJsModuleIndicator), Diagnostics.File_is_a_CommonJS_module_it_may_be_converted_to_an_ES6_module));
|
||||
}
|
||||
|
||||
const isJsFile = isSourceFileJavaScript(sourceFile);
|
||||
const isJsFile = isSourceFileJS(sourceFile);
|
||||
|
||||
check(sourceFile);
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace ts {
|
||||
if (isJsFile) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.FunctionExpression:
|
||||
const decl = getDeclarationOfJSInitializer(node);
|
||||
const decl = getDeclarationOfExpando(node);
|
||||
if (decl) {
|
||||
const symbol = decl.symbol;
|
||||
if (symbol && (symbol.exports && symbol.exports.size || symbol.members && symbol.members.size)) {
|
||||
@@ -86,8 +86,8 @@ namespace ts {
|
||||
case SyntaxKind.ExpressionStatement: {
|
||||
const { expression } = statement as ExpressionStatement;
|
||||
if (!isBinaryExpression(expression)) return isRequireCall(expression, /*checkArgumentIsStringLiteralLike*/ true);
|
||||
const kind = getSpecialPropertyAssignmentKind(expression);
|
||||
return kind === SpecialPropertyAssignmentKind.ExportsProperty || kind === SpecialPropertyAssignmentKind.ModuleExports;
|
||||
const kind = getAssignmentDeclarationKind(expression);
|
||||
return kind === AssignmentDeclarationKind.ExportsProperty || kind === AssignmentDeclarationKind.ModuleExports;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
@@ -132,7 +132,7 @@ namespace ts {
|
||||
// check that a property access expression exists in there and that it is a handler
|
||||
const returnStatements = getReturnStatementsWithPromiseHandlers(node);
|
||||
if (returnStatements.length > 0) {
|
||||
diags.push(createDiagnosticForNode(isVariableDeclaration(node.parent) ? node.parent.name : node, Diagnostics.This_may_be_converted_to_an_async_function));
|
||||
diags.push(createDiagnosticForNode(!node.name && isVariableDeclaration(node.parent) && isIdentifier(node.parent.name) ? node.parent.name : node, Diagnostics.This_may_be_converted_to_an_async_function));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,8 +141,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getReturnStatementsWithPromiseHandlers(node: Node): Node[] {
|
||||
const returnStatements: Node[] = [];
|
||||
export function getReturnStatementsWithPromiseHandlers(node: Node): ReturnStatement[] {
|
||||
const returnStatements: ReturnStatement[] = [];
|
||||
if (isFunctionLike(node)) {
|
||||
forEachChild(node, visit);
|
||||
}
|
||||
@@ -155,14 +155,8 @@ namespace ts {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isReturnStatement(child)) {
|
||||
forEachChild(child, addHandlers);
|
||||
}
|
||||
|
||||
function addHandlers(returnChild: Node) {
|
||||
if (isPromiseHandler(returnChild)) {
|
||||
returnStatements.push(child as ReturnStatement);
|
||||
}
|
||||
if (isReturnStatement(child) && child.expression && isFixablePromiseHandler(child.expression)) {
|
||||
returnStatements.push(child);
|
||||
}
|
||||
|
||||
forEachChild(child, visit);
|
||||
@@ -170,8 +164,39 @@ namespace ts {
|
||||
return returnStatements;
|
||||
}
|
||||
|
||||
function isPromiseHandler(node: Node): boolean {
|
||||
return (isCallExpression(node) && isPropertyAccessExpression(node.expression) &&
|
||||
(node.expression.name.text === "then" || node.expression.name.text === "catch"));
|
||||
// Should be kept up to date with transformExpression in convertToAsyncFunction.ts
|
||||
function isFixablePromiseHandler(node: Node): boolean {
|
||||
// ensure outermost call exists and is a promise handler
|
||||
if (!isPromiseHandler(node) || !node.arguments.every(isFixablePromiseArgument)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ensure all chained calls are valid
|
||||
let currentNode = node.expression;
|
||||
while (isPromiseHandler(currentNode) || isPropertyAccessExpression(currentNode)) {
|
||||
if (isCallExpression(currentNode) && !currentNode.arguments.every(isFixablePromiseArgument)) {
|
||||
return false;
|
||||
}
|
||||
currentNode = currentNode.expression;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function isPromiseHandler(node: Node): node is CallExpression {
|
||||
return isCallExpression(node) && (hasPropertyAccessExpressionWithName(node, "then") || hasPropertyAccessExpressionWithName(node, "catch"));
|
||||
}
|
||||
|
||||
// should be kept up to date with getTransformationBody in convertToAsyncFunction.ts
|
||||
function isFixablePromiseArgument(arg: Expression): boolean {
|
||||
switch (arg.kind) {
|
||||
case SyntaxKind.NullKeyword:
|
||||
case SyntaxKind.Identifier: // identifier includes undefined
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,14 +128,18 @@ namespace ts.SymbolDisplay {
|
||||
let documentation: SymbolDisplayPart[] | undefined;
|
||||
let tags: JSDocTagInfo[] | undefined;
|
||||
const symbolFlags = getCombinedLocalAndExportSymbolFlags(symbol);
|
||||
let symbolKind = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(typeChecker, symbol, location);
|
||||
let symbolKind = semanticMeaning & SemanticMeaning.Value ? getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(typeChecker, symbol, location) : ScriptElementKind.unknown;
|
||||
let hasAddedSymbolInfo = false;
|
||||
const isThisExpression = location.kind === SyntaxKind.ThisKeyword && isExpression(location);
|
||||
const isThisExpression = location.kind === SyntaxKind.ThisKeyword && isInExpressionContext(location);
|
||||
let type: Type | undefined;
|
||||
let printer: Printer;
|
||||
let documentationFromAlias: SymbolDisplayPart[] | undefined;
|
||||
let tagsFromAlias: JSDocTagInfo[] | undefined;
|
||||
|
||||
if (location.kind === SyntaxKind.ThisKeyword && !isThisExpression) {
|
||||
return { displayParts: [keywordPart(SyntaxKind.ThisKeyword)], documentation: [], symbolKind: ScriptElementKind.primitiveType, tags: undefined };
|
||||
}
|
||||
|
||||
// Class at constructor site need to be shown as constructor apart from property,method, vars
|
||||
if (symbolKind !== ScriptElementKind.unknown || symbolFlags & SymbolFlags.Class || symbolFlags & SymbolFlags.Alias) {
|
||||
// If it is accessor they are allowed only if location is at name of the accessor
|
||||
@@ -285,7 +289,7 @@ namespace ts.SymbolDisplay {
|
||||
addFullSymbolName(symbol);
|
||||
writeTypeParametersOfSymbol(symbol, sourceFile);
|
||||
}
|
||||
if (symbolFlags & SymbolFlags.TypeAlias) {
|
||||
if ((symbolFlags & SymbolFlags.TypeAlias) && (semanticMeaning & SemanticMeaning.Type)) {
|
||||
prefixNextMeaning();
|
||||
displayParts.push(keywordPart(SyntaxKind.TypeKeyword));
|
||||
displayParts.push(spacePart());
|
||||
@@ -530,7 +534,7 @@ namespace ts.SymbolDisplay {
|
||||
tags = tagsFromAlias;
|
||||
}
|
||||
|
||||
return { displayParts, documentation, symbolKind, tags: tags! };
|
||||
return { displayParts, documentation, symbolKind, tags: tags!.length === 0 ? undefined : tags };
|
||||
|
||||
function getPrinter() {
|
||||
if (!printer) {
|
||||
|
||||
@@ -784,6 +784,11 @@ namespace ts {
|
||||
|
||||
export interface RenameInfo {
|
||||
canRename: boolean;
|
||||
/**
|
||||
* File or directory to rename.
|
||||
* If set, `getEditsForFileRename` should be called instead of `findRenameLocations`.
|
||||
*/
|
||||
fileToRename?: string;
|
||||
localizedErrorMessage?: string;
|
||||
displayName: string;
|
||||
fullDisplayName: string;
|
||||
|
||||
+25
-16
@@ -23,8 +23,10 @@ namespace ts {
|
||||
|
||||
export function getMeaningFromDeclaration(node: Node): SemanticMeaning {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Parameter:
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
return isInJSFile(node) && getJSDocEnumTag(node) ? SemanticMeaning.All : SemanticMeaning.Value;
|
||||
|
||||
case SyntaxKind.Parameter:
|
||||
case SyntaxKind.BindingElement:
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
case SyntaxKind.PropertySignature:
|
||||
@@ -88,7 +90,7 @@ namespace ts {
|
||||
if (node.kind === SyntaxKind.SourceFile) {
|
||||
return SemanticMeaning.Value;
|
||||
}
|
||||
else if (node.parent.kind === SyntaxKind.ExportAssignment) {
|
||||
else if (node.parent.kind === SyntaxKind.ExportAssignment || node.parent.kind === SyntaxKind.ExternalModuleReference) {
|
||||
return SemanticMeaning.All;
|
||||
}
|
||||
else if (isInRightSideOfInternalImportEqualsDeclaration(node)) {
|
||||
@@ -224,6 +226,14 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function hasPropertyAccessExpressionWithName(node: CallExpression, funcName: string): boolean {
|
||||
if (!isPropertyAccessExpression(node.expression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return node.expression.name.text === funcName;
|
||||
}
|
||||
|
||||
export function isJumpStatementTarget(node: Node): node is Identifier & { parent: BreakOrContinueStatement } {
|
||||
return node.kind === SyntaxKind.Identifier && isBreakOrContinueStatement(node.parent) && node.parent.label === node;
|
||||
}
|
||||
@@ -355,23 +365,23 @@ namespace ts {
|
||||
case SyntaxKind.NamespaceImport:
|
||||
return ScriptElementKind.alias;
|
||||
case SyntaxKind.BinaryExpression:
|
||||
const kind = getSpecialPropertyAssignmentKind(node as BinaryExpression);
|
||||
const kind = getAssignmentDeclarationKind(node as BinaryExpression);
|
||||
const { right } = node as BinaryExpression;
|
||||
switch (kind) {
|
||||
case SpecialPropertyAssignmentKind.None:
|
||||
case AssignmentDeclarationKind.None:
|
||||
return ScriptElementKind.unknown;
|
||||
case SpecialPropertyAssignmentKind.ExportsProperty:
|
||||
case SpecialPropertyAssignmentKind.ModuleExports:
|
||||
case AssignmentDeclarationKind.ExportsProperty:
|
||||
case AssignmentDeclarationKind.ModuleExports:
|
||||
const rightKind = getNodeKind(right);
|
||||
return rightKind === ScriptElementKind.unknown ? ScriptElementKind.constElement : rightKind;
|
||||
case SpecialPropertyAssignmentKind.PrototypeProperty:
|
||||
case AssignmentDeclarationKind.PrototypeProperty:
|
||||
return isFunctionExpression(right) ? ScriptElementKind.memberFunctionElement : ScriptElementKind.memberVariableElement;
|
||||
case SpecialPropertyAssignmentKind.ThisProperty:
|
||||
case AssignmentDeclarationKind.ThisProperty:
|
||||
return ScriptElementKind.memberVariableElement; // property
|
||||
case SpecialPropertyAssignmentKind.Property:
|
||||
case AssignmentDeclarationKind.Property:
|
||||
// static method / property
|
||||
return isFunctionExpression(right) ? ScriptElementKind.memberFunctionElement : ScriptElementKind.memberVariableElement;
|
||||
case SpecialPropertyAssignmentKind.Prototype:
|
||||
case AssignmentDeclarationKind.Prototype:
|
||||
return ScriptElementKind.localClassElement;
|
||||
default: {
|
||||
assertType<never>(kind);
|
||||
@@ -1654,11 +1664,10 @@ namespace ts {
|
||||
return clone;
|
||||
}
|
||||
|
||||
export function getSynthesizedDeepCloneWithRenames<T extends Node | undefined>(node: T, includeTrivia = true, renameMap?: Map<Identifier>, checker?: TypeChecker, callback?: (originalNode: Node, clone: Node) => any): T {
|
||||
|
||||
export function getSynthesizedDeepCloneWithRenames<T extends Node>(node: T, includeTrivia = true, renameMap?: Map<Identifier>, checker?: TypeChecker, callback?: (originalNode: Node, clone: Node) => any): T {
|
||||
let clone;
|
||||
if (node && isIdentifier(node!) && renameMap && checker) {
|
||||
const symbol = checker.getSymbolAtLocation(node!);
|
||||
if (isIdentifier(node) && renameMap && checker) {
|
||||
const symbol = checker.getSymbolAtLocation(node);
|
||||
const renameInfo = symbol && renameMap.get(String(getSymbolId(symbol)));
|
||||
|
||||
if (renameInfo) {
|
||||
@@ -1667,11 +1676,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (!clone) {
|
||||
clone = node && getSynthesizedDeepCloneWorker(node as NonNullable<T>, renameMap, checker, callback);
|
||||
clone = getSynthesizedDeepCloneWorker(node as NonNullable<T>, renameMap, checker, callback);
|
||||
}
|
||||
|
||||
if (clone && !includeTrivia) suppressLeadingAndTrailingTrivia(clone);
|
||||
if (callback && node) callback(node!, clone);
|
||||
if (callback && clone) callback(node, clone);
|
||||
|
||||
return clone as T;
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ class CompilerTest {
|
||||
public verifyModuleResolution() {
|
||||
if (this.options.traceResolution) {
|
||||
Harness.Baseline.runBaseline(this.justName.replace(/\.tsx?$/, ".trace.json"),
|
||||
utils.removeTestPathPrefixes(JSON.stringify(this.result.traces, undefined, 4)));
|
||||
JSON.stringify(this.result.traces.map(utils.sanitizeTraceResolutionLogEntry), undefined, 4));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
"unittests/publicApi.ts",
|
||||
"unittests/reuseProgramStructure.ts",
|
||||
"unittests/session.ts",
|
||||
"unittests/semver.ts",
|
||||
"unittests/symbolWalker.ts",
|
||||
"unittests/telemetry.ts",
|
||||
"unittests/textChanges.ts",
|
||||
|
||||
@@ -1,68 +1,4 @@
|
||||
namespace ts {
|
||||
interface Range {
|
||||
pos: number;
|
||||
end: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface Test {
|
||||
source: string;
|
||||
ranges: Map<Range>;
|
||||
}
|
||||
|
||||
function getTest(source: string): Test {
|
||||
const activeRanges: Range[] = [];
|
||||
let text = "";
|
||||
let lastPos = 0;
|
||||
let pos = 0;
|
||||
const ranges = createMap<Range>();
|
||||
|
||||
while (pos < source.length) {
|
||||
if (source.charCodeAt(pos) === CharacterCodes.openBracket &&
|
||||
(source.charCodeAt(pos + 1) === CharacterCodes.hash || source.charCodeAt(pos + 1) === CharacterCodes.$)) {
|
||||
const saved = pos;
|
||||
pos += 2;
|
||||
const s = pos;
|
||||
consumeIdentifier();
|
||||
const e = pos;
|
||||
if (source.charCodeAt(pos) === CharacterCodes.bar) {
|
||||
pos++;
|
||||
text += source.substring(lastPos, saved);
|
||||
const name = s === e
|
||||
? source.charCodeAt(saved + 1) === CharacterCodes.hash ? "selection" : "extracted"
|
||||
: source.substring(s, e);
|
||||
activeRanges.push({ name, pos: text.length, end: undefined! });
|
||||
lastPos = pos;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
pos = saved;
|
||||
}
|
||||
}
|
||||
else if (source.charCodeAt(pos) === CharacterCodes.bar && source.charCodeAt(pos + 1) === CharacterCodes.closeBracket) {
|
||||
text += source.substring(lastPos, pos);
|
||||
activeRanges[activeRanges.length - 1].end = text.length;
|
||||
const range = activeRanges.pop()!;
|
||||
if (range.name in ranges) {
|
||||
throw new Error(`Duplicate name of range ${range.name}`);
|
||||
}
|
||||
ranges.set(range.name, range);
|
||||
pos += 2;
|
||||
lastPos = pos;
|
||||
continue;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
text += source.substring(lastPos, pos);
|
||||
|
||||
function consumeIdentifier() {
|
||||
while (isIdentifierPart(source.charCodeAt(pos), ScriptTarget.Latest)) {
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
return { source: text, ranges };
|
||||
}
|
||||
|
||||
const libFile: TestFSWithWatch.File = {
|
||||
path: "/a/lib/lib.d.ts",
|
||||
content: `/// <reference no-default-lib="true"/>
|
||||
@@ -319,19 +255,22 @@ interface String { charAt: any; }
|
||||
interface Array<T> {}`
|
||||
};
|
||||
|
||||
function testConvertToAsyncFunction(caption: string, text: string, baselineFolder: string, diagnosticDescription: DiagnosticMessage, codeFixDescription: DiagnosticMessage, includeLib?: boolean) {
|
||||
const t = getTest(text);
|
||||
function testConvertToAsyncFunction(caption: string, text: string, baselineFolder: string, includeLib?: boolean, expectFailure = false) {
|
||||
const t = extractTest(text);
|
||||
const selectionRange = t.ranges.get("selection")!;
|
||||
if (!selectionRange) {
|
||||
throw new Error(`Test ${caption} does not specify selection range`);
|
||||
}
|
||||
|
||||
[Extension.Ts, Extension.Js].forEach(extension =>
|
||||
const extensions = expectFailure ? [Extension.Ts] : [Extension.Ts, Extension.Js];
|
||||
|
||||
extensions.forEach(extension =>
|
||||
it(`${caption} [${extension}]`, () => runBaseline(extension)));
|
||||
|
||||
function runBaseline(extension: Extension) {
|
||||
const path = "/a" + extension;
|
||||
const program = makeProgram({ path, content: t.source }, includeLib)!;
|
||||
const languageService = makeLanguageService({ path, content: t.source }, includeLib);
|
||||
const program = languageService.getProgram()!;
|
||||
|
||||
if (hasSyntacticDiagnostics(program)) {
|
||||
// Don't bother generating JS baselines for inputs that aren't valid JS.
|
||||
@@ -345,10 +284,6 @@ interface Array<T> {}`
|
||||
};
|
||||
|
||||
const sourceFile = program.getSourceFile(path)!;
|
||||
const host = projectSystem.createServerHost([f, libFile]);
|
||||
const projectService = projectSystem.createProjectService(host);
|
||||
projectService.openClientFile(f.path);
|
||||
const languageService = projectService.inferredProjects[0].getLanguageService();
|
||||
const context: CodeFixContext = {
|
||||
errorCode: 80006,
|
||||
span: { start: selectionRange.pos, length: selectionRange.end - selectionRange.pos },
|
||||
@@ -361,37 +296,45 @@ interface Array<T> {}`
|
||||
};
|
||||
|
||||
const diagnostics = languageService.getSuggestionDiagnostics(f.path);
|
||||
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 diagnostic = find(diagnostics, diagnostic => diagnostic.messageText === Diagnostics.This_may_be_converted_to_an_async_function.message &&
|
||||
diagnostic.start === context.span.start && diagnostic.length === context.span.length);
|
||||
if (expectFailure) {
|
||||
assert.isUndefined(diagnostic);
|
||||
}
|
||||
else {
|
||||
assert.exists(diagnostic);
|
||||
}
|
||||
|
||||
const actions = codefix.getFixes(context);
|
||||
const action = find(actions, action => action.description === codeFixDescription.message)!;
|
||||
assert.exists(action);
|
||||
const action = find(actions, action => action.description === Diagnostics.Convert_to_async_function.message);
|
||||
if (expectFailure) {
|
||||
assert.isNotTrue(action && action.changes.length > 0);
|
||||
return;
|
||||
}
|
||||
|
||||
assert.isTrue(action && action.changes.length > 0);
|
||||
|
||||
const data: string[] = [];
|
||||
data.push(`// ==ORIGINAL==`);
|
||||
data.push(text.replace("[#|", "/*[#|*/").replace("|]", "/*|]*/"));
|
||||
const changes = action.changes;
|
||||
const changes = action!.changes;
|
||||
assert.lengthOf(changes, 1);
|
||||
|
||||
data.push(`// ==ASYNC FUNCTION::${action.description}==`);
|
||||
data.push(`// ==ASYNC FUNCTION::${action!.description}==`);
|
||||
const newText = textChanges.applyChanges(sourceFile.text, changes[0].textChanges);
|
||||
data.push(newText);
|
||||
|
||||
const diagProgram = makeProgram({ path, content: newText }, includeLib)!;
|
||||
const diagProgram = makeLanguageService({ path, content: newText }, includeLib).getProgram()!;
|
||||
assert.isFalse(hasSyntacticDiagnostics(diagProgram));
|
||||
Harness.Baseline.runBaseline(`${baselineFolder}/${caption}${extension}`, data.join(newLineCharacter));
|
||||
}
|
||||
|
||||
function makeProgram(f: { path: string, content: string }, includeLib?: boolean) {
|
||||
function makeLanguageService(f: { path: string, content: string }, includeLib?: boolean) {
|
||||
|
||||
const host = projectSystem.createServerHost(includeLib ? [f, libFile] : [f]); // libFile is expensive to parse repeatedly - only test when required
|
||||
const projectService = projectSystem.createProjectService(host);
|
||||
projectService.openClientFile(f.path);
|
||||
const program = projectService.inferredProjects[0].getLanguageService().getProgram();
|
||||
return program;
|
||||
return projectService.inferredProjects[0].getLanguageService();
|
||||
}
|
||||
|
||||
function hasSyntacticDiagnostics(program: Program) {
|
||||
@@ -400,27 +343,6 @@ interface Array<T> {}`
|
||||
}
|
||||
}
|
||||
|
||||
function testConvertToAsyncFunctionFailed(caption: string, text: string, description: DiagnosticMessage) {
|
||||
it(caption, () => {
|
||||
const t = extractTest(text);
|
||||
const selectionRange = t.ranges.get("selection");
|
||||
if (!selectionRange) {
|
||||
throw new Error(`Test ${caption} does not specify selection range`);
|
||||
}
|
||||
const f = {
|
||||
path: "/a.ts",
|
||||
content: t.source
|
||||
};
|
||||
const host = projectSystem.createServerHost([f, libFile]);
|
||||
const projectService = projectSystem.createProjectService(host);
|
||||
projectService.openClientFile(f.path);
|
||||
const languageService = projectService.inferredProjects[0].getLanguageService();
|
||||
|
||||
const actions = languageService.getSuggestionDiagnostics(f.path);
|
||||
assert.isUndefined(find(actions, action => action.messageText === description.message));
|
||||
});
|
||||
}
|
||||
|
||||
describe("convertToAsyncFunctions", () => {
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_basic", `
|
||||
function [#|f|](): Promise<void>{
|
||||
@@ -545,6 +467,12 @@ function [#|f|]():Promise<void | Response> {
|
||||
function [#|f|]():Promise<void | Response> {
|
||||
return fetch('https://typescriptlang.org').catch(rej => console.log(rej));
|
||||
}
|
||||
`
|
||||
);
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_NoRes4", `
|
||||
function [#|f|]() {
|
||||
return fetch('https://typescriptlang.org').then(undefined, rejection => console.log("rejected:", rejection));
|
||||
}
|
||||
`
|
||||
);
|
||||
_testConvertToAsyncFunctionFailed("convertToAsyncFunction_NoSuggestion", `
|
||||
@@ -823,7 +751,7 @@ function [#|f|](): Promise<void> {
|
||||
}
|
||||
return x.then(resp => {
|
||||
var blob = resp.blob().then(blob => blob.byteOffset).catch(err => 'Error');
|
||||
return fetch("https://micorosft.com").then(res => console.log("Another one!"));
|
||||
return fetch("https://microsoft.com").then(res => console.log("Another one!"));
|
||||
});
|
||||
}
|
||||
`
|
||||
@@ -1157,7 +1085,7 @@ function [#|f|]() {
|
||||
`
|
||||
);
|
||||
|
||||
_testConvertToAsyncFunctionFailed("convertToAsyncFunction_NestedFunction", `
|
||||
_testConvertToAsyncFunctionFailed("convertToAsyncFunction_NestedFunctionWrongLocation", `
|
||||
function [#|f|]() {
|
||||
function fn2(){
|
||||
function fn3(){
|
||||
@@ -1167,6 +1095,18 @@ function [#|f|]() {
|
||||
}
|
||||
return fn2();
|
||||
}
|
||||
`);
|
||||
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_NestedFunctionRightLocation", `
|
||||
function f() {
|
||||
function fn2(){
|
||||
function [#|fn3|](){
|
||||
return fetch("https://typescriptlang.org").then(res => console.log(res));
|
||||
}
|
||||
return fn3();
|
||||
}
|
||||
return fn2();
|
||||
}
|
||||
`);
|
||||
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_UntypedFunction", `
|
||||
@@ -1194,14 +1134,62 @@ const [#|foo|] = function () {
|
||||
}
|
||||
`);
|
||||
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_simpleFunctionExpressionWithName", `
|
||||
const foo = function [#|f|]() {
|
||||
return fetch('https://typescriptlang.org').then(result => { console.log(result) });
|
||||
}
|
||||
`);
|
||||
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_simpleFunctionExpressionAssignedToBindingPattern", `
|
||||
const { length } = [#|function|] () {
|
||||
return fetch('https://typescriptlang.org').then(result => { console.log(result) });
|
||||
}
|
||||
`);
|
||||
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_catchBlockUniqueParams", `
|
||||
function [#|f|]() {
|
||||
return Promise.resolve().then(x => 1).catch(x => "a").then(x => !!x);
|
||||
}
|
||||
`);
|
||||
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_bindingPattern", `
|
||||
function [#|f|]() {
|
||||
return fetch('https://typescriptlang.org').then(res);
|
||||
}
|
||||
function res({ status, trailer }){
|
||||
console.log(status);
|
||||
}
|
||||
`);
|
||||
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_bindingPatternNameCollision", `
|
||||
function [#|f|]() {
|
||||
const result = 'https://typescriptlang.org';
|
||||
return fetch(result).then(res);
|
||||
}
|
||||
function res({ status, trailer }){
|
||||
console.log(status);
|
||||
}
|
||||
`);
|
||||
|
||||
_testConvertToAsyncFunctionFailed("convertToAsyncFunction_thenArgumentNotFunction", `
|
||||
function [#|f|]() {
|
||||
return Promise.resolve().then(f ? (x => x) : (y => y));
|
||||
}
|
||||
`);
|
||||
|
||||
_testConvertToAsyncFunctionFailed("convertToAsyncFunction_thenArgumentNotFunctionNotLastInChain", `
|
||||
function [#|f|]() {
|
||||
return Promise.resolve().then(f ? (x => x) : (y => y)).then(q => q);
|
||||
}
|
||||
`);
|
||||
|
||||
});
|
||||
|
||||
function _testConvertToAsyncFunction(caption: string, text: string) {
|
||||
testConvertToAsyncFunction(caption, text, "convertToAsyncFunction", Diagnostics.This_may_be_converted_to_an_async_function, Diagnostics.Convert_to_async_function, /*includeLib*/ true);
|
||||
testConvertToAsyncFunction(caption, text, "convertToAsyncFunction", /*includeLib*/ true);
|
||||
}
|
||||
|
||||
function _testConvertToAsyncFunctionFailed(caption: string, text: string) {
|
||||
testConvertToAsyncFunctionFailed(caption, text, Diagnostics.Convert_to_async_function);
|
||||
testConvertToAsyncFunction(caption, text, "convertToAsyncFunction", /*includeLib*/ true, /*expectFailure*/ true);
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
@@ -76,7 +83,7 @@ namespace ts {
|
||||
describe("Node module resolution - relative paths", () => {
|
||||
|
||||
function testLoadAsFile(containingFileName: string, moduleFileNameNoExt: string, moduleName: string): void {
|
||||
for (const ext of supportedTypeScriptExtensions) {
|
||||
for (const ext of supportedTSExtensions) {
|
||||
test(ext, /*hasDirectoryExists*/ false);
|
||||
test(ext, /*hasDirectoryExists*/ true);
|
||||
}
|
||||
@@ -89,7 +96,7 @@ namespace ts {
|
||||
|
||||
const failedLookupLocations: string[] = [];
|
||||
const dir = getDirectoryPath(containingFileName);
|
||||
for (const e of supportedTypeScriptExtensions) {
|
||||
for (const e of supportedTSExtensions) {
|
||||
if (e === ext) {
|
||||
break;
|
||||
}
|
||||
@@ -130,7 +137,7 @@ namespace ts {
|
||||
const resolution = nodeModuleNameResolver(moduleName, containingFile.name, {}, createModuleResolutionHost(hasDirectoryExists, containingFile, packageJson, moduleFile));
|
||||
checkResolvedModule(resolution.resolvedModule, createResolvedModule(moduleFile.name));
|
||||
// expect three failed lookup location - attempt to load module as file with all supported extensions
|
||||
assert.equal(resolution.failedLookupLocations.length, supportedTypeScriptExtensions.length);
|
||||
assert.equal(resolution.failedLookupLocations.length, supportedTSExtensions.length);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 = $") },
|
||||
@@ -895,7 +914,8 @@ namespace ts {
|
||||
program, newRootFileNames, newOptions,
|
||||
path => program.getSourceFileByPath(path)!.version, /*fileExists*/ returnFalse,
|
||||
/*hasInvalidatedResolution*/ returnFalse,
|
||||
/*hasChangedAutomaticTypeDirectiveNames*/ false
|
||||
/*hasChangedAutomaticTypeDirectiveNames*/ false,
|
||||
/*projectReferences*/ undefined
|
||||
);
|
||||
assert.isTrue(actual);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
namespace ts {
|
||||
import theory = utils.theory;
|
||||
describe("semver", () => {
|
||||
describe("Version", () => {
|
||||
function assertVersion(version: Version, [major, minor, patch, prerelease, build]: [number, number, number, string[]?, string[]?]) {
|
||||
assert.strictEqual(version.major, major);
|
||||
assert.strictEqual(version.minor, minor);
|
||||
assert.strictEqual(version.patch, patch);
|
||||
assert.deepEqual(version.prerelease, prerelease || emptyArray);
|
||||
assert.deepEqual(version.build, build || emptyArray);
|
||||
}
|
||||
describe("new", () => {
|
||||
it("text", () => {
|
||||
assertVersion(new Version("1.2.3-pre.4+build.5"), [1, 2, 3, ["pre", "4"], ["build", "5"]]);
|
||||
});
|
||||
it("parts", () => {
|
||||
assertVersion(new Version(1, 2, 3, "pre.4", "build.5"), [1, 2, 3, ["pre", "4"], ["build", "5"]]);
|
||||
assertVersion(new Version(1, 2, 3), [1, 2, 3]);
|
||||
assertVersion(new Version(1, 2), [1, 2, 0]);
|
||||
assertVersion(new Version(1), [1, 0, 0]);
|
||||
});
|
||||
});
|
||||
it("toString", () => {
|
||||
assert.strictEqual(new Version(1, 2, 3, "pre.4", "build.5").toString(), "1.2.3-pre.4+build.5");
|
||||
assert.strictEqual(new Version(1, 2, 3, "pre.4").toString(), "1.2.3-pre.4");
|
||||
assert.strictEqual(new Version(1, 2, 3, /*prerelease*/ undefined, "build.5").toString(), "1.2.3+build.5");
|
||||
assert.strictEqual(new Version(1, 2, 3).toString(), "1.2.3");
|
||||
assert.strictEqual(new Version(1, 2).toString(), "1.2.0");
|
||||
assert.strictEqual(new Version(1).toString(), "1.0.0");
|
||||
});
|
||||
it("compareTo", () => {
|
||||
// https://semver.org/#spec-item-11
|
||||
// > Precedence is determined by the first difference when comparing each of these
|
||||
// > identifiers from left to right as follows: Major, minor, and patch versions are
|
||||
// > always compared numerically.
|
||||
assert.strictEqual(new Version("1.0.0").compareTo(new Version("2.0.0")), Comparison.LessThan);
|
||||
assert.strictEqual(new Version("1.0.0").compareTo(new Version("1.1.0")), Comparison.LessThan);
|
||||
assert.strictEqual(new Version("1.0.0").compareTo(new Version("1.0.1")), Comparison.LessThan);
|
||||
assert.strictEqual(new Version("2.0.0").compareTo(new Version("1.0.0")), Comparison.GreaterThan);
|
||||
assert.strictEqual(new Version("1.1.0").compareTo(new Version("1.0.0")), Comparison.GreaterThan);
|
||||
assert.strictEqual(new Version("1.0.1").compareTo(new Version("1.0.0")), Comparison.GreaterThan);
|
||||
assert.strictEqual(new Version("1.0.0").compareTo(new Version("1.0.0")), Comparison.EqualTo);
|
||||
|
||||
// https://semver.org/#spec-item-11
|
||||
// > When major, minor, and patch are equal, a pre-release version has lower
|
||||
// > precedence than a normal version.
|
||||
assert.strictEqual(new Version("1.0.0").compareTo(new Version("1.0.0-pre")), Comparison.GreaterThan);
|
||||
assert.strictEqual(new Version("1.0.1-pre").compareTo(new Version("1.0.0")), Comparison.GreaterThan);
|
||||
assert.strictEqual(new Version("1.0.0-pre").compareTo(new Version("1.0.0")), Comparison.LessThan);
|
||||
|
||||
// https://semver.org/#spec-item-11
|
||||
// > identifiers consisting of only digits are compared numerically
|
||||
assert.strictEqual(new Version("1.0.0-0").compareTo(new Version("1.0.0-1")), Comparison.LessThan);
|
||||
assert.strictEqual(new Version("1.0.0-1").compareTo(new Version("1.0.0-0")), Comparison.GreaterThan);
|
||||
assert.strictEqual(new Version("1.0.0-2").compareTo(new Version("1.0.0-10")), Comparison.LessThan);
|
||||
assert.strictEqual(new Version("1.0.0-10").compareTo(new Version("1.0.0-2")), Comparison.GreaterThan);
|
||||
assert.strictEqual(new Version("1.0.0-0").compareTo(new Version("1.0.0-0")), Comparison.EqualTo);
|
||||
|
||||
// https://semver.org/#spec-item-11
|
||||
// > identifiers with letters or hyphens are compared lexically in ASCII sort order.
|
||||
assert.strictEqual(new Version("1.0.0-a").compareTo(new Version("1.0.0-b")), Comparison.LessThan);
|
||||
assert.strictEqual(new Version("1.0.0-a-2").compareTo(new Version("1.0.0-a-10")), Comparison.GreaterThan);
|
||||
assert.strictEqual(new Version("1.0.0-b").compareTo(new Version("1.0.0-a")), Comparison.GreaterThan);
|
||||
assert.strictEqual(new Version("1.0.0-a").compareTo(new Version("1.0.0-a")), Comparison.EqualTo);
|
||||
assert.strictEqual(new Version("1.0.0-A").compareTo(new Version("1.0.0-a")), Comparison.LessThan);
|
||||
|
||||
// https://semver.org/#spec-item-11
|
||||
// > Numeric identifiers always have lower precedence than non-numeric identifiers.
|
||||
assert.strictEqual(new Version("1.0.0-0").compareTo(new Version("1.0.0-alpha")), Comparison.LessThan);
|
||||
assert.strictEqual(new Version("1.0.0-alpha").compareTo(new Version("1.0.0-0")), Comparison.GreaterThan);
|
||||
assert.strictEqual(new Version("1.0.0-0").compareTo(new Version("1.0.0-0")), Comparison.EqualTo);
|
||||
assert.strictEqual(new Version("1.0.0-alpha").compareTo(new Version("1.0.0-alpha")), Comparison.EqualTo);
|
||||
|
||||
// https://semver.org/#spec-item-11
|
||||
// > A larger set of pre-release fields has a higher precedence than a smaller set, if all
|
||||
// > of the preceding identifiers are equal.
|
||||
assert.strictEqual(new Version("1.0.0-alpha").compareTo(new Version("1.0.0-alpha.0")), Comparison.LessThan);
|
||||
assert.strictEqual(new Version("1.0.0-alpha.0").compareTo(new Version("1.0.0-alpha")), Comparison.GreaterThan);
|
||||
|
||||
// https://semver.org/#spec-item-11
|
||||
// > Precedence for two pre-release versions with the same major, minor, and patch version
|
||||
// > MUST be determined by comparing each dot separated identifier from left to right until
|
||||
// > a difference is found [...]
|
||||
assert.strictEqual(new Version("1.0.0-a.0.b.1").compareTo(new Version("1.0.0-a.0.b.2")), Comparison.LessThan);
|
||||
assert.strictEqual(new Version("1.0.0-a.0.b.1").compareTo(new Version("1.0.0-b.0.a.1")), Comparison.LessThan);
|
||||
assert.strictEqual(new Version("1.0.0-a.0.b.2").compareTo(new Version("1.0.0-a.0.b.1")), Comparison.GreaterThan);
|
||||
assert.strictEqual(new Version("1.0.0-b.0.a.1").compareTo(new Version("1.0.0-a.0.b.1")), Comparison.GreaterThan);
|
||||
|
||||
// https://semver.org/#spec-item-11
|
||||
// > Build metadata does not figure into precedence
|
||||
assert.strictEqual(new Version("1.0.0+build").compareTo(new Version("1.0.0")), Comparison.EqualTo);
|
||||
});
|
||||
it("increment", () => {
|
||||
assertVersion(new Version(1, 2, 3, "pre.4", "build.5").increment("major"), [2, 0, 0]);
|
||||
assertVersion(new Version(1, 2, 3, "pre.4", "build.5").increment("minor"), [1, 3, 0]);
|
||||
assertVersion(new Version(1, 2, 3, "pre.4", "build.5").increment("patch"), [1, 2, 4]);
|
||||
});
|
||||
});
|
||||
describe("VersionRange", () => {
|
||||
function assertRange(rangeText: string, versionText: string, inRange = true) {
|
||||
const range = new VersionRange(rangeText);
|
||||
const version = new Version(versionText);
|
||||
assert.strictEqual(range.test(version), inRange, `Expected version '${version}' ${inRange ? `to be` : `to not be`} in range '${rangeText}' (${range})`);
|
||||
}
|
||||
theory("comparators", assertRange, [
|
||||
["", "1.0.0"],
|
||||
["*", "1.0.0"],
|
||||
["1", "1.0.0"],
|
||||
["1", "2.0.0", false],
|
||||
["1.0", "1.0.0"],
|
||||
["1.0", "1.1.0", false],
|
||||
["1.0.0", "1.0.0"],
|
||||
["1.0.0", "1.0.1", false],
|
||||
["1.*", "1.0.0"],
|
||||
["1.*", "2.0.0", false],
|
||||
["1.x", "1.0.0"],
|
||||
["1.x", "2.0.0", false],
|
||||
["=1", "1.0.0"],
|
||||
["=1", "1.1.0"],
|
||||
["=1", "1.0.1"],
|
||||
["=1.0", "1.0.0"],
|
||||
["=1.0", "1.0.1"],
|
||||
["=1.0.0", "1.0.0"],
|
||||
["=*", "0.0.0"],
|
||||
["=*", "1.0.0"],
|
||||
[">1", "2"],
|
||||
[">1.0", "1.1"],
|
||||
[">1.0.0", "1.0.1"],
|
||||
[">1.0.0", "1.0.1-pre"],
|
||||
[">*", "0.0.0", false],
|
||||
[">*", "1.0.0", false],
|
||||
[">=1", "1.0.0"],
|
||||
[">=1.0", "1.0.0"],
|
||||
[">=1.0.0", "1.0.0"],
|
||||
[">=1.0.0", "1.0.1-pre"],
|
||||
[">=*", "0.0.0"],
|
||||
[">=*", "1.0.0"],
|
||||
["<2", "1.0.0"],
|
||||
["<2.1", "2.0.0"],
|
||||
["<2.0.1", "2.0.0"],
|
||||
["<2.0.0", "2.0.0-pre"],
|
||||
["<*", "0.0.0", false],
|
||||
["<*", "1.0.0", false],
|
||||
["<=2", "2.0.0"],
|
||||
["<=2.1", "2.1.0"],
|
||||
["<=2.0.1", "2.0.1"],
|
||||
["<=*", "0.0.0"],
|
||||
["<=*", "1.0.0"],
|
||||
]);
|
||||
theory("conjunctions", assertRange, [
|
||||
[">1.0.0 <2.0.0", "1.0.1"],
|
||||
[">1.0.0 <2.0.0", "2.0.0", false],
|
||||
[">1.0.0 <2.0.0", "1.0.0", false],
|
||||
[">1 >2", "3.0.0"],
|
||||
]);
|
||||
theory("disjunctions", assertRange, [
|
||||
[">=1.0.0 <2.0.0 || >=3.0.0 <4.0.0", "1.0.0"],
|
||||
[">=1.0.0 <2.0.0 || >=3.0.0 <4.0.0", "2.0.0", false],
|
||||
[">=1.0.0 <2.0.0 || >=3.0.0 <4.0.0", "3.0.0"],
|
||||
]);
|
||||
theory("hyphen", assertRange, [
|
||||
["1.0.0 - 2.0.0", "1.0.0"],
|
||||
["1.0.0 - 2.0.0", "2.0.0"],
|
||||
["1.0.0 - 2.0.0", "3.0.0", false],
|
||||
]);
|
||||
theory("tilde", assertRange, [
|
||||
["~0", "0.0.0"],
|
||||
["~0", "0.1.0"],
|
||||
["~0", "0.1.2"],
|
||||
["~0", "0.1.9"],
|
||||
["~0", "1.0.0", false],
|
||||
["~0.1", "0.1.0"],
|
||||
["~0.1", "0.1.2"],
|
||||
["~0.1", "0.1.9"],
|
||||
["~0.1", "0.2.0", false],
|
||||
["~0.1.2", "0.1.2"],
|
||||
["~0.1.2", "0.1.9"],
|
||||
["~0.1.2", "0.2.0", false],
|
||||
["~1", "1.0.0"],
|
||||
["~1", "1.2.0"],
|
||||
["~1", "1.2.3"],
|
||||
["~1", "1.2.0"],
|
||||
["~1", "1.2.3"],
|
||||
["~1", "0.0.0", false],
|
||||
["~1", "2.0.0", false],
|
||||
["~1.2", "1.2.0"],
|
||||
["~1.2", "1.2.3"],
|
||||
["~1.2", "1.1.0", false],
|
||||
["~1.2", "1.3.0", false],
|
||||
["~1.2.3", "1.2.3"],
|
||||
["~1.2.3", "1.2.9"],
|
||||
["~1.2.3", "1.1.0", false],
|
||||
["~1.2.3", "1.3.0", false],
|
||||
]);
|
||||
theory("caret", assertRange, [
|
||||
["^0", "0.0.0"],
|
||||
["^0", "0.1.0"],
|
||||
["^0", "0.9.0"],
|
||||
["^0", "0.1.2"],
|
||||
["^0", "0.1.9"],
|
||||
["^0", "1.0.0", false],
|
||||
["^0.1", "0.1.0"],
|
||||
["^0.1", "0.1.2"],
|
||||
["^0.1", "0.1.9"],
|
||||
["^0.1.2", "0.1.2"],
|
||||
["^0.1.2", "0.1.9"],
|
||||
["^0.1.2", "0.0.0", false],
|
||||
["^0.1.2", "0.2.0", false],
|
||||
["^0.1.2", "1.0.0", false],
|
||||
["^1", "1.0.0"],
|
||||
["^1", "1.2.0"],
|
||||
["^1", "1.2.3"],
|
||||
["^1", "1.9.0"],
|
||||
["^1", "0.0.0", false],
|
||||
["^1", "2.0.0", false],
|
||||
["^1.2", "1.2.0"],
|
||||
["^1.2", "1.2.3"],
|
||||
["^1.2", "1.9.0"],
|
||||
["^1.2", "1.1.0", false],
|
||||
["^1.2", "2.0.0", false],
|
||||
["^1.2.3", "1.2.3"],
|
||||
["^1.2.3", "1.9.0"],
|
||||
["^1.2.3", "1.2.2", false],
|
||||
["^1.2.3", "2.0.0", false],
|
||||
]);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -199,7 +199,7 @@ namespace ts {
|
||||
tick();
|
||||
touch(fs, "/src/logic/index.ts");
|
||||
// Because we haven't reset the build context, the builder should assume there's nothing to do right now
|
||||
const status = builder.getUpToDateStatusOfFile(builder.resolveProjectName("/src/logic")!);
|
||||
const status = builder.getUpToDateStatusOfFile(builder.resolveProjectName("/src/logic"));
|
||||
assert.equal(status.type, UpToDateStatusType.UpToDate, "Project should be assumed to be up-to-date");
|
||||
|
||||
// Rebuild this project
|
||||
@@ -210,10 +210,26 @@ namespace ts {
|
||||
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");
|
||||
|
||||
// Does not build tests or core because there is no change in declaration file
|
||||
tick();
|
||||
builder.buildInvalidatedProject();
|
||||
assert.isBelow(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");
|
||||
|
||||
// Rebuild this project
|
||||
tick();
|
||||
fs.writeFileSync("/src/logic/index.ts", `${fs.readFileSync("/src/logic/index.ts")}
|
||||
export class cNew {}`);
|
||||
builder.invalidateProject("/src/logic");
|
||||
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.buildInvalidatedProject();
|
||||
assert.equal(fs.statSync("/src/tests/index.js").mtimeMs, time(), "Downstream JS file should have been rebuilt");
|
||||
assert.isBelow(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");
|
||||
});
|
||||
});
|
||||
@@ -248,6 +264,63 @@ namespace ts {
|
||||
verifyProjectWithResolveJsonModule("/src/tests/tsconfig_withIncludeAndFiles.json");
|
||||
});
|
||||
});
|
||||
|
||||
describe("tsbuild - lists files", () => {
|
||||
it("listFiles", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { listFiles: true });
|
||||
builder.buildAllProjects();
|
||||
assert.deepEqual(host.traces, [
|
||||
...getLibs(),
|
||||
"/src/core/anotherModule.ts",
|
||||
"/src/core/index.ts",
|
||||
"/src/core/some_decl.d.ts",
|
||||
...getLibs(),
|
||||
...getCoreOutputs(),
|
||||
"/src/logic/index.ts",
|
||||
...getLibs(),
|
||||
...getCoreOutputs(),
|
||||
"/src/logic/index.d.ts",
|
||||
"/src/tests/index.ts"
|
||||
]);
|
||||
|
||||
function getLibs() {
|
||||
return [
|
||||
"/lib/lib.d.ts",
|
||||
"/lib/lib.es5.d.ts",
|
||||
"/lib/lib.dom.d.ts",
|
||||
"/lib/lib.webworker.importscripts.d.ts",
|
||||
"/lib/lib.scripthost.d.ts"
|
||||
];
|
||||
}
|
||||
|
||||
function getCoreOutputs() {
|
||||
return [
|
||||
"/src/core/index.d.ts",
|
||||
"/src/core/anotherModule.d.ts"
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
it("listEmittedFiles", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/tests"], { listEmittedFiles: true });
|
||||
builder.buildAllProjects();
|
||||
assert.deepEqual(host.traces, [
|
||||
"TSFILE: /src/core/anotherModule.js",
|
||||
"TSFILE: /src/core/anotherModule.d.ts",
|
||||
"TSFILE: /src/core/index.js",
|
||||
"TSFILE: /src/core/index.d.ts",
|
||||
"TSFILE: /src/logic/index.js",
|
||||
"TSFILE: /src/logic/index.js.map",
|
||||
"TSFILE: /src/logic/index.d.ts",
|
||||
"TSFILE: /src/tests/index.js",
|
||||
"TSFILE: /src/tests/index.d.ts",
|
||||
]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export namespace OutFile {
|
||||
@@ -292,6 +365,48 @@ namespace ts {
|
||||
});
|
||||
}
|
||||
|
||||
export namespace EmptyFiles {
|
||||
const projFs = loadProjectFromDisk("tests/projects/empty-files");
|
||||
|
||||
const allExpectedOutputs = [
|
||||
"/src/core/index.js",
|
||||
"/src/core/index.d.ts",
|
||||
"/src/core/index.d.ts.map",
|
||||
];
|
||||
|
||||
describe("tsbuild - empty files option in tsconfig", () => {
|
||||
it("has empty files diagnostic when files is empty and no references are provided", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/no-references"], { dry: false, force: false, verbose: false });
|
||||
|
||||
host.clearDiagnostics();
|
||||
builder.buildAllProjects();
|
||||
host.assertDiagnosticMessages(Diagnostics.The_files_list_in_config_file_0_is_empty);
|
||||
|
||||
// Check for outputs to not be written.
|
||||
for (const output of allExpectedOutputs) {
|
||||
assert(!fs.existsSync(output), `Expect file ${output} to not exist`);
|
||||
}
|
||||
});
|
||||
|
||||
it("does not have empty files diagnostic when files is empty and references are provided", () => {
|
||||
const fs = projFs.shadow();
|
||||
const host = new fakes.SolutionBuilderHost(fs);
|
||||
const builder = createSolutionBuilder(host, ["/src/with-references"], { dry: false, force: false, verbose: false });
|
||||
|
||||
host.clearDiagnostics();
|
||||
builder.buildAllProjects();
|
||||
host.assertDiagnosticMessages(/*empty*/);
|
||||
|
||||
// Check for outputs to be written.
|
||||
for (const output of allExpectedOutputs) {
|
||||
assert(fs.existsSync(output), `Expect file ${output} to exist`);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe("tsbuild - graph-ordering", () => {
|
||||
let host: fakes.SolutionBuilderHost | undefined;
|
||||
const deps: [string, string][] = [
|
||||
@@ -335,7 +450,6 @@ namespace ts {
|
||||
|
||||
const projFileNames = rootNames.map(getProjectFileName);
|
||||
const graph = builder.getBuildGraph(projFileNames);
|
||||
if (graph === undefined) throw new Error("Graph shouldn't be undefined");
|
||||
|
||||
assert.sameMembers(graph.buildQueue, expectedBuildSet.map(getProjectFileName));
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ 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 });
|
||||
return ts.createSolutionBuilder(host, rootNames, defaultOptions || { watch: true });
|
||||
}
|
||||
|
||||
function createSolutionBuilderWithWatch(host: WatchedSystem, rootNames: ReadonlyArray<string>, defaultOptions?: BuildOptions) {
|
||||
@@ -26,8 +26,12 @@ namespace ts.tscWatch {
|
||||
type SubProjectFiles = [ReadonlyFile, ReadonlyFile] | [ReadonlyFile, ReadonlyFile, ReadonlyFile, ReadonlyFile];
|
||||
const root = Harness.IO.getWorkspaceRoot();
|
||||
|
||||
function projectPath(subProject: SubProject) {
|
||||
return `${projectsLocation}/${project}/${subProject}`;
|
||||
}
|
||||
|
||||
function projectFilePath(subProject: SubProject, baseFileName: string) {
|
||||
return `${projectsLocation}/${project}/${subProject}/${baseFileName.toLowerCase()}`;
|
||||
return `${projectPath(subProject)}/${baseFileName.toLowerCase()}`;
|
||||
}
|
||||
|
||||
function projectFile(subProject: SubProject, baseFileName: string): File {
|
||||
@@ -58,13 +62,17 @@ namespace ts.tscWatch {
|
||||
return getOutputFileNames(subProject, baseFileNameWithoutExtension).map(f => [f, host.getModifiedTime(f)] as OutputFileStamp);
|
||||
}
|
||||
|
||||
function getOutputFileStamps(host: WatchedSystem): OutputFileStamp[] {
|
||||
return [
|
||||
function getOutputFileStamps(host: WatchedSystem, additionalFiles?: ReadonlyArray<[SubProject, string]>): OutputFileStamp[] {
|
||||
const result = [
|
||||
...getOutputStamps(host, SubProject.core, "anotherModule"),
|
||||
...getOutputStamps(host, SubProject.core, "index"),
|
||||
...getOutputStamps(host, SubProject.logic, "index"),
|
||||
...getOutputStamps(host, SubProject.tests, "index"),
|
||||
];
|
||||
if (additionalFiles) {
|
||||
additionalFiles.forEach(([subProject, baseFileNameWithoutExtension]) => result.push(...getOutputStamps(host, subProject, baseFileNameWithoutExtension)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function verifyChangedFiles(actualStamps: OutputFileStamp[], oldTimeStamps: OutputFileStamp[], changedFiles: string[]) {
|
||||
@@ -87,68 +95,306 @@ namespace ts.tscWatch {
|
||||
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() {
|
||||
function createSolutionInWatchMode(allFiles: ReadonlyArray<File>, defaultOptions?: BuildOptions, disableConsoleClears?: boolean) {
|
||||
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);
|
||||
createSolutionBuilderWithWatch(host, [`${project}/${SubProject.tests}`], defaultOptions);
|
||||
verifyWatches(host);
|
||||
checkOutputErrorsInitial(host, emptyArray, disableConsoleClears);
|
||||
const outputFileStamps = getOutputFileStamps(host);
|
||||
for (const stamp of outputFileStamps) {
|
||||
assert.isDefined(stamp[1], `${stamp[0]} expected to be present`);
|
||||
}
|
||||
return host;
|
||||
}
|
||||
|
||||
function verifyWatches(host: WatchedSystem) {
|
||||
checkWatchedFiles(host, testProjectExpectedWatchedFiles);
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
|
||||
checkWatchedDirectories(host, [projectPath(SubProject.core), projectPath(SubProject.logic)], /*recursive*/ true);
|
||||
}
|
||||
|
||||
it("creates solution in watch mode", () => {
|
||||
createSolutionInWatchMode();
|
||||
createSolutionInWatchMode(allFiles);
|
||||
});
|
||||
|
||||
it("change builds changes and reports found errors message", () => {
|
||||
const host = createSolutionInWatchMode();
|
||||
verifyChange(`${core[1].content}
|
||||
describe("validates the changes and watched files", () => {
|
||||
const newFileWithoutExtension = "newFile";
|
||||
const newFile: File = {
|
||||
path: projectFilePath(SubProject.core, `${newFileWithoutExtension}.ts`),
|
||||
content: `export const newFileConst = 30;`
|
||||
};
|
||||
|
||||
function verifyProjectChanges(allFiles: ReadonlyArray<File>) {
|
||||
function createSolutionInWatchModeToVerifyChanges(additionalFiles?: ReadonlyArray<[SubProject, string]>) {
|
||||
const host = createSolutionInWatchMode(allFiles);
|
||||
return { host, verifyChangeWithFile, verifyChangeAfterTimeout, verifyWatches };
|
||||
|
||||
function verifyChangeWithFile(fileName: string, content: string) {
|
||||
const outputFileStamps = getOutputFileStamps(host, additionalFiles);
|
||||
host.writeFile(fileName, content);
|
||||
verifyChangeAfterTimeout(outputFileStamps);
|
||||
}
|
||||
|
||||
function verifyChangeAfterTimeout(outputFileStamps: OutputFileStamp[]) {
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds core
|
||||
const changedCore = getOutputFileStamps(host, additionalFiles);
|
||||
verifyChangedFiles(changedCore, outputFileStamps, [
|
||||
...getOutputFileNames(SubProject.core, "anotherModule"), // This should not be written really
|
||||
...getOutputFileNames(SubProject.core, "index"),
|
||||
...(additionalFiles ? getOutputFileNames(SubProject.core, newFileWithoutExtension) : emptyArray)
|
||||
]);
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds logic
|
||||
const changedLogic = getOutputFileStamps(host, additionalFiles);
|
||||
verifyChangedFiles(changedLogic, changedCore, [
|
||||
...getOutputFileNames(SubProject.logic, "index") // Again these need not be written
|
||||
]);
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds tests
|
||||
const changedTests = getOutputFileStamps(host, additionalFiles);
|
||||
verifyChangedFiles(changedTests, changedLogic, [
|
||||
...getOutputFileNames(SubProject.tests, "index") // Again these need not be written
|
||||
]);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
checkOutputErrorsIncremental(host, emptyArray);
|
||||
verifyWatches();
|
||||
}
|
||||
|
||||
function verifyWatches() {
|
||||
checkWatchedFiles(host, additionalFiles ? testProjectExpectedWatchedFiles.concat(newFile.path) : testProjectExpectedWatchedFiles);
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
|
||||
checkWatchedDirectories(host, [projectPath(SubProject.core), projectPath(SubProject.logic)], /*recursive*/ true);
|
||||
}
|
||||
}
|
||||
|
||||
it("change builds changes and reports found errors message", () => {
|
||||
const { host, verifyChangeWithFile, verifyChangeAfterTimeout } = createSolutionInWatchModeToVerifyChanges();
|
||||
verifyChange(`${core[1].content}
|
||||
export class someClass { }`);
|
||||
|
||||
// Another change requeues and builds it
|
||||
verifyChange(core[1].content);
|
||||
// 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}
|
||||
// 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}
|
||||
host.writeFile(core[1].path, change1);
|
||||
host.writeFile(core[1].path, `${change1}
|
||||
export class someClass2 { }`);
|
||||
verifyChangeAfterTimeout(outputFileStamps);
|
||||
verifyChangeAfterTimeout(outputFileStamps);
|
||||
|
||||
function verifyChange(coreContent: string) {
|
||||
const outputFileStamps = getOutputFileStamps(host);
|
||||
host.writeFile(core[1].path, coreContent);
|
||||
verifyChangeAfterTimeout(outputFileStamps);
|
||||
function verifyChange(coreContent: string) {
|
||||
verifyChangeWithFile(core[1].path, coreContent);
|
||||
}
|
||||
});
|
||||
|
||||
it("non local change does not start build of referencing projects", () => {
|
||||
const host = createSolutionInWatchMode(allFiles);
|
||||
const outputFileStamps = getOutputFileStamps(host);
|
||||
host.writeFile(core[1].path, `${core[1].content}
|
||||
function foo() { }`);
|
||||
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.checkTimeoutQueueLength(0);
|
||||
checkOutputErrorsIncremental(host, emptyArray);
|
||||
verifyWatches(host);
|
||||
});
|
||||
|
||||
it("builds when new file is added, and its subsequent updates", () => {
|
||||
const additinalFiles: ReadonlyArray<[SubProject, string]> = [[SubProject.core, newFileWithoutExtension]];
|
||||
const { verifyChangeWithFile } = createSolutionInWatchModeToVerifyChanges(additinalFiles);
|
||||
verifyChange(newFile.content);
|
||||
|
||||
// Another change requeues and builds it
|
||||
verifyChange(`${newFile.content}
|
||||
export class someClass2 { }`);
|
||||
|
||||
function verifyChange(newFileContent: string) {
|
||||
verifyChangeWithFile(newFile.path, newFileContent);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function verifyChangeAfterTimeout(outputFileStamps: OutputFileStamp[]) {
|
||||
describe("with simple project reference graph", () => {
|
||||
verifyProjectChanges(allFiles);
|
||||
});
|
||||
|
||||
describe("with circular project reference", () => {
|
||||
const [coreTsconfig, ...otherCoreFiles] = core;
|
||||
const circularCoreConfig: File = {
|
||||
path: coreTsconfig.path,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { composite: true, declaration: true },
|
||||
references: [{ path: "../tests", circular: true }]
|
||||
})
|
||||
};
|
||||
verifyProjectChanges([libFile, circularCoreConfig, ...otherCoreFiles, ...logic, ...tests]);
|
||||
});
|
||||
});
|
||||
|
||||
it("watches config files that are not present", () => {
|
||||
const allFiles = [libFile, ...core, logic[1], ...tests];
|
||||
const host = createWatchedSystem(allFiles, { currentDirectory: projectsLocation });
|
||||
createSolutionBuilderWithWatch(host, [`${project}/${SubProject.tests}`]);
|
||||
checkWatchedFiles(host, [core[0], core[1], core[2], logic[0], ...tests].map(f => f.path));
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
|
||||
checkWatchedDirectories(host, [projectPath(SubProject.core)], /*recursive*/ true);
|
||||
checkOutputErrorsInitial(host, [
|
||||
createCompilerDiagnostic(Diagnostics.File_0_not_found, logic[0].path)
|
||||
]);
|
||||
for (const f of [
|
||||
...getOutputFileNames(SubProject.core, "anotherModule"),
|
||||
...getOutputFileNames(SubProject.core, "index")
|
||||
]) {
|
||||
assert.isTrue(host.fileExists(f), `${f} expected to be present`);
|
||||
}
|
||||
for (const f of [
|
||||
...getOutputFileNames(SubProject.logic, "index"),
|
||||
...getOutputFileNames(SubProject.tests, "index")
|
||||
]) {
|
||||
assert.isFalse(host.fileExists(f), `${f} expected to be absent`);
|
||||
}
|
||||
|
||||
// Create tsconfig file for logic and see that build succeeds
|
||||
const initial = getOutputFileStamps(host);
|
||||
host.writeFile(logic[0].path, logic[0].content);
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds logic
|
||||
const changedLogic = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedLogic, initial, [
|
||||
...getOutputFileNames(SubProject.logic, "index")
|
||||
]);
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds tests
|
||||
const changedTests = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedTests, changedLogic, [
|
||||
...getOutputFileNames(SubProject.tests, "index")
|
||||
]);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
checkOutputErrorsIncremental(host, emptyArray);
|
||||
verifyWatches(host);
|
||||
});
|
||||
|
||||
it("when referenced using prepend, builds referencing project even for non local change", () => {
|
||||
const coreTsConfig: File = {
|
||||
path: core[0].path,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { composite: true, declaration: true, outFile: "index.js" }
|
||||
})
|
||||
};
|
||||
const coreIndex: File = {
|
||||
path: core[1].path,
|
||||
content: `function foo() { return 10; }`
|
||||
};
|
||||
const logicTsConfig: File = {
|
||||
path: logic[0].path,
|
||||
content: JSON.stringify({
|
||||
compilerOptions: { composite: true, declaration: true, outFile: "index.js" },
|
||||
references: [{ path: "../core", prepend: true }]
|
||||
})
|
||||
};
|
||||
const logicIndex: File = {
|
||||
path: logic[1].path,
|
||||
content: `function bar() { return foo() + 1 };`
|
||||
};
|
||||
|
||||
const projectFiles = [coreTsConfig, coreIndex, logicTsConfig, logicIndex];
|
||||
const host = createWatchedSystem([libFile, ...projectFiles], { currentDirectory: projectsLocation });
|
||||
createSolutionBuilderWithWatch(host, [`${project}/${SubProject.logic}`]);
|
||||
verifyWatches();
|
||||
checkOutputErrorsInitial(host, emptyArray);
|
||||
const outputFileStamps = getOutputFileStamps();
|
||||
for (const stamp of outputFileStamps) {
|
||||
assert.isDefined(stamp[1], `${stamp[0]} expected to be present`);
|
||||
}
|
||||
|
||||
// Make non local change
|
||||
verifyChangeInCore(`${coreIndex.content}
|
||||
function myFunc() { return 10; }`);
|
||||
|
||||
// Make local change to function bar
|
||||
verifyChangeInCore(`${coreIndex.content}
|
||||
function myFunc() { return 100; }`);
|
||||
|
||||
function verifyChangeInCore(content: string) {
|
||||
const outputFileStamps = getOutputFileStamps();
|
||||
host.writeFile(coreIndex.path, content);
|
||||
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds core
|
||||
const changedCore = getOutputFileStamps(host);
|
||||
const changedCore = getOutputFileStamps();
|
||||
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
|
||||
const changedLogic = getOutputFileStamps();
|
||||
verifyChangedFiles(changedLogic, changedCore, [
|
||||
...getOutputFileNames(SubProject.logic, "index")
|
||||
]);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
checkOutputErrorsIncremental(host, emptyArray);
|
||||
verifyWatches();
|
||||
}
|
||||
|
||||
function getOutputFileStamps(): OutputFileStamp[] {
|
||||
const result = [
|
||||
...getOutputStamps(host, SubProject.core, "index"),
|
||||
...getOutputStamps(host, SubProject.logic, "index"),
|
||||
];
|
||||
return result;
|
||||
}
|
||||
|
||||
function verifyWatches() {
|
||||
checkWatchedFiles(host, projectFiles.map(f => f.path));
|
||||
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
|
||||
checkWatchedDirectories(host, [projectPath(SubProject.core), projectPath(SubProject.logic)], /*recursive*/ true);
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: write tests reporting errors but that will have more involved work since file
|
||||
describe("reports errors in all projects on incremental compile", () => {
|
||||
function verifyIncrementalErrors(defaultBuildOptions?: BuildOptions, disabledConsoleClear?: boolean) {
|
||||
const host = createSolutionInWatchMode(allFiles, defaultBuildOptions, disabledConsoleClear);
|
||||
const outputFileStamps = getOutputFileStamps(host);
|
||||
|
||||
host.writeFile(logic[1].path, `${logic[1].content}
|
||||
let y: string = 10;`);
|
||||
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds logic
|
||||
const changedLogic = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedLogic, outputFileStamps, emptyArray);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
checkOutputErrorsIncremental(host, [
|
||||
`sample1/logic/index.ts(8,5): error TS2322: Type '10' is not assignable to type 'string'.\n`
|
||||
], disabledConsoleClear);
|
||||
|
||||
host.writeFile(core[1].path, `${core[1].content}
|
||||
let x: string = 10;`);
|
||||
|
||||
host.checkTimeoutQueueLengthAndRun(1); // Builds core
|
||||
const changedCore = getOutputFileStamps(host);
|
||||
verifyChangedFiles(changedCore, changedLogic, emptyArray);
|
||||
host.checkTimeoutQueueLength(0);
|
||||
checkOutputErrorsIncremental(host, [
|
||||
`sample1/core/index.ts(5,5): error TS2322: Type '10' is not assignable to type 'string'.\n`,
|
||||
`sample1/logic/index.ts(8,5): error TS2322: Type '10' is not assignable to type 'string'.\n`
|
||||
], disabledConsoleClear);
|
||||
}
|
||||
|
||||
it("when preserveWatchOutput is not used", () => {
|
||||
verifyIncrementalErrors();
|
||||
});
|
||||
|
||||
it("when preserveWatchOutput is passed on command line", () => {
|
||||
verifyIncrementalErrors({ preserveWatchOutput: true, watch: true }, /*disabledConsoleClear*/ true);
|
||||
});
|
||||
});
|
||||
|
||||
it("tsc-watch works with project references", () => {
|
||||
// Build the composite project
|
||||
const host = createSolutionInWatchMode(allFiles);
|
||||
|
||||
createWatchOfConfigFile(tests[0].path, host);
|
||||
checkOutputErrorsInitial(host, emptyArray);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace ts.tscWatch {
|
||||
checkArray(`Program rootFileNames`, program.getRootFileNames(), expectedFiles);
|
||||
}
|
||||
|
||||
function createWatchOfConfigFile(configFileName: string, host: WatchedSystem, maxNumberOfFilesToIterateForInvalidation?: number) {
|
||||
export function createWatchOfConfigFile(configFileName: string, host: WatchedSystem, maxNumberOfFilesToIterateForInvalidation?: number) {
|
||||
const compilerHost = createWatchCompilerHostOfConfigFile(configFileName, {}, host);
|
||||
compilerHost.maxNumberOfFilesToIterateForInvalidation = maxNumberOfFilesToIterateForInvalidation;
|
||||
const watch = createWatchProgram(compilerHost);
|
||||
@@ -77,7 +77,7 @@ namespace ts.tscWatch {
|
||||
logsBeforeWatchDiagnostic: string[] | undefined,
|
||||
preErrorsWatchDiagnostic: Diagnostic,
|
||||
logsBeforeErrors: string[] | undefined,
|
||||
errors: ReadonlyArray<Diagnostic>,
|
||||
errors: ReadonlyArray<Diagnostic> | ReadonlyArray<string>,
|
||||
disableConsoleClears?: boolean | undefined,
|
||||
...postErrorsWatchDiagnostics: Diagnostic[]
|
||||
) {
|
||||
@@ -96,8 +96,12 @@ namespace ts.tscWatch {
|
||||
assert.equal(host.screenClears.length, screenClears, "Expected number of screen clears");
|
||||
host.clearOutput();
|
||||
|
||||
function assertDiagnostic(diagnostic: Diagnostic) {
|
||||
const expected = formatDiagnostic(diagnostic, host);
|
||||
function isDiagnostic(diagnostic: Diagnostic | string): diagnostic is Diagnostic {
|
||||
return !!(diagnostic as Diagnostic).messageText;
|
||||
}
|
||||
|
||||
function assertDiagnostic(diagnostic: Diagnostic | string) {
|
||||
const expected = isDiagnostic(diagnostic) ? formatDiagnostic(diagnostic, host) : diagnostic;
|
||||
assert.equal(outputs[index], expected, getOutputAtFailedMessage("Diagnostic", expected));
|
||||
index++;
|
||||
}
|
||||
@@ -130,13 +134,13 @@ namespace ts.tscWatch {
|
||||
}
|
||||
}
|
||||
|
||||
function createErrorsFoundCompilerDiagnostic(errors: ReadonlyArray<Diagnostic>) {
|
||||
function createErrorsFoundCompilerDiagnostic(errors: ReadonlyArray<Diagnostic> | ReadonlyArray<string>) {
|
||||
return errors.length === 1
|
||||
? createCompilerDiagnostic(Diagnostics.Found_1_error_Watching_for_file_changes)
|
||||
: createCompilerDiagnostic(Diagnostics.Found_0_errors_Watching_for_file_changes, errors.length);
|
||||
}
|
||||
|
||||
export function checkOutputErrorsInitial(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, disableConsoleClears?: boolean, logsBeforeErrors?: string[]) {
|
||||
export function checkOutputErrorsInitial(host: WatchedSystem, errors: ReadonlyArray<Diagnostic> | ReadonlyArray<string>, disableConsoleClears?: boolean, logsBeforeErrors?: string[]) {
|
||||
checkOutputErrors(
|
||||
host,
|
||||
/*logsBeforeWatchDiagnostic*/ undefined,
|
||||
@@ -147,7 +151,7 @@ namespace ts.tscWatch {
|
||||
createErrorsFoundCompilerDiagnostic(errors));
|
||||
}
|
||||
|
||||
export function checkOutputErrorsIncremental(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) {
|
||||
export function checkOutputErrorsIncremental(host: WatchedSystem, errors: ReadonlyArray<Diagnostic> | ReadonlyArray<string>, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) {
|
||||
checkOutputErrors(
|
||||
host,
|
||||
logsBeforeWatchDiagnostic,
|
||||
@@ -158,7 +162,7 @@ namespace ts.tscWatch {
|
||||
createErrorsFoundCompilerDiagnostic(errors));
|
||||
}
|
||||
|
||||
function checkOutputErrorsIncrementalWithExit(host: WatchedSystem, errors: ReadonlyArray<Diagnostic>, expectedExitCode: ExitStatus, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) {
|
||||
function checkOutputErrorsIncrementalWithExit(host: WatchedSystem, errors: ReadonlyArray<Diagnostic> | ReadonlyArray<string>, expectedExitCode: ExitStatus, disableConsoleClears?: boolean, logsBeforeWatchDiagnostic?: string[], logsBeforeErrors?: string[]) {
|
||||
checkOutputErrors(
|
||||
host,
|
||||
logsBeforeWatchDiagnostic,
|
||||
|
||||
@@ -61,6 +61,19 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function assertParseFileDiagnosticsExclusion(jsonText: string, configFileName: string, basePath: string, allFileList: string[], expectedExcludedDiagnosticCode: number) {
|
||||
{
|
||||
const parsed = getParsedCommandJson(jsonText, configFileName, basePath, allFileList);
|
||||
assert.isTrue(parsed.errors.length >= 0);
|
||||
assert.isTrue(parsed.errors.findIndex(e => e.code === expectedExcludedDiagnosticCode) === -1, `Expected error code ${expectedExcludedDiagnosticCode} to not be in ${JSON.stringify(parsed.errors)}`);
|
||||
}
|
||||
{
|
||||
const parsed = getParsedCommandJsonNode(jsonText, configFileName, basePath, allFileList);
|
||||
assert.isTrue(parsed.errors.length >= 0);
|
||||
assert.isTrue(parsed.errors.findIndex(e => e.code === expectedExcludedDiagnosticCode) === -1, `Expected error code ${expectedExcludedDiagnosticCode} to not be in ${JSON.stringify(parsed.errors)}`);
|
||||
}
|
||||
}
|
||||
|
||||
it("returns empty config for file with only whitespaces", () => {
|
||||
assertParseResult("", { config : {} });
|
||||
assertParseResult(" ", { config : {} });
|
||||
@@ -280,6 +293,30 @@ namespace ts {
|
||||
Diagnostics.The_files_list_in_config_file_0_is_empty.code);
|
||||
});
|
||||
|
||||
it("generates errors for empty files list when no references are provided", () => {
|
||||
const content = `{
|
||||
"files": [],
|
||||
"references": []
|
||||
}`;
|
||||
assertParseFileDiagnostics(content,
|
||||
"/apath/tsconfig.json",
|
||||
"tests/cases/unittests",
|
||||
["/apath/a.ts"],
|
||||
Diagnostics.The_files_list_in_config_file_0_is_empty.code);
|
||||
});
|
||||
|
||||
it("does not generate errors for empty files list when one or more references are provided", () => {
|
||||
const content = `{
|
||||
"files": [],
|
||||
"references": [{ "path": "/apath" }]
|
||||
}`;
|
||||
assertParseFileDiagnosticsExclusion(content,
|
||||
"/apath/tsconfig.json",
|
||||
"tests/cases/unittests",
|
||||
["/apath/a.ts"],
|
||||
Diagnostics.The_files_list_in_config_file_0_is_empty.code);
|
||||
});
|
||||
|
||||
it("generates errors for directory with no .ts files", () => {
|
||||
const content = `{
|
||||
}`;
|
||||
|
||||
@@ -3136,7 +3136,7 @@ namespace ts.projectSystem {
|
||||
const project = projectService.configuredProjects.get(configFile.path)!;
|
||||
assert.isDefined(project);
|
||||
checkProjectActualFiles(project, [file1.path, libFile.path, module1.path, module2.path, configFile.path]);
|
||||
checkWatchedFiles(host, [libFile.path, module1.path, module2.path, configFile.path]);
|
||||
checkWatchedFiles(host, [libFile.path, configFile.path]);
|
||||
checkWatchedDirectories(host, [], /*recursive*/ false);
|
||||
const watchedRecursiveDirectories = getTypeRootsFromLocation(root + "/a/b/src");
|
||||
watchedRecursiveDirectories.push(`${root}/a/b/src/node_modules`, `${root}/a/b/node_modules`);
|
||||
@@ -3204,7 +3204,7 @@ namespace ts.projectSystem {
|
||||
{ text: "number", kind: "keyword" }
|
||||
],
|
||||
documentation: [],
|
||||
tags: []
|
||||
tags: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7435,7 +7435,7 @@ namespace ts.projectSystem {
|
||||
const projectFilePaths = map(projectFiles, f => f.path);
|
||||
checkProjectActualFiles(project, projectFilePaths);
|
||||
|
||||
const filesWatched = filter(projectFilePaths, p => p !== app.path);
|
||||
const filesWatched = filter(projectFilePaths, p => p !== app.path && p.indexOf("/a/b/node_modules") === -1);
|
||||
checkWatchedFiles(host, filesWatched);
|
||||
checkWatchedDirectories(host, typeRootDirectories.concat(recursiveWatchedDirectories), /*recursive*/ true);
|
||||
checkWatchedDirectories(host, [], /*recursive*/ false);
|
||||
@@ -8658,10 +8658,21 @@ new C();`
|
||||
}
|
||||
|
||||
function verifyWatchesWithConfigFile(host: TestServerHost, files: File[], openFile: File, extraExpectedDirectories?: ReadonlyArray<string>) {
|
||||
checkWatchedFiles(host, mapDefined(files, f => f === openFile ? undefined : f.path));
|
||||
const expectedRecursiveDirectories = arrayToSet([projectLocation, `${projectLocation}/${nodeModulesAtTypes}`, ...(extraExpectedDirectories || emptyArray)]);
|
||||
checkWatchedFiles(host, mapDefined(files, f => {
|
||||
if (f === openFile) {
|
||||
return undefined;
|
||||
}
|
||||
const indexOfNodeModules = f.path.indexOf("/node_modules/");
|
||||
if (indexOfNodeModules === -1) {
|
||||
return f.path;
|
||||
}
|
||||
expectedRecursiveDirectories.set(f.path.substr(0, indexOfNodeModules + "/node_modules".length), true);
|
||||
return undefined;
|
||||
}));
|
||||
checkWatchedDirectories(host, [], /*recursive*/ false);
|
||||
checkWatchedDirectories(host, [projectLocation, `${projectLocation}/${nodeModulesAtTypes}`, ...(extraExpectedDirectories || emptyArray)], /*recursive*/ true);
|
||||
}
|
||||
checkWatchedDirectories(host, arrayFrom(expectedRecursiveDirectories.keys()), /*recursive*/ true);
|
||||
}
|
||||
|
||||
describe("from files in same folder", () => {
|
||||
function getFiles(fileContent: string) {
|
||||
@@ -8862,7 +8873,7 @@ new C();`
|
||||
verifyTrace(resolutionTrace, expectedTrace);
|
||||
|
||||
const currentDirectory = getDirectoryPath(file1.path);
|
||||
const watchedFiles = mapDefined(files, f => f === file1 ? undefined : f.path);
|
||||
const watchedFiles = mapDefined(files, f => f === file1 || f.path.indexOf("/node_modules/") !== -1 ? undefined : f.path);
|
||||
forEachAncestorDirectory(currentDirectory, d => {
|
||||
watchedFiles.push(combinePaths(d, "tsconfig.json"), combinePaths(d, "jsconfig.json"));
|
||||
});
|
||||
@@ -9501,7 +9512,7 @@ export function Test2() {
|
||||
kindModifiers: ScriptElementKindModifier.exportedModifier,
|
||||
name: "foo",
|
||||
source: [{ text: "./a", kind: "text" }],
|
||||
tags: emptyArray,
|
||||
tags: undefined,
|
||||
};
|
||||
assert.deepEqual<ReadonlyArray<protocol.CompletionEntryDetails> | undefined>(detailsResponse, [
|
||||
{
|
||||
@@ -9555,6 +9566,65 @@ export function Test2() {
|
||||
});
|
||||
});
|
||||
|
||||
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",
|
||||
|
||||
@@ -1322,7 +1322,7 @@ namespace ts.projectSystem {
|
||||
content: ""
|
||||
};
|
||||
const host = createServerHost([f, node]);
|
||||
const cache = createMapFromTemplate<JsTyping.CachedTyping>({ node: { typingLocation: node.path, version: Semver.parse("1.3.0") } });
|
||||
const cache = createMapFromTemplate<JsTyping.CachedTyping>({ node: { typingLocation: node.path, version: new Version("1.3.0") } });
|
||||
const registry = createTypesRegistry("node");
|
||||
const logger = trackingLogger();
|
||||
const result = JsTyping.discoverTypings(host, logger.log, [f.path], getDirectoryPath(<Path>f.path), emptySafeList, cache, { enable: true }, ["fs", "bar"], registry);
|
||||
@@ -1344,7 +1344,7 @@ namespace ts.projectSystem {
|
||||
content: ""
|
||||
};
|
||||
const host = createServerHost([f, node]);
|
||||
const cache = createMapFromTemplate<JsTyping.CachedTyping>({ node: { typingLocation: node.path, version: Semver.parse("1.3.0") } });
|
||||
const cache = createMapFromTemplate<JsTyping.CachedTyping>({ node: { typingLocation: node.path, version: new Version("1.3.0") } });
|
||||
const logger = trackingLogger();
|
||||
const result = JsTyping.discoverTypings(host, logger.log, [f.path], getDirectoryPath(<Path>f.path), emptySafeList, cache, { enable: true }, ["fs", "bar"], emptyMap);
|
||||
assert.deepEqual(logger.finish(), [
|
||||
@@ -1401,8 +1401,8 @@ namespace ts.projectSystem {
|
||||
};
|
||||
const host = createServerHost([app]);
|
||||
const cache = createMapFromTemplate<JsTyping.CachedTyping>({
|
||||
node: { typingLocation: node.path, version: Semver.parse("1.3.0") },
|
||||
commander: { typingLocation: commander.path, version: Semver.parse("1.0.0") }
|
||||
node: { typingLocation: node.path, version: new Version("1.3.0") },
|
||||
commander: { typingLocation: commander.path, version: new Version("1.0.0") }
|
||||
});
|
||||
const registry = createTypesRegistry("node", "commander");
|
||||
const logger = trackingLogger();
|
||||
@@ -1427,7 +1427,7 @@ namespace ts.projectSystem {
|
||||
};
|
||||
const host = createServerHost([app]);
|
||||
const cache = createMapFromTemplate<JsTyping.CachedTyping>({
|
||||
node: { typingLocation: node.path, version: Semver.parse("1.0.0") }
|
||||
node: { typingLocation: node.path, version: new Version("1.0.0") }
|
||||
});
|
||||
const registry = createTypesRegistry("node");
|
||||
registry.delete(`ts${versionMajorMinor}`);
|
||||
@@ -1458,8 +1458,8 @@ namespace ts.projectSystem {
|
||||
};
|
||||
const host = createServerHost([app]);
|
||||
const cache = createMapFromTemplate<JsTyping.CachedTyping>({
|
||||
node: { typingLocation: node.path, version: Semver.parse("1.3.0-next.0") },
|
||||
commander: { typingLocation: commander.path, version: Semver.parse("1.3.0-next.0") }
|
||||
node: { typingLocation: node.path, version: new Version("1.3.0-next.0") },
|
||||
commander: { typingLocation: commander.path, version: new Version("1.3.0-next.0") }
|
||||
});
|
||||
const registry = createTypesRegistry("node", "commander");
|
||||
registry.get("node")![`ts${versionMajorMinor}`] = "1.3.0-next.1";
|
||||
|
||||
+15
-30
@@ -53,14 +53,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function executeCommandLine(args: string[]): void {
|
||||
if (args.length > 0 && ((args[0].toLowerCase() === "--build") || (args[0].toLowerCase() === "-b"))) {
|
||||
const result = performBuild(args.slice(1));
|
||||
// undefined = in watch mode, do not exit
|
||||
if (result !== undefined) {
|
||||
return sys.exit(result);
|
||||
}
|
||||
else {
|
||||
return;
|
||||
if (args.length > 0 && args[0].charCodeAt(0) === CharacterCodes.minus) {
|
||||
const firstOption = args[0].slice(args[0].charCodeAt(1) === CharacterCodes.minus ? 2 : 1).toLowerCase();
|
||||
if (firstOption === "build" || firstOption === "b") {
|
||||
return performBuild(args.slice(1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,40 +160,30 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function performBuild(args: string[]): number | undefined {
|
||||
const { buildOptions, projects: buildProjects, errors } = parseBuildCommand(args);
|
||||
function performBuild(args: string[]) {
|
||||
const { buildOptions, projects, errors } = parseBuildCommand(args);
|
||||
if (errors.length > 0) {
|
||||
errors.forEach(reportDiagnostic);
|
||||
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
|
||||
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
|
||||
}
|
||||
|
||||
if (buildOptions.help) {
|
||||
printVersion();
|
||||
printHelp(buildOpts, "--build ");
|
||||
return ExitStatus.Success;
|
||||
return sys.exit(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;
|
||||
return sys.exit(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;
|
||||
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
|
||||
}
|
||||
if (buildOptions.watch) {
|
||||
reportWatchModeWithoutSysSupport();
|
||||
@@ -206,16 +192,15 @@ namespace ts {
|
||||
// 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();
|
||||
return sys.exit(builder.cleanAllProjects());
|
||||
}
|
||||
|
||||
if (buildOptions.watch) {
|
||||
builder.buildAllProjects();
|
||||
builder.startWatching();
|
||||
return undefined;
|
||||
return builder.startWatching();
|
||||
}
|
||||
|
||||
return builder.buildAllProjects();
|
||||
return sys.exit(builder.buildAllProjects());
|
||||
}
|
||||
|
||||
function performCompilation(rootNames: string[], projectReferences: ReadonlyArray<ProjectReference> | undefined, options: CompilerOptions, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) {
|
||||
@@ -237,12 +222,12 @@ namespace ts {
|
||||
|
||||
function updateWatchCompilationHost(watchCompilerHost: WatchCompilerHost<EmitAndSemanticDiagnosticsBuilderProgram>) {
|
||||
const compileUsingBuilder = watchCompilerHost.createProgram;
|
||||
watchCompilerHost.createProgram = (rootNames, options, host, oldProgram, configFileParsingDiagnostics) => {
|
||||
watchCompilerHost.createProgram = (rootNames, options, host, oldProgram, configFileParsingDiagnostics, projectReferences) => {
|
||||
Debug.assert(rootNames !== undefined || (options === undefined && !!oldProgram));
|
||||
if (options !== undefined) {
|
||||
enableStatistics(options);
|
||||
}
|
||||
return compileUsingBuilder(rootNames, options, host, oldProgram, configFileParsingDiagnostics);
|
||||
return compileUsingBuilder(rootNames, options, host, oldProgram, configFileParsingDiagnostics, projectReferences);
|
||||
};
|
||||
const emitFilesUsingBuilder = watchCompilerHost.afterProgramCreate!; // TODO: GH#18217
|
||||
watchCompilerHost.afterProgramCreate = builderProgram => {
|
||||
|
||||
@@ -891,7 +891,7 @@ namespace ts.server {
|
||||
|
||||
sys.require = (initialDir: string, moduleName: string): RequireResult => {
|
||||
try {
|
||||
return { module: require(resolveJavaScriptModule(moduleName, initialDir, sys)), error: undefined };
|
||||
return { module: require(resolveJSModule(moduleName, initialDir, sys)), error: undefined };
|
||||
}
|
||||
catch (error) {
|
||||
return { module: undefined, error };
|
||||
@@ -924,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> {
|
||||
|
||||
@@ -252,8 +252,11 @@ namespace ts.server.typingsInstaller {
|
||||
}
|
||||
const info = getProperty(npmLock.dependencies, key);
|
||||
const version = info && info.version;
|
||||
const semver = Semver.parse(version!); // TODO: GH#18217
|
||||
const newTyping: JsTyping.CachedTyping = { typingLocation: typingFile, version: semver };
|
||||
if (!version) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const newTyping: JsTyping.CachedTyping = { typingLocation: typingFile, version: new Version(version) };
|
||||
this.packageNameToTypingLocation.set(packageName, newTyping);
|
||||
}
|
||||
}
|
||||
@@ -356,7 +359,7 @@ namespace ts.server.typingsInstaller {
|
||||
|
||||
// packageName is guaranteed to exist in typesRegistry by filterTypings
|
||||
const distTags = this.typesRegistry.get(packageName)!;
|
||||
const newVersion = Semver.parse(distTags[`ts${versionMajorMinor}`] || distTags[this.latestDistTag]);
|
||||
const newVersion = new Version(distTags[`ts${versionMajorMinor}`] || distTags[this.latestDistTag]);
|
||||
const newTyping: JsTyping.CachedTyping = { typingLocation: typingFile, version: newVersion };
|
||||
this.packageNameToTypingLocation.set(packageName, newTyping);
|
||||
installedTypingFiles.push(typingFile);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
tests/cases/conformance/statements/for-ofStatements/ES5For-ofTypeCheck10.ts(9,6): error TS2693: 'Symbol' only refers to a type, but is being used as a value here.
|
||||
tests/cases/conformance/statements/for-ofStatements/ES5For-ofTypeCheck10.ts(9,6): error TS2585: 'Symbol' only refers to a type, but is being used as a value here. Do you need to change your target library? Try changing the `lib` compiler option to es2015 or later.
|
||||
tests/cases/conformance/statements/for-ofStatements/ES5For-ofTypeCheck10.ts(14,15): error TS2569: Type 'StringIterator' is not an array type or a string type. Use compiler option '--downlevelIteration' to allow iterating of iterators.
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ tests/cases/conformance/statements/for-ofStatements/ES5For-ofTypeCheck10.ts(14,1
|
||||
}
|
||||
[Symbol.iterator]() {
|
||||
~~~~~~
|
||||
!!! error TS2693: 'Symbol' only refers to a type, but is being used as a value here.
|
||||
!!! error TS2585: 'Symbol' only refers to a type, but is being used as a value here. Do you need to change your target library? Try changing the `lib` compiler option to es2015 or later.
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
tests/cases/conformance/Symbols/ES5SymbolProperty2.ts(5,10): error TS2471: A computed property name of the form 'Symbol.iterator' must be of type 'symbol'.
|
||||
tests/cases/conformance/Symbols/ES5SymbolProperty2.ts(10,11): error TS2693: 'Symbol' only refers to a type, but is being used as a value here.
|
||||
tests/cases/conformance/Symbols/ES5SymbolProperty2.ts(10,11): error TS2585: 'Symbol' only refers to a type, but is being used as a value here. Do you need to change your target library? Try changing the `lib` compiler option to es2015 or later.
|
||||
|
||||
|
||||
==== tests/cases/conformance/Symbols/ES5SymbolProperty2.ts (2 errors) ====
|
||||
@@ -16,4 +16,4 @@ tests/cases/conformance/Symbols/ES5SymbolProperty2.ts(10,11): error TS2693: 'Sym
|
||||
|
||||
(new M.C)[Symbol.iterator];
|
||||
~~~~~~
|
||||
!!! error TS2693: 'Symbol' only refers to a type, but is being used as a value here.
|
||||
!!! error TS2585: 'Symbol' only refers to a type, but is being used as a value here. Do you need to change your target library? Try changing the `lib` compiler option to es2015 or later.
|
||||
@@ -1,14 +1,14 @@
|
||||
tests/cases/conformance/Symbols/ES5SymbolProperty6.ts(2,6): error TS2693: 'Symbol' only refers to a type, but is being used as a value here.
|
||||
tests/cases/conformance/Symbols/ES5SymbolProperty6.ts(5,9): error TS2693: 'Symbol' only refers to a type, but is being used as a value here.
|
||||
tests/cases/conformance/Symbols/ES5SymbolProperty6.ts(2,6): error TS2585: 'Symbol' only refers to a type, but is being used as a value here. Do you need to change your target library? Try changing the `lib` compiler option to es2015 or later.
|
||||
tests/cases/conformance/Symbols/ES5SymbolProperty6.ts(5,9): error TS2585: 'Symbol' only refers to a type, but is being used as a value here. Do you need to change your target library? Try changing the `lib` compiler option to es2015 or later.
|
||||
|
||||
|
||||
==== tests/cases/conformance/Symbols/ES5SymbolProperty6.ts (2 errors) ====
|
||||
class C {
|
||||
[Symbol.iterator]() { }
|
||||
~~~~~~
|
||||
!!! error TS2693: 'Symbol' only refers to a type, but is being used as a value here.
|
||||
!!! error TS2585: 'Symbol' only refers to a type, but is being used as a value here. Do you need to change your target library? Try changing the `lib` compiler option to es2015 or later.
|
||||
}
|
||||
|
||||
(new C)[Symbol.iterator]
|
||||
~~~~~~
|
||||
!!! error TS2693: 'Symbol' only refers to a type, but is being used as a value here.
|
||||
!!! error TS2585: 'Symbol' only refers to a type, but is being used as a value here. Do you need to change your target library? Try changing the `lib` compiler option to es2015 or later.
|
||||
@@ -6,7 +6,7 @@
|
||||
"0": {
|
||||
"kind": "JSDocTag",
|
||||
"pos": 63,
|
||||
"end": 68,
|
||||
"end": 67,
|
||||
"atToken": {
|
||||
"kind": "AtToken",
|
||||
"pos": 63,
|
||||
@@ -22,7 +22,7 @@
|
||||
},
|
||||
"length": 1,
|
||||
"pos": 63,
|
||||
"end": 68
|
||||
"end": 67
|
||||
},
|
||||
"comment": "{@link first link}\nInside {@link link text} thing"
|
||||
}
|
||||
+1
-1
@@ -30,7 +30,7 @@
|
||||
{
|
||||
"kind": "JSDocParameterTag",
|
||||
"pos": 34,
|
||||
"end": 54,
|
||||
"end": 64,
|
||||
"atToken": {
|
||||
"kind": "AtToken",
|
||||
"pos": 34,
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"typeParameters": {
|
||||
"0": {
|
||||
"kind": "TypeParameter",
|
||||
"pos": 18,
|
||||
"pos": 17,
|
||||
"end": 19,
|
||||
"name": {
|
||||
"kind": "Identifier",
|
||||
@@ -31,7 +31,7 @@
|
||||
}
|
||||
},
|
||||
"length": 1,
|
||||
"pos": 18,
|
||||
"pos": 17,
|
||||
"end": 19
|
||||
}
|
||||
},
|
||||
|
||||
+2
-2
@@ -21,7 +21,7 @@
|
||||
"typeParameters": {
|
||||
"0": {
|
||||
"kind": "TypeParameter",
|
||||
"pos": 18,
|
||||
"pos": 17,
|
||||
"end": 19,
|
||||
"name": {
|
||||
"kind": "Identifier",
|
||||
@@ -42,7 +42,7 @@
|
||||
}
|
||||
},
|
||||
"length": 2,
|
||||
"pos": 18,
|
||||
"pos": 17,
|
||||
"end": 21
|
||||
}
|
||||
},
|
||||
|
||||
+2
-2
@@ -21,7 +21,7 @@
|
||||
"typeParameters": {
|
||||
"0": {
|
||||
"kind": "TypeParameter",
|
||||
"pos": 18,
|
||||
"pos": 17,
|
||||
"end": 19,
|
||||
"name": {
|
||||
"kind": "Identifier",
|
||||
@@ -42,7 +42,7 @@
|
||||
}
|
||||
},
|
||||
"length": 2,
|
||||
"pos": 18,
|
||||
"pos": 17,
|
||||
"end": 22
|
||||
}
|
||||
},
|
||||
|
||||
+2
-2
@@ -21,7 +21,7 @@
|
||||
"typeParameters": {
|
||||
"0": {
|
||||
"kind": "TypeParameter",
|
||||
"pos": 18,
|
||||
"pos": 17,
|
||||
"end": 19,
|
||||
"name": {
|
||||
"kind": "Identifier",
|
||||
@@ -42,7 +42,7 @@
|
||||
}
|
||||
},
|
||||
"length": 2,
|
||||
"pos": 18,
|
||||
"pos": 17,
|
||||
"end": 22
|
||||
}
|
||||
},
|
||||
|
||||
+2
-2
@@ -21,7 +21,7 @@
|
||||
"typeParameters": {
|
||||
"0": {
|
||||
"kind": "TypeParameter",
|
||||
"pos": 18,
|
||||
"pos": 17,
|
||||
"end": 19,
|
||||
"name": {
|
||||
"kind": "Identifier",
|
||||
@@ -42,7 +42,7 @@
|
||||
}
|
||||
},
|
||||
"length": 2,
|
||||
"pos": 18,
|
||||
"pos": 17,
|
||||
"end": 23
|
||||
}
|
||||
},
|
||||
|
||||
+2
-2
@@ -21,7 +21,7 @@
|
||||
"typeParameters": {
|
||||
"0": {
|
||||
"kind": "TypeParameter",
|
||||
"pos": 18,
|
||||
"pos": 17,
|
||||
"end": 19,
|
||||
"name": {
|
||||
"kind": "Identifier",
|
||||
@@ -42,7 +42,7 @@
|
||||
}
|
||||
},
|
||||
"length": 2,
|
||||
"pos": 18,
|
||||
"pos": 17,
|
||||
"end": 24
|
||||
},
|
||||
"comment": "Description of type parameters."
|
||||
|
||||
+2
-2
@@ -38,7 +38,7 @@
|
||||
{
|
||||
"kind": "JSDocPropertyTag",
|
||||
"pos": 47,
|
||||
"end": 72,
|
||||
"end": 74,
|
||||
"atToken": {
|
||||
"kind": "AtToken",
|
||||
"pos": 47,
|
||||
@@ -72,7 +72,7 @@
|
||||
{
|
||||
"kind": "JSDocPropertyTag",
|
||||
"pos": 74,
|
||||
"end": 97,
|
||||
"end": 100,
|
||||
"atToken": {
|
||||
"kind": "AtToken",
|
||||
"pos": 74,
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ function f<T>(x: T): T {
|
||||
return x;
|
||||
}
|
||||
|
||||
enum E { A, B, C }
|
||||
enum E { A, B, C, "non identifier" }
|
||||
|
||||
const c1 = "abc";
|
||||
const c2 = 123;
|
||||
@@ -13,6 +13,7 @@ const c5 = f(123);
|
||||
const c6 = f(-123);
|
||||
const c7 = true;
|
||||
const c8 = E.A;
|
||||
const c8b = E["non identifier"];
|
||||
const c9 = { x: "abc" };
|
||||
const c10 = [123];
|
||||
const c11 = "abc" + "def";
|
||||
@@ -29,6 +30,7 @@ var E;
|
||||
E[E["A"] = 0] = "A";
|
||||
E[E["B"] = 1] = "B";
|
||||
E[E["C"] = 2] = "C";
|
||||
E[E["non identifier"] = 3] = "non identifier";
|
||||
})(E || (E = {}));
|
||||
var c1 = "abc";
|
||||
var c2 = 123;
|
||||
@@ -38,6 +40,7 @@ var c5 = f(123);
|
||||
var c6 = f(-123);
|
||||
var c7 = true;
|
||||
var c8 = E.A;
|
||||
var c8b = E["non identifier"];
|
||||
var c9 = { x: "abc" };
|
||||
var c10 = [123];
|
||||
var c11 = "abc" + "def";
|
||||
@@ -51,7 +54,8 @@ declare function f<T>(x: T): T;
|
||||
declare enum E {
|
||||
A = 0,
|
||||
B = 1,
|
||||
C = 2
|
||||
C = 2,
|
||||
"non identifier" = 3
|
||||
}
|
||||
declare const c1 = "abc";
|
||||
declare const c2 = 123;
|
||||
@@ -59,8 +63,9 @@ declare const c3 = "abc";
|
||||
declare const c4 = 123;
|
||||
declare const c5 = 123;
|
||||
declare const c6 = -123;
|
||||
declare const c7: boolean;
|
||||
declare const c8: E;
|
||||
declare const c7 = true;
|
||||
declare const c8 = E.A;
|
||||
declare const c8b = E["non identifier"];
|
||||
declare const c9: {
|
||||
x: string;
|
||||
};
|
||||
|
||||
@@ -10,11 +10,12 @@ function f<T>(x: T): T {
|
||||
>x : Symbol(x, Decl(ambientConstLiterals.ts, 0, 14))
|
||||
}
|
||||
|
||||
enum E { A, B, C }
|
||||
enum E { A, B, C, "non identifier" }
|
||||
>E : Symbol(E, Decl(ambientConstLiterals.ts, 2, 1))
|
||||
>A : Symbol(E.A, Decl(ambientConstLiterals.ts, 4, 8))
|
||||
>B : Symbol(E.B, Decl(ambientConstLiterals.ts, 4, 11))
|
||||
>C : Symbol(E.C, Decl(ambientConstLiterals.ts, 4, 14))
|
||||
>"non identifier" : Symbol(E["non identifier"], Decl(ambientConstLiterals.ts, 4, 17))
|
||||
|
||||
const c1 = "abc";
|
||||
>c1 : Symbol(c1, Decl(ambientConstLiterals.ts, 6, 5))
|
||||
@@ -47,27 +48,32 @@ const c8 = E.A;
|
||||
>E : Symbol(E, Decl(ambientConstLiterals.ts, 2, 1))
|
||||
>A : Symbol(E.A, Decl(ambientConstLiterals.ts, 4, 8))
|
||||
|
||||
const c8b = E["non identifier"];
|
||||
>c8b : Symbol(c8b, Decl(ambientConstLiterals.ts, 14, 5))
|
||||
>E : Symbol(E, Decl(ambientConstLiterals.ts, 2, 1))
|
||||
>"non identifier" : Symbol(E["non identifier"], Decl(ambientConstLiterals.ts, 4, 17))
|
||||
|
||||
const c9 = { x: "abc" };
|
||||
>c9 : Symbol(c9, Decl(ambientConstLiterals.ts, 14, 5))
|
||||
>x : Symbol(x, Decl(ambientConstLiterals.ts, 14, 12))
|
||||
>c9 : Symbol(c9, Decl(ambientConstLiterals.ts, 15, 5))
|
||||
>x : Symbol(x, Decl(ambientConstLiterals.ts, 15, 12))
|
||||
|
||||
const c10 = [123];
|
||||
>c10 : Symbol(c10, Decl(ambientConstLiterals.ts, 15, 5))
|
||||
>c10 : Symbol(c10, Decl(ambientConstLiterals.ts, 16, 5))
|
||||
|
||||
const c11 = "abc" + "def";
|
||||
>c11 : Symbol(c11, Decl(ambientConstLiterals.ts, 16, 5))
|
||||
>c11 : Symbol(c11, Decl(ambientConstLiterals.ts, 17, 5))
|
||||
|
||||
const c12 = 123 + 456;
|
||||
>c12 : Symbol(c12, Decl(ambientConstLiterals.ts, 17, 5))
|
||||
>c12 : Symbol(c12, Decl(ambientConstLiterals.ts, 18, 5))
|
||||
|
||||
const c13 = Math.random() > 0.5 ? "abc" : "def";
|
||||
>c13 : Symbol(c13, Decl(ambientConstLiterals.ts, 18, 5))
|
||||
>c13 : Symbol(c13, Decl(ambientConstLiterals.ts, 19, 5))
|
||||
>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
|
||||
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
const c14 = Math.random() > 0.5 ? 123 : 456;
|
||||
>c14 : Symbol(c14, Decl(ambientConstLiterals.ts, 19, 5))
|
||||
>c14 : Symbol(c14, Decl(ambientConstLiterals.ts, 20, 5))
|
||||
>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
|
||||
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
@@ -7,11 +7,12 @@ function f<T>(x: T): T {
|
||||
>x : T
|
||||
}
|
||||
|
||||
enum E { A, B, C }
|
||||
enum E { A, B, C, "non identifier" }
|
||||
>E : E
|
||||
>A : E.A
|
||||
>B : E.B
|
||||
>C : E.C
|
||||
>"non identifier" : E.non identifier
|
||||
|
||||
const c1 = "abc";
|
||||
>c1 : "abc"
|
||||
@@ -52,6 +53,12 @@ const c8 = E.A;
|
||||
>E : typeof E
|
||||
>A : E.A
|
||||
|
||||
const c8b = E["non identifier"];
|
||||
>c8b : E.non identifier
|
||||
>E["non identifier"] : E.non identifier
|
||||
>E : typeof E
|
||||
>"non identifier" : "non identifier"
|
||||
|
||||
const c9 = { x: "abc" };
|
||||
>c9 : { x: string; }
|
||||
>{ x: "abc" } : { x: string; }
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
>E1 : E1
|
||||
|
||||
y = 4.23
|
||||
>y : E1
|
||||
>y : E1.y
|
||||
>4.23 : 4.23
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,6 @@ declare enum E {
|
||||
>E : E
|
||||
|
||||
e = 3
|
||||
>e : E
|
||||
>e : E.e
|
||||
>3 : 3
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user