Bug 1286676 - New console frontend: use new taxonomy for RDP packet types. r=bgrins draft
authorLin Clark <lclark@mozilla.com>
Mon, 11 Jul 2016 18:50:25 -0400
changeset 391356 14f8ff37b6f8b5afbfec7d22bc6bc4c4b2a87bc7
parent 391355 e916fecb376ab7feb14636b574a3a26d7f152bd5
child 391358 b5c331d4c0238bc252308e96efdcf9d959fd314b
push id23882
push userbmo:lclark@mozilla.com
push dateFri, 22 Jul 2016 14:54:29 +0000
reviewersbgrins
bugs1286676
milestone50.0a1
Bug 1286676 - New console frontend: use new taxonomy for RDP packet types. r=bgrins
devtools/client/locales/en-US/webconsole.properties
devtools/client/webconsole/new-console-output/components/message-container.js
devtools/client/webconsole/new-console-output/components/message-types/console-api-call.js
devtools/client/webconsole/new-console-output/components/message-types/evaluation-result.js
devtools/client/webconsole/new-console-output/components/message-types/page-error.js
devtools/client/webconsole/new-console-output/constants.js
devtools/client/webconsole/new-console-output/reducers/messages.js
devtools/client/webconsole/new-console-output/test/components/test_message-icon.html
devtools/client/webconsole/new-console-output/test/store/test_messages.js
devtools/client/webconsole/new-console-output/test/utils/test_getRepeatId.html
devtools/client/webconsole/new-console-output/types.js
devtools/client/webconsole/new-console-output/utils/messages.js
--- a/devtools/client/locales/en-US/webconsole.properties
+++ b/devtools/client/locales/en-US/webconsole.properties
@@ -253,16 +253,17 @@ table.key=Key
 table.value=Values
 
 # LOCALIZATION NOTE (severity.error, severity.warn, severity.info, severity.log):
 # tooltip for icons next to console output
 severity.error=Error
 severity.warn=Warning
 severity.info=Info
 severity.log=Log
+severity.debug=Debug
 
 # LOCALIZATION NOTE (webconsole.find.key)
 # Key shortcut used to focus the search box on upper right of the console
 webconsole.find.key=CmdOrCtrl+F
 
 # LOCALIZATION NOTE (webconsole.close.key)
 # Key shortcut used to close the Browser console (doesn't work in regular web console)
 webconsole.close.key=CmdOrCtrl+W
--- a/devtools/client/webconsole/new-console-output/components/message-container.js
+++ b/devtools/client/webconsole/new-console-output/components/message-container.js
@@ -8,16 +8,21 @@
 
 // React & Redux
 const {
   createClass,
   createFactory,
   PropTypes
 } = require("devtools/client/shared/vendor/react");
 
+const {
+  MESSAGE_SOURCE,
+  MESSAGE_TYPE
+} = require("devtools/client/webconsole/new-console-output/constants");
+
 const componentMap = new Map([
   ["ConsoleApiCall", require("./message-types/console-api-call").ConsoleApiCall],
   ["ConsoleCommand", require("./message-types/console-command").ConsoleCommand],
   ["DefaultRenderer", require("./message-types/default-renderer").DefaultRenderer],
   ["EvaluationResult", require("./message-types/evaluation-result").EvaluationResult],
   ["PageError", require("./message-types/page-error").PageError]
 ]);
 
@@ -31,32 +36,34 @@ const MessageContainer = createClass({
   render() {
     const { message } = this.props;
     let MessageComponent = createFactory(getMessageComponent(message));
     return MessageComponent({ message });
   }
 });
 
 function getMessageComponent(message) {
-  // @TODO Once packets have been converted to Chrome RDP structure, remove.
-  if (message.messageType) {
-    let {messageType} = message;
-    if (!componentMap.has(messageType)) {
-      return componentMap.get("DefaultRenderer");
-    }
-    return componentMap.get(messageType);
-  }
-
   switch (message.source) {
-    case "javascript":
+    case MESSAGE_SOURCE.CONSOLE_API:
+      return componentMap.get("ConsoleApiCall");
+    case MESSAGE_SOURCE.JAVASCRIPT:
       switch (message.type) {
-        case "command":
+        case MESSAGE_TYPE.COMMAND:
           return componentMap.get("ConsoleCommand");
+        case MESSAGE_TYPE.RESULT:
+          return componentMap.get("EvaluationResult");
+        // @TODO this is probably not the right behavior, but works for now.
+        // Chrome doesn't distinguish between page errors and log messages. We
+        // may want to remove the PageError component and just handle errors
+        // with ConsoleApiCall.
+        case MESSAGE_TYPE.LOG:
+          return componentMap.get("PageError");
+        default:
+          componentMap.get("DefaultRenderer");
       }
-      break;
   }
 
   return componentMap.get("DefaultRenderer");
 }
 
 module.exports.MessageContainer = MessageContainer;
 
 // Exported so we can test it with unit tests.
--- a/devtools/client/webconsole/new-console-output/components/message-types/console-api-call.js
+++ b/devtools/client/webconsole/new-console-output/components/message-types/console-api-call.js
@@ -20,20 +20,19 @@ ConsoleApiCall.displayName = "ConsoleApi
 
 ConsoleApiCall.propTypes = {
   message: PropTypes.object.isRequired,
 };
 
 function ConsoleApiCall(props) {
   const { message } = props;
 
-  const counter = message.data.counter;
-  const messageBody = counter ?
-    `${counter.label}: ${counter.count}` :
-    message.data.arguments.map((arg) => GripMessageBody({grip: arg}));
+  const messageBody = message.parameters ?
+    message.parameters.map((grip) => GripMessageBody({grip})) :
+    message.messageText;
 
   const icon = MessageIcon({severity: message.severity});
   const repeat = MessageRepeat({repeat: message.repeat});
 
   // @TODO Use of "is" is a temporary hack to get the category and severity
   // attributes to be applied. There are targeted in webconsole's CSS rules,
   // so if we remove this hack, we have to modify the CSS rules accordingly.
   return dom.div({
--- a/devtools/client/webconsole/new-console-output/components/message-types/evaluation-result.js
+++ b/devtools/client/webconsole/new-console-output/components/message-types/evaluation-result.js
@@ -35,15 +35,15 @@ function EvaluationResult(props) {
     severity: message.severity
   },
     // @TODO add timestamp
     // @TODO add indent if needed with console.group
     icon,
     dom.span(
       {className: "message-body-wrapper message-body devtools-monospace"},
       dom.span({},
-        GripMessageBody({grip: message.data})
+        GripMessageBody({grip: message.parameters})
       )
     )
   );
 }
 
 module.exports.EvaluationResult = EvaluationResult;
--- a/devtools/client/webconsole/new-console-output/components/message-types/page-error.js
+++ b/devtools/client/webconsole/new-console-output/components/message-types/page-error.js
@@ -34,16 +34,16 @@ function PageError(props) {
     is: "fdt-message",
     category: message.category,
     severity: message.severity
   },
     icon,
     dom.span(
       {className: "message-body-wrapper message-body devtools-monospace"},
       dom.span({},
-        message.data.errorMessage
+        message.messageText
       )
     ),
     repeat
   );
 }
 
 module.exports.PageError = PageError;
--- a/devtools/client/webconsole/new-console-output/constants.js
+++ b/devtools/client/webconsole/new-console-output/constants.js
@@ -6,51 +6,31 @@
 "use strict";
 
 const actionTypes = {
   MESSAGE_ADD: "MESSAGE_ADD",
   MESSAGES_CLEAR: "MESSAGES_CLEAR",
 };
 
 const categories = {
-  CATEGORY_NETWORK: 0,
-  CATEGORY_CSS: 1,
-  CATEGORY_JS: 2,
-  CATEGORY_WEBDEV: 3,
-  CATEGORY_INPUT: 4,
-  CATEGORY_OUTPUT: 5,
-  CATEGORY_SECURITY: 6,
-  CATEGORY_SERVER: 7
+  CATEGORY_NETWORK: "network",
+  CATEGORY_CSS: "cssparser",
+  CATEGORY_JS: "exception",
+  CATEGORY_WEBDEV: "console",
+  CATEGORY_INPUT: "input",
+  CATEGORY_OUTPUT: "output",
+  CATEGORY_SECURITY: "security",
+  CATEGORY_SERVER: "server"
 };
 
 const severities = {
-  SEVERITY_ERROR: 0,
-  SEVERITY_WARNING: 1,
-  SEVERITY_INFO: 2,
-  SEVERITY_LOG: 3
-};
-
-// The fragment of a CSS class name that identifies categories/severities.
-const fragments = {
-  CATEGORY_CLASS_FRAGMENTS: [
-    "network",
-    "cssparser",
-    "exception",
-    "console",
-    "input",
-    "output",
-    "security",
-    "server",
-  ],
-  SEVERITY_CLASS_FRAGMENTS: [
-    "error",
-    "warn",
-    "info",
-    "log",
-  ]
+  SEVERITY_ERROR: "error",
+  SEVERITY_WARNING: "warn",
+  SEVERITY_INFO: "info",
+  SEVERITY_LOG: "log"
 };
 
 // A mapping from the console API log event levels to the Web Console
 // severities.
 const levels = {
   LEVELS: {
     error: severities.SEVERITY_ERROR,
     exception: severities.SEVERITY_ERROR,
@@ -68,11 +48,50 @@ const levels = {
     groupCollapsed: severities.SEVERITY_LOG,
     groupEnd: severities.SEVERITY_LOG,
     time: severities.SEVERITY_LOG,
     timeEnd: severities.SEVERITY_LOG,
     count: severities.SEVERITY_LOG
   }
 };
 
+const chromeRDPEnums = {
+  MESSAGE_SOURCE: {
+    XML: "xml",
+    JAVASCRIPT: "javascript",
+    NETWORK: "network",
+    CONSOLE_API: "console-api",
+    STORAGE: "storage",
+    APPCACHE: "appcache",
+    RENDERING: "rendering",
+    SECURITY: "security",
+    OTHER: "other",
+    DEPRECATION: "deprecation"
+  },
+  MESSAGE_TYPE: {
+    LOG: "log",
+    DIR: "dir",
+    TABLE: "table",
+    TRACE: "trace",
+    CLEAR: "clear",
+    START_GROUP: "startGroup",
+    START_GROUP_COLLAPSED: "startGroupCollapsed",
+    END_GROUP: "endGroup",
+    ASSERT: "assert",
+    PROFILE: "profile",
+    PROFILE_END: "profileEnd",
+    // Undocumented in Chrome RDP, but is used for evaluation results.
+    RESULT: "result",
+    // Undocumented in Chrome RDP, but is used for input.
+    COMMAND: "command"
+  },
+  MESSAGE_LEVEL: {
+    LOG: "log",
+    ERROR: "error",
+    WARN: "warn",
+    DEBUG: "debug",
+    INFO: "info"
+  }
+};
+
 // Combine into a single constants object
-module.exports = Object.assign({}, actionTypes, categories, severities,
-  fragments, levels);
+module.exports = Object.assign({}, actionTypes, categories, severities, levels,
+  chromeRDPEnums);
--- a/devtools/client/webconsole/new-console-output/reducers/messages.js
+++ b/devtools/client/webconsole/new-console-output/reducers/messages.js
@@ -8,18 +8,17 @@
 const Immutable = require("devtools/client/shared/vendor/immutable");
 const constants = require("devtools/client/webconsole/new-console-output/constants");
 
 function messages(state = Immutable.List(), action) {
   switch (action.type) {
     case constants.MESSAGE_ADD:
       let newMessage = action.message;
 
-      // @TODO clean this up once we've switched to Chrome RDP packet structure.
-      if (newMessage.data && newMessage.data.level === "clear") {
+      if (newMessage.type === "clear") {
         return Immutable.List([newMessage]);
       }
 
       if (newMessage.allowRepeating && state.size > 0) {
         let lastMessage = state.last();
         if (lastMessage.repeatId === newMessage.repeatId) {
           return state.pop().push(
             newMessage.set("repeat", lastMessage.repeat + 1)
--- a/devtools/client/webconsole/new-console-output/test/components/test_message-icon.html
+++ b/devtools/client/webconsole/new-console-output/test/components/test_message-icon.html
@@ -9,22 +9,21 @@
      - http://creativecommons.org/publicdomain/zero/1.0/ -->
 </head>
 <body>
 <p>Test for MessageIcon component</p>
 
 <script type="text/javascript;version=1.8">
 window.onload = Task.async(function* () {
   const {
-    SEVERITY_CLASS_FRAGMENTS,
     SEVERITY_ERROR,
   } = require("devtools/client/webconsole/new-console-output/constants");
   const { MessageIcon } = require("devtools/client/webconsole/new-console-output/components/message-icon");
 
-  let severity = SEVERITY_CLASS_FRAGMENTS[SEVERITY_ERROR];
+  let severity = SEVERITY_ERROR;
   const iconRendered = renderComponent(MessageIcon, { severity });
   ok(iconRendered.classList.contains("icon"), "MessageIcon has expected class");
   is(iconRendered.getAttribute("title"), "Error",
     "MessageIcon shows correct title attribute");
 
   SimpleTest.finish();
 });
 </script>
--- a/devtools/client/webconsole/new-console-output/test/store/test_messages.js
+++ b/devtools/client/webconsole/new-console-output/test/store/test_messages.js
@@ -53,43 +53,41 @@ add_task(function* () {
     "Non-repeated messages aren't clobbered");
 });
 
 /**
  * Test getRepeatId().
  */
 add_task(function* () {
   const message1 = prepareMessage(packet);
-  const message2 = prepareMessage(packet);
+  let message2 = prepareMessage(packet);
   equal(getRepeatId(message1), getRepeatId(message2),
     "getRepeatId() returns same repeat id for objects with the same values");
 
-  message2.data.arguments = ["new args"];
+  message2 = message2.set("parameters", ["new args"]);
   notEqual(getRepeatId(message1), getRepeatId(message2),
     "getRepeatId() returns different repeat ids for different values");
 });
 
 /**
  * Test adding a console.clear message to the store.
  */
 add_task(function*() {
   const { getState, dispatch } = storeFactory();
 
   dispatch(actions.messageAdd(packet));
 
-  const expectedMessage = prepareMessage(packet);
-
   let messages = getAllMessages(getState());
-  deepEqual(messages.toArray(), [expectedMessage],
+  equal(messages.size, 1,
     "MESSAGE_ADD action adds a message");
 
   dispatch(actions.messageAdd(clearPacket));
 
   messages = getAllMessages(getState());
-  deepEqual(messages.toArray(), [prepareMessage(clearPacket)],
+  deepEqual(messages.first(), prepareMessage(clearPacket),
     "console.clear clears existing messages and add a new one");
 });
 
 /**
  * Test message limit on the store.
  */
 add_task(function* () {
   const { getState, dispatch } = storeFactory();
@@ -99,31 +97,31 @@ add_task(function* () {
   let newPacket = Object.assign({}, packet);
   for (let i = 1; i <= messageNumber; i++) {
     newPacket.message.arguments = [i];
     dispatch(actions.messageAdd(newPacket));
   }
 
   let messages = getAllMessages(getState());
   equal(messages.count(), logLimit, "Messages are pruned up to the log limit");
-  deepEqual(messages.last().data.arguments, [messageNumber],
+  deepEqual(messages.last().parameters, [messageNumber],
     "The last message is the expected one");
 });
 
 /**
  * Test message limit on the store with user set prefs.
  */
 add_task(function* () {
   const userSetLimit = 10;
   Services.prefs.setIntPref("devtools.hud.loglimit", userSetLimit);
 
   const { getState, dispatch } = storeFactory();
 
   let newPacket = Object.assign({}, packet);
   for (let i = 1; i <= userSetLimit + 1; i++) {
-    newPacket.message.arguments = [i];
+    newPacket.message.parameters = [i];
     dispatch(actions.messageAdd(newPacket));
   }
 
   let messages = getAllMessages(getState());
   equal(messages.count(), userSetLimit,
     "Messages are pruned up to the user set log limit");
 });
--- a/devtools/client/webconsole/new-console-output/test/utils/test_getRepeatId.html
+++ b/devtools/client/webconsole/new-console-output/test/utils/test_getRepeatId.html
@@ -22,87 +22,67 @@ window.onload = Task.async(function* () 
   yield testDifferentValues();
   yield testDifferentSeverities();
   yield testFalsyValues();
   yield testConsoleVsJSTerm();
 
   SimpleTest.finish();
 
   function testDuplicateValues() {
-    const packet1 = yield getPacket("console.log('same')", "consoleAPICall");
-    const packet2 = yield getPacket("console.log('same')", "consoleAPICall");
+    const {message: message1} = yield getPacket("console.log('same')", "consoleAPICall");
+    const {message: message2} = yield getPacket("console.log('same')", "consoleAPICall");
 
-    const message1 = prepareMessage(packet1);
-    const message2 = prepareMessage(packet2);
-
-    is(getRepeatId(message1.data), getRepeatId(message2.data),
+    is(getRepeatId(message1), getRepeatId(message2),
       "getRepeatId() returns same repeat id for objects with the same values");
   }
 
   function testDifferentValues() {
-    const packet1 = yield getPacket("console.log('same')", "consoleAPICall");
-    const packet2 = yield getPacket("console.log('diff')", "consoleAPICall");
+    const {message: message1} = yield getPacket("console.log('same')", "consoleAPICall");
+    const {message: message2} = yield getPacket("console.log('diff')", "consoleAPICall");
 
-    const message1 = prepareMessage(packet1);
-    const message2 = prepareMessage(packet2);
-
-    isnot(getRepeatId(message1.data), getRepeatId(message2.data),
+    isnot(getRepeatId(message1), getRepeatId(message2),
       "getRepeatId() returns different repeat ids for different values");
   }
 
   function testDifferentSeverities() {
-    const packet1 = yield getPacket("console.log('test')", "consoleAPICall");
-    const packet2 = yield getPacket("console.warn('test')", "consoleAPICall");
+    const {message: message1} = yield getPacket("console.log('test')", "consoleAPICall");
+    const {message: message2} = yield getPacket("console.warn('test')", "consoleAPICall");
 
-    const message1 = prepareMessage(packet1);
-    const message2 = prepareMessage(packet2);
-
-    isnot(getRepeatId(message1.data), getRepeatId(message2.data),
+    isnot(getRepeatId(message1), getRepeatId(message2),
       "getRepeatId() returns different repeat ids for different severities");
   }
 
   function testFalsyValues() {
-    const packetNaN = yield getPacket("console.log(NaN)", "consoleAPICall");
-    const packetUnd = yield getPacket("console.log(undefined)", "consoleAPICall");
-    const packetNul = yield getPacket("console.log(null)", "consoleAPICall");
-
-    const messageNaN = prepareMessage(packetNaN);
-    const messageUnd = prepareMessage(packetUnd);
-    const messageNul = prepareMessage(packetNul);
+    const {message: messageNaN} = yield getPacket("console.log(NaN)", "consoleAPICall");
+    const {message: messageUnd} = yield getPacket("console.log(undefined)", "consoleAPICall");
+    const {message: messageNul} = yield getPacket("console.log(null)", "consoleAPICall");
 
     const repeatIds = new Set([
-      getRepeatId(messageNaN.data),
-      getRepeatId(messageUnd.data),
-      getRepeatId(messageNul.data)]
+      getRepeatId(messageNaN),
+      getRepeatId(messageUnd),
+      getRepeatId(messageNul)]
     );
     is(repeatIds.size, 3,
       "getRepeatId() handles falsy values distinctly");
 
-    const packetNaN2 = yield getPacket("console.log(NaN)", "consoleAPICall");
-    const packetUnd2 = yield getPacket("console.log(undefined)", "consoleAPICall");
-    const packetNul2 = yield getPacket("console.log(null)", "consoleAPICall");
+    const {message: messageNaN2} = yield getPacket("console.log(NaN)", "consoleAPICall");
+    const {message: messageUnd2} = yield getPacket("console.log(undefined)", "consoleAPICall");
+    const {message: messageNul2} = yield getPacket("console.log(null)", "consoleAPICall");
 
-    const messageNaN2 = prepareMessage(packetNaN2);
-    const messageUnd2 = prepareMessage(packetUnd2);
-    const messageNul2 = prepareMessage(packetNul2);
-
-    is(getRepeatId(messageNaN.data), getRepeatId(messageNaN2.data),
+    is(getRepeatId(messageNaN), getRepeatId(messageNaN2),
       "getRepeatId() handles NaN values");
-    is(getRepeatId(messageUnd.data), getRepeatId(messageUnd2.data),
+    is(getRepeatId(messageUnd), getRepeatId(messageUnd2),
       "getRepeatId() handles undefined values");
-    is(getRepeatId(messageNul.data), getRepeatId(messageNul2.data),
+    is(getRepeatId(messageNul), getRepeatId(messageNul2),
       "getRepeatId() handles null values");
   }
 
   function testConsoleVsJSTerm() {
-    const packet1 = yield getPacket("console.log(undefined)", "consoleAPICall");
-    const packet2 = yield getPacket("undefined");
+    const {message: message1} = yield getPacket("console.log(undefined)", "consoleAPICall");
+    const {result: message2} = yield getPacket("undefined");
 
-    const message1 = prepareMessage(packet1);
-    const message2 = prepareMessage(packet2);
-
-    isnot(getRepeatId(message1.data), getRepeatId(message2.data),
+    isnot(getRepeatId(message1), getRepeatId(message2),
       "getRepeatId() returns different repeat ids for console vs JSTerm");
   }
 });
 </script>
 </body>
 </html>
--- a/devtools/client/webconsole/new-console-output/types.js
+++ b/devtools/client/webconsole/new-console-output/types.js
@@ -13,15 +13,18 @@ exports.ConsoleCommand = Immutable.Recor
   source: null,
   type: null,
   category: null,
   severity: null,
 });
 
 exports.ConsoleMessage = Immutable.Record({
   allowRepeating: true,
+  source: null,
+  type: null,
+  level: null,
+  messageText: null,
+  parameters: null,
+  repeat: 1,
+  repeatId: null,
   category: "output",
   severity: "log",
-  data: null,
-  messageType: null,
-  repeat: 1,
-  repeatId: null,
 });
--- a/devtools/client/webconsole/new-console-output/utils/messages.js
+++ b/devtools/client/webconsole/new-console-output/utils/messages.js
@@ -2,87 +2,115 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* 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 {
-  CATEGORY_CLASS_FRAGMENTS,
+  MESSAGE_SOURCE,
+  MESSAGE_TYPE,
+  MESSAGE_LEVEL,
+  // Legacy
   CATEGORY_JS,
-  CATEGORY_WEBDEV,
   CATEGORY_OUTPUT,
+  CATEGORY_WEBDEV,
   LEVELS,
-  SEVERITY_CLASS_FRAGMENTS,
-  SEVERITY_ERROR,
-  SEVERITY_WARNING,
   SEVERITY_LOG,
 } = require("../constants");
 const WebConsoleUtils = require("devtools/shared/webconsole/utils").Utils;
 const STRINGS_URI = "chrome://devtools/locale/webconsole.properties";
 const l10n = new WebConsoleUtils.L10n(STRINGS_URI);
 const { ConsoleMessage } = require("../types");
 
 function prepareMessage(packet) {
+  // This packet is already in the expected packet structure. Simply return.
   if (packet.source) {
     return packet;
   }
 
+  return transformPacket(packet);
+}
+
+/**
+ * Transforms a packet from Firefox RDP structure to Chrome RDP structure.
+ */
+function transformPacket(packet) {
   if (packet._type) {
     packet = convertCachedPacket(packet);
   }
 
   switch (packet.type) {
     case "consoleAPICall": {
-      let data = Object.assign({}, packet.message);
-      if (data.level === "clear") {
-        data.arguments = [l10n.getStr("consoleCleared")];
-      }
+      let { message } = packet;
+
+      let parameters = message.arguments;
+      let type = message.level;
+      let level = LEVELS[type] || MESSAGE_TYPE.LOG;
+      let messageText = null;
 
-      return new ConsoleMessage({
-        category: CATEGORY_CLASS_FRAGMENTS[CATEGORY_WEBDEV],
-        data,
-        messageType: "ConsoleApiCall",
-        repeatId: getRepeatId(data),
-        severity: SEVERITY_CLASS_FRAGMENTS[LEVELS[data.level]] || "log",
-      });
-    }
-    case "pageError": {
-      let data = Object.assign({}, packet.pageError);
-      let severity = SEVERITY_CLASS_FRAGMENTS[SEVERITY_ERROR];
-      if (data.warning || data.strict) {
-        severity = SEVERITY_CLASS_FRAGMENTS[SEVERITY_WARNING];
-      } else if (data.info) {
-        severity = SEVERITY_CLASS_FRAGMENTS[SEVERITY_LOG];
+      // Special per-type conversion.
+      switch (type) {
+        case "clear":
+          // We show a message to users when calls console.clear() is called.
+          parameters = [l10n.getStr("consoleCleared")];
+          break;
+        case "count":
+          // Chrome RDP doesn't have a special type for count.
+          type = MESSAGE_TYPE.LOG;
+          level = MESSAGE_LEVEL.DEBUG;
+          messageText = `${message.counter.label}: ${message.counter.count}`;
+          parameters = null;
+          break;
       }
 
       return new ConsoleMessage({
-        category: CATEGORY_CLASS_FRAGMENTS[CATEGORY_JS],
-        data,
-        messageType: "PageError",
-        repeatId: getRepeatId(data),
-        severity,
+        source: MESSAGE_SOURCE.CONSOLE_API,
+        type,
+        level,
+        parameters,
+        messageText,
+        repeatId: getRepeatId(message),
+        category: CATEGORY_WEBDEV,
+        severity: level,
       });
     }
-    case "evaluationResult":
-    default: {
-      let data;
-      if (typeof packet.result === "object") {
-        data = Object.assign({}, packet.result);
-      } else {
-        data = packet.result;
+
+    case "pageError": {
+      let { pageError } = packet;
+      let level = MESSAGE_LEVEL.ERROR;
+      if (pageError.warning || pageError.strict) {
+        level = MESSAGE_LEVEL.WARN;
+      } else if (pageError.info) {
+        level = MESSAGE_LEVEL.INFO;
       }
 
       return new ConsoleMessage({
-        category: CATEGORY_CLASS_FRAGMENTS[CATEGORY_OUTPUT],
-        data,
-        messageType: "EvaluationResult",
-        repeatId: getRepeatId(data),
-        severity: SEVERITY_CLASS_FRAGMENTS[SEVERITY_LOG],
+        source: MESSAGE_SOURCE.JAVASCRIPT,
+        type: MESSAGE_TYPE.LOG,
+        messageText: pageError.errorMessage,
+        repeatId: getRepeatId(pageError),
+        category: CATEGORY_JS,
+        severity: level,
+      });
+    }
+
+    case "evaluationResult":
+    default: {
+      let { result } = packet;
+
+      return new ConsoleMessage({
+        source: MESSAGE_SOURCE.JAVASCRIPT,
+        type: MESSAGE_TYPE.RESULT,
+        level: MESSAGE_LEVEL.LOG,
+        parameters: result,
+        repeatId: getRepeatId(result),
+        category: CATEGORY_OUTPUT,
+        severity: SEVERITY_LOG,
       });
     }
   }
 }
 
 // Helpers
 function getRepeatId(message) {
   let clonedMessage = JSON.parse(JSON.stringify(message));