From ca96b60a701007e2bd5e118dc65039112d37b6ec Mon Sep 17 00:00:00 2001
From: Justin Schwartzenberger <schwarty@gmail.com>
Date: Mon, 21 Dec 2015 23:25:12 -0800
Subject: [PATCH 1/2] add new quick fix class for import from

---
 dist/main/lang/fixmyts/quickFixRegistry.js    |  2 +
 .../quickFixes/addImportFromStatement.js      | 58 +++++++++++++
 lib/main/lang/fixmyts/quickFixRegistry.ts     |  2 +
 .../quickFixes/addImportFromStatement.ts      | 84 +++++++++++++++++++
 lib/tsconfig.json                             |  4 +-
 5 files changed, 148 insertions(+), 2 deletions(-)
 create mode 100644 dist/main/lang/fixmyts/quickFixes/addImportFromStatement.js
 create mode 100644 lib/main/lang/fixmyts/quickFixes/addImportFromStatement.ts

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 = <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 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 = <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;
+    }
+}
diff --git a/lib/tsconfig.json b/lib/tsconfig.json
index 52712d822..7942b05c6 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",
@@ -128,8 +129,7 @@
         "./worker/parent.ts",
         "./worker/queryParent.ts",
         "./main/atom/views/rView.tsx",
-        "./main/atom/views/semanticView.tsx",
-        "../typings/main.d.ts"
+        "./main/atom/views/semanticView.tsx"
     ],
     "exclude": [],
     "atom": {

From 2412c5c4c8a7caacbc566324df1fcb042e144e7f Mon Sep 17 00:00:00 2001
From: Justin Schwartzenberger <schwarty@gmail.com>
Date: Mon, 21 Dec 2015 23:44:17 -0800
Subject: [PATCH 2/2] fix missing typings/main.d.ts

---
 lib/tsconfig.json | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lib/tsconfig.json b/lib/tsconfig.json
index 7942b05c6..bc01d87bd 100644
--- a/lib/tsconfig.json
+++ b/lib/tsconfig.json
@@ -129,7 +129,8 @@
         "./worker/parent.ts",
         "./worker/queryParent.ts",
         "./main/atom/views/rView.tsx",
-        "./main/atom/views/semanticView.tsx"
+        "./main/atom/views/semanticView.tsx",
+        "../typings/main.d.ts"
     ],
     "exclude": [],
     "atom": {