Skip to content

Commit

Permalink
feat(app): dep graph WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
matejchalk committed Mar 19, 2021
1 parent 545394a commit 6e57ec7
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 17 deletions.
5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"react": "^17.0.1",
"react-dom": "^17.0.1",
"typescript": "^4.2.3",
"vis-network": "^9.0.4",
"yargs": "^16.2.0"
}
}
8 changes: 6 additions & 2 deletions src/app/components/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { ICruiseResult } from 'dependency-cruiser';
import React, { FC, useEffect, useState } from 'react';
import { parseModules } from '../utils/parsers';
import { getModules } from '../utils/deps';
import { parseModuleDeps } from '../utils/parsers';
import DepGraph from './DepGraph';
import SelectModules from './SelectModules';

const JSON_URL =
Expand All @@ -22,12 +24,14 @@ const App: FC = () => {
return <em>Loading...</em>;
}

const modules = parseModules(data);
const moduleDeps = parseModuleDeps(data);
const modules = getModules(moduleDeps);

return (
<div>
<SelectModules modules={modules} label="Root module(s)" />
<SelectModules modules={modules} label="Leaf module(s)" />
<DepGraph />
</div>
);
};
Expand Down
52 changes: 52 additions & 0 deletions src/app/components/DepGraph.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React, { FC, useEffect, useRef } from 'react';
import { Edge, Network, Node } from 'vis-network/standalone';

type Props = {};

const DepGraph: FC<Props> = () => {
const containerRef = useRef<HTMLDivElement>(null);

useEffect(() => {
if (containerRef.current) {
const nodes: Node[] = [
{ id: 1, label: 'Node 1' },
{ id: 2, label: 'Node 2' },
{ id: 3, label: 'Node 3' },
{ id: 4, label: 'Node 4' },
{ id: 5, label: 'Node 5' },
];

const edges: Edge[] = [
{ from: 1, to: 3 },
{ from: 1, to: 2 },
{ from: 2, to: 4 },
{ from: 2, to: 5 },
{ from: 3, to: 3 },
];

const network = new Network(
containerRef.current,
{ edges, nodes },
{
edges: {
arrows: 'to',
},
layout: {
hierarchical: {
sortMethod: 'directed',
},
},
},
);
}
}, [containerRef.current]);

return (
<div
ref={containerRef}
style={{ height: '50vh', width: '100%', border: '1px solid grey' }}
></div>
);
};

export default DepGraph;
15 changes: 15 additions & 0 deletions src/app/utils/deps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Module, ModuleDeps } from './types';

export function getModules(moduleDeps: ModuleDeps): Module[] {
return moduleDeps.paths.map(path => moduleDeps.modules[path]);
}

// TODO: implement
export declare function createGraph(args: {
moduleDeps: ModuleDeps;
rootModules: string[];
leafModules: string[];
}): {
modules: Module[];
imports: { fromPath: string; toPath: string }[];
};
60 changes: 45 additions & 15 deletions src/app/utils/parsers.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { ICruiseResult } from 'dependency-cruiser';
import { Module } from './types';
import { Module, ModuleDeps } from './types';

export function parseModules(result: ICruiseResult): Module[] {
export function parseModuleDeps(result: ICruiseResult): ModuleDeps {
const localModules = new Map<string, boolean>();
const aliases = new Map<string, string>();
const npmPackageNames = new Map<string, string>();
const sourceDeps = new Map<string, string[]>();
result.modules.forEach(module => {
module.dependencies.forEach(dependency => {
sourceDeps.set(module.source, [
...(sourceDeps.get(module.source) ?? []),
dependency.resolved,
]);
if (dependency.dependencyTypes.includes('local')) {
localModules.set(dependency.resolved, true);
}
Expand All @@ -21,22 +26,47 @@ export function parseModules(result: ICruiseResult): Module[] {
});
});

const modules = result.modules.map(
(module): Module => {
const npmPackageName = npmPackageNames.get(module.source);
const alias = aliases.get(module.source);
const isLocal = localModules.get(module.source) ?? false;
return {
path: npmPackageName ?? module.source,
isLocal,
...(alias && { alias }),
};
},
);
return modules
const allModules = result.modules
.map(
(module): Module => {
const npmPackageName = npmPackageNames.get(module.source);
const alias = aliases.get(module.source);
const isLocal = localModules.get(module.source) ?? false;
return {
path: npmPackageName ?? module.source,
source: module.source,
isLocal,
...(alias && { alias }),
};
},
)
.filter(
(item, index, array) =>
array.findIndex(({ path }) => path === item.path) === index,
)
.sort((a, b) => a.path.localeCompare(b.path));

const { moduleBySource, moduleByPath } = allModules.reduce<{
moduleBySource: Record<string, Module>;
moduleByPath: Record<string, Module>;
}>(
(acc, module) => ({
moduleBySource: { ...acc.moduleBySource, [module.source]: module },
moduleByPath: { ...acc.moduleByPath, [module.path]: module },
}),
{ moduleBySource: {}, moduleByPath: {} },
);

const pathDeps: Record<string, string[]> = {};
sourceDeps.forEach((value, key) => {
pathDeps[moduleBySource[key].path] = value.map(
source => moduleBySource[source].path,
);
});

return {
modules: moduleByPath,
paths: allModules.map(({ path }) => path),
deps: pathDeps,
};
}
7 changes: 7 additions & 0 deletions src/app/utils/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
export type Module = {
path: string;
source: string;
alias?: string;
isLocal: boolean;
};

export type ModuleDeps = {
modules: Record<string, Module>;
paths: string[];
deps: Record<string, string[]>;
};

0 comments on commit 6e57ec7

Please sign in to comment.