Merge branch 'master' into createTypeNode

This commit is contained in:
Arthur Ozga 2017-03-15 13:06:35 -07:00
commit a4b981af16
10 changed files with 203 additions and 6 deletions

View file

@ -709,5 +709,83 @@ class A {
changeTracker.deleteNode(sourceFile, findChild("x", sourceFile));
});
}
{
const text = `
class A {
x = foo
}
`
runSingleFileTest("insertNodeInClassAfterNodeWithoutSeparator1", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
const newNode = createProperty(
/*decorators*/ undefined,
/*modifiers*/ undefined,
createComputedPropertyName(createLiteral(1)),
/*questionToken*/ undefined,
createKeywordTypeNode(SyntaxKind.AnyKeyword),
/*initializer*/ undefined);
changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode, { suffix: newLineCharacter });
});
}
{
const text = `
class A {
x() {
}
}
`
runSingleFileTest("insertNodeInClassAfterNodeWithoutSeparator2", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
const newNode = createProperty(
/*decorators*/ undefined,
/*modifiers*/ undefined,
createComputedPropertyName(createLiteral(1)),
/*questionToken*/ undefined,
createKeywordTypeNode(SyntaxKind.AnyKeyword),
/*initializer*/ undefined);
changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode, { suffix: newLineCharacter });
});
}
{
const text = `
interface A {
x
}
`
runSingleFileTest("insertNodeInInterfaceAfterNodeWithoutSeparator1", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
const newNode = createProperty(
/*decorators*/ undefined,
/*modifiers*/ undefined,
createComputedPropertyName(createLiteral(1)),
/*questionToken*/ undefined,
createKeywordTypeNode(SyntaxKind.AnyKeyword),
/*initializer*/ undefined);
changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode, { suffix: newLineCharacter });
});
}
{
const text = `
interface A {
x()
}
`
runSingleFileTest("insertNodeInInterfaceAfterNodeWithoutSeparator2", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
const newNode = createProperty(
/*decorators*/ undefined,
/*modifiers*/ undefined,
createComputedPropertyName(createLiteral(1)),
/*questionToken*/ undefined,
createKeywordTypeNode(SyntaxKind.AnyKeyword),
/*initializer*/ undefined);
changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode, { suffix: newLineCharacter });
});
}
{
const text = `
let x = foo
`
runSingleFileTest("insertNodeInStatementListAfterNodeWithoutSeparator1", noop, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
const newNode = createStatement(createParen(createLiteral(1)));
changeTracker.insertNodeAfter(sourceFile, findVariableStatementContaining("x", sourceFile), newNode, { suffix: newLineCharacter });
});
}
});
}

View file

@ -5,9 +5,53 @@ interface DOMTokenList {
}
interface NodeList {
/**
* Returns an array of key, value pairs for every entry in the list
*/
entries(): IterableIterator<[number, Node]>;
/**
* Performs the specified action for each node in an list.
* @param callbackfn A function that accepts up to three arguments. forEach calls the callbackfn function one time for each element in the list.
* @param thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
*/
forEach(callbackfn: (value: Node, index: number, listObj: NodeList) => void, thisArg?: any): void;
/**
* Returns an list of keys in the list
*/
keys(): IterableIterator<number>;
/**
* Returns an list of values in the list
*/
values(): IterableIterator<Node>;
[Symbol.iterator](): IterableIterator<Node>
}
interface NodeListOf<TNode extends Node> {
/**
* Returns an array of key, value pairs for every entry in the list
*/
entries(): IterableIterator<[number, TNode]>;
/**
* Performs the specified action for each node in an list.
* @param callbackfn A function that accepts up to three arguments. forEach calls the callbackfn function one time for each element in the list.
* @param thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
*/
forEach(callbackfn: (value: TNode, index: number, listObj: NodeListOf<TNode>) => void, thisArg?: any): void;
/**
* Returns an list of keys in the list
*/
keys(): IterableIterator<number>;
/**
* Returns an list of values in the list
*/
values(): IterableIterator<TNode>;
[Symbol.iterator](): IterableIterator<TNode>
}

View file

@ -253,11 +253,31 @@ namespace ts.textChanges {
}
public insertNodeAfter(sourceFile: SourceFile, after: Node, newNode: Node, options: InsertNodeOptions & ConfigurableEnd = {}) {
if ((isStatementButNotDeclaration(after)) ||
after.kind === SyntaxKind.PropertyDeclaration ||
after.kind === SyntaxKind.PropertySignature ||
after.kind === SyntaxKind.MethodSignature) {
// check if previous statement ends with semicolon
// if not - insert semicolon to preserve the code from changing the meaning due to ASI
if (sourceFile.text.charCodeAt(after.end - 1) !== CharacterCodes.semicolon) {
this.changes.push({
sourceFile,
options: {},
range: { pos: after.end, end: after.end },
node: createToken(SyntaxKind.SemicolonToken)
})
}
}
const endPosition = getAdjustedEndPosition(sourceFile, after, options);
this.changes.push({ sourceFile, options, useIndentationFromFile: true, node: newNode, range: { pos: endPosition, end: endPosition } });
return this;
}
/**
* This function should be used to insert nodes in lists when nodes don't carry separators as the part of the node range,
* i.e. arguments in arguments lists, parameters in parameter lists etc. Statements or class elements are different in sense that
* for them separators are treated as the part of the node.
*/
public insertNodeInListAfter(sourceFile: SourceFile, after: Node, newNode: Node) {
const containingList = formatting.SmartIndenter.getContainingList(after, sourceFile);
if (!containingList) {
@ -463,10 +483,7 @@ namespace ts.textChanges {
private static normalize(changes: Change[]) {
// order changes by start position
const normalized = changes
.map((c, i) => ({ c, i }))
.sort(({ c: a, i: i1 }, { c: b, i: i2 }) => (a.range.pos - b.range.pos) || i1 - i2)
.map(({ c }) => c);
const normalized = stableSort(changes, (a, b) => a.range.pos - b.range.pos);
// verify that end position of the change is less than start position of the next change
for (let i = 0; i < normalized.length - 2; i++) {
Debug.assert(normalized[i].range.end <= normalized[i + 1].range.pos);

View file

@ -1384,7 +1384,7 @@ namespace ts {
// First token is the open curly, this is where we want to put the 'super' call.
return constructor.body.getFirstToken(sourceFile);
}
export function getOpenBraceOfClassLike(declaration: ClassLikeDeclaration, sourceFile: SourceFile) {
return getTokenAtPosition(sourceFile, declaration.members.pos - 1);
}

View file

@ -7,6 +7,6 @@ class A {
===MODIFIED===
class A {
x
x;
a: boolean;
}

View file

@ -0,0 +1,12 @@
===ORIGINAL===
class A {
x = foo
}
===MODIFIED===
class A {
x = foo;
[1]: any;
}

View file

@ -0,0 +1,14 @@
===ORIGINAL===
class A {
x() {
}
}
===MODIFIED===
class A {
x() {
}
[1]: any;
}

View file

@ -0,0 +1,12 @@
===ORIGINAL===
interface A {
x
}
===MODIFIED===
interface A {
x;
[1]: any;
}

View file

@ -0,0 +1,12 @@
===ORIGINAL===
interface A {
x()
}
===MODIFIED===
interface A {
x();
[1]: any;
}

View file

@ -0,0 +1,8 @@
===ORIGINAL===
let x = foo
===MODIFIED===
let x = foo;
(1);