Add node modules and compiled JavaScript from main (#57)

Co-authored-by: Oliver King <oking3@uncc.edu>
This commit is contained in:
github-actions[bot] 2022-06-21 12:18:30 -04:00 committed by GitHub
parent d893f27da9
commit 7f7e5ba5ea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6750 changed files with 1745644 additions and 10860 deletions

View file

@ -0,0 +1,31 @@
const React = require('react');
module.exports = function FileBreadcrumbs({ fileFilter = '', setFileFilter }) {
const parts = fileFilter.split('/');
const breadcrumbs = [
{
path: '',
name: 'all files'
},
...parts.map((part, i) => ({
path: parts.slice(0, i + 1).join('/'),
name: part
}))
];
return breadcrumbs.map(({ path, name }) =>
path === fileFilter ? (
name
) : (
<>
<a
href="javascript:void(0)"
onClick={() => setFileFilter(path)}
>
{name}
</a>
/
</>
)
);
};

View file

@ -0,0 +1,50 @@
const React = require('react');
function ToggleOption({ children, filter, activeFilters, setFilters }) {
return (
<button
className={
'toggle__option ' + (activeFilters[filter] ? 'is-toggled' : '')
}
onClick={() =>
setFilters({
...activeFilters,
[filter]: !activeFilters[filter]
})
}
>
{children}
</button>
);
}
module.exports = function FilterToggle({ activeFilters, setFilters }) {
return (
<div className="toggle">
<div className="toggle__label">Filter:</div>
<div className="toggle__options">
<ToggleOption
filter="low"
activeFilters={activeFilters}
setFilters={setFilters}
>
Low
</ToggleOption>
<ToggleOption
filter="medium"
activeFilters={activeFilters}
setFilters={setFilters}
>
Medium
</ToggleOption>
<ToggleOption
filter="high"
activeFilters={activeFilters}
setFilters={setFilters}
>
High
</ToggleOption>
</div>
</div>
);
};

View file

@ -0,0 +1,25 @@
const React = require('react');
module.exports = function FlattenButton({ setIsFlat, isFlat }) {
return (
<div className="toggle">
<div className="toggle__label">Files:</div>
<div className="toggle__options">
<button
onClick={() => setIsFlat(!isFlat)}
className={
'toggle__option ' + (!isFlat ? 'is-toggled' : '')
}
>
Tree
</button>
<button
onClick={() => setIsFlat(!isFlat)}
className={'toggle__option ' + (isFlat ? 'is-toggled' : '')}
>
Flat
</button>
</div>{' '}
</div>
);
};

View file

@ -0,0 +1,155 @@
function addPath(node, parentPath) {
if (!parentPath) {
return node;
}
return { ...node, file: parentPath + '/' + node.file };
}
function flatten(nodes, parentPath) {
let children = [];
for (let i = 0; i < nodes.length; i++) {
const child = nodes[i];
if (child.children) {
children = [
...children,
...flatten(
child.children,
(parentPath ? parentPath + '/' : '') + child.file
)
];
} else {
children.push(addPath(child, parentPath));
}
}
return children;
}
function filterByFile(nodes, fileFilter, parentPath) {
let children = [];
for (let i = 0; i < nodes.length; i++) {
const child = nodes[i];
const childFullPath = (parentPath ? parentPath + '/' : '') + child.file;
const isChildUnderFilter =
fileFilter === childFullPath ||
fileFilter.indexOf(childFullPath + '/') === 0;
const isChildAboveFilter =
childFullPath.indexOf(fileFilter + '/') === 0;
if (isChildUnderFilter) {
// flatten and continue looking underneath
children = [
...children,
...filterByFile(child.children, fileFilter, childFullPath)
];
} else if (isChildAboveFilter) {
// remove the parent path and add everything underneath
const charsToRemoveFromFile =
fileFilter.length - (parentPath ? parentPath.length : 0);
let childFilename = child.file.slice(charsToRemoveFromFile);
if (childFilename[0] === '/') {
childFilename = childFilename.slice(1);
}
children.push({
...child,
file: childFilename
});
}
}
return children;
}
function sort(childData, activeSort) {
const top = activeSort.order === 'asc' ? 1 : -1;
const bottom = activeSort.order === 'asc' ? -1 : 1;
childData.sort((a, b) => {
let valueA;
let valueB;
if (activeSort.sortKey === 'file') {
valueA = a.file;
valueB = b.file;
} else {
const [metricType, valueType] = activeSort.sortKey.split('.');
valueA = a.metrics[metricType][valueType];
valueB = b.metrics[metricType][valueType];
}
if (valueA === valueB) {
return 0;
}
return valueA < valueB ? top : bottom;
});
for (let i = 0; i < childData.length; i++) {
const child = childData[i];
if (child.children) {
childData[i] = {
...child,
children: sort(child.children, activeSort)
};
}
}
return childData;
}
function filter(nodes, metricsMap, activeFilters) {
const children = [];
for (let i = 0; i < nodes.length; i++) {
let child = nodes[i];
if (child.children) {
const newSubChildren = filter(
child.children,
metricsMap,
activeFilters
);
if (newSubChildren.length) {
child = { ...child, children: newSubChildren };
children.push(child);
}
} else {
if (
(metricsMap.statements &&
activeFilters[child.metrics.statements.classForPercent]) ||
(metricsMap.branches &&
activeFilters[child.metrics.branches.classForPercent]) ||
(metricsMap.functions &&
activeFilters[child.metrics.functions.classForPercent]) ||
(metricsMap.lines &&
activeFilters[child.metrics.lines.classForPercent])
) {
children.push(child);
}
}
}
return children;
}
module.exports = function getChildData(
sourceData,
metricsToShow,
activeSort,
isFlat,
activeFilters,
fileFilter
) {
let childData = sourceData.children;
if (isFlat) {
childData = flatten(childData.slice(0));
}
if (fileFilter) {
childData = filterByFile(childData, fileFilter);
}
if (activeFilters.low) {
activeFilters = { ...activeFilters, empty: true };
}
childData = filter(childData, metricsToShow, activeFilters);
if (activeSort) {
childData = sort(childData, activeSort);
}
return childData;
};

156
node_modules/istanbul-reports/lib/html-spa/src/index.js generated vendored Normal file
View file

@ -0,0 +1,156 @@
// The index file for the spa running on the summary page
const React = require('react');
const ReactDOM = require('react-dom');
const SummaryTableHeader = require('./summaryTableHeader');
const SummaryTableLine = require('./summaryTableLine');
const SummaryHeader = require('./summaryHeader');
const getChildData = require('./getChildData');
const FlattenToggle = require('./flattenToggle');
const FilterToggle = require('./filterToggle');
const FileBreadcrumbs = require('./fileBreadcrumbs');
const { setLocation, decodeLocation } = require('./routing');
const { useState, useMemo, useEffect } = React;
const sourceData = window.data;
const metricsToShow = {};
for (let i = 0; i < window.metricsToShow.length; i++) {
metricsToShow[window.metricsToShow[i]] = true;
}
let firstMount = true;
function App() {
const routingDefaults = decodeLocation();
const [activeSort, setSort] = useState(
(routingDefaults && routingDefaults.activeSort) || {
sortKey: 'file',
order: 'desc'
}
);
const [isFlat, setIsFlat] = useState(
(routingDefaults && routingDefaults.isFlat) || false
);
const [activeFilters, setFilters] = useState(
(routingDefaults && routingDefaults.activeFilters) || {
low: true,
medium: true,
high: true
}
);
const [expandedLines, setExpandedLines] = useState(
(routingDefaults && routingDefaults.expandedLines) || []
);
const [fileFilter, setFileFilter] = useState(
(routingDefaults && routingDefaults.fileFilter) || ''
);
const childData = useMemo(
() =>
getChildData(
sourceData,
metricsToShow,
activeSort,
isFlat,
activeFilters,
fileFilter
),
[activeSort, isFlat, activeFilters, fileFilter]
);
const overallMetrics = sourceData.metrics;
useEffect(() => {
setLocation(
firstMount,
activeSort,
isFlat,
activeFilters,
fileFilter,
expandedLines
);
firstMount = false;
}, [activeSort, isFlat, activeFilters, fileFilter, expandedLines]);
useEffect(() => {
window.onpopstate = () => {
const routingState = decodeLocation();
if (routingState) {
// make sure all the state is set before rendering to avoid url updates
// alternative is to merge all the states into one so it can be set in one go
// https://github.com/facebook/react/issues/14259
ReactDOM.unstable_batchedUpdates(() => {
setFilters(routingState.activeFilters);
setSort(routingState.activeSort);
setIsFlat(routingState.isFlat);
setExpandedLines(routingState.expandedLines);
setFileFilter(routingState.fileFilter);
});
}
};
}, []);
return (
<div className="layout">
<div className="layout__section">
<SummaryHeader
metrics={overallMetrics}
metricsToShow={metricsToShow}
/>
</div>
<div className="layout__section">
<div className="toolbar">
<div className="toolbar__item">
<FlattenToggle setIsFlat={setIsFlat} isFlat={isFlat} />
</div>
<div className="toolbar__item">
<FilterToggle
activeFilters={activeFilters}
setFilters={setFilters}
/>
</div>
</div>
</div>
<div className="layout__section">
<h1>
<FileBreadcrumbs
fileFilter={fileFilter}
setFileFilter={setFileFilter}
/>
</h1>
</div>
<div className="layout__section layout__section--fill">
<table className="coverage-summary">
<SummaryTableHeader
onSort={newSort => {
setSort(newSort);
}}
activeSort={activeSort}
metricsToShow={metricsToShow}
/>
<tbody>
{childData.map(child => (
<SummaryTableLine
{...child}
key={child.file}
metricsToShow={metricsToShow}
expandedLines={expandedLines}
setExpandedLines={setExpandedLines}
fileFilter={fileFilter}
setFileFilter={setFileFilter}
/>
))}
</tbody>
</table>
</div>
<div className="layout__section center small quiet">
Code coverage generated by{' '}
<a href="https://istanbul.js.org/" target="_blank">
istanbul
</a>{' '}
at {window.generatedDatetime}
</div>
</div>
);
}
ReactDOM.render(<App />, document.getElementById('app'));

View file

@ -0,0 +1,52 @@
exports.setLocation = function setLocation(
isReplace,
activeSort,
isFlat,
activeFilters,
fileFilter,
expandedLines
) {
const params = [
activeSort.sortKey,
activeSort.order,
isFlat,
activeFilters.low,
activeFilters.medium,
activeFilters.high,
encodeURIComponent(fileFilter),
expandedLines.map(encodeURIComponent).join(',')
];
const newUrl = `#${params.join('/')}`;
if (newUrl === location.hash) {
return;
}
window.history[isReplace ? 'replaceState' : 'pushState'](null, '', newUrl);
};
exports.decodeLocation = function decodeLocation() {
const items = location.hash.substr(1).split('/');
if (items.length !== 8) {
return null;
}
try {
return {
activeSort: {
sortKey: items[0],
order: items[1]
},
isFlat: JSON.parse(items[2]),
activeFilters: {
low: JSON.parse(items[3]),
medium: JSON.parse(items[4]),
high: JSON.parse(items[5])
},
fileFilter: decodeURIComponent(items[6]),
expandedLines: items[7].split(',').map(decodeURIComponent)
};
} catch (e) {
return null;
}
};

View file

@ -0,0 +1,63 @@
const React = require('react');
function Ignores({ metrics, metricsToShow }) {
const metricKeys = Object.keys(metricsToShow);
const result = [];
for (let i = 0; i < metricKeys.length; i++) {
const metricKey = metricKeys[i];
if (metricsToShow[metricKey]) {
const skipped = metrics[metricKey].skipped;
if (skipped > 0) {
result.push(
`${skipped} ${metricKey}${
skipped === 1 ? '' : metricKey === 'branch' ? 'es' : 's'
}`
);
}
}
}
if (result.length === 0) {
return false;
}
return (
<div className="toolbar__item">
<span className="strong">{result.join(', ')}</span>
<span className="quiet">Ignored</span>
</div>
);
}
function StatusMetric({ data, name }) {
return (
<div className="toolbar__item">
<span className="strong">{data.pct}%</span>{' '}
<span className="quiet">{name}</span>{' '}
<span className={'fraction ' + data.classForPercent}>
{data.covered}/{data.total}
</span>
</div>
);
}
module.exports = function SummaryHeader({ metrics, metricsToShow }) {
return (
<div className="toolbar">
{metricsToShow.statements && (
<StatusMetric data={metrics.statements} name="Statements" />
)}
{metricsToShow.branches && (
<StatusMetric data={metrics.branches} name="Branches" />
)}
{metricsToShow.functions && (
<StatusMetric data={metrics.functions} name="Functions" />
)}
{metricsToShow.lines && (
<StatusMetric data={metrics.lines} name="Lines" />
)}
<Ignores metrics={metrics} metricsToShow={metricsToShow} />
</div>
);
};

View file

@ -0,0 +1,124 @@
const React = require('react');
function getSortDetails(sortKey, activeSort) {
let newSort = { sortKey, order: 'desc' };
let sortClass = '';
if (activeSort && activeSort.sortKey === sortKey) {
sortClass = 'sorted';
if (activeSort.order === 'desc') {
sortClass += '-desc';
newSort.order = 'asc';
} else {
if (sortKey !== 'file') {
newSort = { sortKey: 'file', order: 'desc' };
}
}
}
return {
newSort,
sortClass
};
}
function SummaryTableHeaderCell({ name, onSort, sortKey, activeSort }) {
const { newSort, sortClass } = getSortDetails(sortKey, activeSort);
return (
<th
className={'sortable headercell ' + sortClass}
onClick={() => onSort(newSort)}
>
{name}
<span className="sorter" />
</th>
);
}
function FileHeaderCell({ onSort, activeSort }) {
const { newSort, sortClass } = getSortDetails('file', activeSort);
return (
<th
className={'sortable file ' + sortClass}
onClick={() => onSort(newSort)}
>
File
<span className="sorter" />
</th>
);
}
function SubHeadings({ sortKeyPrefix, onSort, activeSort }) {
return (
<>
<SummaryTableHeaderCell
name="%"
onSort={onSort}
sortKey={sortKeyPrefix + '.pct'}
activeSort={activeSort}
/>
<th className="headercell"></th>
<SummaryTableHeaderCell
name="Covered"
onSort={onSort}
sortKey={sortKeyPrefix + '.covered'}
activeSort={activeSort}
/>
<SummaryTableHeaderCell
name="Total"
onSort={onSort}
sortKey={sortKeyPrefix + '.total'}
activeSort={activeSort}
/>
</>
);
}
module.exports = function SummaryTableHeader({
onSort,
activeSort,
metricsToShow
}) {
return (
<thead>
<tr className="topheading">
<th></th>
{metricsToShow.statements && <th colSpan={4}>Statements</th>}
{metricsToShow.branches && <th colSpan={4}>Branches</th>}
{metricsToShow.functions && <th colSpan={4}>Functions</th>}
{metricsToShow.lines && <th colSpan={4}>Lines</th>}
</tr>
<tr className="subheading">
<FileHeaderCell onSort={onSort} activeSort={activeSort} />
{metricsToShow.statements && (
<SubHeadings
sortKeyPrefix="statements"
onSort={onSort}
activeSort={activeSort}
/>
)}
{metricsToShow.branches && (
<SubHeadings
sortKeyPrefix="branches"
onSort={onSort}
activeSort={activeSort}
/>
)}
{metricsToShow.functions && (
<SubHeadings
sortKeyPrefix="functions"
onSort={onSort}
activeSort={activeSort}
/>
)}
{metricsToShow.lines && (
<SubHeadings
sortKeyPrefix="lines"
onSort={onSort}
activeSort={activeSort}
/>
)}
</tr>
</thead>
);
};

View file

@ -0,0 +1,158 @@
const React = require('react');
function MetricCells({ metrics }) {
const { classForPercent, pct, covered, total } = metrics;
return (
<>
<td className={'pct ' + classForPercent}>{Math.round(pct)}% </td>
<td className={classForPercent}>
<div className="bar">
<div
className={`bar__data ${classForPercent} ${classForPercent}--dark`}
style={{ width: pct + '%' }}
></div>
</div>
</td>
<td className={'abs ' + classForPercent}>{covered}</td>
<td className={'abs ' + classForPercent}>{total}</td>
</>
);
}
function FileCell({
file,
prefix,
expandedLines,
setExpandedLines,
hasChildren,
setFileFilter
}) {
if (hasChildren) {
const expandedIndex = expandedLines.indexOf(prefix + file);
const isExpanded = expandedIndex >= 0;
const newExpandedLines = isExpanded
? [
...expandedLines.slice(0, expandedIndex),
...expandedLines.slice(expandedIndex + 1)
]
: [...expandedLines, prefix + file];
return (
<>
<button
type="button"
onClick={() => setExpandedLines(newExpandedLines)}
className="expandbutton"
>
{isExpanded ? String.fromCharCode(0x2013) : '+'}
</button>
<a
href="javascript:void(0)"
onClick={() => setFileFilter(prefix + file)}
>
{file}
</a>
</>
);
} else {
return <a href={`./${prefix}${file}.html`}>{file}</a>;
}
}
function getWorstMetricClassForPercent(metricsToShow, metrics) {
let classForPercent = 'none';
for (const metricToShow in metricsToShow) {
if (metricsToShow[metricToShow]) {
const metricClassForPercent = metrics[metricToShow].classForPercent;
// ignore none metrics so they don't change whats shown
if (metricClassForPercent === 'none') {
continue;
}
// if the metric low or lower than whats currently being used, replace it
if (
metricClassForPercent == 'low' ||
(metricClassForPercent === 'medium' &&
classForPercent !== 'low') ||
(metricClassForPercent === 'high' &&
classForPercent !== 'low' &&
classForPercent !== 'medium')
) {
classForPercent = metricClassForPercent;
}
}
}
return classForPercent;
}
module.exports = function SummaryTableLine({
prefix,
metrics,
file,
children,
tabSize,
metricsToShow,
expandedLines,
setExpandedLines,
fileFilter,
setFileFilter
}) {
tabSize = tabSize || 0;
if (children && tabSize > 0) {
tabSize--;
}
prefix = (fileFilter ? fileFilter + '/' : '') + (prefix || '');
return (
<>
<tr>
<td
className={
'file ' +
getWorstMetricClassForPercent(metricsToShow, metrics)
}
>
{/* eslint-disable-line prefer-spread */ Array.apply(null, {
length: tabSize
}).map((nothing, index) => (
<span className="filetab" key={index} />
))}
<FileCell
file={file}
prefix={prefix}
expandedLines={expandedLines}
setExpandedLines={setExpandedLines}
hasChildren={Boolean(children)}
setFileFilter={setFileFilter}
/>
</td>
{metricsToShow.statements && (
<MetricCells metrics={metrics.statements} />
)}
{metricsToShow.branches && (
<MetricCells metrics={metrics.branches} />
)}
{metricsToShow.functions && (
<MetricCells metrics={metrics.functions} />
)}
{metricsToShow.lines && <MetricCells metrics={metrics.lines} />}
</tr>
{children &&
expandedLines.indexOf(prefix + file) >= 0 &&
children.map(child => (
<SummaryTableLine
{...child}
tabSize={tabSize + 2}
key={child.file}
prefix={prefix + file + '/'}
metricsToShow={metricsToShow}
expandedLines={expandedLines}
setExpandedLines={setExpandedLines}
setFileFilter={setFileFilter}
/>
))}
</>
);
};