diff --git a/dist/main/lang/fixmyts/quickFixRegistry.js b/dist/main/lang/fixmyts/quickFixRegistry.js index 1d514f597..ab1c36edb 100644 --- a/dist/main/lang/fixmyts/quickFixRegistry.js +++ b/dist/main/lang/fixmyts/quickFixRegistry.js @@ -1,6 +1,7 @@ "use strict"; var addClassMember_1 = require("./quickFixes/addClassMember"); var addClassMethod_1 = require("./quickFixes/addClassMethod"); +var addImportFromStatement_1 = require("./quickFixes/addImportFromStatement"); var addImportStatement_1 = require("./quickFixes/addImportStatement"); var equalsToEquals_1 = require("./quickFixes/equalsToEquals"); var extractVariable_1 = require("./quickFixes/extractVariable"); @@ -15,6 +16,7 @@ var singleLineCommentToJsdoc_1 = require("./quickFixes/singleLineCommentToJsdoc" exports.allQuickFixes = [ new addClassMethod_1.AddClassMethod(), new addClassMember_1.AddClassMember(), + new addImportFromStatement_1.AddImportFromStatement(), new addImportStatement_1.AddImportStatement(), new wrapInProperty_1.WrapInProperty(), new equalsToEquals_1.EqualsToEquals(), diff --git a/dist/main/lang/fixmyts/quickFixes/addImportFromStatement.js b/dist/main/lang/fixmyts/quickFixes/addImportFromStatement.js new file mode 100644 index 000000000..f9c705327 --- /dev/null +++ b/dist/main/lang/fixmyts/quickFixes/addImportFromStatement.js @@ -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 AddImportFromStatement = (function () { + function AddImportFromStatement() { + this.key = AddImportFromStatement.name; + } + AddImportFromStatement.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; + }; + AddImportFromStatement.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 AddImportFromStatement; +})(); +exports.AddImportFromStatement = AddImportFromStatement; diff --git a/lib/main/lang/fixmyts/quickFixRegistry.ts b/lib/main/lang/fixmyts/quickFixRegistry.ts index eb2f04f56..d81ec89f6 100644 --- a/lib/main/lang/fixmyts/quickFixRegistry.ts +++ b/lib/main/lang/fixmyts/quickFixRegistry.ts @@ -4,6 +4,7 @@ import {QuickFix} from "./quickFix"; */ import {AddClassMember} from "./quickFixes/addClassMember"; import {AddClassMethod} from "./quickFixes/addClassMethod"; +import {AddImportFromStatement} from "./quickFixes/addImportFromStatement"; import {AddImportStatement} from "./quickFixes/addImportStatement"; import {EqualsToEquals} from "./quickFixes/equalsToEquals"; import {ExtractVariable} from "./quickFixes/extractVariable"; @@ -18,6 +19,7 @@ import {SingleLineCommentToJsdoc} from "./quickFixes/singleLineCommentToJsdoc"; export var allQuickFixes: QuickFix[] = [ new AddClassMethod(), new AddClassMember(), + new AddImportFromStatement(), new AddImportStatement(), new WrapInProperty(), new EqualsToEquals(), diff --git a/lib/main/lang/fixmyts/quickFixes/addImportFromStatement.ts b/lib/main/lang/fixmyts/quickFixes/addImportFromStatement.ts new file mode 100644 index 000000000..b9ce35671 --- /dev/null +++ b/lib/main/lang/fixmyts/quickFixes/addImportFromStatement.ts @@ -0,0 +1,84 @@ +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 = 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 AddImportFromStatement implements QuickFix { + key = AddImportFromStatement.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 = 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; + } +} diff --git a/lib/tsconfig.json b/lib/tsconfig.json index 52712d822..bc01d87bd 100644 --- a/lib/tsconfig.json +++ b/lib/tsconfig.json @@ -68,6 +68,7 @@ "./main/lang/fixmyts/quickFix.ts", "./main/lang/fixmyts/quickFixes/addClassMember.ts", "./main/lang/fixmyts/quickFixes/addClassMethod.ts", + "./main/lang/fixmyts/quickFixes/addImportFromStatement.ts", "./main/lang/fixmyts/quickFixes/addImportStatement.ts", "./main/lang/fixmyts/quickFixes/equalsToEquals.ts", "./main/lang/fixmyts/quickFixes/extractVariable.ts",