mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
merge with origin/master
This commit is contained in:
+120
-58
@@ -7,7 +7,10 @@ namespace ts {
|
||||
let nextMergeId = 1;
|
||||
|
||||
export function getNodeId(node: Node): number {
|
||||
if (!node.id) node.id = nextNodeId++;
|
||||
if (!node.id) {
|
||||
node.id = nextNodeId;
|
||||
nextNodeId++;
|
||||
}
|
||||
return node.id;
|
||||
}
|
||||
|
||||
@@ -15,7 +18,8 @@ namespace ts {
|
||||
|
||||
export function getSymbolId(symbol: Symbol): number {
|
||||
if (!symbol.id) {
|
||||
symbol.id = nextSymbolId++;
|
||||
symbol.id = nextSymbolId;
|
||||
nextSymbolId++;
|
||||
}
|
||||
|
||||
return symbol.id;
|
||||
@@ -61,6 +65,7 @@ namespace ts {
|
||||
getTypeCount: () => typeCount,
|
||||
isUndefinedSymbol: symbol => symbol === undefinedSymbol,
|
||||
isArgumentsSymbol: symbol => symbol === argumentsSymbol,
|
||||
isUnknownSymbol: symbol => symbol === unknownSymbol,
|
||||
getDiagnostics,
|
||||
getGlobalDiagnostics,
|
||||
|
||||
@@ -287,7 +292,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
function recordMergedSymbol(target: Symbol, source: Symbol) {
|
||||
if (!source.mergeId) source.mergeId = nextMergeId++;
|
||||
if (!source.mergeId) {
|
||||
source.mergeId = nextMergeId;
|
||||
nextMergeId++;
|
||||
}
|
||||
mergedSymbols[source.mergeId] = target;
|
||||
}
|
||||
|
||||
@@ -1301,7 +1309,8 @@ namespace ts {
|
||||
|
||||
function createType(flags: TypeFlags): Type {
|
||||
const result = new Type(checker, flags);
|
||||
result.id = typeCount++;
|
||||
result.id = typeCount;
|
||||
typeCount++;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1862,11 +1871,13 @@ namespace ts {
|
||||
}
|
||||
if (pos < end) {
|
||||
writePunctuation(writer, SyntaxKind.LessThanToken);
|
||||
writeType(typeArguments[pos++], TypeFormatFlags.None);
|
||||
writeType(typeArguments[pos], TypeFormatFlags.None);
|
||||
pos++;
|
||||
while (pos < end) {
|
||||
writePunctuation(writer, SyntaxKind.CommaToken);
|
||||
writeSpace(writer);
|
||||
writeType(typeArguments[pos++], TypeFormatFlags.None);
|
||||
writeType(typeArguments[pos], TypeFormatFlags.None);
|
||||
pos++;
|
||||
}
|
||||
writePunctuation(writer, SyntaxKind.GreaterThanToken);
|
||||
}
|
||||
@@ -2553,9 +2564,9 @@ namespace ts {
|
||||
|
||||
// Return the inferred type for a variable, parameter, or property declaration
|
||||
function getTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration): Type {
|
||||
// A variable declared in a for..in statement is always of type any
|
||||
// A variable declared in a for..in statement is always of type string
|
||||
if (declaration.parent.parent.kind === SyntaxKind.ForInStatement) {
|
||||
return anyType;
|
||||
return stringType;
|
||||
}
|
||||
|
||||
if (declaration.parent.parent.kind === SyntaxKind.ForOfStatement) {
|
||||
@@ -5719,7 +5730,7 @@ namespace ts {
|
||||
return Ternary.False;
|
||||
}
|
||||
let result = Ternary.True;
|
||||
for (let i = 0, len = sourceSignatures.length; i < len; ++i) {
|
||||
for (let i = 0, len = sourceSignatures.length; i < len; i++) {
|
||||
const related = compareSignaturesIdentical(sourceSignatures[i], targetSignatures[i], /*partialMatch*/ false, /*ignoreReturnTypes*/ false, isRelatedTo);
|
||||
if (!related) {
|
||||
return Ternary.False;
|
||||
@@ -7395,6 +7406,12 @@ namespace ts {
|
||||
}
|
||||
return type;
|
||||
}
|
||||
else if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.CommaToken) {
|
||||
if (node === binaryExpression.right) {
|
||||
return getContextualType(binaryExpression);
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -7507,24 +7524,22 @@ namespace ts {
|
||||
return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional) : undefined;
|
||||
}
|
||||
|
||||
function getContextualTypeForJsxExpression(expr: JsxExpression | JsxSpreadAttribute): Type {
|
||||
// Contextual type only applies to JSX expressions that are in attribute assignments (not in 'Children' positions)
|
||||
if (expr.parent.kind === SyntaxKind.JsxAttribute) {
|
||||
const attrib = <JsxAttribute>expr.parent;
|
||||
const attrsType = getJsxElementAttributesType(<JsxOpeningLikeElement>attrib.parent);
|
||||
function getContextualTypeForJsxAttribute(attribute: JsxAttribute | JsxSpreadAttribute) {
|
||||
const kind = attribute.kind;
|
||||
const jsxElement = attribute.parent as JsxOpeningLikeElement;
|
||||
const attrsType = getJsxElementAttributesType(jsxElement);
|
||||
|
||||
if (attribute.kind === SyntaxKind.JsxAttribute) {
|
||||
if (!attrsType || isTypeAny(attrsType)) {
|
||||
return undefined;
|
||||
}
|
||||
else {
|
||||
return getTypeOfPropertyOfType(attrsType, attrib.name.text);
|
||||
}
|
||||
return getTypeOfPropertyOfType(attrsType, (attribute as JsxAttribute).name.text);
|
||||
}
|
||||
else if (attribute.kind === SyntaxKind.JsxSpreadAttribute) {
|
||||
return attrsType;
|
||||
}
|
||||
|
||||
if (expr.kind === SyntaxKind.JsxSpreadAttribute) {
|
||||
return getJsxElementAttributesType(<JsxOpeningLikeElement>expr.parent);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
Debug.fail(`Expected JsxAttribute or JsxSpreadAttribute, got ts.SyntaxKind[${kind}]`);
|
||||
}
|
||||
|
||||
// Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily
|
||||
@@ -7592,8 +7607,10 @@ namespace ts {
|
||||
case SyntaxKind.ParenthesizedExpression:
|
||||
return getContextualType(<ParenthesizedExpression>parent);
|
||||
case SyntaxKind.JsxExpression:
|
||||
return getContextualType(<JsxExpression>parent);
|
||||
case SyntaxKind.JsxAttribute:
|
||||
case SyntaxKind.JsxSpreadAttribute:
|
||||
return getContextualTypeForJsxExpression(<JsxExpression>parent);
|
||||
return getContextualTypeForJsxAttribute(<JsxAttribute | JsxSpreadAttribute>parent);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
@@ -7981,31 +7998,12 @@ namespace ts {
|
||||
return jsxElementType || anyType;
|
||||
}
|
||||
|
||||
function tagNamesAreEquivalent(lhs: EntityName, rhs: EntityName): boolean {
|
||||
if (lhs.kind !== rhs.kind) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lhs.kind === SyntaxKind.Identifier) {
|
||||
return (<Identifier>lhs).text === (<Identifier>rhs).text;
|
||||
}
|
||||
|
||||
return (<QualifiedName>lhs).right.text === (<QualifiedName>rhs).right.text &&
|
||||
tagNamesAreEquivalent((<QualifiedName>lhs).left, (<QualifiedName>rhs).left);
|
||||
}
|
||||
|
||||
function checkJsxElement(node: JsxElement) {
|
||||
// Check attributes
|
||||
checkJsxOpeningLikeElement(node.openingElement);
|
||||
|
||||
// Check that the closing tag matches
|
||||
if (!tagNamesAreEquivalent(node.openingElement.tagName, node.closingElement.tagName)) {
|
||||
error(node.closingElement, Diagnostics.Expected_corresponding_JSX_closing_tag_for_0, getTextOfNode(node.openingElement.tagName));
|
||||
}
|
||||
else {
|
||||
// Perform resolution on the closing tag so that rename/go to definition/etc work
|
||||
getJsxElementTagSymbol(node.closingElement);
|
||||
}
|
||||
// Perform resolution on the closing tag so that rename/go to definition/etc work
|
||||
getJsxElementTagSymbol(node.closingElement);
|
||||
|
||||
// Check children
|
||||
for (const child of node.children) {
|
||||
@@ -8158,6 +8156,7 @@ namespace ts {
|
||||
if (compilerOptions.noImplicitAny) {
|
||||
error(node, Diagnostics.JSX_element_implicitly_has_type_any_because_no_interface_JSX_0_exists, JsxNames.IntrinsicElements);
|
||||
}
|
||||
return unknownSymbol;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8406,14 +8405,13 @@ namespace ts {
|
||||
checkGrammarJsxElement(node);
|
||||
checkJsxPreconditions(node);
|
||||
|
||||
// If we're compiling under --jsx react, the symbol 'React' should
|
||||
// be marked as 'used' so we don't incorrectly elide its import. And if there
|
||||
// is no 'React' symbol in scope, we should issue an error.
|
||||
if (compilerOptions.jsx === JsxEmit.React) {
|
||||
const reactSym = resolveName(node.tagName, "React", SymbolFlags.Value, Diagnostics.Cannot_find_name_0, "React");
|
||||
if (reactSym) {
|
||||
getSymbolLinks(reactSym).referenced = true;
|
||||
}
|
||||
// The reactNamespace symbol should be marked as 'used' so we don't incorrectly elide its import. And if there
|
||||
// is no reactNamespace symbol in scope when targeting React emit, we should issue an error.
|
||||
const reactRefErr = compilerOptions.jsx === JsxEmit.React ? Diagnostics.Cannot_find_name_0 : undefined;
|
||||
const reactNamespace = compilerOptions.reactNamespace ? compilerOptions.reactNamespace : "React";
|
||||
const reactSym = resolveName(node.tagName, reactNamespace, SymbolFlags.Value, reactRefErr, reactNamespace);
|
||||
if (reactSym) {
|
||||
getSymbolLinks(reactSym).referenced = true;
|
||||
}
|
||||
|
||||
const targetAttributesType = getJsxElementAttributesType(node);
|
||||
@@ -8611,6 +8609,56 @@ namespace ts {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the symbol of the for-in variable declared or referenced by the given for-in statement.
|
||||
*/
|
||||
function getForInVariableSymbol(node: ForInStatement): Symbol {
|
||||
const initializer = node.initializer;
|
||||
if (initializer.kind === SyntaxKind.VariableDeclarationList) {
|
||||
const variable = (<VariableDeclarationList>initializer).declarations[0];
|
||||
if (variable && !isBindingPattern(variable.name)) {
|
||||
return getSymbolOfNode(variable);
|
||||
}
|
||||
}
|
||||
else if (initializer.kind === SyntaxKind.Identifier) {
|
||||
return getResolvedSymbol(<Identifier>initializer);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the given type is considered to have numeric property names.
|
||||
*/
|
||||
function hasNumericPropertyNames(type: Type) {
|
||||
return getIndexTypeOfType(type, IndexKind.Number) && !getIndexTypeOfType(type, IndexKind.String);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if given node is an expression consisting of an identifier (possibly parenthesized)
|
||||
* that references a for-in variable for an object with numeric property names.
|
||||
*/
|
||||
function isForInVariableForNumericPropertyNames(expr: Expression) {
|
||||
const e = skipParenthesizedNodes(expr);
|
||||
if (e.kind === SyntaxKind.Identifier) {
|
||||
const symbol = getResolvedSymbol(<Identifier>e);
|
||||
if (symbol.flags & SymbolFlags.Variable) {
|
||||
let child: Node = expr;
|
||||
let node = expr.parent;
|
||||
while (node) {
|
||||
if (node.kind === SyntaxKind.ForInStatement &&
|
||||
child === (<ForInStatement>node).statement &&
|
||||
getForInVariableSymbol(<ForInStatement>node) === symbol &&
|
||||
hasNumericPropertyNames(checkExpression((<ForInStatement>node).expression))) {
|
||||
return true;
|
||||
}
|
||||
child = node;
|
||||
node = node.parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function checkIndexedAccess(node: ElementAccessExpression): Type {
|
||||
// Grammar checking
|
||||
if (!node.argumentExpression) {
|
||||
@@ -8671,7 +8719,7 @@ namespace ts {
|
||||
if (isTypeAnyOrAllConstituentTypesHaveKind(indexType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbol)) {
|
||||
|
||||
// Try to use a number indexer.
|
||||
if (isTypeAnyOrAllConstituentTypesHaveKind(indexType, TypeFlags.NumberLike)) {
|
||||
if (isTypeAnyOrAllConstituentTypesHaveKind(indexType, TypeFlags.NumberLike) || isForInVariableForNumericPropertyNames(node.argumentExpression)) {
|
||||
const numberIndexType = getIndexTypeOfType(objectType, IndexKind.Number);
|
||||
if (numberIndexType) {
|
||||
return numberIndexType;
|
||||
@@ -8686,7 +8734,9 @@ namespace ts {
|
||||
|
||||
// Fall back to any.
|
||||
if (compilerOptions.noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors && !isTypeAny(objectType)) {
|
||||
error(node, Diagnostics.Index_signature_of_object_type_implicitly_has_an_any_type);
|
||||
error(node, getIndexTypeOfType(objectType, IndexKind.Number) ?
|
||||
Diagnostics.Element_implicitly_has_an_any_type_because_index_expression_is_not_of_type_number :
|
||||
Diagnostics.Index_signature_of_object_type_implicitly_has_an_any_type);
|
||||
}
|
||||
|
||||
return anyType;
|
||||
@@ -12745,7 +12795,8 @@ namespace ts {
|
||||
}
|
||||
// For a binding pattern, validate the initializer and exit
|
||||
if (isBindingPattern(node.name)) {
|
||||
if (node.initializer) {
|
||||
// Don't validate for-in initializer as it is already an error
|
||||
if (node.initializer && node.parent.parent.kind !== SyntaxKind.ForInStatement) {
|
||||
checkTypeAssignableTo(checkExpressionCached(node.initializer), getWidenedTypeForVariableLikeDeclaration(node), node, /*headMessage*/ undefined);
|
||||
checkParameterInitializer(node);
|
||||
}
|
||||
@@ -12755,7 +12806,8 @@ namespace ts {
|
||||
const type = getTypeOfVariableOrParameterOrProperty(symbol);
|
||||
if (node === symbol.valueDeclaration) {
|
||||
// Node is the primary declaration of the symbol, just validate the initializer
|
||||
if (node.initializer) {
|
||||
// Don't validate for-in initializer as it is already an error
|
||||
if (node.initializer && node.parent.parent.kind !== SyntaxKind.ForInStatement) {
|
||||
checkTypeAssignableTo(checkExpressionCached(node.initializer), type, node, /*headMessage*/ undefined);
|
||||
checkParameterInitializer(node);
|
||||
}
|
||||
@@ -13884,7 +13936,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (autoValue !== undefined) {
|
||||
getNodeLinks(member).enumMemberValue = autoValue++;
|
||||
getNodeLinks(member).enumMemberValue = autoValue;
|
||||
autoValue++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14446,7 +14499,16 @@ namespace ts {
|
||||
function checkExportSpecifier(node: ExportSpecifier) {
|
||||
checkAliasSymbol(node);
|
||||
if (!(<ExportDeclaration>node.parent.parent).moduleSpecifier) {
|
||||
markExportAsReferenced(node);
|
||||
const exportedName = node.propertyName || node.name;
|
||||
// find immediate value referenced by exported name (SymbolFlags.Alias is set so we don't chase down aliases)
|
||||
const symbol = resolveName(exportedName, exportedName.text, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias,
|
||||
/*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined);
|
||||
if (symbol && isGlobalSourceFile(getDeclarationContainer(symbol.declarations[0]))) {
|
||||
error(exportedName, Diagnostics.Cannot_re_export_name_that_is_not_defined_in_the_module);
|
||||
}
|
||||
else {
|
||||
markExportAsReferenced(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,11 @@ namespace ts {
|
||||
description: Diagnostics.Specify_JSX_code_generation_Colon_preserve_or_react,
|
||||
error: Diagnostics.Argument_for_jsx_must_be_preserve_or_react
|
||||
},
|
||||
{
|
||||
name: "reactNamespace",
|
||||
type: "string",
|
||||
description: Diagnostics.Specifies_the_object_invoked_for_createElement_and_spread_when_targeting_react_JSX_emit
|
||||
},
|
||||
{
|
||||
name: "listFiles",
|
||||
type: "boolean",
|
||||
@@ -334,7 +339,8 @@ namespace ts {
|
||||
function parseStrings(args: string[]) {
|
||||
let i = 0;
|
||||
while (i < args.length) {
|
||||
let s = args[i++];
|
||||
let s = args[i];
|
||||
i++;
|
||||
if (s.charCodeAt(0) === CharacterCodes.at) {
|
||||
parseResponseFile(s.slice(1));
|
||||
}
|
||||
@@ -356,18 +362,21 @@ namespace ts {
|
||||
|
||||
switch (opt.type) {
|
||||
case "number":
|
||||
options[opt.name] = parseInt(args[i++]);
|
||||
options[opt.name] = parseInt(args[i]);
|
||||
i++;
|
||||
break;
|
||||
case "boolean":
|
||||
options[opt.name] = true;
|
||||
break;
|
||||
case "string":
|
||||
options[opt.name] = args[i++] || "";
|
||||
options[opt.name] = args[i] || "";
|
||||
i++;
|
||||
break;
|
||||
// If not a primitive, the possible types are specified in what is effectively a map of options.
|
||||
default:
|
||||
let map = <Map<number>>opt.type;
|
||||
let key = (args[i++] || "").toLowerCase();
|
||||
let key = (args[i] || "").toLowerCase();
|
||||
i++;
|
||||
if (hasProperty(map, key)) {
|
||||
options[opt.name] = map[key];
|
||||
}
|
||||
|
||||
@@ -244,9 +244,11 @@ namespace ts {
|
||||
const count = array.length;
|
||||
if (count > 0) {
|
||||
let pos = 0;
|
||||
let result = arguments.length <= 2 ? array[pos++] : initial;
|
||||
let result = arguments.length <= 2 ? array[pos] : initial;
|
||||
pos++;
|
||||
while (pos < count) {
|
||||
result = f(<U>result, array[pos++]);
|
||||
result = f(<U>result, array[pos]);
|
||||
pos++;
|
||||
}
|
||||
return <U>result;
|
||||
}
|
||||
@@ -260,9 +262,11 @@ namespace ts {
|
||||
if (array) {
|
||||
let pos = array.length - 1;
|
||||
if (pos >= 0) {
|
||||
let result = arguments.length <= 2 ? array[pos--] : initial;
|
||||
let result = arguments.length <= 2 ? array[pos] : initial;
|
||||
pos--;
|
||||
while (pos >= 0) {
|
||||
result = f(<U>result, array[pos--]);
|
||||
result = f(<U>result, array[pos]);
|
||||
pos--;
|
||||
}
|
||||
return <U>result;
|
||||
}
|
||||
|
||||
@@ -511,7 +511,8 @@ namespace ts {
|
||||
}
|
||||
let count = 0;
|
||||
while (true) {
|
||||
const name = baseName + "_" + (++count);
|
||||
count++;
|
||||
const name = baseName + "_" + count;
|
||||
if (!hasProperty(currentIdentifiers, name)) {
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -1771,34 +1771,38 @@
|
||||
"category": "Error",
|
||||
"code": 2660
|
||||
},
|
||||
"Invalid module name in augmentation, module '{0}' cannot be found.": {
|
||||
"Cannot re-export name that is not defined in the module.": {
|
||||
"category": "Error",
|
||||
"code": 2661
|
||||
},
|
||||
"Module augmentation cannot introduce new names in the top level scope.": {
|
||||
"Invalid module name in augmentation, module '{0}' cannot be found.": {
|
||||
"category": "Error",
|
||||
"code": 2662
|
||||
},
|
||||
"Exports are not permitted in module augmentations.": {
|
||||
"Module augmentation cannot introduce new names in the top level scope.": {
|
||||
"category": "Error",
|
||||
"code": 2663
|
||||
},
|
||||
"Imports are not permitted in module augmentations. Consider moving them to the enclosing external module.": {
|
||||
"Exports are not permitted in module augmentations.": {
|
||||
"category": "Error",
|
||||
"code": 2664
|
||||
},
|
||||
"'export' modifier cannot be applied to ambient modules and module augmentations since they are always visible.": {
|
||||
"Imports are not permitted in module augmentations. Consider moving them to the enclosing external module.": {
|
||||
"category": "Error",
|
||||
"code": 2665
|
||||
},
|
||||
"Augmentations for the global scope can only be directly nested in external modules or ambient module declarations.": {
|
||||
"'export' modifier cannot be applied to ambient modules and module augmentations since they are always visible.": {
|
||||
"category": "Error",
|
||||
"code": 2666
|
||||
},
|
||||
"Augmentations for the global scope should have 'declare' modifier unless they appear in already ambient context.": {
|
||||
"Augmentations for the global scope can only be directly nested in external modules or ambient module declarations.": {
|
||||
"category": "Error",
|
||||
"code": 2667
|
||||
},
|
||||
"Augmentations for the global scope should have 'declare' modifier unless they appear in already ambient context.": {
|
||||
"category": "Error",
|
||||
"code": 2668
|
||||
},
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
"code": 4000
|
||||
@@ -2151,6 +2155,10 @@
|
||||
"category": "Error",
|
||||
"code": 5058
|
||||
},
|
||||
"Invalide value for '--reactNamespace'. '{0}' is not a valid identifier.": {
|
||||
"category": "Error",
|
||||
"code": 5059
|
||||
},
|
||||
|
||||
"Concatenate and emit output to single file.": {
|
||||
"category": "Message",
|
||||
@@ -2421,6 +2429,10 @@
|
||||
"category": "Message",
|
||||
"code": 6083
|
||||
},
|
||||
"Specifies the object invoked for createElement and __spread when targeting 'react' JSX emit": {
|
||||
"category": "Message",
|
||||
"code": 6084
|
||||
},
|
||||
|
||||
"Variable '{0}' implicitly has an '{1}' type.": {
|
||||
"category": "Error",
|
||||
@@ -2450,6 +2462,10 @@
|
||||
"category": "Error",
|
||||
"code": 7013
|
||||
},
|
||||
"Element implicitly has an 'any' type because index expression is not of type 'number'.": {
|
||||
"category": "Error",
|
||||
"code": 7015
|
||||
},
|
||||
"Property '{0}' implicitly has type 'any', because its 'set' accessor lacks a type annotation.": {
|
||||
"category": "Error",
|
||||
"code": 7016
|
||||
@@ -2614,5 +2630,9 @@
|
||||
"A type assertion expression is not allowed in the left-hand side of an exponentiation expression. Consider enclosing the expression in parentheses.": {
|
||||
"category": "Error",
|
||||
"code": 17007
|
||||
},
|
||||
"JSX element '{0}' has no corresponding closing tag.": {
|
||||
"category": "Error",
|
||||
"code": 17008
|
||||
}
|
||||
}
|
||||
|
||||
+115
-77
@@ -464,8 +464,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
const writer = createTextWriter(newLine);
|
||||
const { write, writeTextOfNode, writeLine, increaseIndent, decreaseIndent } = writer;
|
||||
|
||||
const sourceMap = compilerOptions.sourceMap || compilerOptions.inlineSourceMap ? createSourceMapWriter(host, writer) : getNullSourceMapWriter();
|
||||
const { setSourceFile, emitStart, emitEnd, emitPos } = sourceMap;
|
||||
let sourceMap = compilerOptions.sourceMap || compilerOptions.inlineSourceMap ? createSourceMapWriter(host, writer) : getNullSourceMapWriter();
|
||||
let { setSourceFile, emitStart, emitEnd, emitPos } = sourceMap;
|
||||
|
||||
let currentSourceFile: SourceFile;
|
||||
let currentText: string;
|
||||
@@ -512,6 +512,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
/** If removeComments is true, no leading-comments needed to be emitted **/
|
||||
const emitLeadingCommentsOfPosition = compilerOptions.removeComments ? function (pos: number) { } : emitLeadingCommentsOfPositionWorker;
|
||||
|
||||
const setSourceMapWriterEmit = compilerOptions.sourceMap || compilerOptions.inlineSourceMap ? changeSourceMapEmit : function (writer: SourceMapWriter) { };
|
||||
|
||||
const moduleEmitDelegates: Map<(node: SourceFile, emitRelativePathAsModuleName?: boolean) => void> = {
|
||||
[ModuleKind.ES6]: emitES6Module,
|
||||
[ModuleKind.AMD]: emitAMDModule,
|
||||
@@ -1186,7 +1188,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
|
||||
function emitJsxElement(openingNode: JsxOpeningLikeElement, children?: JsxChild[]) {
|
||||
const syntheticReactRef = <Identifier>createSynthesizedNode(SyntaxKind.Identifier);
|
||||
syntheticReactRef.text = "React";
|
||||
syntheticReactRef.text = compilerOptions.reactNamespace ? compilerOptions.reactNamespace : "React";
|
||||
syntheticReactRef.parent = openingNode;
|
||||
|
||||
// Call React.createElement(tag, ...
|
||||
@@ -1975,7 +1977,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
result.expression = parenthesizeForAccess(expression);
|
||||
result.dotToken = createSynthesizedNode(SyntaxKind.DotToken);
|
||||
result.name = name;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2568,7 +2569,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
leftHandSideExpression.argumentExpression.kind !== SyntaxKind.StringLiteral) {
|
||||
const tempArgumentExpression = createAndRecordTempVariable(TempFlags._i);
|
||||
(<ElementAccessExpression>synthesizedLHS).argumentExpression = tempArgumentExpression;
|
||||
emitAssignment(tempArgumentExpression, leftHandSideExpression.argumentExpression, /*shouldEmitCommaBeforeAssignment*/ true);
|
||||
emitAssignment(tempArgumentExpression, leftHandSideExpression.argumentExpression, /*shouldEmitCommaBeforeAssignment*/ true, leftHandSideExpression.expression);
|
||||
}
|
||||
else {
|
||||
(<ElementAccessExpression>synthesizedLHS).argumentExpression = leftHandSideExpression.argumentExpression;
|
||||
@@ -2796,7 +2797,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
* Returns false if nothing was written - this can happen for source file level variable declarations
|
||||
* in system modules where such variable declarations are hoisted.
|
||||
*/
|
||||
function tryEmitStartOfVariableDeclarationList(decl: VariableDeclarationList, startPos?: number): boolean {
|
||||
function tryEmitStartOfVariableDeclarationList(decl: VariableDeclarationList): boolean {
|
||||
if (shouldHoistVariable(decl, /*checkIfSourceFileLevelDecl*/ true)) {
|
||||
// variables in variable declaration list were already hoisted
|
||||
return false;
|
||||
@@ -2811,34 +2812,23 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
return false;
|
||||
}
|
||||
|
||||
let tokenKind = SyntaxKind.VarKeyword;
|
||||
emitStart(decl);
|
||||
if (decl && languageVersion >= ScriptTarget.ES6) {
|
||||
if (isLet(decl)) {
|
||||
tokenKind = SyntaxKind.LetKeyword;
|
||||
write("let ");
|
||||
}
|
||||
else if (isConst(decl)) {
|
||||
tokenKind = SyntaxKind.ConstKeyword;
|
||||
write("const ");
|
||||
}
|
||||
else {
|
||||
write("var ");
|
||||
}
|
||||
}
|
||||
|
||||
if (startPos !== undefined) {
|
||||
emitToken(tokenKind, startPos);
|
||||
write(" ");
|
||||
}
|
||||
else {
|
||||
switch (tokenKind) {
|
||||
case SyntaxKind.VarKeyword:
|
||||
write("var ");
|
||||
break;
|
||||
case SyntaxKind.LetKeyword:
|
||||
write("let ");
|
||||
break;
|
||||
case SyntaxKind.ConstKeyword:
|
||||
write("const ");
|
||||
break;
|
||||
}
|
||||
write("var ");
|
||||
}
|
||||
|
||||
// Note here we specifically dont emit end so that if we are going to emit binding pattern
|
||||
// we can alter the source map correctly
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3177,7 +3167,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
endPos = emitToken(SyntaxKind.OpenParenToken, endPos);
|
||||
if (node.initializer && node.initializer.kind === SyntaxKind.VariableDeclarationList) {
|
||||
const variableDeclarationList = <VariableDeclarationList>node.initializer;
|
||||
const startIsEmitted = tryEmitStartOfVariableDeclarationList(variableDeclarationList, endPos);
|
||||
const startIsEmitted = tryEmitStartOfVariableDeclarationList(variableDeclarationList);
|
||||
if (startIsEmitted) {
|
||||
emitCommaList(variableDeclarationList.declarations);
|
||||
}
|
||||
@@ -3218,7 +3208,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
if (node.initializer.kind === SyntaxKind.VariableDeclarationList) {
|
||||
const variableDeclarationList = <VariableDeclarationList>node.initializer;
|
||||
if (variableDeclarationList.declarations.length >= 1) {
|
||||
tryEmitStartOfVariableDeclarationList(variableDeclarationList, endPos);
|
||||
tryEmitStartOfVariableDeclarationList(variableDeclarationList);
|
||||
emit(variableDeclarationList.declarations[0]);
|
||||
}
|
||||
}
|
||||
@@ -3305,21 +3295,21 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
write("; ");
|
||||
|
||||
// _i < _a.length;
|
||||
emitStart(node.initializer);
|
||||
emitStart(node.expression);
|
||||
emitNodeWithoutSourceMap(counter);
|
||||
write(" < ");
|
||||
|
||||
emitNodeWithCommentsAndWithoutSourcemap(rhsReference);
|
||||
write(".length");
|
||||
|
||||
emitEnd(node.initializer);
|
||||
emitEnd(node.expression);
|
||||
write("; ");
|
||||
|
||||
// _i++)
|
||||
emitStart(node.initializer);
|
||||
emitStart(node.expression);
|
||||
emitNodeWithoutSourceMap(counter);
|
||||
write("++");
|
||||
emitEnd(node.initializer);
|
||||
emitEnd(node.expression);
|
||||
emitToken(SyntaxKind.CloseParenToken, node.expression.end);
|
||||
|
||||
// Body
|
||||
@@ -3719,7 +3709,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
* @param value an expression as a right-hand-side operand of the assignment
|
||||
* @param shouldEmitCommaBeforeAssignment a boolean indicating whether to prefix an assignment with comma
|
||||
*/
|
||||
function emitAssignment(name: Identifier, value: Expression, shouldEmitCommaBeforeAssignment: boolean) {
|
||||
function emitAssignment(name: Identifier, value: Expression, shouldEmitCommaBeforeAssignment: boolean, nodeForSourceMap: Node) {
|
||||
if (shouldEmitCommaBeforeAssignment) {
|
||||
write(", ");
|
||||
}
|
||||
@@ -3735,15 +3725,21 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
const isVariableDeclarationOrBindingElement =
|
||||
name.parent && (name.parent.kind === SyntaxKind.VariableDeclaration || name.parent.kind === SyntaxKind.BindingElement);
|
||||
|
||||
if (isVariableDeclarationOrBindingElement) {
|
||||
emitModuleMemberName(<Declaration>name.parent);
|
||||
}
|
||||
else {
|
||||
emit(name);
|
||||
}
|
||||
// If this is first var declaration, we need to start at var/let/const keyword instead
|
||||
// otherwise use nodeForSourceMap as the start position
|
||||
emitStart(isFirstVariableDeclaration(nodeForSourceMap) ? nodeForSourceMap.parent : nodeForSourceMap);
|
||||
withTemporaryNoSourceMap(() => {
|
||||
if (isVariableDeclarationOrBindingElement) {
|
||||
emitModuleMemberName(<Declaration>name.parent);
|
||||
}
|
||||
else {
|
||||
emit(name);
|
||||
}
|
||||
|
||||
write(" = ");
|
||||
emit(value);
|
||||
write(" = ");
|
||||
emit(value);
|
||||
});
|
||||
emitEnd(nodeForSourceMap, /*stopOverridingSpan*/true);
|
||||
|
||||
if (exportChanged) {
|
||||
write(")");
|
||||
@@ -3756,15 +3752,21 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
* @param canDefineTempVariablesInPlace a boolean indicating whether you can define the temporary variable at an assignment location
|
||||
* @param shouldEmitCommaBeforeAssignment a boolean indicating whether an assignment should prefix with comma
|
||||
*/
|
||||
function emitTempVariableAssignment(expression: Expression, canDefineTempVariablesInPlace: boolean, shouldEmitCommaBeforeAssignment: boolean): Identifier {
|
||||
function emitTempVariableAssignment(expression: Expression, canDefineTempVariablesInPlace: boolean, shouldEmitCommaBeforeAssignment: boolean, sourceMapNode?: Node): Identifier {
|
||||
const identifier = createTempVariable(TempFlags.Auto);
|
||||
if (!canDefineTempVariablesInPlace) {
|
||||
recordTempDeclaration(identifier);
|
||||
}
|
||||
emitAssignment(identifier, expression, shouldEmitCommaBeforeAssignment);
|
||||
emitAssignment(identifier, expression, shouldEmitCommaBeforeAssignment, sourceMapNode || expression.parent);
|
||||
return identifier;
|
||||
}
|
||||
|
||||
function isFirstVariableDeclaration(root: Node) {
|
||||
return root.kind === SyntaxKind.VariableDeclaration &&
|
||||
root.parent.kind === SyntaxKind.VariableDeclarationList &&
|
||||
(<VariableDeclarationList>root.parent).declarations[0] === root;
|
||||
}
|
||||
|
||||
function emitDestructuring(root: BinaryExpression | VariableDeclaration | ParameterDeclaration, isAssignmentExpressionStatement: boolean, value?: Expression) {
|
||||
let emitCount = 0;
|
||||
|
||||
@@ -3787,6 +3789,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
}
|
||||
else {
|
||||
Debug.assert(!isAssignmentExpressionStatement);
|
||||
// If first variable declaration of variable statement correct the start location
|
||||
if (isFirstVariableDeclaration(root)) {
|
||||
// Use emit location of "var " as next emit start entry
|
||||
sourceMap.changeEmitSourcePos();
|
||||
}
|
||||
emitBindingElement(<BindingElement>root, value);
|
||||
}
|
||||
|
||||
@@ -3800,20 +3807,21 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
* @param reuseIdentifierExpressions true if identifier expressions can simply be returned;
|
||||
* false if it is necessary to always emit an identifier.
|
||||
*/
|
||||
function ensureIdentifier(expr: Expression, reuseIdentifierExpressions: boolean): Expression {
|
||||
function ensureIdentifier(expr: Expression, reuseIdentifierExpressions: boolean, sourceMapNode: Node): Expression {
|
||||
if (expr.kind === SyntaxKind.Identifier && reuseIdentifierExpressions) {
|
||||
return expr;
|
||||
}
|
||||
|
||||
const identifier = emitTempVariableAssignment(expr, canDefineTempVariablesInPlace, emitCount > 0);
|
||||
const identifier = emitTempVariableAssignment(expr, canDefineTempVariablesInPlace, emitCount > 0, sourceMapNode);
|
||||
emitCount++;
|
||||
return identifier;
|
||||
}
|
||||
|
||||
function createDefaultValueCheck(value: Expression, defaultValue: Expression): Expression {
|
||||
function createDefaultValueCheck(value: Expression, defaultValue: Expression, sourceMapNode: Node): Expression {
|
||||
// The value expression will be evaluated twice, so for anything but a simple identifier
|
||||
// we need to generate a temporary variable
|
||||
value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true);
|
||||
// If the temporary variable needs to be emitted use the source Map node for assignment of that statement
|
||||
value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, sourceMapNode);
|
||||
// Return the expression 'value === void 0 ? defaultValue : value'
|
||||
const equals = <BinaryExpression>createSynthesizedNode(SyntaxKind.BinaryExpression);
|
||||
equals.left = value;
|
||||
@@ -3842,7 +3850,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
let index: Expression;
|
||||
const nameIsComputed = propName.kind === SyntaxKind.ComputedPropertyName;
|
||||
if (nameIsComputed) {
|
||||
index = ensureIdentifier((<ComputedPropertyName>propName).expression, /*reuseIdentifierExpressions*/ false);
|
||||
// TODO to handle when we look into sourcemaps for computed properties, for now use propName
|
||||
index = ensureIdentifier((<ComputedPropertyName>propName).expression, /*reuseIdentifierExpressions*/ false, propName);
|
||||
}
|
||||
else {
|
||||
// We create a synthetic copy of the identifier in order to avoid the rewriting that might
|
||||
@@ -3866,61 +3875,66 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
return call;
|
||||
}
|
||||
|
||||
function emitObjectLiteralAssignment(target: ObjectLiteralExpression, value: Expression) {
|
||||
function emitObjectLiteralAssignment(target: ObjectLiteralExpression, value: Expression, sourceMapNode: Node) {
|
||||
const properties = target.properties;
|
||||
if (properties.length !== 1) {
|
||||
// For anything but a single element destructuring we need to generate a temporary
|
||||
// to ensure value is evaluated exactly once.
|
||||
value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true);
|
||||
// When doing so we want to hightlight the passed in source map node since thats the one needing this temp assignment
|
||||
value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, sourceMapNode);
|
||||
}
|
||||
for (const p of properties) {
|
||||
if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) {
|
||||
const propName = <Identifier | LiteralExpression>(<PropertyAssignment>p).name;
|
||||
const target = p.kind === SyntaxKind.ShorthandPropertyAssignment ? <ShorthandPropertyAssignment>p : (<PropertyAssignment>p).initializer || propName;
|
||||
emitDestructuringAssignment(target, createPropertyAccessForDestructuringProperty(value, propName));
|
||||
// Assignment for target = value.propName should highligh whole property, hence use p as source map node
|
||||
emitDestructuringAssignment(target, createPropertyAccessForDestructuringProperty(value, propName), p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function emitArrayLiteralAssignment(target: ArrayLiteralExpression, value: Expression) {
|
||||
function emitArrayLiteralAssignment(target: ArrayLiteralExpression, value: Expression, sourceMapNode: Node) {
|
||||
const elements = target.elements;
|
||||
if (elements.length !== 1) {
|
||||
// For anything but a single element destructuring we need to generate a temporary
|
||||
// to ensure value is evaluated exactly once.
|
||||
value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true);
|
||||
// When doing so we want to hightlight the passed in source map node since thats the one needing this temp assignment
|
||||
value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, sourceMapNode);
|
||||
}
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
const e = elements[i];
|
||||
if (e.kind !== SyntaxKind.OmittedExpression) {
|
||||
// Assignment for target = value.propName should highligh whole property, hence use e as source map node
|
||||
if (e.kind !== SyntaxKind.SpreadElementExpression) {
|
||||
emitDestructuringAssignment(e, createElementAccessExpression(value, createNumericLiteral(i)));
|
||||
emitDestructuringAssignment(e, createElementAccessExpression(value, createNumericLiteral(i)), e);
|
||||
}
|
||||
else if (i === elements.length - 1) {
|
||||
emitDestructuringAssignment((<SpreadElementExpression>e).expression, createSliceCall(value, i));
|
||||
emitDestructuringAssignment((<SpreadElementExpression>e).expression, createSliceCall(value, i), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function emitDestructuringAssignment(target: Expression | ShorthandPropertyAssignment, value: Expression) {
|
||||
function emitDestructuringAssignment(target: Expression | ShorthandPropertyAssignment, value: Expression, sourceMapNode: Node) {
|
||||
// When emitting target = value use source map node to highlight, including any temporary assignments needed for this
|
||||
if (target.kind === SyntaxKind.ShorthandPropertyAssignment) {
|
||||
if ((<ShorthandPropertyAssignment>target).objectAssignmentInitializer) {
|
||||
value = createDefaultValueCheck(value, (<ShorthandPropertyAssignment>target).objectAssignmentInitializer);
|
||||
value = createDefaultValueCheck(value, (<ShorthandPropertyAssignment>target).objectAssignmentInitializer, sourceMapNode);
|
||||
}
|
||||
target = (<ShorthandPropertyAssignment>target).name;
|
||||
}
|
||||
else if (target.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>target).operatorToken.kind === SyntaxKind.EqualsToken) {
|
||||
value = createDefaultValueCheck(value, (<BinaryExpression>target).right);
|
||||
value = createDefaultValueCheck(value, (<BinaryExpression>target).right, sourceMapNode);
|
||||
target = (<BinaryExpression>target).left;
|
||||
}
|
||||
if (target.kind === SyntaxKind.ObjectLiteralExpression) {
|
||||
emitObjectLiteralAssignment(<ObjectLiteralExpression>target, value);
|
||||
emitObjectLiteralAssignment(<ObjectLiteralExpression>target, value, sourceMapNode);
|
||||
}
|
||||
else if (target.kind === SyntaxKind.ArrayLiteralExpression) {
|
||||
emitArrayLiteralAssignment(<ArrayLiteralExpression>target, value);
|
||||
emitArrayLiteralAssignment(<ArrayLiteralExpression>target, value, sourceMapNode);
|
||||
}
|
||||
else {
|
||||
emitAssignment(<Identifier>target, value, /*shouldEmitCommaBeforeAssignment*/ emitCount > 0);
|
||||
emitAssignment(<Identifier>target, value, /*shouldEmitCommaBeforeAssignment*/ emitCount > 0, sourceMapNode);
|
||||
emitCount++;
|
||||
}
|
||||
}
|
||||
@@ -3933,14 +3947,20 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
emit(value);
|
||||
}
|
||||
else if (isAssignmentExpressionStatement) {
|
||||
emitDestructuringAssignment(target, value);
|
||||
// Source map node for root.left = root.right is root
|
||||
// but if root is synthetic, which could be in below case, use the target which is { a }
|
||||
// for ({a} of {a: string}) {
|
||||
// }
|
||||
emitDestructuringAssignment(target, value, nodeIsSynthesized(root) ? target : root);
|
||||
}
|
||||
else {
|
||||
if (root.parent.kind !== SyntaxKind.ParenthesizedExpression) {
|
||||
write("(");
|
||||
}
|
||||
value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true);
|
||||
emitDestructuringAssignment(target, value);
|
||||
// Temporary assignment needed to emit root should highlight whole binary expression
|
||||
value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ true, root);
|
||||
// Source map node for root.left = root.right is root
|
||||
emitDestructuringAssignment(target, value, root);
|
||||
write(", ");
|
||||
emit(value);
|
||||
if (root.parent.kind !== SyntaxKind.ParenthesizedExpression) {
|
||||
@@ -3950,9 +3970,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
}
|
||||
|
||||
function emitBindingElement(target: BindingElement | VariableDeclaration, value: Expression) {
|
||||
// Any temporary assignments needed to emit target = value should point to target
|
||||
if (target.initializer) {
|
||||
// Combine value and initializer
|
||||
value = value ? createDefaultValueCheck(value, target.initializer) : target.initializer;
|
||||
value = value ? createDefaultValueCheck(value, target.initializer, target) : target.initializer;
|
||||
}
|
||||
else if (!value) {
|
||||
// Use 'void 0' in absence of value and initializer
|
||||
@@ -3968,7 +3989,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
// 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.
|
||||
value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ numElements !== 0);
|
||||
value = ensureIdentifier(value, /*reuseIdentifierExpressions*/ numElements !== 0, target);
|
||||
}
|
||||
|
||||
for (let i = 0; i < numElements; i++) {
|
||||
@@ -3990,7 +4011,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
}
|
||||
}
|
||||
else {
|
||||
emitAssignment(<Identifier>target.name, value, /*shouldEmitCommaBeforeAssignment*/ emitCount > 0);
|
||||
emitAssignment(<Identifier>target.name, value, /*shouldEmitCommaBeforeAssignment*/ emitCount > 0, target);
|
||||
emitCount++;
|
||||
}
|
||||
}
|
||||
@@ -5464,7 +5485,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
});
|
||||
leadingComma = true;
|
||||
}
|
||||
++parameterIndex;
|
||||
parameterIndex++;
|
||||
}
|
||||
}
|
||||
return argumentsWritten;
|
||||
@@ -6488,7 +6509,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
|
||||
let started = false;
|
||||
if (exportedDeclarations) {
|
||||
for (let i = 0; i < exportedDeclarations.length; ++i) {
|
||||
for (let i = 0; i < exportedDeclarations.length; i++) {
|
||||
// write name of exported declaration, i.e 'export var x...'
|
||||
writeExportedName(exportedDeclarations[i]);
|
||||
}
|
||||
@@ -6604,7 +6625,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
writeLine();
|
||||
write("var ");
|
||||
const seen: Map<string> = {};
|
||||
for (let i = 0; i < hoistedVars.length; ++i) {
|
||||
for (let i = 0; i < hoistedVars.length; i++) {
|
||||
const local = hoistedVars[i];
|
||||
const name = local.kind === SyntaxKind.Identifier
|
||||
? <Identifier>local
|
||||
@@ -6816,7 +6837,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
function emitSetters(exportStarFunction: string, dependencyGroups: DependencyGroup[]) {
|
||||
write("setters:[");
|
||||
|
||||
for (let i = 0; i < dependencyGroups.length; ++i) {
|
||||
for (let i = 0; i < dependencyGroups.length; i++) {
|
||||
if (i !== 0) {
|
||||
write(",");
|
||||
}
|
||||
@@ -6864,7 +6885,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
write(`${exportFunctionForFile}({`);
|
||||
writeLine();
|
||||
increaseIndent();
|
||||
for (let i = 0, len = (<ExportDeclaration>entry).exportClause.elements.length; i < len; ++i) {
|
||||
for (let i = 0, len = (<ExportDeclaration>entry).exportClause.elements.length; i < len; i++) {
|
||||
if (i !== 0) {
|
||||
write(",");
|
||||
writeLine();
|
||||
@@ -6909,7 +6930,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
write("execute: function() {");
|
||||
increaseIndent();
|
||||
writeLine();
|
||||
for (let i = startIndex; i < node.statements.length; ++i) {
|
||||
for (let i = startIndex; i < node.statements.length; i++) {
|
||||
const statement = node.statements[i];
|
||||
switch (statement.kind) {
|
||||
// - function declarations are not emitted because they were already hoisted
|
||||
@@ -6971,7 +6992,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
const groupIndices: Map<number> = {};
|
||||
const dependencyGroups: DependencyGroup[] = [];
|
||||
|
||||
for (let i = 0; i < externalImports.length; ++i) {
|
||||
for (let i = 0; i < externalImports.length; i++) {
|
||||
const text = getExternalModuleNameText(externalImports[i], emitRelativePathAsModuleName);
|
||||
if (hasProperty(groupIndices, text)) {
|
||||
// deduplicate/group entries in dependency list by the dependency name
|
||||
@@ -7221,7 +7242,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
// Replace entities like
|
||||
result = result.replace(/&(\w+);/g, function(s: any, m: string) {
|
||||
if (entities[m] !== undefined) {
|
||||
return String.fromCharCode(entities[m]);
|
||||
const ch = String.fromCharCode(entities[m]);
|
||||
// " needs to be escaped
|
||||
return ch === "\"" ? "\\\"" : ch;
|
||||
}
|
||||
else {
|
||||
return s;
|
||||
@@ -7294,7 +7317,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
|
||||
function emitDirectivePrologues(statements: Node[], startWithNewLine: boolean, ensureUseStrict?: boolean): number {
|
||||
let foundUseStrict = false;
|
||||
for (let i = 0; i < statements.length; ++i) {
|
||||
for (let i = 0; i < statements.length; i++) {
|
||||
if (isPrologueDirective(statements[i])) {
|
||||
if (isUseStrictPrologue(statements[i] as ExpressionStatement)) {
|
||||
foundUseStrict = true;
|
||||
@@ -7316,7 +7339,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
|
||||
function writeLines(text: string): void {
|
||||
const lines = text.split(/\r\n|\r|\n/g);
|
||||
for (let i = 0; i < lines.length; ++i) {
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i];
|
||||
if (line.length) {
|
||||
writeLine();
|
||||
@@ -7432,6 +7455,21 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
|
||||
}
|
||||
}
|
||||
|
||||
function changeSourceMapEmit(writer: SourceMapWriter) {
|
||||
sourceMap = writer;
|
||||
emitStart = writer.emitStart;
|
||||
emitEnd = writer.emitEnd;
|
||||
emitPos = writer.emitPos;
|
||||
setSourceFile = writer.setSourceFile;
|
||||
}
|
||||
|
||||
function withTemporaryNoSourceMap(callback: () => void) {
|
||||
const prevSourceMap = sourceMap;
|
||||
setSourceMapWriterEmit(getNullSourceMapWriter());
|
||||
callback();
|
||||
setSourceMapWriterEmit(prevSourceMap);
|
||||
}
|
||||
|
||||
function isSpecializedCommentHandling(node: Node): boolean {
|
||||
switch (node.kind) {
|
||||
// All of these entities are emitted in a specialized fashion. As such, we allow
|
||||
|
||||
+23
-1
@@ -3497,6 +3497,20 @@ namespace ts {
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function tagNamesAreEquivalent(lhs: EntityName, rhs: EntityName): boolean {
|
||||
if (lhs.kind !== rhs.kind) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lhs.kind === SyntaxKind.Identifier) {
|
||||
return (<Identifier>lhs).text === (<Identifier>rhs).text;
|
||||
}
|
||||
|
||||
return (<QualifiedName>lhs).right.text === (<QualifiedName>rhs).right.text &&
|
||||
tagNamesAreEquivalent((<QualifiedName>lhs).left, (<QualifiedName>rhs).left);
|
||||
}
|
||||
|
||||
|
||||
function parseJsxElementOrSelfClosingElement(inExpressionContext: boolean): JsxElement | JsxSelfClosingElement {
|
||||
const opening = parseJsxOpeningOrSelfClosingElement(inExpressionContext);
|
||||
let result: JsxElement | JsxSelfClosingElement;
|
||||
@@ -3506,6 +3520,11 @@ namespace ts {
|
||||
|
||||
node.children = parseJsxChildren(node.openingElement.tagName);
|
||||
node.closingElement = parseJsxClosingElement(inExpressionContext);
|
||||
|
||||
if (!tagNamesAreEquivalent(node.openingElement.tagName, node.closingElement.tagName)) {
|
||||
parseErrorAtPosition(node.closingElement.pos, node.closingElement.end - node.closingElement.pos, Diagnostics.Expected_corresponding_JSX_closing_tag_for_0, getTextOfNodeFromSourceText(sourceText, node.openingElement.tagName));
|
||||
}
|
||||
|
||||
result = finishNode(node);
|
||||
}
|
||||
else {
|
||||
@@ -3565,10 +3584,13 @@ namespace ts {
|
||||
while (true) {
|
||||
token = scanner.reScanJsxToken();
|
||||
if (token === SyntaxKind.LessThanSlashToken) {
|
||||
// Closing tag
|
||||
break;
|
||||
}
|
||||
else if (token === SyntaxKind.EndOfFileToken) {
|
||||
parseErrorAtCurrentToken(Diagnostics.Expected_corresponding_JSX_closing_tag_for_0, getTextOfNodeFromSourceText(sourceText, openingTagName));
|
||||
// If we hit EOF, issue the error at the tag that lacks the closing element
|
||||
// rather than at the end of the file (which is useless)
|
||||
parseErrorAtPosition(openingTagName.pos, openingTagName.end - openingTagName.pos, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, openingTagName));
|
||||
break;
|
||||
}
|
||||
result.push(parseJsxChild());
|
||||
|
||||
+31
-13
@@ -53,13 +53,13 @@ namespace ts {
|
||||
if (getRootLength(moduleName) !== 0 || nameStartsWithDotSlashOrDotDotSlash(moduleName)) {
|
||||
const failedLookupLocations: string[] = [];
|
||||
const candidate = normalizePath(combinePaths(containingDirectory, moduleName));
|
||||
let resolvedFileName = loadNodeModuleFromFile(supportedExtensions, candidate, failedLookupLocations, host);
|
||||
let resolvedFileName = loadNodeModuleFromFile(supportedExtensions, candidate, failedLookupLocations, /*onlyRecordFailures*/ false, host);
|
||||
|
||||
if (resolvedFileName) {
|
||||
return { resolvedModule: { resolvedFileName }, failedLookupLocations };
|
||||
}
|
||||
|
||||
resolvedFileName = loadNodeModuleFromDirectory(supportedExtensions, candidate, failedLookupLocations, host);
|
||||
resolvedFileName = loadNodeModuleFromDirectory(supportedExtensions, candidate, failedLookupLocations, /*onlyRecordFailures*/ false, host);
|
||||
return resolvedFileName
|
||||
? { resolvedModule: { resolvedFileName }, failedLookupLocations }
|
||||
: { resolvedModule: undefined, failedLookupLocations };
|
||||
@@ -69,12 +69,22 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function loadNodeModuleFromFile(extensions: string[], candidate: string, failedLookupLocation: string[], host: ModuleResolutionHost): string {
|
||||
/* @internal */
|
||||
export function directoryProbablyExists(directoryName: string, host: { directoryExists?: (directoryName: string) => boolean } ): boolean {
|
||||
// if host does not support 'directoryExists' assume that directory will exist
|
||||
return !host.directoryExists || host.directoryExists(directoryName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 loadNodeModuleFromFile(extensions: string[], candidate: string, failedLookupLocation: string[], onlyRecordFailures: boolean, host: ModuleResolutionHost): string {
|
||||
return forEach(extensions, tryLoad);
|
||||
|
||||
function tryLoad(ext: string): string {
|
||||
const fileName = fileExtensionIs(candidate, ext) ? candidate : candidate + ext;
|
||||
if (host.fileExists(fileName)) {
|
||||
if (!onlyRecordFailures && host.fileExists(fileName)) {
|
||||
return fileName;
|
||||
}
|
||||
else {
|
||||
@@ -84,9 +94,10 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function loadNodeModuleFromDirectory(extensions: string[], candidate: string, failedLookupLocation: string[], host: ModuleResolutionHost): string {
|
||||
function loadNodeModuleFromDirectory(extensions: string[], candidate: string, failedLookupLocation: string[], onlyRecordFailures: boolean, host: ModuleResolutionHost): string {
|
||||
const packageJsonPath = combinePaths(candidate, "package.json");
|
||||
if (host.fileExists(packageJsonPath)) {
|
||||
const directoryExists = !onlyRecordFailures && directoryProbablyExists(candidate, host);
|
||||
if (directoryExists && host.fileExists(packageJsonPath)) {
|
||||
|
||||
let jsonContent: { typings?: string };
|
||||
|
||||
@@ -100,7 +111,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (typeof jsonContent.typings === "string") {
|
||||
const result = loadNodeModuleFromFile(extensions, normalizePath(combinePaths(candidate, jsonContent.typings)), failedLookupLocation, host);
|
||||
const path = normalizePath(combinePaths(candidate, jsonContent.typings));
|
||||
const result = loadNodeModuleFromFile(extensions, path, failedLookupLocation, !directoryProbablyExists(getDirectoryPath(path), host), host);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
@@ -111,7 +123,7 @@ namespace ts {
|
||||
failedLookupLocation.push(packageJsonPath);
|
||||
}
|
||||
|
||||
return loadNodeModuleFromFile(extensions, combinePaths(candidate, "index"), failedLookupLocation, host);
|
||||
return loadNodeModuleFromFile(extensions, combinePaths(candidate, "index"), failedLookupLocation, !directoryExists, host);
|
||||
}
|
||||
|
||||
function loadModuleFromNodeModules(moduleName: string, directory: string, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations {
|
||||
@@ -121,14 +133,15 @@ namespace ts {
|
||||
const baseName = getBaseFileName(directory);
|
||||
if (baseName !== "node_modules") {
|
||||
const nodeModulesFolder = combinePaths(directory, "node_modules");
|
||||
const nodeModulesFolderExists = directoryProbablyExists(nodeModulesFolder, host);
|
||||
const candidate = normalizePath(combinePaths(nodeModulesFolder, moduleName));
|
||||
// Load only typescript files irrespective of allowJs option if loading from node modules
|
||||
let result = loadNodeModuleFromFile(supportedTypeScriptExtensions, candidate, failedLookupLocations, host);
|
||||
let result = loadNodeModuleFromFile(supportedTypeScriptExtensions, candidate, failedLookupLocations, !nodeModulesFolderExists, host);
|
||||
if (result) {
|
||||
return { resolvedModule: { resolvedFileName: result, isExternalLibraryImport: true }, failedLookupLocations };
|
||||
}
|
||||
|
||||
result = loadNodeModuleFromDirectory(supportedTypeScriptExtensions, candidate, failedLookupLocations, host);
|
||||
result = loadNodeModuleFromDirectory(supportedTypeScriptExtensions, candidate, failedLookupLocations, !nodeModulesFolderExists, host);
|
||||
if (result) {
|
||||
return { resolvedModule: { resolvedFileName: result, isExternalLibraryImport: true }, failedLookupLocations };
|
||||
}
|
||||
@@ -281,7 +294,8 @@ namespace ts {
|
||||
getCanonicalFileName,
|
||||
getNewLine: () => newLine,
|
||||
fileExists: fileName => sys.fileExists(fileName),
|
||||
readFile: fileName => sys.readFile(fileName)
|
||||
readFile: fileName => sys.readFile(fileName),
|
||||
directoryExists: directoryName => sys.directoryExists(directoryName)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -522,7 +536,7 @@ namespace ts {
|
||||
}
|
||||
const resolutions = resolveModuleNamesWorker(moduleNames, getNormalizedAbsolutePath(newSourceFile.fileName, currentDirectory));
|
||||
// ensure that module resolution results are still correct
|
||||
for (let i = 0; i < moduleNames.length; ++i) {
|
||||
for (let i = 0; i < moduleNames.length; i++) {
|
||||
const newResolution = resolutions[i];
|
||||
const oldResolution = getResolvedModule(oldSourceFile, moduleNames[i]);
|
||||
const resolutionChanged = oldResolution
|
||||
@@ -550,7 +564,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
// update fileName -> file mapping
|
||||
for (let i = 0, len = newSourceFiles.length; i < len; ++i) {
|
||||
for (let i = 0, len = newSourceFiles.length; i < len; i++) {
|
||||
filesByName.set(filePaths[i], newSourceFiles[i]);
|
||||
}
|
||||
|
||||
@@ -1348,6 +1362,10 @@ namespace ts {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "emitDecoratorMetadata", "experimentalDecorators"));
|
||||
}
|
||||
|
||||
if (options.reactNamespace && !isIdentifier(options.reactNamespace, languageVersion)) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Invalide_value_for_reactNamespace_0_is_not_a_valid_identifier, options.reactNamespace));
|
||||
}
|
||||
|
||||
// If the emit is enabled make sure that every output file is unique and not overwriting any of the input files
|
||||
if (!options.noEmit) {
|
||||
const emitHost = getEmitHost();
|
||||
|
||||
+79
-32
@@ -289,7 +289,8 @@ namespace ts {
|
||||
let pos = 0;
|
||||
let lineStart = 0;
|
||||
while (pos < text.length) {
|
||||
const ch = text.charCodeAt(pos++);
|
||||
const ch = text.charCodeAt(pos);
|
||||
pos++;
|
||||
switch (ch) {
|
||||
case CharacterCodes.carriageReturn:
|
||||
if (text.charCodeAt(pos) === CharacterCodes.lineFeed) {
|
||||
@@ -688,6 +689,21 @@ namespace ts {
|
||||
ch > CharacterCodes.maxAsciiCharacter && isUnicodeIdentifierPart(ch, languageVersion);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function isIdentifier(name: string, languageVersion: ScriptTarget): boolean {
|
||||
if (!isIdentifierStart(name.charCodeAt(0), languageVersion)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 1, n = name.length; i < n; i++) {
|
||||
if (!isIdentifierPart(name.charCodeAt(i), languageVersion)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Creates a scanner over a (possibly unspecified) range of a piece of text.
|
||||
export function createScanner(languageVersion: ScriptTarget,
|
||||
skipTrivia: boolean,
|
||||
@@ -824,7 +840,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
function scanString(): string {
|
||||
const quote = text.charCodeAt(pos++);
|
||||
const quote = text.charCodeAt(pos);
|
||||
pos++;
|
||||
let result = "";
|
||||
let start = pos;
|
||||
while (true) {
|
||||
@@ -934,7 +951,8 @@ namespace ts {
|
||||
error(Diagnostics.Unexpected_end_of_text);
|
||||
return "";
|
||||
}
|
||||
const ch = text.charCodeAt(pos++);
|
||||
const ch = text.charCodeAt(pos);
|
||||
pos++;
|
||||
switch (ch) {
|
||||
case CharacterCodes._0:
|
||||
return "\0";
|
||||
@@ -1183,7 +1201,8 @@ namespace ts {
|
||||
}
|
||||
return pos += 2, token = SyntaxKind.ExclamationEqualsToken;
|
||||
}
|
||||
return pos++, token = SyntaxKind.ExclamationToken;
|
||||
pos++;
|
||||
return token = SyntaxKind.ExclamationToken;
|
||||
case CharacterCodes.doubleQuote:
|
||||
case CharacterCodes.singleQuote:
|
||||
tokenValue = scanString();
|
||||
@@ -1194,7 +1213,8 @@ namespace ts {
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.equals) {
|
||||
return pos += 2, token = SyntaxKind.PercentEqualsToken;
|
||||
}
|
||||
return pos++, token = SyntaxKind.PercentToken;
|
||||
pos++;
|
||||
return token = SyntaxKind.PercentToken;
|
||||
case CharacterCodes.ampersand:
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.ampersand) {
|
||||
return pos += 2, token = SyntaxKind.AmpersandAmpersandToken;
|
||||
@@ -1202,11 +1222,14 @@ namespace ts {
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.equals) {
|
||||
return pos += 2, token = SyntaxKind.AmpersandEqualsToken;
|
||||
}
|
||||
return pos++, token = SyntaxKind.AmpersandToken;
|
||||
pos++;
|
||||
return token = SyntaxKind.AmpersandToken;
|
||||
case CharacterCodes.openParen:
|
||||
return pos++, token = SyntaxKind.OpenParenToken;
|
||||
pos++;
|
||||
return token = SyntaxKind.OpenParenToken;
|
||||
case CharacterCodes.closeParen:
|
||||
return pos++, token = SyntaxKind.CloseParenToken;
|
||||
pos++;
|
||||
return token = SyntaxKind.CloseParenToken;
|
||||
case CharacterCodes.asterisk:
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.equals) {
|
||||
return pos += 2, token = SyntaxKind.AsteriskEqualsToken;
|
||||
@@ -1217,7 +1240,8 @@ namespace ts {
|
||||
}
|
||||
return pos += 2, token = SyntaxKind.AsteriskAsteriskToken;
|
||||
}
|
||||
return pos++, token = SyntaxKind.AsteriskToken;
|
||||
pos++;
|
||||
return token = SyntaxKind.AsteriskToken;
|
||||
case CharacterCodes.plus:
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.plus) {
|
||||
return pos += 2, token = SyntaxKind.PlusPlusToken;
|
||||
@@ -1225,9 +1249,11 @@ namespace ts {
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.equals) {
|
||||
return pos += 2, token = SyntaxKind.PlusEqualsToken;
|
||||
}
|
||||
return pos++, token = SyntaxKind.PlusToken;
|
||||
pos++;
|
||||
return token = SyntaxKind.PlusToken;
|
||||
case CharacterCodes.comma:
|
||||
return pos++, token = SyntaxKind.CommaToken;
|
||||
pos++;
|
||||
return token = SyntaxKind.CommaToken;
|
||||
case CharacterCodes.minus:
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.minus) {
|
||||
return pos += 2, token = SyntaxKind.MinusMinusToken;
|
||||
@@ -1235,7 +1261,8 @@ namespace ts {
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.equals) {
|
||||
return pos += 2, token = SyntaxKind.MinusEqualsToken;
|
||||
}
|
||||
return pos++, token = SyntaxKind.MinusToken;
|
||||
pos++;
|
||||
return token = SyntaxKind.MinusToken;
|
||||
case CharacterCodes.dot:
|
||||
if (isDigit(text.charCodeAt(pos + 1))) {
|
||||
tokenValue = scanNumber();
|
||||
@@ -1244,7 +1271,8 @@ namespace ts {
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.dot && text.charCodeAt(pos + 2) === CharacterCodes.dot) {
|
||||
return pos += 3, token = SyntaxKind.DotDotDotToken;
|
||||
}
|
||||
return pos++, token = SyntaxKind.DotToken;
|
||||
pos++;
|
||||
return token = SyntaxKind.DotToken;
|
||||
case CharacterCodes.slash:
|
||||
// Single-line comment
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.slash) {
|
||||
@@ -1302,7 +1330,8 @@ namespace ts {
|
||||
return pos += 2, token = SyntaxKind.SlashEqualsToken;
|
||||
}
|
||||
|
||||
return pos++, token = SyntaxKind.SlashToken;
|
||||
pos++;
|
||||
return token = SyntaxKind.SlashToken;
|
||||
|
||||
case CharacterCodes._0:
|
||||
if (pos + 2 < end && (text.charCodeAt(pos + 1) === CharacterCodes.X || text.charCodeAt(pos + 1) === CharacterCodes.x)) {
|
||||
@@ -1355,9 +1384,11 @@ namespace ts {
|
||||
tokenValue = scanNumber();
|
||||
return token = SyntaxKind.NumericLiteral;
|
||||
case CharacterCodes.colon:
|
||||
return pos++, token = SyntaxKind.ColonToken;
|
||||
pos++;
|
||||
return token = SyntaxKind.ColonToken;
|
||||
case CharacterCodes.semicolon:
|
||||
return pos++, token = SyntaxKind.SemicolonToken;
|
||||
pos++;
|
||||
return token = SyntaxKind.SemicolonToken;
|
||||
case CharacterCodes.lessThan:
|
||||
if (isConflictMarkerTrivia(text, pos)) {
|
||||
pos = scanConflictMarkerTrivia(text, pos, error);
|
||||
@@ -1383,7 +1414,8 @@ namespace ts {
|
||||
text.charCodeAt(pos + 2) !== CharacterCodes.asterisk) {
|
||||
return pos += 2, token = SyntaxKind.LessThanSlashToken;
|
||||
}
|
||||
return pos++, token = SyntaxKind.LessThanToken;
|
||||
pos++;
|
||||
return token = SyntaxKind.LessThanToken;
|
||||
case CharacterCodes.equals:
|
||||
if (isConflictMarkerTrivia(text, pos)) {
|
||||
pos = scanConflictMarkerTrivia(text, pos, error);
|
||||
@@ -1404,7 +1436,8 @@ namespace ts {
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.greaterThan) {
|
||||
return pos += 2, token = SyntaxKind.EqualsGreaterThanToken;
|
||||
}
|
||||
return pos++, token = SyntaxKind.EqualsToken;
|
||||
pos++;
|
||||
return token = SyntaxKind.EqualsToken;
|
||||
case CharacterCodes.greaterThan:
|
||||
if (isConflictMarkerTrivia(text, pos)) {
|
||||
pos = scanConflictMarkerTrivia(text, pos, error);
|
||||
@@ -1416,20 +1449,26 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
return pos++, token = SyntaxKind.GreaterThanToken;
|
||||
pos++;
|
||||
return token = SyntaxKind.GreaterThanToken;
|
||||
case CharacterCodes.question:
|
||||
return pos++, token = SyntaxKind.QuestionToken;
|
||||
pos++;
|
||||
return token = SyntaxKind.QuestionToken;
|
||||
case CharacterCodes.openBracket:
|
||||
return pos++, token = SyntaxKind.OpenBracketToken;
|
||||
pos++;
|
||||
return token = SyntaxKind.OpenBracketToken;
|
||||
case CharacterCodes.closeBracket:
|
||||
return pos++, token = SyntaxKind.CloseBracketToken;
|
||||
pos++;
|
||||
return token = SyntaxKind.CloseBracketToken;
|
||||
case CharacterCodes.caret:
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.equals) {
|
||||
return pos += 2, token = SyntaxKind.CaretEqualsToken;
|
||||
}
|
||||
return pos++, token = SyntaxKind.CaretToken;
|
||||
pos++;
|
||||
return token = SyntaxKind.CaretToken;
|
||||
case CharacterCodes.openBrace:
|
||||
return pos++, token = SyntaxKind.OpenBraceToken;
|
||||
pos++;
|
||||
return token = SyntaxKind.OpenBraceToken;
|
||||
case CharacterCodes.bar:
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.bar) {
|
||||
return pos += 2, token = SyntaxKind.BarBarToken;
|
||||
@@ -1437,13 +1476,17 @@ namespace ts {
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.equals) {
|
||||
return pos += 2, token = SyntaxKind.BarEqualsToken;
|
||||
}
|
||||
return pos++, token = SyntaxKind.BarToken;
|
||||
pos++;
|
||||
return token = SyntaxKind.BarToken;
|
||||
case CharacterCodes.closeBrace:
|
||||
return pos++, token = SyntaxKind.CloseBraceToken;
|
||||
pos++;
|
||||
return token = SyntaxKind.CloseBraceToken;
|
||||
case CharacterCodes.tilde:
|
||||
return pos++, token = SyntaxKind.TildeToken;
|
||||
pos++;
|
||||
return token = SyntaxKind.TildeToken;
|
||||
case CharacterCodes.at:
|
||||
return pos++, token = SyntaxKind.AtToken;
|
||||
pos++;
|
||||
return token = SyntaxKind.AtToken;
|
||||
case CharacterCodes.backslash:
|
||||
let cookedChar = peekUnicodeEscape();
|
||||
if (cookedChar >= 0 && isIdentifierStart(cookedChar, languageVersion)) {
|
||||
@@ -1452,7 +1495,8 @@ namespace ts {
|
||||
return token = getIdentifierToken();
|
||||
}
|
||||
error(Diagnostics.Invalid_character);
|
||||
return pos++, token = SyntaxKind.Unknown;
|
||||
pos++;
|
||||
return token = SyntaxKind.Unknown;
|
||||
default:
|
||||
if (isIdentifierStart(ch, languageVersion)) {
|
||||
pos++;
|
||||
@@ -1473,7 +1517,8 @@ namespace ts {
|
||||
continue;
|
||||
}
|
||||
error(Diagnostics.Invalid_character);
|
||||
return pos++, token = SyntaxKind.Unknown;
|
||||
pos++;
|
||||
return token = SyntaxKind.Unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1490,10 +1535,12 @@ namespace ts {
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.equals) {
|
||||
return pos += 2, token = SyntaxKind.GreaterThanGreaterThanEqualsToken;
|
||||
}
|
||||
return pos++, token = SyntaxKind.GreaterThanGreaterThanToken;
|
||||
pos++;
|
||||
return token = SyntaxKind.GreaterThanGreaterThanToken;
|
||||
}
|
||||
if (text.charCodeAt(pos) === CharacterCodes.equals) {
|
||||
return pos++, token = SyntaxKind.GreaterThanEqualsToken;
|
||||
pos++;
|
||||
return token = SyntaxKind.GreaterThanEqualsToken;
|
||||
}
|
||||
}
|
||||
return token;
|
||||
|
||||
@@ -7,7 +7,8 @@ namespace ts {
|
||||
setSourceFile(sourceFile: SourceFile): void;
|
||||
emitPos(pos: number): void;
|
||||
emitStart(range: TextRange): void;
|
||||
emitEnd(range: TextRange): void;
|
||||
emitEnd(range: TextRange, stopOverridingSpan?: boolean): void;
|
||||
changeEmitSourcePos(): void;
|
||||
getText(): string;
|
||||
getSourceMappingURL(): string;
|
||||
initialize(filePath: string, sourceMapFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean): void;
|
||||
@@ -22,8 +23,9 @@ namespace ts {
|
||||
getSourceMapData(): SourceMapData { return undefined; },
|
||||
setSourceFile(sourceFile: SourceFile): void { },
|
||||
emitStart(range: TextRange): void { },
|
||||
emitEnd(range: TextRange): void { },
|
||||
emitEnd(range: TextRange, stopOverridingSpan?: boolean): void { },
|
||||
emitPos(pos: number): void { },
|
||||
changeEmitSourcePos(): void { },
|
||||
getText(): string { return undefined; },
|
||||
getSourceMappingURL(): string { return undefined; },
|
||||
initialize(filePath: string, sourceMapFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean): void { },
|
||||
@@ -38,6 +40,8 @@ namespace ts {
|
||||
const compilerOptions = host.getCompilerOptions();
|
||||
let currentSourceFile: SourceFile;
|
||||
let sourceMapDir: string; // The directory in which sourcemap will be
|
||||
let stopOverridingSpan = false;
|
||||
let modifyLastSourcePos = false;
|
||||
|
||||
// Current source map file and its index in the sources list
|
||||
let sourceMapSourceIndex: number;
|
||||
@@ -56,6 +60,7 @@ namespace ts {
|
||||
emitPos,
|
||||
emitStart,
|
||||
emitEnd,
|
||||
changeEmitSourcePos,
|
||||
getText,
|
||||
getSourceMappingURL,
|
||||
initialize,
|
||||
@@ -142,6 +147,45 @@ namespace ts {
|
||||
sourceMapData = undefined;
|
||||
}
|
||||
|
||||
function updateLastEncodedAndRecordedSpans() {
|
||||
if (modifyLastSourcePos) {
|
||||
// Reset the source pos
|
||||
modifyLastSourcePos = false;
|
||||
|
||||
// Change Last recorded Map with last encoded emit line and character
|
||||
lastRecordedSourceMapSpan.emittedLine = lastEncodedSourceMapSpan.emittedLine;
|
||||
lastRecordedSourceMapSpan.emittedColumn = lastEncodedSourceMapSpan.emittedColumn;
|
||||
|
||||
// Pop sourceMapDecodedMappings to remove last entry
|
||||
sourceMapData.sourceMapDecodedMappings.pop();
|
||||
|
||||
// Change the last encoded source map
|
||||
lastEncodedSourceMapSpan = sourceMapData.sourceMapDecodedMappings.length ?
|
||||
sourceMapData.sourceMapDecodedMappings[sourceMapData.sourceMapDecodedMappings.length - 1] :
|
||||
undefined;
|
||||
|
||||
// TODO: Update lastEncodedNameIndex
|
||||
// Since we dont support this any more, lets not worry about it right now.
|
||||
// When we start supporting nameIndex, we will get back to this
|
||||
|
||||
// Change the encoded source map
|
||||
const sourceMapMappings = sourceMapData.sourceMapMappings;
|
||||
let lenthToSet = sourceMapMappings.length - 1;
|
||||
for (; lenthToSet >= 0; lenthToSet--) {
|
||||
const currentChar = sourceMapMappings.charAt(lenthToSet);
|
||||
if (currentChar === ",") {
|
||||
// Separator for the entry found
|
||||
break;
|
||||
}
|
||||
if (currentChar === ";" && lenthToSet !== 0 && sourceMapMappings.charAt(lenthToSet - 1) !== ";") {
|
||||
// Last line separator found
|
||||
break;
|
||||
}
|
||||
}
|
||||
sourceMapData.sourceMapMappings = sourceMapMappings.substr(0, Math.max(0, lenthToSet));
|
||||
}
|
||||
}
|
||||
|
||||
// Encoding for sourcemap span
|
||||
function encodeLastRecordedSourceMapSpan() {
|
||||
if (!lastRecordedSourceMapSpan || lastRecordedSourceMapSpan === lastEncodedSourceMapSpan) {
|
||||
@@ -178,6 +222,7 @@ namespace ts {
|
||||
|
||||
// 5. Relative namePosition 0 based
|
||||
if (lastRecordedSourceMapSpan.nameIndex >= 0) {
|
||||
Debug.assert(false, "We do not support name index right now, Make sure to update updateLastEncodedAndRecordedSpans when we start using this");
|
||||
sourceMapData.sourceMapMappings += base64VLQFormatEncode(lastRecordedSourceMapSpan.nameIndex - lastEncodedNameIndex);
|
||||
lastEncodedNameIndex = lastRecordedSourceMapSpan.nameIndex;
|
||||
}
|
||||
@@ -219,22 +264,36 @@ namespace ts {
|
||||
sourceColumn: sourceLinePos.character,
|
||||
sourceIndex: sourceMapSourceIndex
|
||||
};
|
||||
|
||||
stopOverridingSpan = false;
|
||||
}
|
||||
else {
|
||||
else if (!stopOverridingSpan) {
|
||||
// Take the new pos instead since there is no change in emittedLine and column since last location
|
||||
lastRecordedSourceMapSpan.sourceLine = sourceLinePos.line;
|
||||
lastRecordedSourceMapSpan.sourceColumn = sourceLinePos.character;
|
||||
lastRecordedSourceMapSpan.sourceIndex = sourceMapSourceIndex;
|
||||
}
|
||||
|
||||
updateLastEncodedAndRecordedSpans();
|
||||
}
|
||||
|
||||
function getStartPos(range: TextRange) {
|
||||
const rangeHasDecorators = !!(range as Node).decorators;
|
||||
return range.pos !== -1 ? skipTrivia(currentSourceFile.text, rangeHasDecorators ? (range as Node).decorators.end : range.pos) : -1;
|
||||
}
|
||||
|
||||
function emitStart(range: TextRange) {
|
||||
const rangeHasDecorators = !!(range as Node).decorators;
|
||||
emitPos(range.pos !== -1 ? skipTrivia(currentSourceFile.text, rangeHasDecorators ? (range as Node).decorators.end : range.pos) : -1);
|
||||
emitPos(getStartPos(range));
|
||||
}
|
||||
|
||||
function emitEnd(range: TextRange) {
|
||||
function emitEnd(range: TextRange, stopOverridingEnd?: boolean) {
|
||||
emitPos(range.end);
|
||||
stopOverridingSpan = stopOverridingEnd;
|
||||
}
|
||||
|
||||
function changeEmitSourcePos() {
|
||||
Debug.assert(!modifyLastSourcePos);
|
||||
modifyLastSourcePos = true;
|
||||
}
|
||||
|
||||
function setSourceFile(sourceFile: SourceFile) {
|
||||
|
||||
@@ -1741,6 +1741,7 @@ namespace ts {
|
||||
isImplementationOfOverload(node: FunctionLikeDeclaration): boolean;
|
||||
isUndefinedSymbol(symbol: Symbol): boolean;
|
||||
isArgumentsSymbol(symbol: Symbol): boolean;
|
||||
isUnknownSymbol(symbol: Symbol): boolean;
|
||||
|
||||
getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number;
|
||||
isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean;
|
||||
@@ -2385,6 +2386,7 @@ namespace ts {
|
||||
inlineSourceMap?: boolean;
|
||||
inlineSources?: boolean;
|
||||
jsx?: JsxEmit;
|
||||
reactNamespace?: string;
|
||||
listFiles?: boolean;
|
||||
locale?: string;
|
||||
mapRoot?: string;
|
||||
@@ -2652,6 +2654,8 @@ namespace ts {
|
||||
// readFile function is used to read arbitrary text files on disk, i.e. when resolution procedure needs the content of 'package.json'
|
||||
// to determine location of bundled typings for node module
|
||||
readFile(fileName: string): string;
|
||||
|
||||
directoryExists?(directoryName: string): boolean;
|
||||
}
|
||||
|
||||
export interface ResolvedModule {
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < array1.length; ++i) {
|
||||
for (let i = 0; i < array1.length; i++) {
|
||||
const equals = equaler ? equaler(array1[i], array2[i]) : array1[i] === array2[i];
|
||||
if (!equals) {
|
||||
return false;
|
||||
@@ -1913,8 +1913,8 @@ namespace ts {
|
||||
writeTextOfNode,
|
||||
writeLiteral,
|
||||
writeLine,
|
||||
increaseIndent: () => indent++,
|
||||
decreaseIndent: () => indent--,
|
||||
increaseIndent: () => { indent++; },
|
||||
decreaseIndent: () => { indent--; },
|
||||
getIndent: () => indent,
|
||||
getTextPos: () => output.length,
|
||||
getLine: () => lineCount + 1,
|
||||
|
||||
@@ -317,6 +317,7 @@ namespace FourSlash {
|
||||
InsertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
|
||||
PlaceOpenBraceOnNewLineForFunctions: false,
|
||||
PlaceOpenBraceOnNewLineForControlBlocks: false,
|
||||
};
|
||||
@@ -727,7 +728,7 @@ namespace FourSlash {
|
||||
// Count only the references in local files. Filter the ones in lib and other files.
|
||||
ts.forEach(references, entry => {
|
||||
if (localFiles.some((fileName) => fileName === entry.fileName)) {
|
||||
++referencesCount;
|
||||
referencesCount++;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1079,9 +1080,15 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
public baselineCurrentFileBreakpointLocations() {
|
||||
let baselineFile = this.testData.globalOptions[metadataOptionNames.baselineFile];
|
||||
if (!baselineFile) {
|
||||
baselineFile = this.activeFile.fileName.replace(this.basePath + "/breakpointValidation", "bpSpan");
|
||||
baselineFile = baselineFile.replace(".ts", ".baseline");
|
||||
|
||||
}
|
||||
Harness.Baseline.runBaseline(
|
||||
"Breakpoint Locations for " + this.activeFile.fileName,
|
||||
this.testData.globalOptions[metadataOptionNames.baselineFile],
|
||||
baselineFile,
|
||||
() => {
|
||||
return this.baselineCurrentFileLocations(pos => this.getBreakpointStatementLocation(pos));
|
||||
},
|
||||
@@ -1093,7 +1100,7 @@ namespace FourSlash {
|
||||
const emitFiles: FourSlashFile[] = []; // List of FourSlashFile that has emitThisFile flag on
|
||||
|
||||
const allFourSlashFiles = this.testData.files;
|
||||
for (let idx = 0; idx < allFourSlashFiles.length; ++idx) {
|
||||
for (let idx = 0; idx < allFourSlashFiles.length; idx++) {
|
||||
const file = allFourSlashFiles[idx];
|
||||
if (file.fileOptions[metadataOptionNames.emitThisFile] === "true") {
|
||||
// Find a file with the flag emitThisFile turned on
|
||||
@@ -1853,7 +1860,7 @@ namespace FourSlash {
|
||||
let item: ts.NavigateToItem = null;
|
||||
|
||||
// Count only the match that match the same MatchKind
|
||||
for (let i = 0; i < items.length; ++i) {
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
item = items[i];
|
||||
if (!matchKind || item.matchKind === matchKind) {
|
||||
actual++;
|
||||
@@ -3284,6 +3291,30 @@ namespace FourSlashInterface {
|
||||
return getClassification("typeAliasName", text, position);
|
||||
}
|
||||
|
||||
export function jsxOpenTagName(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } {
|
||||
return getClassification("jsxOpenTagName", text, position);
|
||||
}
|
||||
|
||||
export function jsxCloseTagName(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } {
|
||||
return getClassification("jsxCloseTagName", text, position);
|
||||
}
|
||||
|
||||
export function jsxSelfClosingTagName(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } {
|
||||
return getClassification("jsxSelfClosingTagName", text, position);
|
||||
}
|
||||
|
||||
export function jsxAttribute(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } {
|
||||
return getClassification("jsxAttribute", text, position);
|
||||
}
|
||||
|
||||
export function jsxText(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } {
|
||||
return getClassification("jsxText", text, position);
|
||||
}
|
||||
|
||||
export function jsxAttributeStringLiteralValue(text: string, position?: number): { classificationType: string; text: string; textSpan?: FourSlash.TextSpan } {
|
||||
return getClassification("jsxAttributeStringLiteralValue", text, position);
|
||||
}
|
||||
|
||||
function getClassification(type: string, text: string, position?: number) {
|
||||
return {
|
||||
classificationType: type,
|
||||
|
||||
@@ -267,6 +267,10 @@ namespace Harness.LanguageService {
|
||||
log(s: string): void { this.nativeHost.log(s); }
|
||||
trace(s: string): void { this.nativeHost.trace(s); }
|
||||
error(s: string): void { this.nativeHost.error(s); }
|
||||
directoryExists(directoryName: string): boolean {
|
||||
// for tests pessimistically assume that directory always exists
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class ClassifierShimProxy implements ts.Classifier {
|
||||
|
||||
@@ -307,9 +307,10 @@ class ProjectRunner extends RunnerBase {
|
||||
// If the generated output file resides in the parent folder or is rooted path,
|
||||
// we need to instead create files that can live in the project reference folder
|
||||
// but make sure extension of these files matches with the fileName the compiler asked to write
|
||||
diskRelativeName = "diskFile" + nonSubfolderDiskFiles++ +
|
||||
diskRelativeName = "diskFile" + nonSubfolderDiskFiles +
|
||||
(Harness.Compiler.isDTS(fileName) ? ".d.ts" :
|
||||
Harness.Compiler.isJS(fileName) ? ".js" : ".js.map");
|
||||
nonSubfolderDiskFiles++;
|
||||
}
|
||||
|
||||
if (Harness.Compiler.isJS(fileName)) {
|
||||
|
||||
Vendored
+5
-2
@@ -321,6 +321,7 @@ interface AudioContext extends EventTarget {
|
||||
destination: AudioDestinationNode;
|
||||
listener: AudioListener;
|
||||
sampleRate: number;
|
||||
state: string;
|
||||
createAnalyser(): AnalyserNode;
|
||||
createBiquadFilter(): BiquadFilterNode;
|
||||
createBuffer(numberOfChannels: number, length: number, sampleRate: number): AudioBuffer;
|
||||
@@ -2774,6 +2775,7 @@ interface Element extends Node, GlobalEventHandlers, ElementTraversal, NodeSelec
|
||||
tagName: string;
|
||||
id: string;
|
||||
className: string;
|
||||
innerHTML: string;
|
||||
getAttribute(name?: string): string;
|
||||
getAttributeNS(namespaceURI: string, localName: string): string;
|
||||
getAttributeNode(name: string): Attr;
|
||||
@@ -2969,7 +2971,7 @@ interface Element extends Node, GlobalEventHandlers, ElementTraversal, NodeSelec
|
||||
removeAttributeNode(oldAttr: Attr): Attr;
|
||||
requestFullscreen(): void;
|
||||
requestPointerLock(): void;
|
||||
setAttribute(name?: string, value?: string): void;
|
||||
setAttribute(name: string, value: string): void;
|
||||
setAttributeNS(namespaceURI: string, qualifiedName: string, value: string): void;
|
||||
setAttributeNode(newAttr: Attr): Attr;
|
||||
setAttributeNodeNS(newAttr: Attr): Attr;
|
||||
@@ -5512,7 +5514,7 @@ interface HTMLMediaElement extends HTMLElement {
|
||||
* Gets or sets the current playback position, in seconds.
|
||||
*/
|
||||
preload: string;
|
||||
readyState: any;
|
||||
readyState: number;
|
||||
/**
|
||||
* Returns a TimeRanges object that represents the ranges of the current media resource that can be seeked.
|
||||
*/
|
||||
@@ -6169,6 +6171,7 @@ interface HTMLSelectElement extends HTMLElement {
|
||||
* Returns whether an element will successfully validate based on forms validation rules and constraints.
|
||||
*/
|
||||
willValidate: boolean;
|
||||
selectedOptions: HTMLCollection;
|
||||
/**
|
||||
* Adds an element to the areas, controlRange, or options collection.
|
||||
* @param element Variant of type Number that specifies the index position in the collection where the element is placed. If no value is given, the method places the element at the end of the collection.
|
||||
|
||||
Vendored
+28
-19
@@ -7,7 +7,7 @@ interface Symbol {
|
||||
/** Returns the primitive value of the specified object. */
|
||||
valueOf(): Object;
|
||||
|
||||
[Symbol.toStringTag]: string;
|
||||
[Symbol.toStringTag]: "Symbol";
|
||||
}
|
||||
|
||||
interface SymbolConstructor {
|
||||
@@ -565,7 +565,7 @@ interface IterableIterator<T> extends Iterator<T> {
|
||||
}
|
||||
|
||||
interface GeneratorFunction extends Function {
|
||||
|
||||
[Symbol.toStringTag]: "GeneratorFunction";
|
||||
}
|
||||
|
||||
interface GeneratorFunctionConstructor {
|
||||
@@ -690,7 +690,7 @@ interface Math {
|
||||
*/
|
||||
cbrt(x: number): number;
|
||||
|
||||
[Symbol.toStringTag]: string;
|
||||
[Symbol.toStringTag]: "Math";
|
||||
}
|
||||
|
||||
interface Date {
|
||||
@@ -807,7 +807,7 @@ interface Map<K, V> {
|
||||
size: number;
|
||||
values(): IterableIterator<V>;
|
||||
[Symbol.iterator]():IterableIterator<[K,V]>;
|
||||
[Symbol.toStringTag]: string;
|
||||
[Symbol.toStringTag]: "Map";
|
||||
}
|
||||
|
||||
interface MapConstructor {
|
||||
@@ -824,7 +824,7 @@ interface WeakMap<K, V> {
|
||||
get(key: K): V;
|
||||
has(key: K): boolean;
|
||||
set(key: K, value?: V): WeakMap<K, V>;
|
||||
[Symbol.toStringTag]: string;
|
||||
[Symbol.toStringTag]: "WeakMap";
|
||||
}
|
||||
|
||||
interface WeakMapConstructor {
|
||||
@@ -846,7 +846,7 @@ interface Set<T> {
|
||||
size: number;
|
||||
values(): IterableIterator<T>;
|
||||
[Symbol.iterator]():IterableIterator<T>;
|
||||
[Symbol.toStringTag]: string;
|
||||
[Symbol.toStringTag]: "Set";
|
||||
}
|
||||
|
||||
interface SetConstructor {
|
||||
@@ -862,7 +862,7 @@ interface WeakSet<T> {
|
||||
clear(): void;
|
||||
delete(value: T): boolean;
|
||||
has(value: T): boolean;
|
||||
[Symbol.toStringTag]: string;
|
||||
[Symbol.toStringTag]: "WeakSet";
|
||||
}
|
||||
|
||||
interface WeakSetConstructor {
|
||||
@@ -874,7 +874,7 @@ interface WeakSetConstructor {
|
||||
declare var WeakSet: WeakSetConstructor;
|
||||
|
||||
interface JSON {
|
||||
[Symbol.toStringTag]: string;
|
||||
[Symbol.toStringTag]: "JSON";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -884,11 +884,11 @@ interface JSON {
|
||||
* buffer as needed.
|
||||
*/
|
||||
interface ArrayBuffer {
|
||||
[Symbol.toStringTag]: string;
|
||||
[Symbol.toStringTag]: "ArrayBuffer";
|
||||
}
|
||||
|
||||
interface DataView {
|
||||
[Symbol.toStringTag]: string;
|
||||
[Symbol.toStringTag]: "DataView";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -909,6 +909,7 @@ interface Int8Array {
|
||||
*/
|
||||
values(): IterableIterator<number>;
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
[Symbol.toStringTag]: "Int8Array";
|
||||
}
|
||||
|
||||
interface Int8ArrayConstructor {
|
||||
@@ -941,6 +942,7 @@ interface Uint8Array {
|
||||
*/
|
||||
values(): IterableIterator<number>;
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
[Symbol.toStringTag]: "UInt8Array";
|
||||
}
|
||||
|
||||
interface Uint8ArrayConstructor {
|
||||
@@ -976,6 +978,7 @@ interface Uint8ClampedArray {
|
||||
values(): IterableIterator<number>;
|
||||
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
[Symbol.toStringTag]: "Uint8ClampedArray";
|
||||
}
|
||||
|
||||
interface Uint8ClampedArrayConstructor {
|
||||
@@ -1013,6 +1016,7 @@ interface Int16Array {
|
||||
|
||||
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
[Symbol.toStringTag]: "Int16Array";
|
||||
}
|
||||
|
||||
interface Int16ArrayConstructor {
|
||||
@@ -1045,6 +1049,7 @@ interface Uint16Array {
|
||||
*/
|
||||
values(): IterableIterator<number>;
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
[Symbol.toStringTag]: "Uint16Array";
|
||||
}
|
||||
|
||||
interface Uint16ArrayConstructor {
|
||||
@@ -1077,6 +1082,7 @@ interface Int32Array {
|
||||
*/
|
||||
values(): IterableIterator<number>;
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
[Symbol.toStringTag]: "Int32Array";
|
||||
}
|
||||
|
||||
interface Int32ArrayConstructor {
|
||||
@@ -1109,6 +1115,7 @@ interface Uint32Array {
|
||||
*/
|
||||
values(): IterableIterator<number>;
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
[Symbol.toStringTag]: "Uint32Array";
|
||||
}
|
||||
|
||||
interface Uint32ArrayConstructor {
|
||||
@@ -1141,6 +1148,7 @@ interface Float32Array {
|
||||
*/
|
||||
values(): IterableIterator<number>;
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
[Symbol.toStringTag]: "Float32Array";
|
||||
}
|
||||
|
||||
interface Float32ArrayConstructor {
|
||||
@@ -1173,6 +1181,7 @@ interface Float64Array {
|
||||
*/
|
||||
values(): IterableIterator<number>;
|
||||
[Symbol.iterator](): IterableIterator<number>;
|
||||
[Symbol.toStringTag]: "Float64Array";
|
||||
}
|
||||
|
||||
interface Float64ArrayConstructor {
|
||||
@@ -1249,7 +1258,7 @@ interface Promise<T> {
|
||||
catch(onrejected?: (reason: any) => T | PromiseLike<T>): Promise<T>;
|
||||
catch(onrejected?: (reason: any) => void): Promise<T>;
|
||||
|
||||
[Symbol.toStringTag]: string;
|
||||
[Symbol.toStringTag]: "Promise";
|
||||
}
|
||||
|
||||
interface PromiseConstructor {
|
||||
@@ -1272,15 +1281,15 @@ interface PromiseConstructor {
|
||||
* @param values An array of Promises.
|
||||
* @returns A new Promise.
|
||||
*/
|
||||
all<T1, T2>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>]): Promise<[T1, T2]>;
|
||||
all<T1, T2, T3>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>]): Promise<[T1, T2, T3]>;
|
||||
all<T1, T2, T3, T4>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>]): Promise<[T1, T2, T3, T4]>;
|
||||
all<T1, T2, T3, T4, T5>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>]): Promise<[T1, T2, T3, T4, T5]>;
|
||||
all<T1, T2, T3, T4, T5, T6>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>]): Promise<[T1, T2, T3, T4, T5, T6]>;
|
||||
all<T1, T2, T3, T4, T5, T6, T7>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>]): Promise<[T1, T2, T3, T4, T5, T6, T7]>;
|
||||
all<T1, T2, T3, T4, T5, T6, T7, T8>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8]>;
|
||||
all<T1, T2, T3, T4, T5, T6, T7, T8, T9>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>;
|
||||
all<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>, T10 | PromiseLike<T10>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>;
|
||||
all<T1, T2, T3, T4, T5, T6, T7, T8, T9>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>;
|
||||
all<T1, T2, T3, T4, T5, T6, T7, T8>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8]>;
|
||||
all<T1, T2, T3, T4, T5, T6, T7>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>]): Promise<[T1, T2, T3, T4, T5, T6, T7]>;
|
||||
all<T1, T2, T3, T4, T5, T6>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>]): Promise<[T1, T2, T3, T4, T5, T6]>;
|
||||
all<T1, T2, T3, T4, T5>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>]): Promise<[T1, T2, T3, T4, T5]>;
|
||||
all<T1, T2, T3, T4>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>]): Promise<[T1, T2, T3, T4]>;
|
||||
all<T1, T2, T3>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>]): Promise<[T1, T2, T3]>;
|
||||
all<T1, T2>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>]): Promise<[T1, T2]>;
|
||||
all<TAll>(values: Iterable<TAll | PromiseLike<TAll>>): Promise<TAll[]>;
|
||||
|
||||
/**
|
||||
|
||||
@@ -100,7 +100,8 @@ namespace ts.server {
|
||||
this.filenameToScript = createFileMap<ScriptInfo>();
|
||||
this.moduleResolutionHost = {
|
||||
fileExists: fileName => this.fileExists(fileName),
|
||||
readFile: fileName => this.host.readFile(fileName)
|
||||
readFile: fileName => this.host.readFile(fileName),
|
||||
directoryExists: directoryName => this.host.directoryExists(directoryName)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -718,7 +719,8 @@ namespace ts.server {
|
||||
else {
|
||||
for (const directory of project.directoriesWatchedForTsconfig) {
|
||||
// if the ref count for this directory watcher drops to 0, it's time to close it
|
||||
if (!(--project.projectService.directoryWatchersRefCount[directory])) {
|
||||
project.projectService.directoryWatchersRefCount[directory]--;
|
||||
if (!project.projectService.directoryWatchersRefCount[directory]) {
|
||||
this.log("Close directory watcher for: " + directory);
|
||||
project.projectService.directoryWatchersForTsconfig[directory].close();
|
||||
delete project.projectService.directoryWatchersForTsconfig[directory];
|
||||
@@ -1330,6 +1332,7 @@ namespace ts.server {
|
||||
InsertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
|
||||
PlaceOpenBraceOnNewLineForFunctions: false,
|
||||
PlaceOpenBraceOnNewLineForControlBlocks: false,
|
||||
};
|
||||
@@ -1730,7 +1733,8 @@ namespace ts.server {
|
||||
let count = 1;
|
||||
let pos = 0;
|
||||
this.index.every((ll, s, len) => {
|
||||
starts[count++] = pos;
|
||||
starts[count] = pos;
|
||||
count++;
|
||||
pos += ll.text.length;
|
||||
return true;
|
||||
}, 0);
|
||||
@@ -1996,7 +2000,8 @@ namespace ts.server {
|
||||
while (adjustedStart >= childCharCount) {
|
||||
this.skipChild(adjustedStart, rangeLength, childIndex, walkFns, CharRangeSection.PreStart);
|
||||
adjustedStart -= childCharCount;
|
||||
child = this.children[++childIndex];
|
||||
childIndex++;
|
||||
child = this.children[childIndex];
|
||||
childCharCount = child.charCount();
|
||||
}
|
||||
// Case I: both start and end of range in same subtree
|
||||
@@ -2011,14 +2016,16 @@ namespace ts.server {
|
||||
return;
|
||||
}
|
||||
let adjustedLength = rangeLength - (childCharCount - adjustedStart);
|
||||
child = this.children[++childIndex];
|
||||
childIndex++;
|
||||
child = this.children[childIndex];
|
||||
childCharCount = child.charCount();
|
||||
while (adjustedLength > childCharCount) {
|
||||
if (this.execWalk(0, childCharCount, walkFns, childIndex, CharRangeSection.Mid)) {
|
||||
return;
|
||||
}
|
||||
adjustedLength -= childCharCount;
|
||||
child = this.children[++childIndex];
|
||||
childIndex++;
|
||||
child = this.children[childIndex];
|
||||
childCharCount = child.charCount();
|
||||
}
|
||||
if (adjustedLength > 0) {
|
||||
@@ -2142,7 +2149,8 @@ namespace ts.server {
|
||||
if (childIndex < clen) {
|
||||
splitNode = new LineNode();
|
||||
while (childIndex < clen) {
|
||||
splitNode.add(this.children[childIndex++]);
|
||||
splitNode.add(this.children[childIndex]);
|
||||
childIndex++;
|
||||
}
|
||||
splitNode.updateCounts();
|
||||
}
|
||||
@@ -2183,7 +2191,9 @@ namespace ts.server {
|
||||
let nodeIndex = 0;
|
||||
childIndex++;
|
||||
while ((childIndex < lineCollectionCapacity) && (nodeIndex < nodeCount)) {
|
||||
this.children[childIndex++] = nodes[nodeIndex++];
|
||||
this.children[childIndex] = nodes[nodeIndex];
|
||||
childIndex++;
|
||||
nodeIndex++;
|
||||
}
|
||||
let splitNodes: LineNode[] = [];
|
||||
let splitNodeCount = 0;
|
||||
@@ -2196,7 +2206,8 @@ namespace ts.server {
|
||||
}
|
||||
let splitNode = <LineNode>splitNodes[0];
|
||||
while (nodeIndex < nodeCount) {
|
||||
splitNode.add(nodes[nodeIndex++]);
|
||||
splitNode.add(nodes[nodeIndex]);
|
||||
nodeIndex++;
|
||||
if (splitNode.children.length === lineCollectionCapacity) {
|
||||
splitNodeIndex++;
|
||||
splitNode = <LineNode>splitNodes[splitNodeIndex];
|
||||
|
||||
@@ -263,7 +263,8 @@ namespace ts.server {
|
||||
let index = 0;
|
||||
const checkOne = () => {
|
||||
if (matchSeq(seq)) {
|
||||
const checkSpec = checkList[index++];
|
||||
const checkSpec = checkList[index];
|
||||
index++;
|
||||
if (checkSpec.project.getSourceFileFromName(checkSpec.fileName, requireOpen)) {
|
||||
this.syntacticCheck(checkSpec.fileName, checkSpec.project);
|
||||
this.immediateId = setImmediate(() => {
|
||||
|
||||
+271
-86
@@ -45,6 +45,10 @@ namespace ts.BreakpointResolver {
|
||||
return createTextSpanFromBounds(start, (endNode || startNode).getEnd());
|
||||
}
|
||||
|
||||
function textSpanEndingAtNextToken(startNode: Node, previousTokenToFindNextEndToken: Node): TextSpan {
|
||||
return textSpan(startNode, findNextToken(previousTokenToFindNextEndToken, previousTokenToFindNextEndToken.parent));
|
||||
}
|
||||
|
||||
function spanInNodeIfStartsOnSameLine(node: Node, otherwiseOnNode?: Node): TextSpan {
|
||||
if (node && lineOfPosition === sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line) {
|
||||
return spanInNode(node);
|
||||
@@ -66,33 +70,6 @@ namespace ts.BreakpointResolver {
|
||||
|
||||
function spanInNode(node: Node): TextSpan {
|
||||
if (node) {
|
||||
if (isExpression(node)) {
|
||||
if (node.parent.kind === SyntaxKind.DoStatement) {
|
||||
// Set span as if on while keyword
|
||||
return spanInPreviousNode(node);
|
||||
}
|
||||
|
||||
if (node.parent.kind === SyntaxKind.Decorator) {
|
||||
// Set breakpoint on the decorator emit
|
||||
return spanInNode(node.parent);
|
||||
}
|
||||
|
||||
if (node.parent.kind === SyntaxKind.ForStatement) {
|
||||
// For now lets set the span on this expression, fix it later
|
||||
return textSpan(node);
|
||||
}
|
||||
|
||||
if (node.parent.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>node.parent).operatorToken.kind === SyntaxKind.CommaToken) {
|
||||
// if this is comma expression, the breakpoint is possible in this expression
|
||||
return textSpan(node);
|
||||
}
|
||||
|
||||
if (node.parent.kind === SyntaxKind.ArrowFunction && (<FunctionLikeDeclaration>node.parent).body === node) {
|
||||
// If this is body of arrow function, it is allowed to have the breakpoint
|
||||
return textSpan(node);
|
||||
}
|
||||
}
|
||||
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.VariableStatement:
|
||||
// Span on first variable declaration
|
||||
@@ -120,7 +97,7 @@ namespace ts.BreakpointResolver {
|
||||
if (isFunctionBlock(node)) {
|
||||
return spanInFunctionBlock(<Block>node);
|
||||
}
|
||||
// Fall through
|
||||
// Fall through
|
||||
case SyntaxKind.ModuleBlock:
|
||||
return spanInBlock(<Block>node);
|
||||
|
||||
@@ -137,7 +114,7 @@ namespace ts.BreakpointResolver {
|
||||
|
||||
case SyntaxKind.WhileStatement:
|
||||
// Span on while(...)
|
||||
return textSpan(node, findNextToken((<WhileStatement>node).expression, node));
|
||||
return textSpanEndingAtNextToken(node, (<WhileStatement>node).expression);
|
||||
|
||||
case SyntaxKind.DoStatement:
|
||||
// span in statement of the do statement
|
||||
@@ -149,7 +126,7 @@ namespace ts.BreakpointResolver {
|
||||
|
||||
case SyntaxKind.IfStatement:
|
||||
// set on if(..) span
|
||||
return textSpan(node, findNextToken((<IfStatement>node).expression, node));
|
||||
return textSpanEndingAtNextToken(node, (<IfStatement>node).expression);
|
||||
|
||||
case SyntaxKind.LabeledStatement:
|
||||
// span in statement
|
||||
@@ -164,13 +141,16 @@ namespace ts.BreakpointResolver {
|
||||
return spanInForStatement(<ForStatement>node);
|
||||
|
||||
case SyntaxKind.ForInStatement:
|
||||
// span of for (a in ...)
|
||||
return textSpanEndingAtNextToken(node, (<ForInStatement>node).expression);
|
||||
|
||||
case SyntaxKind.ForOfStatement:
|
||||
// span on for (a in ...)
|
||||
return textSpan(node, findNextToken((<ForInStatement | ForOfStatement>node).expression, node));
|
||||
// span in initializer
|
||||
return spanInInitializerOfForLike(<ForOfStatement | ForInStatement>node);
|
||||
|
||||
case SyntaxKind.SwitchStatement:
|
||||
// span on switch(...)
|
||||
return textSpan(node, findNextToken((<SwitchStatement>node).expression, node));
|
||||
return textSpanEndingAtNextToken(node, (<SwitchStatement>node).expression);
|
||||
|
||||
case SyntaxKind.CaseClause:
|
||||
case SyntaxKind.DefaultClause:
|
||||
@@ -210,8 +190,7 @@ namespace ts.BreakpointResolver {
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.EnumMember:
|
||||
case SyntaxKind.CallExpression:
|
||||
case SyntaxKind.NewExpression:
|
||||
case SyntaxKind.BindingElement:
|
||||
// span on complete node
|
||||
return textSpan(node);
|
||||
|
||||
@@ -222,6 +201,10 @@ namespace ts.BreakpointResolver {
|
||||
case SyntaxKind.Decorator:
|
||||
return spanInNodeArray(node.parent.decorators);
|
||||
|
||||
case SyntaxKind.ObjectBindingPattern:
|
||||
case SyntaxKind.ArrayBindingPattern:
|
||||
return spanInBindingPattern(<BindingPattern>node);
|
||||
|
||||
// No breakpoint in interface, type alias
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
@@ -234,14 +217,17 @@ namespace ts.BreakpointResolver {
|
||||
|
||||
case SyntaxKind.CommaToken:
|
||||
return spanInPreviousNode(node)
|
||||
|
||||
|
||||
case SyntaxKind.OpenBraceToken:
|
||||
return spanInOpenBraceToken(node);
|
||||
|
||||
case SyntaxKind.CloseBraceToken:
|
||||
return spanInCloseBraceToken(node);
|
||||
|
||||
case SyntaxKind.OpenParenToken:
|
||||
case SyntaxKind.CloseBracketToken:
|
||||
return spanInCloseBracketToken(node);
|
||||
|
||||
case SyntaxKind.OpenParenToken:
|
||||
return spanInOpenParenToken(node);
|
||||
|
||||
case SyntaxKind.CloseParenToken:
|
||||
@@ -263,15 +249,93 @@ namespace ts.BreakpointResolver {
|
||||
case SyntaxKind.FinallyKeyword:
|
||||
return spanInNextNode(node);
|
||||
|
||||
case SyntaxKind.OfKeyword:
|
||||
return spanInOfKeyword(node);
|
||||
|
||||
default:
|
||||
// If this is name of property assignment, set breakpoint in the initializer
|
||||
if (node.parent.kind === SyntaxKind.PropertyAssignment && (<PropertyDeclaration>node.parent).name === node) {
|
||||
return spanInNode((<PropertyDeclaration>node.parent).initializer);
|
||||
// Destructuring pattern in destructuring assignment
|
||||
// [a, b, c] of
|
||||
// [a, b, c] = expression
|
||||
if (isArrayLiteralOrObjectLiteralDestructuringPattern(node)) {
|
||||
return spanInArrayLiteralOrObjectLiteralDestructuringPattern(<DestructuringPattern>node);
|
||||
}
|
||||
|
||||
// Set breakpoint on identifier element of destructuring pattern
|
||||
// a or ...c or d: x from
|
||||
// [a, b, ...c] or { a, b } or { d: x } from destructuring pattern
|
||||
if ((node.kind === SyntaxKind.Identifier ||
|
||||
node.kind == SyntaxKind.SpreadElementExpression ||
|
||||
node.kind === SyntaxKind.PropertyAssignment ||
|
||||
node.kind === SyntaxKind.ShorthandPropertyAssignment) &&
|
||||
isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent)) {
|
||||
return textSpan(node);
|
||||
}
|
||||
|
||||
if (node.kind === SyntaxKind.BinaryExpression) {
|
||||
const binaryExpression = <BinaryExpression>node;
|
||||
// Set breakpoint in destructuring pattern if its destructuring assignment
|
||||
// [a, b, c] or {a, b, c} of
|
||||
// [a, b, c] = expression or
|
||||
// {a, b, c} = expression
|
||||
if (isArrayLiteralOrObjectLiteralDestructuringPattern(binaryExpression.left)) {
|
||||
return spanInArrayLiteralOrObjectLiteralDestructuringPattern(
|
||||
<ArrayLiteralExpression | ObjectLiteralExpression>binaryExpression.left);
|
||||
}
|
||||
|
||||
if (binaryExpression.operatorToken.kind === SyntaxKind.EqualsToken &&
|
||||
isArrayLiteralOrObjectLiteralDestructuringPattern(binaryExpression.parent)) {
|
||||
// Set breakpoint on assignment expression element of destructuring pattern
|
||||
// a = expression of
|
||||
// [a = expression, b, c] = someExpression or
|
||||
// { a = expression, b, c } = someExpression
|
||||
return textSpan(node);
|
||||
}
|
||||
|
||||
if (binaryExpression.operatorToken.kind === SyntaxKind.CommaToken) {
|
||||
return spanInNode(binaryExpression.left);
|
||||
}
|
||||
}
|
||||
|
||||
if (isExpression(node)) {
|
||||
switch (node.parent.kind) {
|
||||
case SyntaxKind.DoStatement:
|
||||
// Set span as if on while keyword
|
||||
return spanInPreviousNode(node);
|
||||
|
||||
case SyntaxKind.Decorator:
|
||||
// Set breakpoint on the decorator emit
|
||||
return spanInNode(node.parent);
|
||||
|
||||
case SyntaxKind.ForStatement:
|
||||
case SyntaxKind.ForOfStatement:
|
||||
return textSpan(node);
|
||||
|
||||
case SyntaxKind.BinaryExpression:
|
||||
if ((<BinaryExpression>node.parent).operatorToken.kind === SyntaxKind.CommaToken) {
|
||||
// if this is comma expression, the breakpoint is possible in this expression
|
||||
return textSpan(node);
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxKind.ArrowFunction:
|
||||
if ((<FunctionLikeDeclaration>node.parent).body === node) {
|
||||
// If this is body of arrow function, it is allowed to have the breakpoint
|
||||
return textSpan(node);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If this is name of property assignment, set breakpoint in the initializer
|
||||
if (node.parent.kind === SyntaxKind.PropertyAssignment &&
|
||||
(<PropertyDeclaration>node.parent).name === node &&
|
||||
!isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent.parent)) {
|
||||
return spanInNode((<PropertyDeclaration>node.parent).initializer);
|
||||
}
|
||||
|
||||
// Breakpoint in type assertion goes to its operand
|
||||
if (node.parent.kind === SyntaxKind.TypeAssertionExpression && (<TypeAssertion>node.parent).type === node) {
|
||||
return spanInNode((<TypeAssertion>node.parent).expression);
|
||||
return spanInNextNode((<TypeAssertion>node.parent).type);
|
||||
}
|
||||
|
||||
// return type of function go to previous token
|
||||
@@ -279,48 +343,70 @@ namespace ts.BreakpointResolver {
|
||||
return spanInPreviousNode(node);
|
||||
}
|
||||
|
||||
// initializer of variable/parameter declaration go to previous node
|
||||
if ((node.parent.kind === SyntaxKind.VariableDeclaration ||
|
||||
node.parent.kind === SyntaxKind.Parameter)) {
|
||||
const paramOrVarDecl = <VariableDeclaration | ParameterDeclaration>node.parent;
|
||||
if (paramOrVarDecl.initializer === node ||
|
||||
paramOrVarDecl.type === node ||
|
||||
isAssignmentOperator(node.kind)) {
|
||||
return spanInPreviousNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
if (node.parent.kind === SyntaxKind.BinaryExpression) {
|
||||
const binaryExpression = <BinaryExpression>node.parent;
|
||||
if (isArrayLiteralOrObjectLiteralDestructuringPattern(binaryExpression.left) &&
|
||||
(binaryExpression.right === node ||
|
||||
binaryExpression.operatorToken === node)) {
|
||||
// If initializer of destructuring assignment move to previous token
|
||||
return spanInPreviousNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
// Default go to parent to set the breakpoint
|
||||
return spanInNode(node.parent);
|
||||
}
|
||||
}
|
||||
|
||||
function textSpanFromVariableDeclaration(variableDeclaration: VariableDeclaration): TextSpan {
|
||||
let declarations = variableDeclaration.parent.declarations;
|
||||
if (declarations && declarations[0] === variableDeclaration) {
|
||||
// First declaration - include let keyword
|
||||
return textSpan(findPrecedingToken(variableDeclaration.pos, sourceFile, variableDeclaration.parent), variableDeclaration);
|
||||
}
|
||||
else {
|
||||
// Span only on this declaration
|
||||
return textSpan(variableDeclaration);
|
||||
}
|
||||
}
|
||||
|
||||
function spanInVariableDeclaration(variableDeclaration: VariableDeclaration): TextSpan {
|
||||
// If declaration of for in statement, just set the span in parent
|
||||
if (variableDeclaration.parent.parent.kind === SyntaxKind.ForInStatement ||
|
||||
variableDeclaration.parent.parent.kind === SyntaxKind.ForOfStatement) {
|
||||
if (variableDeclaration.parent.parent.kind === SyntaxKind.ForInStatement) {
|
||||
return spanInNode(variableDeclaration.parent.parent);
|
||||
}
|
||||
|
||||
let isParentVariableStatement = variableDeclaration.parent.parent.kind === SyntaxKind.VariableStatement;
|
||||
let isDeclarationOfForStatement = variableDeclaration.parent.parent.kind === SyntaxKind.ForStatement && contains((<VariableDeclarationList>(<ForStatement>variableDeclaration.parent.parent).initializer).declarations, variableDeclaration);
|
||||
let declarations = isParentVariableStatement
|
||||
? (<VariableStatement>variableDeclaration.parent.parent).declarationList.declarations
|
||||
: isDeclarationOfForStatement
|
||||
? (<VariableDeclarationList>(<ForStatement>variableDeclaration.parent.parent).initializer).declarations
|
||||
: undefined;
|
||||
|
||||
// If this is a destructuring pattern set breakpoint in binding pattern
|
||||
if (isBindingPattern(variableDeclaration.name)) {
|
||||
return spanInBindingPattern(<BindingPattern>variableDeclaration.name);
|
||||
}
|
||||
|
||||
// Breakpoint is possible in variableDeclaration only if there is initialization
|
||||
if (variableDeclaration.initializer || (variableDeclaration.flags & NodeFlags.Export)) {
|
||||
if (declarations && declarations[0] === variableDeclaration) {
|
||||
if (isParentVariableStatement) {
|
||||
// First declaration - include let keyword
|
||||
return textSpan(variableDeclaration.parent, variableDeclaration);
|
||||
}
|
||||
else {
|
||||
Debug.assert(isDeclarationOfForStatement);
|
||||
// Include let keyword from for statement declarations in the span
|
||||
return textSpan(findPrecedingToken(variableDeclaration.pos, sourceFile, variableDeclaration.parent), variableDeclaration);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Span only on this declaration
|
||||
return textSpan(variableDeclaration);
|
||||
}
|
||||
// or its declaration from 'for of'
|
||||
if (variableDeclaration.initializer ||
|
||||
(variableDeclaration.flags & NodeFlags.Export) ||
|
||||
variableDeclaration.parent.parent.kind === SyntaxKind.ForOfStatement) {
|
||||
return textSpanFromVariableDeclaration(variableDeclaration);
|
||||
}
|
||||
else if (declarations && declarations[0] !== variableDeclaration) {
|
||||
|
||||
let declarations = variableDeclaration.parent.declarations;
|
||||
if (declarations && declarations[0] !== variableDeclaration) {
|
||||
// If we cant set breakpoint on this declaration, set it on previous one
|
||||
let indexOfCurrentDeclaration = indexOf(declarations, variableDeclaration);
|
||||
return spanInVariableDeclaration(declarations[indexOfCurrentDeclaration - 1]);
|
||||
// Because the variable declaration may be binding pattern and
|
||||
// we would like to set breakpoint in last binding element if thats the case,
|
||||
// use preceding token instead
|
||||
return spanInNode(findPrecedingToken(variableDeclaration.pos, sourceFile, variableDeclaration.parent));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,7 +417,11 @@ namespace ts.BreakpointResolver {
|
||||
}
|
||||
|
||||
function spanInParameterDeclaration(parameter: ParameterDeclaration): TextSpan {
|
||||
if (canHaveSpanInParameterDeclaration(parameter)) {
|
||||
if (isBindingPattern(parameter.name)) {
|
||||
// set breakpoint in binding pattern
|
||||
return spanInBindingPattern(<BindingPattern>parameter.name);
|
||||
}
|
||||
else if (canHaveSpanInParameterDeclaration(parameter)) {
|
||||
return textSpan(parameter);
|
||||
}
|
||||
else {
|
||||
@@ -388,11 +478,11 @@ namespace ts.BreakpointResolver {
|
||||
case SyntaxKind.WhileStatement:
|
||||
case SyntaxKind.IfStatement:
|
||||
case SyntaxKind.ForInStatement:
|
||||
case SyntaxKind.ForOfStatement:
|
||||
return spanInNodeIfStartsOnSameLine(block.parent, block.statements[0]);
|
||||
|
||||
// Set span on previous token if it starts on same line otherwise on the first statement of the block
|
||||
case SyntaxKind.ForStatement:
|
||||
case SyntaxKind.ForOfStatement:
|
||||
return spanInNodeIfStartsOnSameLine(findPrecedingToken(block.pos, sourceFile, block.parent), block.statements[0]);
|
||||
}
|
||||
|
||||
@@ -400,17 +490,23 @@ namespace ts.BreakpointResolver {
|
||||
return spanInNode(block.statements[0]);
|
||||
}
|
||||
|
||||
function spanInInitializerOfForLike(forLikeStaement: ForStatement | ForOfStatement | ForInStatement): TextSpan {
|
||||
if (forLikeStaement.initializer.kind === SyntaxKind.VariableDeclarationList) {
|
||||
// declaration list, set breakpoint in first declaration
|
||||
let variableDeclarationList = <VariableDeclarationList>forLikeStaement.initializer;
|
||||
if (variableDeclarationList.declarations.length > 0) {
|
||||
return spanInNode(variableDeclarationList.declarations[0]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Expression - set breakpoint in it
|
||||
return spanInNode(forLikeStaement.initializer);
|
||||
}
|
||||
}
|
||||
|
||||
function spanInForStatement(forStatement: ForStatement): TextSpan {
|
||||
if (forStatement.initializer) {
|
||||
if (forStatement.initializer.kind === SyntaxKind.VariableDeclarationList) {
|
||||
let variableDeclarationList = <VariableDeclarationList>forStatement.initializer;
|
||||
if (variableDeclarationList.declarations.length > 0) {
|
||||
return spanInNode(variableDeclarationList.declarations[0]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return spanInNode(forStatement.initializer);
|
||||
}
|
||||
return spanInInitializerOfForLike(forStatement);
|
||||
}
|
||||
|
||||
if (forStatement.condition) {
|
||||
@@ -421,6 +517,45 @@ namespace ts.BreakpointResolver {
|
||||
}
|
||||
}
|
||||
|
||||
function spanInBindingPattern(bindingPattern: BindingPattern): TextSpan {
|
||||
// Set breakpoint in first binding element
|
||||
let firstBindingElement = forEach(bindingPattern.elements,
|
||||
element => element.kind !== SyntaxKind.OmittedExpression ? element : undefined);
|
||||
|
||||
if (firstBindingElement) {
|
||||
return spanInNode(firstBindingElement);
|
||||
}
|
||||
|
||||
// Empty binding pattern of binding element, set breakpoint on binding element
|
||||
if (bindingPattern.parent.kind === SyntaxKind.BindingElement) {
|
||||
return textSpan(bindingPattern.parent);
|
||||
}
|
||||
|
||||
// Variable declaration is used as the span
|
||||
return textSpanFromVariableDeclaration(<VariableDeclaration>bindingPattern.parent);
|
||||
}
|
||||
|
||||
function spanInArrayLiteralOrObjectLiteralDestructuringPattern(node: DestructuringPattern): TextSpan {
|
||||
Debug.assert(node.kind !== SyntaxKind.ArrayBindingPattern && node.kind !== SyntaxKind.ObjectBindingPattern);
|
||||
const elements: NodeArray<Expression | ObjectLiteralElement> =
|
||||
node.kind === SyntaxKind.ArrayLiteralExpression ?
|
||||
(<ArrayLiteralExpression>node).elements :
|
||||
(<ObjectLiteralExpression>node).properties;
|
||||
|
||||
const firstBindingElement = forEach(elements,
|
||||
element => element.kind !== SyntaxKind.OmittedExpression ? element : undefined);
|
||||
|
||||
if (firstBindingElement) {
|
||||
return spanInNode(firstBindingElement);
|
||||
}
|
||||
|
||||
// Could be ArrayLiteral from destructuring assignment or
|
||||
// just nested element in another destructuring assignment
|
||||
// set breakpoint on assignment when parent is destructuring assignment
|
||||
// Otherwise set breakpoint for this element
|
||||
return textSpan(node.parent.kind === SyntaxKind.BinaryExpression ? node.parent : node);
|
||||
}
|
||||
|
||||
// Tokens:
|
||||
function spanInOpenBraceToken(node: Node): TextSpan {
|
||||
switch (node.parent.kind) {
|
||||
@@ -472,18 +607,52 @@ namespace ts.BreakpointResolver {
|
||||
}
|
||||
return undefined;
|
||||
|
||||
case SyntaxKind.ObjectBindingPattern:
|
||||
// Breakpoint in last binding element or binding pattern if it contains no elements
|
||||
let bindingPattern = <BindingPattern>node.parent;
|
||||
return spanInNode(lastOrUndefined(bindingPattern.elements) || bindingPattern);
|
||||
|
||||
// Default to parent node
|
||||
default:
|
||||
if (isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent)) {
|
||||
// Breakpoint in last binding element or binding pattern if it contains no elements
|
||||
let objectLiteral = <ObjectLiteralExpression>node.parent;
|
||||
return textSpan(lastOrUndefined(objectLiteral.properties) || objectLiteral);
|
||||
}
|
||||
return spanInNode(node.parent);
|
||||
}
|
||||
}
|
||||
|
||||
function spanInCloseBracketToken(node: Node): TextSpan {
|
||||
switch (node.parent.kind) {
|
||||
case SyntaxKind.ArrayBindingPattern:
|
||||
// Breakpoint in last binding element or binding pattern if it contains no elements
|
||||
let bindingPattern = <BindingPattern>node.parent;
|
||||
return textSpan(lastOrUndefined(bindingPattern.elements) || bindingPattern);
|
||||
|
||||
default:
|
||||
if (isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent)) {
|
||||
// Breakpoint in last binding element or binding pattern if it contains no elements
|
||||
let arrayLiteral = <ArrayLiteralExpression>node.parent;
|
||||
return textSpan(lastOrUndefined(arrayLiteral.elements) || arrayLiteral);
|
||||
}
|
||||
|
||||
// Default to parent node
|
||||
return spanInNode(node.parent);
|
||||
}
|
||||
}
|
||||
|
||||
function spanInOpenParenToken(node: Node): TextSpan {
|
||||
if (node.parent.kind === SyntaxKind.DoStatement) {
|
||||
// Go to while keyword and do action instead
|
||||
if (node.parent.kind === SyntaxKind.DoStatement || // Go to while keyword and do action instead
|
||||
node.parent.kind === SyntaxKind.CallExpression ||
|
||||
node.parent.kind === SyntaxKind.NewExpression) {
|
||||
return spanInPreviousNode(node);
|
||||
}
|
||||
|
||||
if (node.parent.kind === SyntaxKind.ParenthesizedExpression) {
|
||||
return spanInNextNode(node);
|
||||
}
|
||||
|
||||
// Default to parent node
|
||||
return spanInNode(node.parent);
|
||||
}
|
||||
@@ -502,6 +671,10 @@ namespace ts.BreakpointResolver {
|
||||
case SyntaxKind.WhileStatement:
|
||||
case SyntaxKind.DoStatement:
|
||||
case SyntaxKind.ForStatement:
|
||||
case SyntaxKind.ForOfStatement:
|
||||
case SyntaxKind.CallExpression:
|
||||
case SyntaxKind.NewExpression:
|
||||
case SyntaxKind.ParenthesizedExpression:
|
||||
return spanInPreviousNode(node);
|
||||
|
||||
// Default to parent node
|
||||
@@ -512,7 +685,9 @@ namespace ts.BreakpointResolver {
|
||||
|
||||
function spanInColonToken(node: Node): TextSpan {
|
||||
// Is this : specifying return annotation of the function declaration
|
||||
if (isFunctionLike(node.parent) || node.parent.kind === SyntaxKind.PropertyAssignment) {
|
||||
if (isFunctionLike(node.parent) ||
|
||||
node.parent.kind === SyntaxKind.PropertyAssignment ||
|
||||
node.parent.kind === SyntaxKind.Parameter) {
|
||||
return spanInPreviousNode(node);
|
||||
}
|
||||
|
||||
@@ -521,7 +696,7 @@ namespace ts.BreakpointResolver {
|
||||
|
||||
function spanInGreaterThanOrLessThanToken(node: Node): TextSpan {
|
||||
if (node.parent.kind === SyntaxKind.TypeAssertionExpression) {
|
||||
return spanInNode((<TypeAssertion>node.parent).expression);
|
||||
return spanInNextNode(node);
|
||||
}
|
||||
|
||||
return spanInNode(node.parent);
|
||||
@@ -530,7 +705,17 @@ namespace ts.BreakpointResolver {
|
||||
function spanInWhileKeyword(node: Node): TextSpan {
|
||||
if (node.parent.kind === SyntaxKind.DoStatement) {
|
||||
// Set span on while expression
|
||||
return textSpan(node, findNextToken((<DoStatement>node.parent).expression, node.parent));
|
||||
return textSpanEndingAtNextToken(node, (<DoStatement>node.parent).expression);
|
||||
}
|
||||
|
||||
// Default to parent node
|
||||
return spanInNode(node.parent);
|
||||
}
|
||||
|
||||
function spanInOfKeyword(node: Node): TextSpan {
|
||||
if (node.parent.kind === SyntaxKind.ForOfStatement) {
|
||||
// set using next token
|
||||
return spanInNextNode(node);
|
||||
}
|
||||
|
||||
// Default to parent node
|
||||
|
||||
@@ -121,7 +121,7 @@ namespace ts.formatting {
|
||||
|
||||
function findOutermostParent(position: number, expectedTokenKind: SyntaxKind, sourceFile: SourceFile): Node {
|
||||
let precedingToken = findPrecedingToken(position, sourceFile);
|
||||
|
||||
|
||||
// when it is claimed that trigger character was typed at given position
|
||||
// we verify that there is a token with a matching kind whose end is equal to position (because the character was just typed).
|
||||
// If this condition is not hold - then trigger character was typed in some other context,
|
||||
@@ -151,7 +151,7 @@ namespace ts.formatting {
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
|
||||
// Returns true if node is a element in some list in parent
|
||||
// i.e. parent is class declaration with the list of members and node is one of members.
|
||||
function isListElement(parent: Node, node: Node): boolean {
|
||||
@@ -198,7 +198,7 @@ namespace ts.formatting {
|
||||
if (!errors.length) {
|
||||
return rangeHasNoErrors;
|
||||
}
|
||||
|
||||
|
||||
// pick only errors that fall in range
|
||||
let sorted = errors
|
||||
.filter(d => rangeOverlapsWithStartEnd(originalRange, d.start, d.start + d.length))
|
||||
@@ -341,6 +341,14 @@ namespace ts.formatting {
|
||||
processNode(enclosingNode, enclosingNode, startLine, undecoratedStartLine, initialIndentation, delta);
|
||||
}
|
||||
|
||||
if (!formattingScanner.isOnToken()) {
|
||||
let leadingTrivia = formattingScanner.getCurrentLeadingTrivia();
|
||||
if (leadingTrivia) {
|
||||
processTrivia(leadingTrivia, enclosingNode, enclosingNode, undefined);
|
||||
trimTrailingWhitespacesForRemainingRange();
|
||||
}
|
||||
}
|
||||
|
||||
formattingScanner.close();
|
||||
|
||||
return edits;
|
||||
@@ -360,7 +368,9 @@ namespace ts.formatting {
|
||||
range: TextRange,
|
||||
inheritedIndentation: number): number {
|
||||
|
||||
if (rangeOverlapsWithStartEnd(range, startPos, endPos)) {
|
||||
if (rangeOverlapsWithStartEnd(range, startPos, endPos) ||
|
||||
rangeContainsStartEnd(range, startPos, endPos) /* Not to miss zero-range nodes e.g. JsxText */) {
|
||||
|
||||
if (inheritedIndentation !== Constants.Unknown) {
|
||||
return inheritedIndentation;
|
||||
}
|
||||
@@ -826,9 +836,7 @@ namespace ts.formatting {
|
||||
}
|
||||
|
||||
// We need to trim trailing whitespace between the tokens if they were on different lines, and no rule was applied to put them on the same line
|
||||
trimTrailingWhitespaces =
|
||||
(rule.Operation.Action & (RuleAction.NewLine | RuleAction.Space)) &&
|
||||
rule.Flag !== RuleFlags.CanDeleteNewLines;
|
||||
trimTrailingWhitespaces = !(rule.Operation.Action & RuleAction.Delete) && rule.Flag !== RuleFlags.CanDeleteNewLines;
|
||||
}
|
||||
else {
|
||||
trimTrailingWhitespaces = true;
|
||||
@@ -927,17 +935,41 @@ namespace ts.formatting {
|
||||
continue;
|
||||
}
|
||||
|
||||
let pos = lineEndPosition;
|
||||
while (pos >= lineStartPosition && isWhiteSpace(sourceFile.text.charCodeAt(pos))) {
|
||||
pos--;
|
||||
}
|
||||
if (pos !== lineEndPosition) {
|
||||
Debug.assert(pos === lineStartPosition || !isWhiteSpace(sourceFile.text.charCodeAt(pos)));
|
||||
recordDelete(pos + 1, lineEndPosition - pos);
|
||||
let whitespaceStart = getTrailingWhitespaceStartPosition(lineStartPosition, lineEndPosition);
|
||||
if (whitespaceStart !== -1) {
|
||||
Debug.assert(whitespaceStart === lineStartPosition || !isWhiteSpace(sourceFile.text.charCodeAt(whitespaceStart - 1)));
|
||||
recordDelete(whitespaceStart, lineEndPosition + 1 - whitespaceStart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param start The position of the first character in range
|
||||
* @param end The position of the last character in range
|
||||
*/
|
||||
function getTrailingWhitespaceStartPosition(start: number, end: number) {
|
||||
let pos = end;
|
||||
while (pos >= start && isWhiteSpace(sourceFile.text.charCodeAt(pos))) {
|
||||
pos--;
|
||||
}
|
||||
if (pos !== end) {
|
||||
return pos + 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trimming will be done for lines after the previous range
|
||||
*/
|
||||
function trimTrailingWhitespacesForRemainingRange() {
|
||||
let startPosition = previousRange ? previousRange.end : originalRange.pos;
|
||||
|
||||
let startLine = sourceFile.getLineAndCharacterOfPosition(startPosition).line;
|
||||
let endLine = sourceFile.getLineAndCharacterOfPosition(originalRange.end).line;
|
||||
|
||||
trimTrailingWhitespacesForLines(startLine, endLine + 1, previousRange);
|
||||
}
|
||||
|
||||
function newTextChange(start: number, len: number, newText: string): TextChange {
|
||||
return { span: createTextSpan(start, len), newText }
|
||||
}
|
||||
|
||||
@@ -5,21 +5,22 @@
|
||||
namespace ts.formatting {
|
||||
const standardScanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ false, LanguageVariant.Standard);
|
||||
const jsxScanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ false, LanguageVariant.JSX);
|
||||
|
||||
|
||||
/**
|
||||
* Scanner that is currently used for formatting
|
||||
*/
|
||||
let scanner: Scanner;
|
||||
|
||||
|
||||
export interface FormattingScanner {
|
||||
advance(): void;
|
||||
isOnToken(): boolean;
|
||||
readTokenInfo(n: Node): TokenInfo;
|
||||
getCurrentLeadingTrivia(): TextRangeWithKind[];
|
||||
lastTrailingTriviaWasNewLine(): boolean;
|
||||
close(): void;
|
||||
}
|
||||
|
||||
const enum ScanAction{
|
||||
const enum ScanAction {
|
||||
Scan,
|
||||
RescanGreaterThanToken,
|
||||
RescanSlashToken,
|
||||
@@ -37,19 +38,20 @@ namespace ts.formatting {
|
||||
let wasNewLine: boolean = true;
|
||||
let leadingTrivia: TextRangeWithKind[];
|
||||
let trailingTrivia: TextRangeWithKind[];
|
||||
|
||||
|
||||
let savedPos: number;
|
||||
let lastScanAction: ScanAction;
|
||||
let lastTokenInfo: TokenInfo;
|
||||
|
||||
return {
|
||||
advance: advance,
|
||||
readTokenInfo: readTokenInfo,
|
||||
isOnToken: isOnToken,
|
||||
advance,
|
||||
readTokenInfo,
|
||||
isOnToken,
|
||||
getCurrentLeadingTrivia: () => leadingTrivia,
|
||||
lastTrailingTriviaWasNewLine: () => wasNewLine,
|
||||
close: () => {
|
||||
Debug.assert(scanner !== undefined);
|
||||
|
||||
|
||||
lastTokenInfo = undefined;
|
||||
scanner.setText(undefined);
|
||||
scanner = undefined;
|
||||
@@ -58,7 +60,7 @@ namespace ts.formatting {
|
||||
|
||||
function advance(): void {
|
||||
Debug.assert(scanner !== undefined);
|
||||
|
||||
|
||||
lastTokenInfo = undefined;
|
||||
let isStarted = scanner.getStartPos() !== startPos;
|
||||
|
||||
@@ -81,7 +83,7 @@ namespace ts.formatting {
|
||||
|
||||
let t: SyntaxKind;
|
||||
let pos = scanner.getStartPos();
|
||||
|
||||
|
||||
// Read leading trivia and token
|
||||
while (pos < endPos) {
|
||||
let t = scanner.getToken();
|
||||
@@ -122,10 +124,10 @@ namespace ts.formatting {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function shouldRescanJsxIdentifier(node: Node): boolean {
|
||||
if (node.parent) {
|
||||
switch(node.parent.kind) {
|
||||
switch (node.parent.kind) {
|
||||
case SyntaxKind.JsxAttribute:
|
||||
case SyntaxKind.JsxOpeningElement:
|
||||
case SyntaxKind.JsxClosingElement:
|
||||
@@ -133,7 +135,7 @@ namespace ts.formatting {
|
||||
return node.kind === SyntaxKind.Identifier;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -142,7 +144,7 @@ namespace ts.formatting {
|
||||
}
|
||||
|
||||
function shouldRescanTemplateToken(container: Node): boolean {
|
||||
return container.kind === SyntaxKind.TemplateMiddle ||
|
||||
return container.kind === SyntaxKind.TemplateMiddle ||
|
||||
container.kind === SyntaxKind.TemplateTail;
|
||||
}
|
||||
|
||||
@@ -152,11 +154,11 @@ namespace ts.formatting {
|
||||
|
||||
function readTokenInfo(n: Node): TokenInfo {
|
||||
Debug.assert(scanner !== undefined);
|
||||
|
||||
|
||||
if (!isOnToken()) {
|
||||
// scanner is not on the token (either advance was not called yet or scanner is already past the end position)
|
||||
return {
|
||||
leadingTrivia: leadingTrivia,
|
||||
leadingTrivia,
|
||||
trailingTrivia: undefined,
|
||||
token: undefined
|
||||
};
|
||||
@@ -164,7 +166,7 @@ namespace ts.formatting {
|
||||
|
||||
// normally scanner returns the smallest available token
|
||||
// check the kind of context node to determine if scanner should have more greedy behavior and consume more text.
|
||||
let expectedScanAction =
|
||||
let expectedScanAction =
|
||||
shouldRescanGreaterThanToken(n)
|
||||
? ScanAction.RescanGreaterThanToken
|
||||
: shouldRescanSlashToken(n)
|
||||
@@ -226,7 +228,7 @@ namespace ts.formatting {
|
||||
if (trailingTrivia) {
|
||||
trailingTrivia = undefined;
|
||||
}
|
||||
while(scanner.getStartPos() < endPos) {
|
||||
while (scanner.getStartPos() < endPos) {
|
||||
currentToken = scanner.scan();
|
||||
if (!isTrivia(currentToken)) {
|
||||
break;
|
||||
@@ -261,7 +263,7 @@ namespace ts.formatting {
|
||||
|
||||
function isOnToken(): boolean {
|
||||
Debug.assert(scanner !== undefined);
|
||||
|
||||
|
||||
let current = (lastTokenInfo && lastTokenInfo.token.kind) || scanner.getToken();
|
||||
let startPos = (lastTokenInfo && lastTokenInfo.token.pos) || scanner.getStartPos();
|
||||
return startPos < endPos && current !== SyntaxKind.EndOfFileToken && !isTrivia(current);
|
||||
|
||||
@@ -219,9 +219,11 @@ namespace ts.formatting {
|
||||
public SpaceBetweenAsyncAndFunctionKeyword: Rule;
|
||||
|
||||
// Template strings
|
||||
public SpaceBetweenTagAndTemplateString: Rule;
|
||||
public NoSpaceBetweenTagAndTemplateString: Rule;
|
||||
public NoSpaceAfterTemplateHeadAndMiddle: Rule;
|
||||
public SpaceAfterTemplateHeadAndMiddle: Rule;
|
||||
public NoSpaceBeforeTemplateMiddleAndTail: Rule;
|
||||
public SpaceBeforeTemplateMiddleAndTail: Rule;
|
||||
|
||||
constructor() {
|
||||
///
|
||||
@@ -376,9 +378,7 @@ namespace ts.formatting {
|
||||
this.SpaceBetweenAsyncAndFunctionKeyword = new Rule(RuleDescriptor.create1(SyntaxKind.AsyncKeyword, SyntaxKind.FunctionKeyword), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));
|
||||
|
||||
// template string
|
||||
this.SpaceBetweenTagAndTemplateString = new Rule(RuleDescriptor.create3(SyntaxKind.Identifier, Shared.TokenRange.FromTokens([SyntaxKind.NoSubstitutionTemplateLiteral, SyntaxKind.TemplateHead])), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));
|
||||
this.NoSpaceAfterTemplateHeadAndMiddle = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.TemplateHead, SyntaxKind.TemplateMiddle]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
|
||||
this.NoSpaceBeforeTemplateMiddleAndTail = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.FromTokens([SyntaxKind.TemplateMiddle, SyntaxKind.TemplateTail])), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
|
||||
this.NoSpaceBetweenTagAndTemplateString = new Rule(RuleDescriptor.create3(SyntaxKind.Identifier, Shared.TokenRange.FromTokens([SyntaxKind.NoSubstitutionTemplateLiteral, SyntaxKind.TemplateHead])), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
|
||||
|
||||
// These rules are higher in priority than user-configurable rules.
|
||||
this.HighPriorityCommonRules = [
|
||||
@@ -406,7 +406,7 @@ namespace ts.formatting {
|
||||
this.SpaceBeforeBinaryKeywordOperator, this.SpaceAfterBinaryKeywordOperator,
|
||||
this.SpaceAfterVoidOperator,
|
||||
this.SpaceBetweenAsyncAndOpenParen, this.SpaceBetweenAsyncAndFunctionKeyword,
|
||||
this.SpaceBetweenTagAndTemplateString, this.NoSpaceAfterTemplateHeadAndMiddle, this.NoSpaceBeforeTemplateMiddleAndTail,
|
||||
this.NoSpaceBetweenTagAndTemplateString,
|
||||
|
||||
// TypeScript-specific rules
|
||||
this.NoSpaceAfterConstructor, this.NoSpaceAfterModuleImport,
|
||||
@@ -444,7 +444,7 @@ namespace ts.formatting {
|
||||
///
|
||||
|
||||
// Insert space after comma delimiter
|
||||
this.SpaceAfterComma = new Rule(RuleDescriptor.create3(SyntaxKind.CommaToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));
|
||||
this.SpaceAfterComma = new Rule(RuleDescriptor.create3(SyntaxKind.CommaToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNextTokenNotCloseBracket), RuleAction.Space));
|
||||
this.NoSpaceAfterComma = new Rule(RuleDescriptor.create3(SyntaxKind.CommaToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
|
||||
|
||||
// Insert space before and after binary operators
|
||||
@@ -485,6 +485,12 @@ namespace ts.formatting {
|
||||
this.NoSpaceAfterOpenBracket = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBracketToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
|
||||
this.NoSpaceBeforeCloseBracket = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBracketToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
|
||||
|
||||
// Insert space after opening and before closing template string braces
|
||||
this.NoSpaceAfterTemplateHeadAndMiddle = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.TemplateHead, SyntaxKind.TemplateMiddle]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
|
||||
this.SpaceAfterTemplateHeadAndMiddle = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.TemplateHead, SyntaxKind.TemplateMiddle]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));
|
||||
this.NoSpaceBeforeTemplateMiddleAndTail = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.FromTokens([SyntaxKind.TemplateMiddle, SyntaxKind.TemplateTail])), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
|
||||
this.SpaceBeforeTemplateMiddleAndTail = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.FromTokens([SyntaxKind.TemplateMiddle, SyntaxKind.TemplateTail])), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));
|
||||
|
||||
// Insert space after function keyword for anonymous functions
|
||||
this.SpaceAfterAnonymousFunctionKeyword = new Rule(RuleDescriptor.create1(SyntaxKind.FunctionKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Space));
|
||||
this.NoSpaceAfterAnonymousFunctionKeyword = new Rule(RuleDescriptor.create1(SyntaxKind.FunctionKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Delete));
|
||||
@@ -705,6 +711,10 @@ namespace ts.formatting {
|
||||
return context.currentTokenSpan.kind !== SyntaxKind.CommaToken;
|
||||
}
|
||||
|
||||
static IsNextTokenNotCloseBracket(context: FormattingContext): boolean {
|
||||
return context.nextTokenSpan.kind !== SyntaxKind.CloseBracketToken;
|
||||
}
|
||||
|
||||
static IsArrowFunctionContext(context: FormattingContext): boolean {
|
||||
return context.contextNode.kind === SyntaxKind.ArrowFunction;
|
||||
}
|
||||
|
||||
@@ -71,15 +71,24 @@ namespace ts.formatting {
|
||||
rules.push(this.globalRules.NoSpaceBetweenParens);
|
||||
}
|
||||
|
||||
if ( options.InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets ) {
|
||||
rules.push( this.globalRules.SpaceAfterOpenBracket );
|
||||
rules.push( this.globalRules.SpaceBeforeCloseBracket );
|
||||
rules.push( this.globalRules.NoSpaceBetweenBrackets );
|
||||
if (options.InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets) {
|
||||
rules.push(this.globalRules.SpaceAfterOpenBracket);
|
||||
rules.push(this.globalRules.SpaceBeforeCloseBracket);
|
||||
rules.push(this.globalRules.NoSpaceBetweenBrackets);
|
||||
}
|
||||
else {
|
||||
rules.push( this.globalRules.NoSpaceAfterOpenBracket );
|
||||
rules.push( this.globalRules.NoSpaceBeforeCloseBracket );
|
||||
rules.push( this.globalRules.NoSpaceBetweenBrackets );
|
||||
rules.push(this.globalRules.NoSpaceAfterOpenBracket);
|
||||
rules.push(this.globalRules.NoSpaceBeforeCloseBracket);
|
||||
rules.push(this.globalRules.NoSpaceBetweenBrackets);
|
||||
}
|
||||
|
||||
if (options.InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces) {
|
||||
rules.push(this.globalRules.SpaceAfterTemplateHeadAndMiddle);
|
||||
rules.push(this.globalRules.SpaceBeforeTemplateMiddleAndTail);
|
||||
}
|
||||
else {
|
||||
rules.push(this.globalRules.NoSpaceAfterTemplateHeadAndMiddle);
|
||||
rules.push(this.globalRules.NoSpaceBeforeTemplateMiddleAndTail);
|
||||
}
|
||||
|
||||
if (options.InsertSpaceAfterSemicolonInForStatements) {
|
||||
|
||||
@@ -450,8 +450,9 @@ namespace ts.formatting {
|
||||
case SyntaxKind.ConditionalExpression:
|
||||
case SyntaxKind.ArrayBindingPattern:
|
||||
case SyntaxKind.ObjectBindingPattern:
|
||||
case SyntaxKind.JsxElement:
|
||||
case SyntaxKind.JsxOpeningElement:
|
||||
case SyntaxKind.JsxSelfClosingElement:
|
||||
case SyntaxKind.JsxExpression:
|
||||
case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
@@ -467,6 +468,7 @@ namespace ts.formatting {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function nodeWillIndentChild(parent: TextRangeWithKind, child: TextRangeWithKind, indentByDefault: boolean) {
|
||||
let childKind = child ? child.kind : SyntaxKind.Unknown;
|
||||
switch (parent.kind) {
|
||||
@@ -484,6 +486,8 @@ namespace ts.formatting {
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
return childKind !== SyntaxKind.Block;
|
||||
case SyntaxKind.JsxElement:
|
||||
return childKind !== SyntaxKind.JsxClosingElement;
|
||||
}
|
||||
// No explicit rule for given nodes so the result will follow the default value argument
|
||||
return indentByDefault;
|
||||
|
||||
+24
-24
@@ -3,19 +3,19 @@ namespace ts.NavigateTo {
|
||||
type RawNavigateToItem = { name: string; fileName: string; matchKind: PatternMatchKind; isCaseSensitive: boolean; declaration: Declaration };
|
||||
|
||||
export function getNavigateToItems(program: Program, cancellationToken: CancellationToken, searchValue: string, maxResultCount: number): NavigateToItem[] {
|
||||
let patternMatcher = createPatternMatcher(searchValue);
|
||||
const patternMatcher = createPatternMatcher(searchValue);
|
||||
let rawItems: RawNavigateToItem[] = [];
|
||||
|
||||
// This means "compare in a case insensitive manner."
|
||||
let baseSensitivity: Intl.CollatorOptions = { sensitivity: "base" };
|
||||
const baseSensitivity: Intl.CollatorOptions = { sensitivity: "base" };
|
||||
|
||||
// Search the declarations in all files and output matched NavigateToItem into array of NavigateToItem[]
|
||||
forEach(program.getSourceFiles(), sourceFile => {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
|
||||
let nameToDeclarations = sourceFile.getNamedDeclarations();
|
||||
for (let name in nameToDeclarations) {
|
||||
let declarations = getProperty(nameToDeclarations, name);
|
||||
const nameToDeclarations = sourceFile.getNamedDeclarations();
|
||||
for (const name in nameToDeclarations) {
|
||||
const declarations = getProperty(nameToDeclarations, name);
|
||||
if (declarations) {
|
||||
// First do a quick check to see if the name of the declaration matches the
|
||||
// last portion of the (possibly) dotted name they're searching for.
|
||||
@@ -25,11 +25,11 @@ namespace ts.NavigateTo {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (let declaration of declarations) {
|
||||
for (const declaration of declarations) {
|
||||
// It was a match! If the pattern has dots in it, then also see if the
|
||||
// declaration container matches as well.
|
||||
if (patternMatcher.patternContainsDots) {
|
||||
let containers = getContainers(declaration);
|
||||
const containers = getContainers(declaration);
|
||||
if (!containers) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -41,8 +41,8 @@ namespace ts.NavigateTo {
|
||||
}
|
||||
}
|
||||
|
||||
let fileName = sourceFile.fileName;
|
||||
let matchKind = bestMatchKind(matches);
|
||||
const fileName = sourceFile.fileName;
|
||||
const matchKind = bestMatchKind(matches);
|
||||
rawItems.push({ name, fileName, matchKind, isCaseSensitive: allMatchesAreCaseSensitive(matches), declaration });
|
||||
}
|
||||
}
|
||||
@@ -54,7 +54,7 @@ namespace ts.NavigateTo {
|
||||
rawItems = rawItems.slice(0, maxResultCount);
|
||||
}
|
||||
|
||||
let items = map(rawItems, createNavigateToItem);
|
||||
const items = map(rawItems, createNavigateToItem);
|
||||
|
||||
return items;
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace ts.NavigateTo {
|
||||
Debug.assert(matches.length > 0);
|
||||
|
||||
// This is a case sensitive match, only if all the submatches were case sensitive.
|
||||
for (let match of matches) {
|
||||
for (const match of matches) {
|
||||
if (!match.isCaseSensitive) {
|
||||
return false;
|
||||
}
|
||||
@@ -86,16 +86,16 @@ namespace ts.NavigateTo {
|
||||
|
||||
function tryAddSingleDeclarationName(declaration: Declaration, containers: string[]) {
|
||||
if (declaration && declaration.name) {
|
||||
let text = getTextOfIdentifierOrLiteral(declaration.name);
|
||||
const text = getTextOfIdentifierOrLiteral(declaration.name);
|
||||
if (text !== undefined) {
|
||||
containers.unshift(text);
|
||||
}
|
||||
else if (declaration.name.kind === SyntaxKind.ComputedPropertyName) {
|
||||
return tryAddComputedPropertyName((<ComputedPropertyName>declaration.name).expression, containers, /*includeLastPortion:*/ true);
|
||||
return tryAddComputedPropertyName((<ComputedPropertyName>declaration.name).expression, containers, /*includeLastPortion*/ true);
|
||||
}
|
||||
else {
|
||||
// Don't know how to add this.
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ namespace ts.NavigateTo {
|
||||
//
|
||||
// [X.Y.Z]() { }
|
||||
function tryAddComputedPropertyName(expression: Expression, containers: string[], includeLastPortion: boolean): boolean {
|
||||
let text = getTextOfIdentifierOrLiteral(expression);
|
||||
const text = getTextOfIdentifierOrLiteral(expression);
|
||||
if (text !== undefined) {
|
||||
if (includeLastPortion) {
|
||||
containers.unshift(text);
|
||||
@@ -115,24 +115,24 @@ namespace ts.NavigateTo {
|
||||
}
|
||||
|
||||
if (expression.kind === SyntaxKind.PropertyAccessExpression) {
|
||||
let propertyAccess = <PropertyAccessExpression>expression;
|
||||
const propertyAccess = <PropertyAccessExpression>expression;
|
||||
if (includeLastPortion) {
|
||||
containers.unshift(propertyAccess.name.text);
|
||||
}
|
||||
|
||||
return tryAddComputedPropertyName(propertyAccess.expression, containers, /*includeLastPortion:*/ true);
|
||||
return tryAddComputedPropertyName(propertyAccess.expression, containers, /*includeLastPortion*/ true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getContainers(declaration: Declaration) {
|
||||
let containers: string[] = [];
|
||||
const containers: string[] = [];
|
||||
|
||||
// First, if we started with a computed property name, then add all but the last
|
||||
// portion into the container array.
|
||||
if (declaration.name.kind === SyntaxKind.ComputedPropertyName) {
|
||||
if (!tryAddComputedPropertyName((<ComputedPropertyName>declaration.name).expression, containers, /*includeLastPortion:*/ false)) {
|
||||
if (!tryAddComputedPropertyName((<ComputedPropertyName>declaration.name).expression, containers, /*includeLastPortion*/ false)) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
@@ -155,8 +155,8 @@ namespace ts.NavigateTo {
|
||||
Debug.assert(matches.length > 0);
|
||||
let bestMatchKind = PatternMatchKind.camelCase;
|
||||
|
||||
for (let match of matches) {
|
||||
let kind = match.kind;
|
||||
for (const match of matches) {
|
||||
const kind = match.kind;
|
||||
if (kind < bestMatchKind) {
|
||||
bestMatchKind = kind;
|
||||
}
|
||||
@@ -171,13 +171,13 @@ namespace ts.NavigateTo {
|
||||
// We first sort case insensitively. So "Aaa" will come before "bar".
|
||||
// Then we sort case sensitively, so "aaa" will come before "Aaa".
|
||||
return i1.matchKind - i2.matchKind ||
|
||||
i1.name.localeCompare(i2.name, undefined, baseSensitivity) ||
|
||||
i1.name.localeCompare(i2.name, undefined, baseSensitivity) ||
|
||||
i1.name.localeCompare(i2.name);
|
||||
}
|
||||
|
||||
function createNavigateToItem(rawItem: RawNavigateToItem): NavigateToItem {
|
||||
let declaration = rawItem.declaration;
|
||||
let container = <Declaration>getContainerNode(declaration);
|
||||
const declaration = rawItem.declaration;
|
||||
const container = <Declaration>getContainerNode(declaration);
|
||||
return {
|
||||
name: rawItem.name,
|
||||
kind: getNodeKind(declaration),
|
||||
|
||||
@@ -1,180 +1,179 @@
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export module OutliningElementsCollector {
|
||||
export function collectElements(sourceFile: SourceFile): OutliningSpan[] {
|
||||
let elements: OutliningSpan[] = [];
|
||||
let collapseText = "...";
|
||||
namespace ts.OutliningElementsCollector {
|
||||
export function collectElements(sourceFile: SourceFile): OutliningSpan[] {
|
||||
const elements: OutliningSpan[] = [];
|
||||
const collapseText = "...";
|
||||
|
||||
function addOutliningSpan(hintSpanNode: Node, startElement: Node, endElement: Node, autoCollapse: boolean) {
|
||||
if (hintSpanNode && startElement && endElement) {
|
||||
let span: OutliningSpan = {
|
||||
textSpan: createTextSpanFromBounds(startElement.pos, endElement.end),
|
||||
hintSpan: createTextSpanFromBounds(hintSpanNode.getStart(), hintSpanNode.end),
|
||||
bannerText: collapseText,
|
||||
autoCollapse: autoCollapse
|
||||
};
|
||||
elements.push(span);
|
||||
}
|
||||
function addOutliningSpan(hintSpanNode: Node, startElement: Node, endElement: Node, autoCollapse: boolean) {
|
||||
if (hintSpanNode && startElement && endElement) {
|
||||
const span: OutliningSpan = {
|
||||
textSpan: createTextSpanFromBounds(startElement.pos, endElement.end),
|
||||
hintSpan: createTextSpanFromBounds(hintSpanNode.getStart(), hintSpanNode.end),
|
||||
bannerText: collapseText,
|
||||
autoCollapse: autoCollapse
|
||||
};
|
||||
elements.push(span);
|
||||
}
|
||||
}
|
||||
|
||||
function addOutliningSpanComments(commentSpan: CommentRange, autoCollapse: boolean) {
|
||||
if (commentSpan) {
|
||||
let span: OutliningSpan = {
|
||||
textSpan: createTextSpanFromBounds(commentSpan.pos, commentSpan.end),
|
||||
hintSpan: createTextSpanFromBounds(commentSpan.pos, commentSpan.end),
|
||||
bannerText: collapseText,
|
||||
autoCollapse: autoCollapse
|
||||
};
|
||||
elements.push(span);
|
||||
}
|
||||
function addOutliningSpanComments(commentSpan: CommentRange, autoCollapse: boolean) {
|
||||
if (commentSpan) {
|
||||
const span: OutliningSpan = {
|
||||
textSpan: createTextSpanFromBounds(commentSpan.pos, commentSpan.end),
|
||||
hintSpan: createTextSpanFromBounds(commentSpan.pos, commentSpan.end),
|
||||
bannerText: collapseText,
|
||||
autoCollapse: autoCollapse
|
||||
};
|
||||
elements.push(span);
|
||||
}
|
||||
}
|
||||
|
||||
function addOutliningForLeadingCommentsForNode(n: Node) {
|
||||
let comments = ts.getLeadingCommentRangesOfNode(n, sourceFile);
|
||||
function addOutliningForLeadingCommentsForNode(n: Node) {
|
||||
const comments = ts.getLeadingCommentRangesOfNode(n, sourceFile);
|
||||
|
||||
if (comments) {
|
||||
let firstSingleLineCommentStart = -1;
|
||||
let lastSingleLineCommentEnd = -1;
|
||||
let isFirstSingleLineComment = true;
|
||||
let singleLineCommentCount = 0;
|
||||
if (comments) {
|
||||
let firstSingleLineCommentStart = -1;
|
||||
let lastSingleLineCommentEnd = -1;
|
||||
let isFirstSingleLineComment = true;
|
||||
let singleLineCommentCount = 0;
|
||||
|
||||
for (let currentComment of comments) {
|
||||
for (const currentComment of comments) {
|
||||
|
||||
// For single line comments, combine consecutive ones (2 or more) into
|
||||
// a single span from the start of the first till the end of the last
|
||||
if (currentComment.kind === SyntaxKind.SingleLineCommentTrivia) {
|
||||
if (isFirstSingleLineComment) {
|
||||
firstSingleLineCommentStart = currentComment.pos;
|
||||
}
|
||||
isFirstSingleLineComment = false;
|
||||
lastSingleLineCommentEnd = currentComment.end;
|
||||
singleLineCommentCount++;
|
||||
// For single line comments, combine consecutive ones (2 or more) into
|
||||
// a single span from the start of the first till the end of the last
|
||||
if (currentComment.kind === SyntaxKind.SingleLineCommentTrivia) {
|
||||
if (isFirstSingleLineComment) {
|
||||
firstSingleLineCommentStart = currentComment.pos;
|
||||
}
|
||||
else if (currentComment.kind === SyntaxKind.MultiLineCommentTrivia) {
|
||||
combineAndAddMultipleSingleLineComments(singleLineCommentCount, firstSingleLineCommentStart, lastSingleLineCommentEnd);
|
||||
addOutliningSpanComments(currentComment, /*autoCollapse*/ false);
|
||||
isFirstSingleLineComment = false;
|
||||
lastSingleLineCommentEnd = currentComment.end;
|
||||
singleLineCommentCount++;
|
||||
}
|
||||
else if (currentComment.kind === SyntaxKind.MultiLineCommentTrivia) {
|
||||
combineAndAddMultipleSingleLineComments(singleLineCommentCount, firstSingleLineCommentStart, lastSingleLineCommentEnd);
|
||||
addOutliningSpanComments(currentComment, /*autoCollapse*/ false);
|
||||
|
||||
singleLineCommentCount = 0;
|
||||
lastSingleLineCommentEnd = -1;
|
||||
isFirstSingleLineComment = true;
|
||||
singleLineCommentCount = 0;
|
||||
lastSingleLineCommentEnd = -1;
|
||||
isFirstSingleLineComment = true;
|
||||
}
|
||||
}
|
||||
|
||||
combineAndAddMultipleSingleLineComments(singleLineCommentCount, firstSingleLineCommentStart, lastSingleLineCommentEnd);
|
||||
}
|
||||
}
|
||||
|
||||
function combineAndAddMultipleSingleLineComments(count: number, start: number, end: number) {
|
||||
|
||||
// Only outline spans of two or more consecutive single line comments
|
||||
if (count > 1) {
|
||||
const multipleSingleLineComments = {
|
||||
pos: start,
|
||||
end: end,
|
||||
kind: SyntaxKind.SingleLineCommentTrivia
|
||||
};
|
||||
|
||||
addOutliningSpanComments(multipleSingleLineComments, /*autoCollapse*/ false);
|
||||
}
|
||||
}
|
||||
|
||||
function autoCollapse(node: Node) {
|
||||
return isFunctionBlock(node) && node.parent.kind !== SyntaxKind.ArrowFunction;
|
||||
}
|
||||
|
||||
let depth = 0;
|
||||
const maxDepth = 20;
|
||||
function walk(n: Node): void {
|
||||
if (depth > maxDepth) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDeclaration(n)) {
|
||||
addOutliningForLeadingCommentsForNode(n);
|
||||
}
|
||||
|
||||
switch (n.kind) {
|
||||
case SyntaxKind.Block:
|
||||
if (!isFunctionBlock(n)) {
|
||||
const parent = n.parent;
|
||||
const openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile);
|
||||
const closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile);
|
||||
|
||||
// Check if the block is standalone, or 'attached' to some parent statement.
|
||||
// If the latter, we want to collaps the block, but consider its hint span
|
||||
// to be the entire span of the parent.
|
||||
if (parent.kind === SyntaxKind.DoStatement ||
|
||||
parent.kind === SyntaxKind.ForInStatement ||
|
||||
parent.kind === SyntaxKind.ForOfStatement ||
|
||||
parent.kind === SyntaxKind.ForStatement ||
|
||||
parent.kind === SyntaxKind.IfStatement ||
|
||||
parent.kind === SyntaxKind.WhileStatement ||
|
||||
parent.kind === SyntaxKind.WithStatement ||
|
||||
parent.kind === SyntaxKind.CatchClause) {
|
||||
|
||||
addOutliningSpan(parent, openBrace, closeBrace, autoCollapse(n));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
combineAndAddMultipleSingleLineComments(singleLineCommentCount, firstSingleLineCommentStart, lastSingleLineCommentEnd);
|
||||
}
|
||||
}
|
||||
|
||||
function combineAndAddMultipleSingleLineComments(count: number, start: number, end: number) {
|
||||
// Only outline spans of two or more consecutive single line comments
|
||||
if (count > 1) {
|
||||
let multipleSingleLineComments = {
|
||||
pos: start,
|
||||
end: end,
|
||||
kind: SyntaxKind.SingleLineCommentTrivia
|
||||
}
|
||||
|
||||
addOutliningSpanComments(multipleSingleLineComments, /*autoCollapse*/ false);
|
||||
}
|
||||
}
|
||||
|
||||
function autoCollapse(node: Node) {
|
||||
return isFunctionBlock(node) && node.parent.kind !== SyntaxKind.ArrowFunction;
|
||||
}
|
||||
|
||||
let depth = 0;
|
||||
let maxDepth = 20;
|
||||
function walk(n: Node): void {
|
||||
if (depth > maxDepth) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDeclaration(n)) {
|
||||
addOutliningForLeadingCommentsForNode(n);
|
||||
}
|
||||
|
||||
switch (n.kind) {
|
||||
case SyntaxKind.Block:
|
||||
if (!isFunctionBlock(n)) {
|
||||
let parent = n.parent;
|
||||
let openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile);
|
||||
let closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile);
|
||||
|
||||
// Check if the block is standalone, or 'attached' to some parent statement.
|
||||
// If the latter, we want to collaps the block, but consider its hint span
|
||||
// to be the entire span of the parent.
|
||||
if (parent.kind === SyntaxKind.DoStatement ||
|
||||
parent.kind === SyntaxKind.ForInStatement ||
|
||||
parent.kind === SyntaxKind.ForOfStatement ||
|
||||
parent.kind === SyntaxKind.ForStatement ||
|
||||
parent.kind === SyntaxKind.IfStatement ||
|
||||
parent.kind === SyntaxKind.WhileStatement ||
|
||||
parent.kind === SyntaxKind.WithStatement ||
|
||||
parent.kind === SyntaxKind.CatchClause) {
|
||||
|
||||
if (parent.kind === SyntaxKind.TryStatement) {
|
||||
// Could be the try-block, or the finally-block.
|
||||
const tryStatement = <TryStatement>parent;
|
||||
if (tryStatement.tryBlock === n) {
|
||||
addOutliningSpan(parent, openBrace, closeBrace, autoCollapse(n));
|
||||
break;
|
||||
}
|
||||
|
||||
if (parent.kind === SyntaxKind.TryStatement) {
|
||||
// Could be the try-block, or the finally-block.
|
||||
let tryStatement = <TryStatement>parent;
|
||||
if (tryStatement.tryBlock === n) {
|
||||
addOutliningSpan(parent, openBrace, closeBrace, autoCollapse(n));
|
||||
else if (tryStatement.finallyBlock === n) {
|
||||
const finallyKeyword = findChildOfKind(tryStatement, SyntaxKind.FinallyKeyword, sourceFile);
|
||||
if (finallyKeyword) {
|
||||
addOutliningSpan(finallyKeyword, openBrace, closeBrace, autoCollapse(n));
|
||||
break;
|
||||
}
|
||||
else if (tryStatement.finallyBlock === n) {
|
||||
let finallyKeyword = findChildOfKind(tryStatement, SyntaxKind.FinallyKeyword, sourceFile);
|
||||
if (finallyKeyword) {
|
||||
addOutliningSpan(finallyKeyword, openBrace, closeBrace, autoCollapse(n));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// fall through.
|
||||
}
|
||||
|
||||
// Block was a standalone block. In this case we want to only collapse
|
||||
// the span of the block, independent of any parent span.
|
||||
let span = createTextSpanFromBounds(n.getStart(), n.end);
|
||||
elements.push({
|
||||
textSpan: span,
|
||||
hintSpan: span,
|
||||
bannerText: collapseText,
|
||||
autoCollapse: autoCollapse(n)
|
||||
});
|
||||
break;
|
||||
// fall through.
|
||||
}
|
||||
// Fallthrough.
|
||||
|
||||
case SyntaxKind.ModuleBlock: {
|
||||
let openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile);
|
||||
let closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile);
|
||||
addOutliningSpan(n.parent, openBrace, closeBrace, autoCollapse(n));
|
||||
// Block was a standalone block. In this case we want to only collapse
|
||||
// the span of the block, independent of any parent span.
|
||||
const span = createTextSpanFromBounds(n.getStart(), n.end);
|
||||
elements.push({
|
||||
textSpan: span,
|
||||
hintSpan: span,
|
||||
bannerText: collapseText,
|
||||
autoCollapse: autoCollapse(n)
|
||||
});
|
||||
break;
|
||||
}
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
case SyntaxKind.CaseBlock: {
|
||||
let openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile);
|
||||
let closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile);
|
||||
addOutliningSpan(n, openBrace, closeBrace, autoCollapse(n));
|
||||
break;
|
||||
}
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
let openBracket = findChildOfKind(n, SyntaxKind.OpenBracketToken, sourceFile);
|
||||
let closeBracket = findChildOfKind(n, SyntaxKind.CloseBracketToken, sourceFile);
|
||||
addOutliningSpan(n, openBracket, closeBracket, autoCollapse(n));
|
||||
break;
|
||||
// Fallthrough.
|
||||
|
||||
case SyntaxKind.ModuleBlock: {
|
||||
const openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile);
|
||||
const closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile);
|
||||
addOutliningSpan(n.parent, openBrace, closeBrace, autoCollapse(n));
|
||||
break;
|
||||
}
|
||||
depth++;
|
||||
forEachChild(n, walk);
|
||||
depth--;
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
case SyntaxKind.CaseBlock: {
|
||||
const openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile);
|
||||
const closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile);
|
||||
addOutliningSpan(n, openBrace, closeBrace, autoCollapse(n));
|
||||
break;
|
||||
}
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
const openBracket = findChildOfKind(n, SyntaxKind.OpenBracketToken, sourceFile);
|
||||
const closeBracket = findChildOfKind(n, SyntaxKind.CloseBracketToken, sourceFile);
|
||||
addOutliningSpan(n, openBracket, closeBracket, autoCollapse(n));
|
||||
break;
|
||||
}
|
||||
|
||||
walk(sourceFile);
|
||||
return elements;
|
||||
depth++;
|
||||
forEachChild(n, walk);
|
||||
depth--;
|
||||
}
|
||||
|
||||
walk(sourceFile);
|
||||
return elements;
|
||||
}
|
||||
}
|
||||
+82
-136
@@ -8,10 +8,10 @@ namespace ts {
|
||||
camelCase
|
||||
}
|
||||
|
||||
// Information about a match made by the pattern matcher between a candidate and the
|
||||
// Information about a match made by the pattern matcher between a candidate and the
|
||||
// search pattern.
|
||||
export interface PatternMatch {
|
||||
// What kind of match this was. Exact matches are better than prefix matches which are
|
||||
// What kind of match this was. Exact matches are better than prefix matches which are
|
||||
// better than substring matches which are better than CamelCase matches.
|
||||
kind: PatternMatchKind;
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace ts {
|
||||
// it was a better match.
|
||||
camelCaseWeight?: number;
|
||||
|
||||
// If this was a match where all constituent parts of the candidate and search pattern
|
||||
// If this was a match where all constituent parts of the candidate and search pattern
|
||||
// matched case sensitively or case insensitively. Case sensitive matches of the kind
|
||||
// are better matches than insensitive matches.
|
||||
isCaseSensitive: boolean;
|
||||
@@ -35,7 +35,7 @@ namespace ts {
|
||||
// once you no longer need it.
|
||||
export interface PatternMatcher {
|
||||
// Used to match a candidate against the last segment of a possibly dotted pattern. This
|
||||
// is useful as a quick check to prevent having to compute a container before calling
|
||||
// is useful as a quick check to prevent having to compute a container before calling
|
||||
// "getMatches".
|
||||
//
|
||||
// For example, if the search pattern is "ts.c.SK" and the candidate is "SyntaxKind", then
|
||||
@@ -55,8 +55,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
// First we break up the pattern given by dots. Each portion of the pattern between the
|
||||
// dots is a 'Segment'. The 'Segment' contains information about the entire section of
|
||||
// text between the dots, as well as information about any individual 'Words' that we
|
||||
// dots is a 'Segment'. The 'Segment' contains information about the entire section of
|
||||
// text between the dots, as well as information about any individual 'Words' that we
|
||||
// can break the segment into. A 'Word' is simply a contiguous sequence of characters
|
||||
// that can appear in a typescript identifier. So "GetKeyword" would be one word, while
|
||||
// "Get Keyword" would be two words. Once we have the individual 'words', we break those
|
||||
@@ -64,20 +64,20 @@ namespace ts {
|
||||
// word, it make character spans corresponding to "U", "I" and "Element". These spans
|
||||
// are then used when doing camel cased matches against candidate patterns.
|
||||
interface Segment {
|
||||
// Information about the entire piece of text between the dots. For example, if the
|
||||
// text between the dots is 'GetKeyword', then TotalTextChunk.Text will be 'GetKeyword' and
|
||||
// Information about the entire piece of text between the dots. For example, if the
|
||||
// text between the dots is 'GetKeyword', then TotalTextChunk.Text will be 'GetKeyword' and
|
||||
// TotalTextChunk.CharacterSpans will correspond to 'Get', 'Keyword'.
|
||||
totalTextChunk: TextChunk;
|
||||
|
||||
// Information about the subwords compromising the total word. For example, if the
|
||||
// text between the dots is 'GetFoo KeywordBar', then the subwords will be 'GetFoo'
|
||||
// and 'KeywordBar'. Those individual words will have CharacterSpans of ('Get' and
|
||||
// 'Foo') and('Keyword' and 'Bar') respectively.
|
||||
// Information about the subwords compromising the total word. For example, if the
|
||||
// text between the dots is 'GetFoo KeywordBar', then the subwords will be 'GetFoo'
|
||||
// and 'KeywordBar'. Those individual words will have CharacterSpans of ('Get' and
|
||||
// 'Foo') and('Keyword' and 'Bar') respectively.
|
||||
subWordTextChunks: TextChunk[];
|
||||
}
|
||||
|
||||
// Information about a chunk of text from the pattern. The chunk is a piece of text, with
|
||||
// cached information about the character spans within in. Character spans are used for
|
||||
// Information about a chunk of text from the pattern. The chunk is a piece of text, with
|
||||
// cached information about the character spans within in. Character spans are used for
|
||||
// camel case matching.
|
||||
interface TextChunk {
|
||||
// The text of the chunk. This should be a contiguous sequence of character that could
|
||||
@@ -92,9 +92,9 @@ namespace ts {
|
||||
// for something entirely lowercase or not.
|
||||
isLowerCase: boolean;
|
||||
|
||||
// The spans in this text chunk that we think are of interest and should be matched
|
||||
// The spans in this text chunk that we think are of interest and should be matched
|
||||
// independently. For example, if the chunk is for "UIElement" the the spans of interest
|
||||
// correspond to "U", "I" and "Element". If "UIElement" isn't found as an exaxt, prefix.
|
||||
// correspond to "U", "I" and "Element". If "UIElement" isn't found as an exact, prefix.
|
||||
// or substring match, then the character spans will be used to attempt a camel case match.
|
||||
characterSpans: TextSpan[];
|
||||
}
|
||||
@@ -110,20 +110,19 @@ namespace ts {
|
||||
|
||||
export function createPatternMatcher(pattern: string): PatternMatcher {
|
||||
// We'll often see the same candidate string many times when searching (For example, when
|
||||
// we see the name of a module that is used everywhere, or the name of an overload). As
|
||||
// such, we cache the information we compute about the candidate for the life of this
|
||||
// we see the name of a module that is used everywhere, or the name of an overload). As
|
||||
// such, we cache the information we compute about the candidate for the life of this
|
||||
// pattern matcher so we don't have to compute it multiple times.
|
||||
let stringToWordSpans: Map<TextSpan[]> = {};
|
||||
const stringToWordSpans: Map<TextSpan[]> = {};
|
||||
|
||||
pattern = pattern.trim();
|
||||
|
||||
let fullPatternSegment = createSegment(pattern);
|
||||
let dotSeparatedSegments = pattern.split(".").map(p => createSegment(p.trim()));
|
||||
let invalidPattern = dotSeparatedSegments.length === 0 || forEach(dotSeparatedSegments, segmentIsInvalid);
|
||||
const dotSeparatedSegments = pattern.split(".").map(p => createSegment(p.trim()));
|
||||
const invalidPattern = dotSeparatedSegments.length === 0 || forEach(dotSeparatedSegments, segmentIsInvalid);
|
||||
|
||||
return {
|
||||
getMatches,
|
||||
getMatchesForLastSegmentOfPattern,
|
||||
getMatchesForLastSegmentOfPattern,
|
||||
patternContainsDots: dotSeparatedSegments.length > 1
|
||||
};
|
||||
|
||||
@@ -131,7 +130,7 @@ namespace ts {
|
||||
function skipMatch(candidate: string) {
|
||||
return invalidPattern || !candidate;
|
||||
}
|
||||
|
||||
|
||||
function getMatchesForLastSegmentOfPattern(candidate: string): PatternMatch[] {
|
||||
if (skipMatch(candidate)) {
|
||||
return undefined;
|
||||
@@ -148,7 +147,7 @@ namespace ts {
|
||||
// First, check that the last part of the dot separated pattern matches the name of the
|
||||
// candidate. If not, then there's no point in proceeding and doing the more
|
||||
// expensive work.
|
||||
let candidateMatch = matchSegment(candidate, lastOrUndefined(dotSeparatedSegments));
|
||||
const candidateMatch = matchSegment(candidate, lastOrUndefined(dotSeparatedSegments));
|
||||
if (!candidateMatch) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -165,16 +164,16 @@ namespace ts {
|
||||
|
||||
// So far so good. Now break up the container for the candidate and check if all
|
||||
// the dotted parts match up correctly.
|
||||
let totalMatch = candidateMatch;
|
||||
const totalMatch = candidateMatch;
|
||||
|
||||
for (let i = dotSeparatedSegments.length - 2, j = candidateContainers.length - 1;
|
||||
i >= 0;
|
||||
i--, j--) {
|
||||
i -= 1, j -= 1) {
|
||||
|
||||
let segment = dotSeparatedSegments[i];
|
||||
let containerName = candidateContainers[j];
|
||||
const segment = dotSeparatedSegments[i];
|
||||
const containerName = candidateContainers[j];
|
||||
|
||||
let containerMatch = matchSegment(containerName, segment);
|
||||
const containerMatch = matchSegment(containerName, segment);
|
||||
if (!containerMatch) {
|
||||
// This container didn't match the pattern piece. So there's no match at all.
|
||||
return undefined;
|
||||
@@ -197,7 +196,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function matchTextChunk(candidate: string, chunk: TextChunk, punctuationStripped: boolean): PatternMatch {
|
||||
let index = indexOfIgnoringCase(candidate, chunk.textLowerCase);
|
||||
const index = indexOfIgnoringCase(candidate, chunk.textLowerCase);
|
||||
if (index === 0) {
|
||||
if (chunk.text.length === candidate.length) {
|
||||
// a) Check if the part matches the candidate entirely, in an case insensitive or
|
||||
@@ -211,18 +210,18 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
let isLowercase = chunk.isLowerCase;
|
||||
const isLowercase = chunk.isLowerCase;
|
||||
if (isLowercase) {
|
||||
if (index > 0) {
|
||||
// c) If the part is entirely lowercase, then check if it is contained anywhere in the
|
||||
// candidate in a case insensitive manner. If so, return that there was a substring
|
||||
// match.
|
||||
// match.
|
||||
//
|
||||
// Note: We only have a substring match if the lowercase part is prefix match of some
|
||||
// word part. That way we don't match something like 'Class' when the user types 'a'.
|
||||
// But we would match 'FooAttribute' (since 'Attribute' starts with 'a').
|
||||
let wordSpans = getWordSpans(candidate);
|
||||
for (let span of wordSpans) {
|
||||
const wordSpans = getWordSpans(candidate);
|
||||
for (const span of wordSpans) {
|
||||
if (partStartsWith(candidate, span, chunk.text, /*ignoreCase:*/ true)) {
|
||||
return createPatternMatch(PatternMatchKind.substring, punctuationStripped,
|
||||
/*isCaseSensitive:*/ partStartsWith(candidate, span, chunk.text, /*ignoreCase:*/ false));
|
||||
@@ -242,7 +241,7 @@ namespace ts {
|
||||
if (!isLowercase) {
|
||||
// e) If the part was not entirely lowercase, then attempt a camel cased match as well.
|
||||
if (chunk.characterSpans.length > 0) {
|
||||
let candidateParts = getWordSpans(candidate);
|
||||
const candidateParts = getWordSpans(candidate);
|
||||
let camelCaseWeight = tryCamelCaseMatch(candidate, candidateParts, chunk, /*ignoreCase:*/ false);
|
||||
if (camelCaseWeight !== undefined) {
|
||||
return createPatternMatch(PatternMatchKind.camelCase, punctuationStripped, /*isCaseSensitive:*/ true, /*camelCaseWeight:*/ camelCaseWeight);
|
||||
@@ -259,8 +258,8 @@ namespace ts {
|
||||
// f) Is the pattern a substring of the candidate starting on one of the candidate's word boundaries?
|
||||
|
||||
// We could check every character boundary start of the candidate for the pattern. However, that's
|
||||
// an m * n operation in the wost case. Instead, find the first instance of the pattern
|
||||
// substring, and see if it starts on a capital letter. It seems unlikely that the user will try to
|
||||
// an m * n operation in the wost case. Instead, find the first instance of the pattern
|
||||
// substring, and see if it starts on a capital letter. It seems unlikely that the user will try to
|
||||
// filter the list based on a substring that starts on a capital letter and also with a lowercase one.
|
||||
// (Pattern: fogbar, Candidate: quuxfogbarFogBar).
|
||||
if (chunk.text.length < candidate.length) {
|
||||
@@ -275,7 +274,7 @@ namespace ts {
|
||||
|
||||
function containsSpaceOrAsterisk(text: string): boolean {
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
let ch = text.charCodeAt(i);
|
||||
const ch = text.charCodeAt(i);
|
||||
if (ch === CharacterCodes.space || ch === CharacterCodes.asterisk) {
|
||||
return true;
|
||||
}
|
||||
@@ -293,7 +292,7 @@ namespace ts {
|
||||
// Note: if the segment contains a space or an asterisk then we must assume that it's a
|
||||
// multi-word segment.
|
||||
if (!containsSpaceOrAsterisk(segment.totalTextChunk.text)) {
|
||||
let match = matchTextChunk(candidate, segment.totalTextChunk, /*punctuationStripped:*/ false);
|
||||
const match = matchTextChunk(candidate, segment.totalTextChunk, /*punctuationStripped:*/ false);
|
||||
if (match) {
|
||||
return [match];
|
||||
}
|
||||
@@ -317,7 +316,7 @@ namespace ts {
|
||||
//
|
||||
// c) If the word is entirely lowercase, then check if it is contained anywhere in the
|
||||
// candidate in a case insensitive manner. If so, return that there was a substring
|
||||
// match.
|
||||
// match.
|
||||
//
|
||||
// Note: We only have a substring match if the lowercase part is prefix match of
|
||||
// some word part. That way we don't match something like 'Class' when the user
|
||||
@@ -331,17 +330,17 @@ namespace ts {
|
||||
// e) If the word was not entirely lowercase, then attempt a camel cased match as
|
||||
// well.
|
||||
//
|
||||
// f) The word is all lower case. Is it a case insensitive substring of the candidate starting
|
||||
// f) The word is all lower case. Is it a case insensitive substring of the candidate starting
|
||||
// on a part boundary of the candidate?
|
||||
//
|
||||
// Only if all words have some sort of match is the pattern considered matched.
|
||||
|
||||
let subWordTextChunks = segment.subWordTextChunks;
|
||||
const subWordTextChunks = segment.subWordTextChunks;
|
||||
let matches: PatternMatch[] = undefined;
|
||||
|
||||
for (let subWordTextChunk of subWordTextChunks) {
|
||||
for (const subWordTextChunk of subWordTextChunks) {
|
||||
// Try to match the candidate with this word
|
||||
let result = matchTextChunk(candidate, subWordTextChunk, /*punctuationStripped:*/ true);
|
||||
const result = matchTextChunk(candidate, subWordTextChunk, /*punctuationStripped:*/ true);
|
||||
if (!result) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -354,18 +353,18 @@ namespace ts {
|
||||
}
|
||||
|
||||
function partStartsWith(candidate: string, candidateSpan: TextSpan, pattern: string, ignoreCase: boolean, patternSpan?: TextSpan): boolean {
|
||||
let patternPartStart = patternSpan ? patternSpan.start : 0;
|
||||
let patternPartLength = patternSpan ? patternSpan.length : pattern.length;
|
||||
const patternPartStart = patternSpan ? patternSpan.start : 0;
|
||||
const patternPartLength = patternSpan ? patternSpan.length : pattern.length;
|
||||
|
||||
if (patternPartLength > candidateSpan.length) {
|
||||
// Pattern part is longer than the candidate part. There can never be a match.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (ignoreCase) {
|
||||
for (let i = 0; i < patternPartLength; i++) {
|
||||
let ch1 = pattern.charCodeAt(patternPartStart + i);
|
||||
let ch2 = candidate.charCodeAt(candidateSpan.start + i);
|
||||
const ch1 = pattern.charCodeAt(patternPartStart + i);
|
||||
const ch2 = candidate.charCodeAt(candidateSpan.start + i);
|
||||
if (toLowerCase(ch1) !== toLowerCase(ch2)) {
|
||||
return false;
|
||||
}
|
||||
@@ -373,8 +372,8 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
for (let i = 0; i < patternPartLength; i++) {
|
||||
let ch1 = pattern.charCodeAt(patternPartStart + i);
|
||||
let ch2 = candidate.charCodeAt(candidateSpan.start + i);
|
||||
const ch1 = pattern.charCodeAt(patternPartStart + i);
|
||||
const ch2 = candidate.charCodeAt(candidateSpan.start + i);
|
||||
if (ch1 !== ch2) {
|
||||
return false;
|
||||
}
|
||||
@@ -385,12 +384,12 @@ namespace ts {
|
||||
}
|
||||
|
||||
function tryCamelCaseMatch(candidate: string, candidateParts: TextSpan[], chunk: TextChunk, ignoreCase: boolean): number {
|
||||
let chunkCharacterSpans = chunk.characterSpans;
|
||||
const chunkCharacterSpans = chunk.characterSpans;
|
||||
|
||||
// Note: we may have more pattern parts than candidate parts. This is because multiple
|
||||
// pattern parts may match a candidate part. For example "SiUI" against "SimpleUI".
|
||||
// We'll have 3 pattern parts Si/U/I against two candidate parts Simple/UI. However, U
|
||||
// and I will both match in UI.
|
||||
// and I will both match in UI.
|
||||
|
||||
let currentCandidate = 0;
|
||||
let currentChunkSpan = 0;
|
||||
@@ -426,14 +425,14 @@ namespace ts {
|
||||
// Consider the case of matching SiUI against SimpleUIElement. The candidate parts
|
||||
// will be Simple/UI/Element, and the pattern parts will be Si/U/I. We'll match 'Si'
|
||||
// against 'Simple' first. Then we'll match 'U' against 'UI'. However, we want to
|
||||
// still keep matching pattern parts against that candidate part.
|
||||
// still keep matching pattern parts against that candidate part.
|
||||
for (; currentChunkSpan < chunkCharacterSpans.length; currentChunkSpan++) {
|
||||
let chunkCharacterSpan = chunkCharacterSpans[currentChunkSpan];
|
||||
const chunkCharacterSpan = chunkCharacterSpans[currentChunkSpan];
|
||||
|
||||
if (gotOneMatchThisCandidate) {
|
||||
// We've already gotten one pattern part match in this candidate. We will
|
||||
// only continue trying to consumer pattern parts if the last part and this
|
||||
// part are both upper case.
|
||||
// part are both upper case.
|
||||
if (!isUpperCaseLetter(chunk.text.charCodeAt(chunkCharacterSpans[currentChunkSpan - 1].start)) ||
|
||||
!isUpperCaseLetter(chunk.text.charCodeAt(chunkCharacterSpans[currentChunkSpan].start))) {
|
||||
break;
|
||||
@@ -470,55 +469,11 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to compare two matches to determine which is better. Matches are first
|
||||
// ordered by kind (so all prefix matches always beat all substring matches). Then, if the
|
||||
// match is a camel case match, the relative weights of the match are used to determine
|
||||
// which is better (with a greater weight being better). Then if the match is of the same
|
||||
// type, then a case sensitive match is considered better than an insensitive one.
|
||||
function patternMatchCompareTo(match1: PatternMatch, match2: PatternMatch): number {
|
||||
return compareType(match1, match2) ||
|
||||
compareCamelCase(match1, match2) ||
|
||||
compareCase(match1, match2) ||
|
||||
comparePunctuation(match1, match2);
|
||||
}
|
||||
|
||||
function comparePunctuation(result1: PatternMatch, result2: PatternMatch) {
|
||||
// Consider a match to be better if it was successful without stripping punctuation
|
||||
// versus a match that had to strip punctuation to succeed.
|
||||
if (result1.punctuationStripped !== result2.punctuationStripped) {
|
||||
return result1.punctuationStripped ? 1 : -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function compareCase(result1: PatternMatch, result2: PatternMatch) {
|
||||
if (result1.isCaseSensitive !== result2.isCaseSensitive) {
|
||||
return result1.isCaseSensitive ? -1 : 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function compareType(result1: PatternMatch, result2: PatternMatch) {
|
||||
return result1.kind - result2.kind;
|
||||
}
|
||||
|
||||
function compareCamelCase(result1: PatternMatch, result2: PatternMatch) {
|
||||
if (result1.kind === PatternMatchKind.camelCase && result2.kind === PatternMatchKind.camelCase) {
|
||||
// Swap the values here. If result1 has a higher weight, then we want it to come
|
||||
// first.
|
||||
return result2.camelCaseWeight - result1.camelCaseWeight;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function createSegment(text: string): Segment {
|
||||
return {
|
||||
totalTextChunk: createTextChunk(text),
|
||||
subWordTextChunks: breakPatternIntoTextChunks(text)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// A segment is considered invalid if we couldn't find any words in it.
|
||||
@@ -536,9 +491,9 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: find a way to determine this for any unicode characters in a
|
||||
// TODO: find a way to determine this for any unicode characters in a
|
||||
// non-allocating manner.
|
||||
let str = String.fromCharCode(ch);
|
||||
const str = String.fromCharCode(ch);
|
||||
return str === str.toUpperCase();
|
||||
}
|
||||
|
||||
@@ -553,22 +508,12 @@ namespace ts {
|
||||
}
|
||||
|
||||
|
||||
// TODO: find a way to determine this for any unicode characters in a
|
||||
// TODO: find a way to determine this for any unicode characters in a
|
||||
// non-allocating manner.
|
||||
let str = String.fromCharCode(ch);
|
||||
const str = String.fromCharCode(ch);
|
||||
return str === str.toLowerCase();
|
||||
}
|
||||
|
||||
function containsUpperCaseLetter(string: string): boolean {
|
||||
for (let i = 0, n = string.length; i < n; i++) {
|
||||
if (isUpperCaseLetter(string.charCodeAt(i))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function startsWith(string: string, search: string) {
|
||||
for (let i = 0, n = search.length; i < n; i++) {
|
||||
if (string.charCodeAt(i) !== search.charCodeAt(i)) {
|
||||
@@ -593,8 +538,8 @@ namespace ts {
|
||||
// Assumes 'value' is already lowercase.
|
||||
function startsWithIgnoringCase(string: string, value: string, start: number): boolean {
|
||||
for (let i = 0, n = value.length; i < n; i++) {
|
||||
let ch1 = toLowerCase(string.charCodeAt(i + start));
|
||||
let ch2 = value.charCodeAt(i);
|
||||
const ch1 = toLowerCase(string.charCodeAt(i + start));
|
||||
const ch2 = value.charCodeAt(i);
|
||||
|
||||
if (ch1 !== ch2) {
|
||||
return false;
|
||||
@@ -614,7 +559,7 @@ namespace ts {
|
||||
return ch;
|
||||
}
|
||||
|
||||
// TODO: find a way to compute this for any unicode characters in a
|
||||
// TODO: find a way to compute this for any unicode characters in a
|
||||
// non-allocating manner.
|
||||
return String.fromCharCode(ch).toLowerCase().charCodeAt(0);
|
||||
}
|
||||
@@ -629,16 +574,17 @@ namespace ts {
|
||||
}
|
||||
|
||||
function breakPatternIntoTextChunks(pattern: string): TextChunk[] {
|
||||
let result: TextChunk[] = [];
|
||||
const result: TextChunk[] = [];
|
||||
let wordStart = 0;
|
||||
let wordLength = 0;
|
||||
|
||||
for (let i = 0; i < pattern.length; i++) {
|
||||
let ch = pattern.charCodeAt(i);
|
||||
const ch = pattern.charCodeAt(i);
|
||||
if (isWordChar(ch)) {
|
||||
if (wordLength++ === 0) {
|
||||
if (wordLength === 0) {
|
||||
wordStart = i;
|
||||
}
|
||||
wordLength++;
|
||||
}
|
||||
else {
|
||||
if (wordLength > 0) {
|
||||
@@ -656,13 +602,13 @@ namespace ts {
|
||||
}
|
||||
|
||||
function createTextChunk(text: string): TextChunk {
|
||||
let textLowerCase = text.toLowerCase();
|
||||
const textLowerCase = text.toLowerCase();
|
||||
return {
|
||||
text,
|
||||
textLowerCase,
|
||||
isLowerCase: text === textLowerCase,
|
||||
characterSpans: breakIntoCharacterSpans(text)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/* @internal */ export function breakIntoCharacterSpans(identifier: string): TextSpan[] {
|
||||
@@ -674,15 +620,15 @@ namespace ts {
|
||||
}
|
||||
|
||||
function breakIntoSpans(identifier: string, word: boolean): TextSpan[] {
|
||||
let result: TextSpan[] = [];
|
||||
const result: TextSpan[] = [];
|
||||
|
||||
let wordStart = 0;
|
||||
for (let i = 1, n = identifier.length; i < n; i++) {
|
||||
let lastIsDigit = isDigit(identifier.charCodeAt(i - 1));
|
||||
let currentIsDigit = isDigit(identifier.charCodeAt(i));
|
||||
const lastIsDigit = isDigit(identifier.charCodeAt(i - 1));
|
||||
const currentIsDigit = isDigit(identifier.charCodeAt(i));
|
||||
|
||||
let hasTransitionFromLowerToUpper = transitionFromLowerToUpper(identifier, word, i);
|
||||
let hasTransitionFromUpperToLower = transitionFromUpperToLower(identifier, word, i, wordStart);
|
||||
const hasTransitionFromLowerToUpper = transitionFromLowerToUpper(identifier, word, i);
|
||||
const hasTransitionFromUpperToLower = transitionFromUpperToLower(identifier, word, i, wordStart);
|
||||
|
||||
if (charIsPunctuation(identifier.charCodeAt(i - 1)) ||
|
||||
charIsPunctuation(identifier.charCodeAt(i)) ||
|
||||
@@ -738,7 +684,7 @@ namespace ts {
|
||||
|
||||
function isAllPunctuation(identifier: string, start: number, end: number): boolean {
|
||||
for (let i = start; i < end; i++) {
|
||||
let ch = identifier.charCodeAt(i);
|
||||
const ch = identifier.charCodeAt(i);
|
||||
|
||||
// We don't consider _ or $ as punctuation as there may be things with that name.
|
||||
if (!charIsPunctuation(ch) || ch === CharacterCodes._ || ch === CharacterCodes.$) {
|
||||
@@ -759,8 +705,8 @@ namespace ts {
|
||||
// etc.
|
||||
if (index !== wordStart &&
|
||||
index + 1 < identifier.length) {
|
||||
let currentIsUpper = isUpperCaseLetter(identifier.charCodeAt(index));
|
||||
let nextIsLower = isLowerCaseLetter(identifier.charCodeAt(index + 1));
|
||||
const currentIsUpper = isUpperCaseLetter(identifier.charCodeAt(index));
|
||||
const nextIsLower = isLowerCaseLetter(identifier.charCodeAt(index + 1));
|
||||
|
||||
if (currentIsUpper && nextIsLower) {
|
||||
// We have a transition from an upper to a lower letter here. But we only
|
||||
@@ -786,12 +732,12 @@ namespace ts {
|
||||
}
|
||||
|
||||
function transitionFromLowerToUpper(identifier: string, word: boolean, index: number): boolean {
|
||||
let lastIsUpper = isUpperCaseLetter(identifier.charCodeAt(index - 1));
|
||||
let currentIsUpper = isUpperCaseLetter(identifier.charCodeAt(index));
|
||||
const lastIsUpper = isUpperCaseLetter(identifier.charCodeAt(index - 1));
|
||||
const currentIsUpper = isUpperCaseLetter(identifier.charCodeAt(index));
|
||||
|
||||
// See if the casing indicates we're starting a new word. Note: if we're breaking on
|
||||
// words, then just seeing an upper case character isn't enough. Instead, it has to
|
||||
// be uppercase and the previous character can't be uppercase.
|
||||
// be uppercase and the previous character can't be uppercase.
|
||||
//
|
||||
// For example, breaking "AddMetadata" on words would make: Add Metadata
|
||||
//
|
||||
@@ -802,7 +748,7 @@ namespace ts {
|
||||
// on characters would be: A M
|
||||
//
|
||||
// We break the search string on characters. But we break the symbol name on words.
|
||||
let transition = word
|
||||
const transition = word
|
||||
? (currentIsUpper && !lastIsUpper)
|
||||
: currentIsUpper;
|
||||
return transition;
|
||||
|
||||
+57
-19
@@ -469,7 +469,8 @@ namespace ts {
|
||||
|
||||
function pushDocCommentLineText(docComments: SymbolDisplayPart[], text: string, blankLineCount: number) {
|
||||
// Add the empty lines in between texts
|
||||
while (blankLineCount--) {
|
||||
while (blankLineCount) {
|
||||
blankLineCount--;
|
||||
docComments.push(textPart(""));
|
||||
}
|
||||
|
||||
@@ -1034,6 +1035,7 @@ namespace ts {
|
||||
* host specific questions using 'getScriptSnapshot'.
|
||||
*/
|
||||
resolveModuleNames?(moduleNames: string[], containingFile: string): ResolvedModule[];
|
||||
directoryExists?(directoryName: string): boolean;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -1217,6 +1219,7 @@ namespace ts {
|
||||
InsertSpaceAfterFunctionKeywordForAnonymousFunctions: boolean;
|
||||
InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: boolean;
|
||||
InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: boolean;
|
||||
InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: boolean;
|
||||
PlaceOpenBraceOnNewLineForFunctions: boolean;
|
||||
PlaceOpenBraceOnNewLineForControlBlocks: boolean;
|
||||
[s: string]: boolean | number | string;
|
||||
@@ -1614,6 +1617,9 @@ namespace ts {
|
||||
public static jsxOpenTagName = "jsx open tag name";
|
||||
public static jsxCloseTagName = "jsx close tag name";
|
||||
public static jsxSelfClosingTagName = "jsx self closing tag name";
|
||||
public static jsxAttribute = "jsx attribute";
|
||||
public static jsxText = "jsx text";
|
||||
public static jsxAttributeStringLiteralValue = "jsx attribute string literal value";
|
||||
}
|
||||
|
||||
export const enum ClassificationType {
|
||||
@@ -1638,6 +1644,9 @@ namespace ts {
|
||||
jsxOpenTagName = 19,
|
||||
jsxCloseTagName = 20,
|
||||
jsxSelfClosingTagName = 21,
|
||||
jsxAttribute = 22,
|
||||
jsxText = 23,
|
||||
jsxAttributeStringLiteralValue = 24,
|
||||
}
|
||||
|
||||
/// Language Service
|
||||
@@ -1911,7 +1920,8 @@ namespace ts {
|
||||
getCurrentDirectory: () => "",
|
||||
getNewLine: () => newLine,
|
||||
fileExists: (fileName): boolean => fileName === inputFileName,
|
||||
readFile: (fileName): string => ""
|
||||
readFile: (fileName): string => "",
|
||||
directoryExists: directoryExists => true
|
||||
};
|
||||
|
||||
const program = createProgram([inputFileName], options, compilerHost);
|
||||
@@ -2768,6 +2778,10 @@ namespace ts {
|
||||
// stub missing host functionality
|
||||
const entry = hostCache.getOrCreateEntry(fileName);
|
||||
return entry && entry.scriptSnapshot.getText(0, entry.scriptSnapshot.getLength());
|
||||
},
|
||||
directoryExists: directoryName => {
|
||||
Debug.assert(!host.resolveModuleNames);
|
||||
return directoryProbablyExists(directoryName, host);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2972,15 +2986,9 @@ namespace ts {
|
||||
// e.g "b a" is valid quoted name but when we strip off the quotes, it is invalid.
|
||||
// We, thus, need to check if whatever was inside the quotes is actually a valid identifier name.
|
||||
if (performCharacterChecks) {
|
||||
if (!isIdentifierStart(name.charCodeAt(0), target)) {
|
||||
if (!isIdentifier(name, target)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
for (let i = 1, n = name.length; i < n; i++) {
|
||||
if (!isIdentifierPart(name.charCodeAt(i), target)) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return name;
|
||||
@@ -3098,6 +3106,7 @@ namespace ts {
|
||||
}
|
||||
else if (kind === SyntaxKind.SlashToken && contextToken.parent.kind === SyntaxKind.JsxClosingElement) {
|
||||
isStartingCloseTag = true;
|
||||
location = contextToken;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3123,8 +3132,11 @@ namespace ts {
|
||||
}
|
||||
else if (isStartingCloseTag) {
|
||||
const tagName = (<JsxElement>contextToken.parent.parent).openingElement.tagName;
|
||||
symbols = [typeChecker.getSymbolAtLocation(tagName)];
|
||||
const tagSymbol = typeChecker.getSymbolAtLocation(tagName);
|
||||
|
||||
if (!typeChecker.isUnknownSymbol(tagSymbol)) {
|
||||
symbols = [tagSymbol];
|
||||
}
|
||||
isMemberCompletion = true;
|
||||
isNewIdentifierLocation = false;
|
||||
}
|
||||
@@ -3830,7 +3842,23 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
if (!symbols || symbols.length === 0) {
|
||||
return undefined;
|
||||
if (sourceFile.languageVariant === LanguageVariant.JSX &&
|
||||
location.parent && location.parent.kind === SyntaxKind.JsxClosingElement) {
|
||||
// In the TypeScript JSX element, if such element is not defined. When users query for completion at closing tag,
|
||||
// instead of simply giving unknown value, the completion will return the tag-name of an associated opening-element.
|
||||
// For example:
|
||||
// var x = <div> </ /*1*/> completion list at "1" will contain "div" with type any
|
||||
const tagName = (<JsxElement>location.parent.parent).openingElement.tagName;
|
||||
entries.push({
|
||||
name: (<Identifier>tagName).text,
|
||||
kind: undefined,
|
||||
kindModifiers: undefined,
|
||||
sortText: "0",
|
||||
});
|
||||
}
|
||||
else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
getCompletionEntriesFromSymbols(symbols, entries);
|
||||
@@ -4438,7 +4466,7 @@ namespace ts {
|
||||
const typeChecker = program.getTypeChecker();
|
||||
const symbol = typeChecker.getSymbolAtLocation(node);
|
||||
|
||||
if (!symbol) {
|
||||
if (!symbol || typeChecker.isUnknownSymbol(symbol)) {
|
||||
// Try getting just type at this position and show
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
@@ -6573,6 +6601,9 @@ namespace ts {
|
||||
case ClassificationType.jsxOpenTagName: return ClassificationTypeNames.jsxOpenTagName;
|
||||
case ClassificationType.jsxCloseTagName: return ClassificationTypeNames.jsxCloseTagName;
|
||||
case ClassificationType.jsxSelfClosingTagName: return ClassificationTypeNames.jsxSelfClosingTagName;
|
||||
case ClassificationType.jsxAttribute: return ClassificationTypeNames.jsxAttribute;
|
||||
case ClassificationType.jsxText: return ClassificationTypeNames.jsxText;
|
||||
case ClassificationType.jsxAttributeStringLiteralValue: return ClassificationTypeNames.jsxAttributeStringLiteralValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6781,12 +6812,12 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function classifyToken(token: Node): void {
|
||||
function classifyTokenOrJsxText(token: Node): void {
|
||||
if (nodeIsMissing(token)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tokenStart = classifyLeadingTriviaAndGetTokenStart(token);
|
||||
const tokenStart = token.kind === SyntaxKind.JsxText ? token.pos : classifyLeadingTriviaAndGetTokenStart(token);
|
||||
|
||||
const tokenWidth = token.end - tokenStart;
|
||||
Debug.assert(tokenWidth >= 0);
|
||||
@@ -6822,7 +6853,8 @@ namespace ts {
|
||||
// the '=' in a variable declaration is special cased here.
|
||||
if (token.parent.kind === SyntaxKind.VariableDeclaration ||
|
||||
token.parent.kind === SyntaxKind.PropertyDeclaration ||
|
||||
token.parent.kind === SyntaxKind.Parameter) {
|
||||
token.parent.kind === SyntaxKind.Parameter ||
|
||||
token.parent.kind === SyntaxKind.JsxAttribute) {
|
||||
return ClassificationType.operator;
|
||||
}
|
||||
}
|
||||
@@ -6841,7 +6873,7 @@ namespace ts {
|
||||
return ClassificationType.numericLiteral;
|
||||
}
|
||||
else if (tokenKind === SyntaxKind.StringLiteral || tokenKind === SyntaxKind.StringLiteralType) {
|
||||
return ClassificationType.stringLiteral;
|
||||
return token.parent.kind === SyntaxKind.JsxAttribute ? ClassificationType.jsxAttributeStringLiteralValue : ClassificationType.stringLiteral;
|
||||
}
|
||||
else if (tokenKind === SyntaxKind.RegularExpressionLiteral) {
|
||||
// TODO: we should get another classification type for these literals.
|
||||
@@ -6851,6 +6883,9 @@ namespace ts {
|
||||
// TODO (drosen): we should *also* get another classification type for these literals.
|
||||
return ClassificationType.stringLiteral;
|
||||
}
|
||||
else if (tokenKind === SyntaxKind.JsxText) {
|
||||
return ClassificationType.jsxText;
|
||||
}
|
||||
else if (tokenKind === SyntaxKind.Identifier) {
|
||||
if (token) {
|
||||
switch (token.parent.kind) {
|
||||
@@ -6902,9 +6937,12 @@ namespace ts {
|
||||
return ClassificationType.jsxSelfClosingTagName;
|
||||
}
|
||||
return;
|
||||
case SyntaxKind.JsxAttribute:
|
||||
if ((<JsxAttribute>token.parent).name === token) {
|
||||
return ClassificationType.jsxAttribute;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ClassificationType.identifier;
|
||||
}
|
||||
}
|
||||
@@ -6921,8 +6959,8 @@ namespace ts {
|
||||
const children = element.getChildren(sourceFile);
|
||||
for (let i = 0, n = children.length; i < n; i++) {
|
||||
const child = children[i];
|
||||
if (isToken(child)) {
|
||||
classifyToken(child);
|
||||
if (isToken(child) || child.kind === SyntaxKind.JsxText) {
|
||||
classifyTokenOrJsxText(child);
|
||||
}
|
||||
else {
|
||||
// Recurse into our child nodes.
|
||||
|
||||
+178
-224
@@ -16,7 +16,11 @@
|
||||
/// <reference path='services.ts' />
|
||||
|
||||
/* @internal */
|
||||
var debugObjectHost = (<any>this);
|
||||
let debugObjectHost = (<any>this);
|
||||
|
||||
// We need to use 'null' to interface with the managed side.
|
||||
/* tslint:disable:no-null */
|
||||
/* tslint:disable:no-in-operator */
|
||||
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
@@ -60,8 +64,9 @@ namespace ts {
|
||||
getNewLine?(): string;
|
||||
getProjectVersion?(): string;
|
||||
useCaseSensitiveFileNames?(): boolean;
|
||||
|
||||
|
||||
getModuleResolutionsForFile?(fileName: string): string;
|
||||
directoryExists(directoryName: string): boolean;
|
||||
}
|
||||
|
||||
/** Public interface of the the of a config service shim instance.*/
|
||||
@@ -233,8 +238,6 @@ namespace ts {
|
||||
}
|
||||
|
||||
class ScriptSnapshotShimAdapter implements IScriptSnapshot {
|
||||
private lineStartPositions: number[] = null;
|
||||
|
||||
constructor(private scriptSnapshotShim: ScriptSnapshotShim) {
|
||||
}
|
||||
|
||||
@@ -247,14 +250,14 @@ namespace ts {
|
||||
}
|
||||
|
||||
public getChangeRange(oldSnapshot: IScriptSnapshot): TextChangeRange {
|
||||
var oldSnapshotShim = <ScriptSnapshotShimAdapter>oldSnapshot;
|
||||
var encoded = this.scriptSnapshotShim.getChangeRange(oldSnapshotShim.scriptSnapshotShim);
|
||||
const oldSnapshotShim = <ScriptSnapshotShimAdapter>oldSnapshot;
|
||||
const encoded = this.scriptSnapshotShim.getChangeRange(oldSnapshotShim.scriptSnapshotShim);
|
||||
// TODO: should this be '==='?
|
||||
if (encoded == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var decoded: { span: { start: number; length: number; }; newLength: number; } = JSON.parse(encoded);
|
||||
const decoded: { span: { start: number; length: number; }; newLength: number; } = JSON.parse(encoded);
|
||||
return createTextChangeRange(
|
||||
createTextSpan(decoded.span.start, decoded.span.length), decoded.newLength);
|
||||
}
|
||||
@@ -272,21 +275,25 @@ namespace ts {
|
||||
private files: string[];
|
||||
private loggingEnabled = false;
|
||||
private tracingEnabled = false;
|
||||
|
||||
|
||||
public resolveModuleNames: (moduleName: string[], containingFile: string) => ResolvedModule[];
|
||||
|
||||
public directoryExists: (directoryName: string) => boolean;
|
||||
|
||||
constructor(private shimHost: LanguageServiceShimHost) {
|
||||
// if shimHost is a COM object then property check will become method call with no arguments.
|
||||
// 'in' does not have this effect.
|
||||
if ("getModuleResolutionsForFile" in this.shimHost) {
|
||||
this.resolveModuleNames = (moduleNames: string[], containingFile: string) => {
|
||||
let resolutionsInFile = <Map<string>>JSON.parse(this.shimHost.getModuleResolutionsForFile(containingFile));
|
||||
const resolutionsInFile = <Map<string>>JSON.parse(this.shimHost.getModuleResolutionsForFile(containingFile));
|
||||
return map(moduleNames, name => {
|
||||
const result = lookUp(resolutionsInFile, name);
|
||||
return result ? { resolvedFileName: result } : undefined;
|
||||
});
|
||||
};
|
||||
}
|
||||
if ("directoryExists" in this.shimHost) {
|
||||
this.directoryExists = directoryName => this.shimHost.directoryExists(directoryName);
|
||||
}
|
||||
}
|
||||
|
||||
public log(s: string): void {
|
||||
@@ -319,7 +326,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
public getCompilationSettings(): CompilerOptions {
|
||||
var settingsJson = this.shimHost.getCompilationSettings();
|
||||
const settingsJson = this.shimHost.getCompilationSettings();
|
||||
// TODO: should this be '==='?
|
||||
if (settingsJson == null || settingsJson == "") {
|
||||
throw Error("LanguageServiceShimHostAdapter.getCompilationSettings: empty compilationSettings");
|
||||
@@ -328,17 +335,12 @@ namespace ts {
|
||||
}
|
||||
|
||||
public getScriptFileNames(): string[] {
|
||||
var encoded = this.shimHost.getScriptFileNames();
|
||||
const encoded = this.shimHost.getScriptFileNames();
|
||||
return this.files = JSON.parse(encoded);
|
||||
}
|
||||
|
||||
public getScriptSnapshot(fileName: string): IScriptSnapshot {
|
||||
// Shim the API changes for 1.5 release. This should be removed once
|
||||
// TypeScript 1.5 has shipped.
|
||||
if (this.files && this.files.indexOf(fileName) < 0) {
|
||||
return undefined;
|
||||
}
|
||||
var scriptSnapshot = this.shimHost.getScriptSnapshot(fileName);
|
||||
const scriptSnapshot = this.shimHost.getScriptSnapshot(fileName);
|
||||
return scriptSnapshot && new ScriptSnapshotShimAdapter(scriptSnapshot);
|
||||
}
|
||||
|
||||
@@ -347,7 +349,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
public getLocalizedDiagnosticMessages(): any {
|
||||
var diagnosticMessagesJson = this.shimHost.getLocalizedDiagnosticMessages();
|
||||
const diagnosticMessagesJson = this.shimHost.getLocalizedDiagnosticMessages();
|
||||
if (diagnosticMessagesJson == null || diagnosticMessagesJson == "") {
|
||||
return null;
|
||||
}
|
||||
@@ -362,7 +364,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
public getCancellationToken(): HostCancellationToken {
|
||||
var hostCancellationToken = this.shimHost.getCancellationToken();
|
||||
const hostCancellationToken = this.shimHost.getCancellationToken();
|
||||
return new ThrottledCancellationToken(hostCancellationToken);
|
||||
}
|
||||
|
||||
@@ -371,14 +373,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
public getDefaultLibFileName(options: CompilerOptions): string {
|
||||
// Wrap the API changes for 1.5 release. This try/catch
|
||||
// should be removed once TypeScript 1.5 has shipped.
|
||||
try {
|
||||
return this.shimHost.getDefaultLibFileName(JSON.stringify(options));
|
||||
}
|
||||
catch (e) {
|
||||
return "";
|
||||
}
|
||||
return this.shimHost.getDefaultLibFileName(JSON.stringify(options));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,8 +388,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
public isCancellationRequested(): boolean {
|
||||
var time = Date.now();
|
||||
var duration = Math.abs(time - this.lastCancellationCheckTime);
|
||||
const time = Date.now();
|
||||
const duration = Math.abs(time - this.lastCancellationCheckTime);
|
||||
if (duration > 10) {
|
||||
// Check no more than once every 10 ms.
|
||||
this.lastCancellationCheckTime = time;
|
||||
@@ -405,52 +400,48 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
export class CoreServicesShimHostAdapter implements ParseConfigHost {
|
||||
export class CoreServicesShimHostAdapter implements ParseConfigHost, ModuleResolutionHost {
|
||||
|
||||
public directoryExists: (directoryName: string) => boolean;
|
||||
|
||||
constructor(private shimHost: CoreServicesShimHost) {
|
||||
if ("directoryExists" in this.shimHost) {
|
||||
this.directoryExists = directoryName => this.shimHost.directoryExists(directoryName);
|
||||
}
|
||||
}
|
||||
|
||||
public readDirectory(rootDir: string, extension: string, exclude: string[]): string[] {
|
||||
// Wrap the API changes for 1.5 release. This try/catch
|
||||
// should be removed once TypeScript 1.5 has shipped.
|
||||
// Also consider removing the optional designation for
|
||||
// the exclude param at this time.
|
||||
var encoded: string;
|
||||
try {
|
||||
encoded = this.shimHost.readDirectory(rootDir, extension, JSON.stringify(exclude));
|
||||
}
|
||||
catch (e) {
|
||||
encoded = this.shimHost.readDirectory(rootDir, extension);
|
||||
}
|
||||
const encoded = this.shimHost.readDirectory(rootDir, extension, JSON.stringify(exclude));
|
||||
return JSON.parse(encoded);
|
||||
}
|
||||
|
||||
|
||||
public fileExists(fileName: string): boolean {
|
||||
return this.shimHost.fileExists(fileName);
|
||||
}
|
||||
|
||||
|
||||
public readFile(fileName: string): string {
|
||||
return this.shimHost.readFile(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
function simpleForwardCall(logger: Logger, actionDescription: string, action: () => any, logPerformance: boolean): any {
|
||||
let start: number;
|
||||
if (logPerformance) {
|
||||
logger.log(actionDescription);
|
||||
var start = Date.now();
|
||||
start = Date.now();
|
||||
}
|
||||
|
||||
var result = action();
|
||||
const result = action();
|
||||
|
||||
if (logPerformance) {
|
||||
var end = Date.now();
|
||||
logger.log(actionDescription + " completed in " + (end - start) + " msec");
|
||||
if (typeof (result) === "string") {
|
||||
var str = <string>result;
|
||||
const end = Date.now();
|
||||
logger.log(`${actionDescription} completed in ${end - start} msec`);
|
||||
if (typeof result === "string") {
|
||||
let str = result;
|
||||
if (str.length > 128) {
|
||||
str = str.substring(0, 128) + "...";
|
||||
}
|
||||
logger.log(" result.length=" + str.length + ", result='" + JSON.stringify(str) + "'");
|
||||
logger.log(` result.length=${str.length}, result='${JSON.stringify(str)}'`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,8 +450,8 @@ namespace ts {
|
||||
|
||||
function forwardJSONCall(logger: Logger, actionDescription: string, action: () => any, logPerformance: boolean): string {
|
||||
try {
|
||||
var result = simpleForwardCall(logger, actionDescription, action, logPerformance);
|
||||
return JSON.stringify({ result: result });
|
||||
const result = simpleForwardCall(logger, actionDescription, action, logPerformance);
|
||||
return JSON.stringify({ result });
|
||||
}
|
||||
catch (err) {
|
||||
if (err instanceof OperationCanceledException) {
|
||||
@@ -481,7 +472,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
export function realizeDiagnostics(diagnostics: Diagnostic[], newLine: string): { message: string; start: number; length: number; category: string; code: number; } []{
|
||||
export function realizeDiagnostics(diagnostics: Diagnostic[], newLine: string): { message: string; start: number; length: number; category: string; code: number; }[] {
|
||||
return diagnostics.map(d => realizeDiagnostic(d, newLine));
|
||||
}
|
||||
|
||||
@@ -540,10 +531,9 @@ namespace ts {
|
||||
*/
|
||||
public refresh(throwOnError: boolean): void {
|
||||
this.forwardJSONCall(
|
||||
"refresh(" + throwOnError + ")",
|
||||
() => {
|
||||
return <any>null;
|
||||
});
|
||||
`refresh(${throwOnError})`,
|
||||
() => <any>null
|
||||
);
|
||||
}
|
||||
|
||||
public cleanupSemanticCache(): void {
|
||||
@@ -555,63 +545,57 @@ namespace ts {
|
||||
});
|
||||
}
|
||||
|
||||
private realizeDiagnostics(diagnostics: Diagnostic[]): { message: string; start: number; length: number; category: string; }[]{
|
||||
var newLine = getNewLineOrDefaultFromHost(this.host);
|
||||
private realizeDiagnostics(diagnostics: Diagnostic[]): { message: string; start: number; length: number; category: string; }[] {
|
||||
const newLine = getNewLineOrDefaultFromHost(this.host);
|
||||
return ts.realizeDiagnostics(diagnostics, newLine);
|
||||
}
|
||||
|
||||
public getSyntacticClassifications(fileName: string, start: number, length: number): string {
|
||||
return this.forwardJSONCall(
|
||||
"getSyntacticClassifications('" + fileName + "', " + start + ", " + length + ")",
|
||||
() => {
|
||||
var classifications = this.languageService.getSyntacticClassifications(fileName, createTextSpan(start, length));
|
||||
return classifications;
|
||||
});
|
||||
`getSyntacticClassifications('${fileName}', ${start}, ${length})`,
|
||||
() => this.languageService.getSyntacticClassifications(fileName, createTextSpan(start, length))
|
||||
);
|
||||
}
|
||||
|
||||
public getSemanticClassifications(fileName: string, start: number, length: number): string {
|
||||
return this.forwardJSONCall(
|
||||
"getSemanticClassifications('" + fileName + "', " + start + ", " + length + ")",
|
||||
() => {
|
||||
var classifications = this.languageService.getSemanticClassifications(fileName, createTextSpan(start, length));
|
||||
return classifications;
|
||||
});
|
||||
`getSemanticClassifications('${fileName}', ${start}, ${length})`,
|
||||
() => this.languageService.getSemanticClassifications(fileName, createTextSpan(start, length))
|
||||
);
|
||||
}
|
||||
|
||||
public getEncodedSyntacticClassifications(fileName: string, start: number, length: number): string {
|
||||
return this.forwardJSONCall(
|
||||
"getEncodedSyntacticClassifications('" + fileName + "', " + start + ", " + length + ")",
|
||||
() => {
|
||||
// directly serialize the spans out to a string. This is much faster to decode
|
||||
// on the managed side versus a full JSON array.
|
||||
return convertClassifications(this.languageService.getEncodedSyntacticClassifications(fileName, createTextSpan(start, length)));
|
||||
});
|
||||
`getEncodedSyntacticClassifications('${fileName}', ${start}, ${length})`,
|
||||
// directly serialize the spans out to a string. This is much faster to decode
|
||||
// on the managed side versus a full JSON array.
|
||||
() => convertClassifications(this.languageService.getEncodedSyntacticClassifications(fileName, createTextSpan(start, length)))
|
||||
);
|
||||
}
|
||||
|
||||
public getEncodedSemanticClassifications(fileName: string, start: number, length: number): string {
|
||||
return this.forwardJSONCall(
|
||||
"getEncodedSemanticClassifications('" + fileName + "', " + start + ", " + length + ")",
|
||||
() => {
|
||||
// directly serialize the spans out to a string. This is much faster to decode
|
||||
// on the managed side versus a full JSON array.
|
||||
return convertClassifications(this.languageService.getEncodedSemanticClassifications(fileName, createTextSpan(start, length)));
|
||||
});
|
||||
`getEncodedSemanticClassifications('${fileName}', ${start}, ${length})`,
|
||||
// directly serialize the spans out to a string. This is much faster to decode
|
||||
// on the managed side versus a full JSON array.
|
||||
() => convertClassifications(this.languageService.getEncodedSemanticClassifications(fileName, createTextSpan(start, length)))
|
||||
);
|
||||
}
|
||||
|
||||
public getSyntacticDiagnostics(fileName: string): string {
|
||||
return this.forwardJSONCall(
|
||||
"getSyntacticDiagnostics('" + fileName + "')",
|
||||
`getSyntacticDiagnostics('${fileName}')`,
|
||||
() => {
|
||||
var diagnostics = this.languageService.getSyntacticDiagnostics(fileName);
|
||||
const diagnostics = this.languageService.getSyntacticDiagnostics(fileName);
|
||||
return this.realizeDiagnostics(diagnostics);
|
||||
});
|
||||
}
|
||||
|
||||
public getSemanticDiagnostics(fileName: string): string {
|
||||
return this.forwardJSONCall(
|
||||
"getSemanticDiagnostics('" + fileName + "')",
|
||||
`getSemanticDiagnostics('${fileName}')`,
|
||||
() => {
|
||||
var diagnostics = this.languageService.getSemanticDiagnostics(fileName);
|
||||
const diagnostics = this.languageService.getSemanticDiagnostics(fileName);
|
||||
return this.realizeDiagnostics(diagnostics);
|
||||
});
|
||||
}
|
||||
@@ -620,7 +604,7 @@ namespace ts {
|
||||
return this.forwardJSONCall(
|
||||
"getCompilerOptionsDiagnostics()",
|
||||
() => {
|
||||
var diagnostics = this.languageService.getCompilerOptionsDiagnostics();
|
||||
const diagnostics = this.languageService.getCompilerOptionsDiagnostics();
|
||||
return this.realizeDiagnostics(diagnostics);
|
||||
});
|
||||
}
|
||||
@@ -633,11 +617,9 @@ namespace ts {
|
||||
*/
|
||||
public getQuickInfoAtPosition(fileName: string, position: number): string {
|
||||
return this.forwardJSONCall(
|
||||
"getQuickInfoAtPosition('" + fileName + "', " + position + ")",
|
||||
() => {
|
||||
var quickInfo = this.languageService.getQuickInfoAtPosition(fileName, position);
|
||||
return quickInfo;
|
||||
});
|
||||
`getQuickInfoAtPosition('${fileName}', ${position})`,
|
||||
() => this.languageService.getQuickInfoAtPosition(fileName, position)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -649,11 +631,9 @@ namespace ts {
|
||||
*/
|
||||
public getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): string {
|
||||
return this.forwardJSONCall(
|
||||
"getNameOrDottedNameSpan('" + fileName + "', " + startPos + ", " + endPos + ")",
|
||||
() => {
|
||||
var spanInfo = this.languageService.getNameOrDottedNameSpan(fileName, startPos, endPos);
|
||||
return spanInfo;
|
||||
});
|
||||
`getNameOrDottedNameSpan('${fileName}', ${startPos}, ${endPos})`,
|
||||
() => this.languageService.getNameOrDottedNameSpan(fileName, startPos, endPos)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -662,22 +642,18 @@ namespace ts {
|
||||
*/
|
||||
public getBreakpointStatementAtPosition(fileName: string, position: number): string {
|
||||
return this.forwardJSONCall(
|
||||
"getBreakpointStatementAtPosition('" + fileName + "', " + position + ")",
|
||||
() => {
|
||||
var spanInfo = this.languageService.getBreakpointStatementAtPosition(fileName, position);
|
||||
return spanInfo;
|
||||
});
|
||||
`getBreakpointStatementAtPosition('${fileName}', ${position})`,
|
||||
() => this.languageService.getBreakpointStatementAtPosition(fileName, position)
|
||||
);
|
||||
}
|
||||
|
||||
/// SIGNATUREHELP
|
||||
|
||||
public getSignatureHelpItems(fileName: string, position: number): string {
|
||||
return this.forwardJSONCall(
|
||||
"getSignatureHelpItems('" + fileName + "', " + position + ")",
|
||||
() => {
|
||||
var signatureInfo = this.languageService.getSignatureHelpItems(fileName, position);
|
||||
return signatureInfo;
|
||||
});
|
||||
`getSignatureHelpItems('${fileName}', ${position})`,
|
||||
() => this.languageService.getSignatureHelpItems(fileName, position)
|
||||
);
|
||||
}
|
||||
|
||||
/// GOTO DEFINITION
|
||||
@@ -688,10 +664,9 @@ namespace ts {
|
||||
*/
|
||||
public getDefinitionAtPosition(fileName: string, position: number): string {
|
||||
return this.forwardJSONCall(
|
||||
"getDefinitionAtPosition('" + fileName + "', " + position + ")",
|
||||
() => {
|
||||
return this.languageService.getDefinitionAtPosition(fileName, position);
|
||||
});
|
||||
`getDefinitionAtPosition('${fileName}', ${position})`,
|
||||
() => this.languageService.getDefinitionAtPosition(fileName, position)
|
||||
);
|
||||
}
|
||||
|
||||
/// GOTO Type
|
||||
@@ -702,44 +677,39 @@ namespace ts {
|
||||
*/
|
||||
public getTypeDefinitionAtPosition(fileName: string, position: number): string {
|
||||
return this.forwardJSONCall(
|
||||
"getTypeDefinitionAtPosition('" + fileName + "', " + position + ")",
|
||||
() => {
|
||||
return this.languageService.getTypeDefinitionAtPosition(fileName, position);
|
||||
});
|
||||
`getTypeDefinitionAtPosition('${fileName}', ${position})`,
|
||||
() => this.languageService.getTypeDefinitionAtPosition(fileName, position)
|
||||
);
|
||||
}
|
||||
|
||||
public getRenameInfo(fileName: string, position: number): string {
|
||||
return this.forwardJSONCall(
|
||||
"getRenameInfo('" + fileName + "', " + position + ")",
|
||||
() => {
|
||||
return this.languageService.getRenameInfo(fileName, position);
|
||||
});
|
||||
`getRenameInfo('${fileName}', ${position})`,
|
||||
() => this.languageService.getRenameInfo(fileName, position)
|
||||
);
|
||||
}
|
||||
|
||||
public findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): string {
|
||||
return this.forwardJSONCall(
|
||||
"findRenameLocations('" + fileName + "', " + position + ", " + findInStrings + ", " + findInComments + ")",
|
||||
() => {
|
||||
return this.languageService.findRenameLocations(fileName, position, findInStrings, findInComments);
|
||||
});
|
||||
`findRenameLocations('${fileName}', ${position}, ${findInStrings}, ${findInComments})`,
|
||||
() => this.languageService.findRenameLocations(fileName, position, findInStrings, findInComments)
|
||||
);
|
||||
}
|
||||
|
||||
/// GET BRACE MATCHING
|
||||
public getBraceMatchingAtPosition(fileName: string, position: number): string {
|
||||
return this.forwardJSONCall(
|
||||
"getBraceMatchingAtPosition('" + fileName + "', " + position + ")",
|
||||
() => {
|
||||
var textRanges = this.languageService.getBraceMatchingAtPosition(fileName, position);
|
||||
return textRanges;
|
||||
});
|
||||
`getBraceMatchingAtPosition('${fileName}', ${position})`,
|
||||
() => this.languageService.getBraceMatchingAtPosition(fileName, position)
|
||||
);
|
||||
}
|
||||
|
||||
/// GET SMART INDENT
|
||||
public getIndentationAtPosition(fileName: string, position: number, options: string /*Services.EditorOptions*/): string {
|
||||
return this.forwardJSONCall(
|
||||
"getIndentationAtPosition('" + fileName + "', " + position + ")",
|
||||
`getIndentationAtPosition('${fileName}', ${position})`,
|
||||
() => {
|
||||
var localOptions: EditorOptions = JSON.parse(options);
|
||||
const localOptions: EditorOptions = JSON.parse(options);
|
||||
return this.languageService.getIndentationAtPosition(fileName, position, localOptions);
|
||||
});
|
||||
}
|
||||
@@ -748,35 +718,32 @@ namespace ts {
|
||||
|
||||
public getReferencesAtPosition(fileName: string, position: number): string {
|
||||
return this.forwardJSONCall(
|
||||
"getReferencesAtPosition('" + fileName + "', " + position + ")",
|
||||
() => {
|
||||
return this.languageService.getReferencesAtPosition(fileName, position);
|
||||
});
|
||||
`getReferencesAtPosition('${fileName}', ${position})`,
|
||||
() => this.languageService.getReferencesAtPosition(fileName, position)
|
||||
);
|
||||
}
|
||||
|
||||
public findReferences(fileName: string, position: number): string {
|
||||
return this.forwardJSONCall(
|
||||
"findReferences('" + fileName + "', " + position + ")",
|
||||
() => {
|
||||
return this.languageService.findReferences(fileName, position);
|
||||
});
|
||||
`findReferences('${fileName}', ${position})`,
|
||||
() => this.languageService.findReferences(fileName, position)
|
||||
);
|
||||
}
|
||||
|
||||
public getOccurrencesAtPosition(fileName: string, position: number): string {
|
||||
return this.forwardJSONCall(
|
||||
"getOccurrencesAtPosition('" + fileName + "', " + position + ")",
|
||||
() => {
|
||||
return this.languageService.getOccurrencesAtPosition(fileName, position);
|
||||
});
|
||||
`getOccurrencesAtPosition('${fileName}', ${position})`,
|
||||
() => this.languageService.getOccurrencesAtPosition(fileName, position)
|
||||
);
|
||||
}
|
||||
|
||||
public getDocumentHighlights(fileName: string, position: number, filesToSearch: string): string {
|
||||
return this.forwardJSONCall(
|
||||
"getDocumentHighlights('" + fileName + "', " + position + ")",
|
||||
`getDocumentHighlights('${fileName}', ${position})`,
|
||||
() => {
|
||||
var results = this.languageService.getDocumentHighlights(fileName, position, JSON.parse(filesToSearch));
|
||||
const results = this.languageService.getDocumentHighlights(fileName, position, JSON.parse(filesToSearch));
|
||||
// workaround for VS document higlighting issue - keep only items from the initial file
|
||||
let normalizedName = normalizeSlashes(fileName).toLowerCase();
|
||||
const normalizedName = normalizeSlashes(fileName).toLowerCase();
|
||||
return filter(results, r => normalizeSlashes(r.fileName).toLowerCase() === normalizedName);
|
||||
});
|
||||
}
|
||||
@@ -790,56 +757,49 @@ namespace ts {
|
||||
*/
|
||||
public getCompletionsAtPosition(fileName: string, position: number) {
|
||||
return this.forwardJSONCall(
|
||||
"getCompletionsAtPosition('" + fileName + "', " + position + ")",
|
||||
() => {
|
||||
var completion = this.languageService.getCompletionsAtPosition(fileName, position);
|
||||
return completion;
|
||||
});
|
||||
`getCompletionsAtPosition('${fileName}', ${position})`,
|
||||
() => this.languageService.getCompletionsAtPosition(fileName, position)
|
||||
);
|
||||
}
|
||||
|
||||
/** Get a string based representation of a completion list entry details */
|
||||
public getCompletionEntryDetails(fileName: string, position: number, entryName: string) {
|
||||
return this.forwardJSONCall(
|
||||
"getCompletionEntryDetails('" + fileName + "', " + position + ", " + entryName + ")",
|
||||
() => {
|
||||
var details = this.languageService.getCompletionEntryDetails(fileName, position, entryName);
|
||||
return details;
|
||||
});
|
||||
`getCompletionEntryDetails('${fileName}', ${position}, '${entryName}')`,
|
||||
() => this.languageService.getCompletionEntryDetails(fileName, position, entryName)
|
||||
);
|
||||
}
|
||||
|
||||
public getFormattingEditsForRange(fileName: string, start: number, end: number, options: string/*Services.FormatCodeOptions*/): string {
|
||||
return this.forwardJSONCall(
|
||||
"getFormattingEditsForRange('" + fileName + "', " + start + ", " + end + ")",
|
||||
`getFormattingEditsForRange('${fileName}', ${start}, ${end})`,
|
||||
() => {
|
||||
var localOptions: ts.FormatCodeOptions = JSON.parse(options);
|
||||
var edits = this.languageService.getFormattingEditsForRange(fileName, start, end, localOptions);
|
||||
return edits;
|
||||
const localOptions: ts.FormatCodeOptions = JSON.parse(options);
|
||||
return this.languageService.getFormattingEditsForRange(fileName, start, end, localOptions);
|
||||
});
|
||||
}
|
||||
|
||||
public getFormattingEditsForDocument(fileName: string, options: string/*Services.FormatCodeOptions*/): string {
|
||||
return this.forwardJSONCall(
|
||||
"getFormattingEditsForDocument('" + fileName + "')",
|
||||
`getFormattingEditsForDocument('${fileName}')`,
|
||||
() => {
|
||||
var localOptions: ts.FormatCodeOptions = JSON.parse(options);
|
||||
var edits = this.languageService.getFormattingEditsForDocument(fileName, localOptions);
|
||||
return edits;
|
||||
const localOptions: ts.FormatCodeOptions = JSON.parse(options);
|
||||
return this.languageService.getFormattingEditsForDocument(fileName, localOptions);
|
||||
});
|
||||
}
|
||||
|
||||
public getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: string/*Services.FormatCodeOptions*/): string {
|
||||
return this.forwardJSONCall(
|
||||
"getFormattingEditsAfterKeystroke('" + fileName + "', " + position + ", '" + key + "')",
|
||||
`getFormattingEditsAfterKeystroke('${fileName}', ${position}, '${key}')`,
|
||||
() => {
|
||||
var localOptions: ts.FormatCodeOptions = JSON.parse(options);
|
||||
var edits = this.languageService.getFormattingEditsAfterKeystroke(fileName, position, key, localOptions);
|
||||
return edits;
|
||||
const localOptions: ts.FormatCodeOptions = JSON.parse(options);
|
||||
return this.languageService.getFormattingEditsAfterKeystroke(fileName, position, key, localOptions);
|
||||
});
|
||||
}
|
||||
|
||||
public getDocCommentTemplateAtPosition(fileName: string, position: number): string {
|
||||
return this.forwardJSONCall(
|
||||
"getDocCommentTemplateAtPosition('" + fileName + "', " + position + ")",
|
||||
`getDocCommentTemplateAtPosition('${fileName}', ${position})`,
|
||||
() => this.languageService.getDocCommentTemplateAtPosition(fileName, position)
|
||||
);
|
||||
}
|
||||
@@ -849,51 +809,38 @@ namespace ts {
|
||||
/** Return a list of symbols that are interesting to navigate to */
|
||||
public getNavigateToItems(searchValue: string, maxResultCount?: number): string {
|
||||
return this.forwardJSONCall(
|
||||
"getNavigateToItems('" + searchValue + "', " + maxResultCount+ ")",
|
||||
() => {
|
||||
var items = this.languageService.getNavigateToItems(searchValue, maxResultCount);
|
||||
return items;
|
||||
});
|
||||
`getNavigateToItems('${searchValue}', ${maxResultCount})`,
|
||||
() => this.languageService.getNavigateToItems(searchValue, maxResultCount)
|
||||
);
|
||||
}
|
||||
|
||||
public getNavigationBarItems(fileName: string): string {
|
||||
return this.forwardJSONCall(
|
||||
"getNavigationBarItems('" + fileName + "')",
|
||||
() => {
|
||||
var items = this.languageService.getNavigationBarItems(fileName);
|
||||
return items;
|
||||
});
|
||||
`getNavigationBarItems('${fileName}')`,
|
||||
() => this.languageService.getNavigationBarItems(fileName)
|
||||
);
|
||||
}
|
||||
|
||||
public getOutliningSpans(fileName: string): string {
|
||||
return this.forwardJSONCall(
|
||||
"getOutliningSpans('" + fileName + "')",
|
||||
() => {
|
||||
var items = this.languageService.getOutliningSpans(fileName);
|
||||
return items;
|
||||
});
|
||||
`getOutliningSpans('${fileName}')`,
|
||||
() => this.languageService.getOutliningSpans(fileName)
|
||||
);
|
||||
}
|
||||
|
||||
public getTodoComments(fileName: string, descriptors: string): string {
|
||||
return this.forwardJSONCall(
|
||||
"getTodoComments('" + fileName + "')",
|
||||
() => {
|
||||
var items = this.languageService.getTodoComments(fileName, JSON.parse(descriptors));
|
||||
return items;
|
||||
});
|
||||
`getTodoComments('${fileName}')`,
|
||||
() => this.languageService.getTodoComments(fileName, JSON.parse(descriptors))
|
||||
);
|
||||
}
|
||||
|
||||
/// Emit
|
||||
public getEmitOutput(fileName: string): string {
|
||||
return this.forwardJSONCall(
|
||||
"getEmitOutput('" + fileName + "')",
|
||||
() => {
|
||||
var output = this.languageService.getEmitOutput(fileName);
|
||||
// Shim the API changes for 1.5 release. This should be removed once
|
||||
// TypeScript 1.5 has shipped.
|
||||
(<any>output).emitOutputStatus = output.emitSkipped ? 1 : 0;
|
||||
return output;
|
||||
});
|
||||
`getEmitOutput('${fileName}')`,
|
||||
() => this.languageService.getEmitOutput(fileName)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -918,12 +865,11 @@ namespace ts {
|
||||
|
||||
/// COLORIZATION
|
||||
public getClassificationsForLine(text: string, lexState: EndOfLineState, classifyKeywordsInGenerics?: boolean): string {
|
||||
var classification = this.classifier.getClassificationsForLine(text, lexState, classifyKeywordsInGenerics);
|
||||
var items = classification.entries;
|
||||
var result = "";
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
result += items[i].length + "\n";
|
||||
result += items[i].classification + "\n";
|
||||
const classification = this.classifier.getClassificationsForLine(text, lexState, classifyKeywordsInGenerics);
|
||||
let result = "";
|
||||
for (const item of classification.entries) {
|
||||
result += item.length + "\n";
|
||||
result += item.classification + "\n";
|
||||
}
|
||||
result += classification.finalLexState;
|
||||
return result;
|
||||
@@ -940,16 +886,16 @@ namespace ts {
|
||||
private forwardJSONCall(actionDescription: string, action: () => any): any {
|
||||
return forwardJSONCall(this.logger, actionDescription, action, this.logPerformance);
|
||||
}
|
||||
|
||||
|
||||
public resolveModuleName(fileName: string, moduleName: string, compilerOptionsJson: string): string {
|
||||
return this.forwardJSONCall(`resolveModuleName('${fileName}')`, () => {
|
||||
let compilerOptions = <CompilerOptions>JSON.parse(compilerOptionsJson);
|
||||
const compilerOptions = <CompilerOptions>JSON.parse(compilerOptionsJson);
|
||||
const result = resolveModuleName(moduleName, normalizeSlashes(fileName), compilerOptions, this.host);
|
||||
return {
|
||||
resolvedFileName: result.resolvedModule ? result.resolvedModule.resolvedFileName: undefined,
|
||||
resolvedFileName: result.resolvedModule ? result.resolvedModule.resolvedFileName : undefined,
|
||||
failedLookupLocations: result.failedLookupLocations
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public getPreProcessedFileInfo(fileName: string, sourceTextSnapshot: IScriptSnapshot): string {
|
||||
@@ -957,8 +903,8 @@ namespace ts {
|
||||
"getPreProcessedFileInfo('" + fileName + "')",
|
||||
() => {
|
||||
// for now treat files as JavaScript
|
||||
var result = preProcessFile(sourceTextSnapshot.getText(0, sourceTextSnapshot.getLength()), /* readImportFiles */ true, /* detectJavaScriptImports */ true);
|
||||
var convertResult = {
|
||||
const result = preProcessFile(sourceTextSnapshot.getText(0, sourceTextSnapshot.getLength()), /* readImportFiles */ true, /* detectJavaScriptImports */ true);
|
||||
const convertResult = {
|
||||
referencedFiles: <IFileReference[]>[],
|
||||
importedFiles: <IFileReference[]>[],
|
||||
ambientExternalModules: result.ambientExternalModules,
|
||||
@@ -986,26 +932,26 @@ namespace ts {
|
||||
|
||||
public getTSConfigFileInfo(fileName: string, sourceTextSnapshot: IScriptSnapshot): string {
|
||||
return this.forwardJSONCall(
|
||||
"getTSConfigFileInfo('" + fileName + "')",
|
||||
`getTSConfigFileInfo('${fileName}')`,
|
||||
() => {
|
||||
let text = sourceTextSnapshot.getText(0, sourceTextSnapshot.getLength());
|
||||
const text = sourceTextSnapshot.getText(0, sourceTextSnapshot.getLength());
|
||||
|
||||
let result = parseConfigFileTextToJson(fileName, text);
|
||||
const result = parseConfigFileTextToJson(fileName, text);
|
||||
|
||||
if (result.error) {
|
||||
return {
|
||||
options: {},
|
||||
files: [],
|
||||
errors: [realizeDiagnostic(result.error, '\r\n')]
|
||||
errors: [realizeDiagnostic(result.error, "\r\n")]
|
||||
};
|
||||
}
|
||||
|
||||
var configFile = parseJsonConfigFileContent(result.config, this.host, getDirectoryPath(normalizeSlashes(fileName)));
|
||||
const configFile = parseJsonConfigFileContent(result.config, this.host, getDirectoryPath(normalizeSlashes(fileName)));
|
||||
|
||||
return {
|
||||
options: configFile.options,
|
||||
files: configFile.fileNames,
|
||||
errors: realizeDiagnostics(configFile.errors, '\r\n')
|
||||
errors: realizeDiagnostics(configFile.errors, "\r\n")
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -1013,9 +959,8 @@ namespace ts {
|
||||
public getDefaultCompilationSettings(): string {
|
||||
return this.forwardJSONCall(
|
||||
"getDefaultCompilationSettings()",
|
||||
() => {
|
||||
return getDefaultCompilerOptions();
|
||||
});
|
||||
() => getDefaultCompilerOptions()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1035,8 +980,8 @@ namespace ts {
|
||||
if (this.documentRegistry === undefined) {
|
||||
this.documentRegistry = createDocumentRegistry(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames(), host.getCurrentDirectory());
|
||||
}
|
||||
var hostAdapter = new LanguageServiceShimHostAdapter(host);
|
||||
var languageService = createLanguageService(hostAdapter, this.documentRegistry);
|
||||
const hostAdapter = new LanguageServiceShimHostAdapter(host);
|
||||
const languageService = createLanguageService(hostAdapter, this.documentRegistry);
|
||||
return new LanguageServiceShimObject(this, host, languageService);
|
||||
}
|
||||
catch (err) {
|
||||
@@ -1057,7 +1002,7 @@ namespace ts {
|
||||
|
||||
public createCoreServicesShim(host: CoreServicesShimHost): CoreServicesShim {
|
||||
try {
|
||||
var adapter = new CoreServicesShimHostAdapter(host);
|
||||
const adapter = new CoreServicesShimHostAdapter(host);
|
||||
return new CoreServicesShimObject(this, <Logger>host, adapter);
|
||||
}
|
||||
catch (err) {
|
||||
@@ -1077,7 +1022,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
public unregisterShim(shim: Shim): void {
|
||||
for (var i = 0, n = this._shims.length; i < n; i++) {
|
||||
for (let i = 0, n = this._shims.length; i < n; i++) {
|
||||
if (this._shims[i] === shim) {
|
||||
delete this._shims[i];
|
||||
return;
|
||||
@@ -1096,12 +1041,21 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
/* tslint:enable:no-in-operator */
|
||||
/* tslint:enable:no-null */
|
||||
|
||||
|
||||
/// TODO: this is used by VS, clean this up on both sides of the interface
|
||||
/* @internal */
|
||||
module TypeScript.Services {
|
||||
export var TypeScriptServicesFactory = ts.TypeScriptServicesFactory;
|
||||
namespace TypeScript.Services {
|
||||
export const TypeScriptServicesFactory = ts.TypeScriptServicesFactory;
|
||||
}
|
||||
|
||||
/* tslint:disable:no-unused-variable */
|
||||
// 'toolsVersion' gets consumed by the managed side, so it's not unused.
|
||||
// TODO: it should be moved into a namespace though.
|
||||
|
||||
/* @internal */
|
||||
const toolsVersion = "1.6";
|
||||
const toolsVersion = "1.8";
|
||||
|
||||
/* tslint:enable:no-unused-variable */
|
||||
@@ -608,6 +608,36 @@ namespace ts {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export function isArrayLiteralOrObjectLiteralDestructuringPattern(node: Node) {
|
||||
if (node.kind === SyntaxKind.ArrayLiteralExpression ||
|
||||
node.kind === SyntaxKind.ObjectLiteralExpression) {
|
||||
// [a,b,c] from:
|
||||
// [a, b, c] = someExpression;
|
||||
if (node.parent.kind === SyntaxKind.BinaryExpression &&
|
||||
(<BinaryExpression>node.parent).left === node &&
|
||||
(<BinaryExpression>node.parent).operatorToken.kind === SyntaxKind.EqualsToken) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// [a, b, c] from:
|
||||
// for([a, b, c] of expression)
|
||||
if (node.parent.kind === SyntaxKind.ForOfStatement &&
|
||||
(<ForOfStatement>node.parent).initializer === node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// [a, b, c] of
|
||||
// [x, [a, b, c] ] = someExpression
|
||||
// or
|
||||
// {x, a: {a, b, c} } = someExpression
|
||||
if (isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent.kind === SyntaxKind.PropertyAssignment ? node.parent.parent : node.parent)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Display-part writer helpers
|
||||
|
||||
Reference in New Issue
Block a user