mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' into isInMultiLineComment
This commit is contained in:
Vendored
+7
@@ -18,6 +18,13 @@
|
||||
"problemMatcher": [
|
||||
"$tsc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"taskName": "tests",
|
||||
"showOutput": "silent",
|
||||
"problemMatcher": [
|
||||
"$tsc"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
+6
-21
@@ -133,6 +133,7 @@ var harnessSources = harnessCoreSources.concat([
|
||||
"projectErrors.ts",
|
||||
"matchFiles.ts",
|
||||
"initializeTSConfig.ts",
|
||||
"extractMethods.ts",
|
||||
"printer.ts",
|
||||
"textChanges.ts",
|
||||
"telemetry.ts",
|
||||
@@ -533,7 +534,6 @@ var tscFile = path.join(builtLocalDirectory, compilerFilename);
|
||||
compileFile(tscFile, compilerSources, [builtLocalDirectory, copyright].concat(compilerSources), [copyright], /*useBuiltCompiler:*/ false);
|
||||
|
||||
var servicesFile = path.join(builtLocalDirectory, "typescriptServices.js");
|
||||
var servicesFileInBrowserTest = path.join(builtLocalDirectory, "typescriptServicesInBrowserTest.js");
|
||||
var standaloneDefinitionsFile = path.join(builtLocalDirectory, "typescriptServices.d.ts");
|
||||
var nodePackageFile = path.join(builtLocalDirectory, "typescript.js");
|
||||
var nodeDefinitionsFile = path.join(builtLocalDirectory, "typescript.d.ts");
|
||||
@@ -572,22 +572,6 @@ compileFile(servicesFile, servicesSources, [builtLocalDirectory, copyright].conc
|
||||
fs.writeFileSync(nodeStandaloneDefinitionsFile, nodeStandaloneDefinitionsFileContents);
|
||||
});
|
||||
|
||||
compileFile(
|
||||
servicesFileInBrowserTest,
|
||||
servicesSources,
|
||||
[builtLocalDirectory, copyright].concat(servicesSources),
|
||||
/*prefixes*/[copyright],
|
||||
/*useBuiltCompiler*/ true,
|
||||
{
|
||||
noOutFile: false,
|
||||
generateDeclarations: true,
|
||||
preserveConstEnums: true,
|
||||
keepComments: true,
|
||||
noResolve: false,
|
||||
stripInternal: true,
|
||||
inlineSourceMap: true
|
||||
});
|
||||
|
||||
file(typescriptServicesDts, [servicesFile]);
|
||||
|
||||
var cancellationTokenFile = path.join(builtLocalDirectory, "cancellationToken.js");
|
||||
@@ -725,7 +709,7 @@ compileFile(
|
||||
/*prereqs*/[builtLocalDirectory, tscFile].concat(libraryTargets).concat(servicesSources).concat(harnessSources),
|
||||
/*prefixes*/[],
|
||||
/*useBuiltCompiler:*/ true,
|
||||
/*opts*/ { inlineSourceMap: true, types: ["node", "mocha", "chai"], lib: "es6" });
|
||||
/*opts*/ { types: ["node", "mocha", "chai"], lib: "es6" });
|
||||
|
||||
var internalTests = "internal/";
|
||||
|
||||
@@ -961,13 +945,14 @@ var nodeServerInFile = "tests/webTestServer.ts";
|
||||
compileFile(nodeServerOutFile, [nodeServerInFile], [builtLocalDirectory, tscFile], [], /*useBuiltCompiler:*/ true, { noOutFile: true, lib: "es6" });
|
||||
|
||||
desc("Runs browserify on run.js to produce a file suitable for running tests in the browser");
|
||||
task("browserify", ["tests", run, builtLocalDirectory, nodeServerOutFile], function() {
|
||||
var cmd = 'browserify built/local/run.js -t ./scripts/browserify-optional -d -o built/local/bundle.js';
|
||||
task("browserify", [], function() {
|
||||
// Shell out to `gulp`, since we do the work to handle sourcemaps correctly w/o inline maps there
|
||||
var cmd = 'gulp browserify --silent';
|
||||
exec(cmd);
|
||||
}, { async: true });
|
||||
|
||||
desc("Runs the tests using the built run.js file like 'jake runtests'. Syntax is jake runtests-browser. Additional optional parameters tests=[regex], browser=[chrome|IE]");
|
||||
task("runtests-browser", ["tests", "browserify", builtLocalDirectory, servicesFileInBrowserTest], function () {
|
||||
task("runtests-browser", ["browserify", nodeServerOutFile], function () {
|
||||
cleanTestDirs();
|
||||
host = "node";
|
||||
browser = process.env.browser || process.env.b || (os.platform() === "linux" ? "chrome" : "IE");
|
||||
|
||||
@@ -90,7 +90,6 @@
|
||||
"setup-hooks": "node scripts/link-hooks.js"
|
||||
},
|
||||
"browser": {
|
||||
"buffer": false,
|
||||
"fs": false,
|
||||
"os": false,
|
||||
"path": false
|
||||
|
||||
+8
-28
@@ -806,11 +806,7 @@ namespace ts {
|
||||
return antecedent;
|
||||
}
|
||||
setFlowNodeReferenced(antecedent);
|
||||
return <FlowCondition>{
|
||||
flags,
|
||||
expression,
|
||||
antecedent
|
||||
};
|
||||
return { flags, expression, antecedent };
|
||||
}
|
||||
|
||||
function createFlowSwitchClause(antecedent: FlowNode, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): FlowNode {
|
||||
@@ -818,31 +814,18 @@ namespace ts {
|
||||
return antecedent;
|
||||
}
|
||||
setFlowNodeReferenced(antecedent);
|
||||
return <FlowSwitchClause>{
|
||||
flags: FlowFlags.SwitchClause,
|
||||
switchStatement,
|
||||
clauseStart,
|
||||
clauseEnd,
|
||||
antecedent
|
||||
};
|
||||
return { flags: FlowFlags.SwitchClause, switchStatement, clauseStart, clauseEnd, antecedent };
|
||||
}
|
||||
|
||||
function createFlowAssignment(antecedent: FlowNode, node: Expression | VariableDeclaration | BindingElement): FlowNode {
|
||||
setFlowNodeReferenced(antecedent);
|
||||
return <FlowAssignment>{
|
||||
flags: FlowFlags.Assignment,
|
||||
antecedent,
|
||||
node
|
||||
};
|
||||
return { flags: FlowFlags.Assignment, antecedent, node };
|
||||
}
|
||||
|
||||
function createFlowArrayMutation(antecedent: FlowNode, node: CallExpression | BinaryExpression): FlowNode {
|
||||
setFlowNodeReferenced(antecedent);
|
||||
return <FlowArrayMutation>{
|
||||
flags: FlowFlags.ArrayMutation,
|
||||
antecedent,
|
||||
node
|
||||
};
|
||||
const res: FlowArrayMutation = { flags: FlowFlags.ArrayMutation, antecedent, node };
|
||||
return res;
|
||||
}
|
||||
|
||||
function finishFlowLabel(flow: FlowLabel): FlowNode {
|
||||
@@ -2784,7 +2767,6 @@ namespace ts {
|
||||
|
||||
function computeParameter(node: ParameterDeclaration, subtreeFlags: TransformFlags) {
|
||||
let transformFlags = subtreeFlags;
|
||||
const modifierFlags = getModifierFlags(node);
|
||||
const name = node.name;
|
||||
const initializer = node.initializer;
|
||||
const dotDotDotToken = node.dotDotDotToken;
|
||||
@@ -2799,7 +2781,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
// If a parameter has an accessibility modifier, then it is TypeScript syntax.
|
||||
if (modifierFlags & ModifierFlags.ParameterPropertyModifier) {
|
||||
if (hasModifier(node, ModifierFlags.ParameterPropertyModifier)) {
|
||||
transformFlags |= TransformFlags.AssertTypeScript | TransformFlags.ContainsParameterPropertyAssignments;
|
||||
}
|
||||
|
||||
@@ -2844,9 +2826,8 @@ namespace ts {
|
||||
|
||||
function computeClassDeclaration(node: ClassDeclaration, subtreeFlags: TransformFlags) {
|
||||
let transformFlags: TransformFlags;
|
||||
const modifierFlags = getModifierFlags(node);
|
||||
|
||||
if (modifierFlags & ModifierFlags.Ambient) {
|
||||
if (hasModifier(node, ModifierFlags.Ambient)) {
|
||||
// An ambient declaration is TypeScript syntax.
|
||||
transformFlags = TransformFlags.AssertTypeScript;
|
||||
}
|
||||
@@ -3190,11 +3171,10 @@ namespace ts {
|
||||
|
||||
function computeVariableStatement(node: VariableStatement, subtreeFlags: TransformFlags) {
|
||||
let transformFlags: TransformFlags;
|
||||
const modifierFlags = getModifierFlags(node);
|
||||
const declarationListTransformFlags = node.declarationList.transformFlags;
|
||||
|
||||
// An ambient declaration is TypeScript syntax.
|
||||
if (modifierFlags & ModifierFlags.Ambient) {
|
||||
if (hasModifier(node, ModifierFlags.Ambient)) {
|
||||
transformFlags = TransformFlags.AssertTypeScript;
|
||||
}
|
||||
else {
|
||||
|
||||
+186
-163
@@ -138,6 +138,9 @@ namespace ts {
|
||||
node = getParseTreeNode(node, isExportSpecifier);
|
||||
return node ? getExportSpecifierLocalTargetSymbol(node) : undefined;
|
||||
},
|
||||
getExportSymbolOfSymbol(symbol) {
|
||||
return getMergedSymbol(symbol.exportSymbol || symbol);
|
||||
},
|
||||
getTypeAtLocation: node => {
|
||||
node = getParseTreeNode(node);
|
||||
return node ? getTypeOfNode(node) : unknownType;
|
||||
@@ -223,11 +226,10 @@ namespace ts {
|
||||
getSuggestionForNonexistentProperty: (node, type) => unescapeLeadingUnderscores(getSuggestionForNonexistentProperty(node, type)),
|
||||
getSuggestionForNonexistentSymbol: (location, name, meaning) => unescapeLeadingUnderscores(getSuggestionForNonexistentSymbol(location, escapeLeadingUnderscores(name), meaning)),
|
||||
getBaseConstraintOfType,
|
||||
getJsxNamespace: () => unescapeLeadingUnderscores(getJsxNamespace()),
|
||||
resolveNameAtLocation(location: Node, name: string, meaning: SymbolFlags): Symbol | undefined {
|
||||
location = getParseTreeNode(location);
|
||||
return resolveName(location, escapeLeadingUnderscores(name), meaning, /*nameNotFoundMessage*/ undefined, escapeLeadingUnderscores(name));
|
||||
resolveName(name, location, meaning) {
|
||||
return resolveName(location, escapeLeadingUnderscores(name), meaning, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined);
|
||||
},
|
||||
getJsxNamespace: () => unescapeLeadingUnderscores(getJsxNamespace()),
|
||||
};
|
||||
|
||||
const tupleTypes: GenericType[] = [];
|
||||
@@ -835,13 +837,13 @@ namespace ts {
|
||||
(<PropertyDeclaration>current.parent).initializer === current;
|
||||
|
||||
if (initializerOfProperty) {
|
||||
if (getModifierFlags(current.parent) & ModifierFlags.Static) {
|
||||
if (hasModifier(current.parent, ModifierFlags.Static)) {
|
||||
if (declaration.kind === SyntaxKind.MethodDeclaration) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
const isDeclarationInstanceProperty = declaration.kind === SyntaxKind.PropertyDeclaration && !(getModifierFlags(declaration) & ModifierFlags.Static);
|
||||
const isDeclarationInstanceProperty = declaration.kind === SyntaxKind.PropertyDeclaration && !hasModifier(declaration, ModifierFlags.Static);
|
||||
if (!isDeclarationInstanceProperty || getContainingClass(usage) !== getContainingClass(declaration)) {
|
||||
return true;
|
||||
}
|
||||
@@ -978,7 +980,7 @@ namespace ts {
|
||||
// local variables of the constructor. This effectively means that entities from outer scopes
|
||||
// by the same name as a constructor parameter or local variable are inaccessible
|
||||
// in initializer expressions for instance member variables.
|
||||
if (isClassLike(location.parent) && !(getModifierFlags(location) & ModifierFlags.Static)) {
|
||||
if (isClassLike(location.parent) && !hasModifier(location, ModifierFlags.Static)) {
|
||||
const ctor = findConstructorDeclaration(<ClassLikeDeclaration>location.parent);
|
||||
if (ctor && ctor.locals) {
|
||||
if (lookup(ctor.locals, name, meaning & SymbolFlags.Value)) {
|
||||
@@ -997,7 +999,7 @@ namespace ts {
|
||||
result = undefined;
|
||||
break;
|
||||
}
|
||||
if (lastLocation && getModifierFlags(lastLocation) & ModifierFlags.Static) {
|
||||
if (lastLocation && hasModifier(lastLocation, ModifierFlags.Static)) {
|
||||
// TypeScript 1.0 spec (April 2014): 3.4.1
|
||||
// The scope of a type parameter extends over the entire declaration with which the type
|
||||
// parameter list is associated, with the exception of static member declarations in classes.
|
||||
@@ -1200,7 +1202,7 @@ namespace ts {
|
||||
|
||||
// No static member is present.
|
||||
// Check if we're in an instance method and look for a relevant instance member.
|
||||
if (location === container && !(getModifierFlags(location) & ModifierFlags.Static)) {
|
||||
if (location === container && !hasModifier(location, ModifierFlags.Static)) {
|
||||
const instanceType = (<InterfaceType>getDeclaredTypeOfSymbol(classSymbol)).thisType;
|
||||
if (getPropertyOfType(instanceType, name)) {
|
||||
error(errorLocation, Diagnostics.Cannot_find_name_0_Did_you_mean_the_instance_member_this_0, diagnosticName(nameArg));
|
||||
@@ -2154,6 +2156,11 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
function isTypeSymbolAccessible(typeSymbol: Symbol, enclosingDeclaration: Node): boolean {
|
||||
const access = isSymbolAccessible(typeSymbol, enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false);
|
||||
return access.accessibility === SymbolAccessibility.Accessible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given symbol in given enclosing declaration is accessible and mark all associated alias to be visible if requested
|
||||
*
|
||||
@@ -2172,7 +2179,7 @@ namespace ts {
|
||||
if (accessibleSymbolChain) {
|
||||
const hasAccessibleDeclarations = hasVisibleDeclarations(accessibleSymbolChain[0], shouldComputeAliasesToMakeVisible);
|
||||
if (!hasAccessibleDeclarations) {
|
||||
return <SymbolAccessibilityResult>{
|
||||
return {
|
||||
accessibility: SymbolAccessibility.NotAccessible,
|
||||
errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning),
|
||||
errorModuleName: symbol !== initialSymbol ? symbolToString(symbol, enclosingDeclaration, SymbolFlags.Namespace) : undefined,
|
||||
@@ -2245,7 +2252,7 @@ namespace ts {
|
||||
|
||||
const anyImportSyntax = getAnyImportSyntax(declaration);
|
||||
if (anyImportSyntax &&
|
||||
!(getModifierFlags(anyImportSyntax) & ModifierFlags.Export) && // import clause without export
|
||||
!hasModifier(anyImportSyntax, ModifierFlags.Export) && // import clause without export
|
||||
isDeclarationVisible(<Declaration>anyImportSyntax.parent)) {
|
||||
// In function "buildTypeDisplay" where we decide whether to write type-alias or serialize types,
|
||||
// we want to just check if type- alias is accessible or not but we don't care about emitting those alias at that time
|
||||
@@ -2294,7 +2301,7 @@ namespace ts {
|
||||
const symbol = resolveName(enclosingDeclaration, firstIdentifier.escapedText, meaning, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined);
|
||||
|
||||
// Verify if the symbol is accessible
|
||||
return (symbol && hasVisibleDeclarations(symbol, /*shouldComputeAliasToMakeVisible*/ true)) || <SymbolVisibilityResult>{
|
||||
return (symbol && hasVisibleDeclarations(symbol, /*shouldComputeAliasToMakeVisible*/ true)) || {
|
||||
accessibility: SymbolAccessibility.NotAccessible,
|
||||
errorSymbolName: getTextOfNode(firstIdentifier),
|
||||
errorNode: firstIdentifier
|
||||
@@ -2484,8 +2491,7 @@ namespace ts {
|
||||
// Ignore constraint/default when creating a usage (as opposed to declaration) of a type parameter.
|
||||
return createTypeReferenceNode(name, /*typeArguments*/ undefined);
|
||||
}
|
||||
if (!inTypeAlias && type.aliasSymbol &&
|
||||
isSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false).accessibility === SymbolAccessibility.Accessible) {
|
||||
if (!inTypeAlias && type.aliasSymbol && isTypeSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration)) {
|
||||
const name = symbolToTypeReferenceName(type.aliasSymbol);
|
||||
const typeArgumentNodes = mapToTypeNodes(type.aliasTypeArguments, context);
|
||||
return createTypeReferenceNode(name, typeArgumentNodes);
|
||||
@@ -2572,8 +2578,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
function shouldWriteTypeOfFunctionSymbol() {
|
||||
const isStaticMethodSymbol = !!(symbol.flags & SymbolFlags.Method && // typeof static method
|
||||
forEach(symbol.declarations, declaration => getModifierFlags(declaration) & ModifierFlags.Static));
|
||||
const isStaticMethodSymbol = !!(symbol.flags & SymbolFlags.Method) && // typeof static method
|
||||
some(symbol.declarations, declaration => hasModifier(declaration, ModifierFlags.Static));
|
||||
const isNonLocalFunctionSymbol = !!(symbol.flags & SymbolFlags.Function) &&
|
||||
(symbol.parent || // is exported function symbol
|
||||
forEach(symbol.declarations, declaration =>
|
||||
@@ -3252,7 +3258,7 @@ namespace ts {
|
||||
buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, nextFlags);
|
||||
}
|
||||
else if (!(flags & TypeFormatFlags.InTypeAlias) && type.aliasSymbol &&
|
||||
isSymbolAccessible(type.aliasSymbol, enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false).accessibility === SymbolAccessibility.Accessible) {
|
||||
((flags & TypeFormatFlags.UseAliasDefinedOutsideCurrentScope) || isTypeSymbolAccessible(type.aliasSymbol, enclosingDeclaration))) {
|
||||
const typeArguments = type.aliasTypeArguments;
|
||||
writeSymbolTypeReference(type.aliasSymbol, typeArguments, 0, length(typeArguments), nextFlags);
|
||||
}
|
||||
@@ -3437,16 +3443,16 @@ namespace ts {
|
||||
}
|
||||
|
||||
function shouldWriteTypeOfFunctionSymbol() {
|
||||
const isStaticMethodSymbol = !!(symbol.flags & SymbolFlags.Method && // typeof static method
|
||||
forEach(symbol.declarations, declaration => getModifierFlags(declaration) & ModifierFlags.Static));
|
||||
const isStaticMethodSymbol = !!(symbol.flags & SymbolFlags.Method) && // typeof static method
|
||||
some(symbol.declarations, declaration => hasModifier(declaration, ModifierFlags.Static));
|
||||
const isNonLocalFunctionSymbol = !!(symbol.flags & SymbolFlags.Function) &&
|
||||
(symbol.parent || // is exported function symbol
|
||||
forEach(symbol.declarations, declaration =>
|
||||
some(symbol.declarations, declaration =>
|
||||
declaration.parent.kind === SyntaxKind.SourceFile || declaration.parent.kind === SyntaxKind.ModuleBlock));
|
||||
if (isStaticMethodSymbol || isNonLocalFunctionSymbol) {
|
||||
// typeof is allowed only for static/non local functions
|
||||
return !!(flags & TypeFormatFlags.UseTypeOfFunction) || // use typeof if format flags specify it
|
||||
(contains(symbolStack, symbol)); // it is type of the symbol uses itself recursively
|
||||
contains(symbolStack, symbol); // it is type of the symbol uses itself recursively
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3892,7 +3898,7 @@ namespace ts {
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.MethodSignature:
|
||||
if (getModifierFlags(node) & (ModifierFlags.Private | ModifierFlags.Protected)) {
|
||||
if (hasModifier(node, ModifierFlags.Private | ModifierFlags.Protected)) {
|
||||
// Private/protected properties/methods are not visible
|
||||
return false;
|
||||
}
|
||||
@@ -5096,8 +5102,8 @@ namespace ts {
|
||||
return unknownType;
|
||||
}
|
||||
|
||||
const declaration = <JSDocTypedefTag | TypeAliasDeclaration>findDeclaration(
|
||||
symbol, d => d.kind === SyntaxKind.JSDocTypedefTag || d.kind === SyntaxKind.TypeAliasDeclaration);
|
||||
const declaration = <JSDocTypedefTag | TypeAliasDeclaration>find(symbol.declarations, d =>
|
||||
d.kind === SyntaxKind.JSDocTypedefTag || d.kind === SyntaxKind.TypeAliasDeclaration);
|
||||
let type = getTypeFromTypeNode(declaration.kind === SyntaxKind.JSDocTypedefTag ? declaration.typeExpression : declaration.type);
|
||||
|
||||
if (popTypeResolution()) {
|
||||
@@ -6300,7 +6306,7 @@ namespace ts {
|
||||
return {
|
||||
kind: TypePredicateKind.This,
|
||||
type: getTypeFromTypeNode(node.type)
|
||||
} as ThisTypePredicate;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6576,6 +6582,10 @@ namespace ts {
|
||||
return signature.resolvedReturnType;
|
||||
}
|
||||
|
||||
function isResolvingReturnTypeOfSignature(signature: Signature) {
|
||||
return !signature.resolvedReturnType && findResolutionCycleStartIndex(signature, TypeSystemPropertyName.ResolvedReturnType) >= 0;
|
||||
}
|
||||
|
||||
function getRestTypeOfSignature(signature: Signature): Type {
|
||||
if (signature.hasRestParameter) {
|
||||
const type = getTypeOfSymbol(lastOrUndefined(signature.parameters));
|
||||
@@ -6657,7 +6667,7 @@ namespace ts {
|
||||
const declaration = getIndexDeclarationOfSymbol(symbol, kind);
|
||||
if (declaration) {
|
||||
return createIndexInfo(declaration.type ? getTypeFromTypeNode(declaration.type) : anyType,
|
||||
(getModifierFlags(declaration) & ModifierFlags.Readonly) !== 0, declaration);
|
||||
hasModifier(declaration, ModifierFlags.Readonly), declaration);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
@@ -7566,7 +7576,6 @@ namespace ts {
|
||||
if (indexInfo) {
|
||||
if (accessExpression && indexInfo.isReadonly && (isAssignmentTarget(accessExpression) || isDeleteTarget(accessExpression))) {
|
||||
error(accessExpression, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(objectType));
|
||||
return unknownType;
|
||||
}
|
||||
return indexInfo.type;
|
||||
}
|
||||
@@ -7607,7 +7616,6 @@ namespace ts {
|
||||
}
|
||||
if (accessNode.kind === SyntaxKind.ElementAccessExpression && isAssignmentTarget(accessNode) && type.declaration.readonlyToken) {
|
||||
error(accessNode, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(type));
|
||||
return unknownType;
|
||||
}
|
||||
}
|
||||
const mapper = createTypeMapper([getTypeParameterFromMappedType(type)], [indexType]);
|
||||
@@ -7909,7 +7917,7 @@ namespace ts {
|
||||
const container = getThisContainer(node, /*includeArrowFunctions*/ false);
|
||||
const parent = container && container.parent;
|
||||
if (parent && (isClassLike(parent) || parent.kind === SyntaxKind.InterfaceDeclaration)) {
|
||||
if (!(getModifierFlags(container) & ModifierFlags.Static) &&
|
||||
if (!hasModifier(container, ModifierFlags.Static) &&
|
||||
(container.kind !== SyntaxKind.Constructor || isNodeDescendantOf(node, (<ConstructorDeclaration>container).body))) {
|
||||
return getDeclaredTypeOfClassOrInterface(getSymbolOfNode(parent)).thisType;
|
||||
}
|
||||
@@ -8109,13 +8117,13 @@ namespace ts {
|
||||
parameterName: predicate.parameterName,
|
||||
parameterIndex: predicate.parameterIndex,
|
||||
type: instantiateType(predicate.type, mapper)
|
||||
} as IdentifierTypePredicate;
|
||||
};
|
||||
}
|
||||
else {
|
||||
return {
|
||||
kind: TypePredicateKind.This,
|
||||
type: instantiateType(predicate.type, mapper)
|
||||
} as ThisTypePredicate;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8405,16 +8413,17 @@ namespace ts {
|
||||
if (forEach(node.parameters, p => !getEffectiveTypeAnnotationNode(p))) {
|
||||
return true;
|
||||
}
|
||||
// For arrow functions we now know we're not context sensitive.
|
||||
if (node.kind === SyntaxKind.ArrowFunction) {
|
||||
return false;
|
||||
if (node.kind !== SyntaxKind.ArrowFunction) {
|
||||
// If the first parameter is not an explicit 'this' parameter, then the function has
|
||||
// an implicit 'this' parameter which is subject to contextual typing.
|
||||
const parameter = firstOrUndefined(node.parameters);
|
||||
if (!(parameter && parameterIsThisKeyword(parameter))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// If the first parameter is not an explicit 'this' parameter, then the function has
|
||||
// an implicit 'this' parameter which is subject to contextual typing. Otherwise we
|
||||
// know that all parameters (including 'this') have type annotations and nothing is
|
||||
// subject to contextual typing.
|
||||
const parameter = firstOrUndefined(node.parameters);
|
||||
return !(parameter && parameterIsThisKeyword(parameter));
|
||||
|
||||
// TODO(anhans): A block should be context-sensitive if it has a context-sensitive return value.
|
||||
return node.body.kind === SyntaxKind.Block ? false : isContextSensitive(node.body);
|
||||
}
|
||||
|
||||
function isContextSensitiveFunctionOrObjectLiteralMethod(func: Node): func is FunctionExpression | ArrowFunction | MethodDeclaration {
|
||||
@@ -8592,7 +8601,7 @@ namespace ts {
|
||||
// The following block preserves behavior forbidding boolean returning functions from being assignable to type guard returning functions
|
||||
if (target.typePredicate) {
|
||||
if (source.typePredicate) {
|
||||
result &= compareTypePredicateRelatedTo(source.typePredicate, target.typePredicate, reportErrors, errorReporter, compareTypes);
|
||||
result &= compareTypePredicateRelatedTo(source.typePredicate, target.typePredicate, source.declaration, target.declaration, reportErrors, errorReporter, compareTypes);
|
||||
}
|
||||
else if (isIdentifierTypePredicate(target.typePredicate)) {
|
||||
if (reportErrors) {
|
||||
@@ -8614,8 +8623,11 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
function compareTypePredicateRelatedTo(source: TypePredicate,
|
||||
function compareTypePredicateRelatedTo(
|
||||
source: TypePredicate,
|
||||
target: TypePredicate,
|
||||
sourceDeclaration: SignatureDeclaration,
|
||||
targetDeclaration: SignatureDeclaration,
|
||||
reportErrors: boolean,
|
||||
errorReporter: ErrorReporter,
|
||||
compareTypes: (s: Type, t: Type, reportErrors?: boolean) => Ternary): Ternary {
|
||||
@@ -8628,11 +8640,13 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (source.kind === TypePredicateKind.Identifier) {
|
||||
const sourceIdentifierPredicate = source as IdentifierTypePredicate;
|
||||
const targetIdentifierPredicate = target as IdentifierTypePredicate;
|
||||
if (sourceIdentifierPredicate.parameterIndex !== targetIdentifierPredicate.parameterIndex) {
|
||||
const sourcePredicate = source as IdentifierTypePredicate;
|
||||
const targetPredicate = target as IdentifierTypePredicate;
|
||||
const sourceIndex = sourcePredicate.parameterIndex - (getThisParameter(sourceDeclaration) ? 1 : 0);
|
||||
const targetIndex = targetPredicate.parameterIndex - (getThisParameter(targetDeclaration) ? 1 : 0);
|
||||
if (sourceIndex !== targetIndex) {
|
||||
if (reportErrors) {
|
||||
errorReporter(Diagnostics.Parameter_0_is_not_in_the_same_position_as_parameter_1, sourceIdentifierPredicate.parameterName, targetIdentifierPredicate.parameterName);
|
||||
errorReporter(Diagnostics.Parameter_0_is_not_in_the_same_position_as_parameter_1, sourcePredicate.parameterName, targetPredicate.parameterName);
|
||||
errorReporter(Diagnostics.Type_predicate_0_is_not_assignable_to_1, typePredicateToString(source), typePredicateToString(target));
|
||||
}
|
||||
return Ternary.False;
|
||||
@@ -9723,8 +9737,8 @@ namespace ts {
|
||||
return true;
|
||||
}
|
||||
|
||||
const sourceAccessibility = getModifierFlags(sourceSignature.declaration) & ModifierFlags.NonPublicAccessibilityModifier;
|
||||
const targetAccessibility = getModifierFlags(targetSignature.declaration) & ModifierFlags.NonPublicAccessibilityModifier;
|
||||
const sourceAccessibility = getSelectedModifierFlags(sourceSignature.declaration, ModifierFlags.NonPublicAccessibilityModifier);
|
||||
const targetAccessibility = getSelectedModifierFlags(targetSignature.declaration, ModifierFlags.NonPublicAccessibilityModifier);
|
||||
|
||||
// A public, protected and private signature is assignable to a private signature.
|
||||
if (targetAccessibility === ModifierFlags.Private) {
|
||||
@@ -9798,7 +9812,7 @@ namespace ts {
|
||||
const symbol = type.symbol;
|
||||
if (symbol && symbol.flags & SymbolFlags.Class) {
|
||||
const declaration = getClassLikeDeclarationOfSymbol(symbol);
|
||||
if (declaration && getModifierFlags(declaration) & ModifierFlags.Abstract) {
|
||||
if (declaration && hasModifier(declaration, ModifierFlags.Abstract)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -12465,7 +12479,7 @@ namespace ts {
|
||||
break;
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
case SyntaxKind.PropertySignature:
|
||||
if (getModifierFlags(container) & ModifierFlags.Static) {
|
||||
if (hasModifier(container, ModifierFlags.Static)) {
|
||||
error(node, Diagnostics.this_cannot_be_referenced_in_a_static_property_initializer);
|
||||
// do not return here so in case if lexical this is captured - it will be reflected in flags on NodeLinks
|
||||
}
|
||||
@@ -12583,7 +12597,7 @@ namespace ts {
|
||||
checkThisBeforeSuper(node, container, Diagnostics.super_must_be_called_before_accessing_a_property_of_super_in_the_constructor_of_a_derived_class);
|
||||
}
|
||||
|
||||
if ((getModifierFlags(container) & ModifierFlags.Static) || isCallExpression) {
|
||||
if (hasModifier(container, ModifierFlags.Static) || isCallExpression) {
|
||||
nodeCheckFlag = NodeCheckFlags.SuperStatic;
|
||||
}
|
||||
else {
|
||||
@@ -12648,7 +12662,7 @@ namespace ts {
|
||||
// This helper creates an object with a "value" property that wraps the `super` property or indexed access for both get and set.
|
||||
// This is required for destructuring assignments, as a call expression cannot be used as the target of a destructuring assignment
|
||||
// while a property access can.
|
||||
if (container.kind === SyntaxKind.MethodDeclaration && getModifierFlags(container) & ModifierFlags.Async) {
|
||||
if (container.kind === SyntaxKind.MethodDeclaration && hasModifier(container, ModifierFlags.Async)) {
|
||||
if (isSuperProperty(node.parent) && isAssignmentTarget(node.parent)) {
|
||||
getNodeLinks(container).flags |= NodeCheckFlags.AsyncMethodWithSuperBinding;
|
||||
}
|
||||
@@ -12714,7 +12728,7 @@ namespace ts {
|
||||
|
||||
// topmost container must be something that is directly nested in the class declaration\object literal expression
|
||||
if (isClassLike(container.parent) || container.parent.kind === SyntaxKind.ObjectLiteralExpression) {
|
||||
if (getModifierFlags(container) & ModifierFlags.Static) {
|
||||
if (hasModifier(container, ModifierFlags.Static)) {
|
||||
return container.kind === SyntaxKind.MethodDeclaration ||
|
||||
container.kind === SyntaxKind.MethodSignature ||
|
||||
container.kind === SyntaxKind.GetAccessor ||
|
||||
@@ -12943,7 +12957,7 @@ namespace ts {
|
||||
// Otherwise, if the containing function is contextually typed by a function type with exactly one call signature
|
||||
// and that call signature is non-generic, return statements are contextually typed by the return type of the signature
|
||||
const signature = getContextualSignatureForFunctionLikeDeclaration(<FunctionExpression>functionDecl);
|
||||
if (signature) {
|
||||
if (signature && !isResolvingReturnTypeOfSignature(signature)) {
|
||||
return getReturnTypeOfSignature(signature);
|
||||
}
|
||||
|
||||
@@ -14599,9 +14613,12 @@ namespace ts {
|
||||
}
|
||||
const prop = getPropertyOfType(apparentType, right.escapedText);
|
||||
if (!prop) {
|
||||
const stringIndexType = getIndexTypeOfType(apparentType, IndexKind.String);
|
||||
if (stringIndexType) {
|
||||
return stringIndexType;
|
||||
const indexInfo = getIndexInfoOfType(apparentType, IndexKind.String);
|
||||
if (indexInfo && indexInfo.type) {
|
||||
if (indexInfo.isReadonly && (isAssignmentTarget(node) || isDeleteTarget(node))) {
|
||||
error(node, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(apparentType));
|
||||
}
|
||||
return indexInfo.type;
|
||||
}
|
||||
if (right.escapedText && !checkAndReportErrorForExtendingInterface(node)) {
|
||||
reportNonexistentProperty(right, type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType ? apparentType : type);
|
||||
@@ -14759,7 +14776,7 @@ namespace ts {
|
||||
if (prop &&
|
||||
noUnusedIdentifiers &&
|
||||
(prop.flags & SymbolFlags.ClassMember) &&
|
||||
prop.valueDeclaration && (getModifierFlags(prop.valueDeclaration) & ModifierFlags.Private)) {
|
||||
prop.valueDeclaration && hasModifier(prop.valueDeclaration, ModifierFlags.Private)) {
|
||||
if (getCheckFlags(prop) & CheckFlags.Instantiated) {
|
||||
getSymbolLinks(prop).target.isReferenced = true;
|
||||
}
|
||||
@@ -15705,9 +15722,10 @@ namespace ts {
|
||||
//
|
||||
// For a decorator, no arguments are susceptible to contextual typing due to the fact
|
||||
// decorators are applied to a declaration by the emitter, and not to an expression.
|
||||
const isSingleNonGenericCandidate = candidates.length === 1 && !candidates[0].typeParameters;
|
||||
let excludeArgument: boolean[];
|
||||
let excludeCount = 0;
|
||||
if (!isDecorator) {
|
||||
if (!isDecorator && !isSingleNonGenericCandidate) {
|
||||
// We do not need to call `getEffectiveArgumentCount` here as it only
|
||||
// applies when calculating the number of arguments for a decorator.
|
||||
for (let i = isTaggedTemplate ? 1 : 0; i < args.length; i++) {
|
||||
@@ -15860,6 +15878,19 @@ namespace ts {
|
||||
function chooseOverload(candidates: Signature[], relation: Map<RelationComparisonResult>, signatureHelpTrailingComma = false) {
|
||||
candidateForArgumentError = undefined;
|
||||
candidateForTypeArgumentError = undefined;
|
||||
|
||||
if (isSingleNonGenericCandidate) {
|
||||
const candidate = candidates[0];
|
||||
if (!hasCorrectArity(node, args, candidate, signatureHelpTrailingComma)) {
|
||||
return undefined;
|
||||
}
|
||||
if (!checkApplicableSignature(node, args, candidate, relation, excludeArgument, /*reportErrors*/ false)) {
|
||||
candidateForArgumentError = candidate;
|
||||
return undefined;
|
||||
}
|
||||
return candidate;
|
||||
}
|
||||
|
||||
for (let candidateIndex = 0; candidateIndex < candidates.length; candidateIndex++) {
|
||||
const originalCandidate = candidates[candidateIndex];
|
||||
if (!hasCorrectArity(node, args, originalCandidate, signatureHelpTrailingComma)) {
|
||||
@@ -15907,7 +15938,6 @@ namespace ts {
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function getLongestCandidateIndex(candidates: Signature[], argsCount: number): number {
|
||||
@@ -16039,7 +16069,7 @@ namespace ts {
|
||||
// In the case of a merged class-module or class-interface declaration,
|
||||
// only the class declaration node will have the Abstract flag set.
|
||||
const valueDecl = expressionType.symbol && getClassLikeDeclarationOfSymbol(expressionType.symbol);
|
||||
if (valueDecl && getModifierFlags(valueDecl) & ModifierFlags.Abstract) {
|
||||
if (valueDecl && hasModifier(valueDecl, ModifierFlags.Abstract)) {
|
||||
error(node, Diagnostics.Cannot_create_an_instance_of_the_abstract_class_0, declarationNameToString(getNameOfDeclaration(valueDecl)));
|
||||
return resolveErrorCall(node);
|
||||
}
|
||||
@@ -16092,10 +16122,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
const declaration = signature.declaration;
|
||||
const modifiers = getModifierFlags(declaration);
|
||||
const modifiers = getSelectedModifierFlags(declaration, ModifierFlags.NonPublicAccessibilityModifier);
|
||||
|
||||
// Public constructor is accessible.
|
||||
if (!(modifiers & ModifierFlags.NonPublicAccessibilityModifier)) {
|
||||
if (!modifiers) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -16333,7 +16363,7 @@ namespace ts {
|
||||
*/
|
||||
function checkCallExpression(node: CallExpression | NewExpression): Type {
|
||||
// Grammar checking; stop grammar-checking if checkGrammarTypeArguments return true
|
||||
checkGrammarTypeArguments(node, node.typeArguments) || checkGrammarArguments(node, node.arguments);
|
||||
checkGrammarTypeArguments(node, node.typeArguments) || checkGrammarArguments(node.arguments);
|
||||
|
||||
const signature = getResolvedSignature(node);
|
||||
|
||||
@@ -16381,7 +16411,7 @@ namespace ts {
|
||||
|
||||
function checkImportCallExpression(node: ImportCall): Type {
|
||||
// Check grammar of dynamic import
|
||||
checkGrammarArguments(node, node.arguments) || checkGrammarImportCallExpression(node);
|
||||
checkGrammarArguments(node.arguments) || checkGrammarImportCallExpression(node);
|
||||
|
||||
if (node.arguments.length === 0) {
|
||||
return createPromiseReturnType(node, anyType);
|
||||
@@ -16568,14 +16598,14 @@ namespace ts {
|
||||
|
||||
// When contextual typing assigns a type to a parameter that contains a binding pattern, we also need to push
|
||||
// the destructured type into the contained binding elements.
|
||||
function assignBindingElementTypes(node: VariableLikeDeclaration) {
|
||||
if (isBindingPattern(node.name)) {
|
||||
for (const element of node.name.elements) {
|
||||
if (!isOmittedExpression(element)) {
|
||||
if (element.name.kind === SyntaxKind.Identifier) {
|
||||
getSymbolLinks(getSymbolOfNode(element)).type = getTypeForBindingElement(element);
|
||||
}
|
||||
assignBindingElementTypes(element);
|
||||
function assignBindingElementTypes(pattern: BindingPattern) {
|
||||
for (const element of pattern.elements) {
|
||||
if (!isOmittedExpression(element)) {
|
||||
if (element.name.kind === SyntaxKind.Identifier) {
|
||||
getSymbolLinks(getSymbolOfNode(element)).type = getTypeForBindingElement(element);
|
||||
}
|
||||
else {
|
||||
assignBindingElementTypes(element.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16585,13 +16615,14 @@ namespace ts {
|
||||
const links = getSymbolLinks(parameter);
|
||||
if (!links.type) {
|
||||
links.type = contextualType;
|
||||
const name = getNameOfDeclaration(parameter.valueDeclaration);
|
||||
// if inference didn't come up with anything but {}, fall back to the binding pattern if present.
|
||||
if (links.type === emptyObjectType &&
|
||||
(name.kind === SyntaxKind.ObjectBindingPattern || name.kind === SyntaxKind.ArrayBindingPattern)) {
|
||||
links.type = getTypeFromBindingPattern(<BindingPattern>name);
|
||||
const decl = parameter.valueDeclaration as ParameterDeclaration;
|
||||
if (decl.name.kind !== SyntaxKind.Identifier) {
|
||||
// if inference didn't come up with anything but {}, fall back to the binding pattern if present.
|
||||
if (links.type === emptyObjectType) {
|
||||
links.type = getTypeFromBindingPattern(decl.name);
|
||||
}
|
||||
assignBindingElementTypes(decl.name);
|
||||
}
|
||||
assignBindingElementTypes(<ParameterDeclaration>parameter.valueDeclaration);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16851,18 +16882,18 @@ namespace ts {
|
||||
function checkFunctionExpressionOrObjectLiteralMethod(node: FunctionExpression | MethodDeclaration, checkMode?: CheckMode): Type {
|
||||
Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node));
|
||||
|
||||
// Grammar checking
|
||||
const hasGrammarError = checkGrammarFunctionLikeDeclaration(node);
|
||||
if (!hasGrammarError && node.kind === SyntaxKind.FunctionExpression) {
|
||||
checkGrammarForGenerator(node);
|
||||
}
|
||||
|
||||
// The identityMapper object is used to indicate that function expressions are wildcards
|
||||
if (checkMode === CheckMode.SkipContextSensitive && isContextSensitive(node)) {
|
||||
checkNodeDeferred(node);
|
||||
return anyFunctionType;
|
||||
}
|
||||
|
||||
// Grammar checking
|
||||
const hasGrammarError = checkGrammarFunctionLikeDeclaration(node);
|
||||
if (!hasGrammarError && node.kind === SyntaxKind.FunctionExpression) {
|
||||
checkGrammarForGenerator(node);
|
||||
}
|
||||
|
||||
const links = getNodeLinks(node);
|
||||
const type = getTypeOfSymbol(node.symbol);
|
||||
|
||||
@@ -17108,7 +17139,9 @@ namespace ts {
|
||||
if (operandType === silentNeverType) {
|
||||
return silentNeverType;
|
||||
}
|
||||
const ok = checkArithmeticOperandType(node.operand, checkNonNullType(operandType, node.operand),
|
||||
const ok = checkArithmeticOperandType(
|
||||
node.operand,
|
||||
checkNonNullType(operandType, node.operand),
|
||||
Diagnostics.An_arithmetic_operand_must_be_of_type_any_number_or_an_enum_type);
|
||||
if (ok) {
|
||||
// run check only if former checks succeeded to avoid reporting cascading errors
|
||||
@@ -17738,15 +17771,14 @@ namespace ts {
|
||||
return getBestChoiceType(type1, type2);
|
||||
}
|
||||
|
||||
function checkLiteralExpression(node: Expression): Type {
|
||||
if (node.kind === SyntaxKind.NumericLiteral) {
|
||||
checkGrammarNumericLiteral(<NumericLiteral>node);
|
||||
}
|
||||
function checkLiteralExpression(node: LiteralExpression | Token<SyntaxKind.TrueKeyword | SyntaxKind.FalseKeyword>): Type {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
||||
case SyntaxKind.StringLiteral:
|
||||
return getFreshTypeOfLiteralType(getLiteralType((<LiteralExpression>node).text));
|
||||
return getFreshTypeOfLiteralType(getLiteralType(node.text));
|
||||
case SyntaxKind.NumericLiteral:
|
||||
return getFreshTypeOfLiteralType(getLiteralType(+(<LiteralExpression>node).text));
|
||||
checkGrammarNumericLiteral(<NumericLiteral>node);
|
||||
return getFreshTypeOfLiteralType(getLiteralType(+node.text));
|
||||
case SyntaxKind.TrueKeyword:
|
||||
return trueType;
|
||||
case SyntaxKind.FalseKeyword:
|
||||
@@ -17964,15 +17996,14 @@ namespace ts {
|
||||
return checkSuperExpression(node);
|
||||
case SyntaxKind.NullKeyword:
|
||||
return nullWideningType;
|
||||
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
||||
case SyntaxKind.StringLiteral:
|
||||
case SyntaxKind.NumericLiteral:
|
||||
case SyntaxKind.TrueKeyword:
|
||||
case SyntaxKind.FalseKeyword:
|
||||
return checkLiteralExpression(node);
|
||||
return checkLiteralExpression(node as LiteralExpression);
|
||||
case SyntaxKind.TemplateExpression:
|
||||
return checkTemplateExpression(<TemplateExpression>node);
|
||||
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
||||
return stringType;
|
||||
case SyntaxKind.RegularExpressionLiteral:
|
||||
return globalRegExpType;
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
@@ -18077,7 +18108,7 @@ namespace ts {
|
||||
|
||||
checkVariableLikeDeclaration(node);
|
||||
let func = getContainingFunction(node);
|
||||
if (getModifierFlags(node) & ModifierFlags.ParameterPropertyModifier) {
|
||||
if (hasModifier(node, ModifierFlags.ParameterPropertyModifier)) {
|
||||
func = getContainingFunction(node);
|
||||
if (!(func.kind === SyntaxKind.Constructor && nodeIsPresent(func.body))) {
|
||||
error(node, Diagnostics.A_parameter_property_is_only_allowed_in_a_constructor_implementation);
|
||||
@@ -18312,7 +18343,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
else {
|
||||
const isStatic = getModifierFlags(member) & ModifierFlags.Static;
|
||||
const isStatic = hasModifier(member, ModifierFlags.Static);
|
||||
const names = isStatic ? staticNames : instanceNames;
|
||||
|
||||
const memberName = member.name && getPropertyNameForPropertyNameNode(member.name);
|
||||
@@ -18373,7 +18404,7 @@ namespace ts {
|
||||
function checkClassForStaticPropertyNameConflicts(node: ClassLikeDeclaration) {
|
||||
for (const member of node.members) {
|
||||
const memberNameNode = member.name;
|
||||
const isStatic = getModifierFlags(member) & ModifierFlags.Static;
|
||||
const isStatic = hasModifier(member, ModifierFlags.Static);
|
||||
if (isStatic && memberNameNode) {
|
||||
const memberName = getPropertyNameForPropertyNameNode(memberNameNode);
|
||||
switch (memberName) {
|
||||
@@ -18478,7 +18509,7 @@ namespace ts {
|
||||
|
||||
// Abstract methods cannot have an implementation.
|
||||
// Extra checks are to avoid reporting multiple errors relating to the "abstractness" of the node.
|
||||
if (getModifierFlags(node) & ModifierFlags.Abstract && node.body) {
|
||||
if (hasModifier(node, ModifierFlags.Abstract) && node.body) {
|
||||
error(node, Diagnostics.Method_0_cannot_have_an_implementation_because_it_is_marked_abstract, declarationNameToString(node.name));
|
||||
}
|
||||
}
|
||||
@@ -18529,7 +18560,7 @@ namespace ts {
|
||||
|
||||
function isInstancePropertyWithInitializer(n: Node): boolean {
|
||||
return n.kind === SyntaxKind.PropertyDeclaration &&
|
||||
!(getModifierFlags(n) & ModifierFlags.Static) &&
|
||||
!hasModifier(n, ModifierFlags.Static) &&
|
||||
!!(<PropertyDeclaration>n).initializer;
|
||||
}
|
||||
|
||||
@@ -18552,8 +18583,8 @@ namespace ts {
|
||||
// - The constructor declares parameter properties
|
||||
// or the containing class declares instance member variables with initializers.
|
||||
const superCallShouldBeFirst =
|
||||
forEach((<ClassDeclaration>node.parent).members, isInstancePropertyWithInitializer) ||
|
||||
forEach(node.parameters, p => getModifierFlags(p) & ModifierFlags.ParameterPropertyModifier);
|
||||
some((<ClassDeclaration>node.parent).members, isInstancePropertyWithInitializer) ||
|
||||
some(node.parameters, p => hasModifier(p, ModifierFlags.ParameterPropertyModifier));
|
||||
|
||||
// Skip past any prologue directives to find the first statement
|
||||
// to ensure that it was a super call.
|
||||
@@ -18607,10 +18638,12 @@ namespace ts {
|
||||
const otherKind = node.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor : SyntaxKind.GetAccessor;
|
||||
const otherAccessor = getDeclarationOfKind<AccessorDeclaration>(node.symbol, otherKind);
|
||||
if (otherAccessor) {
|
||||
if ((getModifierFlags(node) & ModifierFlags.AccessibilityModifier) !== (getModifierFlags(otherAccessor) & ModifierFlags.AccessibilityModifier)) {
|
||||
const nodeFlags = getModifierFlags(node);
|
||||
const otherFlags = getModifierFlags(otherAccessor);
|
||||
if ((nodeFlags & ModifierFlags.AccessibilityModifier) !== (otherFlags & ModifierFlags.AccessibilityModifier)) {
|
||||
error(node.name, Diagnostics.Getter_and_setter_accessors_do_not_agree_in_visibility);
|
||||
}
|
||||
if (hasModifier(node, ModifierFlags.Abstract) !== hasModifier(otherAccessor, ModifierFlags.Abstract)) {
|
||||
if ((nodeFlags & ModifierFlags.Abstract) !== (otherFlags & ModifierFlags.Abstract)) {
|
||||
error(node.name, Diagnostics.Accessors_must_both_be_abstract_or_non_abstract);
|
||||
}
|
||||
|
||||
@@ -18667,7 +18700,7 @@ namespace ts {
|
||||
function checkTypeReferenceNode(node: TypeReferenceNode | ExpressionWithTypeArguments) {
|
||||
checkGrammarTypeArguments(node, node.typeArguments);
|
||||
if (node.kind === SyntaxKind.TypeReference && node.typeName.jsdocDotPos !== undefined && !isInJavaScriptFile(node) && !isInJSDoc(node)) {
|
||||
grammarErrorAtPos(getSourceFileOfNode(node), node.typeName.jsdocDotPos, 1, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments);
|
||||
grammarErrorAtPos(node, node.typeName.jsdocDotPos, 1, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments);
|
||||
|
||||
}
|
||||
const type = getTypeFromTypeReference(node);
|
||||
@@ -18739,13 +18772,10 @@ namespace ts {
|
||||
if (isTypeAssignableTo(indexType, getIndexType(objectType))) {
|
||||
return type;
|
||||
}
|
||||
// Check if we're indexing with a numeric type and the object type is a generic
|
||||
// type with a constraint that has a numeric index signature.
|
||||
if (maybeTypeOfKind(objectType, TypeFlags.TypeVariable) && isTypeAssignableToKind(indexType, TypeFlags.NumberLike)) {
|
||||
const constraint = getBaseConstraintOfType(objectType);
|
||||
if (constraint && getIndexInfoOfType(constraint, IndexKind.Number)) {
|
||||
return type;
|
||||
}
|
||||
// Check if we're indexing with a numeric type and if either object or index types
|
||||
// is a generic type with a constraint that has a numeric index signature.
|
||||
if (getIndexInfoOfType(getApparentType(objectType), IndexKind.Number) && isTypeAssignableToKind(indexType, TypeFlags.NumberLike)) {
|
||||
return type;
|
||||
}
|
||||
error(accessNode, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(objectType));
|
||||
return type;
|
||||
@@ -18766,7 +18796,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function isPrivateWithinAmbient(node: Node): boolean {
|
||||
return (getModifierFlags(node) & ModifierFlags.Private) && isInAmbientContext(node);
|
||||
return hasModifier(node, ModifierFlags.Private) && isInAmbientContext(node);
|
||||
}
|
||||
|
||||
function getEffectiveDeclarationFlags(n: Node, flagsToCheck: ModifierFlags): ModifierFlags {
|
||||
@@ -18879,13 +18909,13 @@ namespace ts {
|
||||
!isComputedPropertyName(node.name) && !isComputedPropertyName(subsequentName) && getEscapedTextOfIdentifierOrLiteral(node.name) === getEscapedTextOfIdentifierOrLiteral(subsequentName))) {
|
||||
const reportError =
|
||||
(node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature) &&
|
||||
(getModifierFlags(node) & ModifierFlags.Static) !== (getModifierFlags(subsequentNode) & ModifierFlags.Static);
|
||||
hasModifier(node, ModifierFlags.Static) !== hasModifier(subsequentNode, ModifierFlags.Static);
|
||||
// we can get here in two cases
|
||||
// 1. mixed static and instance class members
|
||||
// 2. something with the same name was defined before the set of overloads that prevents them from merging
|
||||
// here we'll report error only for the first case since for second we should already report error in binder
|
||||
if (reportError) {
|
||||
const diagnostic = getModifierFlags(node) & ModifierFlags.Static ? Diagnostics.Function_overload_must_be_static : Diagnostics.Function_overload_must_not_be_static;
|
||||
const diagnostic = hasModifier(node, ModifierFlags.Static) ? Diagnostics.Function_overload_must_be_static : Diagnostics.Function_overload_must_not_be_static;
|
||||
error(errorNode, diagnostic);
|
||||
}
|
||||
return;
|
||||
@@ -18903,7 +18933,7 @@ namespace ts {
|
||||
else {
|
||||
// Report different errors regarding non-consecutive blocks of declarations depending on whether
|
||||
// the node in question is abstract.
|
||||
if (getModifierFlags(node) & ModifierFlags.Abstract) {
|
||||
if (hasModifier(node, ModifierFlags.Abstract)) {
|
||||
error(errorNode, Diagnostics.All_declarations_of_an_abstract_method_must_be_consecutive);
|
||||
}
|
||||
else {
|
||||
@@ -18979,7 +19009,7 @@ namespace ts {
|
||||
|
||||
// Abstract methods can't have an implementation -- in particular, they don't need one.
|
||||
if (lastSeenNonAmbientDeclaration && !lastSeenNonAmbientDeclaration.body &&
|
||||
!(getModifierFlags(lastSeenNonAmbientDeclaration) & ModifierFlags.Abstract) && !lastSeenNonAmbientDeclaration.questionToken) {
|
||||
!hasModifier(lastSeenNonAmbientDeclaration, ModifierFlags.Abstract) && !lastSeenNonAmbientDeclaration.questionToken) {
|
||||
reportImplementationExpectedError(lastSeenNonAmbientDeclaration);
|
||||
}
|
||||
|
||||
@@ -19625,7 +19655,7 @@ namespace ts {
|
||||
// checkFunctionOrConstructorSymbol wouldn't be called if we didnt ignore javascript function.
|
||||
const firstDeclaration = find(localSymbol.declarations,
|
||||
// Get first non javascript function declaration
|
||||
declaration => declaration.kind === node.kind && !isSourceFileJavaScript(getSourceFileOfNode(declaration)));
|
||||
declaration => declaration.kind === node.kind && !(declaration.flags & NodeFlags.JavaScriptFile));
|
||||
|
||||
// Only type check the symbol once
|
||||
if (node === firstDeclaration) {
|
||||
@@ -19782,13 +19812,13 @@ namespace ts {
|
||||
if (node.members) {
|
||||
for (const member of node.members) {
|
||||
if (member.kind === SyntaxKind.MethodDeclaration || member.kind === SyntaxKind.PropertyDeclaration) {
|
||||
if (!member.symbol.isReferenced && getModifierFlags(member) & ModifierFlags.Private) {
|
||||
if (!member.symbol.isReferenced && hasModifier(member, ModifierFlags.Private)) {
|
||||
error(member.name, Diagnostics._0_is_declared_but_never_used, unescapeLeadingUnderscores(member.symbol.escapedName));
|
||||
}
|
||||
}
|
||||
else if (member.kind === SyntaxKind.Constructor) {
|
||||
for (const parameter of (<ConstructorDeclaration>member).parameters) {
|
||||
if (!parameter.symbol.isReferenced && getModifierFlags(parameter) & ModifierFlags.Private) {
|
||||
if (!parameter.symbol.isReferenced && hasModifier(parameter, ModifierFlags.Private)) {
|
||||
error(parameter.name, Diagnostics.Property_0_is_declared_but_never_used, unescapeLeadingUnderscores(parameter.symbol.escapedName));
|
||||
}
|
||||
}
|
||||
@@ -20258,7 +20288,7 @@ namespace ts {
|
||||
ModifierFlags.Readonly |
|
||||
ModifierFlags.Static;
|
||||
|
||||
return (getModifierFlags(left) & interestingFlags) === (getModifierFlags(right) & interestingFlags);
|
||||
return getSelectedModifierFlags(left, interestingFlags) === getSelectedModifierFlags(right, interestingFlags);
|
||||
}
|
||||
|
||||
function checkVariableDeclaration(node: VariableDeclaration) {
|
||||
@@ -21011,7 +21041,7 @@ namespace ts {
|
||||
// Only process instance properties with computed names here.
|
||||
// Static properties cannot be in conflict with indexers,
|
||||
// and properties with literal names were already checked.
|
||||
if (!(getModifierFlags(member) & ModifierFlags.Static) && hasDynamicName(member)) {
|
||||
if (!hasModifier(member, ModifierFlags.Static) && hasDynamicName(member)) {
|
||||
const propType = getTypeOfSymbol(member.symbol);
|
||||
checkIndexConstraintForProperty(member.symbol, propType, type, declaredStringIndexer, stringIndexType, IndexKind.String);
|
||||
checkIndexConstraintForProperty(member.symbol, propType, type, declaredNumberIndexer, numberIndexType, IndexKind.Number);
|
||||
@@ -21206,7 +21236,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function checkClassDeclaration(node: ClassDeclaration) {
|
||||
if (!node.name && !(getModifierFlags(node) & ModifierFlags.Default)) {
|
||||
if (!node.name && !hasModifier(node, ModifierFlags.Default)) {
|
||||
grammarErrorOnFirstToken(node, Diagnostics.A_class_declaration_without_the_default_modifier_must_have_a_name);
|
||||
}
|
||||
checkClassLikeDeclaration(node);
|
||||
@@ -21312,7 +21342,7 @@ namespace ts {
|
||||
const signatures = getSignaturesOfType(type, SignatureKind.Construct);
|
||||
if (signatures.length) {
|
||||
const declaration = signatures[0].declaration;
|
||||
if (declaration && getModifierFlags(declaration) & ModifierFlags.Private) {
|
||||
if (declaration && hasModifier(declaration, ModifierFlags.Private)) {
|
||||
const typeClassDeclaration = <ClassLikeDeclaration>getClassLikeDeclarationOfSymbol(type.symbol);
|
||||
if (!isNodeWithinClass(node, typeClassDeclaration)) {
|
||||
error(node, Diagnostics.Cannot_extend_a_class_0_Class_constructor_is_marked_as_private, getFullyQualifiedName(type.symbol));
|
||||
@@ -21378,7 +21408,7 @@ namespace ts {
|
||||
// It is an error to inherit an abstract member without implementing it or being declared abstract.
|
||||
// If there is no declaration for the derived class (as in the case of class expressions),
|
||||
// then the class cannot be declared abstract.
|
||||
if (baseDeclarationFlags & ModifierFlags.Abstract && (!derivedClassDecl || !(getModifierFlags(derivedClassDecl) & ModifierFlags.Abstract))) {
|
||||
if (baseDeclarationFlags & ModifierFlags.Abstract && (!derivedClassDecl || !hasModifier(derivedClassDecl, ModifierFlags.Abstract))) {
|
||||
if (derivedClassDecl.kind === SyntaxKind.ClassExpression) {
|
||||
error(derivedClassDecl, Diagnostics.Non_abstract_class_expression_does_not_implement_inherited_abstract_member_0_from_class_1,
|
||||
symbolToString(baseProperty), typeToString(baseType));
|
||||
@@ -22001,7 +22031,7 @@ namespace ts {
|
||||
// If we hit an import declaration in an illegal context, just bail out to avoid cascading errors.
|
||||
return;
|
||||
}
|
||||
if (!checkGrammarDecorators(node) && !checkGrammarModifiers(node) && getModifierFlags(node) !== 0) {
|
||||
if (!checkGrammarDecorators(node) && !checkGrammarModifiers(node) && hasModifiers(node)) {
|
||||
grammarErrorOnFirstToken(node, Diagnostics.An_import_declaration_cannot_have_modifiers);
|
||||
}
|
||||
if (checkExternalImportOrExportDeclaration(node)) {
|
||||
@@ -22031,7 +22061,7 @@ namespace ts {
|
||||
checkGrammarDecorators(node) || checkGrammarModifiers(node);
|
||||
if (isInternalModuleImportEqualsDeclaration(node) || checkExternalImportOrExportDeclaration(node)) {
|
||||
checkImportBinding(node);
|
||||
if (getModifierFlags(node) & ModifierFlags.Export) {
|
||||
if (hasModifier(node, ModifierFlags.Export)) {
|
||||
markExportAsReferenced(node);
|
||||
}
|
||||
if (isInternalModuleImportEqualsDeclaration(node)) {
|
||||
@@ -22064,7 +22094,7 @@ namespace ts {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!checkGrammarDecorators(node) && !checkGrammarModifiers(node) && getModifierFlags(node) !== 0) {
|
||||
if (!checkGrammarDecorators(node) && !checkGrammarModifiers(node) && hasModifiers(node)) {
|
||||
grammarErrorOnFirstToken(node, Diagnostics.An_export_declaration_cannot_have_modifiers);
|
||||
}
|
||||
|
||||
@@ -22137,7 +22167,7 @@ namespace ts {
|
||||
return;
|
||||
}
|
||||
// Grammar checking
|
||||
if (!checkGrammarDecorators(node) && !checkGrammarModifiers(node) && getModifierFlags(node) !== 0) {
|
||||
if (!checkGrammarDecorators(node) && !checkGrammarModifiers(node) && hasModifiers(node)) {
|
||||
grammarErrorOnFirstToken(node, Diagnostics.An_export_assignment_cannot_have_modifiers);
|
||||
}
|
||||
if (node.expression.kind === SyntaxKind.Identifier) {
|
||||
@@ -22535,7 +22565,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
const symbols = createSymbolTable();
|
||||
let memberFlags: ModifierFlags = ModifierFlags.None;
|
||||
let isStatic = false;
|
||||
|
||||
populateSymbols();
|
||||
|
||||
@@ -22568,7 +22598,7 @@ namespace ts {
|
||||
// add the type parameters into the symbol table
|
||||
// (type parameters of classDeclaration/classExpression and interface are in member property of the symbol.
|
||||
// Note: that the memberFlags come from previous iteration.
|
||||
if (!(memberFlags & ModifierFlags.Static)) {
|
||||
if (!isStatic) {
|
||||
copySymbols(getSymbolOfNode(location).members, meaning & SymbolFlags.Type);
|
||||
}
|
||||
break;
|
||||
@@ -22584,7 +22614,7 @@ namespace ts {
|
||||
copySymbol(argumentsSymbol, meaning);
|
||||
}
|
||||
|
||||
memberFlags = getModifierFlags(location);
|
||||
isStatic = hasModifier(location, ModifierFlags.Static);
|
||||
location = location.parent;
|
||||
}
|
||||
|
||||
@@ -22891,10 +22921,7 @@ namespace ts {
|
||||
// index access
|
||||
if (node.parent.kind === SyntaxKind.ElementAccessExpression && (<ElementAccessExpression>node.parent).argumentExpression === node) {
|
||||
const objectType = getTypeOfExpression((<ElementAccessExpression>node.parent).expression);
|
||||
if (objectType === unknownType) return undefined;
|
||||
const apparentType = getApparentType(objectType);
|
||||
if (apparentType === unknownType) return undefined;
|
||||
return getPropertyOfType(apparentType, (<NumericLiteral>node).text as __String);
|
||||
return getPropertyOfType(objectType, (<NumericLiteral>node).text as __String);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -23045,7 +23072,7 @@ namespace ts {
|
||||
*/
|
||||
function getParentTypeOfClassElement(node: ClassElement) {
|
||||
const classSymbol = getSymbolOfNode(node.parent);
|
||||
return getModifierFlags(node) & ModifierFlags.Static
|
||||
return hasModifier(node, ModifierFlags.Static)
|
||||
? getTypeOfSymbol(classSymbol)
|
||||
: getDeclaredTypeOfSymbol(classSymbol);
|
||||
}
|
||||
@@ -23357,14 +23384,14 @@ namespace ts {
|
||||
return strictNullChecks &&
|
||||
!isOptionalParameter(parameter) &&
|
||||
parameter.initializer &&
|
||||
!(getModifierFlags(parameter) & ModifierFlags.ParameterPropertyModifier);
|
||||
!hasModifier(parameter, ModifierFlags.ParameterPropertyModifier);
|
||||
}
|
||||
|
||||
function isOptionalUninitializedParameterProperty(parameter: ParameterDeclaration) {
|
||||
return strictNullChecks &&
|
||||
isOptionalParameter(parameter) &&
|
||||
!parameter.initializer &&
|
||||
!!(getModifierFlags(parameter) & ModifierFlags.ParameterPropertyModifier);
|
||||
hasModifier(parameter, ModifierFlags.ParameterPropertyModifier);
|
||||
}
|
||||
|
||||
function getNodeCheckFlags(node: Node): NodeCheckFlags {
|
||||
@@ -23979,7 +24006,7 @@ namespace ts {
|
||||
node.kind !== SyntaxKind.SetAccessor) {
|
||||
return grammarErrorOnNode(modifier, Diagnostics.abstract_modifier_can_only_appear_on_a_class_method_or_property_declaration);
|
||||
}
|
||||
if (!(node.parent.kind === SyntaxKind.ClassDeclaration && getModifierFlags(node.parent) & ModifierFlags.Abstract)) {
|
||||
if (!(node.parent.kind === SyntaxKind.ClassDeclaration && hasModifier(node.parent, ModifierFlags.Abstract))) {
|
||||
return grammarErrorOnNode(modifier, Diagnostics.Abstract_methods_can_only_appear_within_an_abstract_class);
|
||||
}
|
||||
if (flags & ModifierFlags.Static) {
|
||||
@@ -24109,8 +24136,7 @@ namespace ts {
|
||||
if (list && list.hasTrailingComma) {
|
||||
const start = list.end - ",".length;
|
||||
const end = list.end;
|
||||
const sourceFile = getSourceFileOfNode(list[0]);
|
||||
return grammarErrorAtPos(sourceFile, start, end - start, Diagnostics.Trailing_comma_not_allowed);
|
||||
return grammarErrorAtPos(list[0], start, end - start, Diagnostics.Trailing_comma_not_allowed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24199,7 +24225,7 @@ namespace ts {
|
||||
if (parameter.dotDotDotToken) {
|
||||
return grammarErrorOnNode(parameter.dotDotDotToken, Diagnostics.An_index_signature_cannot_have_a_rest_parameter);
|
||||
}
|
||||
if (getModifierFlags(parameter) !== 0) {
|
||||
if (hasModifiers(parameter)) {
|
||||
return grammarErrorOnNode(parameter.name, Diagnostics.An_index_signature_parameter_cannot_have_an_accessibility_modifier);
|
||||
}
|
||||
if (parameter.questionToken) {
|
||||
@@ -24238,19 +24264,18 @@ namespace ts {
|
||||
checkGrammarForAtLeastOneTypeArgument(node, typeArguments);
|
||||
}
|
||||
|
||||
function checkGrammarForOmittedArgument(node: CallExpression | NewExpression, args: NodeArray<Expression>): boolean {
|
||||
function checkGrammarForOmittedArgument(args: NodeArray<Expression>): boolean {
|
||||
if (args) {
|
||||
const sourceFile = getSourceFileOfNode(node);
|
||||
for (const arg of args) {
|
||||
if (arg.kind === SyntaxKind.OmittedExpression) {
|
||||
return grammarErrorAtPos(sourceFile, arg.pos, 0, Diagnostics.Argument_expression_expected);
|
||||
return grammarErrorAtPos(arg, arg.pos, 0, Diagnostics.Argument_expression_expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkGrammarArguments(node: CallExpression | NewExpression, args: NodeArray<Expression>): boolean {
|
||||
return checkGrammarForOmittedArgument(node, args);
|
||||
function checkGrammarArguments(args: NodeArray<Expression>): boolean {
|
||||
return checkGrammarForOmittedArgument(args);
|
||||
}
|
||||
|
||||
function checkGrammarHeritageClause(node: HeritageClause): boolean {
|
||||
@@ -24260,8 +24285,7 @@ namespace ts {
|
||||
}
|
||||
if (types && types.length === 0) {
|
||||
const listType = tokenToString(node.token);
|
||||
const sourceFile = getSourceFileOfNode(node);
|
||||
return grammarErrorAtPos(sourceFile, types.pos, 0, Diagnostics._0_list_cannot_be_empty, listType);
|
||||
return grammarErrorAtPos(node, types.pos, 0, Diagnostics._0_list_cannot_be_empty, listType);
|
||||
}
|
||||
return forEach(types, checkGrammarExpressionWithTypeArguments);
|
||||
}
|
||||
@@ -24538,10 +24562,10 @@ namespace ts {
|
||||
else if (isInAmbientContext(accessor)) {
|
||||
return grammarErrorOnNode(accessor.name, Diagnostics.An_accessor_cannot_be_declared_in_an_ambient_context);
|
||||
}
|
||||
else if (accessor.body === undefined && !(getModifierFlags(accessor) & ModifierFlags.Abstract)) {
|
||||
return grammarErrorAtPos(getSourceFileOfNode(accessor), accessor.end - 1, ";".length, Diagnostics._0_expected, "{");
|
||||
else if (accessor.body === undefined && !hasModifier(accessor, ModifierFlags.Abstract)) {
|
||||
return grammarErrorAtPos(accessor, accessor.end - 1, ";".length, Diagnostics._0_expected, "{");
|
||||
}
|
||||
else if (accessor.body && getModifierFlags(accessor) & ModifierFlags.Abstract) {
|
||||
else if (accessor.body && hasModifier(accessor, ModifierFlags.Abstract)) {
|
||||
return grammarErrorOnNode(accessor, Diagnostics.An_abstract_accessor_cannot_have_an_implementation);
|
||||
}
|
||||
else if (accessor.typeParameters) {
|
||||
@@ -24604,7 +24628,7 @@ namespace ts {
|
||||
return true;
|
||||
}
|
||||
else if (node.body === undefined) {
|
||||
return grammarErrorAtPos(getSourceFileOfNode(node), node.end - 1, ";".length, Diagnostics._0_expected, "{");
|
||||
return grammarErrorAtPos(node, node.end - 1, ";".length, Diagnostics._0_expected, "{");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24696,7 +24720,7 @@ namespace ts {
|
||||
|
||||
if (node.initializer) {
|
||||
// Error on equals token which immediately precedes the initializer
|
||||
return grammarErrorAtPos(getSourceFileOfNode(node), node.initializer.pos - 1, 1, Diagnostics.A_rest_element_cannot_have_an_initializer);
|
||||
return grammarErrorAtPos(node, node.initializer.pos - 1, 1, Diagnostics.A_rest_element_cannot_have_an_initializer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24719,15 +24743,13 @@ namespace ts {
|
||||
else {
|
||||
// Error on equals token which immediate precedes the initializer
|
||||
const equalsTokenLength = "=".length;
|
||||
return grammarErrorAtPos(getSourceFileOfNode(node), node.initializer.pos - equalsTokenLength,
|
||||
equalsTokenLength, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts);
|
||||
return grammarErrorAtPos(node, node.initializer.pos - equalsTokenLength, equalsTokenLength, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts);
|
||||
}
|
||||
}
|
||||
if (node.initializer && !(isConst(node) && isStringOrNumberLiteralExpression(node.initializer))) {
|
||||
// Error on equals token which immediate precedes the initializer
|
||||
const equalsTokenLength = "=".length;
|
||||
return grammarErrorAtPos(getSourceFileOfNode(node), node.initializer.pos - equalsTokenLength,
|
||||
equalsTokenLength, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts);
|
||||
return grammarErrorAtPos(node, node.initializer.pos - equalsTokenLength, equalsTokenLength, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts);
|
||||
}
|
||||
}
|
||||
else if (!node.initializer) {
|
||||
@@ -24796,7 +24818,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (!declarationList.declarations.length) {
|
||||
return grammarErrorAtPos(getSourceFileOfNode(declarationList), declarations.pos, declarations.end - declarations.pos, Diagnostics.Variable_declaration_list_cannot_be_empty);
|
||||
return grammarErrorAtPos(declarationList, declarations.pos, declarations.end - declarations.pos, Diagnostics.Variable_declaration_list_cannot_be_empty);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24849,7 +24871,8 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function grammarErrorAtPos(sourceFile: SourceFile, start: number, length: number, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean {
|
||||
function grammarErrorAtPos(nodeForSourceFile: Node, start: number, length: number, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean {
|
||||
const sourceFile = getSourceFileOfNode(nodeForSourceFile);
|
||||
if (!hasParseDiagnostics(sourceFile)) {
|
||||
diagnostics.add(createFileDiagnostic(sourceFile, start, length, message, arg0, arg1, arg2));
|
||||
return true;
|
||||
@@ -24866,7 +24889,7 @@ namespace ts {
|
||||
|
||||
function checkGrammarConstructorTypeParameters(node: ConstructorDeclaration) {
|
||||
if (node.typeParameters) {
|
||||
return grammarErrorAtPos(getSourceFileOfNode(node), node.typeParameters.pos, node.typeParameters.end - node.typeParameters.pos, Diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration);
|
||||
return grammarErrorAtPos(node, node.typeParameters.pos, node.typeParameters.end - node.typeParameters.pos, Diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24924,7 +24947,7 @@ namespace ts {
|
||||
node.kind === SyntaxKind.ExportDeclaration ||
|
||||
node.kind === SyntaxKind.ExportAssignment ||
|
||||
node.kind === SyntaxKind.NamespaceExportDeclaration ||
|
||||
getModifierFlags(node) & (ModifierFlags.Ambient | ModifierFlags.Export | ModifierFlags.Default)) {
|
||||
hasModifier(node, ModifierFlags.Ambient | ModifierFlags.Export | ModifierFlags.Default)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -340,7 +340,6 @@ namespace ts {
|
||||
isTSConfigOnly: true,
|
||||
category: Diagnostics.Module_Resolution_Options,
|
||||
description: Diagnostics.A_series_of_entries_which_re_map_imports_to_lookup_locations_relative_to_the_baseUrl
|
||||
|
||||
},
|
||||
{
|
||||
// this option can only be specified in tsconfig.json
|
||||
@@ -384,6 +383,12 @@ namespace ts {
|
||||
category: Diagnostics.Module_Resolution_Options,
|
||||
description: Diagnostics.Allow_default_imports_from_modules_with_no_default_export_This_does_not_affect_code_emit_just_typechecking
|
||||
},
|
||||
{
|
||||
name: "preserveSymlinks",
|
||||
type: "boolean",
|
||||
category: Diagnostics.Module_Resolution_Options,
|
||||
description: Diagnostics.Do_not_resolve_the_real_path_of_symlinks,
|
||||
},
|
||||
|
||||
// Source Maps
|
||||
{
|
||||
@@ -1111,7 +1116,7 @@ namespace ts {
|
||||
if (option && typeof option.type !== "string") {
|
||||
const customOption = <CommandLineOptionOfCustomType>option;
|
||||
// Validate custom option type
|
||||
if (!customOption.type.has(text)) {
|
||||
if (!customOption.type.has(text.toLowerCase())) {
|
||||
errors.push(
|
||||
createDiagnosticForInvalidCustomType(
|
||||
customOption,
|
||||
@@ -1806,7 +1811,7 @@ namespace ts {
|
||||
return value;
|
||||
}
|
||||
else if (typeof option.type !== "string") {
|
||||
return option.type.get(value);
|
||||
return option.type.get(typeof value === "string" ? value.toLowerCase() : value);
|
||||
}
|
||||
return normalizeNonListOptionValue(option, basePath, value);
|
||||
}
|
||||
|
||||
@@ -415,17 +415,7 @@ namespace ts {
|
||||
* @return true if the comment is a triple-slash comment else false
|
||||
*/
|
||||
function isTripleSlashComment(commentPos: number, commentEnd: number) {
|
||||
// Verify this is /// comment, but do the regexp match only when we first can find /// in the comment text
|
||||
// so that we don't end up computing comment string and doing match for all // comments
|
||||
if (currentText.charCodeAt(commentPos + 1) === CharacterCodes.slash &&
|
||||
commentPos + 2 < commentEnd &&
|
||||
currentText.charCodeAt(commentPos + 2) === CharacterCodes.slash) {
|
||||
const textSubStr = currentText.substring(commentPos, commentEnd);
|
||||
return textSubStr.match(fullTripleSlashReferencePathRegEx) ||
|
||||
textSubStr.match(fullTripleSlashAMDReferencePathRegEx) ?
|
||||
true : false;
|
||||
}
|
||||
return false;
|
||||
return isRecognizedTripleSlashComment(currentText, commentPos, commentEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
+15
-14
@@ -501,13 +501,15 @@ namespace ts {
|
||||
return result || array;
|
||||
}
|
||||
|
||||
export function mapDefined<T, U>(array: ReadonlyArray<T>, mapFn: (x: T, i: number) => U | undefined): U[] {
|
||||
export function mapDefined<T, U>(array: ReadonlyArray<T> | undefined, mapFn: (x: T, i: number) => U | undefined): U[] {
|
||||
const result: U[] = [];
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
const item = array[i];
|
||||
const mapped = mapFn(item, i);
|
||||
if (mapped !== undefined) {
|
||||
result.push(mapped);
|
||||
if (array) {
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
const item = array[i];
|
||||
const mapped = mapFn(item, i);
|
||||
if (mapped !== undefined) {
|
||||
result.push(mapped);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -2208,20 +2210,14 @@ namespace ts {
|
||||
/** Must have ".d.ts" first because if ".ts" goes first, that will be detected as the extension instead of ".d.ts". */
|
||||
export const supportedTypescriptExtensionsForExtractExtension: ReadonlyArray<Extension> = [Extension.Dts, Extension.Ts, Extension.Tsx];
|
||||
export const supportedJavascriptExtensions: ReadonlyArray<Extension> = [Extension.Js, Extension.Jsx];
|
||||
const allSupportedExtensions = [...supportedTypeScriptExtensions, ...supportedJavascriptExtensions];
|
||||
const allSupportedExtensions: ReadonlyArray<Extension> = [...supportedTypeScriptExtensions, ...supportedJavascriptExtensions];
|
||||
|
||||
export function getSupportedExtensions(options?: CompilerOptions, extraFileExtensions?: ReadonlyArray<JsFileExtensionInfo>): ReadonlyArray<string> {
|
||||
const needAllExtensions = options && options.allowJs;
|
||||
if (!extraFileExtensions || extraFileExtensions.length === 0 || !needAllExtensions) {
|
||||
return needAllExtensions ? allSupportedExtensions : supportedTypeScriptExtensions;
|
||||
}
|
||||
const extensions: string[] = allSupportedExtensions.slice(0);
|
||||
for (const extInfo of extraFileExtensions) {
|
||||
if (extensions.indexOf(extInfo.extension) === -1) {
|
||||
extensions.push(extInfo.extension);
|
||||
}
|
||||
}
|
||||
return extensions;
|
||||
return deduplicate([...allSupportedExtensions, ...extraFileExtensions.map(e => e.extension)]);
|
||||
}
|
||||
|
||||
export function hasJavaScriptFileExtension(fileName: string) {
|
||||
@@ -2588,6 +2584,11 @@ namespace ts {
|
||||
}
|
||||
Debug.fail(`File ${path} has unknown extension.`);
|
||||
}
|
||||
|
||||
export function isAnySupportedFileExtension(path: string): boolean {
|
||||
return tryGetExtensionFromPath(path) !== undefined;
|
||||
}
|
||||
|
||||
export function tryGetExtensionFromPath(path: string): Extension | undefined {
|
||||
return find<Extension>(supportedTypescriptExtensionsForExtractExtension, e => fileExtensionIs(path, e)) || find(supportedJavascriptExtensions, e => fileExtensionIs(path, e));
|
||||
}
|
||||
|
||||
@@ -349,7 +349,6 @@ namespace ts {
|
||||
errorNameNode = declaration.name;
|
||||
const format = TypeFormatFlags.UseTypeOfFunction |
|
||||
TypeFormatFlags.WriteClassExpressionAsTypeLiteral |
|
||||
TypeFormatFlags.UseTypeAliasValue |
|
||||
(shouldUseResolverType ? TypeFormatFlags.AddUndefined : 0);
|
||||
resolver.writeTypeOfDeclaration(declaration, enclosingDeclaration, format, writer);
|
||||
errorNameNode = undefined;
|
||||
@@ -368,7 +367,7 @@ namespace ts {
|
||||
resolver.writeReturnTypeOfSignatureDeclaration(
|
||||
signature,
|
||||
enclosingDeclaration,
|
||||
TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseTypeAliasValue | TypeFormatFlags.WriteClassExpressionAsTypeLiteral,
|
||||
TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.WriteClassExpressionAsTypeLiteral,
|
||||
writer);
|
||||
errorNameNode = undefined;
|
||||
}
|
||||
@@ -633,7 +632,7 @@ namespace ts {
|
||||
resolver.writeTypeOfExpression(
|
||||
expr,
|
||||
enclosingDeclaration,
|
||||
TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseTypeAliasValue | TypeFormatFlags.WriteClassExpressionAsTypeLiteral,
|
||||
TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.WriteClassExpressionAsTypeLiteral,
|
||||
writer);
|
||||
write(";");
|
||||
writeLine();
|
||||
@@ -1367,6 +1366,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
function writeVariableStatement(node: VariableStatement) {
|
||||
// If binding pattern doesn't have name, then there is nothing to be emitted for declaration file i.e. const [,] = [1,2].
|
||||
if (every(node.declarationList && node.declarationList.declarations, decl => decl.name && isEmptyBindingPattern(decl.name))) {
|
||||
return;
|
||||
}
|
||||
emitJsDocComments(node);
|
||||
emitModuleElementDeclarationFlags(node);
|
||||
if (isLet(node.declarationList)) {
|
||||
|
||||
@@ -2662,6 +2662,10 @@
|
||||
"category": "Message",
|
||||
"code": 6012
|
||||
},
|
||||
"Do not resolve the real path of symlinks.": {
|
||||
"category": "Message",
|
||||
"code": 6013
|
||||
},
|
||||
"Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'.": {
|
||||
"category": "Message",
|
||||
"code": 6015
|
||||
@@ -3677,5 +3681,15 @@
|
||||
"Convert function '{0}' to class": {
|
||||
"category": "Message",
|
||||
"code": 95002
|
||||
},
|
||||
|
||||
"Extract function": {
|
||||
"category": "Message",
|
||||
"code": 95003
|
||||
},
|
||||
|
||||
"Extract function into '{0}'": {
|
||||
"category": "Message",
|
||||
"code": 95004
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1195,7 +1195,9 @@ namespace ts {
|
||||
if (!(getEmitFlags(node) & EmitFlags.NoIndentation)) {
|
||||
const dotRangeStart = node.expression.end;
|
||||
const dotRangeEnd = skipTrivia(currentSourceFile.text, node.expression.end) + 1;
|
||||
const dotToken = <Node>{ kind: SyntaxKind.DotToken, pos: dotRangeStart, end: dotRangeEnd };
|
||||
const dotToken = createToken(SyntaxKind.DotToken);
|
||||
dotToken.pos = dotRangeStart;
|
||||
dotToken.end = dotRangeEnd;
|
||||
indentBeforeDot = needsIndentation(node, node.expression, dotToken);
|
||||
indentAfterDot = needsIndentation(node, dotToken, node.name);
|
||||
}
|
||||
@@ -1348,7 +1350,7 @@ namespace ts {
|
||||
increaseIndentIf(indentBeforeOperator, isCommaOperator ? " " : undefined);
|
||||
emitLeadingCommentsOfPosition(node.operatorToken.pos);
|
||||
writeTokenNode(node.operatorToken);
|
||||
emitTrailingCommentsOfPosition(node.operatorToken.end);
|
||||
emitTrailingCommentsOfPosition(node.operatorToken.end, /*prefixSpace*/ true); // Binary operators should have a space before the comment starts
|
||||
increaseIndentIf(indentAfterOperator, " ");
|
||||
emitExpression(node.right);
|
||||
decreaseIndentIf(indentBeforeOperator, indentAfterOperator);
|
||||
|
||||
@@ -2586,7 +2586,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function addSyntheticLeadingComment<T extends Node>(node: T, kind: SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia, text: string, hasTrailingNewLine?: boolean) {
|
||||
return setSyntheticLeadingComments(node, append(getSyntheticLeadingComments(node), <SynthesizedComment>{ kind, pos: -1, end: -1, hasTrailingNewLine, text }));
|
||||
return setSyntheticLeadingComments(node, append<SynthesizedComment>(getSyntheticLeadingComments(node), { kind, pos: -1, end: -1, hasTrailingNewLine, text }));
|
||||
}
|
||||
|
||||
export function getSyntheticTrailingComments(node: Node): SynthesizedComment[] | undefined {
|
||||
@@ -2600,7 +2600,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function addSyntheticTrailingComment<T extends Node>(node: T, kind: SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia, text: string, hasTrailingNewLine?: boolean) {
|
||||
return setSyntheticTrailingComments(node, append(getSyntheticTrailingComments(node), <SynthesizedComment>{ kind, pos: -1, end: -1, hasTrailingNewLine, text }));
|
||||
return setSyntheticTrailingComments(node, append<SynthesizedComment>(getSyntheticTrailingComments(node), { kind, pos: -1, end: -1, hasTrailingNewLine, text }));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,13 +13,32 @@ namespace ts {
|
||||
return compilerOptions.traceResolution && host.trace !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Result of trying to resolve a module.
|
||||
* At least one of `ts` and `js` should be defined, or the whole thing should be `undefined`.
|
||||
*/
|
||||
/** Array that is only intended to be pushed to, never read. */
|
||||
/* @internal */
|
||||
export interface Push<T> {
|
||||
push(value: T): void;
|
||||
}
|
||||
|
||||
function withPackageId(packageId: PackageId | undefined, r: PathAndExtension | undefined): Resolved {
|
||||
return r && { path: r.path, extension: r.ext, packageId };
|
||||
}
|
||||
|
||||
function noPackageId(r: PathAndExtension | undefined): Resolved {
|
||||
return withPackageId(/*packageId*/ undefined, r);
|
||||
}
|
||||
|
||||
/** Result of trying to resolve a module. */
|
||||
interface Resolved {
|
||||
path: string;
|
||||
extension: Extension;
|
||||
packageId: PackageId | undefined;
|
||||
}
|
||||
|
||||
/** Result of trying to resolve a module at a file. Needs to have 'packageId' added later. */
|
||||
interface PathAndExtension {
|
||||
path: string;
|
||||
// (Use a different name than `extension` to make sure Resolved isn't assignable to PathAndExtension.)
|
||||
ext: Extension;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,7 +62,7 @@ namespace ts {
|
||||
|
||||
function createResolvedModuleWithFailedLookupLocations(resolved: Resolved | undefined, isExternalLibraryImport: boolean, failedLookupLocations: string[]): ResolvedModuleWithFailedLookupLocations {
|
||||
return {
|
||||
resolvedModule: resolved && { resolvedFileName: resolved.path, extension: resolved.extension, isExternalLibraryImport },
|
||||
resolvedModule: resolved && { resolvedFileName: resolved.path, extension: resolved.extension, isExternalLibraryImport, packageId: resolved.packageId },
|
||||
failedLookupLocations
|
||||
};
|
||||
}
|
||||
@@ -54,9 +73,16 @@ namespace ts {
|
||||
traceEnabled: boolean;
|
||||
}
|
||||
|
||||
interface PackageJson {
|
||||
name?: string;
|
||||
version?: string;
|
||||
typings?: string;
|
||||
types?: string;
|
||||
main?: string;
|
||||
}
|
||||
|
||||
/** Reads from "main" or "types"/"typings" depending on `extensions`. */
|
||||
function tryReadPackageJsonFields(readTypes: boolean, packageJsonPath: string, baseDirectory: string, state: ModuleResolutionState): string | undefined {
|
||||
const jsonContent = readJson(packageJsonPath, state.host);
|
||||
function tryReadPackageJsonFields(readTypes: boolean, jsonContent: PackageJson, baseDirectory: string, state: ModuleResolutionState): string | undefined {
|
||||
return readTypes ? tryReadFromField("typings") || tryReadFromField("types") : tryReadFromField("main");
|
||||
|
||||
function tryReadFromField(fieldName: "typings" | "types" | "main"): string | undefined {
|
||||
@@ -83,7 +109,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function readJson(path: string, host: ModuleResolutionHost): { typings?: string, types?: string, main?: string } {
|
||||
function readJson(path: string, host: ModuleResolutionHost): PackageJson {
|
||||
try {
|
||||
const jsonText = host.readFile(path);
|
||||
return jsonText ? JSON.parse(jsonText) : {};
|
||||
@@ -174,7 +200,10 @@ namespace ts {
|
||||
|
||||
let resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined;
|
||||
if (resolved) {
|
||||
resolved = realpath(resolved, host, traceEnabled);
|
||||
if (!options.preserveSymlinks) {
|
||||
resolved = realPath(resolved, host, traceEnabled);
|
||||
}
|
||||
|
||||
if (traceEnabled) {
|
||||
trace(host, Diagnostics.Type_reference_directive_0_was_successfully_resolved_to_1_primary_Colon_2, typeReferenceDirectiveName, resolved, primary);
|
||||
}
|
||||
@@ -646,7 +675,7 @@ namespace ts {
|
||||
if (extension !== undefined) {
|
||||
const path = tryFile(candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state);
|
||||
if (path !== undefined) {
|
||||
return { path, extension };
|
||||
return { path, extension, packageId: undefined };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -708,8 +737,14 @@ namespace ts {
|
||||
trace(host, Diagnostics.Loading_module_0_from_node_modules_folder_target_file_type_1, moduleName, Extensions[extensions]);
|
||||
}
|
||||
const resolved = loadModuleFromNodeModules(extensions, moduleName, containingDirectory, failedLookupLocations, state, cache);
|
||||
if (!resolved) return undefined;
|
||||
|
||||
let resolvedValue = resolved.value;
|
||||
if (!compilerOptions.preserveSymlinks) {
|
||||
resolvedValue = resolvedValue && { ...resolved.value, path: realPath(resolved.value.path, host, traceEnabled), extension: resolved.value.extension };
|
||||
}
|
||||
// For node_modules lookups, get the real path so that multiple accesses to an `npm link`-ed module do not create duplicate files.
|
||||
return resolved && { value: resolved.value && { resolved: { path: realpath(resolved.value.path, host, traceEnabled), extension: resolved.value.extension }, isExternalLibraryImport: true } };
|
||||
return { value: resolvedValue && { resolved: resolvedValue, isExternalLibraryImport: true } };
|
||||
}
|
||||
else {
|
||||
const candidate = normalizePath(combinePaths(containingDirectory, moduleName));
|
||||
@@ -719,7 +754,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function realpath(path: string, host: ModuleResolutionHost, traceEnabled: boolean): string {
|
||||
function realPath(path: string, host: ModuleResolutionHost, traceEnabled: boolean): string {
|
||||
if (!host.realpath) {
|
||||
return path;
|
||||
}
|
||||
@@ -747,7 +782,7 @@ namespace ts {
|
||||
}
|
||||
const resolvedFromFile = loadModuleFromFile(extensions, candidate, failedLookupLocations, onlyRecordFailures, state);
|
||||
if (resolvedFromFile) {
|
||||
return resolvedFromFile;
|
||||
return noPackageId(resolvedFromFile);
|
||||
}
|
||||
}
|
||||
if (!onlyRecordFailures) {
|
||||
@@ -768,11 +803,15 @@ namespace ts {
|
||||
return !host.directoryExists || host.directoryExists(directoryName);
|
||||
}
|
||||
|
||||
function loadModuleFromFileNoPackageId(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved {
|
||||
return noPackageId(loadModuleFromFile(extensions, candidate, failedLookupLocations, onlyRecordFailures, state));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} onlyRecordFailures - if true then function won't try to actually load files but instead record all attempts as failures. This flag is necessary
|
||||
* in cases when we know upfront that all load attempts will fail (because containing folder does not exists) however we still need to record all failed lookup locations.
|
||||
*/
|
||||
function loadModuleFromFile(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved | undefined {
|
||||
function loadModuleFromFile(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
|
||||
// First, try adding an extension. An import of "foo" could be matched by a file "foo.ts", or "foo.js" by "foo.js.ts"
|
||||
const resolvedByAddingExtension = tryAddingExtensions(candidate, extensions, failedLookupLocations, onlyRecordFailures, state);
|
||||
if (resolvedByAddingExtension) {
|
||||
@@ -792,7 +831,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
/** Try to return an existing file that adds one of the `extensions` to `candidate`. */
|
||||
function tryAddingExtensions(candidate: string, extensions: Extensions, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved | undefined {
|
||||
function tryAddingExtensions(candidate: string, extensions: Extensions, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
|
||||
if (!onlyRecordFailures) {
|
||||
// check if containing folder exists - if it doesn't then just record failures for all supported extensions without disk probing
|
||||
const directory = getDirectoryPath(candidate);
|
||||
@@ -810,9 +849,9 @@ namespace ts {
|
||||
return tryExtension(Extension.Js) || tryExtension(Extension.Jsx);
|
||||
}
|
||||
|
||||
function tryExtension(extension: Extension): Resolved | undefined {
|
||||
const path = tryFile(candidate + extension, failedLookupLocations, onlyRecordFailures, state);
|
||||
return path && { path, extension };
|
||||
function tryExtension(ext: Extension): PathAndExtension | undefined {
|
||||
const path = tryFile(candidate + ext, failedLookupLocations, onlyRecordFailures, state);
|
||||
return path && { path, ext };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -838,12 +877,23 @@ namespace ts {
|
||||
function loadNodeModuleFromDirectory(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson = true): Resolved | undefined {
|
||||
const directoryExists = !onlyRecordFailures && directoryProbablyExists(candidate, state.host);
|
||||
|
||||
let packageId: PackageId | undefined;
|
||||
|
||||
if (considerPackageJson) {
|
||||
const packageJsonPath = pathToPackageJson(candidate);
|
||||
if (directoryExists && state.host.fileExists(packageJsonPath)) {
|
||||
const fromPackageJson = loadModuleFromPackageJson(packageJsonPath, extensions, candidate, failedLookupLocations, state);
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.Found_package_json_at_0, packageJsonPath);
|
||||
}
|
||||
const jsonContent = readJson(packageJsonPath, state.host);
|
||||
|
||||
if (typeof jsonContent.name === "string" && typeof jsonContent.version === "string") {
|
||||
packageId = { name: jsonContent.name, version: jsonContent.version };
|
||||
}
|
||||
|
||||
const fromPackageJson = loadModuleFromPackageJson(jsonContent, extensions, candidate, failedLookupLocations, state);
|
||||
if (fromPackageJson) {
|
||||
return fromPackageJson;
|
||||
return withPackageId(packageId, fromPackageJson);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -855,15 +905,11 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
return loadModuleFromFile(extensions, combinePaths(candidate, "index"), failedLookupLocations, !directoryExists, state);
|
||||
return withPackageId(packageId, loadModuleFromFile(extensions, combinePaths(candidate, "index"), failedLookupLocations, !directoryExists, state));
|
||||
}
|
||||
|
||||
function loadModuleFromPackageJson(packageJsonPath: string, extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.Found_package_json_at_0, packageJsonPath);
|
||||
}
|
||||
|
||||
const file = tryReadPackageJsonFields(extensions !== Extensions.JavaScript, packageJsonPath, candidate, state);
|
||||
function loadModuleFromPackageJson(jsonContent: PackageJson, extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, state: ModuleResolutionState): PathAndExtension | undefined {
|
||||
const file = tryReadPackageJsonFields(extensions !== Extensions.JavaScript, jsonContent, candidate, state);
|
||||
if (!file) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -883,13 +929,18 @@ namespace ts {
|
||||
// Even if extensions is DtsOnly, we can still look up a .ts file as a result of package.json "types"
|
||||
const nextExtensions = extensions === Extensions.DtsOnly ? Extensions.TypeScript : extensions;
|
||||
// Don't do package.json lookup recursively, because Node.js' package lookup doesn't.
|
||||
return nodeLoadModuleByRelativeName(nextExtensions, file, failedLookupLocations, onlyRecordFailures, state, /*considerPackageJson*/ false);
|
||||
const result = nodeLoadModuleByRelativeName(nextExtensions, file, failedLookupLocations, onlyRecordFailures, state, /*considerPackageJson*/ false);
|
||||
if (result) {
|
||||
// It won't have a `packageId` set, because we disabled `considerPackageJson`.
|
||||
Debug.assert(result.packageId === undefined);
|
||||
return { path: result.path, ext: result.extension };
|
||||
}
|
||||
}
|
||||
|
||||
/** Resolve from an arbitrarily specified file. Return `undefined` if it has an unsupported extension. */
|
||||
function resolvedIfExtensionMatches(extensions: Extensions, path: string): Resolved | undefined {
|
||||
const extension = tryGetExtensionFromPath(path);
|
||||
return extension !== undefined && extensionIsOk(extensions, extension) ? { path, extension } : undefined;
|
||||
function resolvedIfExtensionMatches(extensions: Extensions, path: string): PathAndExtension | undefined {
|
||||
const ext = tryGetExtensionFromPath(path);
|
||||
return ext !== undefined && extensionIsOk(extensions, ext) ? { path, ext } : undefined;
|
||||
}
|
||||
|
||||
/** True if `extension` is one of the supported `extensions`. */
|
||||
@@ -911,7 +962,7 @@ namespace ts {
|
||||
function loadModuleFromNodeModulesFolder(extensions: Extensions, moduleName: string, nodeModulesFolder: string, nodeModulesFolderExists: boolean, failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
|
||||
const candidate = normalizePath(combinePaths(nodeModulesFolder, moduleName));
|
||||
|
||||
return loadModuleFromFile(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state) ||
|
||||
return loadModuleFromFileNoPackageId(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state) ||
|
||||
loadNodeModuleFromDirectory(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state);
|
||||
}
|
||||
|
||||
@@ -996,7 +1047,7 @@ namespace ts {
|
||||
if (traceEnabled) {
|
||||
trace(host, Diagnostics.Resolution_for_module_0_was_found_in_cache, moduleName);
|
||||
}
|
||||
return { value: result.resolvedModule && { path: result.resolvedModule.resolvedFileName, extension: result.resolvedModule.extension } };
|
||||
return { value: result.resolvedModule && { path: result.resolvedModule.resolvedFileName, extension: result.resolvedModule.extension, packageId: result.resolvedModule.packageId } };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1010,7 +1061,7 @@ namespace ts {
|
||||
return createResolvedModuleWithFailedLookupLocations(resolved && resolved.value, /*isExternalLibraryImport*/ false, failedLookupLocations);
|
||||
|
||||
function tryResolve(extensions: Extensions): SearchResult<Resolved> {
|
||||
const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loadModuleFromFile, failedLookupLocations, state);
|
||||
const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loadModuleFromFileNoPackageId, failedLookupLocations, state);
|
||||
if (resolvedUsingSettings) {
|
||||
return { value: resolvedUsingSettings };
|
||||
}
|
||||
@@ -1024,7 +1075,7 @@ namespace ts {
|
||||
return resolutionFromCache;
|
||||
}
|
||||
const searchName = normalizePath(combinePaths(directory, moduleName));
|
||||
return toSearchResult(loadModuleFromFile(extensions, searchName, failedLookupLocations, /*onlyRecordFailures*/ false, state));
|
||||
return toSearchResult(loadModuleFromFileNoPackageId(extensions, searchName, failedLookupLocations, /*onlyRecordFailures*/ false, state));
|
||||
});
|
||||
if (resolved) {
|
||||
return resolved;
|
||||
@@ -1036,7 +1087,7 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
const candidate = normalizePath(combinePaths(containingDirectory, moduleName));
|
||||
return toSearchResult(loadModuleFromFile(extensions, candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state));
|
||||
return toSearchResult(loadModuleFromFileNoPackageId(extensions, candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3202,7 +3202,7 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const isAsync = !!(getModifierFlags(arrowFunction) & ModifierFlags.Async);
|
||||
const isAsync = hasModifier(arrowFunction, ModifierFlags.Async);
|
||||
|
||||
// If we have an arrow, then try to parse the body. Even if not, try to parse if we
|
||||
// have an opening brace, just in case we're in an error state.
|
||||
@@ -3382,7 +3382,7 @@ namespace ts {
|
||||
function parseParenthesizedArrowFunctionExpressionHead(allowAmbiguity: boolean): ArrowFunction {
|
||||
const node = <ArrowFunction>createNode(SyntaxKind.ArrowFunction);
|
||||
node.modifiers = parseModifiersForArrowFunction();
|
||||
const isAsync = (getModifierFlags(node) & ModifierFlags.Async) ? SignatureFlags.Await : SignatureFlags.None;
|
||||
const isAsync = hasModifier(node, ModifierFlags.Async) ? SignatureFlags.Await : SignatureFlags.None;
|
||||
|
||||
// Arrow functions are never generators.
|
||||
//
|
||||
@@ -4515,7 +4515,7 @@ namespace ts {
|
||||
node.asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken);
|
||||
|
||||
const isGenerator = node.asteriskToken ? SignatureFlags.Yield : SignatureFlags.None;
|
||||
const isAsync = (getModifierFlags(node) & ModifierFlags.Async) ? SignatureFlags.Await : SignatureFlags.None;
|
||||
const isAsync = hasModifier(node, ModifierFlags.Async) ? SignatureFlags.Await : SignatureFlags.None;
|
||||
node.name =
|
||||
isGenerator && isAsync ? doInYieldAndAwaitContext(parseOptionalIdentifier) :
|
||||
isGenerator ? doInYieldContext(parseOptionalIdentifier) :
|
||||
@@ -6169,7 +6169,7 @@ namespace ts {
|
||||
|
||||
export function parseIsolatedJSDocComment(content: string, start: number, length: number): { jsDoc: JSDoc, diagnostics: Diagnostic[] } | undefined {
|
||||
initializeState(content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS);
|
||||
sourceFile = <SourceFile>{ languageVariant: LanguageVariant.Standard, text: content };
|
||||
sourceFile = <SourceFile>{ languageVariant: LanguageVariant.Standard, text: content }; // tslint:disable-line no-object-literal-type-assertion
|
||||
const jsDoc = parseJSDocCommentWorker(start, length);
|
||||
const diagnostics = parseDiagnostics;
|
||||
clearState();
|
||||
|
||||
+98
-6
@@ -472,6 +472,15 @@ namespace ts {
|
||||
resolveTypeReferenceDirectiveNamesWorker = (typeReferenceDirectiveNames, containingFile) => loadWithLocalCache(checkAllDefined(typeReferenceDirectiveNames), containingFile, loader);
|
||||
}
|
||||
|
||||
// Map from a stringified PackageId to the source file with that id.
|
||||
// Only one source file may have a given packageId. Others become redirects (see createRedirectSourceFile).
|
||||
// `packageIdToSourceFile` is only used while building the program, while `sourceFileToPackageName` and `isSourceFileTargetOfRedirect` are kept around.
|
||||
const packageIdToSourceFile = createMap<SourceFile>();
|
||||
// Maps from a SourceFile's `.path` to the name of the package it was imported with.
|
||||
let sourceFileToPackageName = createMap<string>();
|
||||
// See `sourceFileIsRedirectedTo`.
|
||||
let redirectTargetsSet = createMap<true>();
|
||||
|
||||
const filesByName = createMap<SourceFile | undefined>();
|
||||
// stores 'filename -> file association' ignoring case
|
||||
// used to track cases when two file names differ only in casing
|
||||
@@ -548,6 +557,8 @@ namespace ts {
|
||||
isSourceFileFromExternalLibrary,
|
||||
dropDiagnosticsProducingTypeChecker,
|
||||
getSourceFileFromReference,
|
||||
sourceFileToPackageName,
|
||||
redirectTargetsSet,
|
||||
};
|
||||
|
||||
verifyCompilerOptions();
|
||||
@@ -773,8 +784,12 @@ namespace ts {
|
||||
const modifiedSourceFiles: { oldFile: SourceFile, newFile: SourceFile }[] = [];
|
||||
oldProgram.structureIsReused = StructureIsReused.Completely;
|
||||
|
||||
for (const oldSourceFile of oldProgram.getSourceFiles()) {
|
||||
const newSourceFile = host.getSourceFileByPath
|
||||
const oldSourceFiles = oldProgram.getSourceFiles();
|
||||
const enum SeenPackageName { Exists, Modified }
|
||||
const seenPackageNames = createMap<SeenPackageName>();
|
||||
|
||||
for (const oldSourceFile of oldSourceFiles) {
|
||||
let newSourceFile = host.getSourceFileByPath
|
||||
? host.getSourceFileByPath(oldSourceFile.fileName, oldSourceFile.path, options.target)
|
||||
: host.getSourceFile(oldSourceFile.fileName, options.target);
|
||||
|
||||
@@ -782,10 +797,46 @@ namespace ts {
|
||||
return oldProgram.structureIsReused = StructureIsReused.Not;
|
||||
}
|
||||
|
||||
Debug.assert(!newSourceFile.redirectInfo, "Host should not return a redirect source file from `getSourceFile`");
|
||||
|
||||
let fileChanged: boolean;
|
||||
if (oldSourceFile.redirectInfo) {
|
||||
// We got `newSourceFile` by path, so it is actually for the unredirected file.
|
||||
// This lets us know if the unredirected file has changed. If it has we should break the redirect.
|
||||
if (newSourceFile !== oldSourceFile.redirectInfo.unredirected) {
|
||||
// Underlying file has changed. Might not redirect anymore. Must rebuild program.
|
||||
return oldProgram.structureIsReused = StructureIsReused.Not;
|
||||
}
|
||||
fileChanged = false;
|
||||
newSourceFile = oldSourceFile; // Use the redirect.
|
||||
}
|
||||
else if (oldProgram.redirectTargetsSet.has(oldSourceFile.path)) {
|
||||
// If a redirected-to source file changes, the redirect may be broken.
|
||||
if (newSourceFile !== oldSourceFile) {
|
||||
return oldProgram.structureIsReused = StructureIsReused.Not;
|
||||
}
|
||||
fileChanged = false;
|
||||
}
|
||||
else {
|
||||
fileChanged = newSourceFile !== oldSourceFile;
|
||||
}
|
||||
|
||||
newSourceFile.path = oldSourceFile.path;
|
||||
filePaths.push(newSourceFile.path);
|
||||
|
||||
if (oldSourceFile !== newSourceFile) {
|
||||
const packageName = oldProgram.sourceFileToPackageName.get(oldSourceFile.path);
|
||||
if (packageName !== undefined) {
|
||||
// If there are 2 different source files for the same package name and at least one of them changes,
|
||||
// they might become redirects. So we must rebuild the program.
|
||||
const prevKind = seenPackageNames.get(packageName);
|
||||
const newKind = fileChanged ? SeenPackageName.Modified : SeenPackageName.Exists;
|
||||
if ((prevKind !== undefined && newKind === SeenPackageName.Modified) || prevKind === SeenPackageName.Modified) {
|
||||
return oldProgram.structureIsReused = StructureIsReused.Not;
|
||||
}
|
||||
seenPackageNames.set(packageName, newKind);
|
||||
}
|
||||
|
||||
if (fileChanged) {
|
||||
// The `newSourceFile` object was created for the new program.
|
||||
|
||||
if (oldSourceFile.hasNoDefaultLib !== newSourceFile.hasNoDefaultLib) {
|
||||
@@ -897,6 +948,9 @@ namespace ts {
|
||||
}
|
||||
resolvedTypeReferenceDirectives = oldProgram.getResolvedTypeReferenceDirectives();
|
||||
|
||||
sourceFileToPackageName = oldProgram.sourceFileToPackageName;
|
||||
redirectTargetsSet = oldProgram.redirectTargetsSet;
|
||||
|
||||
return oldProgram.structureIsReused = StructureIsReused.Completely;
|
||||
}
|
||||
|
||||
@@ -1537,7 +1591,7 @@ namespace ts {
|
||||
/** This has side effects through `findSourceFile`. */
|
||||
function processSourceFile(fileName: string, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): void {
|
||||
getSourceFileFromReferenceWorker(fileName,
|
||||
fileName => findSourceFile(fileName, toPath(fileName), isDefaultLib, refFile, refPos, refEnd),
|
||||
fileName => findSourceFile(fileName, toPath(fileName), isDefaultLib, refFile, refPos, refEnd, /*packageId*/ undefined),
|
||||
(diagnostic, ...args) => {
|
||||
fileProcessingDiagnostics.add(refFile !== undefined && refEnd !== undefined && refPos !== undefined
|
||||
? createFileDiagnostic(refFile, refPos, refEnd - refPos, diagnostic, ...args)
|
||||
@@ -1556,8 +1610,26 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function createRedirectSourceFile(redirectTarget: SourceFile, unredirected: SourceFile, fileName: string, path: Path): SourceFile {
|
||||
const redirect: SourceFile = Object.create(redirectTarget);
|
||||
redirect.fileName = fileName;
|
||||
redirect.path = path;
|
||||
redirect.redirectInfo = { redirectTarget, unredirected };
|
||||
Object.defineProperties(redirect, {
|
||||
id: {
|
||||
get(this: SourceFile) { return this.redirectInfo.redirectTarget.id; },
|
||||
set(this: SourceFile, value: SourceFile["id"]) { this.redirectInfo.redirectTarget.id = value; },
|
||||
},
|
||||
symbol: {
|
||||
get(this: SourceFile) { return this.redirectInfo.redirectTarget.symbol; },
|
||||
set(this: SourceFile, value: SourceFile["symbol"]) { this.redirectInfo.redirectTarget.symbol = value; },
|
||||
},
|
||||
});
|
||||
return redirect;
|
||||
}
|
||||
|
||||
// Get source file from normalized fileName
|
||||
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): SourceFile {
|
||||
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, refFile: SourceFile, refPos: number, refEnd: number, packageId: PackageId | undefined): SourceFile | undefined {
|
||||
if (filesByName.has(path)) {
|
||||
const file = filesByName.get(path);
|
||||
// try to check if we've already seen this file but with a different casing in path
|
||||
@@ -1600,6 +1672,26 @@ namespace ts {
|
||||
}
|
||||
});
|
||||
|
||||
if (packageId) {
|
||||
const packageIdKey = `${packageId.name}@${packageId.version}`;
|
||||
const fileFromPackageId = packageIdToSourceFile.get(packageIdKey);
|
||||
if (fileFromPackageId) {
|
||||
// Some other SourceFile already exists with this package name and version.
|
||||
// Instead of creating a duplicate, just redirect to the existing one.
|
||||
const dupFile = createRedirectSourceFile(fileFromPackageId, file, fileName, path);
|
||||
redirectTargetsSet.set(fileFromPackageId.path, true);
|
||||
filesByName.set(path, dupFile);
|
||||
sourceFileToPackageName.set(path, packageId.name);
|
||||
files.push(dupFile);
|
||||
return dupFile;
|
||||
}
|
||||
else if (file) {
|
||||
// This is the first source file to have this packageId.
|
||||
packageIdToSourceFile.set(packageIdKey, file);
|
||||
sourceFileToPackageName.set(path, packageId.name);
|
||||
}
|
||||
}
|
||||
|
||||
filesByName.set(path, file);
|
||||
if (file) {
|
||||
sourceFilesFoundSearchingNodeModules.set(path, currentNodeModulesDepth > 0);
|
||||
@@ -1762,7 +1854,7 @@ namespace ts {
|
||||
else if (shouldAddFile) {
|
||||
const path = toPath(resolvedFileName);
|
||||
const pos = skipTrivia(file.text, file.imports[i].pos);
|
||||
findSourceFile(resolvedFileName, path, /*isDefaultLib*/ false, file, pos, file.imports[i].end);
|
||||
findSourceFile(resolvedFileName, path, /*isDefaultLib*/ false, file, pos, file.imports[i].end, resolution.packageId);
|
||||
}
|
||||
|
||||
if (isFromNodeModulesSearch) {
|
||||
|
||||
@@ -331,11 +331,14 @@ namespace ts {
|
||||
location
|
||||
);
|
||||
}
|
||||
else if (numElements !== 1 && (flattenContext.level < FlattenLevel.ObjectRest || numElements === 0)) {
|
||||
else if (numElements !== 1 && (flattenContext.level < FlattenLevel.ObjectRest || numElements === 0)
|
||||
|| every(elements, isOmittedExpression)) {
|
||||
// For anything other than a single-element destructuring we need to generate a temporary
|
||||
// to ensure value is evaluated exactly once. Additionally, if we have zero elements
|
||||
// we need to emit *something* to ensure that in case a 'var' keyword was already emitted,
|
||||
// so in that case, we'll intentionally create that temporary.
|
||||
// Or all the elements of the binding pattern are omitted expression such as "var [,] = [1,2]",
|
||||
// then we will create temporary variable.
|
||||
const reuseIdentifierExpressions = !isDeclarationBindingElement(parent) || numElements !== 0;
|
||||
value = ensureIdentifier(flattenContext, value, reuseIdentifierExpressions, location);
|
||||
}
|
||||
|
||||
@@ -394,7 +394,7 @@ namespace ts {
|
||||
function shouldVisitNode(node: Node): boolean {
|
||||
return (node.transformFlags & TransformFlags.ContainsES2015) !== 0
|
||||
|| convertedLoopState !== undefined
|
||||
|| (hierarchyFacts & HierarchyFacts.ConstructorWithCapturedSuper && isStatement(node))
|
||||
|| (hierarchyFacts & HierarchyFacts.ConstructorWithCapturedSuper && (isStatement(node) || (node.kind === SyntaxKind.Block)))
|
||||
|| (isIterationStatement(node, /*lookInLabeledStatements*/ false) && shouldConvertIterationStatementBody(node))
|
||||
|| isTypeScriptClassWrapper(node);
|
||||
}
|
||||
@@ -840,7 +840,7 @@ namespace ts {
|
||||
outer.end = skipTrivia(currentText, node.pos);
|
||||
setEmitFlags(outer, EmitFlags.NoComments);
|
||||
|
||||
return createParen(
|
||||
const result = createParen(
|
||||
createCall(
|
||||
outer,
|
||||
/*typeArguments*/ undefined,
|
||||
@@ -849,6 +849,8 @@ namespace ts {
|
||||
: []
|
||||
)
|
||||
);
|
||||
addSyntheticLeadingComment(result, SyntaxKind.MultiLineCommentTrivia, "* @class ");
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2105,13 +2107,14 @@ namespace ts {
|
||||
setCommentRange(declarationList, node);
|
||||
|
||||
if (node.transformFlags & TransformFlags.ContainsBindingPattern
|
||||
&& (isBindingPattern(node.declarations[0].name)
|
||||
|| isBindingPattern(lastOrUndefined(node.declarations).name))) {
|
||||
&& (isBindingPattern(node.declarations[0].name) || isBindingPattern(lastOrUndefined(node.declarations).name))) {
|
||||
// If the first or last declaration is a binding pattern, we need to modify
|
||||
// the source map range for the declaration list.
|
||||
const firstDeclaration = firstOrUndefined(declarations);
|
||||
const lastDeclaration = lastOrUndefined(declarations);
|
||||
setSourceMapRange(declarationList, createRange(firstDeclaration.pos, lastDeclaration.end));
|
||||
if (firstDeclaration) {
|
||||
const lastDeclaration = lastOrUndefined(declarations);
|
||||
setSourceMapRange(declarationList, createRange(firstDeclaration.pos, lastDeclaration.end));
|
||||
}
|
||||
}
|
||||
|
||||
return declarationList;
|
||||
|
||||
@@ -164,12 +164,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
// A generated code block
|
||||
interface CodeBlock {
|
||||
kind: CodeBlockKind;
|
||||
}
|
||||
type CodeBlock = | ExceptionBlock | LabeledBlock | SwitchBlock | LoopBlock | WithBlock;
|
||||
|
||||
// a generated exception block, used for 'try' statements
|
||||
interface ExceptionBlock extends CodeBlock {
|
||||
interface ExceptionBlock {
|
||||
kind: CodeBlockKind.Exception;
|
||||
state: ExceptionBlockState;
|
||||
startLabel: Label;
|
||||
catchVariable?: Identifier;
|
||||
@@ -179,27 +178,31 @@ namespace ts {
|
||||
}
|
||||
|
||||
// A generated code that tracks the target for 'break' statements in a LabeledStatement.
|
||||
interface LabeledBlock extends CodeBlock {
|
||||
interface LabeledBlock {
|
||||
kind: CodeBlockKind.Labeled;
|
||||
labelText: string;
|
||||
isScript: boolean;
|
||||
breakLabel: Label;
|
||||
}
|
||||
|
||||
// a generated block that tracks the target for 'break' statements in a 'switch' statement
|
||||
interface SwitchBlock extends CodeBlock {
|
||||
interface SwitchBlock {
|
||||
kind: CodeBlockKind.Switch;
|
||||
isScript: boolean;
|
||||
breakLabel: Label;
|
||||
}
|
||||
|
||||
// a generated block that tracks the targets for 'break' and 'continue' statements, used for iteration statements
|
||||
interface LoopBlock extends CodeBlock {
|
||||
interface LoopBlock {
|
||||
kind: CodeBlockKind.Loop;
|
||||
continueLabel: Label;
|
||||
isScript: boolean;
|
||||
breakLabel: Label;
|
||||
}
|
||||
|
||||
// a generated block associated with a 'with' statement
|
||||
interface WithBlock extends CodeBlock {
|
||||
interface WithBlock {
|
||||
kind: CodeBlockKind.With;
|
||||
expression: Identifier;
|
||||
startLabel: Label;
|
||||
endLabel: Label;
|
||||
@@ -2070,7 +2073,7 @@ namespace ts {
|
||||
const startLabel = defineLabel();
|
||||
const endLabel = defineLabel();
|
||||
markLabel(startLabel);
|
||||
beginBlock(<WithBlock>{
|
||||
beginBlock({
|
||||
kind: CodeBlockKind.With,
|
||||
expression,
|
||||
startLabel,
|
||||
@@ -2087,10 +2090,6 @@ namespace ts {
|
||||
markLabel(block.endLabel);
|
||||
}
|
||||
|
||||
function isWithBlock(block: CodeBlock): block is WithBlock {
|
||||
return block.kind === CodeBlockKind.With;
|
||||
}
|
||||
|
||||
/**
|
||||
* Begins a code block for a generated `try` statement.
|
||||
*/
|
||||
@@ -2098,7 +2097,7 @@ namespace ts {
|
||||
const startLabel = defineLabel();
|
||||
const endLabel = defineLabel();
|
||||
markLabel(startLabel);
|
||||
beginBlock(<ExceptionBlock>{
|
||||
beginBlock({
|
||||
kind: CodeBlockKind.Exception,
|
||||
state: ExceptionBlockState.Try,
|
||||
startLabel,
|
||||
@@ -2188,10 +2187,6 @@ namespace ts {
|
||||
exception.state = ExceptionBlockState.Done;
|
||||
}
|
||||
|
||||
function isExceptionBlock(block: CodeBlock): block is ExceptionBlock {
|
||||
return block.kind === CodeBlockKind.Exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Begins a code block that supports `break` or `continue` statements that are defined in
|
||||
* the source tree and not from generated code.
|
||||
@@ -2199,7 +2194,7 @@ namespace ts {
|
||||
* @param labelText Names from containing labeled statements.
|
||||
*/
|
||||
function beginScriptLoopBlock(): void {
|
||||
beginBlock(<LoopBlock>{
|
||||
beginBlock({
|
||||
kind: CodeBlockKind.Loop,
|
||||
isScript: true,
|
||||
breakLabel: -1,
|
||||
@@ -2217,7 +2212,7 @@ namespace ts {
|
||||
*/
|
||||
function beginLoopBlock(continueLabel: Label): Label {
|
||||
const breakLabel = defineLabel();
|
||||
beginBlock(<LoopBlock>{
|
||||
beginBlock({
|
||||
kind: CodeBlockKind.Loop,
|
||||
isScript: false,
|
||||
breakLabel,
|
||||
@@ -2245,7 +2240,7 @@ namespace ts {
|
||||
*
|
||||
*/
|
||||
function beginScriptSwitchBlock(): void {
|
||||
beginBlock(<SwitchBlock>{
|
||||
beginBlock({
|
||||
kind: CodeBlockKind.Switch,
|
||||
isScript: true,
|
||||
breakLabel: -1
|
||||
@@ -2259,7 +2254,7 @@ namespace ts {
|
||||
*/
|
||||
function beginSwitchBlock(): Label {
|
||||
const breakLabel = defineLabel();
|
||||
beginBlock(<SwitchBlock>{
|
||||
beginBlock({
|
||||
kind: CodeBlockKind.Switch,
|
||||
isScript: false,
|
||||
breakLabel,
|
||||
@@ -2280,7 +2275,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function beginScriptLabeledBlock(labelText: string) {
|
||||
beginBlock(<LabeledBlock>{
|
||||
beginBlock({
|
||||
kind: CodeBlockKind.Labeled,
|
||||
isScript: true,
|
||||
labelText,
|
||||
@@ -2290,7 +2285,7 @@ namespace ts {
|
||||
|
||||
function beginLabeledBlock(labelText: string) {
|
||||
const breakLabel = defineLabel();
|
||||
beginBlock(<LabeledBlock>{
|
||||
beginBlock({
|
||||
kind: CodeBlockKind.Labeled,
|
||||
isScript: false,
|
||||
labelText,
|
||||
@@ -2878,34 +2873,37 @@ namespace ts {
|
||||
for (; blockIndex < blockActions.length && blockOffsets[blockIndex] <= operationIndex; blockIndex++) {
|
||||
const block = blocks[blockIndex];
|
||||
const blockAction = blockActions[blockIndex];
|
||||
if (isExceptionBlock(block)) {
|
||||
if (blockAction === BlockAction.Open) {
|
||||
if (!exceptionBlockStack) {
|
||||
exceptionBlockStack = [];
|
||||
}
|
||||
switch (block.kind) {
|
||||
case CodeBlockKind.Exception:
|
||||
if (blockAction === BlockAction.Open) {
|
||||
if (!exceptionBlockStack) {
|
||||
exceptionBlockStack = [];
|
||||
}
|
||||
|
||||
if (!statements) {
|
||||
statements = [];
|
||||
}
|
||||
if (!statements) {
|
||||
statements = [];
|
||||
}
|
||||
|
||||
exceptionBlockStack.push(currentExceptionBlock);
|
||||
currentExceptionBlock = block;
|
||||
}
|
||||
else if (blockAction === BlockAction.Close) {
|
||||
currentExceptionBlock = exceptionBlockStack.pop();
|
||||
}
|
||||
}
|
||||
else if (isWithBlock(block)) {
|
||||
if (blockAction === BlockAction.Open) {
|
||||
if (!withBlockStack) {
|
||||
withBlockStack = [];
|
||||
exceptionBlockStack.push(currentExceptionBlock);
|
||||
currentExceptionBlock = block;
|
||||
}
|
||||
else if (blockAction === BlockAction.Close) {
|
||||
currentExceptionBlock = exceptionBlockStack.pop();
|
||||
}
|
||||
break;
|
||||
case CodeBlockKind.With:
|
||||
if (blockAction === BlockAction.Open) {
|
||||
if (!withBlockStack) {
|
||||
withBlockStack = [];
|
||||
}
|
||||
|
||||
withBlockStack.push(block);
|
||||
}
|
||||
else if (blockAction === BlockAction.Close) {
|
||||
withBlockStack.pop();
|
||||
}
|
||||
withBlockStack.push(block);
|
||||
}
|
||||
else if (blockAction === BlockAction.Close) {
|
||||
withBlockStack.pop();
|
||||
}
|
||||
break;
|
||||
// default: do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ namespace ts {
|
||||
compilerOptions.reactNamespace,
|
||||
tagName,
|
||||
objectProperties,
|
||||
filter(map(children, transformJsxChildToExpression), isDefined),
|
||||
mapDefined(children, transformJsxChildToExpression),
|
||||
node,
|
||||
location
|
||||
);
|
||||
|
||||
+70
-13
@@ -999,6 +999,7 @@ namespace ts {
|
||||
export interface StringLiteral extends LiteralExpression {
|
||||
kind: SyntaxKind.StringLiteral;
|
||||
/* @internal */ textSourceNode?: Identifier | StringLiteral | NumericLiteral; // Allows a StringLiteral to get its text from another node (used by transforms).
|
||||
/* @internal */ singleQuote?: boolean;
|
||||
}
|
||||
|
||||
// Note: 'brands' in our syntax nodes serve to give us a small amount of nominal typing.
|
||||
@@ -2176,16 +2177,18 @@ namespace ts {
|
||||
locked?: boolean;
|
||||
}
|
||||
|
||||
export interface AfterFinallyFlow extends FlowNode, FlowLock {
|
||||
export interface AfterFinallyFlow extends FlowNodeBase, FlowLock {
|
||||
antecedent: FlowNode;
|
||||
}
|
||||
|
||||
export interface PreFinallyFlow extends FlowNode {
|
||||
export interface PreFinallyFlow extends FlowNodeBase {
|
||||
antecedent: FlowNode;
|
||||
lock: FlowLock;
|
||||
}
|
||||
|
||||
export interface FlowNode {
|
||||
export type FlowNode =
|
||||
| AfterFinallyFlow | PreFinallyFlow | FlowStart | FlowLabel | FlowAssignment | FlowCondition | FlowSwitchClause | FlowArrayMutation;
|
||||
export interface FlowNodeBase {
|
||||
flags: FlowFlags;
|
||||
id?: number; // Node id used by flow type cache in checker
|
||||
}
|
||||
@@ -2193,30 +2196,30 @@ namespace ts {
|
||||
// FlowStart represents the start of a control flow. For a function expression or arrow
|
||||
// function, the container property references the function (which in turn has a flowNode
|
||||
// property for the containing control flow).
|
||||
export interface FlowStart extends FlowNode {
|
||||
export interface FlowStart extends FlowNodeBase {
|
||||
container?: FunctionExpression | ArrowFunction | MethodDeclaration;
|
||||
}
|
||||
|
||||
// FlowLabel represents a junction with multiple possible preceding control flows.
|
||||
export interface FlowLabel extends FlowNode {
|
||||
export interface FlowLabel extends FlowNodeBase {
|
||||
antecedents: FlowNode[];
|
||||
}
|
||||
|
||||
// FlowAssignment represents a node that assigns a value to a narrowable reference,
|
||||
// i.e. an identifier or a dotted name that starts with an identifier or 'this'.
|
||||
export interface FlowAssignment extends FlowNode {
|
||||
export interface FlowAssignment extends FlowNodeBase {
|
||||
node: Expression | VariableDeclaration | BindingElement;
|
||||
antecedent: FlowNode;
|
||||
}
|
||||
|
||||
// FlowCondition represents a condition that is known to be true or false at the
|
||||
// node's location in the control flow.
|
||||
export interface FlowCondition extends FlowNode {
|
||||
export interface FlowCondition extends FlowNodeBase {
|
||||
expression: Expression;
|
||||
antecedent: FlowNode;
|
||||
}
|
||||
|
||||
export interface FlowSwitchClause extends FlowNode {
|
||||
export interface FlowSwitchClause extends FlowNodeBase {
|
||||
switchStatement: SwitchStatement;
|
||||
clauseStart: number; // Start index of case/default clause range
|
||||
clauseEnd: number; // End index of case/default clause range
|
||||
@@ -2225,7 +2228,7 @@ namespace ts {
|
||||
|
||||
// FlowArrayMutation represents a node potentially mutates an array, i.e. an
|
||||
// operation of the form 'x.push(value)', 'x.unshift(value)' or 'x[n] = value'.
|
||||
export interface FlowArrayMutation extends FlowNode {
|
||||
export interface FlowArrayMutation extends FlowNodeBase {
|
||||
node: CallExpression | BinaryExpression;
|
||||
antecedent: FlowNode;
|
||||
}
|
||||
@@ -2255,6 +2258,17 @@ namespace ts {
|
||||
}
|
||||
|
||||
|
||||
/* @internal */
|
||||
export interface RedirectInfo {
|
||||
/** Source file this redirects to. */
|
||||
readonly redirectTarget: SourceFile;
|
||||
/**
|
||||
* Source file for the duplicate package. This will not be used by the Program,
|
||||
* but we need to keep this around so we can watch for changes in underlying.
|
||||
*/
|
||||
readonly unredirected: SourceFile;
|
||||
}
|
||||
|
||||
// Source files are declarations when they are external modules.
|
||||
export interface SourceFile extends Declaration {
|
||||
kind: SyntaxKind.SourceFile;
|
||||
@@ -2265,6 +2279,13 @@ namespace ts {
|
||||
/* @internal */ path: Path;
|
||||
text: string;
|
||||
|
||||
/**
|
||||
* If two source files are for the same version of the same package, one will redirect to the other.
|
||||
* (See `createRedirectSourceFile` in program.ts.)
|
||||
* The redirect will have this set. The other will not have anything set, but see Program#sourceFileIsRedirectedTo.
|
||||
*/
|
||||
/* @internal */ redirectInfo?: RedirectInfo | undefined;
|
||||
|
||||
amdDependencies: AmdDependency[];
|
||||
moduleName: string;
|
||||
referencedFiles: FileReference[];
|
||||
@@ -2435,6 +2456,11 @@ namespace ts {
|
||||
/* @internal */ structureIsReused?: StructureIsReused;
|
||||
|
||||
/* @internal */ getSourceFileFromReference(referencingFile: SourceFile, ref: FileReference): SourceFile | undefined;
|
||||
|
||||
/** Given a source file, get the name of the package it was imported from. */
|
||||
/* @internal */ sourceFileToPackageName: Map<string>;
|
||||
/** Set of all source files that some other source file redirects to. */
|
||||
/* @internal */ redirectTargetsSet: Map<true>;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -2542,6 +2568,15 @@ namespace ts {
|
||||
getSymbolsOfParameterPropertyDeclaration(parameter: ParameterDeclaration, parameterName: string): Symbol[];
|
||||
getShorthandAssignmentValueSymbol(location: Node): Symbol | undefined;
|
||||
getExportSpecifierLocalTargetSymbol(location: ExportSpecifier): Symbol | undefined;
|
||||
/**
|
||||
* If a symbol is a local symbol with an associated exported symbol, returns the exported symbol.
|
||||
* Otherwise returns its input.
|
||||
* For example, at `export type T = number;`:
|
||||
* - `getSymbolAtLocation` at the location `T` will return the exported symbol for `T`.
|
||||
* - But the result of `getSymbolsInScope` will contain the *local* symbol for `T`, not the exported symbol.
|
||||
* - Calling `getExportSymbolOfSymbol` on that local symbol will return the exported symbol.
|
||||
*/
|
||||
getExportSymbolOfSymbol(symbol: Symbol): Symbol;
|
||||
getPropertySymbolOfDestructuringAssignment(location: Identifier): Symbol | undefined;
|
||||
getTypeAtLocation(node: Node): Type;
|
||||
getTypeFromTypeNode(node: TypeNode): Type;
|
||||
@@ -2606,9 +2641,8 @@ namespace ts {
|
||||
* Does not include properties of primitive types.
|
||||
*/
|
||||
/* @internal */ getAllPossiblePropertiesOfType(type: Type): Symbol[];
|
||||
|
||||
/* @internal */ resolveName(name: string, location: Node, meaning: SymbolFlags): Symbol | undefined;
|
||||
/* @internal */ getJsxNamespace(): string;
|
||||
/* @internal */ resolveNameAtLocation(location: Node, name: string, meaning: SymbolFlags): Symbol | undefined;
|
||||
}
|
||||
|
||||
export enum NodeBuilderFlags {
|
||||
@@ -2683,11 +2717,12 @@ namespace ts {
|
||||
UseFullyQualifiedType = 1 << 8, // Write out the fully qualified type name (eg. Module.Type, instead of Type)
|
||||
InFirstTypeArgument = 1 << 9, // Writing first type argument of the instantiated type
|
||||
InTypeAlias = 1 << 10, // Writing type in type alias declaration
|
||||
UseTypeAliasValue = 1 << 11, // Serialize the type instead of using type-alias. This is needed when we emit declaration file.
|
||||
SuppressAnyReturnType = 1 << 12, // If the return type is any-like, don't offer a return type.
|
||||
AddUndefined = 1 << 13, // Add undefined to types of initialized, non-optional parameters
|
||||
WriteClassExpressionAsTypeLiteral = 1 << 14, // Write a type literal instead of (Anonymous class)
|
||||
InArrayType = 1 << 15, // Writing an array element type
|
||||
UseAliasDefinedOutsideCurrentScope = 1 << 16, // For a `type T = ... ` defined in a different file, write `T` instead of its value,
|
||||
// even though `T` can't be accessed in the current scope.
|
||||
}
|
||||
|
||||
export const enum SymbolFormatFlags {
|
||||
@@ -3101,7 +3136,7 @@ namespace ts {
|
||||
/* @internal */
|
||||
ContainsObjectLiteral = 1 << 22, // Type is or contains object literal type
|
||||
/* @internal */
|
||||
ContainsAnyFunctionType = 1 << 23, // Type is or contains object literal type
|
||||
ContainsAnyFunctionType = 1 << 23, // Type is or contains the anyFunctionType
|
||||
NonPrimitive = 1 << 24, // intrinsic object type
|
||||
/* @internal */
|
||||
JsxAttributes = 1 << 25, // Jsx attributes type
|
||||
@@ -3583,6 +3618,7 @@ namespace ts {
|
||||
paths?: MapLike<string[]>;
|
||||
/*@internal*/ plugins?: PluginImport[];
|
||||
preserveConstEnums?: boolean;
|
||||
preserveSymlinks?: boolean;
|
||||
project?: string;
|
||||
/* @internal */ pretty?: DiagnosticStyle;
|
||||
reactNamespace?: string;
|
||||
@@ -3898,6 +3934,10 @@ namespace ts {
|
||||
readFile(fileName: string): string | undefined;
|
||||
trace?(s: string): void;
|
||||
directoryExists?(directoryName: string): boolean;
|
||||
/**
|
||||
* Resolve a symbolic link.
|
||||
* @see https://nodejs.org/api/fs.html#fs_fs_realpathsync_path_options
|
||||
*/
|
||||
realpath?(path: string): string;
|
||||
getCurrentDirectory?(): string;
|
||||
getDirectories?(path: string): string[];
|
||||
@@ -3925,6 +3965,7 @@ namespace ts {
|
||||
/**
|
||||
* ResolvedModule with an explicitly provided `extension` property.
|
||||
* Prefer this over `ResolvedModule`.
|
||||
* If changing this, remember to change `moduleResolutionIsEqualTo`.
|
||||
*/
|
||||
export interface ResolvedModuleFull extends ResolvedModule {
|
||||
/**
|
||||
@@ -3932,6 +3973,22 @@ namespace ts {
|
||||
* This is optional for backwards-compatibility, but will be added if not provided.
|
||||
*/
|
||||
extension: Extension;
|
||||
packageId?: PackageId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unique identifier with a package name and version.
|
||||
* If changing this, remember to change `packageIdIsEqual`.
|
||||
*/
|
||||
export interface PackageId {
|
||||
/**
|
||||
* Name of the package.
|
||||
* Should not include `@types`.
|
||||
* If accessing a non-index file, this should include its name e.g. "foo/bar".
|
||||
*/
|
||||
name: string;
|
||||
/** Version of the package, e.g. "1.2.3" */
|
||||
version: string;
|
||||
}
|
||||
|
||||
export const enum Extension {
|
||||
|
||||
+111
-215
@@ -27,20 +27,6 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function findDeclaration<T extends Declaration>(symbol: Symbol, predicate: (node: Declaration) => node is T): T | undefined;
|
||||
export function findDeclaration(symbol: Symbol, predicate: (node: Declaration) => boolean): Declaration | undefined;
|
||||
export function findDeclaration(symbol: Symbol, predicate: (node: Declaration) => boolean): Declaration | undefined {
|
||||
const declarations = symbol.declarations;
|
||||
if (declarations) {
|
||||
for (const declaration of declarations) {
|
||||
if (predicate(declaration)) {
|
||||
return declaration;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export interface StringSymbolWriter extends SymbolWriter {
|
||||
string(): string;
|
||||
}
|
||||
@@ -112,19 +98,21 @@ namespace ts {
|
||||
sourceFile.resolvedTypeReferenceDirectiveNames.set(typeReferenceDirectiveName, resolvedTypeReferenceDirective);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function moduleResolutionIsEqualTo(oldResolution: ResolvedModuleFull, newResolution: ResolvedModuleFull): boolean {
|
||||
return oldResolution.isExternalLibraryImport === newResolution.isExternalLibraryImport &&
|
||||
oldResolution.extension === newResolution.extension &&
|
||||
oldResolution.resolvedFileName === newResolution.resolvedFileName;
|
||||
oldResolution.resolvedFileName === newResolution.resolvedFileName &&
|
||||
packageIdIsEqual(oldResolution.packageId, newResolution.packageId);
|
||||
}
|
||||
|
||||
function packageIdIsEqual(a: PackageId | undefined, b: PackageId | undefined): boolean {
|
||||
return a === b || a && b && a.name === b.name && a.version === b.version;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function typeDirectiveIsEqualTo(oldResolution: ResolvedTypeReferenceDirective, newResolution: ResolvedTypeReferenceDirective): boolean {
|
||||
return oldResolution.resolvedFileName === newResolution.resolvedFileName && oldResolution.primary === newResolution.primary;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function hasChangesInResolutions<T>(
|
||||
names: ReadonlyArray<string>,
|
||||
newResolutions: ReadonlyArray<T>,
|
||||
@@ -203,14 +191,6 @@ namespace ts {
|
||||
return `${file.fileName}(${loc.line + 1},${loc.character + 1})`;
|
||||
}
|
||||
|
||||
export function getStartPosOfNode(node: Node): number {
|
||||
return node.pos;
|
||||
}
|
||||
|
||||
export function isDefined(value: any): boolean {
|
||||
return value !== undefined;
|
||||
}
|
||||
|
||||
export function getEndLinePosition(line: number, sourceFile: SourceFileLike): number {
|
||||
Debug.assert(line >= 0);
|
||||
const lineStarts = getLineStarts(sourceFile);
|
||||
@@ -262,6 +242,32 @@ namespace ts {
|
||||
return !nodeIsMissing(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given comment is a triple-slash
|
||||
*
|
||||
* @return true if the comment is a triple-slash comment else false
|
||||
*/
|
||||
export function isRecognizedTripleSlashComment(text: string, commentPos: number, commentEnd: number) {
|
||||
// Verify this is /// comment, but do the regexp match only when we first can find /// in the comment text
|
||||
// so that we don't end up computing comment string and doing match for all // comments
|
||||
if (text.charCodeAt(commentPos + 1) === CharacterCodes.slash &&
|
||||
commentPos + 2 < commentEnd &&
|
||||
text.charCodeAt(commentPos + 2) === CharacterCodes.slash) {
|
||||
const textSubStr = text.substring(commentPos, commentEnd);
|
||||
return textSubStr.match(fullTripleSlashReferencePathRegEx) ||
|
||||
textSubStr.match(fullTripleSlashAMDReferencePathRegEx) ||
|
||||
textSubStr.match(fullTripleSlashReferenceTypeReferenceDirectiveRegEx) ||
|
||||
textSubStr.match(defaultLibReferenceRegEx) ?
|
||||
true : false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isPinnedComment(text: string, comment: CommentRange) {
|
||||
return text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk &&
|
||||
text.charCodeAt(comment.pos + 2) === CharacterCodes.exclamation;
|
||||
}
|
||||
|
||||
export function getTokenPosOfNode(node: Node, sourceFile?: SourceFileLike, includeJsDoc?: boolean): number {
|
||||
// With nodes that have no width (i.e. 'Missing' nodes), we actually *don't*
|
||||
// want to skip trivia because this will launch us forward to the next token.
|
||||
@@ -338,15 +344,20 @@ namespace ts {
|
||||
// or a (possibly escaped) quoted form of the original text if it's string-like.
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.StringLiteral:
|
||||
return '"' + escapeText(node.text) + '"';
|
||||
if ((<StringLiteral>node).singleQuote) {
|
||||
return "'" + escapeText(node.text, CharacterCodes.singleQuote) + "'";
|
||||
}
|
||||
else {
|
||||
return '"' + escapeText(node.text, CharacterCodes.doubleQuote) + '"';
|
||||
}
|
||||
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
||||
return "`" + escapeText(node.text) + "`";
|
||||
return "`" + escapeText(node.text, CharacterCodes.backtick) + "`";
|
||||
case SyntaxKind.TemplateHead:
|
||||
return "`" + escapeText(node.text) + "${";
|
||||
return "`" + escapeText(node.text, CharacterCodes.backtick) + "${";
|
||||
case SyntaxKind.TemplateMiddle:
|
||||
return "}" + escapeText(node.text) + "${";
|
||||
return "}" + escapeText(node.text, CharacterCodes.backtick) + "${";
|
||||
case SyntaxKind.TemplateTail:
|
||||
return "}" + escapeText(node.text) + "`";
|
||||
return "}" + escapeText(node.text, CharacterCodes.backtick) + "`";
|
||||
case SyntaxKind.NumericLiteral:
|
||||
return node.text;
|
||||
}
|
||||
@@ -437,6 +448,7 @@ namespace ts {
|
||||
return isExternalModule(node) || compilerOptions.isolatedModules;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function isBlockScope(node: Node, parentNode: Node) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.SourceFile:
|
||||
@@ -638,10 +650,6 @@ namespace ts {
|
||||
return node.kind !== SyntaxKind.JsxText ? getLeadingCommentRanges(sourceFileOfNode.text, node.pos) : undefined;
|
||||
}
|
||||
|
||||
export function getLeadingCommentRangesOfNodeFromText(node: Node, text: string) {
|
||||
return getLeadingCommentRanges(text, node.pos);
|
||||
}
|
||||
|
||||
export function getJSDocCommentRanges(node: Node, text: string) {
|
||||
const commentRanges = (node.kind === SyntaxKind.Parameter ||
|
||||
node.kind === SyntaxKind.TypeParameter ||
|
||||
@@ -649,7 +657,7 @@ namespace ts {
|
||||
node.kind === SyntaxKind.ArrowFunction ||
|
||||
node.kind === SyntaxKind.ParenthesizedExpression) ?
|
||||
concatenate(getTrailingCommentRanges(text, node.pos), getLeadingCommentRanges(text, node.pos)) :
|
||||
getLeadingCommentRangesOfNodeFromText(node, text);
|
||||
getLeadingCommentRanges(text, node.pos);
|
||||
// True if the comment starts with '/**' but not if it is '/**/'
|
||||
return filter(commentRanges, comment =>
|
||||
text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk &&
|
||||
@@ -657,9 +665,10 @@ namespace ts {
|
||||
text.charCodeAt(comment.pos + 3) !== CharacterCodes.slash);
|
||||
}
|
||||
|
||||
export let fullTripleSlashReferencePathRegEx = /^(\/\/\/\s*<reference\s+path\s*=\s*)('|")(.+?)\2.*?\/>/;
|
||||
export let fullTripleSlashReferenceTypeReferenceDirectiveRegEx = /^(\/\/\/\s*<reference\s+types\s*=\s*)('|")(.+?)\2.*?\/>/;
|
||||
export let fullTripleSlashAMDReferencePathRegEx = /^(\/\/\/\s*<amd-dependency\s+path\s*=\s*)('|")(.+?)\2.*?\/>/;
|
||||
export const fullTripleSlashReferencePathRegEx = /^(\/\/\/\s*<reference\s+path\s*=\s*)('|")(.+?)\2.*?\/>/;
|
||||
const fullTripleSlashReferenceTypeReferenceDirectiveRegEx = /^(\/\/\/\s*<reference\s+types\s*=\s*)('|")(.+?)\2.*?\/>/;
|
||||
export const fullTripleSlashAMDReferencePathRegEx = /^(\/\/\/\s*<amd-dependency\s+path\s*=\s*)('|")(.+?)\2.*?\/>/;
|
||||
const defaultLibReferenceRegEx = /^(\/\/\/\s*<reference\s+no-default-lib\s*=\s*)('|")(.+?)\2\s*\/>/;
|
||||
|
||||
export function isPartOfTypeNode(node: Node): boolean {
|
||||
if (SyntaxKind.FirstTypeNode <= node.kind && node.kind <= SyntaxKind.LastTypeNode) {
|
||||
@@ -1499,8 +1508,8 @@ namespace ts {
|
||||
parent.parent.kind === SyntaxKind.VariableStatement;
|
||||
const variableStatementNode =
|
||||
isInitializerOfVariableDeclarationInStatement ? parent.parent.parent :
|
||||
isVariableOfVariableDeclarationStatement ? parent.parent :
|
||||
undefined;
|
||||
isVariableOfVariableDeclarationStatement ? parent.parent :
|
||||
undefined;
|
||||
if (variableStatementNode) {
|
||||
getJSDocCommentsAndTagsWorker(variableStatementNode);
|
||||
}
|
||||
@@ -1614,7 +1623,7 @@ namespace ts {
|
||||
if (isInJavaScriptFile(node)) {
|
||||
if (node.type && node.type.kind === SyntaxKind.JSDocVariadicType ||
|
||||
forEach(getJSDocParameterTags(node),
|
||||
t => t.typeExpression && t.typeExpression.type.kind === SyntaxKind.JSDocVariadicType)) {
|
||||
t => t.typeExpression && t.typeExpression.type.kind === SyntaxKind.JSDocVariadicType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1846,7 +1855,7 @@ namespace ts {
|
||||
|
||||
export function getFileReferenceFromReferencePath(comment: string, commentRange: CommentRange): ReferencePathMatchResult {
|
||||
const simpleReferenceRegEx = /^\/\/\/\s*<reference\s+/gim;
|
||||
const isNoDefaultLibRegEx = /^(\/\/\/\s*<reference\s+no-default-lib\s*=\s*)('|")(.+?)\2\s*\/>/gim;
|
||||
const isNoDefaultLibRegEx = new RegExp(defaultLibReferenceRegEx.source, "gim");
|
||||
if (simpleReferenceRegEx.test(comment)) {
|
||||
if (isNoDefaultLibRegEx.test(comment)) {
|
||||
return { isNoDefaultLib: true };
|
||||
@@ -2068,10 +2077,6 @@ namespace ts {
|
||||
return getParseTreeNode(sourceFile, isSourceFile) || sourceFile;
|
||||
}
|
||||
|
||||
export function getOriginalSourceFiles(sourceFiles: ReadonlyArray<SourceFile>) {
|
||||
return sameMap(sourceFiles, getOriginalSourceFile);
|
||||
}
|
||||
|
||||
export const enum Associativity {
|
||||
Left,
|
||||
Right
|
||||
@@ -2356,7 +2361,9 @@ namespace ts {
|
||||
// the language service. These characters should be escaped when printing, and if any characters are added,
|
||||
// the map below must be updated. Note that this regexp *does not* include the 'delete' character.
|
||||
// There is no reason for this other than that JSON.stringify does not handle it either.
|
||||
const escapedCharsRegExp = /[\\\"\u0000-\u001f\t\v\f\b\r\n\u2028\u2029\u0085]/g;
|
||||
const doubleQuoteEscapedCharsRegExp = /[\\\"\u0000-\u001f\t\v\f\b\r\n\u2028\u2029\u0085]/g;
|
||||
const singleQuoteEscapedCharsRegExp = /[\\\'\u0000-\u001f\t\v\f\b\r\n\u2028\u2029\u0085]/g;
|
||||
const backtickQuoteEscapedCharsRegExp = /[\\\`\u0000-\u001f\t\v\f\b\r\n\u2028\u2029\u0085]/g;
|
||||
const escapedCharsMap = createMapFromTemplate({
|
||||
"\0": "\\0",
|
||||
"\t": "\\t",
|
||||
@@ -2367,18 +2374,23 @@ namespace ts {
|
||||
"\n": "\\n",
|
||||
"\\": "\\\\",
|
||||
"\"": "\\\"",
|
||||
"\'": "\\\'",
|
||||
"\`": "\\\`",
|
||||
"\u2028": "\\u2028", // lineSeparator
|
||||
"\u2029": "\\u2029", // paragraphSeparator
|
||||
"\u0085": "\\u0085" // nextLine
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Based heavily on the abstract 'Quote'/'QuoteJSONString' operation from ECMA-262 (24.3.2.2),
|
||||
* but augmented for a few select characters (e.g. lineSeparator, paragraphSeparator, nextLine)
|
||||
* Note that this doesn't actually wrap the input in double quotes.
|
||||
*/
|
||||
export function escapeString(s: string): string {
|
||||
export function escapeString(s: string, quoteChar?: CharacterCodes.doubleQuote | CharacterCodes.singleQuote | CharacterCodes.backtick): string {
|
||||
const escapedCharsRegExp =
|
||||
quoteChar === CharacterCodes.backtick ? backtickQuoteEscapedCharsRegExp :
|
||||
quoteChar === CharacterCodes.singleQuote ? singleQuoteEscapedCharsRegExp :
|
||||
doubleQuoteEscapedCharsRegExp;
|
||||
return s.replace(escapedCharsRegExp, getReplacement);
|
||||
}
|
||||
|
||||
@@ -2400,8 +2412,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
const nonAsciiCharacters = /[^\u0000-\u007F]/g;
|
||||
export function escapeNonAsciiString(s: string): string {
|
||||
s = escapeString(s);
|
||||
export function escapeNonAsciiString(s: string, quoteChar?: CharacterCodes.doubleQuote | CharacterCodes.singleQuote | CharacterCodes.backtick): string {
|
||||
s = escapeString(s, quoteChar);
|
||||
// Replace non-ASCII characters with '\uNNNN' escapes if any exist.
|
||||
// Otherwise just return the original string.
|
||||
return nonAsciiCharacters.test(s) ?
|
||||
@@ -2823,7 +2835,7 @@ namespace ts {
|
||||
//
|
||||
// var x = 10;
|
||||
if (node.pos === 0) {
|
||||
leadingComments = filter(getLeadingCommentRanges(text, node.pos), isPinnedComment);
|
||||
leadingComments = filter(getLeadingCommentRanges(text, node.pos), isPinnedCommentLocal);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -2869,9 +2881,8 @@ namespace ts {
|
||||
|
||||
return currentDetachedCommentInfo;
|
||||
|
||||
function isPinnedComment(comment: CommentRange) {
|
||||
return text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk &&
|
||||
text.charCodeAt(comment.pos + 2) === CharacterCodes.exclamation;
|
||||
function isPinnedCommentLocal(comment: CommentRange) {
|
||||
return isPinnedComment(text, comment);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2977,8 +2988,12 @@ namespace ts {
|
||||
return getModifierFlags(node) !== ModifierFlags.None;
|
||||
}
|
||||
|
||||
export function hasModifier(node: Node, flags: ModifierFlags) {
|
||||
return (getModifierFlags(node) & flags) !== 0;
|
||||
export function hasModifier(node: Node, flags: ModifierFlags): boolean {
|
||||
return !!getSelectedModifierFlags(node, flags);
|
||||
}
|
||||
|
||||
export function getSelectedModifierFlags(node: Node, flags: ModifierFlags): ModifierFlags {
|
||||
return getModifierFlags(node) & flags;
|
||||
}
|
||||
|
||||
export function getModifierFlags(node: Node): ModifierFlags {
|
||||
@@ -3064,24 +3079,6 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns false if this heritage clause element's expression contains something unsupported
|
||||
// (i.e. not a name or dotted name).
|
||||
export function isSupportedExpressionWithTypeArguments(node: ExpressionWithTypeArguments): boolean {
|
||||
return isSupportedExpressionWithTypeArgumentsRest(node.expression);
|
||||
}
|
||||
|
||||
function isSupportedExpressionWithTypeArgumentsRest(node: Expression): boolean {
|
||||
if (node.kind === SyntaxKind.Identifier) {
|
||||
return true;
|
||||
}
|
||||
else if (isPropertyAccessExpression(node)) {
|
||||
return isSupportedExpressionWithTypeArgumentsRest(node.expression);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function isExpressionWithTypeArgumentsInClassExtendsClause(node: Node): boolean {
|
||||
return tryGetClassExtendingExpressionWithTypeArguments(node) !== undefined;
|
||||
}
|
||||
@@ -3218,81 +3215,6 @@ namespace ts {
|
||||
return carriageReturnLineFeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether a node and its subtree is simple enough to have its position
|
||||
* information ignored when emitting source maps in a destructuring assignment.
|
||||
*
|
||||
* @param node The expression to test.
|
||||
*/
|
||||
export function isSimpleExpression(node: Expression): boolean {
|
||||
return isSimpleExpressionWorker(node, 0);
|
||||
}
|
||||
|
||||
function isSimpleExpressionWorker(node: Expression, depth: number): boolean {
|
||||
if (depth <= 5) {
|
||||
const kind = node.kind;
|
||||
if (kind === SyntaxKind.StringLiteral
|
||||
|| kind === SyntaxKind.NumericLiteral
|
||||
|| kind === SyntaxKind.RegularExpressionLiteral
|
||||
|| kind === SyntaxKind.NoSubstitutionTemplateLiteral
|
||||
|| kind === SyntaxKind.Identifier
|
||||
|| kind === SyntaxKind.ThisKeyword
|
||||
|| kind === SyntaxKind.SuperKeyword
|
||||
|| kind === SyntaxKind.TrueKeyword
|
||||
|| kind === SyntaxKind.FalseKeyword
|
||||
|| kind === SyntaxKind.NullKeyword) {
|
||||
return true;
|
||||
}
|
||||
else if (kind === SyntaxKind.PropertyAccessExpression) {
|
||||
return isSimpleExpressionWorker((<PropertyAccessExpression>node).expression, depth + 1);
|
||||
}
|
||||
else if (kind === SyntaxKind.ElementAccessExpression) {
|
||||
return isSimpleExpressionWorker((<ElementAccessExpression>node).expression, depth + 1)
|
||||
&& isSimpleExpressionWorker((<ElementAccessExpression>node).argumentExpression, depth + 1);
|
||||
}
|
||||
else if (kind === SyntaxKind.PrefixUnaryExpression
|
||||
|| kind === SyntaxKind.PostfixUnaryExpression) {
|
||||
return isSimpleExpressionWorker((<PrefixUnaryExpression | PostfixUnaryExpression>node).operand, depth + 1);
|
||||
}
|
||||
else if (kind === SyntaxKind.BinaryExpression) {
|
||||
return (<BinaryExpression>node).operatorToken.kind !== SyntaxKind.AsteriskAsteriskToken
|
||||
&& isSimpleExpressionWorker((<BinaryExpression>node).left, depth + 1)
|
||||
&& isSimpleExpressionWorker((<BinaryExpression>node).right, depth + 1);
|
||||
}
|
||||
else if (kind === SyntaxKind.ConditionalExpression) {
|
||||
return isSimpleExpressionWorker((<ConditionalExpression>node).condition, depth + 1)
|
||||
&& isSimpleExpressionWorker((<ConditionalExpression>node).whenTrue, depth + 1)
|
||||
&& isSimpleExpressionWorker((<ConditionalExpression>node).whenFalse, depth + 1);
|
||||
}
|
||||
else if (kind === SyntaxKind.VoidExpression
|
||||
|| kind === SyntaxKind.TypeOfExpression
|
||||
|| kind === SyntaxKind.DeleteExpression) {
|
||||
return isSimpleExpressionWorker((<VoidExpression | TypeOfExpression | DeleteExpression>node).expression, depth + 1);
|
||||
}
|
||||
else if (kind === SyntaxKind.ArrayLiteralExpression) {
|
||||
return (<ArrayLiteralExpression>node).elements.length === 0;
|
||||
}
|
||||
else if (kind === SyntaxKind.ObjectLiteralExpression) {
|
||||
return (<ObjectLiteralExpression>node).properties.length === 0;
|
||||
}
|
||||
else if (kind === SyntaxKind.CallExpression) {
|
||||
if (!isSimpleExpressionWorker((<CallExpression>node).expression, depth + 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const argument of (<CallExpression>node).arguments) {
|
||||
if (!isSimpleExpressionWorker(argument, depth + 1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an enum value as a string for debugging and debug assertions.
|
||||
*/
|
||||
@@ -3365,24 +3287,6 @@ namespace ts {
|
||||
return formatEnum(flags, (<any>ts).ObjectFlags, /*isFlags*/ true);
|
||||
}
|
||||
|
||||
export function getRangePos(range: TextRange | undefined) {
|
||||
return range ? range.pos : -1;
|
||||
}
|
||||
|
||||
export function getRangeEnd(range: TextRange | undefined) {
|
||||
return range ? range.end : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases (or decreases) a position by the provided amount.
|
||||
*
|
||||
* @param pos The position.
|
||||
* @param value The delta.
|
||||
*/
|
||||
export function movePos(pos: number, value: number) {
|
||||
return positionIsSynthesized(pos) ? -1 : pos + value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new TextRange from the provided pos and end.
|
||||
*
|
||||
@@ -3440,26 +3344,6 @@ namespace ts {
|
||||
return range.pos === range.end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new TextRange from a provided range with its end position collapsed to its
|
||||
* start position.
|
||||
*
|
||||
* @param range A TextRange.
|
||||
*/
|
||||
export function collapseRangeToStart(range: TextRange): TextRange {
|
||||
return isCollapsedRange(range) ? range : moveRangeEnd(range, range.pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new TextRange from a provided range with its start position collapsed to its
|
||||
* end position.
|
||||
*
|
||||
* @param range A TextRange.
|
||||
*/
|
||||
export function collapseRangeToEnd(range: TextRange): TextRange {
|
||||
return isCollapsedRange(range) ? range : moveRangePos(range, range.end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new TextRange for a token at the provides start position.
|
||||
*
|
||||
@@ -3523,31 +3407,6 @@ namespace ts {
|
||||
return node.initializer !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether a node is merged with a class declaration in the same scope.
|
||||
*/
|
||||
export function isMergedWithClass(node: Node) {
|
||||
if (node.symbol) {
|
||||
for (const declaration of node.symbol.declarations) {
|
||||
if (declaration.kind === SyntaxKind.ClassDeclaration && declaration !== node) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether a node is the first declaration of its kind.
|
||||
*
|
||||
* @param node A Declaration node.
|
||||
* @param kind The SyntaxKind to find among related declarations.
|
||||
*/
|
||||
export function isFirstDeclarationOfKind(node: Node, kind: SyntaxKind) {
|
||||
return node.symbol && getDeclarationOfKind(node.symbol, kind) === node;
|
||||
}
|
||||
|
||||
export function isWatchSet(options: CompilerOptions) {
|
||||
// Firefox has Object.prototype.watch
|
||||
return options.watch && options.hasOwnProperty("watch");
|
||||
@@ -3856,6 +3715,20 @@ namespace ts {
|
||||
return hasModifier(node, ModifierFlags.ParameterPropertyModifier) && node.parent.kind === SyntaxKind.Constructor && isClassLike(node.parent.parent);
|
||||
}
|
||||
|
||||
export function isEmptyBindingPattern(node: BindingName): node is BindingPattern {
|
||||
if (isBindingPattern(node)) {
|
||||
return every(node.elements, isEmptyBindingElement);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isEmptyBindingElement(node: BindingElement): boolean {
|
||||
if (isOmittedExpression(node)) {
|
||||
return true;
|
||||
}
|
||||
return isEmptyBindingPattern(node.name);
|
||||
}
|
||||
|
||||
function walkUpBindingElementsAndPatterns(node: Node): Node {
|
||||
while (node && (node.kind === SyntaxKind.BindingElement || isBindingPattern(node))) {
|
||||
node = node.parent;
|
||||
@@ -5123,6 +4996,19 @@ namespace ts {
|
||||
return isUnaryExpressionKind(skipPartiallyEmittedExpressions(node).kind);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function isUnaryExpressionWithWrite(expr: Node): expr is PrefixUnaryExpression | PostfixUnaryExpression {
|
||||
switch (expr.kind) {
|
||||
case SyntaxKind.PostfixUnaryExpression:
|
||||
return true;
|
||||
case SyntaxKind.PrefixUnaryExpression:
|
||||
return (<PrefixUnaryExpression>expr).operator === SyntaxKind.PlusPlusToken ||
|
||||
(<PrefixUnaryExpression>expr).operator === SyntaxKind.MinusMinusToken;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function isExpressionKind(kind: SyntaxKind) {
|
||||
return kind === SyntaxKind.ConditionalExpression
|
||||
|| kind === SyntaxKind.YieldExpression
|
||||
@@ -5337,7 +5223,17 @@ namespace ts {
|
||||
const kind = node.kind;
|
||||
return isStatementKindButNotDeclarationKind(kind)
|
||||
|| isDeclarationStatementKind(kind)
|
||||
|| kind === SyntaxKind.Block;
|
||||
|| isBlockStatement(node);
|
||||
}
|
||||
|
||||
function isBlockStatement(node: Node): node is Block {
|
||||
if (node.kind !== SyntaxKind.Block) return false;
|
||||
if (node.parent !== undefined) {
|
||||
if (node.parent.kind === SyntaxKind.TryStatement || node.parent.kind === SyntaxKind.CatchClause) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return !isFunctionBlock(node);
|
||||
}
|
||||
|
||||
// Module references
|
||||
|
||||
+93
-43
@@ -187,6 +187,9 @@ namespace FourSlash {
|
||||
|
||||
// The current caret position in the active file
|
||||
public currentCaretPosition = 0;
|
||||
// The position of the end of the current selection, or -1 if nothing is selected
|
||||
public selectionEnd = -1;
|
||||
|
||||
public lastKnownMarker = "";
|
||||
|
||||
// The file that's currently 'opened'
|
||||
@@ -433,11 +436,19 @@ namespace FourSlash {
|
||||
|
||||
public goToPosition(pos: number) {
|
||||
this.currentCaretPosition = pos;
|
||||
this.selectionEnd = -1;
|
||||
}
|
||||
|
||||
public select(startMarker: string, endMarker: string) {
|
||||
const start = this.getMarkerByName(startMarker), end = this.getMarkerByName(endMarker);
|
||||
this.goToPosition(start.position);
|
||||
this.selectionEnd = end.position;
|
||||
}
|
||||
|
||||
public moveCaretRight(count = 1) {
|
||||
this.currentCaretPosition += count;
|
||||
this.currentCaretPosition = Math.min(this.currentCaretPosition, this.getFileContent(this.activeFile.fileName).length);
|
||||
this.selectionEnd = -1;
|
||||
}
|
||||
|
||||
// Opens a file given its 0-based index or fileName
|
||||
@@ -451,7 +462,7 @@ namespace FourSlash {
|
||||
this.languageServiceAdapterHost.openFile(fileToOpen.fileName, content, scriptKindName);
|
||||
}
|
||||
|
||||
public verifyErrorExistsBetweenMarkers(startMarkerName: string, endMarkerName: string, negative: boolean) {
|
||||
public verifyErrorExistsBetweenMarkers(startMarkerName: string, endMarkerName: string, shouldExist: boolean) {
|
||||
const startMarker = this.getMarkerByName(startMarkerName);
|
||||
const endMarker = this.getMarkerByName(endMarkerName);
|
||||
const predicate = (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) =>
|
||||
@@ -459,9 +470,9 @@ namespace FourSlash {
|
||||
|
||||
const exists = this.anyErrorInRange(predicate, startMarker, endMarker);
|
||||
|
||||
if (exists !== negative) {
|
||||
this.printErrorLog(negative, this.getAllDiagnostics());
|
||||
throw new Error(`Failure between markers: '${startMarkerName}', '${endMarkerName}'`);
|
||||
if (exists !== shouldExist) {
|
||||
this.printErrorLog(shouldExist, this.getAllDiagnostics());
|
||||
throw new Error(`${shouldExist ? "Expected" : "Did not expect"} failure between markers: '${startMarkerName}', '${endMarkerName}'`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -483,10 +494,11 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
private getAllDiagnostics(): ts.Diagnostic[] {
|
||||
return ts.flatMap(this.languageServiceAdapterHost.getFilenames(), fileName => this.getDiagnostics(fileName));
|
||||
return ts.flatMap(this.languageServiceAdapterHost.getFilenames(), fileName =>
|
||||
ts.isAnySupportedFileExtension(fileName) ? this.getDiagnostics(fileName) : []);
|
||||
}
|
||||
|
||||
public verifyErrorExistsAfterMarker(markerName: string, negative: boolean, after: boolean) {
|
||||
public verifyErrorExistsAfterMarker(markerName: string, shouldExist: boolean, after: boolean) {
|
||||
const marker: Marker = this.getMarkerByName(markerName);
|
||||
let predicate: (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) => boolean;
|
||||
|
||||
@@ -502,30 +514,15 @@ namespace FourSlash {
|
||||
const exists = this.anyErrorInRange(predicate, marker);
|
||||
const diagnostics = this.getAllDiagnostics();
|
||||
|
||||
if (exists !== negative) {
|
||||
this.printErrorLog(negative, diagnostics);
|
||||
throw new Error("Failure at marker: " + markerName);
|
||||
if (exists !== shouldExist) {
|
||||
this.printErrorLog(shouldExist, diagnostics);
|
||||
throw new Error(`${shouldExist ? "Expected" : "Did not expect"} failure at marker '${markerName}'`);
|
||||
}
|
||||
}
|
||||
|
||||
private anyErrorInRange(predicate: (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) => boolean, startMarker: Marker, endMarker?: Marker) {
|
||||
|
||||
const errors = this.getDiagnostics(startMarker.fileName);
|
||||
let exists = false;
|
||||
|
||||
const startPos = startMarker.position;
|
||||
let endPos: number = undefined;
|
||||
if (endMarker !== undefined) {
|
||||
endPos = endMarker.position;
|
||||
}
|
||||
|
||||
errors.forEach(function (error: ts.Diagnostic) {
|
||||
if (predicate(error.start, error.start + error.length, startPos, endPos)) {
|
||||
exists = true;
|
||||
}
|
||||
});
|
||||
|
||||
return exists;
|
||||
private anyErrorInRange(predicate: (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) => boolean, startMarker: Marker, endMarker?: Marker): boolean {
|
||||
return this.getDiagnostics(startMarker.fileName).some(({ start, length }) =>
|
||||
predicate(start, start + length, startMarker.position, endMarker === undefined ? undefined : endMarker.position));
|
||||
}
|
||||
|
||||
private printErrorLog(expectErrors: boolean, errors: ts.Diagnostic[]) {
|
||||
@@ -550,6 +547,7 @@ namespace FourSlash {
|
||||
|
||||
public verifyNoErrors() {
|
||||
ts.forEachKey(this.inputFiles, fileName => {
|
||||
if (!ts.isAnySupportedFileExtension(fileName)) return;
|
||||
const errors = this.getDiagnostics(fileName);
|
||||
if (errors.length) {
|
||||
this.printErrorLog(/*expectErrors*/ false, errors);
|
||||
@@ -980,9 +978,9 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
for (const reference of expectedReferences) {
|
||||
const {fileName, start, end} = reference;
|
||||
const { fileName, start, end } = reference;
|
||||
if (reference.marker && reference.marker.data) {
|
||||
const {isWriteAccess, isDefinition} = reference.marker.data;
|
||||
const { isWriteAccess, isDefinition } = reference.marker.data;
|
||||
this.verifyReferencesWorker(actualReferences, fileName, start, end, isWriteAccess, isDefinition);
|
||||
}
|
||||
else {
|
||||
@@ -1193,7 +1191,7 @@ namespace FourSlash {
|
||||
displayParts: ts.SymbolDisplayPart[],
|
||||
documentation: ts.SymbolDisplayPart[],
|
||||
tags: ts.JSDocTagInfo[]
|
||||
) {
|
||||
) {
|
||||
|
||||
const actualQuickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition);
|
||||
assert.equal(actualQuickInfo.kind, kind, this.messageAtLastKnownMarker("QuickInfo kind"));
|
||||
@@ -1789,19 +1787,16 @@ namespace FourSlash {
|
||||
// We get back a set of edits, but langSvc.editScript only accepts one at a time. Use this to keep track
|
||||
// of the incremental offset from each edit to the next. We assume these edit ranges don't overlap
|
||||
|
||||
edits = edits.sort((a, b) => a.span.start - b.span.start);
|
||||
for (let i = 0; i < edits.length - 1; i++) {
|
||||
const firstEditSpan = edits[i].span;
|
||||
const firstEditEnd = firstEditSpan.start + firstEditSpan.length;
|
||||
assert.isTrue(firstEditEnd <= edits[i + 1].span.start);
|
||||
}
|
||||
// Copy this so we don't ruin someone else's copy
|
||||
edits = JSON.parse(JSON.stringify(edits));
|
||||
|
||||
// Get a snapshot of the content of the file so we can make sure any formatting edits didn't destroy non-whitespace characters
|
||||
const oldContent = this.getFileContent(fileName);
|
||||
let runningOffset = 0;
|
||||
|
||||
for (const edit of edits) {
|
||||
const offsetStart = edit.span.start + runningOffset;
|
||||
for (let i = 0; i < edits.length; i++) {
|
||||
const edit = edits[i];
|
||||
const offsetStart = edit.span.start;
|
||||
const offsetEnd = offsetStart + edit.span.length;
|
||||
this.editScriptAndUpdateMarkers(fileName, offsetStart, offsetEnd, edit.newText);
|
||||
const editDelta = edit.newText.length - edit.span.length;
|
||||
@@ -1816,8 +1811,13 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
runningOffset += editDelta;
|
||||
// TODO: Consider doing this at least some of the time for higher fidelity. Currently causes a failure (bug 707150)
|
||||
// this.languageService.getScriptLexicalStructure(fileName);
|
||||
|
||||
// Update positions of any future edits affected by this change
|
||||
for (let j = i + 1; j < edits.length; j++) {
|
||||
if (edits[j].span.start >= edits[i].span.start) {
|
||||
edits[j].span.start += editDelta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isFormattingEdit) {
|
||||
@@ -1901,7 +1901,7 @@ namespace FourSlash {
|
||||
this.goToPosition(len);
|
||||
}
|
||||
|
||||
public goToRangeStart({fileName, start}: Range) {
|
||||
public goToRangeStart({ fileName, start }: Range) {
|
||||
this.openFile(fileName);
|
||||
this.goToPosition(start);
|
||||
}
|
||||
@@ -2075,7 +2075,7 @@ namespace FourSlash {
|
||||
return result;
|
||||
}
|
||||
|
||||
private rangeText({fileName, start, end}: Range): string {
|
||||
private rangeText({ fileName, start, end }: Range): string {
|
||||
return this.getFileContent(fileName).slice(start, end);
|
||||
}
|
||||
|
||||
@@ -2361,7 +2361,7 @@ namespace FourSlash {
|
||||
private applyCodeActions(actions: ts.CodeAction[], index?: number): void {
|
||||
if (index === undefined) {
|
||||
if (!(actions && actions.length === 1)) {
|
||||
this.raiseError(`Should find exactly one codefix, but ${actions ? actions.length : "none"} found. ${actions ? actions.map(a => `${Harness.IO.newLine()} "${a.description}"`) : "" }`);
|
||||
this.raiseError(`Should find exactly one codefix, but ${actions ? actions.length : "none"} found. ${actions ? actions.map(a => `${Harness.IO.newLine()} "${a.description}"`) : ""}`);
|
||||
}
|
||||
index = 0;
|
||||
}
|
||||
@@ -2750,6 +2750,30 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
private getSelection() {
|
||||
return ({
|
||||
pos: this.currentCaretPosition,
|
||||
end: this.selectionEnd === -1 ? this.currentCaretPosition : this.selectionEnd
|
||||
});
|
||||
}
|
||||
|
||||
public verifyRefactorAvailable(negative: boolean, name?: string, subName?: string) {
|
||||
const selection = this.getSelection();
|
||||
|
||||
let refactors = this.languageService.getApplicableRefactors(this.activeFile.fileName, selection) || [];
|
||||
if (name) {
|
||||
refactors = refactors.filter(r => r.name === name && (subName === undefined || r.actions.some(a => a.name === subName)));
|
||||
}
|
||||
const isAvailable = refactors.length > 0;
|
||||
|
||||
if (negative && isAvailable) {
|
||||
this.raiseError(`verifyApplicableRefactorAvailableForRange failed - expected no refactor but found some: ${refactors.map(r => r.name).join(", ")}`);
|
||||
}
|
||||
else if (!negative && !isAvailable) {
|
||||
this.raiseError(`verifyApplicableRefactorAvailableForRange failed - expected a refactor but found none.`);
|
||||
}
|
||||
}
|
||||
|
||||
public verifyApplicableRefactorAvailableForRange(negative: boolean) {
|
||||
const ranges = this.getRanges();
|
||||
if (!(ranges && ranges.length === 1)) {
|
||||
@@ -2766,6 +2790,20 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
public applyRefactor(refactorName: string, actionName: string) {
|
||||
const range = this.getSelection();
|
||||
const refactors = this.languageService.getApplicableRefactors(this.activeFile.fileName, range);
|
||||
const refactor = ts.find(refactors, r => r.name === refactorName);
|
||||
if (!refactor) {
|
||||
this.raiseError(`The expected refactor: ${refactorName} is not available at the marker location.`);
|
||||
}
|
||||
|
||||
const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, this.formatCodeSettings, range, refactorName, actionName);
|
||||
for (const edit of editInfo.edits) {
|
||||
this.applyEdits(edit.fileName, edit.textChanges, /*isFormattingEdit*/ false);
|
||||
}
|
||||
}
|
||||
|
||||
public verifyFileAfterApplyingRefactorAtMarker(
|
||||
markerName: string,
|
||||
expectedContent: string,
|
||||
@@ -3510,6 +3548,10 @@ namespace FourSlashInterface {
|
||||
public file(indexOrName: any, content?: string, scriptKindName?: string): void {
|
||||
this.state.openFile(indexOrName, content, scriptKindName);
|
||||
}
|
||||
|
||||
public select(startMarker: string, endMarker: string) {
|
||||
this.state.select(startMarker, endMarker);
|
||||
}
|
||||
}
|
||||
|
||||
export class VerifyNegatable {
|
||||
@@ -3635,6 +3677,10 @@ namespace FourSlashInterface {
|
||||
public applicableRefactorAvailableForRange() {
|
||||
this.state.verifyApplicableRefactorAvailableForRange(this.negative);
|
||||
}
|
||||
|
||||
public refactorAvailable(name?: string, subName?: string) {
|
||||
this.state.verifyRefactorAvailable(this.negative, name, subName);
|
||||
}
|
||||
}
|
||||
|
||||
export class Verify extends VerifyNegatable {
|
||||
@@ -4030,6 +4076,10 @@ namespace FourSlashInterface {
|
||||
public disableFormatting() {
|
||||
this.state.enableFormatting = false;
|
||||
}
|
||||
|
||||
public applyRefactor(refactorName: string, actionName: string) {
|
||||
this.state.applyRefactor(refactorName, actionName);
|
||||
}
|
||||
}
|
||||
|
||||
export class Debug {
|
||||
|
||||
+62
-35
@@ -67,17 +67,16 @@ namespace Utils {
|
||||
|
||||
export let currentExecutionEnvironment = getExecutionEnvironment();
|
||||
|
||||
const Buffer: typeof global.Buffer = currentExecutionEnvironment !== ExecutionEnvironment.Browser
|
||||
? require("buffer").Buffer
|
||||
: undefined;
|
||||
// Thanks to browserify, Buffer is always available nowadays
|
||||
const Buffer: typeof global.Buffer = require("buffer").Buffer;
|
||||
|
||||
export function encodeString(s: string): string {
|
||||
return Buffer ? (new Buffer(s)).toString("utf8") : s;
|
||||
return Buffer.from(s).toString("utf8");
|
||||
}
|
||||
|
||||
export function byteLength(s: string, encoding?: string): number {
|
||||
// stub implementation if Buffer is not available (in-browser case)
|
||||
return Buffer ? Buffer.byteLength(s, encoding) : s.length;
|
||||
return Buffer.byteLength(s, encoding);
|
||||
}
|
||||
|
||||
export function evalFile(fileContents: string, fileName: string, nodeContext?: any) {
|
||||
@@ -133,17 +132,18 @@ namespace Utils {
|
||||
return content;
|
||||
}
|
||||
|
||||
export function memoize<T extends Function>(f: T): T {
|
||||
const cache: { [idx: string]: any } = {};
|
||||
export function memoize<T extends Function>(f: T, memoKey: (...anything: any[]) => string): T {
|
||||
const cache = ts.createMap<any>();
|
||||
|
||||
return <any>(function(this: any) {
|
||||
const key = Array.prototype.join.call(arguments);
|
||||
const cachedResult = cache[key];
|
||||
if (cachedResult) {
|
||||
return cachedResult;
|
||||
return <any>(function(this: any, ...args: any[]) {
|
||||
const key = memoKey(...args);
|
||||
if (cache.has(key)) {
|
||||
return cache.get(key);
|
||||
}
|
||||
else {
|
||||
return cache[key] = f.apply(this, arguments);
|
||||
const value = f.apply(this, args);
|
||||
cache.set(key, value);
|
||||
return value;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -564,7 +564,7 @@ namespace Harness {
|
||||
}
|
||||
|
||||
export let listFiles: typeof IO.listFiles = (path, spec?, options?) => {
|
||||
options = options || <{ recursive?: boolean; }>{};
|
||||
options = options || {};
|
||||
|
||||
function filesInFolder(folder: string): string[] {
|
||||
let paths: string[] = [];
|
||||
@@ -686,7 +686,7 @@ namespace Harness {
|
||||
|
||||
return dirPath;
|
||||
}
|
||||
export let directoryName: typeof IO.directoryName = Utils.memoize(directoryNameImpl);
|
||||
export let directoryName: typeof IO.directoryName = Utils.memoize(directoryNameImpl, path => path);
|
||||
|
||||
export function resolvePath(path: string) {
|
||||
const response = Http.getFileFromServerSync(serverRoot + path + "?resolve=true");
|
||||
@@ -703,21 +703,22 @@ namespace Harness {
|
||||
return response.status === 200;
|
||||
}
|
||||
|
||||
export let listFiles = Utils.memoize((path: string, spec?: RegExp): string[] => {
|
||||
export const listFiles = Utils.memoize((path: string, spec?: RegExp, options?: { recursive?: boolean }): string[] => {
|
||||
const response = Http.getFileFromServerSync(serverRoot + path);
|
||||
if (response.status === 200) {
|
||||
const results = response.responseText.split(",");
|
||||
let results = response.responseText.split(",");
|
||||
if (spec) {
|
||||
return results.filter(file => spec.test(file));
|
||||
results = results.filter(file => spec.test(file));
|
||||
}
|
||||
else {
|
||||
return results;
|
||||
if (options && !options.recursive) {
|
||||
results = results.filter(file => (ts.getDirectoryPath(ts.normalizeSlashes(file)) === path));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
else {
|
||||
return [""];
|
||||
}
|
||||
});
|
||||
}, (path: string, spec?: RegExp, options?: { recursive?: boolean }) => `${path}|${spec}|${options ? options.recursive : undefined}`);
|
||||
|
||||
export function readFile(file: string): string | undefined {
|
||||
const response = Http.getFileFromServerSync(serverRoot + file);
|
||||
@@ -1194,13 +1195,21 @@ namespace Harness {
|
||||
return { result, options };
|
||||
}
|
||||
|
||||
export function compileDeclarationFiles(inputFiles: TestFile[],
|
||||
export interface DeclarationCompilationContext {
|
||||
declInputFiles: TestFile[];
|
||||
declOtherFiles: TestFile[];
|
||||
harnessSettings: TestCaseParser.CompilerSettings & HarnessOptions;
|
||||
options: ts.CompilerOptions;
|
||||
currentDirectory: string;
|
||||
}
|
||||
|
||||
export function prepareDeclarationCompilationContext(inputFiles: TestFile[],
|
||||
otherFiles: TestFile[],
|
||||
result: CompilerResult,
|
||||
harnessSettings: TestCaseParser.CompilerSettings & HarnessOptions,
|
||||
options: ts.CompilerOptions,
|
||||
// Current directory is needed for rwcRunner to be able to use currentDirectory defined in json file
|
||||
currentDirectory: string) {
|
||||
currentDirectory: string): DeclarationCompilationContext | undefined {
|
||||
if (options.declaration && result.errors.length === 0 && result.declFilesCode.length !== result.files.length) {
|
||||
throw new Error("There were no errors and declFiles generated did not match number of js files generated");
|
||||
}
|
||||
@@ -1212,8 +1221,7 @@ namespace Harness {
|
||||
if (options.declaration && result.errors.length === 0 && result.declFilesCode.length > 0) {
|
||||
ts.forEach(inputFiles, file => addDtsFile(file, declInputFiles));
|
||||
ts.forEach(otherFiles, file => addDtsFile(file, declOtherFiles));
|
||||
const output = compileFiles(declInputFiles, declOtherFiles, harnessSettings, options, currentDirectory || harnessSettings["currentDirectory"]);
|
||||
return { declInputFiles, declOtherFiles, declResult: output.result };
|
||||
return { declInputFiles, declOtherFiles, harnessSettings, options, currentDirectory: currentDirectory || harnessSettings["currentDirectory"] };
|
||||
}
|
||||
|
||||
function addDtsFile(file: TestFile, dtsFiles: TestFile[]) {
|
||||
@@ -1259,6 +1267,15 @@ namespace Harness {
|
||||
}
|
||||
}
|
||||
|
||||
export function compileDeclarationFiles(context: DeclarationCompilationContext | undefined) {
|
||||
if (!context) {
|
||||
return;
|
||||
}
|
||||
const { declInputFiles, declOtherFiles, harnessSettings, options, currentDirectory } = context;
|
||||
const output = compileFiles(declInputFiles, declOtherFiles, harnessSettings, options, currentDirectory);
|
||||
return { declInputFiles, declOtherFiles, declResult: output.result };
|
||||
}
|
||||
|
||||
function normalizeLineEndings(text: string, lineEnding: string): string {
|
||||
let normalized = text.replace(/\r\n?/g, "\n");
|
||||
if (lineEnding !== "\n") {
|
||||
@@ -1273,10 +1290,19 @@ namespace Harness {
|
||||
|
||||
export function getErrorBaseline(inputFiles: TestFile[], diagnostics: ts.Diagnostic[]) {
|
||||
diagnostics.sort(ts.compareDiagnostics);
|
||||
const outputLines: string[] = [];
|
||||
let outputLines = "";
|
||||
// Count up all errors that were found in files other than lib.d.ts so we don't miss any
|
||||
let totalErrorsReportedInNonLibraryFiles = 0;
|
||||
|
||||
let firstLine = true;
|
||||
function newLine() {
|
||||
if (firstLine) {
|
||||
firstLine = false;
|
||||
return "";
|
||||
}
|
||||
return "\r\n";
|
||||
}
|
||||
|
||||
function outputErrorText(error: ts.Diagnostic) {
|
||||
const message = ts.flattenDiagnosticMessageText(error.messageText, Harness.IO.newLine());
|
||||
|
||||
@@ -1285,7 +1311,7 @@ namespace Harness {
|
||||
.map(s => s.length > 0 && s.charAt(s.length - 1) === "\r" ? s.substr(0, s.length - 1) : s)
|
||||
.filter(s => s.length > 0)
|
||||
.map(s => "!!! " + ts.DiagnosticCategory[error.category].toLowerCase() + " TS" + error.code + ": " + s);
|
||||
errLines.forEach(e => outputLines.push(e));
|
||||
errLines.forEach(e => outputLines += (newLine() + e));
|
||||
|
||||
// do not count errors from lib.d.ts here, they are computed separately as numLibraryDiagnostics
|
||||
// if lib.d.ts is explicitly included in input files and there are some errors in it (i.e. because of duplicate identifiers)
|
||||
@@ -1311,7 +1337,7 @@ namespace Harness {
|
||||
|
||||
|
||||
// Header
|
||||
outputLines.push("==== " + inputFile.unitName + " (" + fileErrors.length + " errors) ====");
|
||||
outputLines += (newLine() + "==== " + inputFile.unitName + " (" + fileErrors.length + " errors) ====");
|
||||
|
||||
// Make sure we emit something for every error
|
||||
let markedErrorCount = 0;
|
||||
@@ -1340,7 +1366,7 @@ namespace Harness {
|
||||
nextLineStart = lineStarts[lineIndex + 1];
|
||||
}
|
||||
// Emit this line from the original file
|
||||
outputLines.push(" " + line);
|
||||
outputLines += (newLine() + " " + line);
|
||||
fileErrors.forEach(err => {
|
||||
// Does any error start or continue on to this line? Emit squiggles
|
||||
const end = ts.textSpanEnd(err);
|
||||
@@ -1352,7 +1378,7 @@ namespace Harness {
|
||||
// Calculate the start of the squiggle
|
||||
const squiggleStart = Math.max(0, relativeOffset);
|
||||
// TODO/REVIEW: this doesn't work quite right in the browser if a multi file test has files whose names are just the right length relative to one another
|
||||
outputLines.push(" " + line.substr(0, squiggleStart).replace(/[^\s]/g, " ") + new Array(Math.min(length, line.length - squiggleStart) + 1).join("~"));
|
||||
outputLines += (newLine() + " " + line.substr(0, squiggleStart).replace(/[^\s]/g, " ") + new Array(Math.min(length, line.length - squiggleStart) + 1).join("~"));
|
||||
|
||||
// If the error ended here, or we're at the end of the file, emit its message
|
||||
if ((lineIndex === lines.length - 1) || nextLineStart > end) {
|
||||
@@ -1383,7 +1409,7 @@ namespace Harness {
|
||||
assert.equal(totalErrorsReportedInNonLibraryFiles + numLibraryDiagnostics + numTest262HarnessDiagnostics, diagnostics.length, "total number of errors");
|
||||
|
||||
return minimalDiagnosticsToString(diagnostics) +
|
||||
Harness.IO.newLine() + Harness.IO.newLine() + outputLines.join("\r\n");
|
||||
Harness.IO.newLine() + Harness.IO.newLine() + outputLines;
|
||||
}
|
||||
|
||||
export function doErrorBaseline(baselinePath: string, inputFiles: TestFile[], errors: ts.Diagnostic[]) {
|
||||
@@ -1586,9 +1612,10 @@ namespace Harness {
|
||||
}
|
||||
}
|
||||
|
||||
const declFileCompilationResult =
|
||||
Harness.Compiler.compileDeclarationFiles(
|
||||
toBeCompiled, otherFiles, result, harnessSettings, options, /*currentDirectory*/ undefined);
|
||||
const declFileContext = Harness.Compiler.prepareDeclarationCompilationContext(
|
||||
toBeCompiled, otherFiles, result, harnessSettings, options, /*currentDirectory*/ undefined
|
||||
);
|
||||
const declFileCompilationResult = Harness.Compiler.compileDeclarationFiles(declFileContext);
|
||||
|
||||
if (declFileCompilationResult && declFileCompilationResult.declResult.errors.length) {
|
||||
jsCode += "\r\n\r\n//// [DtsFileErrors]\r\n";
|
||||
@@ -1963,7 +1990,7 @@ namespace Harness {
|
||||
IO.writeFile(actualFileName + ".delete", "");
|
||||
}
|
||||
else {
|
||||
IO.writeFile(actualFileName, actual);
|
||||
IO.writeFile(actualFileName, encoded_actual);
|
||||
}
|
||||
throw new Error(`The baseline file ${relativeFileName} has changed.`);
|
||||
}
|
||||
|
||||
@@ -193,7 +193,9 @@ namespace Harness.LanguageService {
|
||||
}
|
||||
getCurrentDirectory(): string { return virtualFileSystemRoot; }
|
||||
getDefaultLibFileName(): string { return Harness.Compiler.defaultLibFileName; }
|
||||
getScriptFileNames(): string[] { return this.getFilenames(); }
|
||||
getScriptFileNames(): string[] {
|
||||
return this.getFilenames().filter(ts.isAnySupportedFileExtension);
|
||||
}
|
||||
getScriptSnapshot(fileName: string): ts.IScriptSnapshot {
|
||||
const script = this.getScriptInfo(fileName);
|
||||
return script ? new ScriptSnapshot(script) : undefined;
|
||||
@@ -826,6 +828,7 @@ namespace Harness.LanguageService {
|
||||
host: serverHost,
|
||||
cancellationToken: ts.server.nullCancellationToken,
|
||||
useSingleInferredProject: false,
|
||||
useInferredProjectPerProjectRoot: false,
|
||||
typingsInstaller: undefined,
|
||||
byteLength: Utils.byteLength,
|
||||
hrtime: process.hrtime,
|
||||
|
||||
@@ -426,12 +426,12 @@ class ProjectRunner extends RunnerBase {
|
||||
compilerResult.program ?
|
||||
ts.filter(compilerResult.program.getSourceFiles(), sourceFile => !Harness.isDefaultLibraryFile(sourceFile.fileName)) :
|
||||
[]),
|
||||
sourceFile => <Harness.Compiler.TestFile>{
|
||||
(sourceFile): Harness.Compiler.TestFile => ({
|
||||
unitName: ts.isRootedDiskPath(sourceFile.fileName) ?
|
||||
RunnerBase.removeFullPaths(sourceFile.fileName) :
|
||||
sourceFile.fileName,
|
||||
content: sourceFile.text
|
||||
});
|
||||
}));
|
||||
|
||||
return Harness.Compiler.getErrorBaseline(inputFiles, compilerResult.errors);
|
||||
}
|
||||
|
||||
+14
-10
@@ -208,6 +208,14 @@ namespace RWC {
|
||||
}, baselineOpts);
|
||||
});
|
||||
|
||||
it("has the expected types", () => {
|
||||
// We don't need to pass the extension here because "doTypeAndSymbolBaseline" will append appropriate extension of ".types" or ".symbols"
|
||||
Harness.Compiler.doTypeAndSymbolBaseline(baseName, compilerResult, inputFiles
|
||||
.concat(otherFiles)
|
||||
.filter(file => !!compilerResult.program.getSourceFile(file.unitName))
|
||||
.filter(e => !Harness.isDefaultLibraryFile(e.unitName)), baselineOpts);
|
||||
});
|
||||
|
||||
// Ideally, a generated declaration file will have no errors. But we allow generated
|
||||
// declaration file errors as part of the baseline.
|
||||
it("has the expected errors in generated declaration files", () => {
|
||||
@@ -217,8 +225,12 @@ namespace RWC {
|
||||
return null;
|
||||
}
|
||||
|
||||
const declFileCompilationResult = Harness.Compiler.compileDeclarationFiles(
|
||||
inputFiles, otherFiles, compilerResult, /*harnessSettings*/ undefined, compilerOptions, currentDirectory);
|
||||
const declContext = Harness.Compiler.prepareDeclarationCompilationContext(
|
||||
inputFiles, otherFiles, compilerResult, /*harnessSettings*/ undefined, compilerOptions, currentDirectory
|
||||
);
|
||||
// Reset compilerResult before calling into `compileDeclarationFiles` so the memory from the original compilation can be freed
|
||||
compilerResult = undefined;
|
||||
const declFileCompilationResult = Harness.Compiler.compileDeclarationFiles(declContext);
|
||||
|
||||
return Harness.Compiler.minimalDiagnosticsToString(declFileCompilationResult.declResult.errors) +
|
||||
Harness.IO.newLine() + Harness.IO.newLine() +
|
||||
@@ -226,14 +238,6 @@ namespace RWC {
|
||||
}, baselineOpts);
|
||||
}
|
||||
});
|
||||
|
||||
it("has the expected types", () => {
|
||||
// We don't need to pass the extension here because "doTypeAndSymbolBaseline" will append appropriate extension of ".types" or ".symbols"
|
||||
Harness.Compiler.doTypeAndSymbolBaseline(baseName, compilerResult, inputFiles
|
||||
.concat(otherFiles)
|
||||
.filter(file => !!compilerResult.program.getSourceFile(file.unitName))
|
||||
.filter(e => !Harness.isDefaultLibraryFile(e.unitName)), baselineOpts);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ namespace ts {
|
||||
logger: projectSystem.nullLogger,
|
||||
cancellationToken: { isCancellationRequested: () => false },
|
||||
useSingleInferredProject: false,
|
||||
useInferredProjectPerProjectRoot: false,
|
||||
typingsInstaller: undefined
|
||||
};
|
||||
const projectService = new server.ProjectService(svcOpts);
|
||||
|
||||
@@ -36,6 +36,7 @@ namespace ts.projectSystem {
|
||||
host,
|
||||
cancellationToken: nullCancellationToken,
|
||||
useSingleInferredProject: false,
|
||||
useInferredProjectPerProjectRoot: false,
|
||||
typingsInstaller: typingsInstaller || server.nullTypingsInstaller,
|
||||
byteLength: Utils.byteLength,
|
||||
hrtime: process.hrtime,
|
||||
@@ -518,18 +519,20 @@ namespace ts.projectSystem {
|
||||
};
|
||||
const host = createServerHost([f], { newLine });
|
||||
const session = createSession(host);
|
||||
session.executeCommand(<server.protocol.OpenRequest>{
|
||||
const openRequest: server.protocol.OpenRequest = {
|
||||
seq: 1,
|
||||
type: "request",
|
||||
command: "open",
|
||||
command: server.protocol.CommandTypes.Open,
|
||||
arguments: { file: f.path }
|
||||
});
|
||||
session.executeCommand(<server.protocol.CompileOnSaveEmitFileRequest>{
|
||||
};
|
||||
session.executeCommand(openRequest);
|
||||
const emitFileRequest: server.protocol.CompileOnSaveEmitFileRequest = {
|
||||
seq: 2,
|
||||
type: "request",
|
||||
command: "compileOnSaveEmitFile",
|
||||
command: server.protocol.CommandTypes.CompileOnSaveEmitFile,
|
||||
arguments: { file: f.path }
|
||||
});
|
||||
};
|
||||
session.executeCommand(emitFileRequest);
|
||||
const emitOutput = host.readFile(path + ts.Extension.Js);
|
||||
assert.equal(emitOutput, f.content + newLine, "content of emit output should be identical with the input + newline");
|
||||
}
|
||||
@@ -550,7 +553,7 @@ namespace ts.projectSystem {
|
||||
};
|
||||
const host = createServerHost([file1, file2, configFile, libFile], { newLine: "\r\n" });
|
||||
const typingsInstaller = createTestTypingsInstaller(host);
|
||||
const session = createSession(host, typingsInstaller);
|
||||
const session = createSession(host, { typingsInstaller });
|
||||
|
||||
openFilesForSession([file1, file2], session);
|
||||
const compileFileRequest = makeSessionRequest<server.protocol.CompileOnSaveEmitFileRequestArgs>(CommandNames.CompileOnSaveEmitFile, { file: file1.path, projectFileName: configFile.path });
|
||||
|
||||
@@ -67,14 +67,14 @@ namespace ts {
|
||||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
module: ModuleKind.CommonJS,
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
sourceMap: false,
|
||||
lib: ["lib.es5.d.ts", "lib.es2015.core.d.ts", "lib.es2015.symbol.d.ts"]
|
||||
},
|
||||
errors: <Diagnostic[]>[]
|
||||
errors: []
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -92,7 +92,7 @@ namespace ts {
|
||||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
module: ModuleKind.CommonJS,
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
@@ -100,7 +100,7 @@ namespace ts {
|
||||
allowJs: false,
|
||||
lib: ["lib.es5.d.ts", "lib.es2015.core.d.ts", "lib.es2015.symbol.d.ts"]
|
||||
},
|
||||
errors: <Diagnostic[]>[]
|
||||
errors: []
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -117,7 +117,7 @@ namespace ts {
|
||||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
module: ModuleKind.CommonJS,
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
@@ -146,7 +146,7 @@ namespace ts {
|
||||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
sourceMap: false,
|
||||
@@ -174,7 +174,7 @@ namespace ts {
|
||||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
sourceMap: false,
|
||||
@@ -201,7 +201,7 @@ namespace ts {
|
||||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
noImplicitAny: false,
|
||||
sourceMap: false,
|
||||
},
|
||||
@@ -227,7 +227,7 @@ namespace ts {
|
||||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
noImplicitAny: false,
|
||||
sourceMap: false,
|
||||
},
|
||||
@@ -255,7 +255,7 @@ namespace ts {
|
||||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
module: ModuleKind.CommonJS,
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
@@ -286,7 +286,7 @@ namespace ts {
|
||||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
module: ModuleKind.CommonJS,
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
@@ -317,7 +317,7 @@ namespace ts {
|
||||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
module: ModuleKind.CommonJS,
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
@@ -348,7 +348,7 @@ namespace ts {
|
||||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
module: ModuleKind.CommonJS,
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
@@ -379,7 +379,7 @@ namespace ts {
|
||||
}
|
||||
}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
module: ModuleKind.CommonJS,
|
||||
target: ScriptTarget.ES5,
|
||||
noImplicitAny: false,
|
||||
@@ -415,8 +415,8 @@ namespace ts {
|
||||
it("Convert default tsconfig.json to compiler-options ", () => {
|
||||
assertCompilerOptions({}, "tsconfig.json",
|
||||
{
|
||||
compilerOptions: {} as CompilerOptions,
|
||||
errors: <Diagnostic[]>[]
|
||||
compilerOptions: {},
|
||||
errors: []
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -434,7 +434,7 @@ namespace ts {
|
||||
}
|
||||
}, "jsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
allowJs: true,
|
||||
maxNodeModuleJsDepth: 2,
|
||||
allowSyntheticDefaultImports: true,
|
||||
@@ -445,7 +445,7 @@ namespace ts {
|
||||
sourceMap: false,
|
||||
lib: ["lib.es5.d.ts", "lib.es2015.core.d.ts", "lib.es2015.symbol.d.ts"]
|
||||
},
|
||||
errors: <Diagnostic[]>[]
|
||||
errors: []
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -463,7 +463,7 @@ namespace ts {
|
||||
}
|
||||
}, "jsconfig.json",
|
||||
{
|
||||
compilerOptions: <CompilerOptions>{
|
||||
compilerOptions: {
|
||||
allowJs: false,
|
||||
maxNodeModuleJsDepth: 2,
|
||||
allowSyntheticDefaultImports: true,
|
||||
@@ -474,7 +474,7 @@ namespace ts {
|
||||
sourceMap: false,
|
||||
lib: ["lib.es5.d.ts", "lib.es2015.core.d.ts", "lib.es2015.symbol.d.ts"]
|
||||
},
|
||||
errors: <Diagnostic[]>[]
|
||||
errors: []
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -516,7 +516,7 @@ namespace ts {
|
||||
allowSyntheticDefaultImports: true,
|
||||
skipLibCheck: true
|
||||
},
|
||||
errors: <Diagnostic[]>[]
|
||||
errors: []
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,591 @@
|
||||
/// <reference path="..\harness.ts" />
|
||||
/// <reference path="tsserverProjectSystem.ts" />
|
||||
|
||||
namespace ts {
|
||||
interface Range {
|
||||
start: number;
|
||||
end: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface Test {
|
||||
source: string;
|
||||
ranges: Map<Range>;
|
||||
}
|
||||
|
||||
function extractTest(source: string): Test {
|
||||
const activeRanges: Range[] = [];
|
||||
let text = "";
|
||||
let lastPos = 0;
|
||||
let pos = 0;
|
||||
const ranges = createMap<Range>();
|
||||
|
||||
while (pos < source.length) {
|
||||
if (source.charCodeAt(pos) === CharacterCodes.openBracket &&
|
||||
(source.charCodeAt(pos + 1) === CharacterCodes.hash || source.charCodeAt(pos + 1) === CharacterCodes.$)) {
|
||||
const saved = pos;
|
||||
pos += 2;
|
||||
const s = pos;
|
||||
consumeIdentifier();
|
||||
const e = pos;
|
||||
if (source.charCodeAt(pos) === CharacterCodes.bar) {
|
||||
pos++;
|
||||
text += source.substring(lastPos, saved);
|
||||
const name = s === e
|
||||
? source.charCodeAt(saved + 1) === CharacterCodes.hash ? "selection" : "extracted"
|
||||
: source.substring(s, e);
|
||||
activeRanges.push({ name, start: text.length, end: undefined });
|
||||
lastPos = pos;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
pos = saved;
|
||||
}
|
||||
}
|
||||
else if (source.charCodeAt(pos) === CharacterCodes.bar && source.charCodeAt(pos + 1) === CharacterCodes.closeBracket) {
|
||||
text += source.substring(lastPos, pos);
|
||||
activeRanges[activeRanges.length - 1].end = text.length;
|
||||
const range = activeRanges.pop();
|
||||
if (range.name in ranges) {
|
||||
throw new Error(`Duplicate name of range ${range.name}`);
|
||||
}
|
||||
ranges.set(range.name, range);
|
||||
pos += 2;
|
||||
lastPos = pos;
|
||||
continue;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
text += source.substring(lastPos, pos);
|
||||
|
||||
function consumeIdentifier() {
|
||||
while (isIdentifierPart(source.charCodeAt(pos), ScriptTarget.Latest)) {
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
return { source: text, ranges };
|
||||
}
|
||||
|
||||
const newLineCharacter = "\n";
|
||||
function getRuleProvider(action?: (opts: FormatCodeSettings) => void) {
|
||||
const options = {
|
||||
indentSize: 4,
|
||||
tabSize: 4,
|
||||
newLineCharacter,
|
||||
convertTabsToSpaces: true,
|
||||
indentStyle: ts.IndentStyle.Smart,
|
||||
insertSpaceAfterConstructor: false,
|
||||
insertSpaceAfterCommaDelimiter: true,
|
||||
insertSpaceAfterSemicolonInForStatements: true,
|
||||
insertSpaceBeforeAndAfterBinaryOperators: true,
|
||||
insertSpaceAfterKeywordsInControlFlowStatements: true,
|
||||
insertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true,
|
||||
insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false,
|
||||
insertSpaceBeforeFunctionParenthesis: false,
|
||||
placeOpenBraceOnNewLineForFunctions: false,
|
||||
placeOpenBraceOnNewLineForControlBlocks: false,
|
||||
};
|
||||
if (action) {
|
||||
action(options);
|
||||
}
|
||||
const rulesProvider = new formatting.RulesProvider();
|
||||
rulesProvider.ensureUpToDate(options);
|
||||
return rulesProvider;
|
||||
}
|
||||
|
||||
function testExtractRangeFailed(caption: string, s: string, expectedErrors: string[]) {
|
||||
return it(caption, () => {
|
||||
const t = extractTest(s);
|
||||
const file = createSourceFile("a.ts", t.source, ScriptTarget.Latest, /*setParentNodes*/ true);
|
||||
const selectionRange = t.ranges.get("selection");
|
||||
if (!selectionRange) {
|
||||
throw new Error(`Test ${s} does not specify selection range`);
|
||||
}
|
||||
const result = refactor.extractMethod.getRangeToExtract(file, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
|
||||
assert(result.targetRange === undefined, "failure expected");
|
||||
const sortedErrors = result.errors.map(e => <string>e.messageText).sort();
|
||||
assert.deepEqual(sortedErrors, expectedErrors.sort(), "unexpected errors");
|
||||
});
|
||||
}
|
||||
|
||||
function testExtractRange(s: string): void {
|
||||
const t = extractTest(s);
|
||||
const f = createSourceFile("a.ts", t.source, ScriptTarget.Latest, /*setParentNodes*/ true);
|
||||
const selectionRange = t.ranges.get("selection");
|
||||
if (!selectionRange) {
|
||||
throw new Error(`Test ${s} does not specify selection range`);
|
||||
}
|
||||
const result = refactor.extractMethod.getRangeToExtract(f, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
|
||||
const expectedRange = t.ranges.get("extracted");
|
||||
if (expectedRange) {
|
||||
let start: number, end: number;
|
||||
if (ts.isArray(result.targetRange.range)) {
|
||||
start = result.targetRange.range[0].getStart(f);
|
||||
end = ts.lastOrUndefined(result.targetRange.range).getEnd();
|
||||
}
|
||||
else {
|
||||
start = result.targetRange.range.getStart(f);
|
||||
end = result.targetRange.range.getEnd();
|
||||
}
|
||||
assert.equal(start, expectedRange.start, "incorrect start of range");
|
||||
assert.equal(end, expectedRange.end, "incorrect end of range");
|
||||
}
|
||||
else {
|
||||
assert.isTrue(!result.targetRange, `expected range to extract to be undefined`);
|
||||
}
|
||||
}
|
||||
|
||||
describe("extractMethods", () => {
|
||||
it("get extract range from selection", () => {
|
||||
testExtractRange(`
|
||||
[#|
|
||||
[$|var x = 1;
|
||||
var y = 2;|]|]
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|
|
||||
var x = 1;
|
||||
var y = 2|];
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|var x = 1|];
|
||||
var y = 2;
|
||||
`);
|
||||
testExtractRange(`
|
||||
if ([#|[#extracted|a && b && c && d|]|]) {
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
if [#|(a && b && c && d|]) {
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
if (a && b && c && d) {
|
||||
[#| [$|var x = 1;
|
||||
console.log(x);|] |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|
|
||||
if (a) {
|
||||
return 100;
|
||||
} |]
|
||||
`);
|
||||
testExtractRange(`
|
||||
function foo() {
|
||||
[#| [$|if (a) {
|
||||
}
|
||||
return 100|] |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|
|
||||
[$|l1:
|
||||
if (x) {
|
||||
break l1;
|
||||
}|]|]
|
||||
`);
|
||||
testExtractRange(`
|
||||
[#|
|
||||
[$|l2:
|
||||
{
|
||||
if (x) {
|
||||
}
|
||||
break l2;
|
||||
}|]|]
|
||||
`);
|
||||
testExtractRange(`
|
||||
while (true) {
|
||||
[#| if(x) {
|
||||
}
|
||||
break; |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
while (true) {
|
||||
[#| if(x) {
|
||||
}
|
||||
continue; |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
l3:
|
||||
{
|
||||
[#|
|
||||
if (x) {
|
||||
}
|
||||
break l3; |]
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
while (true) {
|
||||
[#|
|
||||
if (x) {
|
||||
return;
|
||||
} |]
|
||||
}
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
while (true) {
|
||||
[#|
|
||||
[$|if (x) {
|
||||
}
|
||||
return;|]
|
||||
|]
|
||||
}
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
return [#| [$|1 + 2|] |]+ 3;
|
||||
}
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
return [$|1 + [#|2 + 3|]|];
|
||||
}
|
||||
}
|
||||
`);
|
||||
testExtractRange(`
|
||||
function f() {
|
||||
return [$|1 + 2 + [#|3 + 4|]|];
|
||||
}
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed1",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
[#|
|
||||
let x = 1
|
||||
if (x) {
|
||||
return 10;
|
||||
}
|
||||
|]
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing conditional return statement."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed2",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
while (true) {
|
||||
[#|
|
||||
let x = 1
|
||||
if (x) {
|
||||
break;
|
||||
}
|
||||
|]
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing conditional break or continue statements."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed3",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
while (true) {
|
||||
[#|
|
||||
let x = 1
|
||||
if (x) {
|
||||
continue;
|
||||
}
|
||||
|]
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing conditional break or continue statements."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed4",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
l1: {
|
||||
[#|
|
||||
let x = 1
|
||||
if (x) {
|
||||
break l1;
|
||||
}
|
||||
|]
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing labeled break or continue with target outside of the range."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed5",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
[#|
|
||||
try {
|
||||
f2()
|
||||
return 10;
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
|]
|
||||
}
|
||||
function f2() {
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing conditional return statement."
|
||||
]);
|
||||
|
||||
testExtractRangeFailed("extractRangeFailed6",
|
||||
`
|
||||
namespace A {
|
||||
function f() {
|
||||
[#|
|
||||
try {
|
||||
f2()
|
||||
}
|
||||
catch (e) {
|
||||
return 10;
|
||||
}
|
||||
|]
|
||||
}
|
||||
function f2() {
|
||||
}
|
||||
}
|
||||
`,
|
||||
[
|
||||
"Cannot extract range containing conditional return statement."
|
||||
]);
|
||||
|
||||
testExtractMethod("extractMethod1",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod2",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
return foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod3",
|
||||
`namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function* a(z: number) {
|
||||
[#|
|
||||
let y = 5;
|
||||
yield z;
|
||||
return foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod4",
|
||||
`namespace A {
|
||||
function foo() {
|
||||
}
|
||||
namespace B {
|
||||
async function a(z: number, z1: any) {
|
||||
[#|
|
||||
let y = 5;
|
||||
if (z) {
|
||||
await z1;
|
||||
}
|
||||
return foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod5",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod6",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
export function foo() {
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod7",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
export namespace C {
|
||||
export function foo() {
|
||||
}
|
||||
}
|
||||
namespace B {
|
||||
function a() {
|
||||
let a = 1;
|
||||
[#|
|
||||
let y = 5;
|
||||
let z = x;
|
||||
a = y;
|
||||
return C.foo();|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod8",
|
||||
`namespace A {
|
||||
let x = 1;
|
||||
namespace B {
|
||||
function a() {
|
||||
let a1 = 1;
|
||||
return 1 + [#|a1 + x|] + 100;
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod9",
|
||||
`namespace A {
|
||||
export interface I { x: number };
|
||||
namespace B {
|
||||
function a() {
|
||||
[#|let a1: I = { x: 1 };
|
||||
return a1.x + 10;|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod10",
|
||||
`namespace A {
|
||||
export interface I { x: number };
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
[#|let a1: I = { x: 1 };
|
||||
return a1.x + 10;|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod11",
|
||||
`namespace A {
|
||||
let y = 1;
|
||||
class C {
|
||||
a() {
|
||||
let z = 1;
|
||||
[#|let a1 = { x: 1 };
|
||||
y = 10;
|
||||
z = 42;
|
||||
return a1.x + 10;|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
testExtractMethod("extractMethod12",
|
||||
`namespace A {
|
||||
let y = 1;
|
||||
class C {
|
||||
b() {}
|
||||
a() {
|
||||
let z = 1;
|
||||
[#|let a1 = { x: 1 };
|
||||
y = 10;
|
||||
z = 42;
|
||||
this.b();
|
||||
return a1.x + 10;|]
|
||||
}
|
||||
}
|
||||
}`);
|
||||
});
|
||||
|
||||
|
||||
function testExtractMethod(caption: string, text: string) {
|
||||
it(caption, () => {
|
||||
Harness.Baseline.runBaseline(`extractMethod/${caption}.js`, () => {
|
||||
const t = extractTest(text);
|
||||
const selectionRange = t.ranges.get("selection");
|
||||
if (!selectionRange) {
|
||||
throw new Error(`Test ${caption} does not specify selection range`);
|
||||
}
|
||||
const f = {
|
||||
path: "/a.ts",
|
||||
content: t.source
|
||||
};
|
||||
const host = projectSystem.createServerHost([f]);
|
||||
const projectService = projectSystem.createProjectService(host);
|
||||
projectService.openClientFile(f.path);
|
||||
const program = projectService.inferredProjects[0].getLanguageService().getProgram();
|
||||
const sourceFile = program.getSourceFile(f.path);
|
||||
const context: RefactorContext = {
|
||||
cancellationToken: { throwIfCancellationRequested() { }, isCancellationRequested() { return false; } },
|
||||
newLineCharacter,
|
||||
program,
|
||||
file: sourceFile,
|
||||
startPosition: -1,
|
||||
rulesProvider: getRuleProvider()
|
||||
};
|
||||
const result = refactor.extractMethod.getRangeToExtract(sourceFile, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
|
||||
assert.equal(result.errors, undefined, "expect no errors");
|
||||
const results = refactor.extractMethod.getPossibleExtractions(result.targetRange, context);
|
||||
const data: string[] = [];
|
||||
data.push(`==ORIGINAL==`);
|
||||
data.push(sourceFile.text);
|
||||
for (const r of results) {
|
||||
const changes = refactor.extractMethod.getPossibleExtractions(result.targetRange, context, results.indexOf(r))[0].changes;
|
||||
data.push(`==SCOPE::${r.scopeDescription}==`);
|
||||
data.push(textChanges.applyChanges(sourceFile.text, changes[0].textChanges));
|
||||
}
|
||||
return data.join(newLineCharacter);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -110,23 +110,21 @@ namespace ts {
|
||||
}
|
||||
{
|
||||
const actual = ts.parseJsonConfigFileContent(json, host, basePath, existingOptions, configFileName, resolutionStack);
|
||||
expected.errors = map(expected.errors, error => {
|
||||
return <Diagnostic>{
|
||||
category: error.category,
|
||||
code: error.code,
|
||||
file: undefined,
|
||||
length: undefined,
|
||||
messageText: error.messageText,
|
||||
start: undefined,
|
||||
};
|
||||
});
|
||||
expected.errors = expected.errors.map<Diagnostic>(error => ({
|
||||
category: error.category,
|
||||
code: error.code,
|
||||
file: undefined,
|
||||
length: undefined,
|
||||
messageText: error.messageText,
|
||||
start: undefined,
|
||||
}));
|
||||
assertParsed(actual, expected);
|
||||
}
|
||||
}
|
||||
|
||||
function createDiagnosticForConfigFile(json: any, start: number, length: number, diagnosticMessage: DiagnosticMessage, arg0: string) {
|
||||
const text = JSON.stringify(json);
|
||||
const file = <SourceFile>{
|
||||
const file = <SourceFile>{ // tslint:disable-line no-object-literal-type-assertion
|
||||
fileName: caseInsensitiveTsconfigPath,
|
||||
kind: SyntaxKind.SourceFile,
|
||||
text
|
||||
|
||||
@@ -26,10 +26,19 @@ namespace ts {
|
||||
interface File {
|
||||
name: string;
|
||||
content?: string;
|
||||
symlinks?: string[];
|
||||
}
|
||||
|
||||
function createModuleResolutionHost(hasDirectoryExists: boolean, ...files: File[]): ModuleResolutionHost {
|
||||
const map = arrayToMap(files, f => f.name);
|
||||
const map = createMap<File>();
|
||||
for (const file of files) {
|
||||
map.set(file.name, file);
|
||||
if (file.symlinks) {
|
||||
for (const symlink of file.symlinks) {
|
||||
map.set(symlink, file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasDirectoryExists) {
|
||||
const directories = createMap<string>();
|
||||
@@ -46,6 +55,7 @@ namespace ts {
|
||||
}
|
||||
return {
|
||||
readFile,
|
||||
realpath,
|
||||
directoryExists: path => directories.has(path),
|
||||
fileExists: path => {
|
||||
assert.isTrue(directories.has(getDirectoryPath(path)), `'fileExists' '${path}' request in non-existing directory`);
|
||||
@@ -54,12 +64,15 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
else {
|
||||
return { readFile, fileExists: path => map.has(path) };
|
||||
return { readFile, realpath, fileExists: path => map.has(path) };
|
||||
}
|
||||
function readFile(path: string): string | undefined {
|
||||
const file = map.get(path);
|
||||
return file && file.content;
|
||||
}
|
||||
function realpath(path: string): string {
|
||||
return map.get(path).name;
|
||||
}
|
||||
}
|
||||
|
||||
describe("Node module resolution - relative paths", () => {
|
||||
@@ -233,8 +246,8 @@ namespace ts {
|
||||
test(/*hasDirectoryExists*/ true);
|
||||
|
||||
function test(hasDirectoryExists: boolean) {
|
||||
const containingFile = { name: "/a/node_modules/b/c/node_modules/d/e.ts" };
|
||||
const moduleFile = { name: "/a/node_modules/foo/index.d.ts" };
|
||||
const containingFile: File = { name: "/a/node_modules/b/c/node_modules/d/e.ts" };
|
||||
const moduleFile: File = { name: "/a/node_modules/foo/index.d.ts" };
|
||||
const resolution = nodeModuleNameResolver("foo", containingFile.name, {}, createModuleResolutionHost(hasDirectoryExists, containingFile, moduleFile));
|
||||
checkResolvedModuleWithFailedLookupLocations(resolution, createResolvedModule(moduleFile.name, /*isExternalLibraryImport*/ true), [
|
||||
"/a/node_modules/b/c/node_modules/d/node_modules/foo.ts",
|
||||
@@ -289,6 +302,19 @@ namespace ts {
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
testPreserveSymlinks(/*preserveSymlinks*/ false);
|
||||
testPreserveSymlinks(/*preserveSymlinks*/ true);
|
||||
function testPreserveSymlinks(preserveSymlinks: boolean) {
|
||||
it(`preserveSymlinks: ${preserveSymlinks}`, () => {
|
||||
const realFileName = "/linked/index.d.ts";
|
||||
const symlinkFileName = "/app/node_modulex/linked/index.d.ts";
|
||||
const host = createModuleResolutionHost(/*hasDirectoryExists*/ true, { name: realFileName, symlinks: [symlinkFileName] });
|
||||
const resolution = nodeModuleNameResolver("linked", "/app/app.ts", { preserveSymlinks }, host);
|
||||
const resolvedFileName = preserveSymlinks ? symlinkFileName : realFileName;
|
||||
checkResolvedModule(resolution.resolvedModule, { resolvedFileName, isExternalLibraryImport: true, extension: Extension.Dts });
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe("Module resolution - relative imports", () => {
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
|
||||
namespace ts.projectSystem {
|
||||
describe("Project errors", () => {
|
||||
function checkProjectErrors(projectFiles: server.ProjectFilesWithTSDiagnostics, expectedErrors: string[]) {
|
||||
function checkProjectErrors(projectFiles: server.ProjectFilesWithTSDiagnostics, expectedErrors: ReadonlyArray<string>): void {
|
||||
assert.isTrue(projectFiles !== undefined, "missing project files");
|
||||
checkProjectErrorsWorker(projectFiles.projectErrors, expectedErrors);
|
||||
}
|
||||
|
||||
function checkProjectErrorsWorker(errors: Diagnostic[], expectedErrors: string[]) {
|
||||
function checkProjectErrorsWorker(errors: ReadonlyArray<Diagnostic>, expectedErrors: ReadonlyArray<string>): void {
|
||||
assert.equal(errors ? errors.length : 0, expectedErrors.length, `expected ${expectedErrors.length} error in the list`);
|
||||
if (expectedErrors.length) {
|
||||
for (let i = 0; i < errors.length; i++) {
|
||||
|
||||
@@ -109,7 +109,10 @@ namespace ts {
|
||||
function createTestCompilerHost(texts: NamedSourceText[], target: ScriptTarget, oldProgram?: ProgramWithSourceTexts): TestCompilerHost {
|
||||
const files = arrayToMap(texts, t => t.name, t => {
|
||||
if (oldProgram) {
|
||||
const oldFile = <SourceFileWithText>oldProgram.getSourceFile(t.name);
|
||||
let oldFile = <SourceFileWithText>oldProgram.getSourceFile(t.name);
|
||||
if (oldFile && oldFile.redirectInfo) {
|
||||
oldFile = oldFile.redirectInfo.unredirected;
|
||||
}
|
||||
if (oldFile && oldFile.sourceText.getVersion() === t.text.getVersion()) {
|
||||
return oldFile;
|
||||
}
|
||||
@@ -171,11 +174,16 @@ namespace ts {
|
||||
return program;
|
||||
}
|
||||
|
||||
function updateProgramText(files: ReadonlyArray<NamedSourceText>, fileName: string, newProgramText: string) {
|
||||
const file = find(files, f => f.name === fileName)!;
|
||||
file.text = file.text.updateProgram(newProgramText);
|
||||
}
|
||||
|
||||
function checkResolvedTypeDirective(expected: ResolvedTypeReferenceDirective, actual: ResolvedTypeReferenceDirective): boolean {
|
||||
if (!expected === !actual) {
|
||||
if (expected) {
|
||||
assert.isTrue(expected.resolvedFileName === actual.resolvedFileName, `'resolvedFileName': expected '${expected.resolvedFileName}' to be equal to '${actual.resolvedFileName}'`);
|
||||
assert.isTrue(expected.primary === actual.primary, `'primary': expected '${expected.primary}' to be equal to '${actual.primary}'`);
|
||||
assert.equal(expected.resolvedFileName, actual.resolvedFileName, `'resolvedFileName': expected '${expected.resolvedFileName}' to be equal to '${actual.resolvedFileName}'`);
|
||||
assert.equal(expected.primary, actual.primary, `'primary': expected '${expected.primary}' to be equal to '${actual.primary}'`);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -238,7 +246,7 @@ namespace ts {
|
||||
const program_2 = updateProgram(program_1, ["a.ts"], { target }, files => {
|
||||
files[0].text = files[0].text.updateProgram("var x = 100");
|
||||
});
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.Completely);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Completely);
|
||||
const program1Diagnostics = program_1.getSemanticDiagnostics(program_1.getSourceFile("a.ts"));
|
||||
const program2Diagnostics = program_2.getSemanticDiagnostics(program_1.getSourceFile("a.ts"));
|
||||
assert.equal(program1Diagnostics.length, program2Diagnostics.length);
|
||||
@@ -249,7 +257,7 @@ namespace ts {
|
||||
const program_2 = updateProgram(program_1, ["a.ts"], { target }, files => {
|
||||
files[0].text = files[0].text.updateProgram("var x = 100");
|
||||
});
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.Completely);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Completely);
|
||||
const program1Diagnostics = program_1.getSemanticDiagnostics(program_1.getSourceFile("a.ts"));
|
||||
const program2Diagnostics = program_2.getSemanticDiagnostics(program_1.getSourceFile("a.ts"));
|
||||
assert.equal(program1Diagnostics.length, program2Diagnostics.length);
|
||||
@@ -263,19 +271,19 @@ namespace ts {
|
||||
`;
|
||||
files[0].text = files[0].text.updateReferences(newReferences);
|
||||
});
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.SafeModules);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.SafeModules);
|
||||
});
|
||||
|
||||
it("fails if change affects type references", () => {
|
||||
const program_1 = newProgram(files, ["a.ts"], { types: ["a"] });
|
||||
updateProgram(program_1, ["a.ts"], { types: ["b"] }, noop);
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.Not);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Not);
|
||||
});
|
||||
|
||||
it("succeeds if change doesn't affect type references", () => {
|
||||
const program_1 = newProgram(files, ["a.ts"], { types: ["a"] });
|
||||
updateProgram(program_1, ["a.ts"], { types: ["a"] }, noop);
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.Completely);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Completely);
|
||||
});
|
||||
|
||||
it("fails if change affects imports", () => {
|
||||
@@ -283,7 +291,7 @@ namespace ts {
|
||||
updateProgram(program_1, ["a.ts"], { target }, files => {
|
||||
files[2].text = files[2].text.updateImportsAndExports("import x from 'b'");
|
||||
});
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.SafeModules);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.SafeModules);
|
||||
});
|
||||
|
||||
it("fails if change affects type directives", () => {
|
||||
@@ -295,25 +303,25 @@ namespace ts {
|
||||
/// <reference types="typerefs1" />`;
|
||||
files[0].text = files[0].text.updateReferences(newReferences);
|
||||
});
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.SafeModules);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.SafeModules);
|
||||
});
|
||||
|
||||
it("fails if module kind changes", () => {
|
||||
const program_1 = newProgram(files, ["a.ts"], { target, module: ModuleKind.CommonJS });
|
||||
updateProgram(program_1, ["a.ts"], { target, module: ModuleKind.AMD }, noop);
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.Not);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Not);
|
||||
});
|
||||
|
||||
it("fails if rootdir changes", () => {
|
||||
const program_1 = newProgram(files, ["a.ts"], { target, module: ModuleKind.CommonJS, rootDir: "/a/b" });
|
||||
updateProgram(program_1, ["a.ts"], { target, module: ModuleKind.CommonJS, rootDir: "/a/c" }, noop);
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.Not);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Not);
|
||||
});
|
||||
|
||||
it("fails if config path changes", () => {
|
||||
const program_1 = newProgram(files, ["a.ts"], { target, module: ModuleKind.CommonJS, configFilePath: "/a/b/tsconfig.json" });
|
||||
updateProgram(program_1, ["a.ts"], { target, module: ModuleKind.CommonJS, configFilePath: "/a/c/tsconfig.json" }, noop);
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.Not);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Not);
|
||||
});
|
||||
|
||||
it("succeeds if missing files remain missing", () => {
|
||||
@@ -357,7 +365,7 @@ namespace ts {
|
||||
const program_2 = updateProgram(program_1, ["a.ts"], options, files => {
|
||||
files[0].text = files[0].text.updateProgram("var x = 2");
|
||||
});
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.Completely);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Completely);
|
||||
|
||||
// content of resolution cache should not change
|
||||
checkResolvedModulesCache(program_1, "a.ts", createMapFromTemplate({ "b": createResolvedModule("b.ts") }));
|
||||
@@ -367,7 +375,7 @@ namespace ts {
|
||||
const program_3 = updateProgram(program_2, ["a.ts"], options, files => {
|
||||
files[0].text = files[0].text.updateImportsAndExports("");
|
||||
});
|
||||
assert.isTrue(program_2.structureIsReused === StructureIsReused.SafeModules);
|
||||
assert.equal(program_2.structureIsReused, StructureIsReused.SafeModules);
|
||||
checkResolvedModulesCache(program_3, "a.ts", /*expectedContent*/ undefined);
|
||||
|
||||
const program_4 = updateProgram(program_3, ["a.ts"], options, files => {
|
||||
@@ -376,7 +384,7 @@ namespace ts {
|
||||
`;
|
||||
files[0].text = files[0].text.updateImportsAndExports(newImports);
|
||||
});
|
||||
assert.isTrue(program_3.structureIsReused === StructureIsReused.SafeModules);
|
||||
assert.equal(program_3.structureIsReused, StructureIsReused.SafeModules);
|
||||
checkResolvedModulesCache(program_4, "a.ts", createMapFromTemplate({ "b": createResolvedModule("b.ts"), "c": undefined }));
|
||||
});
|
||||
|
||||
@@ -394,7 +402,7 @@ namespace ts {
|
||||
const program_2 = updateProgram(program_1, ["/a.ts"], options, files => {
|
||||
files[0].text = files[0].text.updateProgram("var x = 2");
|
||||
});
|
||||
assert.isTrue(program_1.structureIsReused === StructureIsReused.Completely);
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Completely);
|
||||
|
||||
// content of resolution cache should not change
|
||||
checkResolvedTypeDirectivesCache(program_1, "/a.ts", createMapFromTemplate({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } }));
|
||||
@@ -405,7 +413,7 @@ namespace ts {
|
||||
files[0].text = files[0].text.updateReferences("");
|
||||
});
|
||||
|
||||
assert.isTrue(program_2.structureIsReused === StructureIsReused.SafeModules);
|
||||
assert.equal(program_2.structureIsReused, StructureIsReused.SafeModules);
|
||||
checkResolvedTypeDirectivesCache(program_3, "/a.ts", /*expectedContent*/ undefined);
|
||||
|
||||
updateProgram(program_3, ["/a.ts"], options, files => {
|
||||
@@ -414,7 +422,7 @@ namespace ts {
|
||||
`;
|
||||
files[0].text = files[0].text.updateReferences(newReferences);
|
||||
});
|
||||
assert.isTrue(program_3.structureIsReused === StructureIsReused.SafeModules);
|
||||
assert.equal(program_3.structureIsReused, StructureIsReused.SafeModules);
|
||||
checkResolvedTypeDirectivesCache(program_1, "/a.ts", createMapFromTemplate({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } }));
|
||||
});
|
||||
|
||||
@@ -454,7 +462,7 @@ namespace ts {
|
||||
"initialProgram: execute module resolution normally.");
|
||||
|
||||
const initialProgramDiagnostics = initialProgram.getSemanticDiagnostics(initialProgram.getSourceFile("file1.ts"));
|
||||
assert(initialProgramDiagnostics.length === 1, `initialProgram: import should fail.`);
|
||||
assert.lengthOf(initialProgramDiagnostics, 1, `initialProgram: import should fail.`);
|
||||
}
|
||||
|
||||
const afterNpmInstallProgram = updateProgram(initialProgram, rootFiles.map(f => f.name), options, f => {
|
||||
@@ -478,7 +486,7 @@ namespace ts {
|
||||
"afterNpmInstallProgram: execute module resolution normally.");
|
||||
|
||||
const afterNpmInstallProgramDiagnostics = afterNpmInstallProgram.getSemanticDiagnostics(afterNpmInstallProgram.getSourceFile("file1.ts"));
|
||||
assert(afterNpmInstallProgramDiagnostics.length === 0, `afterNpmInstallProgram: program is well-formed with import.`);
|
||||
assert.lengthOf(afterNpmInstallProgramDiagnostics, 0, `afterNpmInstallProgram: program is well-formed with import.`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -617,10 +625,10 @@ namespace ts {
|
||||
"File 'f1.ts' exist - use it as a name resolution result.",
|
||||
"======== Module name './f1' was successfully resolved to 'f1.ts'. ========"
|
||||
],
|
||||
"program_1: execute module reoslution normally.");
|
||||
"program_1: execute module resolution normally.");
|
||||
|
||||
const program_1Diagnostics = program_1.getSemanticDiagnostics(program_1.getSourceFile("f2.ts"));
|
||||
assert(program_1Diagnostics.length === expectedErrors, `initial program should be well-formed`);
|
||||
assert.lengthOf(program_1Diagnostics, expectedErrors, `initial program should be well-formed`);
|
||||
}
|
||||
const indexOfF1 = 6;
|
||||
const program_2 = updateProgram(program_1, program_1.getRootFileNames(), options, f => {
|
||||
@@ -630,7 +638,7 @@ namespace ts {
|
||||
|
||||
{
|
||||
const program_2Diagnostics = program_2.getSemanticDiagnostics(program_2.getSourceFile("f2.ts"));
|
||||
assert(program_2Diagnostics.length === expectedErrors, `removing no-default-lib shouldn't affect any types used.`);
|
||||
assert.lengthOf(program_2Diagnostics, expectedErrors, `removing no-default-lib shouldn't affect any types used.`);
|
||||
|
||||
assert.deepEqual(program_2.host.getTrace(), [
|
||||
"======== Resolving type reference directive 'typerefs1', containing file 'f1.ts', root directory 'node_modules/@types'. ========",
|
||||
@@ -659,7 +667,7 @@ namespace ts {
|
||||
|
||||
{
|
||||
const program_3Diagnostics = program_3.getSemanticDiagnostics(program_3.getSourceFile("f2.ts"));
|
||||
assert(program_3Diagnostics.length === expectedErrors, `typerefs2 was unused, so diagnostics should be unaffected.`);
|
||||
assert.lengthOf(program_3Diagnostics, expectedErrors, `typerefs2 was unused, so diagnostics should be unaffected.`);
|
||||
|
||||
assert.deepEqual(program_3.host.getTrace(), [
|
||||
"======== Resolving module './b1' from 'f1.ts'. ========",
|
||||
@@ -684,7 +692,7 @@ namespace ts {
|
||||
|
||||
{
|
||||
const program_4Diagnostics = program_4.getSemanticDiagnostics(program_4.getSourceFile("f2.ts"));
|
||||
assert(program_4Diagnostics.length === expectedErrors, `a1.ts was unused, so diagnostics should be unaffected.`);
|
||||
assert.lengthOf(program_4Diagnostics, expectedErrors, `a1.ts was unused, so diagnostics should be unaffected.`);
|
||||
|
||||
assert.deepEqual(program_4.host.getTrace(), [
|
||||
"======== Resolving module './b1' from 'f1.ts'. ========",
|
||||
@@ -708,7 +716,7 @@ namespace ts {
|
||||
|
||||
{
|
||||
const program_5Diagnostics = program_5.getSemanticDiagnostics(program_5.getSourceFile("f2.ts"));
|
||||
assert(program_5Diagnostics.length === ++expectedErrors, `import of BB in f1 fails. BB is of type any. Add one error`);
|
||||
assert.lengthOf(program_5Diagnostics, ++expectedErrors, `import of BB in f1 fails. BB is of type any. Add one error`);
|
||||
|
||||
assert.deepEqual(program_5.host.getTrace(), [
|
||||
"======== Resolving module './b1' from 'f1.ts'. ========",
|
||||
@@ -725,7 +733,7 @@ namespace ts {
|
||||
|
||||
{
|
||||
const program_6Diagnostics = program_6.getSemanticDiagnostics(program_6.getSourceFile("f2.ts"));
|
||||
assert(program_6Diagnostics.length === expectedErrors, `import of BB in f1 fails.`);
|
||||
assert.lengthOf(program_6Diagnostics, expectedErrors, `import of BB in f1 fails.`);
|
||||
|
||||
assert.deepEqual(program_6.host.getTrace(), [
|
||||
"======== Resolving module './b1' from 'f1.ts'. ========",
|
||||
@@ -749,7 +757,7 @@ namespace ts {
|
||||
|
||||
{
|
||||
const program_7Diagnostics = program_7.getSemanticDiagnostics(program_7.getSourceFile("f2.ts"));
|
||||
assert(program_7Diagnostics.length === expectedErrors, `removing import is noop with respect to program, so no change in diagnostics.`);
|
||||
assert.lengthOf(program_7Diagnostics, expectedErrors, `removing import is noop with respect to program, so no change in diagnostics.`);
|
||||
|
||||
assert.deepEqual(program_7.host.getTrace(), [
|
||||
"======== Resolving type reference directive 'typerefs2', containing file 'f2.ts', root directory 'node_modules/@types'. ========",
|
||||
@@ -762,6 +770,98 @@ namespace ts {
|
||||
], "program_7 should reuse module resolutions in f2 since it is unchanged");
|
||||
}
|
||||
});
|
||||
|
||||
describe("redirects", () => {
|
||||
const axIndex = "/node_modules/a/node_modules/x/index.d.ts";
|
||||
const axPackage = "/node_modules/a/node_modules/x/package.json";
|
||||
const bxIndex = "/node_modules/b/node_modules/x/index.d.ts";
|
||||
const bxPackage = "/node_modules/b/node_modules/x/package.json";
|
||||
const root = "/a.ts";
|
||||
const compilerOptions = { target, moduleResolution: ModuleResolutionKind.NodeJs };
|
||||
|
||||
function createRedirectProgram(options?: { bText: string, bVersion: string }): ProgramWithSourceTexts {
|
||||
const files: NamedSourceText[] = [
|
||||
{
|
||||
name: "/node_modules/a/index.d.ts",
|
||||
text: SourceText.New("", 'import X from "x";', "export function a(x: X): void;"),
|
||||
},
|
||||
{
|
||||
name: axIndex,
|
||||
text: SourceText.New("", "", "export default class X { private x: number; }"),
|
||||
},
|
||||
{
|
||||
name: axPackage,
|
||||
text: SourceText.New("", "", JSON.stringify({ name: "x", version: "1.2.3" })),
|
||||
},
|
||||
{
|
||||
name: "/node_modules/b/index.d.ts",
|
||||
text: SourceText.New("", 'import X from "x";', "export const b: X;"),
|
||||
},
|
||||
{
|
||||
name: bxIndex,
|
||||
text: SourceText.New("", "", options ? options.bText : "export default class X { private x: number; }"),
|
||||
},
|
||||
{
|
||||
name: bxPackage,
|
||||
text: SourceText.New("", "", JSON.stringify({ name: "x", version: options ? options.bVersion : "1.2.3" })),
|
||||
},
|
||||
{
|
||||
name: root,
|
||||
text: SourceText.New("", 'import { a } from "a"; import { b } from "b";', "a(b)"),
|
||||
},
|
||||
];
|
||||
|
||||
return newProgram(files, [root], compilerOptions);
|
||||
}
|
||||
|
||||
function updateRedirectProgram(program: ProgramWithSourceTexts, updater: (files: NamedSourceText[]) => void): ProgramWithSourceTexts {
|
||||
return updateProgram(program, [root], compilerOptions, updater);
|
||||
}
|
||||
|
||||
it("No changes -> redirect not broken", () => {
|
||||
const program_1 = createRedirectProgram();
|
||||
|
||||
const program_2 = updateRedirectProgram(program_1, files => {
|
||||
updateProgramText(files, root, "const x = 1;");
|
||||
});
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Completely);
|
||||
assert.deepEqual(program_2.getSemanticDiagnostics(), emptyArray);
|
||||
});
|
||||
|
||||
it("Target changes -> redirect broken", () => {
|
||||
const program_1 = createRedirectProgram();
|
||||
assert.deepEqual(program_1.getSemanticDiagnostics(), emptyArray);
|
||||
|
||||
const program_2 = updateRedirectProgram(program_1, files => {
|
||||
updateProgramText(files, axIndex, "export default class X { private x: number; private y: number; }");
|
||||
updateProgramText(files, axPackage, JSON.stringify('{ name: "x", version: "1.2.4" }'));
|
||||
});
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Not);
|
||||
assert.lengthOf(program_2.getSemanticDiagnostics(), 1);
|
||||
});
|
||||
|
||||
it("Underlying changes -> redirect broken", () => {
|
||||
const program_1 = createRedirectProgram();
|
||||
|
||||
const program_2 = updateRedirectProgram(program_1, files => {
|
||||
updateProgramText(files, bxIndex, "export default class X { private x: number; private y: number; }");
|
||||
updateProgramText(files, bxPackage, JSON.stringify({ name: "x", version: "1.2.4" }));
|
||||
});
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Not);
|
||||
assert.lengthOf(program_2.getSemanticDiagnostics(), 1);
|
||||
});
|
||||
|
||||
it("Previously duplicate packages -> program structure not reused", () => {
|
||||
const program_1 = createRedirectProgram({ bVersion: "1.2.4", bText: "export = class X { private x: number; }" });
|
||||
|
||||
const program_2 = updateRedirectProgram(program_1, files => {
|
||||
updateProgramText(files, bxIndex, "export default class X { private x: number; }");
|
||||
updateProgramText(files, bxPackage, JSON.stringify({ name: "x", version: "1.2.3" }));
|
||||
});
|
||||
assert.equal(program_1.structureIsReused, StructureIsReused.Not);
|
||||
assert.deepEqual(program_2.getSemanticDiagnostics(), []);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("host is optional", () => {
|
||||
|
||||
@@ -43,6 +43,7 @@ namespace ts.server {
|
||||
host: mockHost,
|
||||
cancellationToken: nullCancellationToken,
|
||||
useSingleInferredProject: false,
|
||||
useInferredProjectPerProjectRoot: false,
|
||||
typingsInstaller: undefined,
|
||||
byteLength: Utils.byteLength,
|
||||
hrtime: process.hrtime,
|
||||
@@ -81,14 +82,15 @@ namespace ts.server {
|
||||
|
||||
session.executeCommand(req);
|
||||
|
||||
expect(lastSent).to.deep.equal(<protocol.Response>{
|
||||
const expected: protocol.Response = {
|
||||
command: CommandNames.Unknown,
|
||||
type: "response",
|
||||
seq: 0,
|
||||
message: "Unrecognized JSON command: foobar",
|
||||
request_seq: 0,
|
||||
success: false
|
||||
});
|
||||
};
|
||||
expect(lastSent).to.deep.equal(expected);
|
||||
});
|
||||
it("should return a tuple containing the response and if a response is required on success", () => {
|
||||
const req: protocol.ConfigureRequest = {
|
||||
@@ -393,6 +395,7 @@ namespace ts.server {
|
||||
host: mockHost,
|
||||
cancellationToken: nullCancellationToken,
|
||||
useSingleInferredProject: false,
|
||||
useInferredProjectPerProjectRoot: false,
|
||||
typingsInstaller: undefined,
|
||||
byteLength: Utils.byteLength,
|
||||
hrtime: process.hrtime,
|
||||
@@ -460,6 +463,7 @@ namespace ts.server {
|
||||
host: mockHost,
|
||||
cancellationToken: nullCancellationToken,
|
||||
useSingleInferredProject: false,
|
||||
useInferredProjectPerProjectRoot: false,
|
||||
typingsInstaller: undefined,
|
||||
byteLength: Utils.byteLength,
|
||||
hrtime: process.hrtime,
|
||||
|
||||
@@ -185,23 +185,28 @@ namespace ts.projectSystem {
|
||||
}
|
||||
}
|
||||
|
||||
export function createSession(host: server.ServerHost, typingsInstaller?: server.ITypingsInstaller, projectServiceEventHandler?: server.ProjectServiceEventHandler, cancellationToken?: server.ServerCancellationToken, throttleWaitMilliseconds?: number) {
|
||||
if (typingsInstaller === undefined) {
|
||||
typingsInstaller = new TestTypingsInstaller("/a/data/", /*throttleLimit*/5, host);
|
||||
export function createSession(host: server.ServerHost, opts: Partial<server.SessionOptions> = {}) {
|
||||
if (opts.typingsInstaller === undefined) {
|
||||
opts.typingsInstaller = new TestTypingsInstaller("/a/data/", /*throttleLimit*/ 5, host);
|
||||
}
|
||||
const opts: server.SessionOptions = {
|
||||
|
||||
if (opts.eventHandler !== undefined) {
|
||||
opts.canUseEvents = true;
|
||||
}
|
||||
|
||||
const sessionOptions: server.SessionOptions = {
|
||||
host,
|
||||
cancellationToken: cancellationToken || server.nullCancellationToken,
|
||||
cancellationToken: server.nullCancellationToken,
|
||||
useSingleInferredProject: false,
|
||||
typingsInstaller,
|
||||
useInferredProjectPerProjectRoot: false,
|
||||
typingsInstaller: undefined,
|
||||
byteLength: Utils.byteLength,
|
||||
hrtime: process.hrtime,
|
||||
logger: nullLogger,
|
||||
canUseEvents: projectServiceEventHandler !== undefined,
|
||||
eventHandler: projectServiceEventHandler,
|
||||
throttleWaitMilliseconds
|
||||
canUseEvents: false
|
||||
};
|
||||
return new TestSession(opts);
|
||||
|
||||
return new TestSession({ ...sessionOptions, ...opts });
|
||||
}
|
||||
|
||||
interface CreateProjectServiceParameters {
|
||||
@@ -215,9 +220,16 @@ namespace ts.projectSystem {
|
||||
|
||||
export class TestProjectService extends server.ProjectService {
|
||||
constructor(host: server.ServerHost, logger: server.Logger, cancellationToken: HostCancellationToken, useSingleInferredProject: boolean,
|
||||
typingsInstaller: server.ITypingsInstaller, eventHandler: server.ProjectServiceEventHandler) {
|
||||
typingsInstaller: server.ITypingsInstaller, eventHandler: server.ProjectServiceEventHandler, opts: Partial<server.ProjectServiceOptions> = {}) {
|
||||
super({
|
||||
host, logger, cancellationToken, useSingleInferredProject, typingsInstaller, eventHandler
|
||||
host,
|
||||
logger,
|
||||
cancellationToken,
|
||||
useSingleInferredProject,
|
||||
useInferredProjectPerProjectRoot: false,
|
||||
typingsInstaller,
|
||||
eventHandler,
|
||||
...opts
|
||||
});
|
||||
}
|
||||
|
||||
@@ -631,7 +643,7 @@ namespace ts.projectSystem {
|
||||
}
|
||||
}
|
||||
|
||||
describe("tsserver-project-system", () => {
|
||||
describe("tsserverProjectSystem", () => {
|
||||
const commonFile1: FileOrFolder = {
|
||||
path: "/a/b/commonFile1.ts",
|
||||
content: "let x = 1"
|
||||
@@ -2230,13 +2242,16 @@ namespace ts.projectSystem {
|
||||
filePath === f2.path ? server.maxProgramSizeForNonTsFiles + 1 : originalGetFileSize.call(host, filePath);
|
||||
|
||||
let lastEvent: server.ProjectLanguageServiceStateEvent;
|
||||
const session = createSession(host, /*typingsInstaller*/ undefined, e => {
|
||||
if (e.eventName === server.ConfigFileDiagEvent || e.eventName === server.ContextEvent || e.eventName === server.ProjectInfoTelemetryEvent) {
|
||||
return;
|
||||
const session = createSession(host, {
|
||||
canUseEvents: true,
|
||||
eventHandler: e => {
|
||||
if (e.eventName === server.ConfigFileDiagEvent || e.eventName === server.ContextEvent || e.eventName === server.ProjectInfoTelemetryEvent) {
|
||||
return;
|
||||
}
|
||||
assert.equal(e.eventName, server.ProjectLanguageServiceStateEvent);
|
||||
assert.equal(e.data.project.getProjectName(), config.path, "project name");
|
||||
lastEvent = <server.ProjectLanguageServiceStateEvent>e;
|
||||
}
|
||||
assert.equal(e.eventName, server.ProjectLanguageServiceStateEvent);
|
||||
assert.equal(e.data.project.getProjectName(), config.path, "project name");
|
||||
lastEvent = <server.ProjectLanguageServiceStateEvent>e;
|
||||
});
|
||||
session.executeCommand(<protocol.OpenRequest>{
|
||||
seq: 0,
|
||||
@@ -2280,12 +2295,15 @@ namespace ts.projectSystem {
|
||||
host.getFileSize = (filePath: string) =>
|
||||
filePath === f2.path ? server.maxProgramSizeForNonTsFiles + 1 : originalGetFileSize.call(host, filePath);
|
||||
let lastEvent: server.ProjectLanguageServiceStateEvent;
|
||||
const session = createSession(host, /*typingsInstaller*/ undefined, e => {
|
||||
if (e.eventName === server.ConfigFileDiagEvent || e.eventName === server.ProjectInfoTelemetryEvent) {
|
||||
return;
|
||||
const session = createSession(host, {
|
||||
canUseEvents: true,
|
||||
eventHandler: e => {
|
||||
if (e.eventName === server.ConfigFileDiagEvent || e.eventName === server.ProjectInfoTelemetryEvent) {
|
||||
return;
|
||||
}
|
||||
assert.equal(e.eventName, server.ProjectLanguageServiceStateEvent);
|
||||
lastEvent = <server.ProjectLanguageServiceStateEvent>e;
|
||||
}
|
||||
assert.equal(e.eventName, server.ProjectLanguageServiceStateEvent);
|
||||
lastEvent = <server.ProjectLanguageServiceStateEvent>e;
|
||||
});
|
||||
session.executeCommand(<protocol.OpenRequest>{
|
||||
seq: 0,
|
||||
@@ -3069,7 +3087,10 @@ namespace ts.projectSystem {
|
||||
};
|
||||
|
||||
const host = createServerHost([file, configFile]);
|
||||
const session = createSession(host, /*typingsInstaller*/ undefined, serverEventManager.handler);
|
||||
const session = createSession(host, {
|
||||
canUseEvents: true,
|
||||
eventHandler: serverEventManager.handler
|
||||
});
|
||||
openFilesForSession([file], session);
|
||||
serverEventManager.checkEventCountOfType("configFileDiag", 1);
|
||||
|
||||
@@ -3096,7 +3117,10 @@ namespace ts.projectSystem {
|
||||
};
|
||||
|
||||
const host = createServerHost([file, configFile]);
|
||||
const session = createSession(host, /*typingsInstaller*/ undefined, serverEventManager.handler);
|
||||
const session = createSession(host, {
|
||||
canUseEvents: true,
|
||||
eventHandler: serverEventManager.handler
|
||||
});
|
||||
openFilesForSession([file], session);
|
||||
serverEventManager.checkEventCountOfType("configFileDiag", 1);
|
||||
});
|
||||
@@ -3115,7 +3139,10 @@ namespace ts.projectSystem {
|
||||
};
|
||||
|
||||
const host = createServerHost([file, configFile]);
|
||||
const session = createSession(host, /*typingsInstaller*/ undefined, serverEventManager.handler);
|
||||
const session = createSession(host, {
|
||||
canUseEvents: true,
|
||||
eventHandler: serverEventManager.handler
|
||||
});
|
||||
openFilesForSession([file], session);
|
||||
serverEventManager.checkEventCountOfType("configFileDiag", 1);
|
||||
|
||||
@@ -3504,6 +3531,93 @@ namespace ts.projectSystem {
|
||||
checkNumberOfProjects(projectService, { inferredProjects: 1 });
|
||||
checkProjectActualFiles(projectService.inferredProjects[0], [f.path]);
|
||||
});
|
||||
|
||||
it("inferred projects per project root", () => {
|
||||
const file1 = { path: "/a/file1.ts", content: "let x = 1;", projectRootPath: "/a" };
|
||||
const file2 = { path: "/a/file2.ts", content: "let y = 2;", projectRootPath: "/a" };
|
||||
const file3 = { path: "/b/file2.ts", content: "let x = 3;", projectRootPath: "/b" };
|
||||
const file4 = { path: "/c/file3.ts", content: "let z = 4;" };
|
||||
const host = createServerHost([file1, file2, file3, file4]);
|
||||
const session = createSession(host, {
|
||||
useSingleInferredProject: true,
|
||||
useInferredProjectPerProjectRoot: true
|
||||
});
|
||||
session.executeCommand(<server.protocol.SetCompilerOptionsForInferredProjectsRequest>{
|
||||
seq: 1,
|
||||
type: "request",
|
||||
command: CommandNames.CompilerOptionsForInferredProjects,
|
||||
arguments: {
|
||||
options: {
|
||||
allowJs: true,
|
||||
target: ScriptTarget.ESNext
|
||||
}
|
||||
}
|
||||
});
|
||||
session.executeCommand(<server.protocol.SetCompilerOptionsForInferredProjectsRequest>{
|
||||
seq: 2,
|
||||
type: "request",
|
||||
command: CommandNames.CompilerOptionsForInferredProjects,
|
||||
arguments: {
|
||||
options: {
|
||||
allowJs: true,
|
||||
target: ScriptTarget.ES2015
|
||||
},
|
||||
projectRootPath: "/b"
|
||||
}
|
||||
});
|
||||
session.executeCommand(<server.protocol.OpenRequest>{
|
||||
seq: 3,
|
||||
type: "request",
|
||||
command: CommandNames.Open,
|
||||
arguments: {
|
||||
file: file1.path,
|
||||
fileContent: file1.content,
|
||||
scriptKindName: "JS",
|
||||
projectRootPath: file1.projectRootPath
|
||||
}
|
||||
});
|
||||
session.executeCommand(<server.protocol.OpenRequest>{
|
||||
seq: 4,
|
||||
type: "request",
|
||||
command: CommandNames.Open,
|
||||
arguments: {
|
||||
file: file2.path,
|
||||
fileContent: file2.content,
|
||||
scriptKindName: "JS",
|
||||
projectRootPath: file2.projectRootPath
|
||||
}
|
||||
});
|
||||
session.executeCommand(<server.protocol.OpenRequest>{
|
||||
seq: 5,
|
||||
type: "request",
|
||||
command: CommandNames.Open,
|
||||
arguments: {
|
||||
file: file3.path,
|
||||
fileContent: file3.content,
|
||||
scriptKindName: "JS",
|
||||
projectRootPath: file3.projectRootPath
|
||||
}
|
||||
});
|
||||
session.executeCommand(<server.protocol.OpenRequest>{
|
||||
seq: 6,
|
||||
type: "request",
|
||||
command: CommandNames.Open,
|
||||
arguments: {
|
||||
file: file4.path,
|
||||
fileContent: file4.content,
|
||||
scriptKindName: "JS"
|
||||
}
|
||||
});
|
||||
|
||||
const projectService = session.getProjectService();
|
||||
checkNumberOfProjects(projectService, { inferredProjects: 3 });
|
||||
checkProjectActualFiles(projectService.inferredProjects[0], [file4.path]);
|
||||
checkProjectActualFiles(projectService.inferredProjects[1], [file1.path, file2.path]);
|
||||
checkProjectActualFiles(projectService.inferredProjects[2], [file3.path]);
|
||||
assert.equal(projectService.inferredProjects[0].getCompilerOptions().target, ScriptTarget.ESNext);
|
||||
assert.equal(projectService.inferredProjects[1].getCompilerOptions().target, ScriptTarget.ESNext);
|
||||
assert.equal(projectService.inferredProjects[2].getCompilerOptions().target, ScriptTarget.ES2015);
|
||||
});
|
||||
});
|
||||
|
||||
describe("No overwrite emit error", () => {
|
||||
@@ -3697,7 +3811,7 @@ namespace ts.projectSystem {
|
||||
resetRequest: noop
|
||||
};
|
||||
|
||||
const session = createSession(host, /*typingsInstaller*/ undefined, /*projectServiceEventHandler*/ undefined, cancellationToken);
|
||||
const session = createSession(host, { cancellationToken });
|
||||
|
||||
expectedRequestId = session.getNextSeq();
|
||||
session.executeCommandSeq(<server.protocol.OpenRequest>{
|
||||
@@ -3737,7 +3851,11 @@ namespace ts.projectSystem {
|
||||
|
||||
const cancellationToken = new TestServerCancellationToken();
|
||||
const host = createServerHost([f1, config]);
|
||||
const session = createSession(host, /*typingsInstaller*/ undefined, () => { }, cancellationToken);
|
||||
const session = createSession(host, {
|
||||
canUseEvents: true,
|
||||
eventHandler: () => { },
|
||||
cancellationToken
|
||||
});
|
||||
{
|
||||
session.executeCommandSeq(<protocol.OpenRequest>{
|
||||
command: "open",
|
||||
@@ -3870,7 +3988,12 @@ namespace ts.projectSystem {
|
||||
};
|
||||
const cancellationToken = new TestServerCancellationToken(/*cancelAfterRequest*/ 3);
|
||||
const host = createServerHost([f1, config]);
|
||||
const session = createSession(host, /*typingsInstaller*/ undefined, () => { }, cancellationToken, /*throttleWaitMilliseconds*/ 0);
|
||||
const session = createSession(host, {
|
||||
canUseEvents: true,
|
||||
eventHandler: () => { },
|
||||
cancellationToken,
|
||||
throttleWaitMilliseconds: 0
|
||||
});
|
||||
{
|
||||
session.executeCommandSeq(<protocol.OpenRequest>{
|
||||
command: "open",
|
||||
|
||||
@@ -935,25 +935,26 @@ namespace ts.projectSystem {
|
||||
import * as cmd from "commander
|
||||
`
|
||||
};
|
||||
session.executeCommand(<server.protocol.OpenRequest>{
|
||||
const openRequest: server.protocol.OpenRequest = {
|
||||
seq: 1,
|
||||
type: "request",
|
||||
command: "open",
|
||||
command: server.protocol.CommandTypes.Open,
|
||||
arguments: {
|
||||
file: f.path,
|
||||
fileContent: f.content
|
||||
}
|
||||
});
|
||||
};
|
||||
session.executeCommand(openRequest);
|
||||
const projectService = session.getProjectService();
|
||||
checkNumberOfProjects(projectService, { inferredProjects: 1 });
|
||||
const proj = projectService.inferredProjects[0];
|
||||
const version1 = proj.getCachedUnresolvedImportsPerFile_TestOnly().getVersion();
|
||||
|
||||
// make a change that should not affect the structure of the program
|
||||
session.executeCommand(<server.protocol.ChangeRequest>{
|
||||
const changeRequest: server.protocol.ChangeRequest = {
|
||||
seq: 2,
|
||||
type: "request",
|
||||
command: "change",
|
||||
command: server.protocol.CommandTypes.Change,
|
||||
arguments: {
|
||||
file: f.path,
|
||||
insertString: "\nlet x = 1;",
|
||||
@@ -962,7 +963,8 @@ namespace ts.projectSystem {
|
||||
endLine: 2,
|
||||
endOffset: 0
|
||||
}
|
||||
});
|
||||
};
|
||||
session.executeCommand(changeRequest);
|
||||
host.checkTimeoutQueueLength(1);
|
||||
host.runQueuedTimeoutCallbacks();
|
||||
const version2 = proj.getCachedUnresolvedImportsPerFile_TestOnly().getVersion();
|
||||
|
||||
@@ -49,6 +49,12 @@ var q:Point=<Point>p;`;
|
||||
validateEditAtLineCharIndex = undefined;
|
||||
});
|
||||
|
||||
it("handles empty lines array", () => {
|
||||
const lineIndex = new server.LineIndex();
|
||||
lineIndex.load([]);
|
||||
assert.deepEqual(lineIndex.positionToLineOffset(0), { line: 1, offset: 1 });
|
||||
});
|
||||
|
||||
it(`change 9 1 0 1 {"y"}`, () => {
|
||||
validateEditAtLineCharIndex(9, 1, 0, "y");
|
||||
});
|
||||
|
||||
Vendored
+5
-5
@@ -216,7 +216,7 @@ interface ObjectConstructor {
|
||||
* Returns the names of the enumerable properties and methods of an object.
|
||||
* @param o Object that contains the properties and methods. This can be an object that you created or an existing Document Object Model (DOM) object.
|
||||
*/
|
||||
keys(o: any): string[];
|
||||
keys(o: {}): string[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -980,12 +980,12 @@ interface ReadonlyArray<T> {
|
||||
* Combines two or more arrays.
|
||||
* @param items Additional items to add to the end of array1.
|
||||
*/
|
||||
concat(...items: T[][]): T[];
|
||||
concat(...items: ReadonlyArray<T>[]): T[];
|
||||
/**
|
||||
* Combines two or more arrays.
|
||||
* @param items Additional items to add to the end of array1.
|
||||
*/
|
||||
concat(...items: (T | T[])[]): T[];
|
||||
concat(...items: (T | ReadonlyArray<T>)[]): T[];
|
||||
/**
|
||||
* Adds all the elements of an array separated by the specified separator string.
|
||||
* @param separator A string used to separate one element of an array from the next in the resulting String. If omitted, the array elements are separated with a comma.
|
||||
@@ -1099,12 +1099,12 @@ interface Array<T> {
|
||||
* Combines two or more arrays.
|
||||
* @param items Additional items to add to the end of array1.
|
||||
*/
|
||||
concat(...items: T[][]): T[];
|
||||
concat(...items: ReadonlyArray<T>[]): T[];
|
||||
/**
|
||||
* Combines two or more arrays.
|
||||
* @param items Additional items to add to the end of array1.
|
||||
*/
|
||||
concat(...items: (T | T[])[]): T[];
|
||||
concat(...items: (T | ReadonlyArray<T>)[]): T[];
|
||||
/**
|
||||
* Adds all the elements of an array separated by the specified separator string.
|
||||
* @param separator A string used to separate one element of an array from the next in the resulting String. If omitted, the array elements are separated with a comma.
|
||||
|
||||
+139
-48
@@ -22,7 +22,7 @@ namespace ts.server {
|
||||
|
||||
export interface ConfigFileDiagEvent {
|
||||
eventName: typeof ConfigFileDiagEvent;
|
||||
data: { triggerFile: string, configFileName: string, diagnostics: Diagnostic[] };
|
||||
data: { triggerFile: string, configFileName: string, diagnostics: ReadonlyArray<Diagnostic> };
|
||||
}
|
||||
|
||||
export interface ProjectLanguageServiceStateEvent {
|
||||
@@ -200,7 +200,7 @@ namespace ts.server {
|
||||
/**
|
||||
* This helper function processes a list of projects and return the concatenated, sortd and deduplicated output of processing each project.
|
||||
*/
|
||||
export function combineProjectOutput<T>(projects: Project[], action: (project: Project) => T[], comparer?: (a: T, b: T) => number, areEqual?: (a: T, b: T) => boolean) {
|
||||
export function combineProjectOutput<T>(projects: ReadonlyArray<Project>, action: (project: Project) => ReadonlyArray<T>, comparer?: (a: T, b: T) => number, areEqual?: (a: T, b: T) => boolean) {
|
||||
const result = flatMap(projects, action).sort(comparer);
|
||||
return projects.length > 1 ? deduplicate(result, areEqual) : result;
|
||||
}
|
||||
@@ -220,14 +220,14 @@ namespace ts.server {
|
||||
|
||||
interface OpenConfigFileResult {
|
||||
success: boolean;
|
||||
errors?: Diagnostic[];
|
||||
errors?: ReadonlyArray<Diagnostic>;
|
||||
|
||||
project?: ConfiguredProject;
|
||||
}
|
||||
|
||||
export interface OpenConfiguredProjectResult {
|
||||
configFileName?: NormalizedPath;
|
||||
configFileErrors?: Diagnostic[];
|
||||
configFileErrors?: ReadonlyArray<Diagnostic>;
|
||||
}
|
||||
|
||||
interface FilePropertyReader<T> {
|
||||
@@ -323,6 +323,7 @@ namespace ts.server {
|
||||
logger: Logger;
|
||||
cancellationToken: HostCancellationToken;
|
||||
useSingleInferredProject: boolean;
|
||||
useInferredProjectPerProjectRoot: boolean;
|
||||
typingsInstaller: ITypingsInstaller;
|
||||
eventHandler?: ProjectServiceEventHandler;
|
||||
throttleWaitMilliseconds?: number;
|
||||
@@ -364,7 +365,7 @@ namespace ts.server {
|
||||
readonly openFiles: ScriptInfo[] = [];
|
||||
|
||||
private compilerOptionsForInferredProjects: CompilerOptions;
|
||||
private compileOnSaveForInferredProjects: boolean;
|
||||
private compilerOptionsForInferredProjectsPerProjectRoot = createMap<CompilerOptions>();
|
||||
private readonly projectToSizeMap: Map<number> = createMap<number>();
|
||||
private readonly directoryWatchers: DirectoryWatchers;
|
||||
private readonly throttledOperations: ThrottledOperations;
|
||||
@@ -382,6 +383,7 @@ namespace ts.server {
|
||||
public readonly logger: Logger;
|
||||
public readonly cancellationToken: HostCancellationToken;
|
||||
public readonly useSingleInferredProject: boolean;
|
||||
public readonly useInferredProjectPerProjectRoot: boolean;
|
||||
public readonly typingsInstaller: ITypingsInstaller;
|
||||
public readonly throttleWaitMilliseconds?: number;
|
||||
private readonly eventHandler?: ProjectServiceEventHandler;
|
||||
@@ -398,6 +400,7 @@ namespace ts.server {
|
||||
this.logger = opts.logger;
|
||||
this.cancellationToken = opts.cancellationToken;
|
||||
this.useSingleInferredProject = opts.useSingleInferredProject;
|
||||
this.useInferredProjectPerProjectRoot = opts.useInferredProjectPerProjectRoot;
|
||||
this.typingsInstaller = opts.typingsInstaller || nullTypingsInstaller;
|
||||
this.throttleWaitMilliseconds = opts.throttleWaitMilliseconds;
|
||||
this.eventHandler = opts.eventHandler;
|
||||
@@ -441,10 +444,11 @@ namespace ts.server {
|
||||
if (!this.eventHandler) {
|
||||
return;
|
||||
}
|
||||
this.eventHandler(<ProjectLanguageServiceStateEvent>{
|
||||
const event: ProjectLanguageServiceStateEvent = {
|
||||
eventName: ProjectLanguageServiceStateEvent,
|
||||
data: { project, languageServiceEnabled }
|
||||
});
|
||||
};
|
||||
this.eventHandler(event);
|
||||
}
|
||||
|
||||
updateTypingsForProject(response: SetTypings | InvalidateCachedTypings): void {
|
||||
@@ -463,17 +467,42 @@ namespace ts.server {
|
||||
project.updateGraph();
|
||||
}
|
||||
|
||||
setCompilerOptionsForInferredProjects(projectCompilerOptions: protocol.ExternalProjectCompilerOptions): void {
|
||||
this.compilerOptionsForInferredProjects = convertCompilerOptions(projectCompilerOptions);
|
||||
setCompilerOptionsForInferredProjects(projectCompilerOptions: protocol.ExternalProjectCompilerOptions, projectRootPath?: string): void {
|
||||
Debug.assert(projectRootPath === undefined || this.useInferredProjectPerProjectRoot, "Setting compiler options per project root path is only supported when useInferredProjectPerProjectRoot is enabled");
|
||||
|
||||
const compilerOptions = convertCompilerOptions(projectCompilerOptions);
|
||||
|
||||
// always set 'allowNonTsExtensions' for inferred projects since user cannot configure it from the outside
|
||||
// previously we did not expose a way for user to change these settings and this option was enabled by default
|
||||
this.compilerOptionsForInferredProjects.allowNonTsExtensions = true;
|
||||
this.compileOnSaveForInferredProjects = projectCompilerOptions.compileOnSave;
|
||||
for (const proj of this.inferredProjects) {
|
||||
proj.setCompilerOptions(this.compilerOptionsForInferredProjects);
|
||||
proj.compileOnSaveEnabled = projectCompilerOptions.compileOnSave;
|
||||
compilerOptions.allowNonTsExtensions = true;
|
||||
|
||||
if (projectRootPath) {
|
||||
this.compilerOptionsForInferredProjectsPerProjectRoot.set(projectRootPath, compilerOptions);
|
||||
}
|
||||
this.updateProjectGraphs(this.inferredProjects);
|
||||
else {
|
||||
this.compilerOptionsForInferredProjects = compilerOptions;
|
||||
}
|
||||
|
||||
const updatedProjects: Project[] = [];
|
||||
for (const project of this.inferredProjects) {
|
||||
// Only update compiler options in the following cases:
|
||||
// - Inferred projects without a projectRootPath, if the new options do not apply to
|
||||
// a workspace root
|
||||
// - Inferred projects with a projectRootPath, if the new options do not apply to a
|
||||
// workspace root and there is no more specific set of options for that project's
|
||||
// root path
|
||||
// - Inferred projects with a projectRootPath, if the new options apply to that
|
||||
// project root path.
|
||||
if (projectRootPath ?
|
||||
project.projectRootPath === projectRootPath :
|
||||
!project.projectRootPath || !this.compilerOptionsForInferredProjectsPerProjectRoot.has(project.projectRootPath)) {
|
||||
project.setCompilerOptions(compilerOptions);
|
||||
project.compileOnSaveEnabled = compilerOptions.compileOnSave;
|
||||
updatedProjects.push(project);
|
||||
}
|
||||
}
|
||||
|
||||
this.updateProjectGraphs(updatedProjects);
|
||||
}
|
||||
|
||||
stopWatchingDirectory(directory: string) {
|
||||
@@ -602,10 +631,11 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
for (const openFile of this.openFiles) {
|
||||
this.eventHandler(<ContextEvent>{
|
||||
const event: ContextEvent = {
|
||||
eventName: ContextEvent,
|
||||
data: { project: openFile.getDefaultProject(), fileName: openFile.fileName }
|
||||
});
|
||||
};
|
||||
this.eventHandler(event);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -713,7 +743,7 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
private assignScriptInfoToInferredProjectIfNecessary(info: ScriptInfo, addToListOfOpenFiles: boolean): void {
|
||||
private assignScriptInfoToInferredProjectIfNecessary(info: ScriptInfo, addToListOfOpenFiles: boolean, projectRootPath?: string): void {
|
||||
const externalProject = this.findContainingExternalProject(info.fileName);
|
||||
if (externalProject) {
|
||||
// file is already included in some external project - do nothing
|
||||
@@ -741,30 +771,30 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
if (info.containingProjects.length === 0) {
|
||||
// create new inferred project p with the newly opened file as root
|
||||
// or add root to existing inferred project if 'useOneInferredProject' is true
|
||||
const inferredProject = this.createInferredProjectWithRootFileIfNecessary(info);
|
||||
if (!this.useSingleInferredProject) {
|
||||
// if useOneInferredProject is not set then try to fixup ownership of open files
|
||||
// check 'defaultProject !== inferredProject' is necessary to handle cases
|
||||
// when creation inferred project for some file has added other open files into this project (i.e. as referenced files)
|
||||
// we definitely don't want to delete the project that was just created
|
||||
// get (or create) an inferred project using the newly opened file as a root.
|
||||
const inferredProject = this.createInferredProjectWithRootFileIfNecessary(info, projectRootPath);
|
||||
if (!this.useSingleInferredProject && !inferredProject.projectRootPath) {
|
||||
// if useSingleInferredProject is false and the inferred project is not associated
|
||||
// with a project root, then try to repair the ownership of open files.
|
||||
for (const f of this.openFiles) {
|
||||
if (f.containingProjects.length === 0 || !inferredProject.containsScriptInfo(f)) {
|
||||
// this is orphaned file that we have not processed yet - skip it
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const fContainingProject of f.containingProjects) {
|
||||
if (fContainingProject.projectKind === ProjectKind.Inferred &&
|
||||
fContainingProject.isRoot(f) &&
|
||||
fContainingProject !== inferredProject) {
|
||||
|
||||
for (const containingProject of f.containingProjects) {
|
||||
// We verify 'containingProject !== inferredProject' to handle cases
|
||||
// where the inferred project for some file has added other open files
|
||||
// into this project (i.e. as referenced files) as we don't want to
|
||||
// delete the project that was just created
|
||||
if (containingProject.projectKind === ProjectKind.Inferred &&
|
||||
containingProject !== inferredProject &&
|
||||
containingProject.isRoot(f)) {
|
||||
// open file used to be root in inferred project,
|
||||
// this inferred project is different from the one we've just created for current file
|
||||
// and new inferred project references this open file.
|
||||
// We should delete old inferred project and attach open file to the new one
|
||||
this.removeProject(fContainingProject);
|
||||
this.removeProject(containingProject);
|
||||
f.attachToProject(inferredProject);
|
||||
}
|
||||
}
|
||||
@@ -1100,18 +1130,19 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
private reportConfigFileDiagnostics(configFileName: string, diagnostics: Diagnostic[], triggerFile: string) {
|
||||
private reportConfigFileDiagnostics(configFileName: string, diagnostics: ReadonlyArray<Diagnostic>, triggerFile: string) {
|
||||
if (!this.eventHandler) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.eventHandler(<ConfigFileDiagEvent>{
|
||||
const event: ConfigFileDiagEvent = {
|
||||
eventName: ConfigFileDiagEvent,
|
||||
data: { configFileName, diagnostics: diagnostics || [], triggerFile }
|
||||
});
|
||||
data: { configFileName, diagnostics: diagnostics || emptyArray, triggerFile }
|
||||
};
|
||||
this.eventHandler(event);
|
||||
}
|
||||
|
||||
private createAndAddConfiguredProject(configFileName: NormalizedPath, projectOptions: ProjectOptions, configFileErrors: Diagnostic[], clientFileName?: string) {
|
||||
private createAndAddConfiguredProject(configFileName: NormalizedPath, projectOptions: ProjectOptions, configFileErrors: ReadonlyArray<Diagnostic>, clientFileName?: string) {
|
||||
const sizeLimitExceeded = this.exceededTotalSizeLimitForNonTsFiles(configFileName, projectOptions.compilerOptions, projectOptions.files, fileNamePropertyReader);
|
||||
const project = new ConfiguredProject(
|
||||
configFileName,
|
||||
@@ -1143,7 +1174,7 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
private addFilesToProjectAndUpdateGraph<T>(project: ConfiguredProject | ExternalProject, files: T[], propertyReader: FilePropertyReader<T>, clientFileName: string, typeAcquisition: TypeAcquisition, configFileErrors: Diagnostic[]): void {
|
||||
private addFilesToProjectAndUpdateGraph<T>(project: ConfiguredProject | ExternalProject, files: T[], propertyReader: FilePropertyReader<T>, clientFileName: string, typeAcquisition: TypeAcquisition, configFileErrors: ReadonlyArray<Diagnostic>): void {
|
||||
let errors: Diagnostic[];
|
||||
for (const f of files) {
|
||||
const rootFilename = propertyReader.getFileName(f);
|
||||
@@ -1283,11 +1314,74 @@ namespace ts.server {
|
||||
return configFileErrors;
|
||||
}
|
||||
|
||||
createInferredProjectWithRootFileIfNecessary(root: ScriptInfo) {
|
||||
const useExistingProject = this.useSingleInferredProject && this.inferredProjects.length;
|
||||
const project = useExistingProject
|
||||
? this.inferredProjects[0]
|
||||
: new InferredProject(this, this.documentRegistry, this.compilerOptionsForInferredProjects);
|
||||
private getOrCreateInferredProjectForProjectRootPathIfEnabled(root: ScriptInfo, projectRootPath: string | undefined): InferredProject | undefined {
|
||||
if (!this.useInferredProjectPerProjectRoot) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (projectRootPath) {
|
||||
// if we have an explicit project root path, find (or create) the matching inferred project.
|
||||
for (const project of this.inferredProjects) {
|
||||
if (project.projectRootPath === projectRootPath) {
|
||||
return project;
|
||||
}
|
||||
}
|
||||
return this.createInferredProject(/*isSingleInferredProject*/ false, projectRootPath);
|
||||
}
|
||||
|
||||
// we don't have an explicit root path, so we should try to find an inferred project
|
||||
// that more closely contains the file.
|
||||
let bestMatch: InferredProject;
|
||||
for (const project of this.inferredProjects) {
|
||||
// ignore single inferred projects (handled elsewhere)
|
||||
if (!project.projectRootPath) continue;
|
||||
// ignore inferred projects that don't contain the root's path
|
||||
if (!containsPath(project.projectRootPath, root.path, this.host.getCurrentDirectory(), !this.host.useCaseSensitiveFileNames)) continue;
|
||||
// ignore inferred projects that are higher up in the project root.
|
||||
// TODO(rbuckton): Should we add the file as a root to these as well?
|
||||
if (bestMatch && bestMatch.projectRootPath.length > project.projectRootPath.length) continue;
|
||||
bestMatch = project;
|
||||
}
|
||||
|
||||
return bestMatch;
|
||||
}
|
||||
|
||||
private getOrCreateSingleInferredProjectIfEnabled(): InferredProject | undefined {
|
||||
if (!this.useSingleInferredProject) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// If `useInferredProjectPerProjectRoot` is not enabled, then there will only be one
|
||||
// inferred project for all files. If `useInferredProjectPerProjectRoot` is enabled
|
||||
// then we want to put all files that are not opened with a `projectRootPath` into
|
||||
// the same inferred project.
|
||||
//
|
||||
// To avoid the cost of searching through the array and to optimize for the case where
|
||||
// `useInferredProjectPerProjectRoot` is not enabled, we will always put the inferred
|
||||
// project for non-rooted files at the front of the array.
|
||||
if (this.inferredProjects.length > 0 && this.inferredProjects[0].projectRootPath === undefined) {
|
||||
return this.inferredProjects[0];
|
||||
}
|
||||
|
||||
return this.createInferredProject(/*isSingleInferredProject*/ true);
|
||||
}
|
||||
|
||||
private createInferredProject(isSingleInferredProject?: boolean, projectRootPath?: string): InferredProject {
|
||||
const compilerOptions = projectRootPath && this.compilerOptionsForInferredProjectsPerProjectRoot.get(projectRootPath) || this.compilerOptionsForInferredProjects;
|
||||
const project = new InferredProject(this, this.documentRegistry, compilerOptions, projectRootPath);
|
||||
if (isSingleInferredProject) {
|
||||
this.inferredProjects.unshift(project);
|
||||
}
|
||||
else {
|
||||
this.inferredProjects.push(project);
|
||||
}
|
||||
return project;
|
||||
}
|
||||
|
||||
createInferredProjectWithRootFileIfNecessary(root: ScriptInfo, projectRootPath?: string) {
|
||||
const project = this.getOrCreateInferredProjectForProjectRootPathIfEnabled(root, projectRootPath) ||
|
||||
this.getOrCreateSingleInferredProjectIfEnabled() ||
|
||||
this.createInferredProject();
|
||||
|
||||
project.addRoot(root);
|
||||
|
||||
@@ -1298,9 +1392,6 @@ namespace ts.server {
|
||||
|
||||
project.updateGraph();
|
||||
|
||||
if (!useExistingProject) {
|
||||
this.inferredProjects.push(project);
|
||||
}
|
||||
return project;
|
||||
}
|
||||
|
||||
@@ -1456,7 +1547,7 @@ namespace ts.server {
|
||||
|
||||
openClientFileWithNormalizedPath(fileName: NormalizedPath, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, projectRootPath?: NormalizedPath): OpenConfiguredProjectResult {
|
||||
let configFileName: NormalizedPath;
|
||||
let configFileErrors: Diagnostic[];
|
||||
let configFileErrors: ReadonlyArray<Diagnostic>;
|
||||
|
||||
let project: ConfiguredProject | ExternalProject = this.findContainingExternalProject(fileName);
|
||||
if (!project) {
|
||||
@@ -1474,7 +1565,7 @@ namespace ts.server {
|
||||
|
||||
// at this point if file is the part of some configured/external project then this project should be created
|
||||
const info = this.getOrCreateScriptInfoForNormalizedPath(fileName, /*openedByClient*/ true, fileContent, scriptKind, hasMixedContent);
|
||||
this.assignScriptInfoToInferredProjectIfNecessary(info, /*addToListOfOpenFiles*/ true);
|
||||
this.assignScriptInfoToInferredProjectIfNecessary(info, /*addToListOfOpenFiles*/ true, projectRootPath);
|
||||
// Delete the orphan files here because there might be orphan script infos (which are not part of project)
|
||||
// when some file/s were closed which resulted in project removal.
|
||||
// It was then postponed to cleanup these script infos so that they can be reused if
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace ts.server {
|
||||
|
||||
/* @internal */
|
||||
export interface ProjectFilesWithTSDiagnostics extends protocol.ProjectFiles {
|
||||
projectErrors: Diagnostic[];
|
||||
projectErrors: ReadonlyArray<Diagnostic>;
|
||||
}
|
||||
|
||||
export class UnresolvedImportsMap {
|
||||
@@ -147,7 +147,7 @@ namespace ts.server {
|
||||
|
||||
private typingFiles: SortedReadonlyArray<string>;
|
||||
|
||||
protected projectErrors: Diagnostic[];
|
||||
protected projectErrors: ReadonlyArray<Diagnostic>;
|
||||
|
||||
public typesVersion = 0;
|
||||
|
||||
@@ -837,6 +837,7 @@ namespace ts.server {
|
||||
* the file and its imports/references are put into an InferredProject.
|
||||
*/
|
||||
export class InferredProject extends Project {
|
||||
public readonly projectRootPath: string | undefined;
|
||||
|
||||
private static readonly newName = (() => {
|
||||
let nextId = 1;
|
||||
@@ -876,7 +877,7 @@ namespace ts.server {
|
||||
// Used to keep track of what directories are watched for this project
|
||||
directoriesWatchedForTsconfig: string[] = [];
|
||||
|
||||
constructor(projectService: ProjectService, documentRegistry: DocumentRegistry, compilerOptions: CompilerOptions) {
|
||||
constructor(projectService: ProjectService, documentRegistry: DocumentRegistry, compilerOptions: CompilerOptions, projectRootPath?: string) {
|
||||
super(InferredProject.newName(),
|
||||
ProjectKind.Inferred,
|
||||
projectService,
|
||||
@@ -885,6 +886,7 @@ namespace ts.server {
|
||||
/*languageServiceEnabled*/ true,
|
||||
compilerOptions,
|
||||
/*compileOnSaveEnabled*/ false);
|
||||
this.projectRootPath = projectRootPath;
|
||||
}
|
||||
|
||||
addRoot(info: ScriptInfo) {
|
||||
@@ -1045,7 +1047,7 @@ namespace ts.server {
|
||||
return getDirectoryPath(this.getConfigFilePath());
|
||||
}
|
||||
|
||||
setProjectErrors(projectErrors: Diagnostic[]) {
|
||||
setProjectErrors(projectErrors: ReadonlyArray<Diagnostic>) {
|
||||
this.projectErrors = projectErrors;
|
||||
}
|
||||
|
||||
@@ -1189,7 +1191,7 @@ namespace ts.server {
|
||||
return this.typeAcquisition;
|
||||
}
|
||||
|
||||
setProjectErrors(projectErrors: Diagnostic[]) {
|
||||
setProjectErrors(projectErrors: ReadonlyArray<Diagnostic>) {
|
||||
this.projectErrors = projectErrors;
|
||||
}
|
||||
|
||||
|
||||
@@ -930,7 +930,7 @@ namespace ts.server.protocol {
|
||||
/**
|
||||
* An array of span groups (one per file) that refer to the item to be renamed.
|
||||
*/
|
||||
locs: SpanGroup[];
|
||||
locs: ReadonlyArray<SpanGroup>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1320,6 +1320,13 @@ namespace ts.server.protocol {
|
||||
* Compiler options to be used with inferred projects.
|
||||
*/
|
||||
options: ExternalProjectCompilerOptions;
|
||||
|
||||
/**
|
||||
* Specifies the project root path used to scope compiler options.
|
||||
* It is an error to provide this property if the server has not been started with
|
||||
* `useInferredProjectPerProjectRoot` enabled.
|
||||
*/
|
||||
projectRootPath?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2445,6 +2452,7 @@ namespace ts.server.protocol {
|
||||
paths?: MapLike<string[]>;
|
||||
plugins?: PluginImport[];
|
||||
preserveConstEnums?: boolean;
|
||||
preserveSymlinks?: boolean;
|
||||
project?: string;
|
||||
reactNamespace?: string;
|
||||
removeComments?: boolean;
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace ts.server {
|
||||
|
||||
public getVersion() {
|
||||
return this.svc
|
||||
? `SVC-${this.svcVersion}-${this.svc.getSnapshot().version}`
|
||||
? `SVC-${this.svcVersion}-${this.svc.getSnapshotVersion()}`
|
||||
: `Text-${this.textVersion}`;
|
||||
}
|
||||
|
||||
@@ -62,22 +62,19 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
public getLineInfo(line: number): AbsolutePositionAndLineText {
|
||||
return this.switchToScriptVersionCache().getSnapshot().index.lineNumberToInfo(line);
|
||||
return this.switchToScriptVersionCache().getLineInfo(line);
|
||||
}
|
||||
/**
|
||||
* @param line 0 based index
|
||||
*/
|
||||
lineToTextSpan(line: number) {
|
||||
lineToTextSpan(line: number): TextSpan {
|
||||
if (!this.svc) {
|
||||
const lineMap = this.getLineMap();
|
||||
const start = lineMap[line]; // -1 since line is 1-based
|
||||
const end = line + 1 < lineMap.length ? lineMap[line + 1] : this.text.length;
|
||||
return createTextSpanFromBounds(start, end);
|
||||
}
|
||||
const index = this.svc.getSnapshot().index;
|
||||
const { lineText, absolutePosition } = index.lineNumberToInfo(line + 1);
|
||||
const len = lineText !== undefined ? lineText.length : index.absolutePositionOfStartOfLine(line + 2) - absolutePosition;
|
||||
return createTextSpan(absolutePosition, len);
|
||||
return this.svc.lineToTextSpan(line);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,7 +87,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
// TODO: assert this offset is actually on the line
|
||||
return this.svc.getSnapshot().index.absolutePositionOfStartOfLine(line) + (offset - 1);
|
||||
return this.svc.lineOffsetToPosition(line, offset);
|
||||
}
|
||||
|
||||
positionToLineOffset(position: number): protocol.Location {
|
||||
@@ -98,7 +95,7 @@ namespace ts.server {
|
||||
const { line, character } = computeLineAndCharacterOfPosition(this.getLineMap(), position);
|
||||
return { line: line + 1, offset: character + 1 };
|
||||
}
|
||||
return this.svc.getSnapshot().index.positionToLineOffset(position);
|
||||
return this.svc.positionToLineOffset(position);
|
||||
}
|
||||
|
||||
private getFileText(tempFileName?: string) {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
namespace ts.server {
|
||||
const lineCollectionCapacity = 4;
|
||||
|
||||
export interface LineCollection {
|
||||
interface LineCollection {
|
||||
charCount(): number;
|
||||
lineCount(): number;
|
||||
isLeaf(): this is LineLeaf;
|
||||
@@ -17,7 +17,7 @@ namespace ts.server {
|
||||
lineText: string | undefined;
|
||||
}
|
||||
|
||||
export enum CharRangeSection {
|
||||
const enum CharRangeSection {
|
||||
PreStart,
|
||||
Start,
|
||||
Entire,
|
||||
@@ -26,7 +26,7 @@ namespace ts.server {
|
||||
PostEnd
|
||||
}
|
||||
|
||||
export interface ILineIndexWalker {
|
||||
interface ILineIndexWalker {
|
||||
goSubtree: boolean;
|
||||
done: boolean;
|
||||
leaf(relativeStart: number, relativeLength: number, lineCollection: LineLeaf): void;
|
||||
@@ -243,7 +243,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
// text change information
|
||||
export class TextChange {
|
||||
class TextChange {
|
||||
constructor(public pos: number, public deleteLen: number, public insertedText?: string) {
|
||||
}
|
||||
|
||||
@@ -285,17 +285,6 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
latest() {
|
||||
return this.versions[this.currentVersionToIndex()];
|
||||
}
|
||||
|
||||
latestVersion() {
|
||||
if (this.changes.length > 0) {
|
||||
this.getSnapshot();
|
||||
}
|
||||
return this.currentVersion;
|
||||
}
|
||||
|
||||
// reload whole script, leaving no change history behind reload
|
||||
reload(script: string) {
|
||||
this.currentVersion++;
|
||||
@@ -314,7 +303,9 @@ namespace ts.server {
|
||||
this.minVersion = this.currentVersion;
|
||||
}
|
||||
|
||||
getSnapshot() {
|
||||
getSnapshot(): IScriptSnapshot { return this._getSnapshot(); }
|
||||
|
||||
private _getSnapshot(): LineIndexSnapshot {
|
||||
let snap = this.versions[this.currentVersionToIndex()];
|
||||
if (this.changes.length > 0) {
|
||||
let snapIndex = snap.index;
|
||||
@@ -334,6 +325,29 @@ namespace ts.server {
|
||||
return snap;
|
||||
}
|
||||
|
||||
getSnapshotVersion(): number {
|
||||
return this._getSnapshot().version;
|
||||
}
|
||||
|
||||
getLineInfo(line: number): AbsolutePositionAndLineText {
|
||||
return this._getSnapshot().index.lineNumberToInfo(line);
|
||||
}
|
||||
|
||||
lineOffsetToPosition(line: number, column: number): number {
|
||||
return this._getSnapshot().index.absolutePositionOfStartOfLine(line) + (column - 1);
|
||||
}
|
||||
|
||||
positionToLineOffset(position: number): protocol.Location {
|
||||
return this._getSnapshot().index.positionToLineOffset(position);
|
||||
}
|
||||
|
||||
lineToTextSpan(line: number): TextSpan {
|
||||
const index = this._getSnapshot().index;
|
||||
const { lineText, absolutePosition } = index.lineNumberToInfo(line + 1);
|
||||
const len = lineText !== undefined ? lineText.length : index.absolutePositionOfStartOfLine(line + 2) - absolutePosition;
|
||||
return createTextSpan(absolutePosition, len);
|
||||
}
|
||||
|
||||
getTextChangesBetweenVersions(oldVersion: number, newVersion: number) {
|
||||
if (oldVersion < newVersion) {
|
||||
if (oldVersion >= this.minVersion) {
|
||||
@@ -365,7 +379,7 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
export class LineIndexSnapshot implements IScriptSnapshot {
|
||||
class LineIndexSnapshot implements IScriptSnapshot {
|
||||
constructor(readonly version: number, readonly cache: ScriptVersionCache, readonly index: LineIndex, readonly changesSincePreviousVersion: ReadonlyArray<TextChange> = emptyArray) {
|
||||
}
|
||||
|
||||
@@ -389,6 +403,7 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export class LineIndex {
|
||||
root: LineNode;
|
||||
// set this to true to check each edit for accuracy
|
||||
@@ -561,7 +576,7 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
export class LineNode implements LineCollection {
|
||||
class LineNode implements LineCollection {
|
||||
totalChars = 0;
|
||||
totalLines = 0;
|
||||
|
||||
@@ -660,45 +675,29 @@ namespace ts.server {
|
||||
// Input position is relative to the start of this node.
|
||||
// Output line number is absolute.
|
||||
charOffsetToLineInfo(lineNumberAccumulator: number, relativePosition: number): { oneBasedLine: number, zeroBasedColumn: number, lineText: string | undefined } {
|
||||
const childInfo = this.childFromCharOffset(lineNumberAccumulator, relativePosition);
|
||||
if (!childInfo.child) {
|
||||
return {
|
||||
oneBasedLine: lineNumberAccumulator,
|
||||
zeroBasedColumn: relativePosition,
|
||||
lineText: undefined,
|
||||
};
|
||||
if (this.children.length === 0) {
|
||||
// Root node might have no children if this is an empty document.
|
||||
return { oneBasedLine: lineNumberAccumulator, zeroBasedColumn: relativePosition, lineText: undefined };
|
||||
}
|
||||
else if (childInfo.childIndex < this.children.length) {
|
||||
if (childInfo.child.isLeaf()) {
|
||||
return {
|
||||
oneBasedLine: childInfo.lineNumberAccumulator,
|
||||
zeroBasedColumn: childInfo.relativePosition,
|
||||
lineText: childInfo.child.text,
|
||||
};
|
||||
|
||||
for (const child of this.children) {
|
||||
if (child.charCount() > relativePosition) {
|
||||
if (child.isLeaf()) {
|
||||
return { oneBasedLine: lineNumberAccumulator, zeroBasedColumn: relativePosition, lineText: child.text };
|
||||
}
|
||||
else {
|
||||
return (<LineNode>child).charOffsetToLineInfo(lineNumberAccumulator, relativePosition);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const lineNode = <LineNode>(childInfo.child);
|
||||
return lineNode.charOffsetToLineInfo(childInfo.lineNumberAccumulator, childInfo.relativePosition);
|
||||
relativePosition -= child.charCount();
|
||||
lineNumberAccumulator += child.lineCount();
|
||||
}
|
||||
}
|
||||
else {
|
||||
const lineInfo = this.lineNumberToInfo(this.lineCount(), 0);
|
||||
return { oneBasedLine: this.lineCount(), zeroBasedColumn: lineInfo.leaf.charCount(), lineText: undefined };
|
||||
}
|
||||
}
|
||||
|
||||
lineNumberToInfo(relativeOneBasedLine: number, positionAccumulator: number): { position: number, leaf: LineLeaf | undefined } {
|
||||
const childInfo = this.childFromLineNumber(relativeOneBasedLine, positionAccumulator);
|
||||
if (!childInfo.child) {
|
||||
return { position: positionAccumulator, leaf: undefined };
|
||||
}
|
||||
else if (childInfo.child.isLeaf()) {
|
||||
return { position: childInfo.positionAccumulator, leaf: childInfo.child };
|
||||
}
|
||||
else {
|
||||
const lineNode = <LineNode>(childInfo.child);
|
||||
return lineNode.lineNumberToInfo(childInfo.relativeOneBasedLine, childInfo.positionAccumulator);
|
||||
}
|
||||
// Skipped all children
|
||||
const { leaf } = this.lineNumberToInfo(this.lineCount(), 0);
|
||||
return { oneBasedLine: this.lineCount(), zeroBasedColumn: leaf.charCount(), lineText: undefined };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -706,39 +705,19 @@ namespace ts.server {
|
||||
* Output line number is relative to the child.
|
||||
* positionAccumulator will be an absolute position once relativeLineNumber reaches 0.
|
||||
*/
|
||||
private childFromLineNumber(relativeOneBasedLine: number, positionAccumulator: number): { child: LineCollection, relativeOneBasedLine: number, positionAccumulator: number } {
|
||||
let child: LineCollection;
|
||||
let i: number;
|
||||
for (i = 0; i < this.children.length; i++) {
|
||||
child = this.children[i];
|
||||
lineNumberToInfo(relativeOneBasedLine: number, positionAccumulator: number): { position: number, leaf: LineLeaf | undefined } {
|
||||
for (const child of this.children) {
|
||||
const childLineCount = child.lineCount();
|
||||
if (childLineCount >= relativeOneBasedLine) {
|
||||
break;
|
||||
return child.isLeaf() ? { position: positionAccumulator, leaf: child } : (<LineNode>child).lineNumberToInfo(relativeOneBasedLine, positionAccumulator);
|
||||
}
|
||||
else {
|
||||
relativeOneBasedLine -= childLineCount;
|
||||
positionAccumulator += child.charCount();
|
||||
}
|
||||
}
|
||||
return { child, relativeOneBasedLine, positionAccumulator };
|
||||
}
|
||||
|
||||
private childFromCharOffset(lineNumberAccumulator: number, relativePosition: number
|
||||
): { child: LineCollection, childIndex: number, relativePosition: number, lineNumberAccumulator: number } {
|
||||
let child: LineCollection;
|
||||
let i: number;
|
||||
let len: number;
|
||||
for (i = 0, len = this.children.length; i < len; i++) {
|
||||
child = this.children[i];
|
||||
if (child.charCount() > relativePosition) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
relativePosition -= child.charCount();
|
||||
lineNumberAccumulator += child.lineCount();
|
||||
}
|
||||
}
|
||||
return { child, childIndex: i, relativePosition, lineNumberAccumulator };
|
||||
return { position: positionAccumulator, leaf: undefined };
|
||||
}
|
||||
|
||||
private splitAfter(childIndex: number) {
|
||||
@@ -844,7 +823,7 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
export class LineLeaf implements LineCollection {
|
||||
class LineLeaf implements LineCollection {
|
||||
constructor(public text: string) {
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace ts.server {
|
||||
canUseEvents: boolean;
|
||||
installerEventPort: number;
|
||||
useSingleInferredProject: boolean;
|
||||
useInferredProjectPerProjectRoot: boolean;
|
||||
disableAutomaticTypingAcquisition: boolean;
|
||||
globalTypingsCacheLocation: string;
|
||||
logger: Logger;
|
||||
@@ -414,6 +415,7 @@ namespace ts.server {
|
||||
host,
|
||||
cancellationToken,
|
||||
useSingleInferredProject,
|
||||
useInferredProjectPerProjectRoot,
|
||||
typingsInstaller: typingsInstaller || nullTypingsInstaller,
|
||||
byteLength: Buffer.byteLength,
|
||||
hrtime: process.hrtime,
|
||||
@@ -779,6 +781,7 @@ namespace ts.server {
|
||||
const allowLocalPluginLoads = hasArgument("--allowLocalPluginLoads");
|
||||
|
||||
const useSingleInferredProject = hasArgument("--useSingleInferredProject");
|
||||
const useInferredProjectPerProjectRoot = hasArgument("--useInferredProjectPerProjectRoot");
|
||||
const disableAutomaticTypingAcquisition = hasArgument("--disableAutomaticTypingAcquisition");
|
||||
const telemetryEnabled = hasArgument(Arguments.EnableTelemetry);
|
||||
|
||||
@@ -788,6 +791,7 @@ namespace ts.server {
|
||||
installerEventPort: eventPort,
|
||||
canUseEvents: eventPort === undefined,
|
||||
useSingleInferredProject,
|
||||
useInferredProjectPerProjectRoot,
|
||||
disableAutomaticTypingAcquisition,
|
||||
globalTypingsCacheLocation: getGlobalTypingsCacheLocation(),
|
||||
typingSafeListLocation,
|
||||
|
||||
+39
-38
@@ -247,6 +247,7 @@ namespace ts.server {
|
||||
host: ServerHost;
|
||||
cancellationToken: ServerCancellationToken;
|
||||
useSingleInferredProject: boolean;
|
||||
useInferredProjectPerProjectRoot: boolean;
|
||||
typingsInstaller: ITypingsInstaller;
|
||||
byteLength: (buf: string, encoding?: string) => number;
|
||||
hrtime: (start?: number[]) => number[];
|
||||
@@ -307,6 +308,7 @@ namespace ts.server {
|
||||
logger: this.logger,
|
||||
cancellationToken: this.cancellationToken,
|
||||
useSingleInferredProject: opts.useSingleInferredProject,
|
||||
useInferredProjectPerProjectRoot: opts.useInferredProjectPerProjectRoot,
|
||||
typingsInstaller: this.typingsInstaller,
|
||||
throttleWaitMilliseconds,
|
||||
eventHandler: this.eventHandler,
|
||||
@@ -379,7 +381,7 @@ namespace ts.server {
|
||||
this.host.write(formatMessage(msg, this.logger, this.byteLength, this.host.newLine));
|
||||
}
|
||||
|
||||
public configFileDiagnosticEvent(triggerFile: string, configFile: string, diagnostics: Diagnostic[]) {
|
||||
public configFileDiagnosticEvent(triggerFile: string, configFile: string, diagnostics: ReadonlyArray<Diagnostic>) {
|
||||
const bakedDiags = map(diagnostics, diagnostic => formatConfigFileDiag(diagnostic, /*includeFileName*/ true));
|
||||
const ev: protocol.ConfigFileDiagnosticEvent = {
|
||||
seq: 0,
|
||||
@@ -539,8 +541,8 @@ namespace ts.server {
|
||||
);
|
||||
}
|
||||
|
||||
private convertToDiagnosticsWithLinePositionFromDiagnosticFile(diagnostics: Diagnostic[]) {
|
||||
return diagnostics.map(d => <protocol.DiagnosticWithLinePosition>{
|
||||
private convertToDiagnosticsWithLinePositionFromDiagnosticFile(diagnostics: ReadonlyArray<Diagnostic>): protocol.DiagnosticWithLinePosition[] {
|
||||
return diagnostics.map<protocol.DiagnosticWithLinePosition>(d => ({
|
||||
message: flattenDiagnosticMessageText(d.messageText, this.host.newLine),
|
||||
start: d.start,
|
||||
length: d.length,
|
||||
@@ -548,7 +550,7 @@ namespace ts.server {
|
||||
code: d.code,
|
||||
startLocation: d.file && convertToLocation(getLineAndCharacterOfPosition(d.file, d.start)),
|
||||
endLocation: d.file && convertToLocation(getLineAndCharacterOfPosition(d.file, d.start + d.length))
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
private getCompilerOptionsDiagnostics(args: protocol.CompilerOptionsDiagnosticsRequestArgs) {
|
||||
@@ -565,7 +567,7 @@ namespace ts.server {
|
||||
);
|
||||
}
|
||||
|
||||
private convertToDiagnosticsWithLinePosition(diagnostics: Diagnostic[], scriptInfo: ScriptInfo) {
|
||||
private convertToDiagnosticsWithLinePosition(diagnostics: ReadonlyArray<Diagnostic>, scriptInfo: ScriptInfo): protocol.DiagnosticWithLinePosition[] {
|
||||
return diagnostics.map(d => <protocol.DiagnosticWithLinePosition>{
|
||||
message: flattenDiagnosticMessageText(d.messageText, this.host.newLine),
|
||||
start: d.start,
|
||||
@@ -578,10 +580,12 @@ namespace ts.server {
|
||||
});
|
||||
}
|
||||
|
||||
private getDiagnosticsWorker(args: protocol.FileRequestArgs, isSemantic: boolean, selector: (project: Project, file: string) => Diagnostic[], includeLinePosition: boolean) {
|
||||
private getDiagnosticsWorker(
|
||||
args: protocol.FileRequestArgs, isSemantic: boolean, selector: (project: Project, file: string) => ReadonlyArray<Diagnostic>, includeLinePosition: boolean
|
||||
): ReadonlyArray<protocol.DiagnosticWithLinePosition> | ReadonlyArray<protocol.Diagnostic> {
|
||||
const { project, file } = this.getFileAndProject(args);
|
||||
if (isSemantic && isDeclarationFileInJSOnlyNonConfiguredProject(project, file)) {
|
||||
return [];
|
||||
return emptyArray;
|
||||
}
|
||||
const scriptInfo = project.getScriptInfoForNormalizedPath(file);
|
||||
const diagnostics = selector(project, file);
|
||||
@@ -590,14 +594,14 @@ namespace ts.server {
|
||||
: diagnostics.map(d => formatDiag(file, project, d));
|
||||
}
|
||||
|
||||
private getDefinition(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.FileSpan[] | DefinitionInfo[] {
|
||||
private getDefinition(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): ReadonlyArray<protocol.FileSpan> | ReadonlyArray<DefinitionInfo> {
|
||||
const { file, project } = this.getFileAndProject(args);
|
||||
const scriptInfo = project.getScriptInfoForNormalizedPath(file);
|
||||
const position = this.getPosition(args, scriptInfo);
|
||||
|
||||
const definitions = project.getLanguageService().getDefinitionAtPosition(file, position);
|
||||
if (!definitions) {
|
||||
return undefined;
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
if (simplifiedResult) {
|
||||
@@ -615,14 +619,14 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
private getTypeDefinition(args: protocol.FileLocationRequestArgs): protocol.FileSpan[] {
|
||||
private getTypeDefinition(args: protocol.FileLocationRequestArgs): ReadonlyArray<protocol.FileSpan> {
|
||||
const { file, project } = this.getFileAndProject(args);
|
||||
const scriptInfo = project.getScriptInfoForNormalizedPath(file);
|
||||
const position = this.getPosition(args, scriptInfo);
|
||||
|
||||
const definitions = project.getLanguageService().getTypeDefinitionAtPosition(file, position);
|
||||
if (!definitions) {
|
||||
return undefined;
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
return definitions.map(def => {
|
||||
@@ -635,12 +639,12 @@ namespace ts.server {
|
||||
});
|
||||
}
|
||||
|
||||
private getImplementation(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.FileSpan[] | ImplementationLocation[] {
|
||||
private getImplementation(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): ReadonlyArray<protocol.FileSpan> | ReadonlyArray<ImplementationLocation> {
|
||||
const { file, project } = this.getFileAndProject(args);
|
||||
const position = this.getPosition(args, project.getScriptInfoForNormalizedPath(file));
|
||||
const implementations = project.getLanguageService().getImplementationAtPosition(file, position);
|
||||
if (!implementations) {
|
||||
return [];
|
||||
return emptyArray;
|
||||
}
|
||||
if (simplifiedResult) {
|
||||
return implementations.map(({ fileName, textSpan }) => {
|
||||
@@ -657,7 +661,7 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
private getOccurrences(args: protocol.FileLocationRequestArgs): protocol.OccurrencesResponseItem[] {
|
||||
private getOccurrences(args: protocol.FileLocationRequestArgs): ReadonlyArray<protocol.OccurrencesResponseItem> {
|
||||
const { file, project } = this.getFileAndProject(args);
|
||||
const scriptInfo = project.getScriptInfoForNormalizedPath(file);
|
||||
const position = this.getPosition(args, scriptInfo);
|
||||
@@ -665,7 +669,7 @@ namespace ts.server {
|
||||
const occurrences = project.getLanguageService().getOccurrencesAtPosition(file, position);
|
||||
|
||||
if (!occurrences) {
|
||||
return undefined;
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
return occurrences.map(occurrence => {
|
||||
@@ -687,17 +691,17 @@ namespace ts.server {
|
||||
});
|
||||
}
|
||||
|
||||
private getSyntacticDiagnosticsSync(args: protocol.SyntacticDiagnosticsSyncRequestArgs): protocol.Diagnostic[] | protocol.DiagnosticWithLinePosition[] {
|
||||
private getSyntacticDiagnosticsSync(args: protocol.SyntacticDiagnosticsSyncRequestArgs): ReadonlyArray<protocol.Diagnostic> | ReadonlyArray<protocol.DiagnosticWithLinePosition> {
|
||||
const { configFile } = this.getConfigFileAndProject(args);
|
||||
if (configFile) {
|
||||
// all the config file errors are reported as part of semantic check so nothing to report here
|
||||
return [];
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
return this.getDiagnosticsWorker(args, /*isSemantic*/ false, (project, file) => project.getLanguageService().getSyntacticDiagnostics(file), args.includeLinePosition);
|
||||
}
|
||||
|
||||
private getSemanticDiagnosticsSync(args: protocol.SemanticDiagnosticsSyncRequestArgs): protocol.Diagnostic[] | protocol.DiagnosticWithLinePosition[] {
|
||||
private getSemanticDiagnosticsSync(args: protocol.SemanticDiagnosticsSyncRequestArgs): ReadonlyArray<protocol.Diagnostic> | ReadonlyArray<protocol.DiagnosticWithLinePosition> {
|
||||
const { configFile, project } = this.getConfigFileAndProject(args);
|
||||
if (configFile) {
|
||||
return this.getConfigFileDiagnostics(configFile, project, args.includeLinePosition);
|
||||
@@ -705,14 +709,14 @@ namespace ts.server {
|
||||
return this.getDiagnosticsWorker(args, /*isSemantic*/ true, (project, file) => project.getLanguageService().getSemanticDiagnostics(file), args.includeLinePosition);
|
||||
}
|
||||
|
||||
private getDocumentHighlights(args: protocol.DocumentHighlightsRequestArgs, simplifiedResult: boolean): protocol.DocumentHighlightsItem[] | DocumentHighlights[] {
|
||||
private getDocumentHighlights(args: protocol.DocumentHighlightsRequestArgs, simplifiedResult: boolean): ReadonlyArray<protocol.DocumentHighlightsItem> | ReadonlyArray<DocumentHighlights> {
|
||||
const { file, project } = this.getFileAndProject(args);
|
||||
const scriptInfo = project.getScriptInfoForNormalizedPath(file);
|
||||
const position = this.getPosition(args, scriptInfo);
|
||||
const documentHighlights = project.getLanguageService().getDocumentHighlights(file, position, args.filesToSearch);
|
||||
|
||||
if (!documentHighlights) {
|
||||
return undefined;
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
if (simplifiedResult) {
|
||||
@@ -741,7 +745,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
private setCompilerOptionsForInferredProjects(args: protocol.SetCompilerOptionsForInferredProjectsArgs): void {
|
||||
this.projectService.setCompilerOptionsForInferredProjects(args.options);
|
||||
this.projectService.setCompilerOptionsForInferredProjects(args.options, args.projectRootPath);
|
||||
}
|
||||
|
||||
private getProjectInfo(args: protocol.ProjectInfoRequestArgs): protocol.ProjectInfo {
|
||||
@@ -796,7 +800,7 @@ namespace ts.server {
|
||||
return info.getDefaultProject();
|
||||
}
|
||||
|
||||
private getRenameLocations(args: protocol.RenameRequestArgs, simplifiedResult: boolean): protocol.RenameResponseBody | RenameLocation[] {
|
||||
private getRenameLocations(args: protocol.RenameRequestArgs, simplifiedResult: boolean): protocol.RenameResponseBody | ReadonlyArray<RenameLocation> {
|
||||
const file = toNormalizedPath(args.file);
|
||||
const info = this.projectService.getScriptInfoForNormalizedPath(file);
|
||||
const position = this.getPosition(args, info);
|
||||
@@ -813,7 +817,7 @@ namespace ts.server {
|
||||
if (!renameInfo.canRename) {
|
||||
return {
|
||||
info: renameInfo,
|
||||
locs: []
|
||||
locs: emptyArray
|
||||
};
|
||||
}
|
||||
|
||||
@@ -822,12 +826,12 @@ namespace ts.server {
|
||||
(project: Project) => {
|
||||
const renameLocations = project.getLanguageService().findRenameLocations(file, position, args.findInStrings, args.findInComments);
|
||||
if (!renameLocations) {
|
||||
return [];
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
return renameLocations.map(location => {
|
||||
const locationScriptInfo = project.getScriptInfo(location.fileName);
|
||||
return <protocol.FileSpan>{
|
||||
return {
|
||||
file: location.fileName,
|
||||
start: locationScriptInfo.positionToLineOffset(location.textSpan.start),
|
||||
end: locationScriptInfo.positionToLineOffset(textSpanEnd(location.textSpan)),
|
||||
@@ -899,7 +903,7 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
private getReferences(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.ReferencesResponseBody | ReferencedSymbol[] {
|
||||
private getReferences(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.ReferencesResponseBody | undefined | ReadonlyArray<ReferencedSymbol> {
|
||||
const file = toNormalizedPath(args.file);
|
||||
const projects = this.getProjects(args);
|
||||
|
||||
@@ -921,7 +925,7 @@ namespace ts.server {
|
||||
(project: Project) => {
|
||||
const references = project.getLanguageService().getReferencesAtPosition(file, position);
|
||||
if (!references) {
|
||||
return [];
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
return references.map(ref => {
|
||||
@@ -978,7 +982,7 @@ namespace ts.server {
|
||||
if (this.eventHandler) {
|
||||
this.eventHandler({
|
||||
eventName: "configFileDiag",
|
||||
data: { triggerFile: fileName, configFileName, diagnostics: configFileErrors || [] }
|
||||
data: { triggerFile: fileName, configFileName, diagnostics: configFileErrors || emptyArray }
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1171,7 +1175,7 @@ namespace ts.server {
|
||||
});
|
||||
}
|
||||
|
||||
private getCompletions(args: protocol.CompletionsRequestArgs, simplifiedResult: boolean): protocol.CompletionEntry[] | CompletionInfo {
|
||||
private getCompletions(args: protocol.CompletionsRequestArgs, simplifiedResult: boolean): ReadonlyArray<protocol.CompletionEntry> | CompletionInfo | undefined {
|
||||
const prefix = args.prefix || "";
|
||||
const { file, project } = this.getFileAndProject(args);
|
||||
|
||||
@@ -1179,11 +1183,8 @@ namespace ts.server {
|
||||
const position = this.getPosition(args, scriptInfo);
|
||||
|
||||
const completions = project.getLanguageService().getCompletionsAtPosition(file, position);
|
||||
if (!completions) {
|
||||
return undefined;
|
||||
}
|
||||
if (simplifiedResult) {
|
||||
return mapDefined(completions.entries, entry => {
|
||||
return mapDefined(completions && completions.entries, entry => {
|
||||
if (completions.isMemberCompletion || (entry.name.toLowerCase().indexOf(prefix.toLowerCase()) === 0)) {
|
||||
const { name, kind, kindModifiers, sortText, replacementSpan } = entry;
|
||||
const convertedSpan = replacementSpan ? this.decorateSpan(replacementSpan, scriptInfo) : undefined;
|
||||
@@ -1196,7 +1197,7 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
private getCompletionEntryDetails(args: protocol.CompletionDetailsRequestArgs): protocol.CompletionEntryDetails[] {
|
||||
private getCompletionEntryDetails(args: protocol.CompletionDetailsRequestArgs): ReadonlyArray<protocol.CompletionEntryDetails> {
|
||||
const { file, project } = this.getFileAndProject(args);
|
||||
const scriptInfo = project.getScriptInfoForNormalizedPath(file);
|
||||
const position = this.getPosition(args, scriptInfo);
|
||||
@@ -1205,12 +1206,12 @@ namespace ts.server {
|
||||
project.getLanguageService().getCompletionEntryDetails(file, position, entryName));
|
||||
}
|
||||
|
||||
private getCompileOnSaveAffectedFileList(args: protocol.FileRequestArgs): protocol.CompileOnSaveAffectedFileListSingleProject[] {
|
||||
private getCompileOnSaveAffectedFileList(args: protocol.FileRequestArgs): ReadonlyArray<protocol.CompileOnSaveAffectedFileListSingleProject> {
|
||||
const info = this.projectService.getScriptInfo(args.file);
|
||||
const result: protocol.CompileOnSaveAffectedFileListSingleProject[] = [];
|
||||
|
||||
if (!info) {
|
||||
return [];
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
// if specified a project, we only return affected file list in this project
|
||||
@@ -1368,7 +1369,7 @@ namespace ts.server {
|
||||
: tree;
|
||||
}
|
||||
|
||||
private getNavigateToItems(args: protocol.NavtoRequestArgs, simplifiedResult: boolean): protocol.NavtoItem[] | NavigateToItem[] {
|
||||
private getNavigateToItems(args: protocol.NavtoRequestArgs, simplifiedResult: boolean): ReadonlyArray<protocol.NavtoItem> | ReadonlyArray<NavigateToItem> {
|
||||
const projects = this.getProjects(args);
|
||||
|
||||
const fileName = args.currentFileOnly ? args.file && normalizeSlashes(args.file) : undefined;
|
||||
@@ -1378,7 +1379,7 @@ namespace ts.server {
|
||||
project => {
|
||||
const navItems = project.getLanguageService().getNavigateToItems(args.searchValue, args.maxResultCount, fileName, /*excludeDts*/ project.isNonTsProject());
|
||||
if (!navItems) {
|
||||
return [];
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
return navItems.map((navItem) => {
|
||||
|
||||
@@ -356,14 +356,15 @@ namespace ts.server.typingsInstaller {
|
||||
this.sendResponse(this.createSetTypings(req, currentlyCachedTypings.concat(installedTypingFiles)));
|
||||
}
|
||||
finally {
|
||||
this.sendResponse(<EndInstallTypes>{
|
||||
const response: EndInstallTypes = {
|
||||
kind: EventEndInstallTypes,
|
||||
eventId: requestId,
|
||||
projectName: req.projectName,
|
||||
packagesToInstall: scopedTypings,
|
||||
installSuccess: ok,
|
||||
typingsInstallerVersion: ts.version // qualified explicitly to prevent occasional shadowing
|
||||
});
|
||||
};
|
||||
this.sendResponse(response);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ namespace ts.codefix {
|
||||
}
|
||||
else if (isJsxOpeningLikeElement(token.parent) && token.parent.tagName === token) {
|
||||
// The error wasn't for the symbolAtLocation, it was for the JSX tag itself, which needs access to e.g. `React`.
|
||||
symbol = checker.getAliasedSymbol(checker.resolveNameAtLocation(token, checker.getJsxNamespace(), SymbolFlags.Value));
|
||||
symbol = checker.getAliasedSymbol(checker.resolveName(checker.getJsxNamespace(), token.parent.tagName, SymbolFlags.Value));
|
||||
symbolName = symbol.name;
|
||||
}
|
||||
else {
|
||||
@@ -394,9 +394,11 @@ namespace ts.codefix {
|
||||
: isNamespaceImport
|
||||
? createImportClause(/*name*/ undefined, createNamespaceImport(createIdentifier(symbolName)))
|
||||
: createImportClause(/*name*/ undefined, createNamedImports([createImportSpecifier(/*propertyName*/ undefined, createIdentifier(symbolName))]));
|
||||
const importDecl = createImportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, importClause, createLiteral(moduleSpecifierWithoutQuotes));
|
||||
const moduleSpecifierLiteral = createLiteral(moduleSpecifierWithoutQuotes);
|
||||
moduleSpecifierLiteral.singleQuote = getSingleQuoteStyleFromExistingImports();
|
||||
const importDecl = createImportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, importClause, moduleSpecifierLiteral);
|
||||
if (!lastImportDeclaration) {
|
||||
changeTracker.insertNodeAt(sourceFile, sourceFile.getStart(), importDecl, { suffix: `${context.newLineCharacter}${context.newLineCharacter}` });
|
||||
changeTracker.insertNodeAt(sourceFile, getSourceFileImportLocation(sourceFile), importDecl, { suffix: `${context.newLineCharacter}${context.newLineCharacter}` });
|
||||
}
|
||||
else {
|
||||
changeTracker.insertNodeAfter(sourceFile, lastImportDeclaration, importDecl, { suffix: context.newLineCharacter });
|
||||
@@ -413,6 +415,46 @@ namespace ts.codefix {
|
||||
moduleSpecifierWithoutQuotes
|
||||
);
|
||||
|
||||
function getSourceFileImportLocation(node: SourceFile) {
|
||||
// For a source file, it is possible there are detached comments we should not skip
|
||||
const text = node.text;
|
||||
let ranges = getLeadingCommentRanges(text, 0);
|
||||
if (!ranges) return 0;
|
||||
let position = 0;
|
||||
// However we should still skip a pinned comment at the top
|
||||
if (ranges.length && ranges[0].kind === SyntaxKind.MultiLineCommentTrivia && isPinnedComment(text, ranges[0])) {
|
||||
position = ranges[0].end + 1;
|
||||
ranges = ranges.slice(1);
|
||||
}
|
||||
// As well as any triple slash references
|
||||
for (const range of ranges) {
|
||||
if (range.kind === SyntaxKind.SingleLineCommentTrivia && isRecognizedTripleSlashComment(node.text, range.pos, range.end)) {
|
||||
position = range.end + 1;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
function getSingleQuoteStyleFromExistingImports() {
|
||||
const firstModuleSpecifier = forEach(sourceFile.statements, node => {
|
||||
if (isImportDeclaration(node) || isExportDeclaration(node)) {
|
||||
if (node.moduleSpecifier && isStringLiteral(node.moduleSpecifier)) {
|
||||
return node.moduleSpecifier;
|
||||
}
|
||||
}
|
||||
else if (isImportEqualsDeclaration(node)) {
|
||||
if (isExternalModuleReference(node.moduleReference) && isStringLiteral(node.moduleReference.expression)) {
|
||||
return node.moduleReference.expression;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (firstModuleSpecifier) {
|
||||
return sourceFile.text.charCodeAt(firstModuleSpecifier.getStart()) === CharacterCodes.singleQuote;
|
||||
}
|
||||
}
|
||||
|
||||
function getModuleSpecifierForNewImport() {
|
||||
const fileName = sourceFile.fileName;
|
||||
const moduleFileName = moduleSymbol.valueDeclaration.getSourceFile().fileName;
|
||||
|
||||
@@ -652,10 +652,15 @@ namespace ts.FindAllReferences.Core {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// If the symbol has a parent, it's globally visible.
|
||||
// Unless that parent is an external module, then we should only search in the module (and recurse on the export later).
|
||||
// But if the parent is a module that has `export as namespace`, then the symbol *is* globally visible.
|
||||
if (parent && !((parent.flags & SymbolFlags.Module) && isExternalModuleSymbol(parent) && !parent.globalExports)) {
|
||||
/*
|
||||
If the symbol has a parent, it's globally visible unless:
|
||||
- It's a private property (handled above).
|
||||
- It's a type parameter.
|
||||
- The parent is an external module: then we should only search in the module (and recurse on the export later).
|
||||
- But if the parent has `export as namespace`, the symbol is globally visible through that namespace.
|
||||
*/
|
||||
const exposedByParent = parent && !(symbol.flags & SymbolFlags.TypeParameter);
|
||||
if (exposedByParent && !((parent.flags & SymbolFlags.Module) && isExternalModuleSymbol(parent) && !parent.globalExports)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -682,7 +687,7 @@ namespace ts.FindAllReferences.Core {
|
||||
// declare module "a" { export type T = number; }
|
||||
// declare module "b" { import { T } from "a"; export const x: T; }
|
||||
// So we must search the whole source file. (Because we will mark the source file as seen, we we won't return to it when searching for imports.)
|
||||
return parent ? scope.getSourceFile() : scope;
|
||||
return exposedByParent ? scope.getSourceFile() : scope;
|
||||
}
|
||||
|
||||
function getPossibleSymbolReferencePositions(sourceFile: SourceFile, symbolName: string, container: Node = sourceFile): number[] {
|
||||
|
||||
@@ -76,6 +76,28 @@ namespace ts.GoToDefinition {
|
||||
declaration => createDefinitionInfo(declaration, shorthandSymbolKind, shorthandSymbolName, shorthandContainerName));
|
||||
}
|
||||
|
||||
// If the node is the name of a BindingElement within an ObjectBindingPattern instead of just returning the
|
||||
// declaration the symbol (which is itself), we should try to get to the original type of the ObjectBindingPattern
|
||||
// and return the property declaration for the referenced property.
|
||||
// For example:
|
||||
// import('./foo').then(({ b/*goto*/ar }) => undefined); => should get use to the declaration in file "./foo"
|
||||
//
|
||||
// function bar<T>(onfulfilled: (value: T) => void) { //....}
|
||||
// interface Test {
|
||||
// pr/*destination*/op1: number
|
||||
// }
|
||||
// bar<Test>(({pr/*goto*/op1})=>{});
|
||||
if (isPropertyName(node) && isBindingElement(node.parent) && isObjectBindingPattern(node.parent.parent) &&
|
||||
(node === (node.parent.propertyName || node.parent.name))) {
|
||||
const type = typeChecker.getTypeAtLocation(node.parent.parent);
|
||||
if (type) {
|
||||
const propSymbols = getPropertySymbolsFromType(type, node);
|
||||
if (propSymbols) {
|
||||
return flatMap(propSymbols, propSymbol => getDefinitionFromSymbol(typeChecker, propSymbol, node));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the current location we want to find its definition is in an object literal, try to get the contextual type for the
|
||||
// object literal, lookup the property symbol in the contextual type, and use this for goto-definition.
|
||||
// For example
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* @internal */
|
||||
|
||||
namespace ts.refactor {
|
||||
namespace ts.refactor.convertFunctionToES6Class {
|
||||
const actionName = "convert";
|
||||
|
||||
const convertFunctionToES6Class: Refactor = {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1 +1,2 @@
|
||||
/// <reference path="convertFunctionToEs6Class.ts" />
|
||||
/// <reference path="extractMethod.ts" />
|
||||
|
||||
@@ -2150,12 +2150,17 @@ namespace ts {
|
||||
export function getPropertySymbolsFromContextualType(typeChecker: TypeChecker, node: ObjectLiteralElement): Symbol[] {
|
||||
const objectLiteral = <ObjectLiteralExpression | JsxAttributes>node.parent;
|
||||
const contextualType = typeChecker.getContextualType(objectLiteral);
|
||||
const name = unescapeLeadingUnderscores(getTextOfPropertyName(node.name));
|
||||
if (name && contextualType) {
|
||||
return getPropertySymbolsFromType(contextualType, node.name);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function getPropertySymbolsFromType(type: Type, propName: PropertyName) {
|
||||
const name = unescapeLeadingUnderscores(getTextOfPropertyName(propName));
|
||||
if (name && type) {
|
||||
const result: Symbol[] = [];
|
||||
const symbol = contextualType.getProperty(name);
|
||||
if (contextualType.flags & TypeFlags.Union) {
|
||||
forEach((<UnionType>contextualType).types, t => {
|
||||
const symbol = type.getProperty(name);
|
||||
if (type.flags & TypeFlags.Union) {
|
||||
forEach((<UnionType>type).types, t => {
|
||||
const symbol = t.getProperty(name);
|
||||
if (symbol) {
|
||||
result.push(symbol);
|
||||
|
||||
@@ -203,7 +203,7 @@ namespace ts.SymbolDisplay {
|
||||
// get the signature from the declaration and write it
|
||||
const functionDeclaration = <FunctionLike>location.parent;
|
||||
// Use function declaration to write the signatures only if the symbol corresponding to this declaration
|
||||
const locationIsSymbolDeclaration = findDeclaration(symbol, declaration =>
|
||||
const locationIsSymbolDeclaration = find(symbol.declarations, declaration =>
|
||||
declaration === (location.kind === SyntaxKind.ConstructorKeyword ? functionDeclaration.parent : functionDeclaration));
|
||||
|
||||
if (locationIsSymbolDeclaration) {
|
||||
|
||||
+129
-43
@@ -83,16 +83,43 @@ namespace ts.textChanges {
|
||||
delta?: number;
|
||||
}
|
||||
|
||||
export type ChangeNodeOptions = ConfigurableStartEnd & InsertNodeOptions;
|
||||
enum ChangeKind {
|
||||
Remove,
|
||||
ReplaceWithSingleNode,
|
||||
ReplaceWithMultipleNodes
|
||||
}
|
||||
|
||||
interface Change {
|
||||
type Change = ReplaceWithSingleNode | ReplaceWithMultipleNodes | RemoveNode;
|
||||
|
||||
interface BaseChange {
|
||||
readonly sourceFile: SourceFile;
|
||||
readonly range: TextRange;
|
||||
}
|
||||
|
||||
export interface ChangeNodeOptions extends ConfigurableStartEnd, InsertNodeOptions {
|
||||
readonly useIndentationFromFile?: boolean;
|
||||
readonly node?: Node;
|
||||
}
|
||||
interface ReplaceWithSingleNode extends BaseChange {
|
||||
readonly kind: ChangeKind.ReplaceWithSingleNode;
|
||||
readonly node: Node;
|
||||
readonly options?: ChangeNodeOptions;
|
||||
}
|
||||
|
||||
interface RemoveNode extends BaseChange {
|
||||
readonly kind: ChangeKind.Remove;
|
||||
readonly node?: never;
|
||||
readonly options?: never;
|
||||
}
|
||||
|
||||
export interface ChangeMultipleNodesOptions extends ChangeNodeOptions {
|
||||
nodeSeparator: string;
|
||||
}
|
||||
interface ReplaceWithMultipleNodes extends BaseChange {
|
||||
readonly kind: ChangeKind.ReplaceWithMultipleNodes;
|
||||
readonly nodes: ReadonlyArray<Node>;
|
||||
readonly options?: ChangeMultipleNodesOptions;
|
||||
}
|
||||
|
||||
export function getSeparatorCharacter(separator: Token<SyntaxKind.CommaToken | SyntaxKind.SemicolonToken>) {
|
||||
return tokenToString(separator.kind);
|
||||
}
|
||||
@@ -126,13 +153,11 @@ namespace ts.textChanges {
|
||||
}
|
||||
|
||||
export function getAdjustedEndPosition(sourceFile: SourceFile, node: Node, options: ConfigurableEnd) {
|
||||
if (options.useNonAdjustedEndPosition) {
|
||||
if (options.useNonAdjustedEndPosition || isExpression(node)) {
|
||||
return node.getEnd();
|
||||
}
|
||||
const end = node.getEnd();
|
||||
const newEnd = skipTrivia(sourceFile.text, end, /*stopAfterLineBreak*/ true);
|
||||
// check if last character before newPos is linebreak
|
||||
// if yes - considered all skipped trivia to be trailing trivia of the node
|
||||
return newEnd !== end && isLineBreak(sourceFile.text.charCodeAt(newEnd - 1))
|
||||
? newEnd
|
||||
: end;
|
||||
@@ -153,12 +178,16 @@ namespace ts.textChanges {
|
||||
return s;
|
||||
}
|
||||
|
||||
function getNewlineKind(context: { newLineCharacter: string }) {
|
||||
return context.newLineCharacter === "\n" ? NewLineKind.LineFeed : NewLineKind.CarriageReturnLineFeed;
|
||||
}
|
||||
|
||||
export class ChangeTracker {
|
||||
private changes: Change[] = [];
|
||||
private readonly newLineCharacter: string;
|
||||
|
||||
public static fromCodeFixContext(context: { newLineCharacter: string, rulesProvider: formatting.RulesProvider }) {
|
||||
return new ChangeTracker(context.newLineCharacter === "\n" ? NewLineKind.LineFeed : NewLineKind.CarriageReturnLineFeed, context.rulesProvider);
|
||||
public static fromCodeFixContext(context: { newLineCharacter: string, rulesProvider?: formatting.RulesProvider }) {
|
||||
return new ChangeTracker(getNewlineKind(context), context.rulesProvider);
|
||||
}
|
||||
|
||||
constructor(
|
||||
@@ -168,22 +197,22 @@ namespace ts.textChanges {
|
||||
this.newLineCharacter = getNewLineCharacter({ newLine });
|
||||
}
|
||||
|
||||
public deleteNode(sourceFile: SourceFile, node: Node, options: ConfigurableStartEnd = {}) {
|
||||
const startPosition = getAdjustedStartPosition(sourceFile, node, options, Position.FullStart);
|
||||
const endPosition = getAdjustedEndPosition(sourceFile, node, options);
|
||||
this.changes.push({ sourceFile, options, range: { pos: startPosition, end: endPosition } });
|
||||
public deleteRange(sourceFile: SourceFile, range: TextRange) {
|
||||
this.changes.push({ kind: ChangeKind.Remove, sourceFile, range });
|
||||
return this;
|
||||
}
|
||||
|
||||
public deleteRange(sourceFile: SourceFile, range: TextRange) {
|
||||
this.changes.push({ sourceFile, range });
|
||||
public deleteNode(sourceFile: SourceFile, node: Node, options: ConfigurableStartEnd = {}) {
|
||||
const startPosition = getAdjustedStartPosition(sourceFile, node, options, Position.FullStart);
|
||||
const endPosition = getAdjustedEndPosition(sourceFile, node, options);
|
||||
this.changes.push({ kind: ChangeKind.Remove, sourceFile, range: { pos: startPosition, end: endPosition } });
|
||||
return this;
|
||||
}
|
||||
|
||||
public deleteNodeRange(sourceFile: SourceFile, startNode: Node, endNode: Node, options: ConfigurableStartEnd = {}) {
|
||||
const startPosition = getAdjustedStartPosition(sourceFile, startNode, options, Position.FullStart);
|
||||
const endPosition = getAdjustedEndPosition(sourceFile, endNode, options);
|
||||
this.changes.push({ sourceFile, options, range: { pos: startPosition, end: endPosition } });
|
||||
this.changes.push({ kind: ChangeKind.Remove, sourceFile, range: { pos: startPosition, end: endPosition } });
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -223,33 +252,74 @@ namespace ts.textChanges {
|
||||
}
|
||||
|
||||
public replaceRange(sourceFile: SourceFile, range: TextRange, newNode: Node, options: InsertNodeOptions = {}) {
|
||||
this.changes.push({ sourceFile, range, options, node: newNode });
|
||||
this.changes.push({ kind: ChangeKind.ReplaceWithSingleNode, sourceFile, range, options, node: newNode });
|
||||
return this;
|
||||
}
|
||||
|
||||
public replaceNode(sourceFile: SourceFile, oldNode: Node, newNode: Node, options: ChangeNodeOptions = {}) {
|
||||
const startPosition = getAdjustedStartPosition(sourceFile, oldNode, options, Position.Start);
|
||||
const endPosition = getAdjustedEndPosition(sourceFile, oldNode, options);
|
||||
this.changes.push({ sourceFile, options, useIndentationFromFile: true, node: newNode, range: { pos: startPosition, end: endPosition } });
|
||||
return this;
|
||||
return this.replaceWithSingle(sourceFile, startPosition, endPosition, newNode, options);
|
||||
}
|
||||
|
||||
public replaceNodeRange(sourceFile: SourceFile, startNode: Node, endNode: Node, newNode: Node, options: ChangeNodeOptions = {}) {
|
||||
const startPosition = getAdjustedStartPosition(sourceFile, startNode, options, Position.Start);
|
||||
const endPosition = getAdjustedEndPosition(sourceFile, endNode, options);
|
||||
this.changes.push({ sourceFile, options, useIndentationFromFile: true, node: newNode, range: { pos: startPosition, end: endPosition } });
|
||||
return this.replaceWithSingle(sourceFile, startPosition, endPosition, newNode, options);
|
||||
}
|
||||
|
||||
private replaceWithSingle(sourceFile: SourceFile, startPosition: number, endPosition: number, newNode: Node, options: ChangeNodeOptions): this {
|
||||
this.changes.push({
|
||||
kind: ChangeKind.ReplaceWithSingleNode,
|
||||
sourceFile,
|
||||
options,
|
||||
node: newNode,
|
||||
range: { pos: startPosition, end: endPosition }
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
private replaceWithMultiple(sourceFile: SourceFile, startPosition: number, endPosition: number, newNodes: ReadonlyArray<Node>, options: ChangeMultipleNodesOptions): this {
|
||||
this.changes.push({
|
||||
kind: ChangeKind.ReplaceWithMultipleNodes,
|
||||
sourceFile,
|
||||
options,
|
||||
nodes: newNodes,
|
||||
range: { pos: startPosition, end: endPosition }
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
public replaceNodeWithNodes(sourceFile: SourceFile, oldNode: Node, newNodes: ReadonlyArray<Node>, options: ChangeMultipleNodesOptions) {
|
||||
const startPosition = getAdjustedStartPosition(sourceFile, oldNode, options, Position.Start);
|
||||
const endPosition = getAdjustedEndPosition(sourceFile, oldNode, options);
|
||||
return this.replaceWithMultiple(sourceFile, startPosition, endPosition, newNodes, options);
|
||||
}
|
||||
|
||||
public replaceNodesWithNodes(sourceFile: SourceFile, oldNodes: ReadonlyArray<Node>, newNodes: ReadonlyArray<Node>, options: ChangeMultipleNodesOptions) {
|
||||
const startPosition = getAdjustedStartPosition(sourceFile, oldNodes[0], options, Position.Start);
|
||||
const endPosition = getAdjustedEndPosition(sourceFile, lastOrUndefined(oldNodes), options);
|
||||
return this.replaceWithMultiple(sourceFile, startPosition, endPosition, newNodes, options);
|
||||
}
|
||||
|
||||
public replaceRangeWithNodes(sourceFile: SourceFile, range: TextRange, newNodes: ReadonlyArray<Node>, options: ChangeMultipleNodesOptions) {
|
||||
return this.replaceWithMultiple(sourceFile, range.pos, range.end, newNodes, options);
|
||||
}
|
||||
|
||||
public replaceNodeRangeWithNodes(sourceFile: SourceFile, startNode: Node, endNode: Node, newNodes: ReadonlyArray<Node>, options: ChangeMultipleNodesOptions) {
|
||||
const startPosition = getAdjustedStartPosition(sourceFile, startNode, options, Position.Start);
|
||||
const endPosition = getAdjustedEndPosition(sourceFile, endNode, options);
|
||||
return this.replaceWithMultiple(sourceFile, startPosition, endPosition, newNodes, options);
|
||||
}
|
||||
|
||||
public insertNodeAt(sourceFile: SourceFile, pos: number, newNode: Node, options: InsertNodeOptions = {}) {
|
||||
this.changes.push({ sourceFile, options, node: newNode, range: { pos, end: pos } });
|
||||
this.changes.push({ kind: ChangeKind.ReplaceWithSingleNode, sourceFile, options, node: newNode, range: { pos, end: pos } });
|
||||
return this;
|
||||
}
|
||||
|
||||
public insertNodeBefore(sourceFile: SourceFile, before: Node, newNode: Node, options: InsertNodeOptions & ConfigurableStart = {}) {
|
||||
const startPosition = getAdjustedStartPosition(sourceFile, before, options, Position.Start);
|
||||
this.changes.push({ sourceFile, options, useIndentationFromFile: true, node: newNode, range: { pos: startPosition, end: startPosition } });
|
||||
return this;
|
||||
return this.replaceWithSingle(sourceFile, startPosition, startPosition, newNode, options);
|
||||
}
|
||||
|
||||
public insertNodeAfter(sourceFile: SourceFile, after: Node, newNode: Node, options: InsertNodeOptions & ConfigurableEnd = {}) {
|
||||
@@ -261,6 +331,7 @@ namespace ts.textChanges {
|
||||
// if not - insert semicolon to preserve the code from changing the meaning due to ASI
|
||||
if (sourceFile.text.charCodeAt(after.end - 1) !== CharacterCodes.semicolon) {
|
||||
this.changes.push({
|
||||
kind: ChangeKind.ReplaceWithSingleNode,
|
||||
sourceFile,
|
||||
options: {},
|
||||
range: { pos: after.end, end: after.end },
|
||||
@@ -269,8 +340,7 @@ namespace ts.textChanges {
|
||||
}
|
||||
}
|
||||
const endPosition = getAdjustedEndPosition(sourceFile, after, options);
|
||||
this.changes.push({ sourceFile, options, useIndentationFromFile: true, node: newNode, range: { pos: endPosition, end: endPosition } });
|
||||
return this;
|
||||
return this.replaceWithSingle(sourceFile, endPosition, endPosition, newNode, options);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -339,10 +409,10 @@ namespace ts.textChanges {
|
||||
}
|
||||
|
||||
this.changes.push({
|
||||
kind: ChangeKind.ReplaceWithSingleNode,
|
||||
sourceFile,
|
||||
range: { pos: startPos, end: containingList[index + 1].getStart(sourceFile) },
|
||||
node: newNode,
|
||||
useIndentationFromFile: true,
|
||||
options: {
|
||||
prefix,
|
||||
// write separator and leading trivia of the next element as suffix
|
||||
@@ -383,6 +453,7 @@ namespace ts.textChanges {
|
||||
if (multilineList) {
|
||||
// insert separator immediately following the 'after' node to preserve comments in trailing trivia
|
||||
this.changes.push({
|
||||
kind: ChangeKind.ReplaceWithSingleNode,
|
||||
sourceFile,
|
||||
range: { pos: end, end },
|
||||
node: createToken(separator),
|
||||
@@ -396,6 +467,7 @@ namespace ts.textChanges {
|
||||
insertPos--;
|
||||
}
|
||||
this.changes.push({
|
||||
kind: ChangeKind.ReplaceWithSingleNode,
|
||||
sourceFile,
|
||||
range: { pos: insertPos, end: insertPos },
|
||||
node: newNode,
|
||||
@@ -404,6 +476,7 @@ namespace ts.textChanges {
|
||||
}
|
||||
else {
|
||||
this.changes.push({
|
||||
kind: ChangeKind.ReplaceWithSingleNode,
|
||||
sourceFile,
|
||||
range: { pos: end, end },
|
||||
node: newNode,
|
||||
@@ -446,38 +519,51 @@ namespace ts.textChanges {
|
||||
}
|
||||
|
||||
private computeNewText(change: Change, sourceFile: SourceFile): string {
|
||||
if (!change.node) {
|
||||
if (change.kind === ChangeKind.Remove) {
|
||||
// deletion case
|
||||
return "";
|
||||
}
|
||||
|
||||
const options = change.options || {};
|
||||
const nonFormattedText = getNonformattedText(change.node, sourceFile, this.newLine);
|
||||
let text: string;
|
||||
const pos = change.range.pos;
|
||||
const posStartsLine = getLineStartPositionForPosition(pos, sourceFile) === pos;
|
||||
if (change.kind === ChangeKind.ReplaceWithMultipleNodes) {
|
||||
const parts = change.nodes.map(n => this.getFormattedTextOfNode(n, sourceFile, pos, options));
|
||||
text = parts.join(change.options.nodeSeparator);
|
||||
}
|
||||
else {
|
||||
Debug.assert(change.kind === ChangeKind.ReplaceWithSingleNode, "change.kind === ReplaceWithSingleNode");
|
||||
text = this.getFormattedTextOfNode(change.node, sourceFile, pos, options);
|
||||
}
|
||||
// strip initial indentation (spaces or tabs) if text will be inserted in the middle of the line
|
||||
text = (posStartsLine || options.indentation !== undefined) ? text : text.replace(/^\s+/, "");
|
||||
return (options.prefix || "") + text + (options.suffix || "");
|
||||
}
|
||||
|
||||
private getFormattedTextOfNode(node: Node, sourceFile: SourceFile, pos: number, options: ChangeNodeOptions): string {
|
||||
const nonformattedText = getNonformattedText(node, sourceFile, this.newLine);
|
||||
if (this.validator) {
|
||||
this.validator(nonFormattedText);
|
||||
this.validator(nonformattedText);
|
||||
}
|
||||
|
||||
const formatOptions = this.rulesProvider.getFormatOptions();
|
||||
const pos = change.range.pos;
|
||||
const posStartsLine = getLineStartPositionForPosition(pos, sourceFile) === pos;
|
||||
|
||||
const initialIndentation =
|
||||
change.options.indentation !== undefined
|
||||
? change.options.indentation
|
||||
: change.useIndentationFromFile
|
||||
? formatting.SmartIndenter.getIndentation(change.range.pos, sourceFile, formatOptions, posStartsLine || (change.options.prefix === this.newLineCharacter))
|
||||
options.indentation !== undefined
|
||||
? options.indentation
|
||||
: (options.useIndentationFromFile !== false)
|
||||
? formatting.SmartIndenter.getIndentation(pos, sourceFile, formatOptions, posStartsLine || (options.prefix === this.newLineCharacter))
|
||||
: 0;
|
||||
const delta =
|
||||
change.options.delta !== undefined
|
||||
? change.options.delta
|
||||
: formatting.SmartIndenter.shouldIndentChildNode(change.node)
|
||||
? formatOptions.indentSize
|
||||
options.delta !== undefined
|
||||
? options.delta
|
||||
: formatting.SmartIndenter.shouldIndentChildNode(node)
|
||||
? (formatOptions.indentSize || 0)
|
||||
: 0;
|
||||
|
||||
let text = applyFormatting(nonFormattedText, sourceFile, initialIndentation, delta, this.rulesProvider);
|
||||
// strip initial indentation (spaces or tabs) if text will be inserted in the middle of the line
|
||||
// however keep indentation if it is was forced
|
||||
text = posStartsLine || change.options.indentation !== undefined ? text : text.replace(/^\s+/, "");
|
||||
return (options.prefix || "") + text + (options.suffix || "");
|
||||
return applyFormatting(nonformattedText, sourceFile, initialIndentation, delta, this.rulesProvider);
|
||||
}
|
||||
|
||||
private static normalize(changes: Change[]): Change[] {
|
||||
@@ -654,4 +740,4 @@ namespace ts.textChanges {
|
||||
this.lastNonTriviaPosition = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,7 +273,6 @@ namespace ts {
|
||||
getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan;
|
||||
|
||||
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: number[], formatOptions: FormatCodeSettings): CodeAction[];
|
||||
|
||||
getApplicableRefactors(fileName: string, positionOrRaneg: number | TextRange): ApplicableRefactorInfo[];
|
||||
getEditsForRefactor(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string, actionName: string): RefactorEditInfo | undefined;
|
||||
|
||||
|
||||
@@ -1247,6 +1247,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function signatureToDisplayParts(typechecker: TypeChecker, signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags): SymbolDisplayPart[] {
|
||||
flags |= TypeFormatFlags.UseAliasDefinedOutsideCurrentScope;
|
||||
return mapToDisplayParts(writer => {
|
||||
typechecker.getSymbolDisplayBuilder().buildSignatureDisplay(signature, writer, enclosingDeclaration, flags);
|
||||
});
|
||||
|
||||
@@ -1158,3 +1158,4 @@ MERCHANTABLITY OR NON-INFRINGEMENT.
|
||||
See the Apache Version 2.0 License for specific language governing permissions
|
||||
and limitations under the License.
|
||||
***************************************************************************** */
|
||||
/// <reference no-default-lib="true"/>
|
||||
|
||||
@@ -16,17 +16,17 @@ class Board {
|
||||
}
|
||||
|
||||
//// [2dArrays.js]
|
||||
var Cell = (function () {
|
||||
var Cell = /** @class */ (function () {
|
||||
function Cell() {
|
||||
}
|
||||
return Cell;
|
||||
}());
|
||||
var Ship = (function () {
|
||||
var Ship = /** @class */ (function () {
|
||||
function Ship() {
|
||||
}
|
||||
return Ship;
|
||||
}());
|
||||
var Board = (function () {
|
||||
var Board = /** @class */ (function () {
|
||||
function Board() {
|
||||
}
|
||||
Board.prototype.allShipsSunk = function () {
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ var p = new A.Point(0, 0); // unexpected error here, bug 840000
|
||||
//// [classPoint.js]
|
||||
var A;
|
||||
(function (A) {
|
||||
var Point = (function () {
|
||||
var Point = /** @class */ (function () {
|
||||
function Point(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
+6
-6
@@ -51,7 +51,7 @@ module clodule4 {
|
||||
|
||||
//// [ClassAndModuleThatMergeWithModuleMemberThatUsesClassTypeParameter.js]
|
||||
// all expected to be errors
|
||||
var clodule1 = (function () {
|
||||
var clodule1 = /** @class */ (function () {
|
||||
function clodule1() {
|
||||
}
|
||||
return clodule1;
|
||||
@@ -59,20 +59,20 @@ var clodule1 = (function () {
|
||||
(function (clodule1) {
|
||||
function f(x) { }
|
||||
})(clodule1 || (clodule1 = {}));
|
||||
var clodule2 = (function () {
|
||||
var clodule2 = /** @class */ (function () {
|
||||
function clodule2() {
|
||||
}
|
||||
return clodule2;
|
||||
}());
|
||||
(function (clodule2) {
|
||||
var x;
|
||||
var D = (function () {
|
||||
var D = /** @class */ (function () {
|
||||
function D() {
|
||||
}
|
||||
return D;
|
||||
}());
|
||||
})(clodule2 || (clodule2 = {}));
|
||||
var clodule3 = (function () {
|
||||
var clodule3 = /** @class */ (function () {
|
||||
function clodule3() {
|
||||
}
|
||||
return clodule3;
|
||||
@@ -80,13 +80,13 @@ var clodule3 = (function () {
|
||||
(function (clodule3) {
|
||||
clodule3.y = { id: T };
|
||||
})(clodule3 || (clodule3 = {}));
|
||||
var clodule4 = (function () {
|
||||
var clodule4 = /** @class */ (function () {
|
||||
function clodule4() {
|
||||
}
|
||||
return clodule4;
|
||||
}());
|
||||
(function (clodule4) {
|
||||
var D = (function () {
|
||||
var D = /** @class */ (function () {
|
||||
function D() {
|
||||
}
|
||||
return D;
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ module clodule {
|
||||
|
||||
|
||||
//// [ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndGenericClassStaticFunctionOfTheSameName.js]
|
||||
var clodule = (function () {
|
||||
var clodule = /** @class */ (function () {
|
||||
function clodule() {
|
||||
}
|
||||
clodule.fn = function (id) { };
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ module clodule {
|
||||
|
||||
|
||||
//// [ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndNonGenericClassStaticFunctionOfTheSameName.js]
|
||||
var clodule = (function () {
|
||||
var clodule = /** @class */ (function () {
|
||||
function clodule() {
|
||||
}
|
||||
clodule.fn = function (id) { };
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ module clodule {
|
||||
|
||||
|
||||
//// [ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.js]
|
||||
var clodule = (function () {
|
||||
var clodule = /** @class */ (function () {
|
||||
function clodule() {
|
||||
}
|
||||
clodule.sfn = function (id) { return 42; };
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@ module A {
|
||||
}
|
||||
|
||||
//// [ClassAndModuleThatMergeWithStaticFunctionAndExportedFunctionThatShareAName.js]
|
||||
var Point = (function () {
|
||||
var Point = /** @class */ (function () {
|
||||
function Point(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
@@ -37,7 +37,7 @@ var Point = (function () {
|
||||
})(Point || (Point = {}));
|
||||
var A;
|
||||
(function (A) {
|
||||
var Point = (function () {
|
||||
var Point = /** @class */ (function () {
|
||||
function Point(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@ module A {
|
||||
}
|
||||
|
||||
//// [ClassAndModuleThatMergeWithStaticFunctionAndNonExportedFunctionThatShareAName.js]
|
||||
var Point = (function () {
|
||||
var Point = /** @class */ (function () {
|
||||
function Point(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
@@ -36,7 +36,7 @@ var Point = (function () {
|
||||
})(Point || (Point = {}));
|
||||
var A;
|
||||
(function (A) {
|
||||
var Point = (function () {
|
||||
var Point = /** @class */ (function () {
|
||||
function Point(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@ module A {
|
||||
}
|
||||
|
||||
//// [ClassAndModuleThatMergeWithStaticVariableAndExportedVarThatShareAName.js]
|
||||
var Point = (function () {
|
||||
var Point = /** @class */ (function () {
|
||||
function Point(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
@@ -36,7 +36,7 @@ var Point = (function () {
|
||||
})(Point || (Point = {}));
|
||||
var A;
|
||||
(function (A) {
|
||||
var Point = (function () {
|
||||
var Point = /** @class */ (function () {
|
||||
function Point(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@ module A {
|
||||
}
|
||||
|
||||
//// [ClassAndModuleThatMergeWithStaticVariableAndNonExportedVarThatShareAName.js]
|
||||
var Point = (function () {
|
||||
var Point = /** @class */ (function () {
|
||||
function Point(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
@@ -36,7 +36,7 @@ var Point = (function () {
|
||||
})(Point || (Point = {}));
|
||||
var A;
|
||||
(function (A) {
|
||||
var Point = (function () {
|
||||
var Point = /** @class */ (function () {
|
||||
function Point(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
@@ -45,7 +45,7 @@ var X;
|
||||
(function (X) {
|
||||
var Y;
|
||||
(function (Y) {
|
||||
var Point = (function () {
|
||||
var Point = /** @class */ (function () {
|
||||
function Point(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
@@ -71,7 +71,7 @@ var X;
|
||||
var cl = new X.Y.Point(1, 1);
|
||||
var cl = X.Y.Point.Origin; // error not expected here same as bug 83996 ?
|
||||
//// [simple.js]
|
||||
var A = (function () {
|
||||
var A = /** @class */ (function () {
|
||||
function A() {
|
||||
}
|
||||
return A;
|
||||
|
||||
@@ -5,7 +5,7 @@ class C {
|
||||
}
|
||||
|
||||
//// [ClassDeclaration10.js]
|
||||
var C = (function () {
|
||||
var C = /** @class */ (function () {
|
||||
function C() {
|
||||
}
|
||||
return C;
|
||||
|
||||
@@ -5,7 +5,7 @@ class C {
|
||||
}
|
||||
|
||||
//// [ClassDeclaration11.js]
|
||||
var C = (function () {
|
||||
var C = /** @class */ (function () {
|
||||
function C() {
|
||||
}
|
||||
C.prototype.foo = function () { };
|
||||
|
||||
@@ -5,7 +5,7 @@ class C {
|
||||
}
|
||||
|
||||
//// [ClassDeclaration13.js]
|
||||
var C = (function () {
|
||||
var C = /** @class */ (function () {
|
||||
function C() {
|
||||
}
|
||||
C.prototype.bar = function () { };
|
||||
|
||||
@@ -5,7 +5,7 @@ class C {
|
||||
}
|
||||
|
||||
//// [ClassDeclaration14.js]
|
||||
var C = (function () {
|
||||
var C = /** @class */ (function () {
|
||||
function C() {
|
||||
}
|
||||
return C;
|
||||
|
||||
@@ -5,7 +5,7 @@ class C {
|
||||
}
|
||||
|
||||
//// [ClassDeclaration15.js]
|
||||
var C = (function () {
|
||||
var C = /** @class */ (function () {
|
||||
function C() {
|
||||
}
|
||||
return C;
|
||||
|
||||
@@ -5,7 +5,7 @@ class C {
|
||||
}
|
||||
|
||||
//// [ClassDeclaration21.js]
|
||||
var C = (function () {
|
||||
var C = /** @class */ (function () {
|
||||
function C() {
|
||||
}
|
||||
C.prototype[1] = function () { };
|
||||
|
||||
@@ -5,7 +5,7 @@ class C {
|
||||
}
|
||||
|
||||
//// [ClassDeclaration22.js]
|
||||
var C = (function () {
|
||||
var C = /** @class */ (function () {
|
||||
function C() {
|
||||
}
|
||||
C.prototype["bar"] = function () { };
|
||||
|
||||
@@ -3,7 +3,7 @@ class any {
|
||||
}
|
||||
|
||||
//// [ClassDeclaration24.js]
|
||||
var any = (function () {
|
||||
var any = /** @class */ (function () {
|
||||
function any() {
|
||||
}
|
||||
return any;
|
||||
|
||||
@@ -10,7 +10,7 @@ class List<U> implements IList<U> {
|
||||
|
||||
|
||||
//// [ClassDeclaration25.js]
|
||||
var List = (function () {
|
||||
var List = /** @class */ (function () {
|
||||
function List() {
|
||||
}
|
||||
return List;
|
||||
|
||||
@@ -6,7 +6,7 @@ class C {
|
||||
}
|
||||
|
||||
//// [ClassDeclaration26.js]
|
||||
var C = (function () {
|
||||
var C = /** @class */ (function () {
|
||||
function C() {
|
||||
this.foo = 10;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ class C {
|
||||
}
|
||||
|
||||
//// [ClassDeclaration8.js]
|
||||
var C = (function () {
|
||||
var C = /** @class */ (function () {
|
||||
function C() {
|
||||
}
|
||||
return C;
|
||||
|
||||
@@ -4,7 +4,7 @@ class C {
|
||||
}
|
||||
|
||||
//// [ClassDeclaration9.js]
|
||||
var C = (function () {
|
||||
var C = /** @class */ (function () {
|
||||
function C() {
|
||||
}
|
||||
return C;
|
||||
|
||||
@@ -4,7 +4,7 @@ class AtomicNumbers {
|
||||
}
|
||||
|
||||
//// [ClassDeclarationWithInvalidConstOnPropertyDeclaration.js]
|
||||
var AtomicNumbers = (function () {
|
||||
var AtomicNumbers = /** @class */ (function () {
|
||||
function AtomicNumbers() {
|
||||
}
|
||||
AtomicNumbers.H = 1;
|
||||
|
||||
@@ -5,7 +5,7 @@ class C {
|
||||
}
|
||||
|
||||
//// [ClassDeclarationWithInvalidConstOnPropertyDeclaration2.js]
|
||||
var C = (function () {
|
||||
var C = /** @class */ (function () {
|
||||
function C() {
|
||||
this.x = 10;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ for (var v of new StringIterator) { }
|
||||
|
||||
//// [ES5For-ofTypeCheck10.js]
|
||||
// In ES3/5, you cannot for...of over an arbitrary iterable.
|
||||
var StringIterator = (function () {
|
||||
var StringIterator = /** @class */ (function () {
|
||||
function StringIterator() {
|
||||
}
|
||||
StringIterator.prototype.next = function () {
|
||||
|
||||
@@ -14,7 +14,7 @@ module M {
|
||||
var M;
|
||||
(function (M) {
|
||||
var Symbol;
|
||||
var C = (function () {
|
||||
var C = /** @class */ (function () {
|
||||
function C() {
|
||||
}
|
||||
C.prototype[Symbol.iterator] = function () { };
|
||||
|
||||
@@ -9,7 +9,7 @@ class C {
|
||||
|
||||
//// [ES5SymbolProperty3.js]
|
||||
var Symbol;
|
||||
var C = (function () {
|
||||
var C = /** @class */ (function () {
|
||||
function C() {
|
||||
}
|
||||
C.prototype[Symbol.iterator] = function () { };
|
||||
|
||||
@@ -9,7 +9,7 @@ class C {
|
||||
|
||||
//// [ES5SymbolProperty4.js]
|
||||
var Symbol;
|
||||
var C = (function () {
|
||||
var C = /** @class */ (function () {
|
||||
function C() {
|
||||
}
|
||||
C.prototype[Symbol.iterator] = function () { };
|
||||
|
||||
@@ -9,7 +9,7 @@ class C {
|
||||
|
||||
//// [ES5SymbolProperty5.js]
|
||||
var Symbol;
|
||||
var C = (function () {
|
||||
var C = /** @class */ (function () {
|
||||
function C() {
|
||||
}
|
||||
C.prototype[Symbol.iterator] = function () { };
|
||||
|
||||
@@ -6,7 +6,7 @@ class C {
|
||||
(new C)[Symbol.iterator]
|
||||
|
||||
//// [ES5SymbolProperty6.js]
|
||||
var C = (function () {
|
||||
var C = /** @class */ (function () {
|
||||
function C() {
|
||||
}
|
||||
C.prototype[Symbol.iterator] = function () { };
|
||||
|
||||
@@ -9,7 +9,7 @@ class C {
|
||||
|
||||
//// [ES5SymbolProperty7.js]
|
||||
var Symbol;
|
||||
var C = (function () {
|
||||
var C = /** @class */ (function () {
|
||||
function C() {
|
||||
}
|
||||
C.prototype[Symbol.iterator] = function () { };
|
||||
|
||||
@@ -23,7 +23,7 @@ var enumdule;
|
||||
enumdule[enumdule["Blue"] = 1] = "Blue";
|
||||
})(enumdule || (enumdule = {}));
|
||||
(function (enumdule) {
|
||||
var Point = (function () {
|
||||
var Point = /** @class */ (function () {
|
||||
function Point(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
@@ -6,7 +6,7 @@ export = B;
|
||||
|
||||
//// [ExportAssignment7.js]
|
||||
"use strict";
|
||||
var C = (function () {
|
||||
var C = /** @class */ (function () {
|
||||
function C() {
|
||||
}
|
||||
return C;
|
||||
|
||||
@@ -6,7 +6,7 @@ export class C {
|
||||
|
||||
//// [ExportAssignment8.js]
|
||||
"use strict";
|
||||
var C = (function () {
|
||||
var C = /** @class */ (function () {
|
||||
function C() {
|
||||
}
|
||||
return C;
|
||||
|
||||
@@ -22,7 +22,7 @@ module A {
|
||||
//// [ExportClassWhichExtendsInterfaceWithInaccessibleType.js]
|
||||
var A;
|
||||
(function (A) {
|
||||
var Point2d = (function () {
|
||||
var Point2d = /** @class */ (function () {
|
||||
function Point2d(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
+3
-3
@@ -33,14 +33,14 @@ var __extends = (this && this.__extends) || (function () {
|
||||
})();
|
||||
var A;
|
||||
(function (A) {
|
||||
var Point = (function () {
|
||||
var Point = /** @class */ (function () {
|
||||
function Point() {
|
||||
}
|
||||
return Point;
|
||||
}());
|
||||
A.Point = Point;
|
||||
A.Origin = { x: 0, y: 0 };
|
||||
var Point3d = (function (_super) {
|
||||
var Point3d = /** @class */ (function (_super) {
|
||||
__extends(Point3d, _super);
|
||||
function Point3d() {
|
||||
return _super !== null && _super.apply(this, arguments) || this;
|
||||
@@ -49,7 +49,7 @@ var A;
|
||||
}(Point));
|
||||
A.Point3d = Point3d;
|
||||
A.Origin3d = { x: 0, y: 0, z: 0 };
|
||||
var Line = (function () {
|
||||
var Line = /** @class */ (function () {
|
||||
function Line(start, end) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
|
||||
+2
-2
@@ -18,12 +18,12 @@ module A {
|
||||
//// [ExportClassWithInaccessibleTypeInIndexerTypeAnnotations.js]
|
||||
var A;
|
||||
(function (A) {
|
||||
var Point = (function () {
|
||||
var Point = /** @class */ (function () {
|
||||
function Point() {
|
||||
}
|
||||
return Point;
|
||||
}());
|
||||
var points = (function () {
|
||||
var points = /** @class */ (function () {
|
||||
function points() {
|
||||
}
|
||||
return points;
|
||||
|
||||
+3
-3
@@ -37,13 +37,13 @@ var __extends = (this && this.__extends) || (function () {
|
||||
})();
|
||||
var A;
|
||||
(function (A) {
|
||||
var Point = (function () {
|
||||
var Point = /** @class */ (function () {
|
||||
function Point() {
|
||||
}
|
||||
return Point;
|
||||
}());
|
||||
A.Origin = { x: 0, y: 0 };
|
||||
var Point3d = (function (_super) {
|
||||
var Point3d = /** @class */ (function (_super) {
|
||||
__extends(Point3d, _super);
|
||||
function Point3d() {
|
||||
return _super !== null && _super.apply(this, arguments) || this;
|
||||
@@ -52,7 +52,7 @@ var A;
|
||||
}(Point));
|
||||
A.Point3d = Point3d;
|
||||
A.Origin3d = { x: 0, y: 0, z: 0 };
|
||||
var Line = (function () {
|
||||
var Line = /** @class */ (function () {
|
||||
function Line(start, end) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
|
||||
+2
-2
@@ -18,13 +18,13 @@ module A {
|
||||
//// [ExportFunctionWithAccessibleTypesInParameterAndReturnTypeAnnotation.js]
|
||||
var A;
|
||||
(function (A) {
|
||||
var Point = (function () {
|
||||
var Point = /** @class */ (function () {
|
||||
function Point() {
|
||||
}
|
||||
return Point;
|
||||
}());
|
||||
A.Point = Point;
|
||||
var Line = (function () {
|
||||
var Line = /** @class */ (function () {
|
||||
function Line(start, end) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
|
||||
+2
-2
@@ -18,12 +18,12 @@ module A {
|
||||
//// [ExportFunctionWithInaccessibleTypesInParameterTypeAnnotation.js]
|
||||
var A;
|
||||
(function (A) {
|
||||
var Point = (function () {
|
||||
var Point = /** @class */ (function () {
|
||||
function Point() {
|
||||
}
|
||||
return Point;
|
||||
}());
|
||||
var Line = (function () {
|
||||
var Line = /** @class */ (function () {
|
||||
function Line(start, end) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user