Update LKG

This commit is contained in:
Mohamed Hegazy
2017-09-08 17:34:24 -07:00
parent 9434a81b71
commit c476a08188
9 changed files with 496 additions and 438 deletions
+5 -4
View File
@@ -11088,7 +11088,8 @@ var ts;
return token() === 24 ||
isIdentifierOrPattern() ||
ts.isModifierKind(token()) ||
token() === 57 || isStartOfType();
token() === 57 ||
isStartOfType(true);
}
function parseParameter() {
var node = createNode(146);
@@ -11427,7 +11428,7 @@ var ts;
return parseTypeReference();
}
}
function isStartOfType() {
function isStartOfType(inStartOfParameter) {
switch (token()) {
case 119:
case 136:
@@ -11454,9 +11455,9 @@ var ts;
case 39:
return true;
case 38:
return lookAhead(nextTokenIsNumericLiteral);
return !inStartOfParameter && lookAhead(nextTokenIsNumericLiteral);
case 19:
return lookAhead(isStartOfParenthesizedOrFunctionType);
return !inStartOfParameter && lookAhead(isStartOfParenthesizedOrFunctionType);
default:
return isIdentifier();
}
+115 -106
View File
@@ -12958,7 +12958,8 @@ var ts;
return token() === 24 ||
isIdentifierOrPattern() ||
ts.isModifierKind(token()) ||
token() === 57 || isStartOfType();
token() === 57 ||
isStartOfType(true);
}
function parseParameter() {
var node = createNode(146);
@@ -13297,7 +13298,7 @@ var ts;
return parseTypeReference();
}
}
function isStartOfType() {
function isStartOfType(inStartOfParameter) {
switch (token()) {
case 119:
case 136:
@@ -13324,9 +13325,9 @@ var ts;
case 39:
return true;
case 38:
return lookAhead(nextTokenIsNumericLiteral);
return !inStartOfParameter && lookAhead(nextTokenIsNumericLiteral);
case 19:
return lookAhead(isStartOfParenthesizedOrFunctionType);
return !inStartOfParameter && lookAhead(isStartOfParenthesizedOrFunctionType);
default:
return isIdentifier();
}
@@ -74425,7 +74426,9 @@ var ts;
deleteCallback();
}
return {
edits: changeTracker.getChanges()
edits: changeTracker.getChanges(),
renameFilename: undefined,
renameLocation: undefined,
};
function deleteNode(node, inList) {
if (inList === void 0) { inList = false; }
@@ -74576,11 +74579,11 @@ var ts;
var usedNames = ts.createMap();
var i = 0;
for (var _i = 0, extractions_1 = extractions; _i < extractions_1.length; _i++) {
var extr = extractions_1[_i];
if (extr.errors && extr.errors.length) {
var _a = extractions_1[_i], scopeDescription = _a.scopeDescription, errors = _a.errors;
if (errors.length) {
continue;
}
var description = ts.formatStringFromArgs(ts.Diagnostics.Extract_function_into_0.message, [extr.scopeDescription]);
var description = ts.formatStringFromArgs(ts.Diagnostics.Extract_function_into_0.message, [scopeDescription]);
if (!usedNames.has(description)) {
usedNames.set(description, true);
actions.push({
@@ -74608,9 +74611,7 @@ var ts;
ts.Debug.assert(!!parsedIndexMatch, "Scope name should have matched the regexp");
var index = +parsedIndexMatch[1];
ts.Debug.assert(isFinite(index), "Expected to parse a finite number from the scope index");
var extractions = getPossibleExtractions(targetRange, context, index);
ts.Debug.assert(extractions !== undefined, "The extraction went missing? How?");
return ({ edits: extractions[0].changes });
return getExtractionAtIndex(targetRange, context, index);
}
var Messages;
(function (Messages) {
@@ -74639,7 +74640,7 @@ var ts;
RangeFacts[RangeFacts["IsAsyncFunction"] = 4] = "IsAsyncFunction";
RangeFacts[RangeFacts["UsesThis"] = 8] = "UsesThis";
RangeFacts[RangeFacts["InStaticRegion"] = 16] = "InStaticRegion";
})(RangeFacts = extractMethod_1.RangeFacts || (extractMethod_1.RangeFacts = {}));
})(RangeFacts || (RangeFacts = {}));
function getRangeToExtract(sourceFile, span) {
var length = span.length || 0;
var start = getParentNodeInSpan(ts.getTokenAtPosition(sourceFile, span.start, false), sourceFile, span);
@@ -74879,7 +74880,7 @@ var ts;
return undefined;
}
function isValidExtractionTarget(node) {
return (node.kind === 228) || ts.isSourceFile(node) || isModuleBlock(node) || ts.isClassLike(node);
return (node.kind === 228) || ts.isSourceFile(node) || ts.isModuleBlock(node) || ts.isClassLike(node);
}
function collectEnclosingScopes(range) {
var current = isReadonlyArray(range.range) ? ts.firstOrUndefined(range.range) : range.range;
@@ -74904,9 +74905,21 @@ var ts;
}
return scopes;
}
extractMethod_1.collectEnclosingScopes = collectEnclosingScopes;
function getPossibleExtractions(targetRange, context, requestedChangesIndex) {
if (requestedChangesIndex === void 0) { requestedChangesIndex = undefined; }
function getExtractionAtIndex(targetRange, context, requestedChangesIndex) {
var _a = getPossibleExtractionsWorker(targetRange, context), scopes = _a.scopes, _b = _a.readsAndWrites, target = _b.target, usagesPerScope = _b.usagesPerScope, errorsPerScope = _b.errorsPerScope;
ts.Debug.assert(!errorsPerScope[requestedChangesIndex].length, "The extraction went missing? How?");
context.cancellationToken.throwIfCancellationRequested();
return extractFunctionInScope(target, scopes[requestedChangesIndex], usagesPerScope[requestedChangesIndex], targetRange, context);
}
extractMethod_1.getExtractionAtIndex = getExtractionAtIndex;
function getPossibleExtractions(targetRange, context) {
var extractions = getPossibleExtractionsWorker(targetRange, context);
return extractions && extractions.scopes.map(function (scope, i) {
return ({ scopeDescription: getDescriptionForScope(scope), errors: extractions.readsAndWrites.errorsPerScope[i] });
});
}
extractMethod_1.getPossibleExtractions = getPossibleExtractions;
function getPossibleExtractionsWorker(targetRange, context) {
var sourceFile = context.file;
if (targetRange === undefined) {
return undefined;
@@ -74916,29 +74929,9 @@ var ts;
return undefined;
}
var enclosingTextRange = getEnclosingTextRange(targetRange, sourceFile);
var _a = collectReadsAndWrites(targetRange, scopes, enclosingTextRange, sourceFile, context.program.getTypeChecker()), target = _a.target, usagesPerScope = _a.usagesPerScope, errorsPerScope = _a.errorsPerScope;
context.cancellationToken.throwIfCancellationRequested();
if (requestedChangesIndex !== undefined) {
if (errorsPerScope[requestedChangesIndex].length) {
return undefined;
}
return [extractFunctionInScope(target, scopes[requestedChangesIndex], usagesPerScope[requestedChangesIndex], targetRange, context)];
}
else {
return scopes.map(function (scope, i) {
var errors = errorsPerScope[i];
if (errors.length) {
return {
scope: scope,
scopeDescription: getDescriptionForScope(scope),
errors: errors
};
}
return { scope: scope, scopeDescription: getDescriptionForScope(scope) };
});
}
var readsAndWrites = collectReadsAndWrites(targetRange, scopes, enclosingTextRange, sourceFile, context.program.getTypeChecker());
return { scopes: scopes, readsAndWrites: readsAndWrites };
}
extractMethod_1.getPossibleExtractions = getPossibleExtractions;
function getDescriptionForScope(scope) {
if (ts.isFunctionLike(scope)) {
switch (scope.kind) {
@@ -74960,7 +74953,7 @@ var ts;
return "'set " + scope.name.getText() + "'";
}
}
else if (isModuleBlock(scope)) {
else if (ts.isModuleBlock(scope)) {
return "namespace '" + scope.parent.name.getText() + "'";
}
else if (ts.isClassLike(scope)) {
@@ -74977,14 +74970,10 @@ var ts;
return "unknown";
}
}
function getUniqueName(isNameOkay) {
function getUniqueName(fileText) {
var functionNameText = "newFunction";
if (isNameOkay(functionNameText)) {
return functionNameText;
}
var i = 1;
while (!isNameOkay(functionNameText = "newFunction_" + i)) {
i++;
for (var i = 1; fileText.indexOf(functionNameText) !== -1; i++) {
functionNameText = "newFunction_" + i;
}
return functionNameText;
}
@@ -74992,10 +74981,9 @@ var ts;
var usagesInScope = _a.usages, substitutions = _a.substitutions;
var checker = context.program.getTypeChecker();
var file = scope.getSourceFile();
var functionNameText = getUniqueName(function (n) { return !file.identifiers.has(n); });
var functionNameText = getUniqueName(file.text);
var isJS = ts.isInJavaScriptFile(scope);
var functionName = ts.createIdentifier(functionNameText);
var functionReference = ts.createIdentifier(functionNameText);
var returnType = undefined;
var parameters = [];
var callArguments = [];
@@ -75018,7 +75006,7 @@ var ts;
var contextualType = checker.getContextualType(node);
returnType = checker.typeToTypeNode(contextualType);
}
var _b = transformFunctionBody(node), body = _b.body, returnValueProperty = _b.returnValueProperty;
var _b = transformFunctionBody(node, writes, substitutions, !!(range.facts & RangeFacts.HasReturn)), body = _b.body, returnValueProperty = _b.returnValueProperty;
var newFunction;
if (ts.isClassLike(scope)) {
var modifiers = isJS ? [] : [ts.createToken(112)];
@@ -75036,7 +75024,8 @@ var ts;
var changeTracker = ts.textChanges.ChangeTracker.fromCodeFixContext(context);
changeTracker.insertNodeBefore(context.file, scope.getLastToken(), newFunction, { prefix: context.newLineCharacter, suffix: context.newLineCharacter });
var newNodes = [];
var call = ts.createCall(ts.isClassLike(scope) ? ts.createPropertyAccess(range.facts & RangeFacts.InStaticRegion ? ts.createIdentifier(scope.name.getText()) : ts.createThis(), functionReference) : functionReference, undefined, callArguments);
var called = getCalledExpression(scope, range, functionNameText);
var call = ts.createCall(called, undefined, callArguments);
if (range.facts & RangeFacts.IsGenerator) {
call = ts.createYield(ts.createToken(39), call);
}
@@ -75086,65 +75075,85 @@ var ts;
else {
changeTracker.replaceNodeWithNodes(context.file, range.range, newNodes, { nodeSeparator: context.newLineCharacter });
}
return {
scope: scope,
scopeDescription: getDescriptionForScope(scope),
changes: changeTracker.getChanges()
};
function getPropertyAssignmentsForWrites(writes) {
return writes.map(function (w) { return ts.createShorthandPropertyAssignment(w.symbol.name); });
}
function generateReturnValueProperty() {
return "__return";
}
function transformFunctionBody(body) {
if (ts.isBlock(body) && !writes && substitutions.size === 0) {
return { body: ts.createBlock(body.statements, true), returnValueProperty: undefined };
}
var returnValueProperty;
var statements = ts.createNodeArray(ts.isBlock(body) ? body.statements.slice(0) : [ts.isStatement(body) ? body : ts.createReturn(body)]);
if (writes || substitutions.size) {
var rewrittenStatements = ts.visitNodes(statements, visitor).slice();
if (writes && !(range.facts & RangeFacts.HasReturn) && ts.isStatement(body)) {
var assignments = getPropertyAssignmentsForWrites(writes);
if (assignments.length === 1) {
rewrittenStatements.push(ts.createReturn(assignments[0].name));
}
else {
rewrittenStatements.push(ts.createReturn(ts.createObjectLiteral(assignments)));
}
var edits = changeTracker.getChanges();
var renameRange = isReadonlyArray(range.range) ? range.range[0] : range.range;
var renameFilename = renameRange.getSourceFile().fileName;
var renameLocation = getRenameLocation(edits, renameFilename, functionNameText);
return { renameFilename: renameFilename, renameLocation: renameLocation, edits: edits };
}
function getRenameLocation(edits, renameFilename, functionNameText) {
var delta = 0;
for (var _i = 0, edits_1 = edits; _i < edits_1.length; _i++) {
var _a = edits_1[_i], fileName = _a.fileName, textChanges_1 = _a.textChanges;
ts.Debug.assert(fileName === renameFilename);
for (var _b = 0, textChanges_2 = textChanges_1; _b < textChanges_2.length; _b++) {
var change = textChanges_2[_b];
var span_17 = change.span, newText = change.newText;
var index = newText.indexOf(functionNameText);
if (index !== -1) {
return span_17.start + delta + index;
}
return { body: ts.createBlock(rewrittenStatements, true), returnValueProperty: returnValueProperty };
delta += newText.length - span_17.length;
}
else {
return { body: ts.createBlock(statements, true), returnValueProperty: undefined };
}
function visitor(node) {
if (node.kind === 219 && writes) {
var assignments = getPropertyAssignmentsForWrites(writes);
if (node.expression) {
if (!returnValueProperty) {
returnValueProperty = generateReturnValueProperty();
}
assignments.unshift(ts.createPropertyAssignment(returnValueProperty, ts.visitNode(node.expression, visitor)));
}
if (assignments.length === 1) {
return ts.createReturn(assignments[0].name);
}
else {
return ts.createReturn(ts.createObjectLiteral(assignments));
}
}
throw new Error();
}
function getCalledExpression(scope, range, functionNameText) {
var functionReference = ts.createIdentifier(functionNameText);
if (ts.isClassLike(scope)) {
var lhs = range.facts & RangeFacts.InStaticRegion ? ts.createIdentifier(scope.name.text) : ts.createThis();
return ts.createPropertyAccess(lhs, functionReference);
}
else {
return functionReference;
}
}
function transformFunctionBody(body, writes, substitutions, hasReturn) {
if (ts.isBlock(body) && !writes && substitutions.size === 0) {
return { body: ts.createBlock(body.statements, true), returnValueProperty: undefined };
}
var returnValueProperty;
var statements = ts.createNodeArray(ts.isBlock(body) ? body.statements.slice(0) : [ts.isStatement(body) ? body : ts.createReturn(body)]);
if (writes || substitutions.size) {
var rewrittenStatements = ts.visitNodes(statements, visitor).slice();
if (writes && !hasReturn && ts.isStatement(body)) {
var assignments = getPropertyAssignmentsForWrites(writes);
if (assignments.length === 1) {
rewrittenStatements.push(ts.createReturn(assignments[0].name));
}
else {
var substitution = substitutions.get(ts.getNodeId(node).toString());
return substitution || ts.visitEachChild(node, visitor, ts.nullTransformationContext);
rewrittenStatements.push(ts.createReturn(ts.createObjectLiteral(assignments)));
}
}
return { body: ts.createBlock(rewrittenStatements, true), returnValueProperty: returnValueProperty };
}
else {
return { body: ts.createBlock(statements, true), returnValueProperty: undefined };
}
function visitor(node) {
if (node.kind === 219 && writes) {
var assignments = getPropertyAssignmentsForWrites(writes);
if (node.expression) {
if (!returnValueProperty) {
returnValueProperty = "__return";
}
assignments.unshift(ts.createPropertyAssignment(returnValueProperty, ts.visitNode(node.expression, visitor)));
}
if (assignments.length === 1) {
return ts.createReturn(assignments[0].name);
}
else {
return ts.createReturn(ts.createObjectLiteral(assignments));
}
}
else {
var substitution = substitutions.get(ts.getNodeId(node).toString());
return substitution || ts.visitEachChild(node, visitor, ts.nullTransformationContext);
}
}
}
extractMethod_1.extractFunctionInScope = extractFunctionInScope;
function isModuleBlock(n) {
return n.kind === 234;
function getPropertyAssignmentsForWrites(writes) {
return writes.map(function (w) { return ts.createShorthandPropertyAssignment(w.symbol.name); });
}
function isReadonlyArray(v) {
return ts.isArray(v);
@@ -81209,8 +81218,8 @@ var ts;
{ start: start, end: end, text: text, code: code, category: category, source: source };
}
function allEditsBeforePos(edits, pos) {
for (var _i = 0, edits_1 = edits; _i < edits_1.length; _i++) {
var edit = edits_1[_i];
for (var _i = 0, edits_2 = edits; _i < edits_2.length; _i++) {
var edit = edits_2[_i];
if (ts.textSpanEnd(edit.span) >= pos) {
return false;
}
@@ -82372,12 +82381,12 @@ var ts;
return undefined;
}
if (simplifiedResult) {
var span_17 = helpItems.applicableSpan;
var span_18 = helpItems.applicableSpan;
return {
items: helpItems.items,
applicableSpan: {
start: scriptInfo.positionToLineOffset(span_17.start),
end: scriptInfo.positionToLineOffset(span_17.start + span_17.length)
start: scriptInfo.positionToLineOffset(span_18.start),
end: scriptInfo.positionToLineOffset(span_18.start + span_18.length)
},
selectedItemIndex: helpItems.selectedItemIndex,
argumentIndex: helpItems.argumentIndex,
+2 -2
View File
@@ -3283,8 +3283,8 @@ declare namespace ts {
};
type RefactorEditInfo = {
edits: FileTextChanges[];
renameFilename?: string;
renameLocation?: number;
renameFilename: string | undefined;
renameLocation: number | undefined;
};
interface TextInsertion {
newText: string;
+115 -106
View File
@@ -12155,7 +12155,8 @@ var ts;
return token() === 24 ||
isIdentifierOrPattern() ||
ts.isModifierKind(token()) ||
token() === 57 || isStartOfType();
token() === 57 ||
isStartOfType(true);
}
function parseParameter() {
var node = createNode(146);
@@ -12494,7 +12495,7 @@ var ts;
return parseTypeReference();
}
}
function isStartOfType() {
function isStartOfType(inStartOfParameter) {
switch (token()) {
case 119:
case 136:
@@ -12521,9 +12522,9 @@ var ts;
case 39:
return true;
case 38:
return lookAhead(nextTokenIsNumericLiteral);
return !inStartOfParameter && lookAhead(nextTokenIsNumericLiteral);
case 19:
return lookAhead(isStartOfParenthesizedOrFunctionType);
return !inStartOfParameter && lookAhead(isStartOfParenthesizedOrFunctionType);
default:
return isIdentifier();
}
@@ -74425,7 +74426,9 @@ var ts;
deleteCallback();
}
return {
edits: changeTracker.getChanges()
edits: changeTracker.getChanges(),
renameFilename: undefined,
renameLocation: undefined,
};
function deleteNode(node, inList) {
if (inList === void 0) { inList = false; }
@@ -74576,11 +74579,11 @@ var ts;
var usedNames = ts.createMap();
var i = 0;
for (var _i = 0, extractions_1 = extractions; _i < extractions_1.length; _i++) {
var extr = extractions_1[_i];
if (extr.errors && extr.errors.length) {
var _a = extractions_1[_i], scopeDescription = _a.scopeDescription, errors = _a.errors;
if (errors.length) {
continue;
}
var description = ts.formatStringFromArgs(ts.Diagnostics.Extract_function_into_0.message, [extr.scopeDescription]);
var description = ts.formatStringFromArgs(ts.Diagnostics.Extract_function_into_0.message, [scopeDescription]);
if (!usedNames.has(description)) {
usedNames.set(description, true);
actions.push({
@@ -74608,9 +74611,7 @@ var ts;
ts.Debug.assert(!!parsedIndexMatch, "Scope name should have matched the regexp");
var index = +parsedIndexMatch[1];
ts.Debug.assert(isFinite(index), "Expected to parse a finite number from the scope index");
var extractions = getPossibleExtractions(targetRange, context, index);
ts.Debug.assert(extractions !== undefined, "The extraction went missing? How?");
return ({ edits: extractions[0].changes });
return getExtractionAtIndex(targetRange, context, index);
}
var Messages;
(function (Messages) {
@@ -74639,7 +74640,7 @@ var ts;
RangeFacts[RangeFacts["IsAsyncFunction"] = 4] = "IsAsyncFunction";
RangeFacts[RangeFacts["UsesThis"] = 8] = "UsesThis";
RangeFacts[RangeFacts["InStaticRegion"] = 16] = "InStaticRegion";
})(RangeFacts = extractMethod_1.RangeFacts || (extractMethod_1.RangeFacts = {}));
})(RangeFacts || (RangeFacts = {}));
function getRangeToExtract(sourceFile, span) {
var length = span.length || 0;
var start = getParentNodeInSpan(ts.getTokenAtPosition(sourceFile, span.start, false), sourceFile, span);
@@ -74879,7 +74880,7 @@ var ts;
return undefined;
}
function isValidExtractionTarget(node) {
return (node.kind === 228) || ts.isSourceFile(node) || isModuleBlock(node) || ts.isClassLike(node);
return (node.kind === 228) || ts.isSourceFile(node) || ts.isModuleBlock(node) || ts.isClassLike(node);
}
function collectEnclosingScopes(range) {
var current = isReadonlyArray(range.range) ? ts.firstOrUndefined(range.range) : range.range;
@@ -74904,9 +74905,21 @@ var ts;
}
return scopes;
}
extractMethod_1.collectEnclosingScopes = collectEnclosingScopes;
function getPossibleExtractions(targetRange, context, requestedChangesIndex) {
if (requestedChangesIndex === void 0) { requestedChangesIndex = undefined; }
function getExtractionAtIndex(targetRange, context, requestedChangesIndex) {
var _a = getPossibleExtractionsWorker(targetRange, context), scopes = _a.scopes, _b = _a.readsAndWrites, target = _b.target, usagesPerScope = _b.usagesPerScope, errorsPerScope = _b.errorsPerScope;
ts.Debug.assert(!errorsPerScope[requestedChangesIndex].length, "The extraction went missing? How?");
context.cancellationToken.throwIfCancellationRequested();
return extractFunctionInScope(target, scopes[requestedChangesIndex], usagesPerScope[requestedChangesIndex], targetRange, context);
}
extractMethod_1.getExtractionAtIndex = getExtractionAtIndex;
function getPossibleExtractions(targetRange, context) {
var extractions = getPossibleExtractionsWorker(targetRange, context);
return extractions && extractions.scopes.map(function (scope, i) {
return ({ scopeDescription: getDescriptionForScope(scope), errors: extractions.readsAndWrites.errorsPerScope[i] });
});
}
extractMethod_1.getPossibleExtractions = getPossibleExtractions;
function getPossibleExtractionsWorker(targetRange, context) {
var sourceFile = context.file;
if (targetRange === undefined) {
return undefined;
@@ -74916,29 +74929,9 @@ var ts;
return undefined;
}
var enclosingTextRange = getEnclosingTextRange(targetRange, sourceFile);
var _a = collectReadsAndWrites(targetRange, scopes, enclosingTextRange, sourceFile, context.program.getTypeChecker()), target = _a.target, usagesPerScope = _a.usagesPerScope, errorsPerScope = _a.errorsPerScope;
context.cancellationToken.throwIfCancellationRequested();
if (requestedChangesIndex !== undefined) {
if (errorsPerScope[requestedChangesIndex].length) {
return undefined;
}
return [extractFunctionInScope(target, scopes[requestedChangesIndex], usagesPerScope[requestedChangesIndex], targetRange, context)];
}
else {
return scopes.map(function (scope, i) {
var errors = errorsPerScope[i];
if (errors.length) {
return {
scope: scope,
scopeDescription: getDescriptionForScope(scope),
errors: errors
};
}
return { scope: scope, scopeDescription: getDescriptionForScope(scope) };
});
}
var readsAndWrites = collectReadsAndWrites(targetRange, scopes, enclosingTextRange, sourceFile, context.program.getTypeChecker());
return { scopes: scopes, readsAndWrites: readsAndWrites };
}
extractMethod_1.getPossibleExtractions = getPossibleExtractions;
function getDescriptionForScope(scope) {
if (ts.isFunctionLike(scope)) {
switch (scope.kind) {
@@ -74960,7 +74953,7 @@ var ts;
return "'set " + scope.name.getText() + "'";
}
}
else if (isModuleBlock(scope)) {
else if (ts.isModuleBlock(scope)) {
return "namespace '" + scope.parent.name.getText() + "'";
}
else if (ts.isClassLike(scope)) {
@@ -74977,14 +74970,10 @@ var ts;
return "unknown";
}
}
function getUniqueName(isNameOkay) {
function getUniqueName(fileText) {
var functionNameText = "newFunction";
if (isNameOkay(functionNameText)) {
return functionNameText;
}
var i = 1;
while (!isNameOkay(functionNameText = "newFunction_" + i)) {
i++;
for (var i = 1; fileText.indexOf(functionNameText) !== -1; i++) {
functionNameText = "newFunction_" + i;
}
return functionNameText;
}
@@ -74992,10 +74981,9 @@ var ts;
var usagesInScope = _a.usages, substitutions = _a.substitutions;
var checker = context.program.getTypeChecker();
var file = scope.getSourceFile();
var functionNameText = getUniqueName(function (n) { return !file.identifiers.has(n); });
var functionNameText = getUniqueName(file.text);
var isJS = ts.isInJavaScriptFile(scope);
var functionName = ts.createIdentifier(functionNameText);
var functionReference = ts.createIdentifier(functionNameText);
var returnType = undefined;
var parameters = [];
var callArguments = [];
@@ -75018,7 +75006,7 @@ var ts;
var contextualType = checker.getContextualType(node);
returnType = checker.typeToTypeNode(contextualType);
}
var _b = transformFunctionBody(node), body = _b.body, returnValueProperty = _b.returnValueProperty;
var _b = transformFunctionBody(node, writes, substitutions, !!(range.facts & RangeFacts.HasReturn)), body = _b.body, returnValueProperty = _b.returnValueProperty;
var newFunction;
if (ts.isClassLike(scope)) {
var modifiers = isJS ? [] : [ts.createToken(112)];
@@ -75036,7 +75024,8 @@ var ts;
var changeTracker = ts.textChanges.ChangeTracker.fromCodeFixContext(context);
changeTracker.insertNodeBefore(context.file, scope.getLastToken(), newFunction, { prefix: context.newLineCharacter, suffix: context.newLineCharacter });
var newNodes = [];
var call = ts.createCall(ts.isClassLike(scope) ? ts.createPropertyAccess(range.facts & RangeFacts.InStaticRegion ? ts.createIdentifier(scope.name.getText()) : ts.createThis(), functionReference) : functionReference, undefined, callArguments);
var called = getCalledExpression(scope, range, functionNameText);
var call = ts.createCall(called, undefined, callArguments);
if (range.facts & RangeFacts.IsGenerator) {
call = ts.createYield(ts.createToken(39), call);
}
@@ -75086,65 +75075,85 @@ var ts;
else {
changeTracker.replaceNodeWithNodes(context.file, range.range, newNodes, { nodeSeparator: context.newLineCharacter });
}
return {
scope: scope,
scopeDescription: getDescriptionForScope(scope),
changes: changeTracker.getChanges()
};
function getPropertyAssignmentsForWrites(writes) {
return writes.map(function (w) { return ts.createShorthandPropertyAssignment(w.symbol.name); });
}
function generateReturnValueProperty() {
return "__return";
}
function transformFunctionBody(body) {
if (ts.isBlock(body) && !writes && substitutions.size === 0) {
return { body: ts.createBlock(body.statements, true), returnValueProperty: undefined };
}
var returnValueProperty;
var statements = ts.createNodeArray(ts.isBlock(body) ? body.statements.slice(0) : [ts.isStatement(body) ? body : ts.createReturn(body)]);
if (writes || substitutions.size) {
var rewrittenStatements = ts.visitNodes(statements, visitor).slice();
if (writes && !(range.facts & RangeFacts.HasReturn) && ts.isStatement(body)) {
var assignments = getPropertyAssignmentsForWrites(writes);
if (assignments.length === 1) {
rewrittenStatements.push(ts.createReturn(assignments[0].name));
}
else {
rewrittenStatements.push(ts.createReturn(ts.createObjectLiteral(assignments)));
}
var edits = changeTracker.getChanges();
var renameRange = isReadonlyArray(range.range) ? range.range[0] : range.range;
var renameFilename = renameRange.getSourceFile().fileName;
var renameLocation = getRenameLocation(edits, renameFilename, functionNameText);
return { renameFilename: renameFilename, renameLocation: renameLocation, edits: edits };
}
function getRenameLocation(edits, renameFilename, functionNameText) {
var delta = 0;
for (var _i = 0, edits_1 = edits; _i < edits_1.length; _i++) {
var _a = edits_1[_i], fileName = _a.fileName, textChanges_1 = _a.textChanges;
ts.Debug.assert(fileName === renameFilename);
for (var _b = 0, textChanges_2 = textChanges_1; _b < textChanges_2.length; _b++) {
var change = textChanges_2[_b];
var span_17 = change.span, newText = change.newText;
var index = newText.indexOf(functionNameText);
if (index !== -1) {
return span_17.start + delta + index;
}
return { body: ts.createBlock(rewrittenStatements, true), returnValueProperty: returnValueProperty };
delta += newText.length - span_17.length;
}
else {
return { body: ts.createBlock(statements, true), returnValueProperty: undefined };
}
function visitor(node) {
if (node.kind === 219 && writes) {
var assignments = getPropertyAssignmentsForWrites(writes);
if (node.expression) {
if (!returnValueProperty) {
returnValueProperty = generateReturnValueProperty();
}
assignments.unshift(ts.createPropertyAssignment(returnValueProperty, ts.visitNode(node.expression, visitor)));
}
if (assignments.length === 1) {
return ts.createReturn(assignments[0].name);
}
else {
return ts.createReturn(ts.createObjectLiteral(assignments));
}
}
throw new Error();
}
function getCalledExpression(scope, range, functionNameText) {
var functionReference = ts.createIdentifier(functionNameText);
if (ts.isClassLike(scope)) {
var lhs = range.facts & RangeFacts.InStaticRegion ? ts.createIdentifier(scope.name.text) : ts.createThis();
return ts.createPropertyAccess(lhs, functionReference);
}
else {
return functionReference;
}
}
function transformFunctionBody(body, writes, substitutions, hasReturn) {
if (ts.isBlock(body) && !writes && substitutions.size === 0) {
return { body: ts.createBlock(body.statements, true), returnValueProperty: undefined };
}
var returnValueProperty;
var statements = ts.createNodeArray(ts.isBlock(body) ? body.statements.slice(0) : [ts.isStatement(body) ? body : ts.createReturn(body)]);
if (writes || substitutions.size) {
var rewrittenStatements = ts.visitNodes(statements, visitor).slice();
if (writes && !hasReturn && ts.isStatement(body)) {
var assignments = getPropertyAssignmentsForWrites(writes);
if (assignments.length === 1) {
rewrittenStatements.push(ts.createReturn(assignments[0].name));
}
else {
var substitution = substitutions.get(ts.getNodeId(node).toString());
return substitution || ts.visitEachChild(node, visitor, ts.nullTransformationContext);
rewrittenStatements.push(ts.createReturn(ts.createObjectLiteral(assignments)));
}
}
return { body: ts.createBlock(rewrittenStatements, true), returnValueProperty: returnValueProperty };
}
else {
return { body: ts.createBlock(statements, true), returnValueProperty: undefined };
}
function visitor(node) {
if (node.kind === 219 && writes) {
var assignments = getPropertyAssignmentsForWrites(writes);
if (node.expression) {
if (!returnValueProperty) {
returnValueProperty = "__return";
}
assignments.unshift(ts.createPropertyAssignment(returnValueProperty, ts.visitNode(node.expression, visitor)));
}
if (assignments.length === 1) {
return ts.createReturn(assignments[0].name);
}
else {
return ts.createReturn(ts.createObjectLiteral(assignments));
}
}
else {
var substitution = substitutions.get(ts.getNodeId(node).toString());
return substitution || ts.visitEachChild(node, visitor, ts.nullTransformationContext);
}
}
}
extractMethod_1.extractFunctionInScope = extractFunctionInScope;
function isModuleBlock(n) {
return n.kind === 234;
function getPropertyAssignmentsForWrites(writes) {
return writes.map(function (w) { return ts.createShorthandPropertyAssignment(w.symbol.name); });
}
function isReadonlyArray(v) {
return ts.isArray(v);
@@ -77374,8 +77383,8 @@ var ts;
{ start: start, end: end, text: text, code: code, category: category, source: source };
}
function allEditsBeforePos(edits, pos) {
for (var _i = 0, edits_1 = edits; _i < edits_1.length; _i++) {
var edit = edits_1[_i];
for (var _i = 0, edits_2 = edits; _i < edits_2.length; _i++) {
var edit = edits_2[_i];
if (ts.textSpanEnd(edit.span) >= pos) {
return false;
}
@@ -78537,12 +78546,12 @@ var ts;
return undefined;
}
if (simplifiedResult) {
var span_17 = helpItems.applicableSpan;
var span_18 = helpItems.applicableSpan;
return {
items: helpItems.items,
applicableSpan: {
start: scriptInfo.positionToLineOffset(span_17.start),
end: scriptInfo.positionToLineOffset(span_17.start + span_17.length)
start: scriptInfo.positionToLineOffset(span_18.start),
end: scriptInfo.positionToLineOffset(span_18.start + span_18.length)
},
selectedItemIndex: helpItems.selectedItemIndex,
argumentIndex: helpItems.argumentIndex,
+2 -2
View File
@@ -3935,8 +3935,8 @@ declare namespace ts {
*/
type RefactorEditInfo = {
edits: FileTextChanges[];
renameFilename?: string;
renameLocation?: number;
renameFilename: string | undefined;
renameLocation: number | undefined;
};
interface TextInsertion {
newText: string;
+125 -106
View File
@@ -13845,7 +13845,8 @@ var ts;
return token() === 24 /* DotDotDotToken */ ||
isIdentifierOrPattern() ||
ts.isModifierKind(token()) ||
token() === 57 /* AtToken */ || isStartOfType();
token() === 57 /* AtToken */ ||
isStartOfType(/*inStartOfParameter*/ true);
}
function parseParameter() {
var node = createNode(146 /* Parameter */);
@@ -14252,7 +14253,7 @@ var ts;
return parseTypeReference();
}
}
function isStartOfType() {
function isStartOfType(inStartOfParameter) {
switch (token()) {
case 119 /* AnyKeyword */:
case 136 /* StringKeyword */:
@@ -14279,11 +14280,11 @@ var ts;
case 39 /* AsteriskToken */:
return true;
case 38 /* MinusToken */:
return lookAhead(nextTokenIsNumericLiteral);
return !inStartOfParameter && lookAhead(nextTokenIsNumericLiteral);
case 19 /* OpenParenToken */:
// Only consider '(' the start of a type if followed by ')', '...', an identifier, a modifier,
// or something that starts a type. We don't want to consider things like '(1)' a type.
return lookAhead(isStartOfParenthesizedOrFunctionType);
return !inStartOfParameter && lookAhead(isStartOfParenthesizedOrFunctionType);
default:
return isIdentifier();
}
@@ -89385,7 +89386,9 @@ var ts;
deleteCallback();
}
return {
edits: changeTracker.getChanges()
edits: changeTracker.getChanges(),
renameFilename: undefined,
renameLocation: undefined,
};
function deleteNode(node, inList) {
if (inList === void 0) { inList = false; }
@@ -89561,15 +89564,15 @@ var ts;
var usedNames = ts.createMap();
var i = 0;
for (var _i = 0, extractions_1 = extractions; _i < extractions_1.length; _i++) {
var extr = extractions_1[_i];
var _a = extractions_1[_i], scopeDescription = _a.scopeDescription, errors = _a.errors;
// Skip these since we don't have a way to report errors yet
if (extr.errors && extr.errors.length) {
if (errors.length) {
continue;
}
// Don't issue refactorings with duplicated names.
// Scopes come back in "innermost first" order, so extractions will
// preferentially go into nearer scopes
var description = ts.formatStringFromArgs(ts.Diagnostics.Extract_function_into_0.message, [extr.scopeDescription]);
var description = ts.formatStringFromArgs(ts.Diagnostics.Extract_function_into_0.message, [scopeDescription]);
if (!usedNames.has(description)) {
usedNames.set(description, true);
actions.push({
@@ -89599,10 +89602,7 @@ var ts;
ts.Debug.assert(!!parsedIndexMatch, "Scope name should have matched the regexp");
var index = +parsedIndexMatch[1];
ts.Debug.assert(isFinite(index), "Expected to parse a finite number from the scope index");
var extractions = getPossibleExtractions(targetRange, context, index);
// Scope is no longer valid from when the user issued the refactor (??)
ts.Debug.assert(extractions !== undefined, "The extraction went missing? How?");
return ({ edits: extractions[0].changes });
return getExtractionAtIndex(targetRange, context, index);
}
// Move these into diagnostic messages if they become user-facing
var Messages;
@@ -89635,13 +89635,14 @@ var ts;
* The range is in a function which needs the 'static' modifier in a class
*/
RangeFacts[RangeFacts["InStaticRegion"] = 16] = "InStaticRegion";
})(RangeFacts = extractMethod_1.RangeFacts || (extractMethod_1.RangeFacts = {}));
})(RangeFacts || (RangeFacts = {}));
/**
* getRangeToExtract takes a span inside a text file and returns either an expression or an array
* of statements representing the minimum set of nodes needed to extract the entire span. This
* process may fail, in which case a set of errors is returned instead (these are currently
* not shown to the user, but can be used by us diagnostically)
*/
// exported only for tests
function getRangeToExtract(sourceFile, span) {
var length = span.length || 0;
// Walk up starting from the the start position until we find a non-SourceFile node that subsumes the selected span.
@@ -89927,7 +89928,7 @@ var ts;
}
function isValidExtractionTarget(node) {
// Note that we don't use isFunctionLike because we don't want to put the extracted closure *inside* a method
return (node.kind === 228 /* FunctionDeclaration */) || ts.isSourceFile(node) || isModuleBlock(node) || ts.isClassLike(node);
return (node.kind === 228 /* FunctionDeclaration */) || ts.isSourceFile(node) || ts.isModuleBlock(node) || ts.isClassLike(node);
}
/**
* Computes possible places we could extract the function into. For example,
@@ -89965,14 +89966,29 @@ var ts;
}
return scopes;
}
extractMethod_1.collectEnclosingScopes = collectEnclosingScopes;
// exported only for tests
function getExtractionAtIndex(targetRange, context, requestedChangesIndex) {
var _a = getPossibleExtractionsWorker(targetRange, context), scopes = _a.scopes, _b = _a.readsAndWrites, target = _b.target, usagesPerScope = _b.usagesPerScope, errorsPerScope = _b.errorsPerScope;
ts.Debug.assert(!errorsPerScope[requestedChangesIndex].length, "The extraction went missing? How?");
context.cancellationToken.throwIfCancellationRequested();
return extractFunctionInScope(target, scopes[requestedChangesIndex], usagesPerScope[requestedChangesIndex], targetRange, context);
}
extractMethod_1.getExtractionAtIndex = getExtractionAtIndex;
/**
* Given a piece of text to extract ('targetRange'), computes a list of possible extractions.
* Each returned ExtractResultForScope corresponds to a possible target scope and is either a set of changes
* or an error explaining why we can't extract into that scope.
*/
function getPossibleExtractions(targetRange, context, requestedChangesIndex) {
if (requestedChangesIndex === void 0) { requestedChangesIndex = undefined; }
// exported only for tests
function getPossibleExtractions(targetRange, context) {
var extractions = getPossibleExtractionsWorker(targetRange, context);
// Need the inner type annotation to avoid https://github.com/Microsoft/TypeScript/issues/7547
return extractions && extractions.scopes.map(function (scope, i) {
return ({ scopeDescription: getDescriptionForScope(scope), errors: extractions.readsAndWrites.errorsPerScope[i] });
});
}
extractMethod_1.getPossibleExtractions = getPossibleExtractions;
function getPossibleExtractionsWorker(targetRange, context) {
var sourceFile = context.file;
if (targetRange === undefined) {
return undefined;
@@ -89982,29 +89998,9 @@ var ts;
return undefined;
}
var enclosingTextRange = getEnclosingTextRange(targetRange, sourceFile);
var _a = collectReadsAndWrites(targetRange, scopes, enclosingTextRange, sourceFile, context.program.getTypeChecker()), target = _a.target, usagesPerScope = _a.usagesPerScope, errorsPerScope = _a.errorsPerScope;
context.cancellationToken.throwIfCancellationRequested();
if (requestedChangesIndex !== undefined) {
if (errorsPerScope[requestedChangesIndex].length) {
return undefined;
}
return [extractFunctionInScope(target, scopes[requestedChangesIndex], usagesPerScope[requestedChangesIndex], targetRange, context)];
}
else {
return scopes.map(function (scope, i) {
var errors = errorsPerScope[i];
if (errors.length) {
return {
scope: scope,
scopeDescription: getDescriptionForScope(scope),
errors: errors
};
}
return { scope: scope, scopeDescription: getDescriptionForScope(scope) };
});
}
var readsAndWrites = collectReadsAndWrites(targetRange, scopes, enclosingTextRange, sourceFile, context.program.getTypeChecker());
return { scopes: scopes, readsAndWrites: readsAndWrites };
}
extractMethod_1.getPossibleExtractions = getPossibleExtractions;
function getDescriptionForScope(scope) {
if (ts.isFunctionLike(scope)) {
switch (scope.kind) {
@@ -90026,7 +90022,7 @@ var ts;
return "'set " + scope.name.getText() + "'";
}
}
else if (isModuleBlock(scope)) {
else if (ts.isModuleBlock(scope)) {
return "namespace '" + scope.parent.name.getText() + "'";
}
else if (ts.isClassLike(scope)) {
@@ -90043,26 +90039,25 @@ var ts;
return "unknown";
}
}
function getUniqueName(isNameOkay) {
function getUniqueName(fileText) {
var functionNameText = "newFunction";
if (isNameOkay(functionNameText)) {
return functionNameText;
}
var i = 1;
while (!isNameOkay(functionNameText = "newFunction_" + i)) {
i++;
for (var i = 1; fileText.indexOf(functionNameText) !== -1; i++) {
functionNameText = "newFunction_" + i;
}
return functionNameText;
}
/**
* Result of 'extractRange' operation for a specific scope.
* Stores either a list of changes that should be applied to extract a range or a list of errors
*/
function extractFunctionInScope(node, scope, _a, range, context) {
var usagesInScope = _a.usages, substitutions = _a.substitutions;
var checker = context.program.getTypeChecker();
// Make a unique name for the extracted function
var file = scope.getSourceFile();
var functionNameText = getUniqueName(function (n) { return !file.identifiers.has(n); });
var functionNameText = getUniqueName(file.text);
var isJS = ts.isInJavaScriptFile(scope);
var functionName = ts.createIdentifier(functionNameText);
var functionReference = ts.createIdentifier(functionNameText);
var returnType = undefined;
var parameters = [];
var callArguments = [];
@@ -90093,7 +90088,7 @@ var ts;
var contextualType = checker.getContextualType(node);
returnType = checker.typeToTypeNode(contextualType);
}
var _b = transformFunctionBody(node), body = _b.body, returnValueProperty = _b.returnValueProperty;
var _b = transformFunctionBody(node, writes, substitutions, !!(range.facts & RangeFacts.HasReturn)), body = _b.body, returnValueProperty = _b.returnValueProperty;
var newFunction;
if (ts.isClassLike(scope)) {
// always create private method in TypeScript files
@@ -90119,7 +90114,8 @@ var ts;
changeTracker.insertNodeBefore(context.file, scope.getLastToken(), newFunction, { prefix: context.newLineCharacter, suffix: context.newLineCharacter });
var newNodes = [];
// replace range with function call
var call = ts.createCall(ts.isClassLike(scope) ? ts.createPropertyAccess(range.facts & RangeFacts.InStaticRegion ? ts.createIdentifier(scope.name.getText()) : ts.createThis(), functionReference) : functionReference,
var called = getCalledExpression(scope, range, functionNameText);
var call = ts.createCall(called,
/*typeArguments*/ undefined, callArguments);
if (range.facts & RangeFacts.IsGenerator) {
call = ts.createYield(ts.createToken(39 /* AsteriskToken */), call);
@@ -90176,69 +90172,92 @@ var ts;
else {
changeTracker.replaceNodeWithNodes(context.file, range.range, newNodes, { nodeSeparator: context.newLineCharacter });
}
return {
scope: scope,
scopeDescription: getDescriptionForScope(scope),
changes: changeTracker.getChanges()
};
function getPropertyAssignmentsForWrites(writes) {
return writes.map(function (w) { return ts.createShorthandPropertyAssignment(w.symbol.name); });
}
function generateReturnValueProperty() {
return "__return";
}
function transformFunctionBody(body) {
if (ts.isBlock(body) && !writes && substitutions.size === 0) {
// already block, no writes to propagate back, no substitutions - can use node as is
return { body: ts.createBlock(body.statements, /*multLine*/ true), returnValueProperty: undefined };
}
var returnValueProperty;
var statements = ts.createNodeArray(ts.isBlock(body) ? body.statements.slice(0) : [ts.isStatement(body) ? body : ts.createReturn(body)]);
// rewrite body if either there are writes that should be propagated back via return statements or there are substitutions
if (writes || substitutions.size) {
var rewrittenStatements = ts.visitNodes(statements, visitor).slice();
if (writes && !(range.facts & RangeFacts.HasReturn) && ts.isStatement(body)) {
// add return at the end to propagate writes back in case if control flow falls out of the function body
// it is ok to know that range has at least one return since it we only allow unconditional returns
var assignments = getPropertyAssignmentsForWrites(writes);
if (assignments.length === 1) {
rewrittenStatements.push(ts.createReturn(assignments[0].name));
}
else {
rewrittenStatements.push(ts.createReturn(ts.createObjectLiteral(assignments)));
}
var edits = changeTracker.getChanges();
var renameRange = isReadonlyArray(range.range) ? range.range[0] : range.range;
var renameFilename = renameRange.getSourceFile().fileName;
var renameLocation = getRenameLocation(edits, renameFilename, functionNameText);
return { renameFilename: renameFilename, renameLocation: renameLocation, edits: edits };
}
function getRenameLocation(edits, renameFilename, functionNameText) {
var delta = 0;
for (var _i = 0, edits_1 = edits; _i < edits_1.length; _i++) {
var _a = edits_1[_i], fileName = _a.fileName, textChanges_1 = _a.textChanges;
ts.Debug.assert(fileName === renameFilename);
for (var _b = 0, textChanges_2 = textChanges_1; _b < textChanges_2.length; _b++) {
var change = textChanges_2[_b];
var span_17 = change.span, newText = change.newText;
// TODO(acasey): We are assuming that the call expression comes before the function declaration,
// because we want the new cursor to be on the call expression,
// which is closer to where the user was before extracting the function.
var index = newText.indexOf(functionNameText);
if (index !== -1) {
return span_17.start + delta + index;
}
return { body: ts.createBlock(rewrittenStatements, /*multiLine*/ true), returnValueProperty: returnValueProperty };
delta += newText.length - span_17.length;
}
else {
return { body: ts.createBlock(statements, /*multiLine*/ true), returnValueProperty: undefined };
}
function visitor(node) {
if (node.kind === 219 /* ReturnStatement */ && writes) {
var assignments = getPropertyAssignmentsForWrites(writes);
if (node.expression) {
if (!returnValueProperty) {
returnValueProperty = generateReturnValueProperty();
}
assignments.unshift(ts.createPropertyAssignment(returnValueProperty, ts.visitNode(node.expression, visitor)));
}
if (assignments.length === 1) {
return ts.createReturn(assignments[0].name);
}
else {
return ts.createReturn(ts.createObjectLiteral(assignments));
}
}
throw new Error(); // Didn't find the text we inserted?
}
function getCalledExpression(scope, range, functionNameText) {
var functionReference = ts.createIdentifier(functionNameText);
if (ts.isClassLike(scope)) {
var lhs = range.facts & RangeFacts.InStaticRegion ? ts.createIdentifier(scope.name.text) : ts.createThis();
return ts.createPropertyAccess(lhs, functionReference);
}
else {
return functionReference;
}
}
function transformFunctionBody(body, writes, substitutions, hasReturn) {
if (ts.isBlock(body) && !writes && substitutions.size === 0) {
// already block, no writes to propagate back, no substitutions - can use node as is
return { body: ts.createBlock(body.statements, /*multLine*/ true), returnValueProperty: undefined };
}
var returnValueProperty;
var statements = ts.createNodeArray(ts.isBlock(body) ? body.statements.slice(0) : [ts.isStatement(body) ? body : ts.createReturn(body)]);
// rewrite body if either there are writes that should be propagated back via return statements or there are substitutions
if (writes || substitutions.size) {
var rewrittenStatements = ts.visitNodes(statements, visitor).slice();
if (writes && !hasReturn && ts.isStatement(body)) {
// add return at the end to propagate writes back in case if control flow falls out of the function body
// it is ok to know that range has at least one return since it we only allow unconditional returns
var assignments = getPropertyAssignmentsForWrites(writes);
if (assignments.length === 1) {
rewrittenStatements.push(ts.createReturn(assignments[0].name));
}
else {
var substitution = substitutions.get(ts.getNodeId(node).toString());
return substitution || ts.visitEachChild(node, visitor, ts.nullTransformationContext);
rewrittenStatements.push(ts.createReturn(ts.createObjectLiteral(assignments)));
}
}
return { body: ts.createBlock(rewrittenStatements, /*multiLine*/ true), returnValueProperty: returnValueProperty };
}
else {
return { body: ts.createBlock(statements, /*multiLine*/ true), returnValueProperty: undefined };
}
function visitor(node) {
if (node.kind === 219 /* ReturnStatement */ && writes) {
var assignments = getPropertyAssignmentsForWrites(writes);
if (node.expression) {
if (!returnValueProperty) {
returnValueProperty = "__return";
}
assignments.unshift(ts.createPropertyAssignment(returnValueProperty, ts.visitNode(node.expression, visitor)));
}
if (assignments.length === 1) {
return ts.createReturn(assignments[0].name);
}
else {
return ts.createReturn(ts.createObjectLiteral(assignments));
}
}
else {
var substitution = substitutions.get(ts.getNodeId(node).toString());
return substitution || ts.visitEachChild(node, visitor, ts.nullTransformationContext);
}
}
}
extractMethod_1.extractFunctionInScope = extractFunctionInScope;
function isModuleBlock(n) {
return n.kind === 234 /* ModuleBlock */;
function getPropertyAssignmentsForWrites(writes) {
return writes.map(function (w) { return ts.createShorthandPropertyAssignment(w.symbol.name); });
}
function isReadonlyArray(v) {
return ts.isArray(v);
+2 -2
View File
@@ -3935,8 +3935,8 @@ declare namespace ts {
*/
type RefactorEditInfo = {
edits: FileTextChanges[];
renameFilename?: string;
renameLocation?: number;
renameFilename: string | undefined;
renameLocation: number | undefined;
};
interface TextInsertion {
newText: string;
+125 -106
View File
@@ -13845,7 +13845,8 @@ var ts;
return token() === 24 /* DotDotDotToken */ ||
isIdentifierOrPattern() ||
ts.isModifierKind(token()) ||
token() === 57 /* AtToken */ || isStartOfType();
token() === 57 /* AtToken */ ||
isStartOfType(/*inStartOfParameter*/ true);
}
function parseParameter() {
var node = createNode(146 /* Parameter */);
@@ -14252,7 +14253,7 @@ var ts;
return parseTypeReference();
}
}
function isStartOfType() {
function isStartOfType(inStartOfParameter) {
switch (token()) {
case 119 /* AnyKeyword */:
case 136 /* StringKeyword */:
@@ -14279,11 +14280,11 @@ var ts;
case 39 /* AsteriskToken */:
return true;
case 38 /* MinusToken */:
return lookAhead(nextTokenIsNumericLiteral);
return !inStartOfParameter && lookAhead(nextTokenIsNumericLiteral);
case 19 /* OpenParenToken */:
// Only consider '(' the start of a type if followed by ')', '...', an identifier, a modifier,
// or something that starts a type. We don't want to consider things like '(1)' a type.
return lookAhead(isStartOfParenthesizedOrFunctionType);
return !inStartOfParameter && lookAhead(isStartOfParenthesizedOrFunctionType);
default:
return isIdentifier();
}
@@ -89385,7 +89386,9 @@ var ts;
deleteCallback();
}
return {
edits: changeTracker.getChanges()
edits: changeTracker.getChanges(),
renameFilename: undefined,
renameLocation: undefined,
};
function deleteNode(node, inList) {
if (inList === void 0) { inList = false; }
@@ -89561,15 +89564,15 @@ var ts;
var usedNames = ts.createMap();
var i = 0;
for (var _i = 0, extractions_1 = extractions; _i < extractions_1.length; _i++) {
var extr = extractions_1[_i];
var _a = extractions_1[_i], scopeDescription = _a.scopeDescription, errors = _a.errors;
// Skip these since we don't have a way to report errors yet
if (extr.errors && extr.errors.length) {
if (errors.length) {
continue;
}
// Don't issue refactorings with duplicated names.
// Scopes come back in "innermost first" order, so extractions will
// preferentially go into nearer scopes
var description = ts.formatStringFromArgs(ts.Diagnostics.Extract_function_into_0.message, [extr.scopeDescription]);
var description = ts.formatStringFromArgs(ts.Diagnostics.Extract_function_into_0.message, [scopeDescription]);
if (!usedNames.has(description)) {
usedNames.set(description, true);
actions.push({
@@ -89599,10 +89602,7 @@ var ts;
ts.Debug.assert(!!parsedIndexMatch, "Scope name should have matched the regexp");
var index = +parsedIndexMatch[1];
ts.Debug.assert(isFinite(index), "Expected to parse a finite number from the scope index");
var extractions = getPossibleExtractions(targetRange, context, index);
// Scope is no longer valid from when the user issued the refactor (??)
ts.Debug.assert(extractions !== undefined, "The extraction went missing? How?");
return ({ edits: extractions[0].changes });
return getExtractionAtIndex(targetRange, context, index);
}
// Move these into diagnostic messages if they become user-facing
var Messages;
@@ -89635,13 +89635,14 @@ var ts;
* The range is in a function which needs the 'static' modifier in a class
*/
RangeFacts[RangeFacts["InStaticRegion"] = 16] = "InStaticRegion";
})(RangeFacts = extractMethod_1.RangeFacts || (extractMethod_1.RangeFacts = {}));
})(RangeFacts || (RangeFacts = {}));
/**
* getRangeToExtract takes a span inside a text file and returns either an expression or an array
* of statements representing the minimum set of nodes needed to extract the entire span. This
* process may fail, in which case a set of errors is returned instead (these are currently
* not shown to the user, but can be used by us diagnostically)
*/
// exported only for tests
function getRangeToExtract(sourceFile, span) {
var length = span.length || 0;
// Walk up starting from the the start position until we find a non-SourceFile node that subsumes the selected span.
@@ -89927,7 +89928,7 @@ var ts;
}
function isValidExtractionTarget(node) {
// Note that we don't use isFunctionLike because we don't want to put the extracted closure *inside* a method
return (node.kind === 228 /* FunctionDeclaration */) || ts.isSourceFile(node) || isModuleBlock(node) || ts.isClassLike(node);
return (node.kind === 228 /* FunctionDeclaration */) || ts.isSourceFile(node) || ts.isModuleBlock(node) || ts.isClassLike(node);
}
/**
* Computes possible places we could extract the function into. For example,
@@ -89965,14 +89966,29 @@ var ts;
}
return scopes;
}
extractMethod_1.collectEnclosingScopes = collectEnclosingScopes;
// exported only for tests
function getExtractionAtIndex(targetRange, context, requestedChangesIndex) {
var _a = getPossibleExtractionsWorker(targetRange, context), scopes = _a.scopes, _b = _a.readsAndWrites, target = _b.target, usagesPerScope = _b.usagesPerScope, errorsPerScope = _b.errorsPerScope;
ts.Debug.assert(!errorsPerScope[requestedChangesIndex].length, "The extraction went missing? How?");
context.cancellationToken.throwIfCancellationRequested();
return extractFunctionInScope(target, scopes[requestedChangesIndex], usagesPerScope[requestedChangesIndex], targetRange, context);
}
extractMethod_1.getExtractionAtIndex = getExtractionAtIndex;
/**
* Given a piece of text to extract ('targetRange'), computes a list of possible extractions.
* Each returned ExtractResultForScope corresponds to a possible target scope and is either a set of changes
* or an error explaining why we can't extract into that scope.
*/
function getPossibleExtractions(targetRange, context, requestedChangesIndex) {
if (requestedChangesIndex === void 0) { requestedChangesIndex = undefined; }
// exported only for tests
function getPossibleExtractions(targetRange, context) {
var extractions = getPossibleExtractionsWorker(targetRange, context);
// Need the inner type annotation to avoid https://github.com/Microsoft/TypeScript/issues/7547
return extractions && extractions.scopes.map(function (scope, i) {
return ({ scopeDescription: getDescriptionForScope(scope), errors: extractions.readsAndWrites.errorsPerScope[i] });
});
}
extractMethod_1.getPossibleExtractions = getPossibleExtractions;
function getPossibleExtractionsWorker(targetRange, context) {
var sourceFile = context.file;
if (targetRange === undefined) {
return undefined;
@@ -89982,29 +89998,9 @@ var ts;
return undefined;
}
var enclosingTextRange = getEnclosingTextRange(targetRange, sourceFile);
var _a = collectReadsAndWrites(targetRange, scopes, enclosingTextRange, sourceFile, context.program.getTypeChecker()), target = _a.target, usagesPerScope = _a.usagesPerScope, errorsPerScope = _a.errorsPerScope;
context.cancellationToken.throwIfCancellationRequested();
if (requestedChangesIndex !== undefined) {
if (errorsPerScope[requestedChangesIndex].length) {
return undefined;
}
return [extractFunctionInScope(target, scopes[requestedChangesIndex], usagesPerScope[requestedChangesIndex], targetRange, context)];
}
else {
return scopes.map(function (scope, i) {
var errors = errorsPerScope[i];
if (errors.length) {
return {
scope: scope,
scopeDescription: getDescriptionForScope(scope),
errors: errors
};
}
return { scope: scope, scopeDescription: getDescriptionForScope(scope) };
});
}
var readsAndWrites = collectReadsAndWrites(targetRange, scopes, enclosingTextRange, sourceFile, context.program.getTypeChecker());
return { scopes: scopes, readsAndWrites: readsAndWrites };
}
extractMethod_1.getPossibleExtractions = getPossibleExtractions;
function getDescriptionForScope(scope) {
if (ts.isFunctionLike(scope)) {
switch (scope.kind) {
@@ -90026,7 +90022,7 @@ var ts;
return "'set " + scope.name.getText() + "'";
}
}
else if (isModuleBlock(scope)) {
else if (ts.isModuleBlock(scope)) {
return "namespace '" + scope.parent.name.getText() + "'";
}
else if (ts.isClassLike(scope)) {
@@ -90043,26 +90039,25 @@ var ts;
return "unknown";
}
}
function getUniqueName(isNameOkay) {
function getUniqueName(fileText) {
var functionNameText = "newFunction";
if (isNameOkay(functionNameText)) {
return functionNameText;
}
var i = 1;
while (!isNameOkay(functionNameText = "newFunction_" + i)) {
i++;
for (var i = 1; fileText.indexOf(functionNameText) !== -1; i++) {
functionNameText = "newFunction_" + i;
}
return functionNameText;
}
/**
* Result of 'extractRange' operation for a specific scope.
* Stores either a list of changes that should be applied to extract a range or a list of errors
*/
function extractFunctionInScope(node, scope, _a, range, context) {
var usagesInScope = _a.usages, substitutions = _a.substitutions;
var checker = context.program.getTypeChecker();
// Make a unique name for the extracted function
var file = scope.getSourceFile();
var functionNameText = getUniqueName(function (n) { return !file.identifiers.has(n); });
var functionNameText = getUniqueName(file.text);
var isJS = ts.isInJavaScriptFile(scope);
var functionName = ts.createIdentifier(functionNameText);
var functionReference = ts.createIdentifier(functionNameText);
var returnType = undefined;
var parameters = [];
var callArguments = [];
@@ -90093,7 +90088,7 @@ var ts;
var contextualType = checker.getContextualType(node);
returnType = checker.typeToTypeNode(contextualType);
}
var _b = transformFunctionBody(node), body = _b.body, returnValueProperty = _b.returnValueProperty;
var _b = transformFunctionBody(node, writes, substitutions, !!(range.facts & RangeFacts.HasReturn)), body = _b.body, returnValueProperty = _b.returnValueProperty;
var newFunction;
if (ts.isClassLike(scope)) {
// always create private method in TypeScript files
@@ -90119,7 +90114,8 @@ var ts;
changeTracker.insertNodeBefore(context.file, scope.getLastToken(), newFunction, { prefix: context.newLineCharacter, suffix: context.newLineCharacter });
var newNodes = [];
// replace range with function call
var call = ts.createCall(ts.isClassLike(scope) ? ts.createPropertyAccess(range.facts & RangeFacts.InStaticRegion ? ts.createIdentifier(scope.name.getText()) : ts.createThis(), functionReference) : functionReference,
var called = getCalledExpression(scope, range, functionNameText);
var call = ts.createCall(called,
/*typeArguments*/ undefined, callArguments);
if (range.facts & RangeFacts.IsGenerator) {
call = ts.createYield(ts.createToken(39 /* AsteriskToken */), call);
@@ -90176,69 +90172,92 @@ var ts;
else {
changeTracker.replaceNodeWithNodes(context.file, range.range, newNodes, { nodeSeparator: context.newLineCharacter });
}
return {
scope: scope,
scopeDescription: getDescriptionForScope(scope),
changes: changeTracker.getChanges()
};
function getPropertyAssignmentsForWrites(writes) {
return writes.map(function (w) { return ts.createShorthandPropertyAssignment(w.symbol.name); });
}
function generateReturnValueProperty() {
return "__return";
}
function transformFunctionBody(body) {
if (ts.isBlock(body) && !writes && substitutions.size === 0) {
// already block, no writes to propagate back, no substitutions - can use node as is
return { body: ts.createBlock(body.statements, /*multLine*/ true), returnValueProperty: undefined };
}
var returnValueProperty;
var statements = ts.createNodeArray(ts.isBlock(body) ? body.statements.slice(0) : [ts.isStatement(body) ? body : ts.createReturn(body)]);
// rewrite body if either there are writes that should be propagated back via return statements or there are substitutions
if (writes || substitutions.size) {
var rewrittenStatements = ts.visitNodes(statements, visitor).slice();
if (writes && !(range.facts & RangeFacts.HasReturn) && ts.isStatement(body)) {
// add return at the end to propagate writes back in case if control flow falls out of the function body
// it is ok to know that range has at least one return since it we only allow unconditional returns
var assignments = getPropertyAssignmentsForWrites(writes);
if (assignments.length === 1) {
rewrittenStatements.push(ts.createReturn(assignments[0].name));
}
else {
rewrittenStatements.push(ts.createReturn(ts.createObjectLiteral(assignments)));
}
var edits = changeTracker.getChanges();
var renameRange = isReadonlyArray(range.range) ? range.range[0] : range.range;
var renameFilename = renameRange.getSourceFile().fileName;
var renameLocation = getRenameLocation(edits, renameFilename, functionNameText);
return { renameFilename: renameFilename, renameLocation: renameLocation, edits: edits };
}
function getRenameLocation(edits, renameFilename, functionNameText) {
var delta = 0;
for (var _i = 0, edits_1 = edits; _i < edits_1.length; _i++) {
var _a = edits_1[_i], fileName = _a.fileName, textChanges_1 = _a.textChanges;
ts.Debug.assert(fileName === renameFilename);
for (var _b = 0, textChanges_2 = textChanges_1; _b < textChanges_2.length; _b++) {
var change = textChanges_2[_b];
var span_17 = change.span, newText = change.newText;
// TODO(acasey): We are assuming that the call expression comes before the function declaration,
// because we want the new cursor to be on the call expression,
// which is closer to where the user was before extracting the function.
var index = newText.indexOf(functionNameText);
if (index !== -1) {
return span_17.start + delta + index;
}
return { body: ts.createBlock(rewrittenStatements, /*multiLine*/ true), returnValueProperty: returnValueProperty };
delta += newText.length - span_17.length;
}
else {
return { body: ts.createBlock(statements, /*multiLine*/ true), returnValueProperty: undefined };
}
function visitor(node) {
if (node.kind === 219 /* ReturnStatement */ && writes) {
var assignments = getPropertyAssignmentsForWrites(writes);
if (node.expression) {
if (!returnValueProperty) {
returnValueProperty = generateReturnValueProperty();
}
assignments.unshift(ts.createPropertyAssignment(returnValueProperty, ts.visitNode(node.expression, visitor)));
}
if (assignments.length === 1) {
return ts.createReturn(assignments[0].name);
}
else {
return ts.createReturn(ts.createObjectLiteral(assignments));
}
}
throw new Error(); // Didn't find the text we inserted?
}
function getCalledExpression(scope, range, functionNameText) {
var functionReference = ts.createIdentifier(functionNameText);
if (ts.isClassLike(scope)) {
var lhs = range.facts & RangeFacts.InStaticRegion ? ts.createIdentifier(scope.name.text) : ts.createThis();
return ts.createPropertyAccess(lhs, functionReference);
}
else {
return functionReference;
}
}
function transformFunctionBody(body, writes, substitutions, hasReturn) {
if (ts.isBlock(body) && !writes && substitutions.size === 0) {
// already block, no writes to propagate back, no substitutions - can use node as is
return { body: ts.createBlock(body.statements, /*multLine*/ true), returnValueProperty: undefined };
}
var returnValueProperty;
var statements = ts.createNodeArray(ts.isBlock(body) ? body.statements.slice(0) : [ts.isStatement(body) ? body : ts.createReturn(body)]);
// rewrite body if either there are writes that should be propagated back via return statements or there are substitutions
if (writes || substitutions.size) {
var rewrittenStatements = ts.visitNodes(statements, visitor).slice();
if (writes && !hasReturn && ts.isStatement(body)) {
// add return at the end to propagate writes back in case if control flow falls out of the function body
// it is ok to know that range has at least one return since it we only allow unconditional returns
var assignments = getPropertyAssignmentsForWrites(writes);
if (assignments.length === 1) {
rewrittenStatements.push(ts.createReturn(assignments[0].name));
}
else {
var substitution = substitutions.get(ts.getNodeId(node).toString());
return substitution || ts.visitEachChild(node, visitor, ts.nullTransformationContext);
rewrittenStatements.push(ts.createReturn(ts.createObjectLiteral(assignments)));
}
}
return { body: ts.createBlock(rewrittenStatements, /*multiLine*/ true), returnValueProperty: returnValueProperty };
}
else {
return { body: ts.createBlock(statements, /*multiLine*/ true), returnValueProperty: undefined };
}
function visitor(node) {
if (node.kind === 219 /* ReturnStatement */ && writes) {
var assignments = getPropertyAssignmentsForWrites(writes);
if (node.expression) {
if (!returnValueProperty) {
returnValueProperty = "__return";
}
assignments.unshift(ts.createPropertyAssignment(returnValueProperty, ts.visitNode(node.expression, visitor)));
}
if (assignments.length === 1) {
return ts.createReturn(assignments[0].name);
}
else {
return ts.createReturn(ts.createObjectLiteral(assignments));
}
}
else {
var substitution = substitutions.get(ts.getNodeId(node).toString());
return substitution || ts.visitEachChild(node, visitor, ts.nullTransformationContext);
}
}
}
extractMethod_1.extractFunctionInScope = extractFunctionInScope;
function isModuleBlock(n) {
return n.kind === 234 /* ModuleBlock */;
function getPropertyAssignmentsForWrites(writes) {
return writes.map(function (w) { return ts.createShorthandPropertyAssignment(w.symbol.name); });
}
function isReadonlyArray(v) {
return ts.isArray(v);
+5 -4
View File
@@ -11098,7 +11098,8 @@ var ts;
return token() === 24 ||
isIdentifierOrPattern() ||
ts.isModifierKind(token()) ||
token() === 57 || isStartOfType();
token() === 57 ||
isStartOfType(true);
}
function parseParameter() {
var node = createNode(146);
@@ -11437,7 +11438,7 @@ var ts;
return parseTypeReference();
}
}
function isStartOfType() {
function isStartOfType(inStartOfParameter) {
switch (token()) {
case 119:
case 136:
@@ -11464,9 +11465,9 @@ var ts;
case 39:
return true;
case 38:
return lookAhead(nextTokenIsNumericLiteral);
return !inStartOfParameter && lookAhead(nextTokenIsNumericLiteral);
case 19:
return lookAhead(isStartOfParenthesizedOrFunctionType);
return !inStartOfParameter && lookAhead(isStartOfParenthesizedOrFunctionType);
default:
return isIdentifier();
}