Skip to content

Commit

Permalink
Merge pull request #1144 from kyasbal-1994/master
Browse files Browse the repository at this point in the history
Improve import quickfix
  • Loading branch information
guncha committed Dec 15, 2016
2 parents 8db97ee + dae3038 commit cdf4c60
Show file tree
Hide file tree
Showing 9 changed files with 167 additions and 13 deletions.
2 changes: 2 additions & 0 deletions dist/main/lang/fixmyts/quickFixRegistry.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"use strict";
var addClassMember_1 = require("./quickFixes/addClassMember");
var addClassMethod_1 = require("./quickFixes/addClassMethod");
var addImportDefaultStatement_1 = require("./quickFixes/addImportDefaultStatement");
var addImportFromStatement_1 = require("./quickFixes/addImportFromStatement");
var addImportStatement_1 = require("./quickFixes/addImportStatement");
var equalsToEquals_1 = require("./quickFixes/equalsToEquals");
Expand All @@ -16,6 +17,7 @@ var singleLineCommentToJsdoc_1 = require("./quickFixes/singleLineCommentToJsdoc"
exports.allQuickFixes = [
new addClassMethod_1.AddClassMethod(),
new addClassMember_1.AddClassMember(),
new addImportDefaultStatement_1.AddImportDefaultStatement(),
new addImportFromStatement_1.AddImportFromStatement(),
new addImportStatement_1.AddImportStatement(),
new wrapInProperty_1.WrapInProperty(),
Expand Down
58 changes: 58 additions & 0 deletions dist/main/lang/fixmyts/quickFixes/addImportDefaultStatement.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"use strict";
var os_1 = require("os");
var displayPartsToString = ts.displayPartsToString, typeToDisplayParts = ts.typeToDisplayParts;
var getPathCompletions_1 = require("../../modules/getPathCompletions");
function getIdentifierAndFileNames(error, project) {
var errorText = error.messageText;
if (typeof errorText !== 'string') {
return undefined;
}
;
var match = errorText.match(/Cannot find name \'(\w+)\'./);
if (!match)
return;
var identifierName = match[1];
var files = getPathCompletions_1.getPathCompletions({
project: project,
filePath: error.file.fileName,
prefix: identifierName,
includeExternalModules: false
}).files;
var file = files.length > 0 ? files[0].relativePath : undefined;
var basename = files.length > 0 ? files[0].name : undefined;
return { identifierName: identifierName, file: file, basename: basename };
}
var AddImportDefaultStatement = (function () {
function AddImportDefaultStatement() {
this.key = AddImportDefaultStatement.name;
}
AddImportDefaultStatement.prototype.canProvideFix = function (info) {
var relevantError = info.positionErrors.filter(function (x) { return x.code == 2304; })[0];
if (!relevantError)
return;
if (info.positionNode.kind !== ts.SyntaxKind.Identifier)
return;
var matches = getIdentifierAndFileNames(relevantError, info.project);
if (!matches)
return;
var identifierName = matches.identifierName, file = matches.file;
return file ? { display: "import " + identifierName + " from \"" + file + "\"" } : undefined;
};
AddImportDefaultStatement.prototype.provideFix = function (info) {
var relevantError = info.positionErrors.filter(function (x) { return x.code == 2304; })[0];
var identifier = info.positionNode;
var identifierName = identifier.text;
var fileNameforFix = getIdentifierAndFileNames(relevantError, info.project);
var refactorings = [{
span: {
start: 0,
length: 0
},
newText: "import " + identifierName + " from \"" + fileNameforFix.file + "\";" + os_1.EOL,
filePath: info.sourceFile.fileName
}];
return refactorings;
};
return AddImportDefaultStatement;
}());
exports.AddImportDefaultStatement = AddImportDefaultStatement;
7 changes: 6 additions & 1 deletion dist/main/lang/modules/getPathCompletions.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ function getExternalModuleNames(program) {
});
return entries;
}
function formatImportPath(sourcePath) {
sourcePath = sourcePath.replace(/\.d$/, "");
sourcePath = sourcePath.replace(/.*\/node_modules\//, "");
return sourcePath;
}
function getPathCompletions(query) {
var project = query.project;
var sourceDir = path.dirname(query.filePath);
Expand All @@ -30,7 +35,7 @@ function getPathCompletions(query) {
filePaths.forEach(function (p) {
files.push({
name: path.basename(p, '.ts'),
relativePath: tsconfig.removeExt(tsconfig.makeRelativePath(sourceDir, p)),
relativePath: formatImportPath(tsconfig.removeExt(tsconfig.makeRelativePath(sourceDir, p))),
fullPath: p
});
});
Expand Down
4 changes: 3 additions & 1 deletion lib/main/lang/fixmyts/quickFixRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {QuickFix} from "./quickFix";
*/
import {AddClassMember} from "./quickFixes/addClassMember";
import {AddClassMethod} from "./quickFixes/addClassMethod";
import {AddImportDefaultStatement} from "./quickFixes/addImportDefaultStatement";
import {AddImportFromStatement} from "./quickFixes/addImportFromStatement";
import {AddImportStatement} from "./quickFixes/addImportStatement";
import {EqualsToEquals} from "./quickFixes/equalsToEquals";
Expand All @@ -19,6 +20,7 @@ import {SingleLineCommentToJsdoc} from "./quickFixes/singleLineCommentToJsdoc";
export var allQuickFixes: QuickFix[] = [
new AddClassMethod(),
new AddClassMember(),
new AddImportDefaultStatement(),
new AddImportFromStatement(),
new AddImportStatement(),
new WrapInProperty(),
Expand All @@ -31,4 +33,4 @@ export var allQuickFixes: QuickFix[] = [
new TypeAssertPropertyAccessToType(),
new ImplementInterface(),
new SingleLineCommentToJsdoc()
];
];
82 changes: 82 additions & 0 deletions lib/main/lang/fixmyts/quickFixes/addImportDefaultStatement.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import {QuickFix, QuickFixQueryInformation, Refactoring, CanProvideFixResponse} from "../quickFix";
import * as ast from "../astUtils";
import {EOL } from "os";
var { displayPartsToString, typeToDisplayParts } = ts;
import path = require('path');
import {Project} from "../../core/project";

import {getPathCompletions} from "../../modules/getPathCompletions";

function getIdentifierAndFileNames(error: ts.Diagnostic, project: Project) {

var errorText: string = <any>error.messageText;

// We don't support error chains yet
if (typeof errorText !== 'string') {
return undefined;
};

var match = errorText.match(/Cannot find name \'(\w+)\'./);

// If for whatever reason the error message doesn't match
if (!match) return;

var [, identifierName] = match;
var {files} = getPathCompletions({
project,
filePath: error.file.fileName,
prefix: identifierName,
includeExternalModules: false
});
var file = files.length > 0 ? files[0].relativePath : undefined;
var basename = files.length > 0 ? files[0].name : undefined;
return { identifierName, file, basename };
}

export class AddImportDefaultStatement implements QuickFix {
key = AddImportDefaultStatement.name;

canProvideFix(info: QuickFixQueryInformation): CanProvideFixResponse {
var relevantError = info.positionErrors.filter(x => x.code == 2304)[0];
if (!relevantError) return;
if (info.positionNode.kind !== ts.SyntaxKind.Identifier) return;
var matches = getIdentifierAndFileNames(relevantError, info.project);
if (!matches) return;
var { identifierName, file} = matches;
return file ? { display: `import ${identifierName} from \"${file}\"` } : undefined;
}

provideFix(info: QuickFixQueryInformation): Refactoring[] {
var relevantError = info.positionErrors.filter(x => x.code == 2304)[0];
var identifier = <ts.Identifier>info.positionNode;

var identifierName = identifier.text;
var fileNameforFix = getIdentifierAndFileNames(relevantError, info.project);
// Add stuff at the top of the file
let refactorings: Refactoring[] = [{
span: {
start: 0,
length: 0
},
newText: `import ${identifierName} from \"${fileNameforFix.file}\";${EOL}`,
filePath: info.sourceFile.fileName
}];

// Also refactor the variable name to match the file name
// TODO: the following code only takes into account location
// There may be other locations where this is used.
// Better that they trigger a *rename* explicitly later if they want to rename the variable
// if (identifierName !== fileNameforFix.basename) {
// refactorings.push({
// span: {
// start: identifier.getStart(),
// length: identifier.end - identifier.getStart()
// },
// newText: fileNameforFix.basename,
// filePath: info.srcFile.fileName
// })
// }

return refactorings;
}
}
6 changes: 2 additions & 4 deletions lib/main/lang/fixmyts/quickFixes/addImportFromStatement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,23 +37,21 @@ export class AddImportFromStatement implements QuickFix {
key = AddImportFromStatement.name;

canProvideFix(info: QuickFixQueryInformation): CanProvideFixResponse {
var relevantError = info.positionErrors.filter(x=> x.code == 2304)[0];
var relevantError = info.positionErrors.filter(x => x.code == 2304)[0];
if (!relevantError) return;
if (info.positionNode.kind !== ts.SyntaxKind.Identifier) return;
var matches = getIdentifierAndFileNames(relevantError, info.project);
if (!matches) return;

var { identifierName, file} = matches;
return file ? { display: `import {${identifierName}} from \"${file}\"` } : undefined;
}

provideFix(info: QuickFixQueryInformation): Refactoring[] {
var relevantError = info.positionErrors.filter(x=> x.code == 2304)[0];
var relevantError = info.positionErrors.filter(x => x.code == 2304)[0];
var identifier = <ts.Identifier>info.positionNode;

var identifierName = identifier.text;
var fileNameforFix = getIdentifierAndFileNames(relevantError, info.project);

// Add stuff at the top of the file
let refactorings: Refactoring[] = [{
span: {
Expand Down
4 changes: 2 additions & 2 deletions lib/main/lang/fixmyts/quickFixes/addImportStatement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export class AddImportStatement implements QuickFix {
key = AddImportStatement.name;

canProvideFix(info: QuickFixQueryInformation): CanProvideFixResponse {
var relevantError = info.positionErrors.filter(x=> x.code == 2304)[0];
var relevantError = info.positionErrors.filter(x => x.code == 2304)[0];
if (!relevantError) return;
if (info.positionNode.kind !== ts.SyntaxKind.Identifier) return;
var matches = getIdentifierAndFileNames(relevantError, info.project);
Expand All @@ -48,7 +48,7 @@ export class AddImportStatement implements QuickFix {
}

provideFix(info: QuickFixQueryInformation): Refactoring[] {
var relevantError = info.positionErrors.filter(x=> x.code == 2304)[0];
var relevantError = info.positionErrors.filter(x => x.code == 2304)[0];
var identifier = <ts.Identifier>info.positionNode;

var identifierName = identifier.text;
Expand Down
16 changes: 11 additions & 5 deletions lib/main/lang/modules/getPathCompletions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ function getExternalModuleNames(program: ts.Program): string[] {
return entries;
}

function formatImportPath(sourcePath: string): string {
sourcePath = sourcePath.replace(/\.d$/, ""); // tsconfig.removeExt can convert d.ts file path into the filepath end with `.d`;
sourcePath = sourcePath.replace(/.*\/node_modules\//, "");
return sourcePath;
}

export interface GetRelativePathsInProjectResponse {
files: {
name: string;
Expand All @@ -40,7 +46,7 @@ export interface GetPathCompletions {
export function getPathCompletions(query: GetPathCompletions): GetRelativePathsInProjectResponse {
var project = query.project;
var sourceDir = path.dirname(query.filePath);
var filePaths = project.projectFile.project.files.filter(p=> p !== query.filePath);
var filePaths = project.projectFile.project.files.filter(p => p !== query.filePath);
var files: {
name: string;
relativePath: string;
Expand All @@ -49,17 +55,17 @@ export function getPathCompletions(query: GetPathCompletions): GetRelativePathsI

if (query.includeExternalModules) {
var externalModules = getExternalModuleNames(project.languageService.getProgram());
externalModules.forEach(e=> files.push({
externalModules.forEach(e => files.push({
name: `${e}`,
relativePath: e,
fullPath: e
}));
}

filePaths.forEach(p=> {
filePaths.forEach(p => {
files.push({
name: path.basename(p, '.ts'),
relativePath: tsconfig.removeExt(tsconfig.makeRelativePath(sourceDir, p)),
relativePath: formatImportPath(tsconfig.removeExt(tsconfig.makeRelativePath(sourceDir, p))),
fullPath: p
});
});
Expand All @@ -75,4 +81,4 @@ export function getPathCompletions(query: GetPathCompletions): GetRelativePathsI
};

return response;
}
}
1 change: 1 addition & 0 deletions lib/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
"./main/lang/fixmyts/quickFix.ts",
"./main/lang/fixmyts/quickFixes/addClassMember.ts",
"./main/lang/fixmyts/quickFixes/addClassMethod.ts",
"./main/lang/fixmyts/quickFixes/addImportDefaultStatement.ts",
"./main/lang/fixmyts/quickFixes/addImportFromStatement.ts",
"./main/lang/fixmyts/quickFixes/addImportStatement.ts",
"./main/lang/fixmyts/quickFixes/equalsToEquals.ts",
Expand Down

0 comments on commit cdf4c60

Please sign in to comment.