diff --git a/package.json b/package.json
index 739abb88..a6d90c2f 100644
--- a/package.json
+++ b/package.json
@@ -33,6 +33,7 @@
"run:sample:highlight": "ts-node -O '{\"module\": \"commonjs\"}' ./src/index.ts -d './dummy_project' --include includeFiles config --exclude excludeFiles utils --abstraction abstractions --LR --highlight config.ts b.ts",
"run:sample:link": "ts-node -O '{\"module\": \"commonjs\"}' ./src/index.ts -d './dummy_project' --mermaid-link",
"run:sample:README": "ts-node -O '{\"module\": \"commonjs\"}' ./src/index.ts -d /Users/horiyousuke/Documents/dev/numberplace --include src/components/atoms/ConfigMenu --exclude test stories node_modules",
+ "run:instability": "ts-node -O '{\"module\": \"commonjs\"}' ./src/index.ts --measure-instability",
"build": "tsc",
"build:re": "rm -r ./dist && tsc",
"commit": "git-cz",
diff --git a/src/index.ts b/src/index.ts
index 7d55726a..0b060aff 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -45,6 +45,10 @@ program
)
.option('--LR', 'Specify Flowchart orientation Left-to-Right')
.option('--TB', 'Specify Flowchart orientation Top-to-Bottom')
+ .option(
+ '--measure-instability',
+ 'Enable the beta feature to measure the instability of the modules',
+ )
.option(
'--config-file',
'Specify the relative path to the config file (from cwd or specified by -d, --dir). Default is .tsgrc.json.',
@@ -61,6 +65,27 @@ export async function main(
const { graph: fullGraph, meta } = createGraph(dir);
+ let couplingData: {
+ afferentCoupling: number;
+ efferentCoupling: number;
+ path: string;
+ name: string;
+ isDirectory?: boolean | undefined;
+ }[] = [];
+ if (commandOptions.measureInstability) {
+ console.time('coupling');
+ couplingData = fullGraph.nodes.map(node => {
+ const afferentCoupling = fullGraph.relations.filter(
+ r => r.kind === 'depends_on' && r.to.path === node.path,
+ ).length;
+ const efferentCoupling = fullGraph.relations.filter(
+ r => r.kind === 'depends_on' && r.from.path === node.path,
+ ).length;
+ return { ...node, afferentCoupling, efferentCoupling };
+ });
+ console.timeEnd('coupling');
+ }
+
const graph = pipe(
fullGraph,
graph =>
@@ -73,11 +98,16 @@ export async function main(
graph => highlight(commandOptions.highlight, graph),
);
- await writeMarkdownFile(commandOptions.md ?? 'typescript-graph', graph, {
- ...commandOptions,
- rootDir: meta.rootDir,
- executedScript: commandOptions.executedScript,
- });
+ await writeMarkdownFile(
+ commandOptions.md ?? 'typescript-graph',
+ graph,
+ {
+ ...commandOptions,
+ rootDir: meta.rootDir,
+ executedScript: commandOptions.executedScript,
+ },
+ couplingData,
+ );
}
const dir = path.resolve(opt.dir ?? './');
diff --git a/src/models.ts b/src/models.ts
index c9e76794..2a3745c0 100644
--- a/src/models.ts
+++ b/src/models.ts
@@ -9,6 +9,7 @@ export type OptionValues = {
LR: boolean;
TB: boolean;
configFile: string;
+ measureInstability: boolean;
};
type FileName = string;
diff --git a/src/writeMarkdownFile.ts b/src/writeMarkdownFile.ts
index 3ec94f43..db38f7ed 100644
--- a/src/writeMarkdownFile.ts
+++ b/src/writeMarkdownFile.ts
@@ -11,6 +11,13 @@ export async function writeMarkdownFile(
markdownTitle: string,
graph: Graph,
options: Options,
+ couplingData: {
+ afferentCoupling: number;
+ efferentCoupling: number;
+ path: string;
+ name: string;
+ isDirectory?: boolean | undefined;
+ }[],
) {
return new Promise((resolve, reject) => {
const filename = markdownTitle.endsWith('.md')
@@ -31,6 +38,37 @@ export async function writeMarkdownFile(
ws.write('```mermaid\n');
mermaidify(str => ws.write(str), graph, options);
ws.write('```\n');
+
+ if (couplingData.length !== 0) {
+ ws.write('## Instability\n');
+ ws.write('\n');
+ ws.write(
+ 'module name | Afferent
coupling | Efferent
coupling | Instability\n',
+ );
+ ws.write('--|--|--|--\n');
+
+ couplingData
+ .filter(node => !node.isDirectory)
+ // node_modules 配下のモジュールを除外する
+ .filter(node => !node.path.includes('node_modules'))
+ // json ファイルを除外する
+ .filter(node => !node.path.endsWith('.json'))
+ .map(node => {
+ const totalCoupling = node.afferentCoupling + node.efferentCoupling;
+ const instability =
+ totalCoupling === 0 ? 0 : node.efferentCoupling / totalCoupling;
+ return { ...node, instability };
+ })
+ .toSorted((a, b) => b.instability - a.instability)
+ .forEach(node => {
+ const totalCoupling = node.afferentCoupling + node.efferentCoupling;
+ const instability =
+ totalCoupling === 0 ? 0 : node.efferentCoupling / totalCoupling;
+ ws.write(
+ `${node.name} | ${node.afferentCoupling} | ${node.efferentCoupling} | ${instability.toFixed(2)}\n`,
+ );
+ });
+ }
ws.end();
console.log(filename);