mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' into tsbuild
This commit is contained in:
+52
-31
@@ -1698,6 +1698,7 @@ namespace ts {
|
||||
symbol.parent = container.symbol;
|
||||
}
|
||||
addDeclarationToSymbol(symbol, node, symbolFlags);
|
||||
return symbol;
|
||||
}
|
||||
|
||||
function bindBlockScopedDeclaration(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags) {
|
||||
@@ -2317,13 +2318,11 @@ namespace ts {
|
||||
// expression is the declaration
|
||||
setCommonJsModuleIndicator(node);
|
||||
const lhs = node.left as PropertyAccessEntityNameExpression;
|
||||
const symbol = forEachIdentifierInEntityName(lhs.expression, (id, original) => {
|
||||
if (!original) {
|
||||
return undefined;
|
||||
const symbol = forEachIdentifierInEntityName(lhs.expression, /*parent*/ undefined, (id, symbol) => {
|
||||
if (symbol) {
|
||||
addDeclarationToSymbol(symbol, id, SymbolFlags.Module | SymbolFlags.JSContainer);
|
||||
}
|
||||
const s = getJSInitializerSymbol(original)!;
|
||||
addDeclarationToSymbol(s, id, SymbolFlags.Module | SymbolFlags.JSContainer);
|
||||
return s;
|
||||
return symbol;
|
||||
});
|
||||
if (symbol) {
|
||||
const flags = isClassExpression(node.right) ?
|
||||
@@ -2359,12 +2358,12 @@ namespace ts {
|
||||
switch (thisContainer.kind) {
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
let constructorSymbol = thisContainer.symbol;
|
||||
let constructorSymbol: Symbol | undefined = thisContainer.symbol;
|
||||
// For `f.prototype.m = function() { this.x = 0; }`, `this.x = 0` should modify `f`'s members, not the function expression.
|
||||
if (isBinaryExpression(thisContainer.parent) && thisContainer.parent.operatorToken.kind === SyntaxKind.EqualsToken) {
|
||||
const l = thisContainer.parent.left;
|
||||
if (isPropertyAccessEntityNameExpression(l) && isPrototypeAccess(l.expression)) {
|
||||
constructorSymbol = getJSInitializerSymbolFromName(l.expression.expression, thisParentContainer)!;
|
||||
constructorSymbol = lookupSymbolForPropertyAccess(l.expression.expression, thisParentContainer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2463,46 +2462,68 @@ namespace ts {
|
||||
bindPropertyAssignment(node.expression, node, /*isPrototypeProperty*/ false);
|
||||
}
|
||||
|
||||
function getJSInitializerSymbolFromName(name: EntityNameExpression, lookupContainer?: Node): Symbol | undefined {
|
||||
return getJSInitializerSymbol(lookupSymbolForPropertyAccess(name, lookupContainer));
|
||||
}
|
||||
|
||||
function bindPropertyAssignment(name: EntityNameExpression, propertyAccess: PropertyAccessEntityNameExpression, isPrototypeProperty: boolean) {
|
||||
let symbol = getJSInitializerSymbolFromName(name);
|
||||
let namespaceSymbol = lookupSymbolForPropertyAccess(name);
|
||||
const isToplevelNamespaceableInitializer = isBinaryExpression(propertyAccess.parent)
|
||||
? getParentOfBinaryExpression(propertyAccess.parent).parent.kind === SyntaxKind.SourceFile &&
|
||||
!!getJavascriptInitializer(getInitializerOfBinaryExpression(propertyAccess.parent), isPrototypeAccess(propertyAccess.parent.left))
|
||||
: propertyAccess.parent.parent.kind === SyntaxKind.SourceFile;
|
||||
if (!isPrototypeProperty && (!symbol || !(symbol.flags & SymbolFlags.Namespace)) && isToplevelNamespaceableInitializer) {
|
||||
if (!isPrototypeProperty && (!namespaceSymbol || !(namespaceSymbol.flags & SymbolFlags.Namespace)) && isToplevelNamespaceableInitializer) {
|
||||
// make symbols or add declarations for intermediate containers
|
||||
const flags = SymbolFlags.Module | SymbolFlags.JSContainer;
|
||||
const excludeFlags = SymbolFlags.ValueModuleExcludes & ~SymbolFlags.JSContainer;
|
||||
forEachIdentifierInEntityName(propertyAccess.expression, (id, original) => {
|
||||
if (original) {
|
||||
// Note: add declaration to original symbol, not the special-syntax's symbol, so that namespaces work for type lookup
|
||||
addDeclarationToSymbol(original, id, flags);
|
||||
return original;
|
||||
namespaceSymbol = forEachIdentifierInEntityName(propertyAccess.expression, namespaceSymbol, (id, symbol, parent) => {
|
||||
if (symbol) {
|
||||
addDeclarationToSymbol(symbol, id, flags);
|
||||
return symbol;
|
||||
}
|
||||
else {
|
||||
return symbol = declareSymbol(symbol ? symbol.exports! : container.locals!, symbol, id, flags, excludeFlags);
|
||||
return declareSymbol(parent ? parent.exports! : container.locals!, parent, id, flags, excludeFlags);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!symbol || !(symbol.flags & (SymbolFlags.Function | SymbolFlags.Class | SymbolFlags.NamespaceModule | SymbolFlags.ObjectLiteral))) {
|
||||
if (!namespaceSymbol || !isJavascriptContainer(namespaceSymbol)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set up the members collection if it doesn't exist already
|
||||
const symbolTable = isPrototypeProperty ?
|
||||
(symbol.members || (symbol.members = createSymbolTable())) :
|
||||
(symbol.exports || (symbol.exports = createSymbolTable()));
|
||||
(namespaceSymbol.members || (namespaceSymbol.members = createSymbolTable())) :
|
||||
(namespaceSymbol.exports || (namespaceSymbol.exports = createSymbolTable()));
|
||||
|
||||
// Declare the method/property
|
||||
const jsContainerFlag = isToplevelNamespaceableInitializer ? SymbolFlags.JSContainer : 0;
|
||||
const isMethod = isFunctionLikeDeclaration(getAssignedJavascriptInitializer(propertyAccess)!); // TODO: GH#18217
|
||||
const isMethod = isFunctionLikeDeclaration(getAssignedJavascriptInitializer(propertyAccess)!);
|
||||
const symbolFlags = (isMethod ? SymbolFlags.Method : SymbolFlags.Property) | jsContainerFlag;
|
||||
const symbolExcludes = (isMethod ? SymbolFlags.MethodExcludes : SymbolFlags.PropertyExcludes) & ~jsContainerFlag;
|
||||
declareSymbol(symbolTable, symbol, propertyAccess, symbolFlags, symbolExcludes);
|
||||
declareSymbol(symbolTable, namespaceSymbol, propertyAccess, symbolFlags, symbolExcludes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Javascript containers are:
|
||||
* - Functions
|
||||
* - classes
|
||||
* - namespaces
|
||||
* - variables initialized with function expressions
|
||||
* - with class expressions
|
||||
* - with empty object literals
|
||||
* - with non-empty object literals if assigned to the prototype property
|
||||
*/
|
||||
function isJavascriptContainer(symbol: Symbol): boolean {
|
||||
if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Class | SymbolFlags.NamespaceModule)) {
|
||||
return true;
|
||||
}
|
||||
const node = symbol.valueDeclaration;
|
||||
const init = !node ? undefined :
|
||||
isVariableDeclaration(node) ? node.initializer :
|
||||
isBinaryExpression(node) ? node.right :
|
||||
isPropertyAccessExpression(node) && isBinaryExpression(node.parent) ? node.parent.right :
|
||||
undefined;
|
||||
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 false;
|
||||
}
|
||||
|
||||
function getParentOfBinaryExpression(expr: BinaryExpression) {
|
||||
@@ -2517,22 +2538,22 @@ namespace ts {
|
||||
return lookupSymbolForNameWorker(lookupContainer, node.escapedText);
|
||||
}
|
||||
else {
|
||||
const symbol = getJSInitializerSymbol(lookupSymbolForPropertyAccess(node.expression));
|
||||
const symbol = lookupSymbolForPropertyAccess(node.expression);
|
||||
return symbol && symbol.exports && symbol.exports.get(node.name.escapedText);
|
||||
}
|
||||
}
|
||||
|
||||
function forEachIdentifierInEntityName(e: EntityNameExpression, action: (e: Identifier, symbol: Symbol | undefined) => Symbol | undefined): Symbol | undefined {
|
||||
function forEachIdentifierInEntityName(e: EntityNameExpression, parent: Symbol | undefined, action: (e: Identifier, symbol: Symbol | undefined, parent: Symbol | undefined) => Symbol | undefined): Symbol | undefined {
|
||||
if (isExportsOrModuleExportsOrAlias(file, e)) {
|
||||
return file.symbol;
|
||||
}
|
||||
else if (isIdentifier(e)) {
|
||||
return action(e, lookupSymbolForPropertyAccess(e));
|
||||
return action(e, lookupSymbolForPropertyAccess(e), parent);
|
||||
}
|
||||
else {
|
||||
const s = getJSInitializerSymbol(forEachIdentifierInEntityName(e.expression, action));
|
||||
const s = forEachIdentifierInEntityName(e.expression, parent, action);
|
||||
if (!s || !s.exports) return Debug.fail();
|
||||
return action(e.name, s.exports.get(e.name.escapedText));
|
||||
return action(e.name, s.exports.get(e.name.escapedText), s);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2596,7 +2617,7 @@ namespace ts {
|
||||
bindBlockScopedVariableDeclaration(node);
|
||||
}
|
||||
else if (isParameterDeclaration(node)) {
|
||||
// It is safe to walk up parent chain to find whether the node is a destructing parameter declaration
|
||||
// It is safe to walk up parent chain to find whether the node is a destructuring parameter declaration
|
||||
// because its parent chain has already been set up, since parents are set before descending into children.
|
||||
//
|
||||
// If node is a binding element in parameter declaration, we need to use ParameterExcludes.
|
||||
|
||||
@@ -549,8 +549,8 @@ 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>, options: CompilerOptions, host?: CompilerHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): SemanticDiagnosticsBuilderProgram;
|
||||
export function createSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | ReadonlyArray<string>, hostOrOptions: BuilderProgramHost | CompilerOptions, oldProgramOrHost?: CompilerHost | SemanticDiagnosticsBuilderProgram, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray<Diagnostic> | SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) {
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -559,8 +559,8 @@ 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>, options: CompilerOptions, host?: CompilerHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): EmitAndSemanticDiagnosticsBuilderProgram;
|
||||
export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | ReadonlyArray<string>, hostOrOptions: BuilderProgramHost | CompilerOptions, oldProgramOrHost?: CompilerHost | EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray<Diagnostic> | EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) {
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -568,8 +568,8 @@ namespace ts {
|
||||
* 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>, options: CompilerOptions, host?: CompilerHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): BuilderProgram;
|
||||
export function createAbstractBuilder(newProgramOrRootNames: Program | ReadonlyArray<string>, hostOrOptions: BuilderProgramHost | CompilerOptions, oldProgramOrHost?: CompilerHost | BuilderProgram, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray<Diagnostic> | 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);
|
||||
return {
|
||||
// Only return program, all other methods are not implemented
|
||||
|
||||
+155
-178
@@ -310,21 +310,34 @@ namespace ts {
|
||||
const node = getParseTreeNode(nodeIn, isTypeNode);
|
||||
return node && getTypeArgumentConstraint(node);
|
||||
},
|
||||
getSuggestionDiagnostics: (file, ct) => {
|
||||
let diagnostics: DiagnosticWithLocation[] | undefined;
|
||||
try {
|
||||
// Record the cancellation token so it can be checked later on during checkSourceElement.
|
||||
// Do this in a finally block so we can ensure that it gets reset back to nothing after
|
||||
// this call is done.
|
||||
cancellationToken = ct;
|
||||
|
||||
getSuggestionDiagnostics: file => {
|
||||
return (suggestionDiagnostics.get(file.fileName) || emptyArray).concat(getUnusedDiagnostics());
|
||||
function getUnusedDiagnostics(): ReadonlyArray<DiagnosticWithLocation> {
|
||||
if (file.isDeclarationFile) return emptyArray;
|
||||
|
||||
// Ensure file is type checked
|
||||
checkSourceFile(file);
|
||||
const diagnostics: DiagnosticWithLocation[] = [];
|
||||
Debug.assert(!!(getNodeLinks(file).flags & NodeCheckFlags.TypeChecked));
|
||||
|
||||
diagnostics = addRange(diagnostics, suggestionDiagnostics.get(file.fileName));
|
||||
if (!file.isDeclarationFile && (!unusedIsError(UnusedKind.Local) || !unusedIsError(UnusedKind.Parameter))) {
|
||||
addUnusedDiagnostics();
|
||||
}
|
||||
return diagnostics || emptyArray;
|
||||
}
|
||||
finally {
|
||||
cancellationToken = undefined;
|
||||
}
|
||||
|
||||
function addUnusedDiagnostics() {
|
||||
checkUnusedIdentifiers(getPotentiallyUnusedIdentifiers(file), (kind, diag) => {
|
||||
if (!unusedIsError(kind)) {
|
||||
diagnostics.push({ ...diag, category: DiagnosticCategory.Suggestion });
|
||||
(diagnostics || (diagnostics = [])).push({ ...diag, category: DiagnosticCategory.Suggestion });
|
||||
}
|
||||
});
|
||||
return diagnostics;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -889,11 +902,17 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
function mergeSymbol(target: Symbol, source: Symbol) {
|
||||
/**
|
||||
* Note: if target is transient, then it is mutable, and mergeSymbol with both mutate and return it.
|
||||
* If target is not transient, mergeSymbol will produce a transient clone, mutate that and return it.
|
||||
*/
|
||||
function mergeSymbol(target: Symbol, source: Symbol): Symbol {
|
||||
if (!(target.flags & getExcludedSymbolFlags(source.flags)) ||
|
||||
(source.flags | target.flags) & SymbolFlags.JSContainer) {
|
||||
const targetValueDeclaration = target.valueDeclaration;
|
||||
Debug.assert(!!(target.flags & SymbolFlags.Transient));
|
||||
Debug.assert(source !== target);
|
||||
if (!(target.flags & SymbolFlags.Transient)) {
|
||||
target = cloneSymbol(target);
|
||||
}
|
||||
// Javascript static-property-assignment declarations always merge, even though they are also values
|
||||
if (source.flags & SymbolFlags.ValueModule && target.flags & SymbolFlags.ValueModule && target.constEnumOnlyModule && !source.constEnumOnlyModule) {
|
||||
// reset flag when merging instantiated module into value module that has only const enums
|
||||
@@ -915,18 +934,6 @@ namespace ts {
|
||||
if (!target.exports) target.exports = createSymbolTable();
|
||||
mergeSymbolTable(target.exports, source.exports);
|
||||
}
|
||||
if ((source.flags | target.flags) & SymbolFlags.JSContainer) {
|
||||
const sourceInitializer = getJSInitializerSymbol(source)!;
|
||||
const init = getDeclaredJavascriptInitializer(targetValueDeclaration) || getAssignedJavascriptInitializer(targetValueDeclaration);
|
||||
let targetInitializer = init && init.symbol ? init.symbol : target;
|
||||
if (!(targetInitializer.flags & SymbolFlags.Transient)) {
|
||||
const mergedInitializer = getMergedSymbol(targetInitializer);
|
||||
targetInitializer = mergedInitializer === targetInitializer ? cloneSymbol(targetInitializer) : mergedInitializer;
|
||||
}
|
||||
if (sourceInitializer !== source || targetInitializer !== target) {
|
||||
mergeSymbol(targetInitializer, sourceInitializer);
|
||||
}
|
||||
}
|
||||
recordMergedSymbol(target, source);
|
||||
}
|
||||
else if (target.flags & SymbolFlags.NamespaceModule) {
|
||||
@@ -947,11 +954,12 @@ namespace ts {
|
||||
error(errorNode, message, symbolToString(source));
|
||||
});
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
function combineSymbolTables(first: SymbolTable | undefined, second: SymbolTable | undefined): SymbolTable | undefined {
|
||||
if (!first || first.size === 0) return second;
|
||||
if (!second || second.size === 0) return first;
|
||||
if (!hasEntries(first)) return second;
|
||||
if (!hasEntries(second)) return first;
|
||||
const combined = createSymbolTable();
|
||||
mergeSymbolTable(combined, first);
|
||||
mergeSymbolTable(combined, second);
|
||||
@@ -960,17 +968,7 @@ namespace ts {
|
||||
|
||||
function mergeSymbolTable(target: SymbolTable, source: SymbolTable) {
|
||||
source.forEach((sourceSymbol, id) => {
|
||||
let targetSymbol = target.get(id);
|
||||
if (!targetSymbol) {
|
||||
target.set(id, sourceSymbol);
|
||||
}
|
||||
else {
|
||||
if (!(targetSymbol.flags & SymbolFlags.Transient)) {
|
||||
targetSymbol = cloneSymbol(targetSymbol);
|
||||
target.set(id, targetSymbol);
|
||||
}
|
||||
mergeSymbol(targetSymbol, sourceSymbol);
|
||||
}
|
||||
target.set(id, target.has(id) ? mergeSymbol(target.get(id)!, sourceSymbol) : sourceSymbol);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1000,10 +998,7 @@ namespace ts {
|
||||
// obtain item referenced by 'export='
|
||||
mainModule = resolveExternalModuleSymbol(mainModule);
|
||||
if (mainModule.flags & SymbolFlags.Namespace) {
|
||||
// if module symbol has already been merged - it is safe to use it.
|
||||
// otherwise clone it
|
||||
mainModule = mainModule.flags & SymbolFlags.Transient ? mainModule : cloneSymbol(mainModule);
|
||||
mergeSymbol(mainModule, moduleAugmentation.symbol);
|
||||
mainModule = mergeSymbol(mainModule, moduleAugmentation.symbol);
|
||||
}
|
||||
else {
|
||||
// moduleName will be a StringLiteral since this is not `declare global`.
|
||||
@@ -1463,9 +1458,8 @@ namespace ts {
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
case SyntaxKind.JSDocCallbackTag:
|
||||
// js type aliases do not resolve names from their host, so skip past it
|
||||
lastLocation = location;
|
||||
location = getJSDocHost(location).parent;
|
||||
continue;
|
||||
location = getJSDocHost(location);
|
||||
break;
|
||||
}
|
||||
if (isSelfReferenceLocation(location)) {
|
||||
lastSelfReferenceLocation = location;
|
||||
@@ -1789,7 +1783,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function isSyntacticDefault(node: Node) {
|
||||
return ((isExportAssignment(node) && !node.isExportEquals) || hasModifier(node, ModifierFlags.Default));
|
||||
return ((isExportAssignment(node) && !node.isExportEquals) || hasModifier(node, ModifierFlags.Default) || isExportSpecifier(node));
|
||||
}
|
||||
|
||||
function canHaveSyntheticDefault(file: SourceFile | undefined, moduleSymbol: Symbol, dontResolveAlias: boolean) {
|
||||
@@ -2124,14 +2118,6 @@ namespace ts {
|
||||
return namespace;
|
||||
}
|
||||
if (isInJavaScriptFile(name)) {
|
||||
const initializer = getDeclaredJavascriptInitializer(namespace.valueDeclaration) || getAssignedJavascriptInitializer(namespace.valueDeclaration);
|
||||
if (initializer) {
|
||||
namespace = getSymbolOfNode(initializer)!;
|
||||
}
|
||||
// Currently, IIFEs may not have a symbol and we don't know about their contents. Give up in this case.
|
||||
if (!namespace) {
|
||||
return undefined;
|
||||
}
|
||||
if (namespace.valueDeclaration &&
|
||||
isVariableDeclaration(namespace.valueDeclaration) &&
|
||||
namespace.valueDeclaration.initializer &&
|
||||
@@ -2324,14 +2310,7 @@ namespace ts {
|
||||
}
|
||||
moduleSymbol.exports!.forEach((s, name) => {
|
||||
if (name === InternalSymbolName.ExportEquals) return;
|
||||
if (!merged.exports!.has(name)) {
|
||||
merged.exports!.set(name, s);
|
||||
}
|
||||
else {
|
||||
const ms = cloneSymbol(merged.exports!.get(name)!);
|
||||
mergeSymbol(ms, s);
|
||||
merged.exports!.set(name, ms);
|
||||
}
|
||||
merged.exports!.set(name, merged.exports!.has(name) ? mergeSymbol(merged.exports!.get(name)!, s) : s);
|
||||
});
|
||||
return merged;
|
||||
}
|
||||
@@ -2533,6 +2512,46 @@ namespace ts {
|
||||
return getMergedSymbol(symbol.parent && getLateBoundSymbol(symbol.parent));
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to find the symbol corresponding to the container a symbol is in - usually this
|
||||
* is just its' `.parent`, but for locals, this value is `undefined`
|
||||
*/
|
||||
function getContainerOfSymbol(symbol: Symbol): Symbol | undefined {
|
||||
const container = getParentOfSymbol(symbol);
|
||||
if (container) {
|
||||
return container;
|
||||
}
|
||||
const candidate = forEach(symbol.declarations, d => !isAmbientModule(d) && d.parent && hasNonGlobalAugmentationExternalModuleSymbol(d.parent) ? getSymbolOfNode(d.parent) : undefined);
|
||||
if (!candidate) {
|
||||
return undefined;
|
||||
}
|
||||
const alias = getAliasForSymbolInContainer(candidate, symbol);
|
||||
return alias ? candidate : undefined;
|
||||
}
|
||||
|
||||
function getAliasForSymbolInContainer(container: Symbol, symbol: Symbol) {
|
||||
if (container === getParentOfSymbol(symbol)) {
|
||||
// fast path, `symbol` is either already the alias or isn't aliased
|
||||
return symbol;
|
||||
}
|
||||
const exports = getExportsOfSymbol(container);
|
||||
const quick = exports.get(symbol.escapedName);
|
||||
if (quick && symbolRefersToTarget(quick)) {
|
||||
return quick;
|
||||
}
|
||||
return forEachEntry(exports, exported => {
|
||||
if (symbolRefersToTarget(exported)) {
|
||||
return exported;
|
||||
}
|
||||
});
|
||||
|
||||
function symbolRefersToTarget(s: Symbol) {
|
||||
if (s === symbol || resolveSymbol(s) === symbol || resolveSymbol(s) === resolveSymbol(symbol)) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getExportSymbolOfValueSymbolIfExported(symbol: Symbol): Symbol;
|
||||
function getExportSymbolOfValueSymbolIfExported(symbol: Symbol | undefined): Symbol | undefined;
|
||||
function getExportSymbolOfValueSymbolIfExported(symbol: Symbol | undefined): Symbol | undefined {
|
||||
@@ -2838,7 +2857,7 @@ namespace ts {
|
||||
// But it can't, hence the accessible is going to be undefined, but that doesn't mean m.c is inaccessible
|
||||
// It is accessible if the parent m is accessible because then m.c can be accessed through qualification
|
||||
meaningToLook = getQualifiedLeftMeaning(meaning);
|
||||
symbol = getParentOfSymbol(symbol);
|
||||
symbol = getContainerOfSymbol(symbol);
|
||||
}
|
||||
|
||||
// This could be a symbol that is not exported in the external module
|
||||
@@ -3729,12 +3748,12 @@ namespace ts {
|
||||
needsQualification(accessibleSymbolChain[0], context.enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning))) {
|
||||
|
||||
// Go up and add our parent.
|
||||
const parent = getParentOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol);
|
||||
const parent = getContainerOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol);
|
||||
if (parent) {
|
||||
const parentChain = getSymbolChain(parent, getQualifiedLeftMeaning(meaning), /*endOfChain*/ false);
|
||||
if (parentChain) {
|
||||
parentSymbol = parent;
|
||||
accessibleSymbolChain = parentChain.concat(accessibleSymbolChain || [symbol]);
|
||||
accessibleSymbolChain = parentChain.concat(accessibleSymbolChain || [getAliasForSymbolInContainer(parent, symbol) || symbol]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4065,7 +4084,8 @@ namespace ts {
|
||||
// ambient module, just use declaration/symbol name (fallthrough)
|
||||
}
|
||||
else {
|
||||
return `"${getResolvedExternalModuleName(context!.tracker.moduleResolverHost!, file, getSourceFileOfNode(getOriginalNode(context!.enclosingDeclaration)))}"`;
|
||||
const contextFile = getSourceFileOfNode(getOriginalNode(context!.enclosingDeclaration))!;
|
||||
return `"${file.moduleName || moduleSpecifiers.getModuleSpecifier(compilerOptions, contextFile, contextFile.path, file.path, context!.tracker.moduleResolverHost!)}"`;
|
||||
}
|
||||
}
|
||||
const declaration = symbol.declarations[0];
|
||||
@@ -4926,6 +4946,8 @@ namespace ts {
|
||||
else if (isJSDocPropertyLikeTag(declaration)
|
||||
|| isPropertyAccessExpression(declaration)
|
||||
|| isIdentifier(declaration)
|
||||
|| isClassDeclaration(declaration)
|
||||
|| isFunctionDeclaration(declaration)
|
||||
|| (isMethodDeclaration(declaration) && !isObjectLiteralMethod(declaration))
|
||||
|| isMethodSignature(declaration)) {
|
||||
|
||||
@@ -4955,7 +4977,7 @@ namespace ts {
|
||||
type = getWidenedTypeForVariableLikeDeclaration(declaration, /*reportErrors*/ true);
|
||||
}
|
||||
else {
|
||||
return Debug.fail("Unhandled declaration kind! " + Debug.showSyntaxKind(declaration));
|
||||
return Debug.fail("Unhandled declaration kind! " + Debug.showSyntaxKind(declaration) + " for " + Debug.showSymbol(symbol));
|
||||
}
|
||||
|
||||
if (!popTypeResolution()) {
|
||||
@@ -5057,8 +5079,25 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getTypeOfFuncClassEnumModule(symbol: Symbol): Type {
|
||||
const links = getSymbolLinks(symbol);
|
||||
let links = getSymbolLinks(symbol);
|
||||
if (!links.type) {
|
||||
const jsDeclaration = getDeclarationOfJSInitializer(symbol.valueDeclaration);
|
||||
if (jsDeclaration) {
|
||||
const jsSymbol = getSymbolOfNode(jsDeclaration);
|
||||
if (jsSymbol && (hasEntries(jsSymbol.exports) || hasEntries(jsSymbol.members))) {
|
||||
symbol = cloneSymbol(symbol);
|
||||
// note:we overwrite links because we just cloned the symbol
|
||||
links = symbol as TransientSymbol;
|
||||
if (hasEntries(jsSymbol.exports)) {
|
||||
symbol.exports = symbol.exports || createSymbolTable();
|
||||
mergeSymbolTable(symbol.exports, jsSymbol.exports);
|
||||
}
|
||||
if (hasEntries(jsSymbol.members)) {
|
||||
symbol.members = symbol.members || createSymbolTable();
|
||||
mergeSymbolTable(symbol.members, jsSymbol.members);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (symbol.flags & SymbolFlags.Module && isShorthandAmbientModuleSymbol(symbol)) {
|
||||
links.type = anyType;
|
||||
}
|
||||
@@ -7406,18 +7445,17 @@ namespace ts {
|
||||
const result: Signature[] = [];
|
||||
for (let i = 0; i < symbol.declarations.length; i++) {
|
||||
const decl = symbol.declarations[i];
|
||||
const node = isPropertyAccessExpression(decl) ? getAssignedJavascriptInitializer(decl)! : decl; // TODO: GH#18217
|
||||
if (!isFunctionLike(node)) continue;
|
||||
if (!isFunctionLike(decl)) continue;
|
||||
// Don't include signature if node is the implementation of an overloaded function. A node is considered
|
||||
// an implementation node if it has a body and the previous node is of the same kind and immediately
|
||||
// precedes the implementation node (i.e. has the same parent and ends where the implementation starts).
|
||||
if (i > 0 && (node as FunctionLikeDeclaration).body) {
|
||||
if (i > 0 && (decl as FunctionLikeDeclaration).body) {
|
||||
const previous = symbol.declarations[i - 1];
|
||||
if (node.parent === previous.parent && node.kind === previous.kind && node.pos === previous.end) {
|
||||
if (decl.parent === previous.parent && decl.kind === previous.kind && decl.pos === previous.end) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
result.push(getSignatureFromDeclaration(node));
|
||||
result.push(getSignatureFromDeclaration(decl));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -8844,7 +8882,9 @@ namespace ts {
|
||||
return type.simplified === circularConstraintType ? type : type.simplified;
|
||||
}
|
||||
type.simplified = circularConstraintType;
|
||||
const objectType = type.objectType;
|
||||
// We recursively simplify the object type as it may in turn be an indexed access type. For example, with
|
||||
// '{ [P in T]: { [Q in U]: number } }[T][U]' we want to first simplify the inner indexed access type.
|
||||
const objectType = getSimplifiedType(type.objectType);
|
||||
if (objectType.flags & TypeFlags.Intersection && isGenericObjectType(objectType)) {
|
||||
// Given an indexed access type T[K], if T is an intersection containing one or more generic types and one or
|
||||
// more object types with only a string index signature, e.g. '(U & V & { [x: string]: D })[K]', return a
|
||||
@@ -9165,12 +9205,13 @@ namespace ts {
|
||||
}
|
||||
|
||||
function resolveImportSymbolType(node: ImportTypeNode, links: NodeLinks, symbol: Symbol, meaning: SymbolFlags) {
|
||||
links.resolvedSymbol = symbol;
|
||||
const resolvedSymbol = resolveSymbol(symbol);
|
||||
links.resolvedSymbol = resolvedSymbol;
|
||||
if (meaning === SymbolFlags.Value) {
|
||||
return links.resolvedType = getTypeOfSymbol(symbol);
|
||||
return links.resolvedType = getTypeOfSymbol(symbol); // intentionally doesn't use resolved symbol so type is cached as expected on the alias
|
||||
}
|
||||
else {
|
||||
return links.resolvedType = getTypeReferenceType(node, symbol);
|
||||
return links.resolvedType = getTypeReferenceType(node, resolvedSymbol); // getTypeReferenceType doesn't handle aliases - it must get the resolved symbol
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14075,11 +14116,14 @@ namespace ts {
|
||||
if (operator === SyntaxKind.ExclamationEqualsToken || operator === SyntaxKind.ExclamationEqualsEqualsToken) {
|
||||
assumeTrue = !assumeTrue;
|
||||
}
|
||||
if (type.flags & TypeFlags.Any && literal.text === "function") {
|
||||
return type;
|
||||
}
|
||||
if (assumeTrue && !(type.flags & TypeFlags.Union)) {
|
||||
// We narrow a non-union type to an exact primitive type if the non-union type
|
||||
// is a supertype of that primitive type. For example, type 'any' can be narrowed
|
||||
// to one of the primitive types.
|
||||
const targetType = typeofTypesByName.get(literal.text);
|
||||
const targetType = literal.text === "function" ? globalFunctionType : typeofTypesByName.get(literal.text);
|
||||
if (targetType) {
|
||||
if (isTypeSubtypeOf(targetType, type)) {
|
||||
return targetType;
|
||||
@@ -15259,7 +15303,7 @@ namespace ts {
|
||||
// expression has no contextual type, the right operand is contextually typed by the type of the left operand,
|
||||
// except for the special case of Javascript declarations of the form `namespace.prop = namespace.prop || {}`
|
||||
const type = getContextualType(binaryExpression);
|
||||
return !type && node === right && !getDeclaredJavascriptInitializer(binaryExpression.parent) && !getAssignedJavascriptInitializer(binaryExpression) ?
|
||||
return !type && node === right && !isDefaultedJavascriptInitializer(binaryExpression) ?
|
||||
getTypeOfExpression(left) : type;
|
||||
case SyntaxKind.AmpersandAmpersandToken:
|
||||
case SyntaxKind.CommaToken:
|
||||
@@ -15268,6 +15312,7 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// In an assignment expression, the right operand is contextually typed by the type of the left operand.
|
||||
// Don't do this for special property assignments to avoid circularity.
|
||||
function isContextSensitiveAssignment(binaryExpression: BinaryExpression): boolean {
|
||||
@@ -15935,13 +15980,16 @@ namespace ts {
|
||||
let hasComputedStringProperty = false;
|
||||
let hasComputedNumberProperty = false;
|
||||
|
||||
if (isInJSFile && node.properties.length === 0) {
|
||||
// an empty JS object literal that nonetheless has members is a JS namespace
|
||||
const symbol = getSymbolOfNode(node);
|
||||
if (symbol.exports) {
|
||||
propertiesTable = symbol.exports;
|
||||
symbol.exports.forEach(symbol => propertiesArray.push(getMergedSymbol(symbol)));
|
||||
return createObjectLiteralType();
|
||||
if (isInJSFile) {
|
||||
const decl = getDeclarationOfJSInitializer(node);
|
||||
if (decl) {
|
||||
// a JS object literal whose declaration's symbol has exports is a JS namespace
|
||||
const symbol = getMergedSymbol(decl.symbol);
|
||||
if (symbol && hasEntries(symbol.exports)) {
|
||||
propertiesTable = symbol.exports;
|
||||
symbol.exports.forEach(symbol => propertiesArray.push(getMergedSymbol(symbol)));
|
||||
return createObjectLiteralType();
|
||||
}
|
||||
}
|
||||
}
|
||||
propertiesTable = createSymbolTable();
|
||||
@@ -17335,88 +17383,11 @@ namespace ts {
|
||||
* and 1 insertion/deletion at 3 characters)
|
||||
*/
|
||||
function getSpellingSuggestionForName(name: string, symbols: Symbol[], meaning: SymbolFlags): Symbol | undefined {
|
||||
const maximumLengthDifference = Math.min(2, Math.floor(name.length * 0.34));
|
||||
let bestDistance = Math.floor(name.length * 0.4) + 1; // If the best result isn't better than this, don't bother.
|
||||
let bestCandidate: Symbol | undefined;
|
||||
let justCheckExactMatches = false;
|
||||
const nameLowerCase = name.toLowerCase();
|
||||
for (const candidate of symbols) {
|
||||
return getSpellingSuggestion(name, symbols, getCandidateName);
|
||||
function getCandidateName(candidate: Symbol) {
|
||||
const candidateName = symbolName(candidate);
|
||||
if (candidateName.charCodeAt(0) === CharacterCodes.doubleQuote
|
||||
|| !(candidate.flags & meaning && Math.abs(candidateName.length - nameLowerCase.length) <= maximumLengthDifference)) {
|
||||
continue;
|
||||
}
|
||||
const candidateNameLowerCase = candidateName.toLowerCase();
|
||||
if (candidateNameLowerCase === nameLowerCase) {
|
||||
return candidate;
|
||||
}
|
||||
if (justCheckExactMatches) {
|
||||
continue;
|
||||
}
|
||||
if (candidateName.length < 3) {
|
||||
// Don't bother, user would have noticed a 2-character name having an extra character
|
||||
continue;
|
||||
}
|
||||
// Only care about a result better than the best so far.
|
||||
const distance = levenshteinWithMax(nameLowerCase, candidateNameLowerCase, bestDistance - 1);
|
||||
if (distance === undefined) {
|
||||
continue;
|
||||
}
|
||||
if (distance < 3) {
|
||||
justCheckExactMatches = true;
|
||||
bestCandidate = candidate;
|
||||
}
|
||||
else {
|
||||
Debug.assert(distance < bestDistance); // Else `levenshteinWithMax` should return undefined
|
||||
bestDistance = distance;
|
||||
bestCandidate = candidate;
|
||||
}
|
||||
return !startsWith(candidateName, "\"") && candidate.flags & meaning ? candidateName : undefined;
|
||||
}
|
||||
return bestCandidate;
|
||||
}
|
||||
|
||||
function levenshteinWithMax(s1: string, s2: string, max: number): number | undefined {
|
||||
let previous = new Array(s2.length + 1);
|
||||
let current = new Array(s2.length + 1);
|
||||
/** Represents any value > max. We don't care about the particular value. */
|
||||
const big = max + 1;
|
||||
|
||||
for (let i = 0; i <= s2.length; i++) {
|
||||
previous[i] = i;
|
||||
}
|
||||
|
||||
for (let i = 1; i <= s1.length; i++) {
|
||||
const c1 = s1.charCodeAt(i - 1);
|
||||
const minJ = i > max ? i - max : 1;
|
||||
const maxJ = s2.length > max + i ? max + i : s2.length;
|
||||
current[0] = i;
|
||||
/** Smallest value of the matrix in the ith column. */
|
||||
let colMin = i;
|
||||
for (let j = 1; j < minJ; j++) {
|
||||
current[j] = big;
|
||||
}
|
||||
for (let j = minJ; j <= maxJ; j++) {
|
||||
const dist = c1 === s2.charCodeAt(j - 1)
|
||||
? previous[j - 1]
|
||||
: Math.min(/*delete*/ previous[j] + 1, /*insert*/ current[j - 1] + 1, /*substitute*/ previous[j - 1] + 2);
|
||||
current[j] = dist;
|
||||
colMin = Math.min(colMin, dist);
|
||||
}
|
||||
for (let j = maxJ + 1; j <= s2.length; j++) {
|
||||
current[j] = big;
|
||||
}
|
||||
if (colMin > max) {
|
||||
// Give up -- everything in this column is > max and it can't get better in future columns.
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const temp = previous;
|
||||
previous = current;
|
||||
current = temp;
|
||||
}
|
||||
|
||||
const res = previous[s2.length];
|
||||
return res > max ? undefined : res;
|
||||
}
|
||||
|
||||
function markPropertyAsReferenced(prop: Symbol, nodeForCheckWriteOnly: Node | undefined, isThisAccess: boolean) {
|
||||
@@ -18636,6 +18607,7 @@ namespace ts {
|
||||
if (node.expression.kind === SyntaxKind.SuperKeyword) {
|
||||
const superType = checkSuperExpression(node.expression);
|
||||
if (isTypeAny(superType)) {
|
||||
forEach(node.arguments, checkExpression); // Still visit arguments so they get marked for visibility, etc
|
||||
return anySignature;
|
||||
}
|
||||
if (superType !== errorType) {
|
||||
@@ -19043,10 +19015,6 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getJavaScriptClassType(symbol: Symbol): Type | undefined {
|
||||
const initializer = getDeclaredJavascriptInitializer(symbol.valueDeclaration);
|
||||
if (initializer) {
|
||||
symbol = getSymbolOfNode(initializer)!;
|
||||
}
|
||||
let inferred: Type | undefined;
|
||||
if (isJavaScriptConstructor(symbol.valueDeclaration)) {
|
||||
inferred = getInferredClassType(symbol);
|
||||
@@ -19157,7 +19125,17 @@ namespace ts {
|
||||
if (returnType.flags & TypeFlags.ESSymbolLike && isSymbolOrSymbolForCall(node)) {
|
||||
return getESSymbolLikeTypeForNode(walkUpParenthesizedExpressions(node.parent));
|
||||
}
|
||||
return returnType;
|
||||
let jsAssignmentType: Type | undefined;
|
||||
if (isInJavaScriptFile(node)) {
|
||||
const decl = getDeclarationOfJSInitializer(node);
|
||||
if (decl) {
|
||||
const jsSymbol = getSymbolOfNode(decl);
|
||||
if (jsSymbol && hasEntries(jsSymbol.exports)) {
|
||||
jsAssignmentType = createAnonymousType(jsSymbol, jsSymbol.exports, emptyArray, emptyArray, jsObjectLiteralIndexInfo, undefined);
|
||||
}
|
||||
}
|
||||
}
|
||||
return jsAssignmentType ? getIntersectionType([returnType, jsAssignmentType]) : returnType;
|
||||
}
|
||||
|
||||
function isSymbolOrSymbolForCall(node: Node) {
|
||||
@@ -20653,13 +20631,12 @@ namespace ts {
|
||||
}
|
||||
|
||||
function checkDeclarationInitializer(declaration: HasExpressionInitializer) {
|
||||
const inJs = isInJavaScriptFile(declaration);
|
||||
const initializer = inJs && getDeclaredJavascriptInitializer(declaration) || declaration.initializer!;
|
||||
const initializer = getEffectiveInitializer(declaration)!;
|
||||
const type = getTypeOfExpression(initializer, /*cache*/ true);
|
||||
const widened = getCombinedNodeFlags(declaration) & NodeFlags.Const ||
|
||||
(getCombinedModifierFlags(declaration) & ModifierFlags.Readonly && !isParameterPropertyDeclaration(declaration)) ||
|
||||
isTypeAssertion(initializer) ? type : getWidenedLiteralType(type);
|
||||
if (inJs) {
|
||||
if (isInJavaScriptFile(declaration)) {
|
||||
if (widened.flags & TypeFlags.Nullable) {
|
||||
if (noImplicitAny) {
|
||||
reportImplicitAnyError(declaration, anyType);
|
||||
@@ -22737,7 +22714,7 @@ namespace ts {
|
||||
function errorUnusedLocal(declaration: Declaration, name: string, addDiagnostic: AddUnusedDiagnostic) {
|
||||
const node = getNameOfDeclaration(declaration) || declaration;
|
||||
const message = isTypeDeclaration(declaration) ? Diagnostics._0_is_declared_but_never_used : Diagnostics._0_is_declared_but_its_value_is_never_read;
|
||||
addDiagnostic(UnusedKind.Local, createDiagnosticForNodeSpan(getSourceFileOfNode(declaration), declaration, node, message, name));
|
||||
addDiagnostic(UnusedKind.Local, createDiagnosticForNode(node, message, name));
|
||||
}
|
||||
|
||||
function parameterNameStartsWithUnderscore(parameterName: DeclarationName) {
|
||||
@@ -23285,8 +23262,8 @@ namespace ts {
|
||||
if (node === symbol.valueDeclaration) {
|
||||
// Node is the primary declaration of the symbol, just validate the initializer
|
||||
// Don't validate for-in initializer as it is already an error
|
||||
if (node.initializer && node.parent.parent.kind !== SyntaxKind.ForInStatement) {
|
||||
const initializer = isInJavaScriptFile(node) && getDeclaredJavascriptInitializer(node) || node.initializer;
|
||||
const initializer = getEffectiveInitializer(node);
|
||||
if (initializer && node.parent.parent.kind !== SyntaxKind.ForInStatement) {
|
||||
checkTypeAssignableTo(checkExpressionCached(initializer), type, node, /*headMessage*/ undefined);
|
||||
checkParameterInitializer(node);
|
||||
}
|
||||
@@ -28369,9 +28346,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
function checkGrammarConstructorTypeParameters(node: ConstructorDeclaration) {
|
||||
const typeParameters = getEffectiveTypeParameterDeclarations(node);
|
||||
if (isNodeArray(typeParameters)) {
|
||||
const { pos, end } = typeParameters;
|
||||
const jsdocTypeParameters = isInJavaScriptFile(node) && getJSDocTypeParameterDeclarations(node);
|
||||
if (node.typeParameters || jsdocTypeParameters && jsdocTypeParameters.length) {
|
||||
const { pos, end } = node.typeParameters || jsdocTypeParameters && jsdocTypeParameters[0] || node;
|
||||
return grammarErrorAtPos(node, pos, end - pos, Diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,66 @@
|
||||
namespace ts {
|
||||
/* @internal */
|
||||
export const compileOnSaveCommandLineOption: CommandLineOption = { name: "compileOnSave", type: "boolean" };
|
||||
|
||||
// NOTE: The order here is important to default lib ordering as entries will have the same
|
||||
// order in the generated program (see `getDefaultLibPriority` in program.ts). This
|
||||
// order also affects overload resolution when a type declared in one lib is
|
||||
// augmented in another lib.
|
||||
const libEntries: [string, string][] = [
|
||||
// JavaScript only
|
||||
["es5", "lib.es5.d.ts"],
|
||||
["es6", "lib.es2015.d.ts"],
|
||||
["es2015", "lib.es2015.d.ts"],
|
||||
["es7", "lib.es2016.d.ts"],
|
||||
["es2016", "lib.es2016.d.ts"],
|
||||
["es2017", "lib.es2017.d.ts"],
|
||||
["es2018", "lib.es2018.d.ts"],
|
||||
["esnext", "lib.esnext.d.ts"],
|
||||
// Host only
|
||||
["dom", "lib.dom.d.ts"],
|
||||
["dom.iterable", "lib.dom.iterable.d.ts"],
|
||||
["webworker", "lib.webworker.d.ts"],
|
||||
["webworker.importscripts", "lib.webworker.importscripts.d.ts"],
|
||||
["scripthost", "lib.scripthost.d.ts"],
|
||||
// ES2015 Or ESNext By-feature options
|
||||
["es2015.core", "lib.es2015.core.d.ts"],
|
||||
["es2015.collection", "lib.es2015.collection.d.ts"],
|
||||
["es2015.generator", "lib.es2015.generator.d.ts"],
|
||||
["es2015.iterable", "lib.es2015.iterable.d.ts"],
|
||||
["es2015.promise", "lib.es2015.promise.d.ts"],
|
||||
["es2015.proxy", "lib.es2015.proxy.d.ts"],
|
||||
["es2015.reflect", "lib.es2015.reflect.d.ts"],
|
||||
["es2015.symbol", "lib.es2015.symbol.d.ts"],
|
||||
["es2015.symbol.wellknown", "lib.es2015.symbol.wellknown.d.ts"],
|
||||
["es2016.array.include", "lib.es2016.array.include.d.ts"],
|
||||
["es2017.object", "lib.es2017.object.d.ts"],
|
||||
["es2017.sharedmemory", "lib.es2017.sharedmemory.d.ts"],
|
||||
["es2017.string", "lib.es2017.string.d.ts"],
|
||||
["es2017.intl", "lib.es2017.intl.d.ts"],
|
||||
["es2017.typedarrays", "lib.es2017.typedarrays.d.ts"],
|
||||
["es2018.intl", "lib.es2018.intl.d.ts"],
|
||||
["es2018.promise", "lib.es2018.promise.d.ts"],
|
||||
["es2018.regexp", "lib.es2018.regexp.d.ts"],
|
||||
["esnext.array", "lib.esnext.array.d.ts"],
|
||||
["esnext.symbol", "lib.esnext.symbol.d.ts"],
|
||||
["esnext.asynciterable", "lib.esnext.asynciterable.d.ts"],
|
||||
];
|
||||
|
||||
/**
|
||||
* An array of supported "lib" reference file names used to determine the order for inclusion
|
||||
* when referenced, as well as for spelling suggestions. This ensures the correct ordering for
|
||||
* overload resolution when a type declared in one lib is extended by another.
|
||||
*/
|
||||
/* @internal */
|
||||
export const libs = libEntries.map(entry => entry[0]);
|
||||
|
||||
/**
|
||||
* A map of lib names to lib files. This map is used both for parsing the "lib" command line
|
||||
* option as well as for resolving lib reference directives.
|
||||
*/
|
||||
/* @internal */
|
||||
export const libMap = createMapFromEntries(libEntries);
|
||||
|
||||
/* @internal */
|
||||
export const optionDeclarations: CommandLineOption[] = [
|
||||
// CommandLine only options
|
||||
@@ -122,43 +182,7 @@ namespace ts {
|
||||
type: "list",
|
||||
element: {
|
||||
name: "lib",
|
||||
type: createMapFromTemplate({
|
||||
// JavaScript only
|
||||
"es5": "lib.es5.d.ts",
|
||||
"es6": "lib.es2015.d.ts",
|
||||
"es2015": "lib.es2015.d.ts",
|
||||
"es7": "lib.es2016.d.ts",
|
||||
"es2016": "lib.es2016.d.ts",
|
||||
"es2017": "lib.es2017.d.ts",
|
||||
"es2018": "lib.es2018.d.ts",
|
||||
"esnext": "lib.esnext.d.ts",
|
||||
// Host only
|
||||
"dom": "lib.dom.d.ts",
|
||||
"dom.iterable": "lib.dom.iterable.d.ts",
|
||||
"webworker": "lib.webworker.d.ts",
|
||||
"scripthost": "lib.scripthost.d.ts",
|
||||
// ES2015 Or ESNext By-feature options
|
||||
"es2015.core": "lib.es2015.core.d.ts",
|
||||
"es2015.collection": "lib.es2015.collection.d.ts",
|
||||
"es2015.generator": "lib.es2015.generator.d.ts",
|
||||
"es2015.iterable": "lib.es2015.iterable.d.ts",
|
||||
"es2015.promise": "lib.es2015.promise.d.ts",
|
||||
"es2015.proxy": "lib.es2015.proxy.d.ts",
|
||||
"es2015.reflect": "lib.es2015.reflect.d.ts",
|
||||
"es2015.symbol": "lib.es2015.symbol.d.ts",
|
||||
"es2015.symbol.wellknown": "lib.es2015.symbol.wellknown.d.ts",
|
||||
"es2016.array.include": "lib.es2016.array.include.d.ts",
|
||||
"es2017.object": "lib.es2017.object.d.ts",
|
||||
"es2017.sharedmemory": "lib.es2017.sharedmemory.d.ts",
|
||||
"es2017.string": "lib.es2017.string.d.ts",
|
||||
"es2017.intl": "lib.es2017.intl.d.ts",
|
||||
"es2017.typedarrays": "lib.es2017.typedarrays.d.ts",
|
||||
"es2018.intl": "lib.es2018.intl.d.ts",
|
||||
"es2018.promise": "lib.es2018.promise.d.ts",
|
||||
"es2018.regexp": "lib.es2018.regexp.d.ts",
|
||||
"esnext.array": "lib.esnext.array.d.ts",
|
||||
"esnext.asynciterable": "lib.esnext.asynciterable.d.ts",
|
||||
}),
|
||||
type: libMap
|
||||
},
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Basic_Options,
|
||||
@@ -937,7 +961,8 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getOptionFromName(optionName: string, allowShort = false): CommandLineOption | undefined {
|
||||
/** @internal */
|
||||
export function getOptionFromName(optionName: string, allowShort = false): CommandLineOption | undefined {
|
||||
optionName = optionName.toLowerCase();
|
||||
const { optionNameMap, shortOptionNames } = getOptionNameMap();
|
||||
// Try to translate short option names to their full equivalents.
|
||||
|
||||
+140
-6
@@ -59,6 +59,14 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
export function createMapFromEntries<T>(entries: [string, T][]): Map<T> {
|
||||
const map = createMap<T>();
|
||||
for (const [key, value] of entries) {
|
||||
map.set(key, value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
export function createMapFromTemplate<T>(template: MapLike<T>): Map<T> {
|
||||
const map: Map<T> = new MapCtr<T>();
|
||||
|
||||
@@ -169,6 +177,10 @@ namespace ts {
|
||||
return array ? array.length : 0;
|
||||
}
|
||||
|
||||
export function hasEntries(map: ReadonlyUnderscoreEscapedMap<any> | undefined): map is ReadonlyUnderscoreEscapedMap<any> {
|
||||
return !!map && !!map.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates through 'array' by index and performs the callback on each element of array until the callback
|
||||
* returns a truthy value, then returns that value.
|
||||
@@ -1792,7 +1804,7 @@ namespace ts {
|
||||
* Case-insensitive comparisons compare both strings one code-point at a time using the integer
|
||||
* value of each code-point after applying `toUpperCase` to each string. We always map both
|
||||
* strings to their upper-case form as some unicode characters do not properly round-trip to
|
||||
* lowercase (such as `ẞ` (German sharp capital s)).
|
||||
* lowercase (such as `ẞ` (German sharp capital s)).
|
||||
*/
|
||||
export function compareStringsCaseInsensitive(a: string, b: string) {
|
||||
if (a === b) return Comparison.EqualTo;
|
||||
@@ -1864,7 +1876,7 @@ namespace ts {
|
||||
//
|
||||
// For case insensitive comparisons we always map both strings to their
|
||||
// upper-case form as some unicode characters do not properly round-trip to
|
||||
// lowercase (such as `ẞ` (German sharp capital s)).
|
||||
// lowercase (such as `ẞ` (German sharp capital s)).
|
||||
return (a, b) => compareWithCallback(a, b, compareDictionaryOrder);
|
||||
|
||||
function compareDictionaryOrder(a: string, b: string) {
|
||||
@@ -1989,6 +2001,103 @@ namespace ts {
|
||||
return text1 ? Comparison.GreaterThan : Comparison.LessThan;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a name and a list of names that are *not* equal to the name, return a spelling suggestion if there is one that is close enough.
|
||||
* Names less than length 3 only check for case-insensitive equality, not Levenshtein distance.
|
||||
*
|
||||
* If there is a candidate that's the same except for case, return that.
|
||||
* If there is a candidate that's within one edit of the name, return that.
|
||||
* Otherwise, return the candidate with the smallest Levenshtein distance,
|
||||
* except for candidates:
|
||||
* * With no name
|
||||
* * Whose length differs from the target name by more than 0.34 of the length of the name.
|
||||
* * Whose levenshtein distance is more than 0.4 of the length of the name
|
||||
* (0.4 allows 1 substitution/transposition for every 5 characters,
|
||||
* and 1 insertion/deletion at 3 characters)
|
||||
*/
|
||||
export function getSpellingSuggestion<T>(name: string, candidates: T[], getName: (candidate: T) => string | undefined): T | undefined {
|
||||
const maximumLengthDifference = Math.min(2, Math.floor(name.length * 0.34));
|
||||
let bestDistance = Math.floor(name.length * 0.4) + 1; // If the best result isn't better than this, don't bother.
|
||||
let bestCandidate: T | undefined;
|
||||
let justCheckExactMatches = false;
|
||||
const nameLowerCase = name.toLowerCase();
|
||||
for (const candidate of candidates) {
|
||||
const candidateName = getName(candidate);
|
||||
if (candidateName !== undefined && Math.abs(candidateName.length - nameLowerCase.length) <= maximumLengthDifference) {
|
||||
const candidateNameLowerCase = candidateName.toLowerCase();
|
||||
if (candidateNameLowerCase === nameLowerCase) {
|
||||
return candidate;
|
||||
}
|
||||
if (justCheckExactMatches) {
|
||||
continue;
|
||||
}
|
||||
if (candidateName.length < 3) {
|
||||
// Don't bother, user would have noticed a 2-character name having an extra character
|
||||
continue;
|
||||
}
|
||||
// Only care about a result better than the best so far.
|
||||
const distance = levenshteinWithMax(nameLowerCase, candidateNameLowerCase, bestDistance - 1);
|
||||
if (distance === undefined) {
|
||||
continue;
|
||||
}
|
||||
if (distance < 3) {
|
||||
justCheckExactMatches = true;
|
||||
bestCandidate = candidate;
|
||||
}
|
||||
else {
|
||||
Debug.assert(distance < bestDistance); // Else `levenshteinWithMax` should return undefined
|
||||
bestDistance = distance;
|
||||
bestCandidate = candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
return bestCandidate;
|
||||
}
|
||||
|
||||
function levenshteinWithMax(s1: string, s2: string, max: number): number | undefined {
|
||||
let previous = new Array(s2.length + 1);
|
||||
let current = new Array(s2.length + 1);
|
||||
/** Represents any value > max. We don't care about the particular value. */
|
||||
const big = max + 1;
|
||||
|
||||
for (let i = 0; i <= s2.length; i++) {
|
||||
previous[i] = i;
|
||||
}
|
||||
|
||||
for (let i = 1; i <= s1.length; i++) {
|
||||
const c1 = s1.charCodeAt(i - 1);
|
||||
const minJ = i > max ? i - max : 1;
|
||||
const maxJ = s2.length > max + i ? max + i : s2.length;
|
||||
current[0] = i;
|
||||
/** Smallest value of the matrix in the ith column. */
|
||||
let colMin = i;
|
||||
for (let j = 1; j < minJ; j++) {
|
||||
current[j] = big;
|
||||
}
|
||||
for (let j = minJ; j <= maxJ; j++) {
|
||||
const dist = c1 === s2.charCodeAt(j - 1)
|
||||
? previous[j - 1]
|
||||
: Math.min(/*delete*/ previous[j] + 1, /*insert*/ current[j - 1] + 1, /*substitute*/ previous[j - 1] + 2);
|
||||
current[j] = dist;
|
||||
colMin = Math.min(colMin, dist);
|
||||
}
|
||||
for (let j = maxJ + 1; j <= s2.length; j++) {
|
||||
current[j] = big;
|
||||
}
|
||||
if (colMin > max) {
|
||||
// Give up -- everything in this column is > max and it can't get better in future columns.
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const temp = previous;
|
||||
previous = current;
|
||||
current = temp;
|
||||
}
|
||||
|
||||
const res = previous[s2.length];
|
||||
return res > max ? undefined : res;
|
||||
}
|
||||
|
||||
export function getEmitScriptTarget(compilerOptions: CompilerOptions) {
|
||||
return compilerOptions.target || ScriptTarget.ES3;
|
||||
}
|
||||
@@ -2588,6 +2697,22 @@ namespace ts {
|
||||
return startsWith(str, prefix) ? str.substr(prefix.length) : str;
|
||||
}
|
||||
|
||||
export function tryRemovePrefix(str: string, prefix: string): string | undefined {
|
||||
return startsWith(str, prefix) ? str.substring(prefix.length) : undefined;
|
||||
}
|
||||
|
||||
export function tryRemoveDirectoryPrefix(path: string, dirPath: string): string | undefined {
|
||||
const a = tryRemovePrefix(path, dirPath);
|
||||
if (a === undefined) return undefined;
|
||||
switch (a.charCodeAt(0)) {
|
||||
case CharacterCodes.slash:
|
||||
case CharacterCodes.backslash:
|
||||
return a.slice(1);
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export function endsWith(str: string, suffix: string): boolean {
|
||||
const expectedPos = str.length - suffix.length;
|
||||
return expectedPos >= 0 && str.indexOf(suffix, expectedPos) === expectedPos;
|
||||
@@ -2597,6 +2722,10 @@ namespace ts {
|
||||
return endsWith(str, suffix) ? str.slice(0, str.length - suffix.length) : str;
|
||||
}
|
||||
|
||||
export function tryRemoveSuffix(str: string, suffix: string): string | undefined {
|
||||
return endsWith(str, suffix) ? str.slice(0, str.length - suffix.length) : undefined;
|
||||
}
|
||||
|
||||
export function stringContains(str: string, substring: string): boolean {
|
||||
return str.indexOf(substring) !== -1;
|
||||
}
|
||||
@@ -2797,6 +2926,7 @@ namespace ts {
|
||||
basePaths: ReadonlyArray<string>;
|
||||
}
|
||||
|
||||
/** @param path directory of the tsconfig.json */
|
||||
export function getFileMatcherPatterns(path: string, excludes: ReadonlyArray<string> | undefined, includes: ReadonlyArray<string> | undefined, useCaseSensitiveFileNames: boolean, currentDirectory: string): FileMatcherPatterns {
|
||||
path = normalizePath(path);
|
||||
currentDirectory = normalizePath(currentDirectory);
|
||||
@@ -2811,16 +2941,20 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
export function getRegexFromPattern(pattern: string, useCaseSensitiveFileNames: boolean): RegExp {
|
||||
return new RegExp(pattern, useCaseSensitiveFileNames ? "" : "i");
|
||||
}
|
||||
|
||||
/** @param path directory of the tsconfig.json */
|
||||
export function matchFiles(path: string, extensions: ReadonlyArray<string> | undefined, excludes: ReadonlyArray<string> | undefined, includes: ReadonlyArray<string> | undefined, useCaseSensitiveFileNames: boolean, currentDirectory: string, depth: number | undefined, getFileSystemEntries: (path: string) => FileSystemEntries): string[] {
|
||||
path = normalizePath(path);
|
||||
currentDirectory = normalizePath(currentDirectory);
|
||||
|
||||
const patterns = getFileMatcherPatterns(path, excludes, includes, useCaseSensitiveFileNames, currentDirectory);
|
||||
|
||||
const regexFlag = useCaseSensitiveFileNames ? "" : "i";
|
||||
const includeFileRegexes = patterns.includeFilePatterns && patterns.includeFilePatterns.map(pattern => new RegExp(pattern, regexFlag));
|
||||
const includeDirectoryRegex = patterns.includeDirectoryPattern && new RegExp(patterns.includeDirectoryPattern, regexFlag);
|
||||
const excludeRegex = patterns.excludePattern && new RegExp(patterns.excludePattern, regexFlag);
|
||||
const includeFileRegexes = patterns.includeFilePatterns && patterns.includeFilePatterns.map(pattern => getRegexFromPattern(pattern, useCaseSensitiveFileNames));
|
||||
const includeDirectoryRegex = patterns.includeDirectoryPattern && getRegexFromPattern(patterns.includeDirectoryPattern, useCaseSensitiveFileNames);
|
||||
const excludeRegex = patterns.excludePattern && getRegexFromPattern(patterns.excludePattern, useCaseSensitiveFileNames);
|
||||
|
||||
// Associate an array of results with each include regex. This keeps results in order of the "include" order.
|
||||
// If there are no "includes", then just put everything in results[0].
|
||||
|
||||
@@ -219,6 +219,10 @@
|
||||
"category": "Error",
|
||||
"code": 1068
|
||||
},
|
||||
"Unexpected token. A type parameter name was expected without curly braces.": {
|
||||
"category": "Error",
|
||||
"code": 1069
|
||||
},
|
||||
"'{0}' modifier cannot appear on a type member.": {
|
||||
"category": "Error",
|
||||
"code": 1070
|
||||
@@ -2365,6 +2369,14 @@
|
||||
"category": "Error",
|
||||
"code": 2725
|
||||
},
|
||||
"Cannot find lib definition for '{0}'.": {
|
||||
"category": "Error",
|
||||
"code": 2726
|
||||
},
|
||||
"Cannot find lib definition for '{0}'. Did you mean '{1}'?": {
|
||||
"category": "Error",
|
||||
"code": 2727
|
||||
},
|
||||
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
const jsFilePath = getOwnEmitOutputFilePath(sourceFile, host, getOutputExtension(sourceFile, options));
|
||||
const sourceMapFilePath = getSourceMapFilePath(jsFilePath, 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 declarationFilePath = ((forceDtsPaths || options.declaration) && !isJs) ? getDeclarationEmitOutputFilePath(sourceFile, host) : undefined;
|
||||
@@ -1458,7 +1458,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None;
|
||||
const allowTrailingComma = currentSourceFile.languageVersion >= ScriptTarget.ES5 ? ListFormat.AllowTrailingComma : ListFormat.None;
|
||||
const allowTrailingComma = currentSourceFile.languageVersion >= ScriptTarget.ES5 && !isJsonSourceFile(currentSourceFile) ? ListFormat.AllowTrailingComma : ListFormat.None;
|
||||
emitList(node, node.properties, ListFormat.ObjectLiteralExpressionProperties | allowTrailingComma | preferNewLine);
|
||||
|
||||
if (indentedFlag) {
|
||||
|
||||
@@ -2432,12 +2432,13 @@ namespace ts {
|
||||
|
||||
// Top-level nodes
|
||||
|
||||
export function updateSourceFileNode(node: SourceFile, statements: ReadonlyArray<Statement>, isDeclarationFile?: boolean, referencedFiles?: SourceFile["referencedFiles"], typeReferences?: SourceFile["typeReferenceDirectives"], hasNoDefaultLib?: boolean) {
|
||||
export function updateSourceFileNode(node: SourceFile, statements: ReadonlyArray<Statement>, isDeclarationFile?: boolean, referencedFiles?: SourceFile["referencedFiles"], typeReferences?: SourceFile["typeReferenceDirectives"], hasNoDefaultLib?: boolean, libReferences?: SourceFile["libReferenceDirectives"]) {
|
||||
if (
|
||||
node.statements !== statements ||
|
||||
(isDeclarationFile !== undefined && node.isDeclarationFile !== isDeclarationFile) ||
|
||||
(referencedFiles !== undefined && node.referencedFiles !== referencedFiles) ||
|
||||
(typeReferences !== undefined && node.typeReferenceDirectives !== typeReferences) ||
|
||||
(libReferences !== undefined && node.libReferenceDirectives !== libReferences) ||
|
||||
(hasNoDefaultLib !== undefined && node.hasNoDefaultLib !== hasNoDefaultLib)
|
||||
) {
|
||||
const updated = <SourceFile>createSynthesizedNode(SyntaxKind.SourceFile);
|
||||
@@ -2451,6 +2452,7 @@ namespace ts {
|
||||
updated.referencedFiles = referencedFiles === undefined ? node.referencedFiles : referencedFiles;
|
||||
updated.typeReferenceDirectives = typeReferences === undefined ? node.typeReferenceDirectives : typeReferences;
|
||||
updated.hasNoDefaultLib = hasNoDefaultLib === undefined ? node.hasNoDefaultLib : hasNoDefaultLib;
|
||||
updated.libReferenceDirectives = libReferences === undefined ? node.libReferenceDirectives : libReferences;
|
||||
if (node.amdDependencies !== undefined) updated.amdDependencies = node.amdDependencies;
|
||||
if (node.moduleName !== undefined) updated.moduleName = node.moduleName;
|
||||
if (node.languageVariant !== undefined) updated.languageVariant = node.languageVariant;
|
||||
|
||||
@@ -132,10 +132,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
export interface GetEffectiveTypeRootsHost {
|
||||
directoryExists?(directoryName: string): boolean;
|
||||
getCurrentDirectory?(): string;
|
||||
}
|
||||
export function getEffectiveTypeRoots(options: CompilerOptions, host: GetEffectiveTypeRootsHost): string[] | undefined {
|
||||
if (options.typeRoots) {
|
||||
return options.typeRoots;
|
||||
|
||||
@@ -0,0 +1,370 @@
|
||||
// Used by importFixes to synthesize import module specifiers.
|
||||
/* @internal */
|
||||
namespace ts.moduleSpecifiers {
|
||||
export interface ModuleSpecifierPreferences {
|
||||
importModuleSpecifierPreference?: "relative" | "non-relative";
|
||||
}
|
||||
|
||||
// Note: fromSourceFile is just for usesJsExtensionOnImports
|
||||
export function getModuleSpecifier(compilerOptions: CompilerOptions, fromSourceFile: SourceFile, fromSourceFileName: string, toFileName: string, host: ModuleSpecifierResolutionHost, preferences: ModuleSpecifierPreferences = {}) {
|
||||
const info = getInfo(compilerOptions, fromSourceFile, fromSourceFileName, host);
|
||||
return getGlobalModuleSpecifier(toFileName, info, host, compilerOptions) ||
|
||||
first(getLocalModuleSpecifiers(toFileName, info, compilerOptions, preferences));
|
||||
}
|
||||
|
||||
// For each symlink/original for a module, returns a list of ways to import that file.
|
||||
export function getModuleSpecifiers(
|
||||
moduleSymbol: Symbol,
|
||||
program: Program,
|
||||
importingSourceFile: SourceFile,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
preferences: ModuleSpecifierPreferences,
|
||||
): ReadonlyArray<ReadonlyArray<string>> {
|
||||
const ambient = tryGetModuleNameFromAmbientModule(moduleSymbol);
|
||||
if (ambient) return [[ambient]];
|
||||
|
||||
const compilerOptions = program.getCompilerOptions();
|
||||
const info = getInfo(compilerOptions, importingSourceFile, importingSourceFile.fileName, host);
|
||||
const modulePaths = getAllModulePaths(program, getSourceFileOfNode(moduleSymbol.valueDeclaration));
|
||||
|
||||
const global = mapDefined(modulePaths, moduleFileName => getGlobalModuleSpecifier(moduleFileName, info, host, compilerOptions));
|
||||
return global.length ? global.map(g => [g]) : modulePaths.map(moduleFileName =>
|
||||
getLocalModuleSpecifiers(moduleFileName, info, compilerOptions, preferences));
|
||||
}
|
||||
|
||||
interface Info {
|
||||
readonly moduleResolutionKind: ModuleResolutionKind;
|
||||
readonly addJsExtension: boolean;
|
||||
readonly getCanonicalFileName: GetCanonicalFileName;
|
||||
readonly sourceDirectory: string;
|
||||
}
|
||||
// importingSourceFileName is separate because getEditsForFileRename may need to specify an updated path
|
||||
function getInfo(compilerOptions: CompilerOptions, importingSourceFile: SourceFile, importingSourceFileName: string, host: ModuleSpecifierResolutionHost): Info {
|
||||
const moduleResolutionKind = getEmitModuleResolutionKind(compilerOptions);
|
||||
const addJsExtension = usesJsExtensionOnImports(importingSourceFile);
|
||||
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames ? host.useCaseSensitiveFileNames() : true);
|
||||
const sourceDirectory = getDirectoryPath(importingSourceFileName);
|
||||
return { moduleResolutionKind, addJsExtension, getCanonicalFileName, sourceDirectory };
|
||||
}
|
||||
|
||||
function getGlobalModuleSpecifier(
|
||||
moduleFileName: string,
|
||||
{ addJsExtension, getCanonicalFileName, sourceDirectory }: Info,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
compilerOptions: CompilerOptions,
|
||||
) {
|
||||
return tryGetModuleNameFromTypeRoots(compilerOptions, host, getCanonicalFileName, moduleFileName, addJsExtension)
|
||||
|| tryGetModuleNameAsNodeModule(compilerOptions, moduleFileName, host, getCanonicalFileName, sourceDirectory)
|
||||
|| compilerOptions.rootDirs && tryGetModuleNameFromRootDirs(compilerOptions.rootDirs, moduleFileName, sourceDirectory, getCanonicalFileName);
|
||||
}
|
||||
|
||||
function getLocalModuleSpecifiers(
|
||||
moduleFileName: string,
|
||||
{ moduleResolutionKind, addJsExtension, getCanonicalFileName, sourceDirectory }: Info,
|
||||
compilerOptions: CompilerOptions,
|
||||
preferences: ModuleSpecifierPreferences,
|
||||
) {
|
||||
const { baseUrl, paths } = compilerOptions;
|
||||
|
||||
const relativePath = removeExtensionAndIndexPostFix(ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, moduleFileName, getCanonicalFileName)), moduleResolutionKind, addJsExtension);
|
||||
if (!baseUrl || preferences.importModuleSpecifierPreference === "relative") {
|
||||
return [relativePath];
|
||||
}
|
||||
|
||||
const relativeToBaseUrl = getRelativePathIfInDirectory(moduleFileName, baseUrl, getCanonicalFileName);
|
||||
if (!relativeToBaseUrl) {
|
||||
return [relativePath];
|
||||
}
|
||||
|
||||
const importRelativeToBaseUrl = removeExtensionAndIndexPostFix(relativeToBaseUrl, moduleResolutionKind, addJsExtension);
|
||||
if (paths) {
|
||||
const fromPaths = tryGetModuleNameFromPaths(removeFileExtension(relativeToBaseUrl), importRelativeToBaseUrl, paths);
|
||||
if (fromPaths) {
|
||||
return [fromPaths];
|
||||
}
|
||||
}
|
||||
|
||||
if (preferences.importModuleSpecifierPreference === "non-relative") {
|
||||
return [importRelativeToBaseUrl];
|
||||
}
|
||||
|
||||
if (preferences.importModuleSpecifierPreference !== undefined) Debug.assertNever(preferences.importModuleSpecifierPreference);
|
||||
|
||||
if (isPathRelativeToParent(relativeToBaseUrl)) {
|
||||
return [relativePath];
|
||||
}
|
||||
|
||||
/*
|
||||
Prefer a relative import over a baseUrl import if it doesn't traverse up to baseUrl.
|
||||
|
||||
Suppose we have:
|
||||
baseUrl = /base
|
||||
sourceDirectory = /base/a/b
|
||||
moduleFileName = /base/foo/bar
|
||||
Then:
|
||||
relativePath = ../../foo/bar
|
||||
getRelativePathNParents(relativePath) = 2
|
||||
pathFromSourceToBaseUrl = ../../
|
||||
getRelativePathNParents(pathFromSourceToBaseUrl) = 2
|
||||
2 < 2 = false
|
||||
In this case we should prefer using the baseUrl path "/a/b" instead of the relative path "../../foo/bar".
|
||||
|
||||
Suppose we have:
|
||||
baseUrl = /base
|
||||
sourceDirectory = /base/foo/a
|
||||
moduleFileName = /base/foo/bar
|
||||
Then:
|
||||
relativePath = ../a
|
||||
getRelativePathNParents(relativePath) = 1
|
||||
pathFromSourceToBaseUrl = ../../
|
||||
getRelativePathNParents(pathFromSourceToBaseUrl) = 2
|
||||
1 < 2 = true
|
||||
In this case we should prefer using the relative path "../a" instead of the baseUrl path "foo/a".
|
||||
*/
|
||||
const pathFromSourceToBaseUrl = ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, baseUrl, getCanonicalFileName));
|
||||
const relativeFirst = getRelativePathNParents(relativePath) < getRelativePathNParents(pathFromSourceToBaseUrl);
|
||||
return relativeFirst ? [relativePath, importRelativeToBaseUrl] : [importRelativeToBaseUrl, relativePath];
|
||||
}
|
||||
|
||||
function usesJsExtensionOnImports({ imports }: SourceFile): boolean {
|
||||
return firstDefined(imports, ({ text }) => pathIsRelative(text) ? fileExtensionIs(text, Extension.Js) : undefined) || false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for a existing imports that use symlinks to this module.
|
||||
* Only if no symlink is available, the real path will be used.
|
||||
*/
|
||||
function getAllModulePaths(program: Program, { fileName }: SourceFile): ReadonlyArray<string> {
|
||||
const symlinks = mapDefined(program.getSourceFiles(), sf =>
|
||||
sf.resolvedModules && firstDefinedIterator(sf.resolvedModules.values(), res =>
|
||||
res && res.resolvedFileName === fileName ? res.originalPath : undefined));
|
||||
return symlinks.length === 0 ? [fileName] : symlinks;
|
||||
}
|
||||
|
||||
function getRelativePathNParents(relativePath: string): number {
|
||||
const components = getPathComponents(relativePath);
|
||||
if (components[0] || components.length === 1) return 0;
|
||||
for (let i = 1; i < components.length; i++) {
|
||||
if (components[i] !== "..") return i - 1;
|
||||
}
|
||||
return components.length - 1;
|
||||
}
|
||||
|
||||
function tryGetModuleNameFromAmbientModule(moduleSymbol: Symbol): string | undefined {
|
||||
const decl = moduleSymbol.valueDeclaration;
|
||||
if (isModuleDeclaration(decl) && isStringLiteral(decl.name)) {
|
||||
return decl.name.text;
|
||||
}
|
||||
}
|
||||
|
||||
function tryGetModuleNameFromPaths(relativeToBaseUrlWithIndex: string, relativeToBaseUrl: string, paths: MapLike<ReadonlyArray<string>>): string | undefined {
|
||||
for (const key in paths) {
|
||||
for (const patternText of paths[key]) {
|
||||
const pattern = removeFileExtension(normalizePath(patternText));
|
||||
const indexOfStar = pattern.indexOf("*");
|
||||
if (indexOfStar === 0 && pattern.length === 1) {
|
||||
continue;
|
||||
}
|
||||
else if (indexOfStar !== -1) {
|
||||
const prefix = pattern.substr(0, indexOfStar);
|
||||
const suffix = pattern.substr(indexOfStar + 1);
|
||||
if (relativeToBaseUrl.length >= prefix.length + suffix.length &&
|
||||
startsWith(relativeToBaseUrl, prefix) &&
|
||||
endsWith(relativeToBaseUrl, suffix)) {
|
||||
const matchedStar = relativeToBaseUrl.substr(prefix.length, relativeToBaseUrl.length - suffix.length);
|
||||
return key.replace("*", matchedStar);
|
||||
}
|
||||
}
|
||||
else if (pattern === relativeToBaseUrl || pattern === relativeToBaseUrlWithIndex) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function tryGetModuleNameFromRootDirs(rootDirs: ReadonlyArray<string>, moduleFileName: string, sourceDirectory: string, getCanonicalFileName: (file: string) => string): string | undefined {
|
||||
const normalizedTargetPath = getPathRelativeToRootDirs(moduleFileName, rootDirs, getCanonicalFileName);
|
||||
if (normalizedTargetPath === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const normalizedSourcePath = getPathRelativeToRootDirs(sourceDirectory, rootDirs, getCanonicalFileName);
|
||||
const relativePath = normalizedSourcePath !== undefined ? ensurePathIsNonModuleName(getRelativePathFromDirectory(normalizedSourcePath, normalizedTargetPath, getCanonicalFileName)) : normalizedTargetPath;
|
||||
return removeFileExtension(relativePath);
|
||||
}
|
||||
|
||||
function tryGetModuleNameFromTypeRoots(
|
||||
options: CompilerOptions,
|
||||
host: GetEffectiveTypeRootsHost,
|
||||
getCanonicalFileName: (file: string) => string,
|
||||
moduleFileName: string,
|
||||
addJsExtension: boolean,
|
||||
): string | undefined {
|
||||
const roots = getEffectiveTypeRoots(options, host);
|
||||
return firstDefined(roots, unNormalizedTypeRoot => {
|
||||
const typeRoot = toPath(unNormalizedTypeRoot, /*basePath*/ undefined, getCanonicalFileName);
|
||||
if (startsWith(moduleFileName, typeRoot)) {
|
||||
// For a type definition, we can strip `/index` even with classic resolution.
|
||||
return removeExtensionAndIndexPostFix(moduleFileName.substring(typeRoot.length + 1), ModuleResolutionKind.NodeJs, addJsExtension);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function tryGetModuleNameAsNodeModule(
|
||||
options: CompilerOptions,
|
||||
moduleFileName: string,
|
||||
host: ModuleSpecifierResolutionHost,
|
||||
getCanonicalFileName: (file: string) => string,
|
||||
sourceDirectory: string,
|
||||
): string | undefined {
|
||||
if (getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeJs) {
|
||||
// nothing to do here
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const parts: NodeModulePathParts = getNodeModulePathParts(moduleFileName)!;
|
||||
|
||||
if (!parts) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// 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
|
||||
const moduleSpecifier = getDirectoryOrExtensionlessFileName(moduleFileName);
|
||||
// Get a path that's relative to node_modules or the importing file's path
|
||||
// if node_modules folder is in this folder or any of its parent folders, no need to keep it.
|
||||
if (!startsWith(sourceDirectory, moduleSpecifier.substring(0, parts.topLevelNodeModulesIndex))) return undefined;
|
||||
// If the module was found in @types, get the actual Node package name
|
||||
return getPackageNameFromAtTypesDirectory(moduleSpecifier.substring(parts.topLevelPackageNameIndex + 1));
|
||||
|
||||
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 (mainExportFile === getCanonicalFileName(path)) {
|
||||
return packageRootPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We still have a file name - remove the extension
|
||||
const fullModulePathWithoutExtension = removeFileExtension(path);
|
||||
|
||||
// If the file is /index, it can be imported by its directory name
|
||||
// IFF there is not _also_ a file by the same name
|
||||
if (getCanonicalFileName(fullModulePathWithoutExtension.substring(parts.fileNameIndex)) === "/index" && !tryGetAnyFileFromPath(host, fullModulePathWithoutExtension.substring(0, parts.fileNameIndex))) {
|
||||
return fullModulePathWithoutExtension.substring(0, parts.fileNameIndex);
|
||||
}
|
||||
|
||||
return fullModulePathWithoutExtension;
|
||||
}
|
||||
}
|
||||
|
||||
function tryGetAnyFileFromPath(host: ModuleSpecifierResolutionHost, path: string) {
|
||||
// We check all js, `node` and `json` extensions in addition to TS, since node module resolution would also choose those over the directory
|
||||
const extensions = getSupportedExtensions({ allowJs: true }, [{ extension: "node", isMixedContent: false }, { extension: "json", isMixedContent: false, scriptKind: ScriptKind.JSON }]);
|
||||
for (const e of extensions) {
|
||||
const fullPath = path + e;
|
||||
if (host.fileExists!(fullPath)) { // TODO: GH#18217
|
||||
return fullPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface NodeModulePathParts {
|
||||
readonly topLevelNodeModulesIndex: number;
|
||||
readonly topLevelPackageNameIndex: number;
|
||||
readonly packageRootIndex: number;
|
||||
readonly fileNameIndex: number;
|
||||
}
|
||||
function getNodeModulePathParts(fullPath: string): NodeModulePathParts | undefined {
|
||||
// If fullPath can't be valid module file within node_modules, returns undefined.
|
||||
// Example of expected pattern: /base/path/node_modules/[@scope/otherpackage/@otherscope/node_modules/]package/[subdirectory/]file.js
|
||||
// Returns indices: ^ ^ ^ ^
|
||||
|
||||
let topLevelNodeModulesIndex = 0;
|
||||
let topLevelPackageNameIndex = 0;
|
||||
let packageRootIndex = 0;
|
||||
let fileNameIndex = 0;
|
||||
|
||||
const enum States {
|
||||
BeforeNodeModules,
|
||||
NodeModules,
|
||||
Scope,
|
||||
PackageContent
|
||||
}
|
||||
|
||||
let partStart = 0;
|
||||
let partEnd = 0;
|
||||
let state = States.BeforeNodeModules;
|
||||
|
||||
while (partEnd >= 0) {
|
||||
partStart = partEnd;
|
||||
partEnd = fullPath.indexOf("/", partStart + 1);
|
||||
switch (state) {
|
||||
case States.BeforeNodeModules:
|
||||
if (fullPath.indexOf("/node_modules/", partStart) === partStart) {
|
||||
topLevelNodeModulesIndex = partStart;
|
||||
topLevelPackageNameIndex = partEnd;
|
||||
state = States.NodeModules;
|
||||
}
|
||||
break;
|
||||
case States.NodeModules:
|
||||
case States.Scope:
|
||||
if (state === States.NodeModules && fullPath.charAt(partStart + 1) === "@") {
|
||||
state = States.Scope;
|
||||
}
|
||||
else {
|
||||
packageRootIndex = partEnd;
|
||||
state = States.PackageContent;
|
||||
}
|
||||
break;
|
||||
case States.PackageContent:
|
||||
if (fullPath.indexOf("/node_modules/", partStart) === partStart) {
|
||||
state = States.NodeModules;
|
||||
}
|
||||
else {
|
||||
state = States.PackageContent;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fileNameIndex = partStart;
|
||||
|
||||
return state > States.NodeModules ? { topLevelNodeModulesIndex, topLevelPackageNameIndex, packageRootIndex, fileNameIndex } : undefined;
|
||||
}
|
||||
|
||||
function getPathRelativeToRootDirs(path: string, rootDirs: ReadonlyArray<string>, getCanonicalFileName: GetCanonicalFileName): string | undefined {
|
||||
return firstDefined(rootDirs, rootDir => {
|
||||
const relativePath = getRelativePathIfInDirectory(path, rootDir, getCanonicalFileName)!; // TODO: GH#18217
|
||||
return isPathRelativeToParent(relativePath) ? undefined : relativePath;
|
||||
});
|
||||
}
|
||||
|
||||
function removeExtensionAndIndexPostFix(fileName: string, moduleResolutionKind: ModuleResolutionKind, addJsExtension: boolean): string {
|
||||
const noExtension = removeFileExtension(fileName);
|
||||
return addJsExtension
|
||||
? noExtension + ".js"
|
||||
: moduleResolutionKind === ModuleResolutionKind.NodeJs
|
||||
? removeSuffix(noExtension, "/index")
|
||||
: noExtension;
|
||||
}
|
||||
|
||||
function getRelativePathIfInDirectory(path: string, directoryPath: string, getCanonicalFileName: GetCanonicalFileName): string | undefined {
|
||||
const relativePath = getRelativePathToDirectoryOrUrl(directoryPath, path, directoryPath, getCanonicalFileName, /*isAbsolutePathAnUrl*/ false);
|
||||
return isRootedDiskPath(relativePath) ? undefined : relativePath;
|
||||
}
|
||||
|
||||
function isPathRelativeToParent(path: string): boolean {
|
||||
return startsWith(path, "..");
|
||||
}
|
||||
}
|
||||
+147
-183
@@ -4,7 +4,6 @@ namespace ts {
|
||||
Yield = 1 << 0,
|
||||
Await = 1 << 1,
|
||||
Type = 1 << 2,
|
||||
RequireCompleteParameterList = 1 << 3,
|
||||
IgnoreMissingOpenBrace = 1 << 4,
|
||||
JSDoc = 1 << 5,
|
||||
}
|
||||
@@ -717,6 +716,7 @@ namespace ts {
|
||||
initializeState(sourceText, languageVersion, syntaxCursor, ScriptKind.JSON);
|
||||
// Set source file so that errors will be reported with this file name
|
||||
sourceFile = createSourceFile(fileName, ScriptTarget.ES2015, ScriptKind.JSON, /*isDeclaration*/ false);
|
||||
sourceFile.flags = contextFlags;
|
||||
|
||||
// Prime the scanner.
|
||||
nextToken();
|
||||
@@ -1256,8 +1256,8 @@ namespace ts {
|
||||
new TokenConstructor(kind, p, p);
|
||||
}
|
||||
|
||||
function createNodeWithJSDoc(kind: SyntaxKind): Node {
|
||||
const node = createNode(kind);
|
||||
function createNodeWithJSDoc(kind: SyntaxKind, pos?: number): Node {
|
||||
const node = createNode(kind, pos);
|
||||
if (scanner.getTokenFlags() & TokenFlags.PrecedingJSDocComment) {
|
||||
addJSDocComment(<HasJSDoc>node);
|
||||
}
|
||||
@@ -2256,6 +2256,24 @@ namespace ts {
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
// If true, we should abort parsing an error function.
|
||||
function typeHasArrowFunctionBlockingParseError(node: TypeNode): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.TypeReference:
|
||||
return nodeIsMissing((node as TypeReferenceNode).typeName);
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.ConstructorType: {
|
||||
const { parameters, type } = node as FunctionOrConstructorTypeNode;
|
||||
// parameters.pos === parameters.end only if we used parseMissingList, else should contain at least `()`
|
||||
return parameters.pos === parameters.end || typeHasArrowFunctionBlockingParseError(type);
|
||||
}
|
||||
case SyntaxKind.ParenthesizedType:
|
||||
return typeHasArrowFunctionBlockingParseError((node as ParenthesizedTypeNode).type);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function parseThisTypePredicate(lhs: ThisTypeNode): TypePredicateNode {
|
||||
nextToken();
|
||||
const node = createNode(SyntaxKind.TypePredicate, lhs.pos) as TypePredicateNode;
|
||||
@@ -2342,7 +2360,7 @@ namespace ts {
|
||||
return finishNode(parameter);
|
||||
}
|
||||
|
||||
function parseJSDocType() {
|
||||
function parseJSDocType(): TypeNode {
|
||||
const dotdotdot = parseOptionalToken(SyntaxKind.DotDotDotToken);
|
||||
let type = parseType();
|
||||
if (dotdotdot) {
|
||||
@@ -2450,6 +2468,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: If returnToken is EqualsGreaterThanToken, `signature.type` will always be defined.
|
||||
* @returns If return type parsing succeeds
|
||||
*/
|
||||
function fillSignature(
|
||||
@@ -2459,12 +2478,12 @@ namespace ts {
|
||||
if (!(flags & SignatureFlags.JSDoc)) {
|
||||
signature.typeParameters = parseTypeParameters();
|
||||
}
|
||||
signature.parameters = parseParameterList(flags)!; // TODO: GH#18217
|
||||
const parametersParsedSuccessfully = parseParameterList(signature, flags);
|
||||
if (shouldParseReturnType(returnToken, !!(flags & SignatureFlags.Type))) {
|
||||
signature.type = parseTypeOrTypePredicate();
|
||||
return signature.type !== undefined;
|
||||
if (typeHasArrowFunctionBlockingParseError(signature.type)) return false;
|
||||
}
|
||||
return true;
|
||||
return parametersParsedSuccessfully;
|
||||
}
|
||||
|
||||
function shouldParseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): boolean {
|
||||
@@ -2484,7 +2503,8 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
function parseParameterList(flags: SignatureFlags) {
|
||||
// Returns true on success.
|
||||
function parseParameterList(signature: SignatureDeclaration, flags: SignatureFlags): boolean {
|
||||
// FormalParameters [Yield,Await]: (modified)
|
||||
// [empty]
|
||||
// FormalParameterList[?Yield,Await]
|
||||
@@ -2498,31 +2518,23 @@ namespace ts {
|
||||
//
|
||||
// SingleNameBinding [Yield,Await]:
|
||||
// BindingIdentifier[?Yield,?Await]Initializer [In, ?Yield,?Await] opt
|
||||
if (parseExpected(SyntaxKind.OpenParenToken)) {
|
||||
const savedYieldContext = inYieldContext();
|
||||
const savedAwaitContext = inAwaitContext();
|
||||
|
||||
setYieldContext(!!(flags & SignatureFlags.Yield));
|
||||
setAwaitContext(!!(flags & SignatureFlags.Await));
|
||||
|
||||
const result = parseDelimitedList(ParsingContext.Parameters, flags & SignatureFlags.JSDoc ? parseJSDocParameter : parseParameter);
|
||||
|
||||
setYieldContext(savedYieldContext);
|
||||
setAwaitContext(savedAwaitContext);
|
||||
|
||||
if (!parseExpected(SyntaxKind.CloseParenToken) && (flags & SignatureFlags.RequireCompleteParameterList)) {
|
||||
// Caller insisted that we had to end with a ) We didn't. So just return
|
||||
// undefined here.
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return result;
|
||||
if (!parseExpected(SyntaxKind.OpenParenToken)) {
|
||||
signature.parameters = createMissingList<ParameterDeclaration>();
|
||||
return false;
|
||||
}
|
||||
|
||||
// We didn't even have an open paren. If the caller requires a complete parameter list,
|
||||
// we definitely can't provide that. However, if they're ok with an incomplete one,
|
||||
// then just return an empty set of parameters.
|
||||
return (flags & SignatureFlags.RequireCompleteParameterList) ? undefined : createMissingList<ParameterDeclaration>();
|
||||
const savedYieldContext = inYieldContext();
|
||||
const savedAwaitContext = inAwaitContext();
|
||||
|
||||
setYieldContext(!!(flags & SignatureFlags.Yield));
|
||||
setAwaitContext(!!(flags & SignatureFlags.Await));
|
||||
|
||||
signature.parameters = parseDelimitedList(ParsingContext.Parameters, flags & SignatureFlags.JSDoc ? parseJSDocParameter : parseParameter);
|
||||
|
||||
setYieldContext(savedYieldContext);
|
||||
setAwaitContext(savedAwaitContext);
|
||||
|
||||
return parseExpected(SyntaxKind.CloseParenToken);
|
||||
}
|
||||
|
||||
function parseTypeMemberSemicolon() {
|
||||
@@ -2771,28 +2783,19 @@ namespace ts {
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parseParenthesizedType(): ParenthesizedTypeNode {
|
||||
function parseParenthesizedType(): TypeNode {
|
||||
const node = <ParenthesizedTypeNode>createNode(SyntaxKind.ParenthesizedType);
|
||||
parseExpected(SyntaxKind.OpenParenToken);
|
||||
node.type = parseType();
|
||||
if (!node.type) {
|
||||
return undefined!; // TODO: GH#18217
|
||||
}
|
||||
parseExpected(SyntaxKind.CloseParenToken);
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parseFunctionOrConstructorType(kind: SyntaxKind): FunctionOrConstructorTypeNode | undefined {
|
||||
const node = <FunctionOrConstructorTypeNode>createNodeWithJSDoc(kind);
|
||||
if (kind === SyntaxKind.ConstructorType) {
|
||||
parseExpected(SyntaxKind.NewKeyword);
|
||||
}
|
||||
if (!fillSignature(SyntaxKind.EqualsGreaterThanToken, SignatureFlags.Type | (sourceFile.languageVariant === LanguageVariant.JSX ? SignatureFlags.RequireCompleteParameterList : 0), node)) {
|
||||
return undefined;
|
||||
}
|
||||
if (!node.parameters) {
|
||||
return undefined;
|
||||
}
|
||||
function parseFunctionOrConstructorType(): TypeNode {
|
||||
const pos = getNodePos();
|
||||
const kind = parseOptional(SyntaxKind.NewKeyword) ? SyntaxKind.ConstructorType : SyntaxKind.FunctionType;
|
||||
const node = <FunctionOrConstructorTypeNode>createNodeWithJSDoc(kind, pos);
|
||||
fillSignature(SyntaxKind.EqualsGreaterThanToken, SignatureFlags.Type, node);
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
@@ -3133,11 +3136,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
function parseTypeWorker(noConditionalTypes?: boolean): TypeNode {
|
||||
if (isStartOfFunctionType()) {
|
||||
return parseFunctionOrConstructorType(SyntaxKind.FunctionType)!; // TODO: GH#18217
|
||||
}
|
||||
if (token() === SyntaxKind.NewKeyword) {
|
||||
return parseFunctionOrConstructorType(SyntaxKind.ConstructorType)!;
|
||||
if (isStartOfFunctionType() || token() === SyntaxKind.NewKeyword) {
|
||||
return parseFunctionOrConstructorType();
|
||||
}
|
||||
const type = parseUnionTypeOrHigher();
|
||||
if (!noConditionalTypes && !scanner.hasPrecedingLineBreak() && parseOptional(SyntaxKind.ExtendsKeyword)) {
|
||||
@@ -3625,12 +3625,7 @@ namespace ts {
|
||||
// a => (b => c)
|
||||
// And think that "(b =>" was actually a parenthesized arrow function with a missing
|
||||
// close paren.
|
||||
if (!fillSignature(SyntaxKind.ColonToken, isAsync | (allowAmbiguity ? SignatureFlags.None : SignatureFlags.RequireCompleteParameterList), node)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// If we couldn't get parameters, we definitely could not parse out an arrow function.
|
||||
if (!node.parameters) {
|
||||
if (!fillSignature(SyntaxKind.ColonToken, isAsync, node) && !allowAmbiguity) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -4147,27 +4142,6 @@ namespace ts {
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function tagNamesAreEquivalent(lhs: JsxTagNameExpression, rhs: JsxTagNameExpression): boolean {
|
||||
if (lhs.kind !== rhs.kind) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lhs.kind === SyntaxKind.Identifier) {
|
||||
return (<Identifier>lhs).escapedText === (<Identifier>rhs).escapedText;
|
||||
}
|
||||
|
||||
if (lhs.kind === SyntaxKind.ThisKeyword) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we are at this statement then we must have PropertyAccessExpression and because tag name in Jsx element can only
|
||||
// take forms of JsxTagNameExpression which includes an identifier, "this" expression, or another propertyAccessExpression
|
||||
// it is safe to case the expression property as such. See parseJsxElementName for how we parse tag name in Jsx element
|
||||
return (<PropertyAccessExpression>lhs).name.escapedText === (<PropertyAccessExpression>rhs).name.escapedText &&
|
||||
tagNamesAreEquivalent((<PropertyAccessExpression>lhs).expression as JsxTagNameExpression, (<PropertyAccessExpression>rhs).expression as JsxTagNameExpression);
|
||||
}
|
||||
|
||||
|
||||
function parseJsxElementOrSelfClosingElementOrFragment(inExpressionContext: boolean): JsxElement | JsxSelfClosingElement | JsxFragment {
|
||||
const opening = parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext);
|
||||
let result: JsxElement | JsxSelfClosingElement | JsxFragment;
|
||||
@@ -6385,17 +6359,14 @@ namespace ts {
|
||||
indent += text.length;
|
||||
}
|
||||
|
||||
let t = nextJSDocToken();
|
||||
while (t === SyntaxKind.WhitespaceTrivia) {
|
||||
t = nextJSDocToken();
|
||||
}
|
||||
if (t === SyntaxKind.NewLineTrivia) {
|
||||
nextJSDocToken();
|
||||
while (parseOptionalJsdoc(SyntaxKind.WhitespaceTrivia));
|
||||
if (parseOptionalJsdoc(SyntaxKind.NewLineTrivia)) {
|
||||
state = JSDocState.BeginningOfLine;
|
||||
indent = 0;
|
||||
t = nextJSDocToken();
|
||||
}
|
||||
loop: while (true) {
|
||||
switch (t) {
|
||||
switch (token()) {
|
||||
case SyntaxKind.AtToken:
|
||||
if (state === JSDocState.BeginningOfLine || state === JSDocState.SawAsterisk) {
|
||||
removeTrailingNewlines(comments);
|
||||
@@ -6455,12 +6426,11 @@ namespace ts {
|
||||
pushComment(scanner.getTokenText());
|
||||
break;
|
||||
}
|
||||
t = nextJSDocToken();
|
||||
nextJSDocToken();
|
||||
}
|
||||
removeLeadingNewlines(comments);
|
||||
removeTrailingNewlines(comments);
|
||||
result = createJSDocComment();
|
||||
|
||||
});
|
||||
|
||||
return result;
|
||||
@@ -6516,54 +6486,42 @@ namespace ts {
|
||||
|
||||
const tagName = parseJSDocIdentifierName();
|
||||
skipWhitespace();
|
||||
if (!tagName) {
|
||||
return;
|
||||
}
|
||||
|
||||
let tag: JSDocTag | undefined;
|
||||
if (tagName) {
|
||||
switch (tagName.escapedText) {
|
||||
case "augments":
|
||||
case "extends":
|
||||
tag = parseAugmentsTag(atToken, tagName);
|
||||
break;
|
||||
case "class":
|
||||
case "constructor":
|
||||
tag = parseClassTag(atToken, tagName);
|
||||
break;
|
||||
case "arg":
|
||||
case "argument":
|
||||
case "param":
|
||||
return parseParameterOrPropertyTag(atToken, tagName, PropertyLikeParse.Parameter, indent);
|
||||
case "return":
|
||||
case "returns":
|
||||
tag = parseReturnTag(atToken, tagName);
|
||||
break;
|
||||
case "template":
|
||||
tag = parseTemplateTag(atToken, tagName);
|
||||
break;
|
||||
case "type":
|
||||
tag = parseTypeTag(atToken, tagName);
|
||||
break;
|
||||
case "typedef":
|
||||
tag = parseTypedefTag(atToken, tagName, indent);
|
||||
break;
|
||||
case "callback":
|
||||
tag = parseCallbackTag(atToken, tagName, indent);
|
||||
break;
|
||||
default:
|
||||
tag = parseUnknownTag(atToken, tagName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
tag = parseUnknownTag(atToken, tagName);
|
||||
switch (tagName.escapedText) {
|
||||
case "augments":
|
||||
case "extends":
|
||||
tag = parseAugmentsTag(atToken, tagName);
|
||||
break;
|
||||
case "class":
|
||||
case "constructor":
|
||||
tag = parseClassTag(atToken, tagName);
|
||||
break;
|
||||
case "arg":
|
||||
case "argument":
|
||||
case "param":
|
||||
return parseParameterOrPropertyTag(atToken, tagName, PropertyLikeParse.Parameter, indent);
|
||||
case "return":
|
||||
case "returns":
|
||||
tag = parseReturnTag(atToken, tagName);
|
||||
break;
|
||||
case "template":
|
||||
tag = parseTemplateTag(atToken, tagName);
|
||||
break;
|
||||
case "type":
|
||||
tag = parseTypeTag(atToken, tagName);
|
||||
break;
|
||||
case "typedef":
|
||||
tag = parseTypedefTag(atToken, tagName, indent);
|
||||
break;
|
||||
case "callback":
|
||||
tag = parseCallbackTag(atToken, tagName, indent);
|
||||
break;
|
||||
default:
|
||||
tag = parseUnknownTag(atToken, tagName);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!tag) {
|
||||
// a badly malformed tag should not be added to the list of tags
|
||||
return;
|
||||
}
|
||||
if (!tag.comment) {
|
||||
// some tags, like typedef and callback, have already parsed their comments earlier
|
||||
tag.comment = parseTagComments(indent + tag.end - tag.pos);
|
||||
@@ -6793,11 +6751,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
function parsePropertyAccessEntityNameExpression() {
|
||||
let node: Identifier | PropertyAccessEntityNameExpression = parseJSDocIdentifierName(/*createIfMissing*/ true);
|
||||
let node: Identifier | PropertyAccessEntityNameExpression = parseJSDocIdentifierName();
|
||||
while (parseOptional(SyntaxKind.DotToken)) {
|
||||
const prop: PropertyAccessEntityNameExpression = createNode(SyntaxKind.PropertyAccessExpression, node.pos) as PropertyAccessEntityNameExpression;
|
||||
prop.expression = node;
|
||||
prop.name = parseJSDocIdentifierName()!; // TODO: GH#18217
|
||||
prop.name = parseJSDocIdentifierName();
|
||||
node = finishNode(prop);
|
||||
}
|
||||
return node;
|
||||
@@ -6862,9 +6820,11 @@ namespace ts {
|
||||
|
||||
function parseJSDocTypeNameWithNamespace(nested?: boolean) {
|
||||
const pos = scanner.getTokenPos();
|
||||
if (!tokenIsIdentifierOrKeyword(token())) {
|
||||
return undefined;
|
||||
}
|
||||
const typeNameOrNamespaceName = parseJSDocIdentifierName();
|
||||
|
||||
if (typeNameOrNamespaceName && parseOptional(SyntaxKind.DotToken)) {
|
||||
if (parseOptional(SyntaxKind.DotToken)) {
|
||||
const jsDocNamespaceNode = <JSDocNamespaceDeclaration>createNode(SyntaxKind.ModuleDeclaration, pos);
|
||||
if (nested) {
|
||||
jsDocNamespaceNode.flags |= NodeFlags.NestedNamespace;
|
||||
@@ -6874,7 +6834,7 @@ namespace ts {
|
||||
return finishNode(jsDocNamespaceNode);
|
||||
}
|
||||
|
||||
if (typeNameOrNamespaceName && nested) {
|
||||
if (nested) {
|
||||
typeNameOrNamespaceName.isInJSDocNamespace = true;
|
||||
}
|
||||
return typeNameOrNamespaceName;
|
||||
@@ -6897,8 +6857,7 @@ namespace ts {
|
||||
jsdocSignature.parameters = append(jsdocSignature.parameters as MutableNodeArray<JSDocParameterTag>, child);
|
||||
}
|
||||
const returnTag = tryParse(() => {
|
||||
if (token() === SyntaxKind.AtToken) {
|
||||
nextJSDocToken();
|
||||
if (parseOptionalJsdoc(SyntaxKind.AtToken)) {
|
||||
const tag = parseTag(indent);
|
||||
if (tag && tag.kind === SyntaxKind.JSDocReturnTag) {
|
||||
return tag as JSDocReturnTag;
|
||||
@@ -6985,9 +6944,6 @@ namespace ts {
|
||||
|
||||
const tagName = parseJSDocIdentifierName();
|
||||
skipWhitespace();
|
||||
if (!tagName) {
|
||||
return false;
|
||||
}
|
||||
let t: PropertyLikeParse;
|
||||
switch (tagName.escapedText) {
|
||||
case "type":
|
||||
@@ -7012,36 +6968,26 @@ namespace ts {
|
||||
return tag;
|
||||
}
|
||||
|
||||
function parseTemplateTag(atToken: AtToken, tagName: Identifier): JSDocTemplateTag | undefined {
|
||||
if (some(tags, isJSDocTemplateTag)) {
|
||||
parseErrorAt(tagName.pos, scanner.getTokenPos(), Diagnostics._0_tag_already_specified, tagName.escapedText);
|
||||
function parseTemplateTag(atToken: AtToken, tagName: Identifier): JSDocTemplateTag {
|
||||
// the template tag looks like '@template {Constraint} T,U,V'
|
||||
let constraint: JSDocTypeExpression | undefined;
|
||||
if (token() === SyntaxKind.OpenBraceToken) {
|
||||
constraint = parseJSDocTypeExpression();
|
||||
}
|
||||
|
||||
// Type parameter list looks like '@template T,U,V'
|
||||
const typeParameters = [];
|
||||
const typeParametersPos = getNodePos();
|
||||
|
||||
while (true) {
|
||||
do {
|
||||
skipWhitespace();
|
||||
const typeParameter = <TypeParameterDeclaration>createNode(SyntaxKind.TypeParameter);
|
||||
const name = parseJSDocIdentifierNameWithOptionalBraces();
|
||||
typeParameter.name = parseJSDocIdentifierName(Diagnostics.Unexpected_token_A_type_parameter_name_was_expected_without_curly_braces);
|
||||
skipWhitespace();
|
||||
if (!name) {
|
||||
parseErrorAtPosition(scanner.getStartPos(), 0, Diagnostics.Identifier_expected);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
typeParameter.name = name;
|
||||
finishNode(typeParameter);
|
||||
|
||||
typeParameters.push(typeParameter);
|
||||
} while (parseOptionalJsdoc(SyntaxKind.CommaToken));
|
||||
|
||||
if (token() === SyntaxKind.CommaToken) {
|
||||
nextJSDocToken();
|
||||
skipWhitespace();
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
if (constraint) {
|
||||
first(typeParameters).constraint = constraint.type;
|
||||
}
|
||||
|
||||
const result = <JSDocTemplateTag>createNode(SyntaxKind.JSDocTemplateTag, atToken.pos);
|
||||
@@ -7052,21 +6998,20 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
function parseJSDocIdentifierNameWithOptionalBraces(): Identifier | undefined {
|
||||
const parsedBrace = parseOptional(SyntaxKind.OpenBraceToken);
|
||||
const res = parseJSDocIdentifierName();
|
||||
if (parsedBrace) {
|
||||
parseExpected(SyntaxKind.CloseBraceToken);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function nextJSDocToken(): JsDocSyntaxKind {
|
||||
return currentToken = scanner.scanJSDocToken();
|
||||
}
|
||||
|
||||
function parseOptionalJsdoc(t: JsDocSyntaxKind): boolean {
|
||||
if (token() === t) {
|
||||
nextJSDocToken();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function parseJSDocEntityName(): EntityName {
|
||||
let entity: EntityName = parseJSDocIdentifierName(/*createIfMissing*/ true);
|
||||
let entity: EntityName = parseJSDocIdentifierName();
|
||||
if (parseOptional(SyntaxKind.OpenBracketToken)) {
|
||||
parseExpected(SyntaxKind.CloseBracketToken);
|
||||
// Note that y[] is accepted as an entity name, but the postfix brackets are not saved for checking.
|
||||
@@ -7074,7 +7019,7 @@ namespace ts {
|
||||
// but it's not worth it to enforce that restriction.
|
||||
}
|
||||
while (parseOptional(SyntaxKind.DotToken)) {
|
||||
const name = parseJSDocIdentifierName(/*createIfMissing*/ true);
|
||||
const name = parseJSDocIdentifierName();
|
||||
if (parseOptional(SyntaxKind.OpenBracketToken)) {
|
||||
parseExpected(SyntaxKind.CloseBracketToken);
|
||||
}
|
||||
@@ -7083,17 +7028,9 @@ namespace ts {
|
||||
return entity;
|
||||
}
|
||||
|
||||
function parseJSDocIdentifierName(): Identifier | undefined;
|
||||
function parseJSDocIdentifierName(createIfMissing: true): Identifier;
|
||||
function parseJSDocIdentifierName(createIfMissing = false): Identifier | undefined {
|
||||
function parseJSDocIdentifierName(message?: DiagnosticMessage): Identifier {
|
||||
if (!tokenIsIdentifierOrKeyword(token())) {
|
||||
if (createIfMissing) {
|
||||
return createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected);
|
||||
}
|
||||
else {
|
||||
parseErrorAtCurrentToken(Diagnostics.Identifier_expected);
|
||||
return undefined;
|
||||
}
|
||||
return createMissingNode<Identifier>(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ !message, message || Diagnostics.Identifier_expected);
|
||||
}
|
||||
|
||||
const pos = scanner.getTokenPos();
|
||||
@@ -7691,6 +7628,7 @@ namespace ts {
|
||||
checkJsDirective?: CheckJsDirective;
|
||||
referencedFiles: FileReference[];
|
||||
typeReferenceDirectives: FileReference[];
|
||||
libReferenceDirectives: FileReference[];
|
||||
amdDependencies: AmdDependency[];
|
||||
hasNoDefaultLib?: boolean;
|
||||
moduleName?: string;
|
||||
@@ -7744,6 +7682,7 @@ namespace ts {
|
||||
context.checkJsDirective = undefined;
|
||||
context.referencedFiles = [];
|
||||
context.typeReferenceDirectives = [];
|
||||
context.libReferenceDirectives = [];
|
||||
context.amdDependencies = [];
|
||||
context.hasNoDefaultLib = false;
|
||||
context.pragmas!.forEach((entryOrList, key) => { // TODO: GH#18217
|
||||
@@ -7753,6 +7692,7 @@ namespace ts {
|
||||
case "reference": {
|
||||
const referencedFiles = context.referencedFiles;
|
||||
const typeReferenceDirectives = context.typeReferenceDirectives;
|
||||
const libReferenceDirectives = context.libReferenceDirectives;
|
||||
forEach(toArray(entryOrList), (arg: PragmaPsuedoMap["reference"]) => {
|
||||
// TODO: GH#18217
|
||||
if (arg!.arguments["no-default-lib"]) {
|
||||
@@ -7761,6 +7701,9 @@ namespace ts {
|
||||
else if (arg!.arguments.types) {
|
||||
typeReferenceDirectives.push({ pos: arg!.arguments.types!.pos, end: arg!.arguments.types!.end, fileName: arg!.arguments.types!.value });
|
||||
}
|
||||
else if (arg!.arguments.lib) {
|
||||
libReferenceDirectives.push({ pos: arg!.arguments.lib!.pos, end: arg!.arguments.lib!.end, fileName: arg!.arguments.lib!.value });
|
||||
}
|
||||
else if (arg!.arguments.path) {
|
||||
referencedFiles.push({ pos: arg!.arguments.path!.pos, end: arg!.arguments.path!.end, fileName: arg!.arguments.path!.value });
|
||||
}
|
||||
@@ -7906,4 +7849,25 @@ namespace ts {
|
||||
}
|
||||
return argMap;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function tagNamesAreEquivalent(lhs: JsxTagNameExpression, rhs: JsxTagNameExpression): boolean {
|
||||
if (lhs.kind !== rhs.kind) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lhs.kind === SyntaxKind.Identifier) {
|
||||
return (<Identifier>lhs).escapedText === (<Identifier>rhs).escapedText;
|
||||
}
|
||||
|
||||
if (lhs.kind === SyntaxKind.ThisKeyword) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we are at this statement then we must have PropertyAccessExpression and because tag name in Jsx element can only
|
||||
// take forms of JsxTagNameExpression which includes an identifier, "this" expression, or another propertyAccessExpression
|
||||
// it is safe to case the expression property as such. See parseJsxElementName for how we parse tag name in Jsx element
|
||||
return (<PropertyAccessExpression>lhs).name.escapedText === (<PropertyAccessExpression>rhs).name.escapedText &&
|
||||
tagNamesAreEquivalent((<PropertyAccessExpression>lhs).expression as JsxTagNameExpression, (<PropertyAccessExpression>rhs).expression as JsxTagNameExpression);
|
||||
}
|
||||
}
|
||||
|
||||
Executable → Regular
+99
-24
@@ -491,6 +491,17 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new 'Program' instance. A Program is an immutable collection of 'SourceFile's and a 'CompilerOptions'
|
||||
* that represent a compilation unit.
|
||||
*
|
||||
* Creating a program proceeds from a set of root files, expanding the set of inputs by following imports and
|
||||
* triple-slash-reference-path directives transitively. '@types' and triple-slash-reference-types are also pulled in.
|
||||
*
|
||||
* @param createProgramOptions - The options for creating a program.
|
||||
* @returns A 'Program' object.
|
||||
*/
|
||||
export function createProgram(createProgramOptions: CreateProgramOptions): Program;
|
||||
/**
|
||||
* Create a new 'Program' instance. A Program is an immutable collection of 'SourceFile's and a 'CompilerOptions'
|
||||
* that represent a compilation unit.
|
||||
@@ -505,7 +516,6 @@ namespace ts {
|
||||
* @param configFileParsingDiagnostics - error during config file parsing
|
||||
* @returns A 'Program' object.
|
||||
*/
|
||||
export function createProgram(createProgramOptions: CreateProgramOptions): Program;
|
||||
export function createProgram(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): Program;
|
||||
export function createProgram(rootNamesOrOptions: ReadonlyArray<string> | CreateProgramOptions, _options?: CompilerOptions, _host?: CompilerHost, _oldProgram?: Program, _configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): Program {
|
||||
const createProgramOptions = isArray(rootNamesOrOptions) ? createCreateProgramOptions(rootNamesOrOptions, _options!, _host, _oldProgram, _configFileParsingDiagnostics) : rootNamesOrOptions; // TODO: GH#18217
|
||||
@@ -513,7 +523,9 @@ namespace ts {
|
||||
let { oldProgram } = createProgramOptions;
|
||||
|
||||
let program: Program;
|
||||
let files: SourceFile[] = [];
|
||||
let processingDefaultLibFiles: SourceFile[] | undefined;
|
||||
let processingOtherFiles: SourceFile[] | undefined;
|
||||
let files: SourceFile[];
|
||||
let commonSourceDirectory: string;
|
||||
let diagnosticsProducingTypeChecker: TypeChecker;
|
||||
let noDiagnosticsTypeChecker: TypeChecker;
|
||||
@@ -613,7 +625,7 @@ namespace ts {
|
||||
if (parsedRef) {
|
||||
if (parsedRef.commandLine.options.outFile) {
|
||||
const dtsOutfile = changeExtension(parsedRef.commandLine.options.outFile, ".d.ts");
|
||||
processSourceFile(dtsOutfile, /*isDefaultLib*/ false, /*packageId*/ undefined);
|
||||
processSourceFile(dtsOutfile, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined);
|
||||
}
|
||||
addProjectReferenceRedirects(parsedRef.commandLine, projectReferenceRedirects);
|
||||
}
|
||||
@@ -623,7 +635,9 @@ namespace ts {
|
||||
const shouldCreateNewSourceFile = shouldProgramCreateNewSourceFiles(oldProgram, options);
|
||||
const structuralIsReused = tryReuseStructureFromOldProgram();
|
||||
if (structuralIsReused !== StructureIsReused.Completely) {
|
||||
forEach(rootNames, name => processRootFile(name, /*isDefaultLib*/ false));
|
||||
processingDefaultLibFiles = [];
|
||||
processingOtherFiles = [];
|
||||
forEach(rootNames, name => processRootFile(name, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false));
|
||||
|
||||
// load type declarations specified via 'types' argument or implicitly from types/ and node_modules/@types folders
|
||||
const typeReferences: string[] = getAutomaticTypeDirectiveNames(options, host);
|
||||
@@ -647,16 +661,19 @@ namespace ts {
|
||||
// otherwise, using options specified in '--lib' instead of '--target' default library file
|
||||
const defaultLibraryFileName = getDefaultLibraryFileName();
|
||||
if (!options.lib && defaultLibraryFileName) {
|
||||
processRootFile(defaultLibraryFileName, /*isDefaultLib*/ true);
|
||||
processRootFile(defaultLibraryFileName, /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ false);
|
||||
}
|
||||
else {
|
||||
forEach(options.lib, libFileName => {
|
||||
processRootFile(combinePaths(defaultLibraryPath, libFileName), /*isDefaultLib*/ true);
|
||||
processRootFile(combinePaths(defaultLibraryPath, libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
missingFilePaths = arrayFrom(filesByName.keys(), p => <Path>p).filter(p => !filesByName.get(p));
|
||||
files = stableSort(processingDefaultLibFiles, compareDefaultLibFiles).concat(processingOtherFiles);
|
||||
processingDefaultLibFiles = undefined;
|
||||
processingOtherFiles = undefined;
|
||||
}
|
||||
|
||||
Debug.assert(!!missingFilePaths);
|
||||
@@ -686,6 +703,7 @@ namespace ts {
|
||||
getOptionsDiagnostics,
|
||||
getGlobalDiagnostics,
|
||||
getSemanticDiagnostics,
|
||||
getSuggestionDiagnostics,
|
||||
getDeclarationDiagnostics,
|
||||
getTypeChecker,
|
||||
getClassifiableNames,
|
||||
@@ -703,6 +721,7 @@ namespace ts {
|
||||
isSourceFileDefaultLibrary,
|
||||
dropDiagnosticsProducingTypeChecker,
|
||||
getSourceFileFromReference,
|
||||
getLibFileFromReference,
|
||||
sourceFileToPackageName,
|
||||
redirectTargetsSet,
|
||||
isEmittedFile,
|
||||
@@ -717,6 +736,21 @@ namespace ts {
|
||||
|
||||
return program;
|
||||
|
||||
function compareDefaultLibFiles(a: SourceFile, b: SourceFile) {
|
||||
return compareValues(getDefaultLibFilePriority(a), getDefaultLibFilePriority(b));
|
||||
}
|
||||
|
||||
function getDefaultLibFilePriority(a: SourceFile) {
|
||||
if (containsPath(defaultLibraryPath, a.fileName, /*ignoreCase*/ false)) {
|
||||
const basename = getBaseFileName(a.fileName);
|
||||
if (basename === "lib.d.ts" || basename === "lib.es6.d.ts") return 0;
|
||||
const name = removeSuffix(removePrefix(basename, "lib."), ".d.ts");
|
||||
const index = libs.indexOf(name);
|
||||
if (index !== -1) return index + 1;
|
||||
}
|
||||
return libs.length + 2;
|
||||
}
|
||||
|
||||
function getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string): ResolvedModuleWithFailedLookupLocations | undefined {
|
||||
return moduleResolutionCache && resolveModuleNameFromCache(moduleName, containingFile, moduleResolutionCache);
|
||||
}
|
||||
@@ -1039,6 +1073,11 @@ namespace ts {
|
||||
if (fileChanged) {
|
||||
// The `newSourceFile` object was created for the new program.
|
||||
|
||||
if (!arrayIsEqualTo(oldSourceFile.libReferenceDirectives, newSourceFile.libReferenceDirectives, fileReferenceIsEqualTo)) {
|
||||
// 'lib' references has changed. Matches behavior in changesAffectModuleResolution
|
||||
return oldProgram.structureIsReused = StructureIsReused.Not;
|
||||
}
|
||||
|
||||
if (oldSourceFile.hasNoDefaultLib !== newSourceFile.hasNoDefaultLib) {
|
||||
// value of no-default-lib has changed
|
||||
// this will affect if default library is injected into the list of files
|
||||
@@ -1171,6 +1210,9 @@ namespace ts {
|
||||
writeFile: writeFileCallback || (
|
||||
(fileName, data, writeByteOrderMark, onError, sourceFiles) => host.writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles)),
|
||||
isEmitBlocked,
|
||||
readFile: f => host.readFile(f),
|
||||
fileExists: f => host.fileExists(f),
|
||||
...(host.directoryExists ? { directoryExists: f => host.directoryExists!(f) } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1427,6 +1469,12 @@ namespace ts {
|
||||
});
|
||||
}
|
||||
|
||||
function getSuggestionDiagnostics(sourceFile: SourceFile, cancellationToken: CancellationToken): ReadonlyArray<DiagnosticWithLocation> {
|
||||
return runWithCancellationToken(() => {
|
||||
return getDiagnosticsProducingTypeChecker().getSuggestionDiagnostics(sourceFile, cancellationToken);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip errors if previous line start with '// @ts-ignore' comment, not counting non-empty non-comment lines
|
||||
*/
|
||||
@@ -1696,8 +1744,8 @@ namespace ts {
|
||||
return configFileParsingDiagnostics || emptyArray;
|
||||
}
|
||||
|
||||
function processRootFile(fileName: string, isDefaultLib: boolean) {
|
||||
processSourceFile(normalizePath(fileName), isDefaultLib, /*packageId*/ undefined);
|
||||
function processRootFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean) {
|
||||
processSourceFile(normalizePath(fileName), isDefaultLib, ignoreNoDefaultLib, /*packageId*/ undefined);
|
||||
}
|
||||
|
||||
function fileReferenceIsEqualTo(a: FileReference, b: FileReference): boolean {
|
||||
@@ -1807,11 +1855,9 @@ namespace ts {
|
||||
else if (isLiteralImportTypeNode(node)) {
|
||||
imports = append(imports, node.argument.literal);
|
||||
}
|
||||
else {
|
||||
collectDynamicImportOrRequireCallsForEachChild(node);
|
||||
if (hasJSDocNodes(node)) {
|
||||
forEach(node.jsDoc, collectDynamicImportOrRequireCallsForEachChild);
|
||||
}
|
||||
collectDynamicImportOrRequireCallsForEachChild(node);
|
||||
if (hasJSDocNodes(node)) {
|
||||
forEach(node.jsDoc, collectDynamicImportOrRequireCallsForEachChild);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1820,6 +1866,14 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getLibFileFromReference(ref: FileReference) {
|
||||
const libName = ref.fileName.toLocaleLowerCase();
|
||||
const libFileName = libMap.get(libName);
|
||||
if (libFileName) {
|
||||
return getSourceFile(combinePaths(defaultLibraryPath, libFileName));
|
||||
}
|
||||
}
|
||||
|
||||
/** This should have similar behavior to 'processSourceFile' without diagnostics or mutation. */
|
||||
function getSourceFileFromReference(referencingFile: SourceFile, ref: FileReference): SourceFile | undefined {
|
||||
return getSourceFileFromReferenceWorker(resolveTripleslashReference(ref.fileName, referencingFile.fileName), fileName => filesByName.get(toPath(fileName)));
|
||||
@@ -1870,9 +1924,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
/** This has side effects through `findSourceFile`. */
|
||||
function processSourceFile(fileName: string, isDefaultLib: boolean, packageId: PackageId | undefined, refFile?: SourceFile, refPos?: number, refEnd?: number): void {
|
||||
function processSourceFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, packageId: PackageId | undefined, refFile?: SourceFile, refPos?: number, refEnd?: number): void {
|
||||
getSourceFileFromReferenceWorker(fileName,
|
||||
fileName => findSourceFile(fileName, toPath(fileName), isDefaultLib, refFile!, refPos!, refEnd!, packageId), // TODO: GH#18217
|
||||
fileName => findSourceFile(fileName, toPath(fileName), isDefaultLib, ignoreNoDefaultLib, refFile!, refPos!, refEnd!, packageId), // TODO: GH#18217
|
||||
(diagnostic, ...args) => {
|
||||
fileProcessingDiagnostics.add(refFile !== undefined && refEnd !== undefined && refPos !== undefined
|
||||
? createFileDiagnostic(refFile, refPos, refEnd - refPos, diagnostic, ...args)
|
||||
@@ -1910,7 +1964,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
// Get source file from normalized fileName
|
||||
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, refFile: SourceFile, refPos: number, refEnd: number, packageId: PackageId | undefined): SourceFile | undefined {
|
||||
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, refFile: SourceFile, refPos: number, refEnd: number, packageId: PackageId | undefined): SourceFile | undefined {
|
||||
if (filesByName.has(path)) {
|
||||
const file = filesByName.get(path);
|
||||
// try to check if we've already seen this file but with a different casing in path
|
||||
@@ -1928,6 +1982,8 @@ namespace ts {
|
||||
processTypeReferenceDirectives(file);
|
||||
}
|
||||
|
||||
processLibReferenceDirectives(file);
|
||||
|
||||
modulesWithElidedImports.set(file.path, false);
|
||||
processImportedModules(file);
|
||||
}
|
||||
@@ -1978,7 +2034,7 @@ namespace ts {
|
||||
redirectTargetsSet.set(fileFromPackageId.path, true);
|
||||
filesByName.set(path, dupFile);
|
||||
sourceFileToPackageName.set(path, packageId.name);
|
||||
files.push(dupFile);
|
||||
processingOtherFiles!.push(dupFile);
|
||||
return dupFile;
|
||||
}
|
||||
else if (file) {
|
||||
@@ -2010,21 +2066,23 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
skipDefaultLib = skipDefaultLib || file.hasNoDefaultLib;
|
||||
skipDefaultLib = skipDefaultLib || (file.hasNoDefaultLib && !ignoreNoDefaultLib);
|
||||
|
||||
if (!options.noResolve) {
|
||||
processReferencedFiles(file, isDefaultLib);
|
||||
processTypeReferenceDirectives(file);
|
||||
}
|
||||
|
||||
processLibReferenceDirectives(file);
|
||||
|
||||
// always process imported modules to record module name resolutions
|
||||
processImportedModules(file);
|
||||
|
||||
if (isDefaultLib) {
|
||||
files.unshift(file);
|
||||
processingDefaultLibFiles!.push(file);
|
||||
}
|
||||
else {
|
||||
files.push(file);
|
||||
processingOtherFiles!.push(file);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2051,7 +2109,7 @@ namespace ts {
|
||||
function processReferencedFiles(file: SourceFile, isDefaultLib: boolean) {
|
||||
forEach(file.referencedFiles, ref => {
|
||||
const referencedFileName = resolveTripleslashReference(ref.fileName, file.fileName);
|
||||
processSourceFile(referencedFileName, isDefaultLib, /*packageId*/ undefined, file, ref.pos, ref.end);
|
||||
processSourceFile(referencedFileName, isDefaultLib, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined, file, ref.pos, ref.end);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2086,7 +2144,7 @@ namespace ts {
|
||||
if (resolvedTypeReferenceDirective) {
|
||||
if (resolvedTypeReferenceDirective.primary) {
|
||||
// resolved from the primary path
|
||||
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile, refPos, refEnd); // TODO: GH#18217
|
||||
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile, refPos, refEnd); // TODO: GH#18217
|
||||
}
|
||||
else {
|
||||
// If we already resolved to this file, it must have been a secondary reference. Check file contents
|
||||
@@ -2109,7 +2167,7 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
// First resolution of this library
|
||||
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile, refPos, refEnd);
|
||||
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile, refPos, refEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2122,6 +2180,23 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function processLibReferenceDirectives(file: SourceFile) {
|
||||
forEach(file.libReferenceDirectives, libReference => {
|
||||
const libName = libReference.fileName.toLocaleLowerCase();
|
||||
const libFileName = libMap.get(libName);
|
||||
if (libFileName) {
|
||||
// we ignore any 'no-default-lib' reference set on this file.
|
||||
processRootFile(combinePaths(defaultLibraryPath, libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ true);
|
||||
}
|
||||
else {
|
||||
const unqualifiedLibName = removeSuffix(removePrefix(libName, "lib."), ".d.ts");
|
||||
const suggestion = getSpellingSuggestion(unqualifiedLibName, libs, identity);
|
||||
const message = suggestion ? Diagnostics.Cannot_find_lib_definition_for_0_Did_you_mean_1 : Diagnostics.Cannot_find_lib_definition_for_0;
|
||||
fileProcessingDiagnostics.add(createDiagnostic(file, libReference.pos, libReference.end, message, libName, suggestion));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createDiagnostic(refFile: SourceFile, refPos: number, refEnd: number, message: DiagnosticMessage, ...args: any[]): Diagnostic {
|
||||
if (refFile === undefined || refPos === undefined || refEnd === undefined) {
|
||||
return createCompilerDiagnostic(message, ...args);
|
||||
@@ -2182,7 +2257,7 @@ namespace ts {
|
||||
else if (shouldAddFile) {
|
||||
const path = toPath(resolvedFileName);
|
||||
const pos = skipTrivia(file.text, file.imports[i].pos);
|
||||
findSourceFile(resolvedFileName, path, /*isDefaultLib*/ false, file, pos, file.imports[i].end, resolution.packageId);
|
||||
findSourceFile(resolvedFileName, path, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, file, pos, file.imports[i].end, resolution.packageId);
|
||||
}
|
||||
|
||||
if (isFromNodeModulesSearch) {
|
||||
|
||||
@@ -129,7 +129,7 @@ namespace ts {
|
||||
* @param sourceFileOrBundle The input source file or bundle for the program.
|
||||
*/
|
||||
function initialize(filePath: string, sourceMapFilePath: string, sourceFileOrBundle: SourceFile | Bundle, outputSourceMapDataList?: SourceMapData[]) {
|
||||
if (disabled) {
|
||||
if (disabled || fileExtensionIs(filePath, Extension.Json)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -336,7 +336,7 @@ namespace ts {
|
||||
* @param pos The position.
|
||||
*/
|
||||
function emitPos(pos: number) {
|
||||
if (disabled || positionIsSynthesized(pos)) {
|
||||
if (disabled || positionIsSynthesized(pos) || isJsonSourceMapSource(currentSource)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -403,7 +403,7 @@ namespace ts {
|
||||
* @param emitCallback The callback used to emit the node.
|
||||
*/
|
||||
function emitNodeWithSourceMap(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) {
|
||||
if (disabled) {
|
||||
if (disabled || isInJsonFile(node)) {
|
||||
return emitCallback(hint, node);
|
||||
}
|
||||
|
||||
@@ -485,7 +485,7 @@ namespace ts {
|
||||
* @param emitCallback The callback used to emit the token.
|
||||
*/
|
||||
function emitTokenWithSourceMap(node: Node, token: SyntaxKind, writer: (s: string) => void, tokenPos: number, emitCallback: (token: SyntaxKind, writer: (s: string) => void, tokenStartPos: number) => number) {
|
||||
if (disabled) {
|
||||
if (disabled || isInJsonFile(node)) {
|
||||
return emitCallback(token, writer, tokenPos);
|
||||
}
|
||||
|
||||
@@ -508,6 +508,10 @@ namespace ts {
|
||||
return tokenPos;
|
||||
}
|
||||
|
||||
function isJsonSourceMapSource(sourceFile: SourceMapSource) {
|
||||
return fileExtensionIs(sourceFile.fileName, Extension.Json);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current source file.
|
||||
*
|
||||
@@ -521,6 +525,10 @@ namespace ts {
|
||||
currentSource = sourceFile;
|
||||
currentSourceText = currentSource.text;
|
||||
|
||||
if (isJsonSourceMapSource(sourceFile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the file to tsFilePaths
|
||||
// If sourceroot option: Use the relative path corresponding to the common directory path
|
||||
// otherwise source locations relative to map file location
|
||||
@@ -550,7 +558,7 @@ namespace ts {
|
||||
* Gets the text for the source map.
|
||||
*/
|
||||
function getText() {
|
||||
if (disabled) {
|
||||
if (disabled || isJsonSourceMapSource(currentSource)) {
|
||||
return undefined!; // TODO: GH#18217
|
||||
}
|
||||
|
||||
@@ -563,7 +571,7 @@ namespace ts {
|
||||
* Gets the SourceMappingURL for the source map.
|
||||
*/
|
||||
function getSourceMappingURL() {
|
||||
if (disabled) {
|
||||
if (disabled || isJsonSourceMapSource(currentSource)) {
|
||||
return undefined!; // TODO: GH#18217
|
||||
}
|
||||
|
||||
@@ -615,4 +623,4 @@ namespace ts {
|
||||
|
||||
return encodedStr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,12 +171,12 @@ namespace ts {
|
||||
[createModifier(SyntaxKind.DeclareKeyword)],
|
||||
createLiteral(getResolvedExternalModuleName(context.getEmitHost(), sourceFile)),
|
||||
createModuleBlock(setTextRange(createNodeArray(transformAndReplaceLatePaintedStatements(statements)), sourceFile.statements))
|
||||
)], /*isDeclarationFile*/ true, /*referencedFiles*/ [], /*typeReferences*/ [], /*hasNoDefaultLib*/ false);
|
||||
)], /*isDeclarationFile*/ true, /*referencedFiles*/ [], /*typeReferences*/ [], /*hasNoDefaultLib*/ false, /*libReferences*/ []);
|
||||
return newFile;
|
||||
}
|
||||
needsDeclare = true;
|
||||
const updated = visitNodes(sourceFile.statements, visitDeclarationStatements);
|
||||
return updateSourceFileNode(sourceFile, transformAndReplaceLatePaintedStatements(updated), /*isDeclarationFile*/ true, /*referencedFiles*/ [], /*typeReferences*/ [], /*hasNoDefaultLib*/ false);
|
||||
return updateSourceFileNode(sourceFile, transformAndReplaceLatePaintedStatements(updated), /*isDeclarationFile*/ true, /*referencedFiles*/ [], /*typeReferences*/ [], /*hasNoDefaultLib*/ false, /*libReferences*/ []);
|
||||
}
|
||||
), mapDefined(node.prepends, prepend => {
|
||||
if (prepend.kind === SyntaxKind.InputFiles) {
|
||||
|
||||
@@ -552,7 +552,9 @@ namespace ts {
|
||||
|
||||
function visitSourceFile(node: SourceFile) {
|
||||
const alwaysStrict = getStrictOptionValue(compilerOptions, "alwaysStrict") &&
|
||||
!(isExternalModule(node) && moduleKind >= ModuleKind.ES2015);
|
||||
!(isExternalModule(node) && moduleKind >= ModuleKind.ES2015) &&
|
||||
!isJsonSourceFile(node);
|
||||
|
||||
return updateSourceFileNode(
|
||||
node,
|
||||
visitLexicalEnvironment(node.statements, sourceElementVisitor, context, /*start*/ 0, alwaysStrict));
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
"builderState.ts",
|
||||
"builder.ts",
|
||||
"resolutionCache.ts",
|
||||
"moduleSpecifiers.ts",
|
||||
"watch.ts",
|
||||
"commandLineParser.ts",
|
||||
"tsbuild.ts",
|
||||
|
||||
+40
-20
@@ -1098,11 +1098,16 @@ namespace ts {
|
||||
|
||||
export type FunctionOrConstructorTypeNode = FunctionTypeNode | ConstructorTypeNode;
|
||||
|
||||
export interface FunctionTypeNode extends TypeNode, SignatureDeclarationBase {
|
||||
export interface FunctionOrConstructorTypeNodeBase extends TypeNode, SignatureDeclarationBase {
|
||||
kind: SyntaxKind.FunctionType | SyntaxKind.ConstructorType;
|
||||
type: TypeNode;
|
||||
}
|
||||
|
||||
export interface FunctionTypeNode extends FunctionOrConstructorTypeNodeBase {
|
||||
kind: SyntaxKind.FunctionType;
|
||||
}
|
||||
|
||||
export interface ConstructorTypeNode extends TypeNode, SignatureDeclarationBase {
|
||||
export interface ConstructorTypeNode extends FunctionOrConstructorTypeNodeBase {
|
||||
kind: SyntaxKind.ConstructorType;
|
||||
}
|
||||
|
||||
@@ -2566,6 +2571,7 @@ namespace ts {
|
||||
moduleName?: string;
|
||||
referencedFiles: ReadonlyArray<FileReference>;
|
||||
typeReferenceDirectives: ReadonlyArray<FileReference>;
|
||||
libReferenceDirectives: ReadonlyArray<FileReference>;
|
||||
languageVariant: LanguageVariant;
|
||||
isDeclarationFile: boolean;
|
||||
|
||||
@@ -2759,6 +2765,7 @@ namespace ts {
|
||||
getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
|
||||
getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<DiagnosticWithLocation>;
|
||||
getConfigFileParsingDiagnostics(): ReadonlyArray<Diagnostic>;
|
||||
/* @internal */ getSuggestionDiagnostics(sourceFile: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<DiagnosticWithLocation>;
|
||||
|
||||
/**
|
||||
* Gets a type checker that can be used to semantically analyze source files in the program.
|
||||
@@ -2788,6 +2795,7 @@ namespace ts {
|
||||
/* @internal */ structureIsReused?: StructureIsReused;
|
||||
|
||||
/* @internal */ getSourceFileFromReference(referencingFile: SourceFile, ref: FileReference): SourceFile | undefined;
|
||||
/* @internal */ getLibFileFromReference(ref: FileReference): SourceFile | undefined;
|
||||
|
||||
/** Given a source file, get the name of the package it was imported from. */
|
||||
/* @internal */ sourceFileToPackageName: Map<string>;
|
||||
@@ -3080,7 +3088,7 @@ namespace ts {
|
||||
* Does *not* get *all* suggestion diagnostics, just the ones that were convenient to report in the checker.
|
||||
* Others are added in computeSuggestionDiagnostics.
|
||||
*/
|
||||
/* @internal */ getSuggestionDiagnostics(file: SourceFile): ReadonlyArray<DiagnosticWithLocation>;
|
||||
/* @internal */ getSuggestionDiagnostics(file: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<DiagnosticWithLocation>;
|
||||
|
||||
/**
|
||||
* Depending on the operation performed, it may be appropriate to throw away the checker
|
||||
@@ -5029,8 +5037,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface EmitHost extends ScriptReferenceHost {
|
||||
export interface EmitHost extends ScriptReferenceHost, ModuleSpecifierResolutionHost {
|
||||
getSourceFiles(): ReadonlyArray<SourceFile>;
|
||||
getCurrentDirectory(): string;
|
||||
|
||||
/* @internal */
|
||||
isSourceFileFromExternalLibrary(file: SourceFile): boolean;
|
||||
@@ -5292,11 +5301,15 @@ namespace ts {
|
||||
isAtStartOfLine(): boolean;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface ModuleNameResolverHost {
|
||||
getCanonicalFileName(f: string): string;
|
||||
getCommonSourceDirectory(): string;
|
||||
getCurrentDirectory(): string;
|
||||
export interface GetEffectiveTypeRootsHost {
|
||||
directoryExists?(directoryName: string): boolean;
|
||||
getCurrentDirectory?(): string;
|
||||
}
|
||||
/** @internal */
|
||||
export interface ModuleSpecifierResolutionHost extends GetEffectiveTypeRootsHost {
|
||||
useCaseSensitiveFileNames?(): boolean;
|
||||
fileExists?(path: string): boolean;
|
||||
readFile?(path: string): string | undefined;
|
||||
}
|
||||
|
||||
/** @deprecated See comment on SymbolWriter */
|
||||
@@ -5310,7 +5323,7 @@ namespace ts {
|
||||
reportPrivateInBaseOfClassExpression?(propertyName: string): void;
|
||||
reportInaccessibleUniqueSymbolError?(): void;
|
||||
/* @internal */
|
||||
moduleResolverHost?: ModuleNameResolverHost;
|
||||
moduleResolverHost?: ModuleSpecifierResolutionHost;
|
||||
/* @internal */
|
||||
trackReferencedAmbientModule?(decl: ModuleDeclaration): void;
|
||||
}
|
||||
@@ -5464,8 +5477,12 @@ namespace ts {
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface PragmaDefinition<T1 extends string = string, T2 extends string = string, T3 extends string = string> {
|
||||
args?: [PragmaArgumentSpecification<T1>] | [PragmaArgumentSpecification<T1>, PragmaArgumentSpecification<T2>] | [PragmaArgumentSpecification<T1>, PragmaArgumentSpecification<T2>, PragmaArgumentSpecification<T3>];
|
||||
export interface PragmaDefinition<T1 extends string = string, T2 extends string = string, T3 extends string = string, T4 extends string = string> {
|
||||
args?:
|
||||
| [PragmaArgumentSpecification<T1>]
|
||||
| [PragmaArgumentSpecification<T1>, PragmaArgumentSpecification<T2>]
|
||||
| [PragmaArgumentSpecification<T1>, PragmaArgumentSpecification<T2>, PragmaArgumentSpecification<T3>]
|
||||
| [PragmaArgumentSpecification<T1>, PragmaArgumentSpecification<T2>, PragmaArgumentSpecification<T3>, PragmaArgumentSpecification<T4>];
|
||||
// If not present, defaults to PragmaKindFlags.Default
|
||||
kind?: PragmaKindFlags;
|
||||
}
|
||||
@@ -5474,7 +5491,7 @@ namespace ts {
|
||||
* This function only exists to cause exact types to be inferred for all the literals within `commentPragmas`
|
||||
*/
|
||||
/* @internal */
|
||||
function _contextuallyTypePragmas<T extends {[name: string]: PragmaDefinition<K1, K2, K3>}, K1 extends string, K2 extends string, K3 extends string>(args: T): T {
|
||||
function _contextuallyTypePragmas<T extends {[name: string]: PragmaDefinition<K1, K2, K3, K4>}, K1 extends string, K2 extends string, K3 extends string, K4 extends string>(args: T): T {
|
||||
return args;
|
||||
}
|
||||
|
||||
@@ -5485,6 +5502,7 @@ namespace ts {
|
||||
"reference": {
|
||||
args: [
|
||||
{ name: "types", optional: true, captureSpan: true },
|
||||
{ name: "lib", optional: true, captureSpan: true },
|
||||
{ name: "path", optional: true, captureSpan: true },
|
||||
{ name: "no-default-lib", optional: true }
|
||||
],
|
||||
@@ -5525,13 +5543,15 @@ namespace ts {
|
||||
*/
|
||||
/* @internal */
|
||||
type PragmaArgumentType<T extends PragmaDefinition> =
|
||||
T extends { args: [PragmaArgumentSpecification<infer TName1>, PragmaArgumentSpecification<infer TName2>, PragmaArgumentSpecification<infer TName3>] }
|
||||
? PragmaArgTypeOptional<T["args"][0], TName1> & PragmaArgTypeOptional<T["args"][1], TName2> & PragmaArgTypeOptional<T["args"][2], TName3>
|
||||
: T extends { args: [PragmaArgumentSpecification<infer TName1>, PragmaArgumentSpecification<infer TName2>] }
|
||||
? PragmaArgTypeOptional<T["args"][0], TName1> & PragmaArgTypeOptional<T["args"][1], TName2>
|
||||
: T extends { args: [PragmaArgumentSpecification<infer TName>] }
|
||||
? PragmaArgTypeOptional<T["args"][0], TName>
|
||||
: object;
|
||||
T extends { args: [PragmaArgumentSpecification<infer TName1>, PragmaArgumentSpecification<infer TName2>, PragmaArgumentSpecification<infer TName3>, PragmaArgumentSpecification<infer TName4>] }
|
||||
? PragmaArgTypeOptional<T["args"][0], TName1> & PragmaArgTypeOptional<T["args"][1], TName2> & PragmaArgTypeOptional<T["args"][2], TName3> & PragmaArgTypeOptional<T["args"][2], TName4>
|
||||
: T extends { args: [PragmaArgumentSpecification<infer TName1>, PragmaArgumentSpecification<infer TName2>, PragmaArgumentSpecification<infer TName3>] }
|
||||
? PragmaArgTypeOptional<T["args"][0], TName1> & PragmaArgTypeOptional<T["args"][1], TName2> & PragmaArgTypeOptional<T["args"][2], TName3>
|
||||
: T extends { args: [PragmaArgumentSpecification<infer TName1>, PragmaArgumentSpecification<infer TName2>] }
|
||||
? PragmaArgTypeOptional<T["args"][0], TName1> & PragmaArgTypeOptional<T["args"][1], TName2>
|
||||
: T extends { args: [PragmaArgumentSpecification<infer TName>] }
|
||||
? PragmaArgTypeOptional<T["args"][0], TName>
|
||||
: object;
|
||||
// The above fallback to `object` when there's no args to allow `{}` (as intended), but not the number 2, for example
|
||||
// TODO: Swap to `undefined` for a cleaner API once strictNullChecks is enabled
|
||||
|
||||
|
||||
+70
-47
@@ -641,11 +641,6 @@ namespace ts {
|
||||
return createFileDiagnostic(sourceFile, span.start, span.length, message, arg0, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
export function createDiagnosticForNodeSpan(sourceFile: SourceFile, startNode: Node, endNode: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): DiagnosticWithLocation {
|
||||
const start = skipTrivia(sourceFile.text, startNode.pos);
|
||||
return createFileDiagnostic(sourceFile, start, endNode.end - start, message, arg0, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
export function createDiagnosticForNodeFromMessageChain(node: Node, messageChain: DiagnosticMessageChain): DiagnosticWithLocation {
|
||||
const sourceFile = getSourceFileOfNode(node);
|
||||
const span = getErrorSpanForNode(sourceFile, node);
|
||||
@@ -1088,7 +1083,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function getPropertyAssignment(objectLiteral: ObjectLiteralExpression, key: string, key2?: string): ReadonlyArray<PropertyAssignment> {
|
||||
return filter(objectLiteral.properties, (property): property is PropertyAssignment => {
|
||||
return objectLiteral.properties.filter((property): property is PropertyAssignment => {
|
||||
if (property.kind === SyntaxKind.PropertyAssignment) {
|
||||
const propName = getTextOfPropertyName(property.name);
|
||||
return key === propName || (!!key2 && key2 === propName);
|
||||
@@ -1105,12 +1100,15 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function getTsConfigPropArrayElementValue(tsConfigSourceFile: TsConfigSourceFile | undefined, propKey: string, elementValue: string): StringLiteral | undefined {
|
||||
return firstDefined(getTsConfigPropArray(tsConfigSourceFile, propKey), property =>
|
||||
isArrayLiteralExpression(property.initializer) ?
|
||||
find(property.initializer.elements, (element): element is StringLiteral => isStringLiteral(element) && element.text === elementValue) :
|
||||
undefined);
|
||||
}
|
||||
|
||||
export function getTsConfigPropArray(tsConfigSourceFile: TsConfigSourceFile | undefined, propKey: string): ReadonlyArray<PropertyAssignment> {
|
||||
const jsonObjectLiteral = getTsConfigObjectLiteralExpression(tsConfigSourceFile);
|
||||
return jsonObjectLiteral &&
|
||||
firstDefined(getPropertyAssignment(jsonObjectLiteral, propKey), property =>
|
||||
isArrayLiteralExpression(property.initializer) ?
|
||||
find(property.initializer.elements, (element): element is StringLiteral => isStringLiteral(element) && element.text === elementValue) :
|
||||
undefined);
|
||||
return jsonObjectLiteral ? getPropertyAssignment(jsonObjectLiteral, propKey) : emptyArray;
|
||||
}
|
||||
|
||||
export function getContainingFunction(node: Node): SignatureDeclaration | undefined {
|
||||
@@ -1560,28 +1558,49 @@ namespace ts {
|
||||
return getSourceTextOfNodeFromSourceFile(sourceFile, str).charCodeAt(0) === CharacterCodes.doubleQuote;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the symbol of a declaration, find the symbol of its Javascript container-like initializer,
|
||||
* if it has one. Otherwise just return the original symbol.
|
||||
*
|
||||
* Container-like initializer behave like namespaces, so the binder needs to add contained symbols
|
||||
* to their exports. An example is a function with assignments to `this` inside.
|
||||
*/
|
||||
export function getJSInitializerSymbol(symbol: Symbol | undefined) {
|
||||
if (!symbol || !symbol.valueDeclaration) {
|
||||
return symbol;
|
||||
export function getDeclarationOfJSInitializer(node: Node): Node | undefined {
|
||||
if (!isInJavaScriptFile(node) || !node.parent) {
|
||||
return undefined;
|
||||
}
|
||||
const declaration = symbol.valueDeclaration;
|
||||
const e = getDeclaredJavascriptInitializer(declaration) || getAssignedJavascriptInitializer(declaration);
|
||||
return e && e.symbol ? e.symbol : symbol;
|
||||
let name: Expression | BindingName | undefined;
|
||||
let decl: Node | undefined;
|
||||
if (isVariableDeclaration(node.parent) && node.parent.initializer === node) {
|
||||
name = node.parent.name;
|
||||
decl = node.parent;
|
||||
}
|
||||
else if (isBinaryExpression(node.parent) && node.parent.operatorToken.kind === SyntaxKind.EqualsToken && node.parent.right === node) {
|
||||
name = node.parent.left;
|
||||
decl = name;
|
||||
}
|
||||
else if (isBinaryExpression(node.parent) && node.parent.operatorToken.kind === SyntaxKind.BarBarToken) {
|
||||
if (isVariableDeclaration(node.parent.parent) && node.parent.parent.initializer === node.parent) {
|
||||
name = node.parent.parent.name;
|
||||
decl = node.parent.parent;
|
||||
}
|
||||
else if (isBinaryExpression(node.parent.parent) && node.parent.parent.operatorToken.kind === SyntaxKind.EqualsToken && node.parent.parent.right === node.parent) {
|
||||
name = node.parent.parent.left;
|
||||
decl = name;
|
||||
}
|
||||
|
||||
if (!name || !isEntityNameExpression(name) || !isSameEntityName(name, node.parent.left)) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
if (!name || !getJavascriptInitializer(node, isPrototypeAccess(name))) {
|
||||
return undefined;
|
||||
}
|
||||
return decl;
|
||||
}
|
||||
|
||||
/** Get the declaration initializer, when the initializer is container-like (See getJavascriptInitializer) */
|
||||
export function getDeclaredJavascriptInitializer(node: Node) {
|
||||
if (node && isVariableDeclaration(node) && node.initializer) {
|
||||
return getJavascriptInitializer(node.initializer, /*isPrototypeAssignment*/ false) ||
|
||||
isIdentifier(node.name) && getDefaultedJavascriptInitializer(node.name, node.initializer, /*isPrototypeAssignment*/ false);
|
||||
/** Get the initializer, taking into account defaulted Javascript initializers */
|
||||
export function getEffectiveInitializer(node: HasExpressionInitializer) {
|
||||
if (isInJavaScriptFile(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;
|
||||
}
|
||||
return node.initializer;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1636,6 +1655,13 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
export function isDefaultedJavascriptInitializer(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);
|
||||
}
|
||||
|
||||
/** 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 {
|
||||
if (isBinaryExpression(node.parent)) {
|
||||
@@ -1658,7 +1684,7 @@ namespace ts {
|
||||
* var min = window.min || {}
|
||||
* my.app = self.my.app || class { }
|
||||
*/
|
||||
function isSameEntityName(name: EntityNameExpression, initializer: EntityNameExpression): boolean {
|
||||
function isSameEntityName(name: Expression, initializer: Expression): boolean {
|
||||
if (isIdentifier(name) && isIdentifier(initializer)) {
|
||||
return name.escapedText === initializer.escapedText;
|
||||
}
|
||||
@@ -2916,11 +2942,11 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
export function getResolvedExternalModuleName(host: ModuleNameResolverHost, file: SourceFile, referenceFile?: SourceFile): string {
|
||||
export function getResolvedExternalModuleName(host: EmitHost, file: SourceFile, referenceFile?: SourceFile): string {
|
||||
return file.moduleName || getExternalModuleNameFromPath(host, file.fileName, referenceFile && referenceFile.fileName);
|
||||
}
|
||||
|
||||
export function getExternalModuleNameFromDeclaration(host: ModuleNameResolverHost, resolver: EmitResolver, declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration | ImportTypeNode): string | undefined {
|
||||
export function getExternalModuleNameFromDeclaration(host: EmitHost, resolver: EmitResolver, declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration | ImportTypeNode): string | undefined {
|
||||
const file = resolver.getExternalModuleFileFromDeclaration(declaration);
|
||||
if (!file || file.isDeclarationFile) {
|
||||
return undefined;
|
||||
@@ -2931,7 +2957,7 @@ namespace ts {
|
||||
/**
|
||||
* Resolves a local path to a path which is absolute to the base of the emit
|
||||
*/
|
||||
export function getExternalModuleNameFromPath(host: ModuleNameResolverHost, fileName: string, referencePath?: string): string {
|
||||
export function getExternalModuleNameFromPath(host: EmitHost, fileName: string, referencePath?: string): string {
|
||||
const getCanonicalFileName = (f: string) => host.getCanonicalFileName(f);
|
||||
const dir = toPath(referencePath ? getDirectoryPath(referencePath) : host.getCommonSourceDirectory(), host.getCurrentDirectory(), getCanonicalFileName);
|
||||
const filePath = getNormalizedAbsolutePath(fileName, host.getCurrentDirectory());
|
||||
@@ -3146,21 +3172,18 @@ namespace ts {
|
||||
}
|
||||
if (isJSDocTypeAlias(node)) {
|
||||
Debug.assert(node.parent.kind === SyntaxKind.JSDocComment);
|
||||
const templateTags = flatMap(filter(node.parent.tags, isJSDocTemplateTag), tag => tag.typeParameters) as ReadonlyArray<TypeParameterDeclaration>;
|
||||
const templateTagNodes = templateTags as NodeArray<TypeParameterDeclaration>;
|
||||
templateTagNodes.pos = templateTagNodes.length > 0 ? first(templateTagNodes).pos : node.pos;
|
||||
templateTagNodes.end = templateTagNodes.length > 0 ? last(templateTagNodes).end : node.end;
|
||||
templateTagNodes.hasTrailingComma = false;
|
||||
return templateTagNodes;
|
||||
return flatMap(node.parent.tags, tag => isJSDocTemplateTag(tag) ? tag.typeParameters : undefined) as ReadonlyArray<TypeParameterDeclaration>;
|
||||
}
|
||||
return node.typeParameters || (isInJavaScriptFile(node) ? getJSDocTypeParameterDeclarations(node) : emptyArray);
|
||||
}
|
||||
|
||||
export function getJSDocTypeParameterDeclarations(node: DeclarationWithTypeParameters): ReadonlyArray<TypeParameterDeclaration> {
|
||||
// template tags are only available when a typedef isn't already using them
|
||||
const tag = find(getJSDocTags(node), (tag): tag is JSDocTemplateTag =>
|
||||
isJSDocTemplateTag(tag) && !(tag.parent.kind === SyntaxKind.JSDocComment && tag.parent.tags!.some(isJSDocTypeAlias)));
|
||||
return (tag && tag.typeParameters) || emptyArray;
|
||||
return flatMap(getJSDocTags(node), tag => isNonTypeAliasTemplate(tag) ? tag.typeParameters : undefined);
|
||||
}
|
||||
|
||||
/** template tags are only available when a typedef isn't already using them */
|
||||
function isNonTypeAliasTemplate(tag: JSDocTag): tag is JSDocTemplateTag {
|
||||
return isJSDocTemplateTag(tag) && !(tag.parent.kind === SyntaxKind.JSDocComment && tag.parent.tags!.some(isJSDocTypeAlias));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3656,15 +3679,15 @@ namespace ts {
|
||||
return output;
|
||||
}
|
||||
|
||||
export function base64encode(host: { base64encode?(input: string): string }, input: string): string {
|
||||
if (host.base64encode) {
|
||||
export function base64encode(host: { base64encode?(input: string): string } | undefined, input: string): string {
|
||||
if (host && host.base64encode) {
|
||||
return host.base64encode(input);
|
||||
}
|
||||
return convertToBase64(input);
|
||||
}
|
||||
|
||||
export function base64decode(host: { base64decode?(input: string): string }, input: string): string {
|
||||
if (host.base64decode) {
|
||||
export function base64decode(host: { base64decode?(input: string): string } | undefined, input: string): string {
|
||||
if (host && host.base64decode) {
|
||||
return host.base64decode(input);
|
||||
}
|
||||
const length = input.length;
|
||||
|
||||
@@ -1468,7 +1468,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
return isNodeArray(statements)
|
||||
? setTextRange(createNodeArray(concatenate(declarations, statements)), statements)
|
||||
? setTextRange(createNodeArray(prependStatements(statements.slice(), declarations)), statements)
|
||||
: prependStatements(statements, declarations);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user