Bug 1649018 - Expose compatibility computation for CSS declaration block via CompatiblityActor and add browser dataset fetch r=daisuke,devtools-backward-compat-reviewers DONTBUILD
authorKriyszig <lelouch.cpp@gmail.com>
Wed, 15 Jul 2020 09:11:21 +0000
changeset 543647 55761bef0a044caaeb0b1edaea255f298519bc50
parent 543646 d65ebfd97a1e21a3ef133cbcea1afc2701876180
child 543648 a42888e04bfce40c27c59b40caf07d919fea6008
push id37677
push usermalexandru@mozilla.com
push dateFri, 07 Aug 2020 03:32:06 +0000
treeherdermozilla-central@d51942b1e2d8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdaisuke, devtools-backward-compat-reviewers
bugs1649018
milestone81.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1649018 - Expose compatibility computation for CSS declaration block via CompatiblityActor and add browser dataset fetch r=daisuke,devtools-backward-compat-reviewers DONTBUILD Previously CompatibilityActor could only compute the compatiblity issues taking node actor. However with the implementation of inline compatibility warning, it becomes necessary to compute compatiblity issue from the CSS declaration block. This patch exposes a getCssDeclarationBlockIssues and add browser dataset fetch within the actor for inline warnings. Differential Revision: https://phabricator.services.mozilla.com/D81472
devtools/client/fronts/styles.js
devtools/server/actors/compatibility.js
devtools/server/actors/styles.js
--- a/devtools/client/fronts/styles.js
+++ b/devtools/client/fronts/styles.js
@@ -187,16 +187,19 @@ class StyleRuleFront extends FrontClassW
   get cssText() {
     return this._form.cssText;
   }
   get authoredText() {
     return typeof this._form.authoredText === "string"
       ? this._form.authoredText
       : this._form.cssText;
   }
+  get compatibilityIssues() {
+    return this._form.compatibilityIssues || [];
+  }
   get declarations() {
     return this._form.declarations || [];
   }
   get keyText() {
     return this._form.keyText;
   }
   get name() {
     return this._form.name;
--- a/devtools/server/actors/compatibility.js
+++ b/devtools/server/actors/compatibility.js
@@ -1,23 +1,42 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
+const Services = require("Services");
 var protocol = require("devtools/shared/protocol");
 const { compatibilitySpec } = require("devtools/shared/specs/compatibility");
 
+loader.lazyRequireGetter(
+  this,
+  "browsersDataset",
+  "devtools/shared/compatibility/dataset/browsers.json"
+);
+
 loader.lazyGetter(this, "mdnCompatibility", () => {
   const MDNCompatibility = require("devtools/shared/compatibility/MDNCompatibility");
   const cssPropertiesCompatData = require("devtools/shared/compatibility/dataset/css-properties.json");
   return new MDNCompatibility(cssPropertiesCompatData);
 });
 
+const TARGET_BROWSER_ID = [
+  "firefox",
+  "firefox_android",
+  "chrome",
+  "chrome_android",
+  "safari",
+  "safari_ios",
+  "edge",
+];
+const TARGET_BROWSER_STATUS = ["esr", "current", "beta", "nightly"];
+const TARGET_BROWSER_PREF = "devtools.inspector.compatibility.target-browsers";
+
 const CompatibilityActor = protocol.ActorClassWithSpec(compatibilitySpec, {
   /**
    * Create a CompatibilityActor.
    * CompatibilityActor is responsible for providing the compatibility information
    * for the web page using the data from the Inspector and the `MDNCompatibility`
    * and conveys them to the compatibility panel in the DevTool Inspector. Currently,
    * the `CompatibilityActor` only detects compatibility issues in the CSS declarations
    * but plans are in motion to extend it to evaluate compatibility information for
@@ -35,16 +54,110 @@ const CompatibilityActor = protocol.Acto
     this.inspector = inspector;
   },
 
   destroy: function() {
     protocol.Actor.prototype.destroy.call(this);
     this.inspector = null;
   },
 
+  _getDefaultTargetBrowsers() {
+    // Retrieve the information that matches to the browser id and the status
+    // from the browsersDataset.
+    // For the structure of then browsersDataset,
+    // see https://github.com/mdn/browser-compat-data/blob/master/browsers/firefox.json
+    const targets = [];
+
+    for (const id of TARGET_BROWSER_ID) {
+      const { name, releases } = browsersDataset[id];
+
+      for (const version in releases) {
+        const { status } = releases[version];
+
+        if (!TARGET_BROWSER_STATUS.includes(status)) {
+          continue;
+        }
+
+        // MDN compat data might have browser data that have the same id and status.
+        // e.g. https://github.com/mdn/browser-compat-data/commit/53453400ecb2a85e7750d99e2e0a1611648d1d56#diff-31a16f09157f13354db27821261604aa
+        // In this case, replace to the browser that has newer version to keep uniqueness
+        // by id and status.
+        const target = { id, name, version, status };
+        const index = targets.findIndex(
+          t => target.id === t.id && target.status === t.status
+        );
+
+        if (index < 0) {
+          targets.push(target);
+          continue;
+        }
+
+        const existingTarget = targets[index];
+        if (parseFloat(existingTarget.version) < parseFloat(target.version)) {
+          targets[index] = target;
+        }
+      }
+    }
+
+    return targets;
+  },
+
+  _getTargetBrowsers() {
+    const targetsString = Services.prefs.getCharPref(TARGET_BROWSER_PREF);
+    return targetsString
+      ? JSON.parse(targetsString)
+      : this._getDefaultTargetBrowsers();
+  },
+
+  /**
+   * Responsible for computing the compatibility issues for a given CSS declaration block
+   * @param Array
+   *  Array of CSS declaration object of the form:
+   *    {
+   *      // Declaration name
+   *      name: <string>,
+   *      // Declaration value
+   *      value: <string>,
+   *    }
+   * @param object options
+   *  `targetBrowsers`: Array of target browsers to be used to check CSS compatibility against.
+   *     It is an Array of the following form
+   *     {
+   *       // Browser id as specified in `devtools/shared/compatibility/datasets/browser.json`
+   *       id: <string>,
+   *       name: <string>,
+   *       version: <string>,
+   *       // Browser status - esr, current, beta, nightly
+   *       status: <string>,
+   *     }
+   * @returns An Array of JSON objects with compatibility information in following form:
+   *    {
+   *      // Type of compatibility issue
+   *      type: <string>,
+   *      // The CSS declaration that has compatibility issues
+   *      property: <string>,
+   *      // Alias to the given CSS property
+   *      alias: <Array>,
+   *      // Link to MDN documentation for the particular CSS rule
+   *      url: <string>,
+   *      deprecated: <boolean>,
+   *      experimental: <boolean>,
+   *      // An array of all the browsers that don't support the given CSS rule
+   *      unsupportedBrowsers: <Array>,
+   *    }
+   */
+  getCSSDeclarationBlockIssues: function(declarationBlock, options) {
+    const targetBrowsers =
+      (options && options.targetBrowsers) || this._getTargetBrowsers();
+    return mdnCompatibility.getCSSDeclarationBlockIssues(
+      declarationBlock,
+      targetBrowsers
+    );
+  },
+
   /**
    * Responsible for computing the compatibility issues in the
    * CSS declaration of the given node.
    * @param NodeActor node
    * @param targetBrowsers Array
    *   An Array of JSON object of target browser to check compatibility against in following form:
    *   {
    *     // Browser id as specified in `devtools/shared/compatibility/datasets/browser.json`
--- a/devtools/server/actors/styles.js
+++ b/devtools/server/actors/styles.js
@@ -1665,16 +1665,27 @@ var StyleRuleActor = protocol.ActorClass
           style,
           this.rawRule,
           decl.name
         );
         // Check property name. All valid CSS properties support "initial" as a value.
         decl.isNameValid = CSS.supports(decl.name, "initial");
         return decl;
       });
+
+      // Associate all the compatibility issues for the declarations with the
+      // form. Once Bug 1648339
+      // https://bugzilla.mozilla.org/show_bug.cgi?id=1648339
+      // is solved we can directly associate compatibility issue with the
+      // declaration themselves.
+      const compatibility = this.pageStyle.inspector.getCompatibility();
+      form.compatibilityIssues = compatibility.getCSSDeclarationBlockIssues(
+        declarations
+      );
+
       // Cache parsed declarations so we don't needlessly re-parse authoredText every time
       // we need to check previous property names and values when tracking changes.
       this._declarations = declarations;
     }
 
     return form;
   },