Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d4bb267

Browse filesBrowse files
committed
add insertNodeInListAfter functionality
1 parent e7e1ac9 commit d4bb267
Copy full SHA for d4bb267

28 files changed

+580-125Lines changed: 580 additions & 125 deletions
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎src/harness/unittests/textChanges.ts‎

Copy file name to clipboardExpand all lines: src/harness/unittests/textChanges.ts
+153-19Lines changed: 153 additions & 19 deletions
Large diffs are not rendered by default.
Collapse file

‎src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts‎

Copy file name to clipboardExpand all lines: src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ namespace ts.codefix {
2727
}
2828
}
2929
const changeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
30-
changeTracker.insertNodeAfter(sourceFile, getOpenBrace(<ConstructorDeclaration>constructor, sourceFile), superCall, { insertTrailingNewLine: true });
30+
changeTracker.insertNodeAfter(sourceFile, getOpenBrace(<ConstructorDeclaration>constructor, sourceFile), superCall, { suffix: context.newLineCharacter });
3131
changeTracker.deleteNode(sourceFile, superCall);
3232

3333
return [{
Collapse file

‎src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts‎

Copy file name to clipboardExpand all lines: src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace ts.codefix {
1212

1313
const changeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
1414
const superCall = createStatement(createCall(createSuper(), /*typeArguments*/ undefined, /*argumentsArray*/ emptyArray));
15-
changeTracker.insertNodeAfter(sourceFile, getOpenBrace(<ConstructorDeclaration>token.parent, sourceFile), superCall, { insertTrailingNewLine: true });
15+
changeTracker.insertNodeAfter(sourceFile, getOpenBrace(<ConstructorDeclaration>token.parent, sourceFile), superCall, { suffix: context.newLineCharacter });
1616

1717
return [{
1818
description: getLocaleSpecificMessage(Diagnostics.Add_missing_super_call),
Collapse file

‎src/services/codefixes/importFixes.ts‎

Copy file name to clipboardExpand all lines: src/services/codefixes/importFixes.ts
+42-61Lines changed: 42 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -130,22 +130,22 @@ namespace ts.codefix {
130130

131131
// this is a module id -> module import declaration map
132132
const cachedImportDeclarations: (ImportDeclaration | ImportEqualsDeclaration)[][] = [];
133-
let cachedNewImportInsertPosition: number;
133+
let lastImportDeclaration: Node;
134134

135135
const currentTokenMeaning = getMeaningFromLocation(token);
136136
if (context.errorCode === Diagnostics._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead.code) {
137137
const symbol = checker.getAliasedSymbol(checker.getSymbolAtLocation(token));
138138
return getCodeActionForImport(symbol, /*isDefault*/ false, /*isNamespaceImport*/ true);
139139
}
140140

141-
const allPotentialModules = checker.getAmbientModules();
141+
const candidateModules = checker.getAmbientModules();
142142
for (const otherSourceFile of allSourceFiles) {
143143
if (otherSourceFile !== sourceFile && isExternalOrCommonJsModule(otherSourceFile)) {
144-
allPotentialModules.push(otherSourceFile.symbol);
144+
candidateModules.push(otherSourceFile.symbol);
145145
}
146146
}
147147

148-
for (const moduleSymbol of allPotentialModules) {
148+
for (const moduleSymbol of candidateModules) {
149149
context.cancellationToken.throwIfCancellationRequested();
150150

151151
// check the default export
@@ -277,14 +277,12 @@ namespace ts.codefix {
277277
* If the existing import declaration already has a named import list, just
278278
* insert the identifier into that list.
279279
*/
280-
const textChange = getTextChangeForImportClause(namedImportDeclaration.importClause);
280+
const fileTextChanges = getTextChangeForImportClause(namedImportDeclaration.importClause);
281281
const moduleSpecifierWithoutQuotes = stripQuotes(namedImportDeclaration.moduleSpecifier.getText());
282282
actions.push(createCodeAction(
283283
Diagnostics.Add_0_to_existing_import_declaration_from_1,
284284
[name, moduleSpecifierWithoutQuotes],
285-
textChange.newText,
286-
textChange.span,
287-
sourceFile.fileName,
285+
fileTextChanges,
288286
"InsertingIntoExistingImport",
289287
moduleSpecifierWithoutQuotes
290288
));
@@ -302,49 +300,31 @@ namespace ts.codefix {
302300
return declaration.moduleReference.getText();
303301
}
304302

305-
function getTextChangeForImportClause(importClause: ImportClause): TextChange {
306-
const newImportText = isDefault ? `default as ${name}` : name;
303+
function getTextChangeForImportClause(importClause: ImportClause): FileTextChanges[] {
304+
//const newImportText = isDefault ? `default as ${name}` : name;
307305
const importList = <NamedImports>importClause.namedBindings;
306+
const newImportSpecifier = createImportSpecifier(/*propertyName*/ undefined, createIdentifier(name));
308307
// case 1:
309308
// original text: import default from "module"
310309
// change to: import default, { name } from "module"
311-
if (!importList && importClause.name) {
312-
const start = importClause.name.getEnd();
313-
return {
314-
newText: `, { ${newImportText} }`,
315-
span: { start, length: 0 }
316-
};
317-
}
318-
319310
// case 2:
320311
// original text: import {} from "module"
321312
// change to: import { name } from "module"
322-
if (importList.elements.length === 0) {
323-
const start = importList.getStart();
324-
return {
325-
newText: `{ ${newImportText} }`,
326-
span: { start, length: importList.getEnd() - start }
327-
};
313+
if (!importList || importList.elements.length === 0) {
314+
const newImportClause = createImportClause(importClause.name, createNamedImports([newImportSpecifier]));
315+
return createChangeTracker().replaceNode(sourceFile, importClause, newImportClause).getChanges();
328316
}
329317

330-
// case 3:
331-
// original text: import { foo, bar } from "module"
332-
// change to: import { foo, bar, name } from "module"
333-
const insertPoint = importList.elements[importList.elements.length - 1].getEnd();
334318
/**
335319
* If the import list has one import per line, preserve that. Otherwise, insert on same line as last element
336320
* import {
337321
* foo
338322
* } from "./module";
339323
*/
340-
const startLine = getLineOfLocalPosition(sourceFile, importList.getStart());
341-
const endLine = getLineOfLocalPosition(sourceFile, importList.getEnd());
342-
const oneImportPerLine = endLine - startLine > importList.elements.length;
343-
344-
return {
345-
newText: `,${oneImportPerLine ? context.newLineCharacter : " "}${newImportText}`,
346-
span: { start: insertPoint, length: 0 }
347-
};
324+
return createChangeTracker().insertNodeInListAfter(
325+
sourceFile,
326+
importList.elements[importList.elements.length - 1],
327+
newImportSpecifier).getChanges();
348328
}
349329

350330
function getCodeActionForNamespaceImport(declaration: ImportDeclaration | ImportEqualsDeclaration): ImportCodeAction {
@@ -370,48 +350,47 @@ namespace ts.codefix {
370350
return createCodeAction(
371351
Diagnostics.Change_0_to_1,
372352
[name, `${namespacePrefix}.${name}`],
373-
`${namespacePrefix}.`,
374-
{ start: token.getStart(), length: 0 },
375-
sourceFile.fileName,
353+
createChangeTracker().replaceNode(sourceFile, token, createPropertyAccess(createIdentifier(namespacePrefix), name)).getChanges(),
376354
"CodeChange"
377355
);
378356
}
379357
}
380358

381359
function getCodeActionForNewImport(moduleSpecifier?: string): ImportCodeAction {
382-
if (!cachedNewImportInsertPosition) {
360+
if (!lastImportDeclaration) {
383361
// insert after any existing imports
384-
let lastModuleSpecifierEnd = -1;
385-
for (const moduleSpecifier of sourceFile.imports) {
386-
const end = moduleSpecifier.getEnd();
387-
if (!lastModuleSpecifierEnd || end > lastModuleSpecifierEnd) {
388-
lastModuleSpecifierEnd = end;
362+
for (let i = sourceFile.statements.length - 1; i >= 0; i--) {
363+
const statement = sourceFile.statements[i];
364+
if (statement.kind === SyntaxKind.ImportEqualsDeclaration || statement.kind === SyntaxKind.ImportDeclaration) {
365+
lastImportDeclaration = statement;
366+
break;
389367
}
390368
}
391-
cachedNewImportInsertPosition = lastModuleSpecifierEnd > 0 ? sourceFile.getLineEndOfPosition(lastModuleSpecifierEnd) : sourceFile.getStart();
392369
}
393370

394371
const getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
395372
const moduleSpecifierWithoutQuotes = stripQuotes(moduleSpecifier || getModuleSpecifierForNewImport());
396-
const importStatementText = isDefault
397-
? `import ${name} from "${moduleSpecifierWithoutQuotes}"`
373+
const changeTracker = createChangeTracker();
374+
const importClause = isDefault
375+
? createImportClause(createIdentifier(name), /*namedBindings*/ undefined)
398376
: isNamespaceImport
399-
? `import * as ${name} from "${moduleSpecifierWithoutQuotes}"`
400-
: `import { ${name} } from "${moduleSpecifierWithoutQuotes}"`;
377+
? createImportClause(/*name*/ undefined, createNamespaceImport(createIdentifier(name)))
378+
: createImportClause(/*name*/ undefined, createNamedImports([createImportSpecifier(/*propertyName*/ undefined, createIdentifier(name))]));
379+
const importDecl = createImportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, importClause, createLiteral(moduleSpecifierWithoutQuotes));
380+
if (!lastImportDeclaration) {
381+
changeTracker.insertNodeAt(sourceFile, sourceFile.getStart(), importDecl, { suffix: `${context.newLineCharacter}${context.newLineCharacter}` });
382+
}
383+
else {
384+
changeTracker.insertNodeAfter(sourceFile, lastImportDeclaration, importDecl, { suffix: context.newLineCharacter });
385+
}
401386

402387
// if this file doesn't have any import statements, insert an import statement and then insert a new line
403388
// between the only import statement and user code. Otherwise just insert the statement because chances
404389
// are there are already a new line seperating code and import statements.
405-
const newText = cachedNewImportInsertPosition === sourceFile.getStart()
406-
? `${importStatementText};${context.newLineCharacter}${context.newLineCharacter}`
407-
: `${context.newLineCharacter}${importStatementText};`;
408-
409390
return createCodeAction(
410391
Diagnostics.Import_0_from_1,
411392
[name, `"${moduleSpecifierWithoutQuotes}"`],
412-
newText,
413-
{ start: cachedNewImportInsertPosition, length: 0 },
414-
sourceFile.fileName,
393+
changeTracker.getChanges(),
415394
"NewImport",
416395
moduleSpecifierWithoutQuotes
417396
);
@@ -576,17 +555,19 @@ namespace ts.codefix {
576555

577556
}
578557

558+
function createChangeTracker() {
559+
return textChanges.ChangeTracker.fromCodeFixContext(context);;
560+
}
561+
579562
function createCodeAction(
580563
description: DiagnosticMessage,
581564
diagnosticArgs: string[],
582-
newText: string,
583-
span: TextSpan,
584-
fileName: string,
565+
changes: FileTextChanges[],
585566
kind: ImportCodeActionKind,
586567
moduleSpecifier?: string): ImportCodeAction {
587568
return {
588569
description: formatMessage.apply(undefined, [undefined, description].concat(<any[]>diagnosticArgs)),
589-
changes: [{ fileName, textChanges: [{ newText, span }] }],
570+
changes,
590571
kind,
591572
moduleSpecifier
592573
};
Collapse file

‎src/services/codefixes/unusedIdentifierFixes.ts‎

Copy file name to clipboardExpand all lines: src/services/codefixes/unusedIdentifierFixes.ts
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ namespace ts.codefix {
132132
else {
133133
const previousToken = getTokenAtPosition(sourceFile, namespaceImport.pos - 1);
134134
if (previousToken && previousToken.kind === SyntaxKind.CommaToken) {
135-
const startPosition = textChanges.getAdjustedStartPosition(sourceFile, previousToken, {}, /*forDeleteOperation*/ true);
135+
const startPosition = textChanges.getAdjustedStartPosition(sourceFile, previousToken, {}, textChanges.Position.FullStart);
136136
return deleteRange({ pos: startPosition, end: namespaceImport.end });
137137
}
138138
return deleteRange(namespaceImport);
Collapse file

‎src/services/formatting/formattingScanner.ts‎

Copy file name to clipboardExpand all lines: src/services/formatting/formattingScanner.ts
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -276,8 +276,8 @@ namespace ts.formatting {
276276
function isOnToken(): boolean {
277277
Debug.assert(scanner !== undefined);
278278

279-
const current = (lastTokenInfo && lastTokenInfo.token.kind) || scanner.getToken();
280-
const startPos = (lastTokenInfo && lastTokenInfo.token.pos) || scanner.getStartPos();
279+
const current = lastTokenInfo ? lastTokenInfo.token.kind : scanner.getToken();
280+
const startPos = lastTokenInfo ? lastTokenInfo.token.pos : scanner.getStartPos();
281281
return startPos < endPos && current !== SyntaxKind.EndOfFileToken && !isTrivia(current);
282282
}
283283

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.