Web Inspector: Add infrastructure for eslint based static analyzer
authorjonowells@apple.com <jonowells@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 11 Nov 2014 00:39:11 +0000 (00:39 +0000)
committerjonowells@apple.com <jonowells@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 11 Nov 2014 00:39:11 +0000 (00:39 +0000)
https://bugs.webkit.org/show_bug.cgi?id=137890

Reviewed by Timothy Hatcher.

Fix to previous patch to add AnalyzerManager and AnalyzerMessage classes. Changed Main.html to include ESLint.js
before Main.js in the combined resources.

* UserInterface/Base/Main.js:
* UserInterface/Controllers/AnalyzerManager.js: Added.
(WebInspector.AnalyzerManager):
(set WebInspector.AnalyzerManager.prototype.getAnalyzerMessagesForSourceCode.):
(set WebInspector.AnalyzerManager.prototype.getAnalyzerMessagesForSourceCode):
(set WebInspector.AnalyzerManager.prototype.set get sourceCodeCanBeAnalyzed):
(set WebInspector.AnalyzerManager.prototype._handleSourceCodeContentDidChange):
* UserInterface/Main.html:
* UserInterface/Models/AnalyzerMessage.js: Added.
(WebInspector.AnalyzerMessage):
(WebInspector.AnalyzerMessage.prototype.get sourceCodeLocation):
(WebInspector.AnalyzerMessage.prototype.get sourceCode):
(WebInspector.AnalyzerMessage.prototype.get text):
(WebInspector.AnalyzerMessage.prototype.get ruleIdentifier):
* UserInterface/Models/SourceCode.js:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@175838 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Base/Main.js
Source/WebInspectorUI/UserInterface/Controllers/AnalyzerManager.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Main.html
Source/WebInspectorUI/UserInterface/Models/AnalyzerMessage.js [new file with mode: 0644]
Source/WebInspectorUI/UserInterface/Models/SourceCode.js

index ba9bfb1..531ba56 100644 (file)
@@ -1,3 +1,29 @@
+2014-11-10  Jonathan Wells  <jonowells@apple.com>
+
+        Web Inspector: Add infrastructure for eslint based static analyzer
+        https://bugs.webkit.org/show_bug.cgi?id=137890
+
+        Reviewed by Timothy Hatcher.
+
+        Fix to previous patch to add AnalyzerManager and AnalyzerMessage classes. Changed Main.html to include ESLint.js
+        before Main.js in the combined resources.
+
+        * UserInterface/Base/Main.js:
+        * UserInterface/Controllers/AnalyzerManager.js: Added.
+        (WebInspector.AnalyzerManager):
+        (set WebInspector.AnalyzerManager.prototype.getAnalyzerMessagesForSourceCode.):
+        (set WebInspector.AnalyzerManager.prototype.getAnalyzerMessagesForSourceCode):
+        (set WebInspector.AnalyzerManager.prototype.set get sourceCodeCanBeAnalyzed):
+        (set WebInspector.AnalyzerManager.prototype._handleSourceCodeContentDidChange):
+        * UserInterface/Main.html:
+        * UserInterface/Models/AnalyzerMessage.js: Added.
+        (WebInspector.AnalyzerMessage):
+        (WebInspector.AnalyzerMessage.prototype.get sourceCodeLocation):
+        (WebInspector.AnalyzerMessage.prototype.get sourceCode):
+        (WebInspector.AnalyzerMessage.prototype.get text):
+        (WebInspector.AnalyzerMessage.prototype.get ruleIdentifier):
+        * UserInterface/Models/SourceCode.js:
+
 2014-11-08  Matt Baker  <mattbaker@apple.com>
 
         Web Inspector: decouple child element folderization logic from FrameTreeElement
index 8b9457d..443027c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -100,6 +100,7 @@ WebInspector.loaded = function()
     this.cssStyleManager = new WebInspector.CSSStyleManager;
     this.logManager = new WebInspector.LogManager;
     this.issueManager = new WebInspector.IssueManager;
+    this.analyzerManager = new WebInspector.AnalyzerManager;
     this.runtimeManager = new WebInspector.RuntimeManager;
     this.applicationCacheManager = new WebInspector.ApplicationCacheManager;
     this.timelineManager = new WebInspector.TimelineManager;
diff --git a/Source/WebInspectorUI/UserInterface/Controllers/AnalyzerManager.js b/Source/WebInspectorUI/UserInterface/Controllers/AnalyzerManager.js
new file mode 100644 (file)
index 0000000..9638bff
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.AnalyzerManager = function()
+{
+    WebInspector.Object.call(this);
+
+    this._eslintConfig = {
+        env: {
+            "browser": true,
+            "node": false
+        },
+        globals: {
+            "document": true
+        },
+        rules: {
+            "consistent-return": 2,
+            "curly": 0,
+            "eqeqeq": 0,
+            "new-parens": 0,
+            "no-comma-dangle": 0,
+            "no-console": 0,
+            "no-constant-condition": 0,
+            "no-extra-bind": 2,
+            "no-extra-semi": 2,
+            "no-proto": 0,
+            "no-return-assign": 2,
+            "no-trailing-spaces": 2,
+            "no-underscore-dangle": 0,
+            "no-unused-expressions": 2,
+            "no-wrap-func": 2,
+            "semi": 2,
+            "space-infix-ops": 2,
+            "space-return-throw-case": 2,
+            "strict": 0,
+            "valid-typeof": 2
+        }
+    };
+
+    this._sourceCodeMessagesMap = new WeakMap;
+
+    WebInspector.SourceCode.addEventListener(WebInspector.SourceCode.Event.ContentDidChange, this._handleSourceCodeContentDidChange, this);
+};
+
+WebInspector.AnalyzerManager._typeAnalyzerMap = new Map;
+WebInspector.AnalyzerManager._typeAnalyzerMap.set(WebInspector.Resource.Type.Script, eslint);
+
+WebInspector.AnalyzerManager.prototype = {
+    constructor: WebInspector.AnalyzerManager,
+    __proto__: WebInspector.Object.prototype,
+
+    // Public
+
+    getAnalyzerMessagesForSourceCode: function(sourceCode)
+    {
+        return new Promise(function(resolve, reject) {
+            var analyzer = WebInspector.AnalyzerManager._typeAnalyzerMap.get(sourceCode.type);
+            if (!analyzer) {
+                reject(new Error("This resource type cannot be analyzed."));
+                return;
+            }
+
+            if (this._sourceCodeMessagesMap.has(sourceCode)) {
+                resolve(this._sourceCodeMessagesMap.get(sourceCode));
+                return;
+            }
+
+            function retrieveAnalyzerMessages()
+            {
+                var analyzerMessages = [];
+                var rawAnalyzerMessages = analyzer.verify(sourceCode.content, this._eslintConfig);
+
+                // Raw line and column numbers are one-based. SourceCodeLocation expects them to be zero-based so we subtract 1 from each.
+                for (var rawAnalyzerMessage of rawAnalyzerMessages)
+                    analyzerMessages.push(new WebInspector.AnalyzerMessage(new WebInspector.SourceCodeLocation(sourceCode, rawAnalyzerMessage.line - 1, rawAnalyzerMessage.column - 1), rawAnalyzerMessage.message, rawAnalyzerMessage.ruleId));
+
+                this._sourceCodeMessagesMap.set(sourceCode, analyzerMessages);
+
+                resolve(analyzerMessages);
+            }
+
+            sourceCode.requestContent(retrieveAnalyzerMessages.bind(this));
+        }.bind(this));
+    },
+
+    sourceCodeCanBeAnalyzed: function(sourceCode)
+    {
+        return sourceCode.type === WebInspector.Resource.Type.Script;
+    },
+
+    // Private
+
+    _handleSourceCodeContentDidChange: function(event)
+    {
+        var sourceCode = event.target;
+
+        // Since sourceCode has changed, remove it and its messages from the map so getAnalyzerMessagesForSourceCode will have to reanalyze the next time it is called.
+        this._sourceCodeMessagesMap.delete(sourceCode);
+    }
+};
index b9729e9..bf7e36c 100644 (file)
     <script src="External/CodeMirror/sql.js"></script>
     <script src="External/CodeMirror/xml.js"></script>
 
+    <script src="External/ESLint/eslint.js"></script>
+
     <script src="Base/WebInspector.js"></script>
     <script src="Protocol/InspectorFrontendHostStub.js"></script>
     <script src="Base/Platform.js"></script>
     <script src="Models/Timeline.js"></script>
     <script src="Models/TimelineRecord.js"></script>
 
+    <script src="Models/AnalyzerMessage.js"></script>
     <script src="Models/ApplicationCacheFrame.js"></script>
     <script src="Models/ApplicationCacheManifest.js"></script>
     <script src="Models/BackForwardEntry.js"></script>
 
     <script src="Controllers/CodeMirrorEditingController.js"></script>
 
+    <script src="Controllers/AnalyzerManager.js"></script>
     <script src="Controllers/ApplicationCacheManager.js"></script>
     <script src="Controllers/BranchManager.js"></script>
     <script src="Controllers/CSSStyleManager.js"></script>
diff --git a/Source/WebInspectorUI/UserInterface/Models/AnalyzerMessage.js b/Source/WebInspectorUI/UserInterface/Models/AnalyzerMessage.js
new file mode 100644 (file)
index 0000000..e305567
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.AnalyzerMessage = function(sourceCodeLocation, text, ruleIdentifier)
+{
+    WebInspector.Object.call(this);
+
+    console.assert(sourceCodeLocation instanceof WebInspector.SourceCodeLocation);
+    console.assert(typeof text === "string");
+
+    this._sourceCodeLocation = sourceCodeLocation;
+    this._text = text;
+    this._ruleIdentifier = ruleIdentifier;
+};
+
+WebInspector.AnalyzerMessage.prototype = {
+    constructor: WebInspector.AnalyzerMessage,
+    __proto__: WebInspector.Object.prototype,
+
+    get sourceCodeLocation()
+    {
+        return this._sourceCodeLocation;
+    },
+
+    get sourceCode()
+    {
+        return this._sourceCodeLocation.sourceCode;
+    },
+
+    get text()
+    {
+        return this._text;
+    },
+
+    get ruleIdentifier()
+    {
+        return this._ruleIdentifier;
+    }
+};
index 8ef0b58..dbea019 100644 (file)
@@ -36,6 +36,8 @@ WebInspector.SourceCode = function()
     this._formatterSourceMap = null;
 };
 
+WebInspector.Object.addConstructorFunctions(WebInspector.SourceCode);
+
 WebInspector.SourceCode.Event = {
     ContentDidChange: "source-code-content-did-change",
     SourceMapAdded: "source-code-source-map-added",