Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
bc0139f
feat(cli-command,client): add IntelliStory storybook affected-story f…
RaghavsBrowserStack Jul 15, 2026
9c525f1
refactor(cli-command): drop stream-json for in-memory stats parsing; …
RaghavsBrowserStack Jul 15, 2026
d515af8
fix lint issues
RaghavsBrowserStack Jul 15, 2026
893cd7e
Update CLI for new API
RaghavsBrowserStack Jul 17, 2026
8dcdcde
chore: remove accidentally committed build artifact and snapshot archive
RaghavsBrowserStack Jul 17, 2026
b61044f
update intelliStory test
RaghavsBrowserStack Jul 17, 2026
00a1679
add more test coverage
RaghavsBrowserStack Jul 17, 2026
3e67e73
fix test
RaghavsBrowserStack Jul 20, 2026
d9b317b
Merge branch 'master' into PPLT-5844
RaghavsBrowserStack Jul 20, 2026
d85f8f0
update smartsnap skip checkg
RaghavsBrowserStack Jul 20, 2026
735ecfc
account for browser upgrade bail
RaghavsBrowserStack Jul 20, 2026
425630f
send build id with snapshot-name endopint as well
RaghavsBrowserStack Jul 20, 2026
4d683ad
update clien tests
RaghavsBrowserStack Jul 20, 2026
faf80ed
test smartsnap in percy
RaghavsBrowserStack Jul 21, 2026
5657256
apply suggested fixed
RaghavsBrowserStack Jul 21, 2026
e071c95
test: cover new IntelliStory bail branches to restore 100% coverage
RaghavsBrowserStack Jul 21, 2026
102fe36
fix cli review comments
RaghavsBrowserStack Jul 21, 2026
001c036
fix(cli-command): match brace/bracket globs in bailOnChanges/untraced
RaghavsBrowserStack Jul 21, 2026
6b1c79e
update cli for new api
RaghavsBrowserStack Aug 3, 2026
0586767
Merge branch 'master' into PPLT-5844
RaghavsBrowserStack Aug 4, 2026
966c05d
fix lint issue
RaghavsBrowserStack Aug 4, 2026
f6ef573
Merge branch 'master' into PPLT-5844
RaghavsBrowserStack Aug 5, 2026
01aa1f6
Merge branch 'master' into PPLT-5844
RaghavsBrowserStack Aug 5, 2026
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