Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .semgrepignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,5 @@ packages/core/src/api.js
# in the file-load helper anyway. No user input flows here.
packages/core/test/unit/maestro-hierarchy.test.js
packages/core/test/unit/maestro-hierarchy.parity.test.js

packages/cli-command/test/noRequireBinding.test.js
7 changes: 6 additions & 1 deletion packages/cli-command/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
".": "./dist/index.js",
"./flags": "./dist/flags.js",
"./utils": "./dist/utils.js",
"./intelliStory": "./dist/intelliStory.js",
"./test/helpers": "./test/helpers.js"
},
"scripts": {
Expand All @@ -38,6 +39,10 @@
"dependencies": {
"@percy/config": "1.32.4",
"@percy/core": "1.32.4",
"@percy/logger": "1.32.4"
"@percy/logger": "1.32.4",
"glob-to-regexp": "^0.4.1"
},
"optionalDependencies": {
"snyk-nodejs-lockfile-parser": "2.7.1"
}
}
117 changes: 117 additions & 0 deletions packages/cli-command/src/graphTrace.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import fs from 'fs';
import path from 'path';
import url from 'url';

const TEMPLATE_PATH = path.resolve(url.fileURLToPath(import.meta.url), '../graphTraceTemplate.html');

function templateKindOf(v) {
if (v.changed) return 'is_relevant';
switch (v.kind) {
case 'dependency': return 'package';
case 'component': return 'component';
case 'story': return 'story';
default: return 'component';
}
}

const KIND_RANK = { package: 0, component: 1, is_relevant: 1, story: 2 };

function computeLayout(rawVertices, edges, transitiveClosure) {
const n = rawVertices.length;
const vertices = rawVertices.map((v, i) => ({
index: i,
name: v.file_path,
kind: v.kind,
changed: !!v.changed,
row: 0,
col: 0
}));

const incomingMax = new Array(n).fill(0);
for (const triple of transitiveClosure) {
const [u, v, val] = triple;
if (u === v || val <= 0) continue;
if (v < 0 || v >= n) continue;
if (val > incomingMax[v]) incomingMax[v] = val;
}
for (let i = 0; i < n; i++) {
vertices[i].col = vertices[i].kind === 'dependency' ? 0 : incomingMax[i] + 1;
}

const iterations = n + 2;
for (let iter = 0; iter < iterations; iter++) {
let changed = false;
for (const [s, t] of edges) {
if (s < 0 || s >= n || t < 0 || t >= n) continue;
if (vertices[s].col < vertices[t].col) continue;
vertices[t].col = vertices[s].col + 1;
changed = true;
}
if (!changed) break;
}

let furthestNonStory = 0;
for (const v of vertices) {
if (v.kind === 'story') continue;
if (v.col > furthestNonStory) furthestNonStory = v.col;
}
for (const v of vertices) {
if (v.kind !== 'story') continue;
if (v.col < furthestNonStory + 1) v.col = furthestNonStory + 1;
}

const groups = new Map();
for (const v of vertices) {
let list = groups.get(v.col);
if (!list) groups.set(v.col, list = []);
list.push(v);
}
const rankOf = v => {
const r = KIND_RANK[templateKindOf(v)];
/* istanbul ignore next */
return r === undefined ? 99 : r;
};
for (const list of groups.values()) {
list.sort((a, b) => {
const ra = rankOf(a);
const rb = rankOf(b);
if (ra !== rb) return ra - rb;
if (a.name < b.name) return -1;
if (a.name > b.name) return 1;
return 0;
});
list.forEach((v, row) => { v.row = row; });
}

return vertices.map(v => ({
index: v.index,
name: v.name,
row: v.row,
col: v.col,
kind: templateKindOf(v)
}));
}

const LS = String.fromCharCode(0x2028);
const PS = String.fromCharCode(0x2029);
function safeJson(obj) {
return JSON.stringify(obj)
.replace(/<\//g, '<\\/')
.replace(/<!--/g, '<\\!--')
.replace(/--(!?)>/g, '--$1\\>')
.split(LS).join('\\u2028')
.split(PS).join('\\u2029');
}

export function renderGraphTraceHtml({ vertices, edges, transitiveClosureMatrixSparse }) {
const laidOutVertices = computeLayout(
vertices || [],
edges || [],
transitiveClosureMatrixSparse || []
);
const template = fs.readFileSync(TEMPLATE_PATH, 'utf8');
return template
.replace('__VERTICES_JSON__', safeJson(laidOutVertices))
.replace('__EDGES_JSON__', safeJson(edges || []))
.replace('__TRANSITIVE_CLOSURE_JSON__', safeJson(transitiveClosureMatrixSparse || []));
}
Loading
Loading