Global Metrics
path: .metrics.mi.mi_visual_studio
old: 15.273038193572484
new: 15.268823451840923
path: .metrics.mi.mi_original
old: 26.116895311008943
new: 26.10968810264798
path: .metrics.mi.mi_sei
old: -15.39329756374608
new: -15.40369536750709
path: .metrics.halstead.purity_ratio
old: 0.94457799093314
new: 0.9432697111673048
path: .metrics.halstead.volume
old: 4917.349031901351
new: 4924.169210863765
path: .metrics.halstead.time
old: 11707.293189323273
new: 11766.47410270353
path: .metrics.halstead.effort
old: 210731.2774078189
new: 211796.53384866356
path: .metrics.halstead.length
old: 721.0
new: 722.0
path: .metrics.halstead.N2
old: 273.0
new: 274.0
path: .metrics.halstead.difficulty
old: 42.854651162790695
new: 43.01162790697674
path: .metrics.halstead.level
old: 0.02333469000135667
new: 0.023249526899161935
path: .metrics.halstead.bugs
old: 1.180406009345032
new: 1.1843806703256243
Spaces Data
Minimal test - lines (8, 264)
path: .spaces[0].metrics.mi.mi_original
old: 26.823600056454353
new: 26.81636275535567
path: .spaces[0].metrics.mi.mi_sei
old: -16.770188422731053
new: -16.780629641135533
path: .spaces[0].metrics.mi.mi_visual_studio
old: 15.686315822487924
new: 15.682083482664131
path: .spaces[0].metrics.halstead.level
old: 0.02296022960229602
new: 0.02287581699346405
path: .spaces[0].metrics.halstead.volume
old: 4878.390592039376
new: 4885.185007905727
path: .spaces[0].metrics.halstead.length
old: 718.0
new: 719.0
path: .spaces[0].metrics.halstead.N2
old: 271.0
new: 272.0
path: .spaces[0].metrics.halstead.bugs
old: 1.1868950186892473
new: 1.1909175080623615
path: .spaces[0].metrics.halstead.time
old: 11803.962950380992
new: 11864.020733485337
path: .spaces[0].metrics.halstead.purity_ratio
old: 0.9266526825512946
new: 0.9253638749260494
path: .spaces[0].metrics.halstead.difficulty
old: 43.55357142857143
new: 43.714285714285715
path: .spaces[0].metrics.halstead.effort
old: 212471.33310685784
new: 213552.37320273605
Code
define(function(require, exports, module) {
// Dependencies
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { span } = require("devtools/client/shared/vendor/react-dom-factories");
const {
lengthBubble,
} = require("devtools/client/shared/components/reps/shared/grip-length-bubble");
const {
interleave,
getGripType,
isGrip,
wrapRender,
ellipsisElement,
} = require("devtools/client/shared/components/reps/reps/rep-utils");
const {
MODE,
} = require("devtools/client/shared/components/reps/reps/constants");
const {
ModePropType,
} = require("devtools/client/shared/components/reps/reps/array");
const DEFAULT_TITLE = "Array";
/**
* Renders an array. The array is enclosed by left and right bracket
* and the max number of rendered items depends on the current mode.
*/
GripArray.propTypes = {
object: PropTypes.object.isRequired,
// @TODO Change this to Object.values when supported in Node's version of V8
mode: ModePropType,
provider: PropTypes.object,
onDOMNodeMouseOver: PropTypes.func,
onDOMNodeMouseOut: PropTypes.func,
onInspectIconClick: PropTypes.func,
shouldRenderTooltip: PropTypes.bool,
};
function GripArray(props) {
const { object, mode = MODE.SHORT, shouldRenderTooltip } = props;
let brackets;
const needSpace = function(space) {
return space ? { left: "[ ", right: " ]" } : { left: "[", right: "]" };
};
const config = {
"data-link-actor-id": object.actor,
className: "objectBox objectBox-array",
title: shouldRenderTooltip ? "Array" : null,
};
const title = getTitle(props, object);
if (mode === MODE.TINY) {
const isEmpty = getLength(object) === 0;
// Omit bracketed ellipsis for non-empty non-Array arraylikes (f.e: Sets).
if (!isEmpty && object.class !== "Array") {
return span(config, title);
}
brackets = needSpace(false);
return span(
config,
title,
span(
{
className: "arrayLeftBracket",
},
brackets.left
),
isEmpty ? null : ellipsisElement,
span(
{
className: "arrayRightBracket",
},
brackets.right
)
);
}
const max = maxLengthMap.get(mode);
const items = arrayIterator(props, object, max);
brackets = needSpace(items.length > 0);
return span(
config,
title,
span(
{
className: "arrayLeftBracket",
},
brackets.left
),
...interleave(items, ", "),
span(
{
className: "arrayRightBracket",
},
brackets.right
),
span({
className: "arrayProperties",
role: "group",
})
);
}
function getLength(grip) {
if (!grip.preview) {
return 0;
}
return grip.preview.length || grip.preview.childNodesLength || 0;
}
function getTitle(props, object) {
const objectLength = getLength(object);
const isEmpty = objectLength === 0;
let title = props.title || object.class || DEFAULT_TITLE;
const length = lengthBubble({
object,
mode: props.mode,
maxLengthMap,
getLength,
});
if (props.mode === MODE.TINY) {
if (isEmpty) {
if (object.class === DEFAULT_TITLE) {
return null;
}
return span({ className: "objectTitle" }, `${title} `);
}
let trailingSpace;
if (object.class === DEFAULT_TITLE) {
title = null;
trailingSpace = " ";
}
return span({ className: "objectTitle" }, title, length, trailingSpace);
}
return span({ className: "objectTitle" }, title, length, " ");
}
function getPreviewItems(grip) {
if (!grip.preview) {
return null;
}
return grip.preview.items || grip.preview.childNodes || [];
}
function arrayIterator(props, grip, max) {
const { Rep } = require("devtools/client/shared/components/reps/reps/rep");
let items = [];
const gripLength = getLength(grip);
if (!gripLength) {
return items;
}
const previewItems = getPreviewItems(grip);
const provider = props.provider;
let emptySlots = 0;
let foldedEmptySlots = 0;
items = previewItems.reduce((res, itemGrip) => {
if (res.length >= max) {
return res;
}
let object;
try {
if (!provider && itemGrip === null) {
emptySlots++;
return res;
}
object = provider ? provider.getValue(itemGrip) : itemGrip;
} catch (exc) {
object = exc;
}
if (emptySlots > 0) {
res.push(getEmptySlotsElement(emptySlots));
foldedEmptySlots = foldedEmptySlots + emptySlots - 1;
emptySlots = 0;
}
if (res.length < max) {
res.push(
Rep({
...props,
object,
mode: MODE.TINY,
// Do not propagate title to array items reps
title: undefined,
})
);
}
return res;
}, []);
// Handle trailing empty slots if there are some.
if (items.length < max && emptySlots > 0) {
items.push(getEmptySlotsElement(emptySlots));
foldedEmptySlots = foldedEmptySlots + emptySlots - 1;
}
const itemsShown = items.length + foldedEmptySlots;
if (gripLength > itemsShown) {
items.push(ellipsisElement);
}
return items;
}
function getEmptySlotsElement(number) {
// TODO: Use l10N - See https://github.com/firefox-devtools/reps/issues/141
return `<${number} empty slot${number > 1 ? "s" : ""}>`;
}
function supportsObject(grip, noGrip = false) {
if (noGrip === true || !isGrip(grip)) {
return false;
}
return (
grip.preview &&
(grip.preview.kind == "ArrayLike" ||
getGripType(grip, noGrip) === "DocumentFragment")
);
}
const maxLengthMap = new Map();
maxLengthMap.set(MODE.SHORT, 3);
maxLengthMap.set(MODE.LONG, 10);
// Exports from this module
module.exports = {
rep: wrapRender(GripArray),
supportsObject,
maxLengthMap,
getLength,
};
});
Minimal test - lines (241, 251)
path: .spaces[0].spaces[6].metrics.halstead.bugs
old: 0.04772188926642685
new: 0.05066799285084565
path: .spaces[0].spaces[6].metrics.halstead.purity_ratio
old: 1.834586539016274
new: 1.7887218755408671
path: .spaces[0].spaces[6].metrics.halstead.level
old: 0.1
new: 0.09375
path: .spaces[0].spaces[6].metrics.halstead.effort
old: 1713.0037948837166
new: 1874.0554337189376
path: .spaces[0].spaces[6].metrics.halstead.length
old: 39.0
new: 40.0
path: .spaces[0].spaces[6].metrics.halstead.difficulty
old: 10.0
new: 10.666666666666666
path: .spaces[0].spaces[6].metrics.halstead.N2
old: 15.0
new: 16.0
path: .spaces[0].spaces[6].metrics.halstead.volume
old: 171.30037948837168
new: 175.69269691115042
path: .spaces[0].spaces[6].metrics.halstead.time
old: 95.1668774935398
new: 104.11419076216322
path: .spaces[0].spaces[6].metrics.mi.mi_original
old: 104.25831975317564
new: 104.12666715165732
path: .spaces[0].spaces[6].metrics.mi.mi_sei
old: 75.22120818433193
new: 75.03127362900135
path: .spaces[0].spaces[6].metrics.mi.mi_visual_studio
old: 60.969777633436046
new: 60.89278780798674
Code
function supportsObject(grip, noGrip = false) {
if (noGrip === true || !isGrip(grip)) {
return false;
}
return (
grip.preview &&
(grip.preview.kind == "ArrayLike" ||
getGripType(grip, noGrip) === "DocumentFragment")
);
}