Repository: sverweij/dependency-cruiser
Pull request #929 (2024-04-07 15:50:04)

feat(report/metrics): adds experimental stats
## Description

- adds the newly introduced (experimental) stats to the output of the _metrics_ reporter
- refactors the metric reporter (so it's easier to provide other output formats later on)
- formats all the numbers with `Intl` - which is particularly useful for the `size` stat as that tends to run in the thousands.

## Motivation and Context

Might prove useful

## How Has This Been Tested?

- [x] green ci
- [x] updated & added automated non-regression tests

## Screenshots

```
type    name                                                 N     Ca     Ce  I (%)        size   #tls
------- ----------------------------------------------- ------ ------ ------ ------ ----------- ------
folder  src                                                 13      0      0    0 %      36.125     99
folder  src/cache                                            6      0      6  100 %      25.367     54
module  src/cache/cache.mjs                                  1      0      5  100 %       5.817     12
module  src/cache/content-strategy.mjs                       1      1      2   67 %       3.948      7
module  src/cache/find-content-changes.mjs                   1      1      3   75 %       3.663      6
module  src/cache/helpers.mjs                                1      3      1   25 %       3.612     16
module  src/cache/metadata-strategy.mjs                      1      1      2   67 %       3.720      5
module  src/cache/options-compatible.mjs                     1      1      0    0 %       4.607      8
folder  src/extract                                          2      1      1   50 %       4.985     20
folder  src/extract/transpile                                2      1      1   50 %       4.985     20
module  src/extract/transpile/meta.mjs                       1      1      2   67 %       3.519     10
module  src/extract/transpile/try-import-available.mjs       1      1      0    0 %       1.466     10
folder  src/graph-utl                                        1      1      0    0 %         382      3
module  src/graph-utl/match-facade.mjs                       1      1      0    0 %         382      3
module  src/meta.cjs                                         1      1      0    0 %         467      1
folder  src/utl                                              3      4      0    0 %       4.924     21
module  src/utl/bus.mjs                                      1      3      0    0 %         766     10
module  src/utl/find-all-files.mjs                           1      1      1   50 %       3.040      9
module  src/utl/path-to-posix.mjs                            1      1      0    0 %       1.118      2
```

## Types of changes

- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] Documentation only change
- [x] Refactor (non-breaking change which fixes an issue without changing functionality)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)

## Checklist

- [x] :book:

  - My change doesn't require a documentation update, or ...
  - it _does_ and I have updated it

- [x] :balance_scale:
  - The contribution will be subject to [The MIT license](https://github.com/sverweij/dependency-cruiser/blob/main/LICENSE), and I'm OK with that.
  - The contribution is my own original work.
  - I am ok with the stuff in [**CONTRIBUTING.md**](https://github.com/sverweij/dependency-cruiser/blob/main/.github/CONTRIBUTING.md).



Patch:
diff --git a/.c8rc.json b/.c8rc.json
index 970ec2b8..52e0a0c6 100644
--- a/.c8rc.json
+++ b/.c8rc.json
@@ -1,7 +1,7 @@
 {
   "checkCoverage": true,
   "statements": 99.89,
-  "branches": 98.41,
+  "branches": 98.44,
   "functions": 100,
   "lines": 99.89,
   "exclude": [
diff --git a/doc/cli.md b/doc/cli.md
index 65b6250d..992617bc 100644
--- a/doc/cli.md
+++ b/doc/cli.md
@@ -557,113 +557,53 @@ Generates a list of all current violations you can use as input for the
 
 #### metrics - generate a report with stability metrics for each folder
 
-Shows for each module and each folder:
-
-| metric             | abbreviation | description                                                                                                               |
-| ------------------ | ------------ | ------------------------------------------------------------------------------------------------------------------------- |
-| number of modules  | N            |                                                                                                                           |
-| Afferent couplings | Ca           | The number of modules outside this folder that depend on this folder ("coming in")                                        |
-| Efferent couplings | Ce           | The number of modules this folder depends on _outside_ the current folder ("going out")                                   |
-| Instability        | I            | Ce / (Ca + Ce) a number between 0 and 1 that indicates how 'stable' the folder with 0: wholy stable; and 1 wholy unstable |
+Shows for each module and each folder (but only when dependency-cruiser was asked
+to calculate it):
+
+| metric               | abbreviation | description                                                                                                                                                    |
+| -------------------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| Type of component    | type         | The type of the component: 'module' or 'folder'                                                                                                                |
+| Number of modules    | N            | The number of modules in the component (for modules this will always be 1)                                                                                     |
+| Afferent couplings   | Ca           | The number of modules outside this folder that depend on this folder ("coming in")                                                                             |
+| Efferent couplings   | Ce           | The number of modules this folder depends on _outside_ the current folder ("going out")                                                                        |
+| Instability          | I            | Ce / (Ca + Ce) a number between 0 and 1 that indicates how 'stable' the folder with 0: wholy stable; and 1 wholy unstable                                      |
+| Size                 | size         | The size in bytes of the module - only available when the [experimentalStats](./options-reference.md#experimentalstats) option is set to true                  |
+| Top level statements | #tls         | The number of top level statements in the module - only available when the [experimentalStats](./options-reference.md#experimentalstats) option is set to true |
 
 While the term 'instability' has a negative connotation it's also unavoidable
 in any meaningful system. It's the basis of Martin's variable component stability
 principle: 'the instability of a folder should be larger than the folders it
 depends on'.
 
-Only present when dependency-cruiser was asked to calculate it.
+With [options for the metrics reporter](./options-reference.md#metrics)
+you can show or hide 'module' or 'folder' components, and sort by the name
+or by any of the metrics/ stats.
 
 <details>
 <summary>Typical output</summary>
 
 ```
-name                                                      N    Ca    Ce  I
------------------------------------------------------ ----- ----- -----  -----
-bin                                                       4     0    12  1
-src/validate                                              7     0     4  1
-bin/depcruise-baseline.js                                 1     0     4  1
-bin/depcruise-fmt.js                                      1     0     4  1
-bin/dependency-cruise.js                                  1     0     4  1
-src/validate/index.js                                     1     0     4  1
-src/extract                                              40     3    86  0.97
-src/extract/get-dependencies.js                           1     1    14  0.93
-src                                                      64     9   115  0.93
-src/extract/resolve/index.js                              1     1    11  0.92
-src/main                                                 10     3    25  0.89
-src/main/resolve-options                                  1     1     7  0.88
-src/extract/clear-caches.js                               1     1     7  0.88
-src/main/resolve-options/normalize.js                     1     1     7  0.88
-src/extract/transpile                                    10     4    27  0.87
-src/extract/resolve                                      10     5    30  0.86
-src/extract/transpile/vue-template-wrap.js                1     1     6  0.86
-src/extract/gather-initial-sources.js                     1     1     6  0.86
-src/extract/resolve/resolve-cjs.js                        1     1     5  0.83
-src/extract/index.js                                      1     1     4  0.8
-src/extract/parse/to-javascript-ast.js                    1     2     8  0.8
-src/extract/transpile/coffeescript-wrap.js                1     1     4  0.8
-src/extract/transpile/svelte-wrap.js                      1     1     4  0.8
-src/extract/transpile/typescript-wrap.js                  1     1     4  0.8
-src/extract/resolve/determine-dependency-types.js         1     1     4  0.8
-src/main/options/normalize.js                             1     1     4  0.8
-src/main/rule-set/validate.js                             1     1     4  0.8
-src/validate/match-dependency-rule.js                     1     1     4  0.8
-src/validate/match-module-rule.js                         1     1     4  0.8
-src/cli/index.js                                          1     2     7  0.78
-src/cli/normalize-cli-options.js                          1     2     7  0.78
-src/main/index.js                                         1     3    10  0.77
-src/cli                                                   6     6    18  0.75
-src/extract/resolve/get-manifest                          2     2     6  0.75
-src/main/rule-set                                         2     2     6  0.75
-src/extract/transpile/babel-wrap.js                       1     1     3  0.75
-src/extract/transpile/livescript-wrap.js                  1     1     3  0.75
-src/extract/resolve/get-manifest/merge-manifests.js       1     1     3  0.75
-src/extract/ast-extractors/extract-amd-deps.js            1     1     3  0.75
-src/extract/ast-extractors/extract-es6-deps.js            1     1     3  0.75
-src/extract/ast-extractors/swc-dependency-visitor.js      1     1     3  0.75
-src/extract/ast-extractors/extract-typescript-deps.js     1     1     3  0.75
-src/cli/format-meta-info.js                               1     1     3  0.75
-src/cli/format.js                                         1     1     3  0.75
-src/extract/transpile/meta.js                             1     4    10  0.71
-src/extract/parse/to-typescript-ast.js                    1     2     5  0.71
-src/extract/resolve/resolve-amd.js                        1     2     5  0.71
-src/extract/parse                                         3     7    17  0.71
-src/extract/ast-extractors                                7     5    11  0.69
-src/main/options                                          3     3     6  0.67
-src/extract/resolve/external-module-helpers.js            1     3     6  0.67
-src/extract/resolve/get-manifest/index.js                 1     2     4  0.67
-src/extract/resolve/resolve-helpers.js                    1     1     2  0.67
-src/main/report-wrap.js                                   1     1     2  0.67
-src/main/rule-set/normalize.js                            1     1     2  0.67
-src/validate/violates-required-rule.js                    1     1     2  0.67
-src/main/utl                                              1     2     3  0.6
-src/main/utl/normalize-re-properties.js                   1     2     3  0.6
-src/main/options/validate.js                              1     2     3  0.6
-src/extract/parse/to-swc-ast.js                           1     3     4  0.57
-src/main/files-and-dirs                                   1     1     1  0.5
-src/extract/transpile/index.js                            1     1     1  0.5
-src/extract/transpile/svelte-preprocess.js                1     1     1  0.5
-src/extract/resolve/resolve.js                            1     3     3  0.5
-src/extract/ast-extractors/extract-cjs-deps.js            1     2     2  0.5
-src/extract/ast-extractors/extract-swc-deps.js            1     1     1  0.5
-src/extract/utl/detect-pre-compilation-ness.js            1     1     1  0.5
-src/main/files-and-dirs/normalize.js                      1     1     1  0.5
-src/cli/validate-node-environment.js                      1     3     2  0.4
-src/extract/utl/get-extension.js                          1     2     1  0.33
-src/validate/is-module-only-rule.js                       1     2     1  0.33
-src/extract/resolve/module-classifiers.js                 1     5     2  0.29
-src/extract/ast-extractors/estree-helpers.js              1     3     1  0.25
-src/extract/utl                                           6    10     2  0.17
-src/extract/utl/path-to-posix.js                          1     5     1  0.17
-src/meta.js                                               1    15     0  0
-src/extract/transpile/javascript-wrap.js                  1     1     0  0
-src/extract/utl/strip-query-parameters.js                 1     1     0  0
-src/extract/utl/compare.js                                1     1     0  0
-src/extract/utl/extract-module-attributes.js              1     1     0  0
-src/main/options/defaults.js                              1     1     0  0
-src/cli/defaults.js                                       1     1     0  0
-bin/wrap-stream-in-html.js                                1     0     0  0
-src/validate/matchers.js                                  1     3     0  0
-src/validate/utl.js                                       1     3     0  0
+type    name                                                 N     Ca     Ce  I (%)        size   #tls
+------- ----------------------------------------------- ------ ------ ------ ------ ----------- ------
+folder  src                                                 13      0      0    0 %      36.125     99
+folder  src/cache                                            6      0      6  100 %      25.367     54
+module  src/cache/cache.mjs                                  1      0      5  100 %       5.817     12
+module  src/cache/content-strategy.mjs                       1      1      2   67 %       3.948      7
+module  src/cache/find-content-changes.mjs                   1      1      3   75 %       3.663      6
+module  src/cache/helpers.mjs                                1      3      1   25 %       3.612     16
+module  src/cache/metadata-strategy.mjs                      1      1      2   67 %       3.720      5
+module  src/cache/options-compatible.mjs                     1      1      0    0 %       4.607      8
+folder  src/extract                                          2      1      1   50 %       4.985     20
+folder  src/extract/transpile                                2      1      1   50 %       4.985     20
+module  src/extract/transpile/meta.mjs                       1      1      2   67 %       3.519     10
+module  src/extract/transpile/try-import-available.mjs       1      1      0    0 %       1.466     10
+folder  src/graph-utl                                        1      1      0    0 %         382      3
+module  src/graph-utl/match-facade.mjs                       1      1      0    0 %         382      3
+module  src/meta.cjs                                         1      1      0    0 %         467      1
+folder  src/utl                                              3      4      0    0 %       4.924     21
+module  src/utl/bus.mjs                                      1      3      0    0 %         766     10
+module  src/utl/find-all-files.mjs                           1      1      1   50 %       3.040      9
+module  src/utl/path-to-posix.mjs                            1      1      0    0 %       1.118      2
 ```
 
 </details>
diff --git a/doc/options-reference.md b/doc/options-reference.md
index 91f39f53..5b785eb5 100644
--- a/doc/options-reference.md
+++ b/doc/options-reference.md
@@ -22,6 +22,7 @@
   - [summarising/ `collapsePattern` (`dot` and `archi` reporters)](#summarising-collapsepattern-dot-and-archi-reporters)
   - [filtering (`dot`, `ddot` and `archi` reporters)](#filtering-dot-ddot-and-archi-reporters)
   - [wordlist - (`anon` reporter)](#wordlist---anon-reporter)
+  - [metrics](#metrics)
   - [markdown](#markdown)
   - [mermaid](#mermaid)
   - [text](#text)
@@ -1226,7 +1227,7 @@ module.exports = {
 }
 ```
 
-### options for the _metrics_ reporter
+### metrics
 
 By default the metrics reporter emits instability metrics for all modules and
 folders, ordered by instability (descending). If you want to see less, or
@@ -1239,7 +1240,8 @@ use a different sort order, you can tweak that with the metrics reporterOptions.
 - `orderBy`: with this you can specify how the metrics reporter orders its output.
   Defaults to `instability`.
   Possible values `name`, `moduleCount`, `afferentCouplings`, `efferentCouplings`,
-  `instability`.
+  `instability`, `size` and `topLevelStatementCount` (the latter two only
+  available when the `experimentalStats` option is set to `true`).
 
 ```javascript
 module.exports = {
diff --git a/src/report/metrics.mjs b/src/report/metrics.mjs
index 44644449..07f6896f 100644
--- a/src/report/metrics.mjs
+++ b/src/report/metrics.mjs
@@ -1,65 +1,164 @@
 import { EOL } from "node:os";
 import chalk from "chalk";
-import { formatPercentage } from "./utl/index.mjs";
+import { formatNumber, formatPercentage } from "./utl/index.mjs";
 
-const DECIMAL_BASE = 10;
-const METRIC_WIDTH = 5;
-const COMPONENT_HEADER = "name";
-
-function getHeader(pMaxNameWidth) {
-  return `${COMPONENT_HEADER.padEnd(pMaxNameWidth)} ${"N".padStart(
-    METRIC_WIDTH + 1
-  )} ${"Ca".padStart(METRIC_WIDTH + 1)} ${"Ce".padStart(
-    METRIC_WIDTH + 1
-  )} ${"I (%)".padStart(METRIC_WIDTH + 1)}`;
-}
+/**
+ * @typedef {"string"|"integer"|"percent"} ColumnFormatType
+ * @typedef {{title: string; format: ColumnFormatType; width: string}} IColumnMetaData
+ * @typedef {Map<string,IColumnMetaData>} IMeta
+ * @typedef {{name: string; moduleCount: number; afferentCouplings:number; efferentCouplings:number; instability:number; size:number; topLevelStatementCount:number;}} IData
+ * @typedef {{meta: IMeta; data: IData[]}} ITableObject
+ */
 
-function getDemarcationLine(pMaxNameWidth) {
-  return `${"-".repeat(pMaxNameWidth)} ${"-".repeat(
-    METRIC_WIDTH + 1
-  )} ${"-".repeat(METRIC_WIDTH + 1)} ${"-".repeat(
-    METRIC_WIDTH + 1
-  )} ${"-".repeat(METRIC_WIDTH + 1)}`;
-}
+const METRIC_WIDTH = 5;
 
-function getMetricsTable(pMetrics, pMaxNameWidth) {
-  return pMetrics.map(
-    ({
-      name,
-      moduleCount,
-      afferentCouplings,
-      efferentCouplings,
-      instability,
-    }) =>
-      `${name.padEnd(pMaxNameWidth, " ")}  ${moduleCount
-        .toString(DECIMAL_BASE)
-        .padStart(METRIC_WIDTH)}  ${afferentCouplings
-        .toString(DECIMAL_BASE)
-        .padStart(METRIC_WIDTH)}  ${efferentCouplings
-        .toString(DECIMAL_BASE)
-        .padStart(METRIC_WIDTH)}  ${formatPercentage(instability).padStart(
-        METRIC_WIDTH
-      )}`
-  );
+function getMetricsFromFolder({
+  name,
+  moduleCount,
+  afferentCouplings,
+  efferentCouplings,
+  instability,
+  experimentalStats,
+}) {
+  const lReturnValue = {
+    type: "folder",
+    name,
+    moduleCount,
+    afferentCouplings,
+    efferentCouplings,
+    instability,
+  };
+  if (experimentalStats) {
+    lReturnValue.size = experimentalStats.size;
+    lReturnValue.topLevelStatementCount =
+      experimentalStats.topLevelStatementCount;
+  }
+  return lReturnValue;
 }
 
-function metricifyModule({ source, dependents, dependencies, instability }) {
-  return {
+/**
+ *
+ * @param {import("../../types/cruise-result.mjs").IModule} param0
+ * @returns
+ */
+function getMetricsFromModule({
+  source,
+  dependents,
+  dependencies,
+  instability,
+  experimentalStats,
+}) {
+  const lReturnValue = {
+    type: "module",
     name: source,
     moduleCount: 1,
     afferentCouplings: dependents.length,
     efferentCouplings: dependencies.length,
     instability,
   };
+  if (experimentalStats) {
+    lReturnValue.size = experimentalStats.size;
+    lReturnValue.topLevelStatementCount =
+      experimentalStats.topLevelStatementCount;
+  }
+  return lReturnValue;
 }
 
 function metricsAreCalculable(pModule) {
-  return Object.prototype.hasOwnProperty.call(pModule, "instability");
+  return Object.hasOwn(pModule, "instability");
+}
+
+function componentIsCalculable(pComponent) {
+  return (
+    Number.isInteger(pComponent.moduleCount) && pComponent.moduleCount > -1
+  );
+}
+
+/**
+ *
+ * @param {{modules: import("../../types/cruise-result.mjs").IModule[]; folders: import("../../types/cruise-result.mjs").IFolder[];}} param0
+ * @param {smallIntegerWidth:number; largeIntegerWidth: number} param1
+ * @returns {ITableObject}
+ */
+// eslint-disable-next-line max-lines-per-function
+function transformToTableObject(
+  { modules, folders },
+  { smallIntegerWidth, largeIntegerWidth },
+) {
+  const lReturnValue = {
+    meta: new Map([
+      ["type", { width: 6, title: "type", format: "string" }],
+      ["name", { width: 0, title: "name", format: "string" }],
+      [
+        "moduleCount",
+        {
+          width: smallIntegerWidth,
+          title: "N",
+          format: "integer",
+        },
+      ],
+      [
+        "afferentCouplings",
+        {
+          width: smallIntegerWidth,
+          title: "Ca",
+          format: "integer",
+        },
+      ],
+      [
+        "efferentCouplings",
+        {
+          width: smallIntegerWidth,
+          title: "Ce",
+          format: "integer",
+        },
+      ],
+      [
+        "instability",
+        {
+          width: smallIntegerWidth,
+          title: "I (%)",
+          format: "percent",
+        },
+      ],
+      [
+        "size",
+        {
+          width: largeIntegerWidth,
+          title: "size",
+          format: "integer",
+        },
+      ],
+      [
+        "topLevelStatementCount",
+        {
+          width: smallIntegerWidth,
+          title: "#tls",
+          format: "integer",
+        },
+      ],
+    ]),
+    data: [],
+  };
+  lReturnValue.data = folders
+    .map(getMetricsFromFolder)
+    .concat(modules.filter(metricsAreCalculable).map(getMetricsFromModule))
+    .filter(componentIsCalculable);
+
+  const lMaxNameWidth = lReturnValue.data
+    .map(({ name }) => name.length)
+    .concat(lReturnValue.meta.get("name").title.length)
+    .sort((pLeft, pRight) => pLeft - pRight)
+    .pop();
+  lReturnValue.meta.get("name").width = lMaxNameWidth;
+
+  return lReturnValue;
 }
 
 function orderByNumber(pAttributeName) {
-  // eslint-disable-next-line security/detect-object-injection
-  return (pLeft, pRight) => pRight[pAttributeName] - pLeft[pAttributeName];
+  return (pLeft, pRight) =>
+    // eslint-disable-next-line security/detect-object-injection
+    (pRight[pAttributeName] || 0) - (pLeft[pAttributeName] || 0);
 }
 
 function orderByString(pAttributeName) {
@@ -67,43 +166,98 @@ function orderByString(pAttributeName) {
     // eslint-disable-next-line security/detect-object-injection
     pLeft[pAttributeName].localeCompare(pRight[pAttributeName]);
 }
+/**
+ * @param {IMeta} pMetaData
+ * @returns {string}
+ */
+function formatToTextHeader(pMetaData) {
+  return Array.from(pMetaData.values())
+    .map(({ title, width, format }) =>
+      format === "string" ? title.padEnd(width + 1) : title.padStart(width + 1),
+    )
+    .join(" ");
+}
 
-function componentIsCalculable(pComponent) {
-  return (
-    Number.isInteger(pComponent.moduleCount) && pComponent.moduleCount > -1
-  );
+/**
+ * @param {IMeta} pMetaData
+ * @returns {string}
+ */
+function formatToTextDemarcationLine(pMetaData) {
+  return Array.from(pMetaData.values())
+    .map(({ width }) => "-".repeat(width + 1))
+    .join(" ");
+}
+
+/**
+ * @param {IData[]} pData
+ * @param {IMeta} pMetaData
+ * @returns {string}
+ */
+function formatToTextData(pData, pMetaData) {
+  return pData
+    .map((pRow) => {
+      return Object.keys(pRow)
+        .map((pKey) => {
+          const lMeta = pMetaData.get(pKey);
+          if (lMeta.format === "string") {
+            // eslint-disable-next-line security/detect-object-injection
+            return pRow[pKey].padEnd(lMeta.width + 1);
+          }
+          if (lMeta.format === "percent") {
+            // eslint-disable-next-line security/detect-object-injection
+            return formatPercentage(pRow[pKey]).padStart(lMeta.width + 1);
+          }
+          // eslint-disable-next-line security/detect-object-injection
+          return Number.isInteger(pRow[pKey])
+            ? // eslint-disable-next-line security/detect-object-injection
+              formatNumber(pRow[pKey]).padStart(lMeta.width + 1)
+            : "".padStart(lMeta.width + 1);
+        })
+        .join(" ");
+    })
+    .join(EOL);
+}
+
+/**
+ * @param {IData[]} pData
+ * @param {IMeta} pMetaData
+ * @returns {string}
+ */
+function formatToTextTable(pData, pMetaData) {
+  return [chalk.bold(formatToTextHeader(pMetaData))]
+    .concat(formatToTextDemarcationLine(pMetaData))
+    .concat(formatToTextData(pData, pMetaData))
+    .join(EOL)
+    .concat(EOL);
 }
 
+/**
+ *
+ * @param {{modules: import("../../types/cruise-result.mjs").IModule[]; folders: import("../../types/cruise-result.mjs").IFolder[];}} param0
+ * @param {{orderBy: string; hideFolders: boolean; hideModules: boolean; experimentalStats: boolean;}} param1
+ * @returns {string}
+ */
 function transformMetricsToTable(
   { modules, folders },
-  { orderBy, hideFolders, hideModules }
+  { orderBy, hideFolders, hideModules },
 ) {
-  // TODO: should probably use a table module for this (i.e. text-table)
-  // to simplify this code
-  let lComponents = [];
-  lComponents = lComponents.concat(hideFolders ? [] : folders);
-  lComponents = lComponents.concat(
-    hideModules ? [] : modules.filter(metricsAreCalculable).map(metricifyModule)
+  /** @type {ITableObject} */
+  const lObject = transformToTableObject(
+    { modules, folders },
+    {
+      smallIntegerWidth: METRIC_WIDTH,
+      largeIntegerWidth: METRIC_WIDTH + METRIC_WIDTH,
+    },
   );
-  const lMaxNameWidth = lComponents
-    .map(({ name }) => name.length)
-    .concat(COMPONENT_HEADER.length)
-    .sort((pLeft, pRight) => pLeft - pRight)
-    .pop();
-
-  return [chalk.bold(getHeader(lMaxNameWidth))]
-    .concat(getDemarcationLine(lMaxNameWidth))
-    .concat(
-      getMetricsTable(
-        lComponents
-          .filter(componentIsCalculable)
-          .sort(orderByString("name"))
-          .sort(orderByNumber(orderBy || "instability")),
-        lMaxNameWidth
-      )
+  let lComponents = lObject.data
+    .filter(
+      (pComponent) =>
+        (!hideModules && pComponent.type === "module") ||
+        (!hideFolders && pComponent.type === "folder"),
     )
-    .join(EOL)
-    .concat(EOL);
+    .sort(orderByString("name"))
+    .sort(orderByNumber(orderBy || "instability"));
+  return formatToTextTable(lComponents, lObject.meta);
 }
 
 /**
diff --git a/src/report/utl/index.mjs b/src/report/utl/index.mjs
index ff4cc4b3..a385e881 100644
--- a/src/report/utl/index.mjs
+++ b/src/report/utl/index.mjs
@@ -7,6 +7,9 @@ export const formatPercentage = new Intl.NumberFormat(undefined, {
   style: "percent",
 }).format;
 
+// eslint-disable-next-line no-undefined
+export const formatNumber = new Intl.NumberFormat(undefined).format;
+
 export function formatViolation(
   pViolation,
   pViolationType2Formatter,
diff --git a/src/schema/configuration.schema.json b/src/schema/configuration.schema.json
index 7299bd1c..514d78ad 100644
--- a/src/schema/configuration.schema.json
+++ b/src/schema/configuration.schema.json
@@ -845,7 +845,9 @@
             "moduleCount",
             "afferentCouplings",
             "efferentCouplings",
-            "name"
+            "name",
+            "size",
+            "topLevelStatementCount"
           ],
           "description": "By what attribute (in addition to the names of the folders/ modules) to order the metrics by. Defaults to 'instability'."
         },
diff --git a/src/schema/configuration.schema.mjs b/src/schema/configuration.schema.mjs
index 04e49547..ee9b9f78 100644
--- a/src/schema/configuration.schema.mjs
+++ b/src/schema/configuration.schema.mjs
@@ -1,1 +1,1 @@
-/* generated - don't edit */export default {"title":"dependency-cruiser configuration","$schema":"http://json-schema.org/draft-07/schema#","$id":"https://dependency-cruiser.js.org/schema/configuration.schema.json","type":"object","additionalProperties":false,"properties":{"$schema":{"type":"string"},"forbidden":{"type":"array","items":{"$ref":"#/definitions/ForbiddenRuleType"}},"allowed":{"type":"array","items":{"$ref":"#/definitions/AllowedRuleType"}},"allowedSeverity":{"$ref":"#/definitions/SeverityType"},"required":{"type":"array","items":{"$ref":"#/definitions/RequiredRuleType"}},"options":{"$ref":"#/definitions/OptionsType"},"extends":{"$ref":"#/definitions/ExtendsType"}},"definitions":{"RuleSetType":{"type":"object","additionalProperties":false,"properties":{"forbidden":{"type":"array","items":{"$ref":"#/definitions/ForbiddenRuleType"}},"allowed":{"type":"array","items":{"$ref":"#/definitions/AllowedRuleType"}},"allowedSeverity":{"$ref":"#/definitions/SeverityType"},"required":{"type":"array","items":{"$ref":"#/definitions/RequiredRuleType"}}}},"AllowedRuleType":{"oneOf":[{"$ref":"#/definitions/RegularAllowedRuleType"},{"$ref":"#/definitions/ReachabilityAllowedRuleType"}]},"RegularAllowedRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"comment":{"type":"string"},"scope":{"type":"string","enum":["module","folder"]},"from":{"$ref":"#/definitions/FromRestrictionType"},"to":{"$ref":"#/definitions/ToRestrictionType"}}},"ReachabilityAllowedRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"comment":{"type":"string"},"scope":{"type":"string","enum":["module","folder"]},"from":{"$ref":"#/definitions/ReachabilityFromRestrictionType"},"to":{"$ref":"#/definitions/ReachabilityToRestrictionType"}}},"ForbiddenRuleType":{"oneOf":[{"$ref":"#/definitions/RegularForbiddenRuleType"},{"$ref":"#/definitions/ReachabilityForbiddenRuleType"},{"$ref":"#/definitions/DependentsForbiddenRuleType"}]},"RegularForbiddenRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"from":{"$ref":"#/definitions/FromRestrictionType"},"to":{"$ref":"#/definitions/ToRestrictionType"}}},"DependentsForbiddenRuleType":{"type":"object","required":["module","from"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"module":{"$ref":"#/definitions/DependentsModuleRestrictionType"},"from":{"$ref":"#/definitions/DependentsFromRestrictionType"}}},"ReachabilityForbiddenRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"from":{"$ref":"#/definitions/ReachabilityFromRestrictionType"},"to":{"$ref":"#/definitions/ReachabilityToRestrictionType"}}},"RequiredRuleType":{"type":"object","required":["module","to"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"module":{"$ref":"#/definitions/RequiredModuleRestrictionType"},"to":{"$ref":"#/definitions/RequiredToRestrictionType"}}},"MiniDependencyRestrictionType":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"dependencyTypesNot":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}}}}]},"FromRestrictionType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"orphan":{"type":"boolean"}}},"ReachabilityFromRestrictionType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"}}},"ToRestrictionType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"couldNotResolve":{"type":"boolean"},"circular":{"type":"boolean"},"dynamic":{"type":"boolean"},"exoticallyRequired":{"type":"boolean"},"exoticRequire":{"$ref":"#/definitions/REAsStringsType"},"exoticRequireNot":{"$ref":"#/definitions/REAsStringsType"},"preCompilationOnly":{"type":"boolean"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"dependencyTypesNot":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"moreThanOneDependencyType":{"type":"boolean"},"license":{"$ref":"#/definitions/REAsStringsType"},"licenseNot":{"$ref":"#/definitions/REAsStringsType"},"via":{"$ref":"#/definitions/MiniDependencyRestrictionType"},"viaOnly":{"$ref":"#/definitions/MiniDependencyRestrictionType"},"viaNot":{"deprecated":true,"$ref":"#/definitions/REAsStringsType"},"viaSomeNot":{"deprecated":true,"$ref":"#/definitions/REAsStringsType"},"moreUnstable":{"type":"boolean"}}},"DependentsModuleRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"numberOfDependentsLessThan":{"type":"integer","minimum":0,"maximum":100},"numberOfDependentsMoreThan":{"type":"integer","minimum":0,"maximum":100}}},"DependentsFromRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"}}},"ReachabilityToRestrictionType":{"required":["reachable"],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"reachable":{"type":"boolean"}}},"RequiredModuleRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"}}},"RequiredToRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"DependencyTypeType":{"type":"string","enum":["aliased-subpath-import","aliased-tsconfig-base-url","aliased-tsconfig-paths","aliased-tsconfig","aliased-webpack","aliased-workspace","aliased","amd-define","amd-require","amd-exotic-require","core","deprecated","dynamic-import","exotic-require","export","import-equals","import","local","localmodule","npm-bundled","npm-dev","npm-no-pkg","npm-optional","npm-peer","npm-unknown","npm","pre-compilation-only","require","triple-slash-amd-dependency","triple-slash-directive","triple-slash-file-reference","triple-slash-type-reference","type-import","type-only","undetermined","unknown"]},"REAsStringsType":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"SeverityType":{"type":"string","enum":["error","warn","info","ignore"]},"OptionsType":{"type":"object","additionalProperties":false,"properties":{"doNotFollow":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundDoNotFollowType"}]},"exclude":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundExcludeType"}]},"includeOnly":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundIncludeOnlyType"}]},"focus":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundFocusType"}]},"reaches":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundReachesType"}]},"highlight":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundHighlightType"}]},"knownViolations":{"$ref":"#/definitions/ViolationsType"},"collapse":{"oneOf":[{"type":"string"},{"type":"integer","minimum":1,"maximum":9}]},"maxDepth":{"type":"integer","minimum":0,"maximum":99},"moduleSystems":{"$ref":"#/definitions/ModuleSystemsType"},"prefix":{"type":"string"},"preserveSymlinks":{"type":"boolean"},"combinedDependencies":{"type":"boolean"},"tsConfig":{"type":"object","additionalProperties":false,"properties":{"fileName":{"type":"string"}}},"tsPreCompilationDeps":{"oneOf":[{"type":"boolean"},{"type":"string","enum":["specify"]}]},"extraExtensionsToScan":{"type":"array","items":{"type":"string"}},"externalModuleResolutionStrategy":{"type":"string","enum":["node_modules","yarn-pnp"]},"builtInModules":{"type":"object","additionalProperties":false,"properties":{"override":{"type":"array","items":{"type":"string"}},"add":{"type":"array","items":{"type":"string"}}}},"forceDeriveDependents":{"type":"boolean"},"webpackConfig":{"type":"object","additionalProperties":false,"properties":{"fileName":{"type":"string"},"env":{"oneOf":[{"type":"object"},{"type":"string"}]},"arguments":{"type":"object"}}},"enhancedResolveOptions":{"type":"object","additionalProperties":false,"properties":{"exportsFields":{"type":"array","items":{"type":"string"}},"conditionNames":{"type":"array","items":{"type":"string"}},"extensions":{"type":"array","items":{"type":"string"}},"mainFields":{"type":"array","items":{"type":"string"}},"mainFiles":{"type":"array"},"aliasFields":{"type":"array","items":{"type":"string"}},"cachedInputFileSystem":{"type":"object","additionalProperties":false,"properties":{"cacheDuration":{"type":"integer","minimum":0,"maximum":1800000}}}}},"babelConfig":{"type":"object","additionalProperties":false,"properties":{"fileName":{"type":"string"}}},"parser":{"type":"string","enum":["acorn","tsc","swc"]},"exoticRequireStrings":{"type":"array","items":{"type":"string"}},"reporterOptions":{"$ref":"#/definitions/ReporterOptionsType"},"progress":{"type":"object","additionalProperties":false,"properties":{"type":{"type":"string","enum":["cli-feedback","performance-log","ndjson","none"]},"maximumLevel":{"type":"number","enum":[-1,40,50,60,70,80,99]}}},"metrics":{"type":"boolean"},"experimentalStats":{"type":"boolean"},"baseDir":{"type":"string"},"cache":{"oneOf":[{"type":"boolean"},{"deprecated":true,"type":"string"},{"$ref":"#/definitions/CacheOptionsType"}]}}},"ModuleSystemType":{"type":"string","enum":["cjs","es6","amd","tsd"]},"ModuleSystemsType":{"type":"array","items":{"$ref":"#/definitions/ModuleSystemType"}},"CompoundExcludeType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"dynamic":{"type":"boolean"}}},"CompoundDoNotFollowType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}}}},"CompoundIncludeOnlyType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"CompoundFocusType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"depth":{"type":"number","minimum":1,"maximum":4}}},"CompoundReachesType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"CompoundHighlightType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"ReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"anon":{"$ref":"#/definitions/AnonReporterOptionsType"},"archi":{"$ref":"#/definitions/DotReporterOptionsType"},"dot":{"$ref":"#/definitions/DotReporterOptionsType"},"ddot":{"$ref":"#/definitions/DotReporterOptionsType"},"flat":{"$ref":"#/definitions/DotReporterOptionsType"},"markdown":{"$ref":"#/definitions/MarkdownReporterOptionsType"},"metrics":{"$ref":"#/definitions/MetricsReporterOptionsType"},"mermaid":{"$ref":"#/definitions/MermaidReporterOptionsType"},"text":{"$ref":"#/definitions/TextReporterOptionsType"}}},"AnonReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"wordlist":{"type":"array","items":{"type":"string"}}}},"MetricsReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"orderBy":{"type":"string","enum":["instability","moduleCount","afferentCouplings","efferentCouplings","name"]},"hideModules":{"type":"boolean"},"hideFolders":{"type":"boolean"}}},"MarkdownReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"showTitle":{"type":"boolean"},"title":{"type":"string"},"showSummary":{"type":"boolean"},"showSummaryHeader":{"type":"boolean"},"summaryHeader":{"type":"string"},"showStatsSummary":{"type":"boolean"},"showRulesSummary":{"type":"boolean"},"includeIgnoredInSummary":{"type":"boolean"},"showDetails":{"type":"boolean"},"includeIgnoredInDetails":{"type":"boolean"},"showDetailsHeader":{"type":"boolean"},"detailsHeader":{"type":"string"},"collapseDetails":{"type":"boolean"},"collapsedMessage":{"type":"string"},"noViolationsMessage":{"type":"string"},"showFooter":{"type":"boolean"}}},"MermaidReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"minify":{"type":"boolean"}}},"TextReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"highlightFocused":{"type":"boolean"}}},"DotReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"collapsePattern":{"$ref":"#/definitions/REAsStringsType"},"filters":{"$ref":"#/definitions/ReporterFiltersType"},"showMetrics":{"type":"boolean"},"theme":{"$ref":"#/definitions/DotThemeType"}}},"DotThemeType":{"type":"object","additionalProperties":false,"properties":{"replace":{"type":"boolean"},"graph":{"type":"object"},"node":{"type":"object"},"edge":{"type":"object"},"modules":{"$ref":"#/definitions/DotThemeArrayType"},"dependencies":{"$ref":"#/definitions/DotThemeArrayType"}}},"DotThemeArrayType":{"type":"array","items":{"$ref":"#/definitions/DotThemeEntryType"}},"DotThemeEntryType":{"type":"object","additionalProperties":false,"properties":{"criteria":{"type":"object"},"attributes":{"type":"object"}}},"ReporterFiltersType":{"type":"object","additionalProperties":false,"properties":{"exclude":{"$ref":"#/definitions/CompoundExcludeType"},"includeOnly":{"$ref":"#/definitions/CompoundIncludeOnlyType"},"focus":{"$ref":"#/definitions/CompoundFocusType"},"reaches":{"$ref":"#/definitions/CompoundReachesType"}}},"ViolationsType":{"type":"array","items":{"$ref":"#/definitions/ViolationType"}},"ViolationType":{"type":"object","required":["from","to","rule"],"additionalProperties":false,"properties":{"from":{"type":"string"},"to":{"type":"string"},"type":{"$ref":"#/definitions/ViolationTypeType"},"rule":{"$ref":"#/definitions/RuleSummaryType"},"cycle":{"type":"array","items":{"$ref":"#/definitions/MiniDependency"}},"via":{"type":"array","items":{"$ref":"#/definitions/MiniDependency"}},"metrics":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"from":{"type":"object","required":["instability"],"additionalProperties":false,"properties":{"instability":{"type":"number"}}},"to":{"type":"object","required":["instability"],"additionalProperties":false,"properties":{"instability":{"type":"number"}}}}},"comment":{"type":"string"}}},"RuleSummaryType":{"type":"object","required":["name","severity"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"}}},"ViolationTypeType":{"type":"string","enum":["dependency","module","reachability","cycle","instability","folder"]},"MiniDependency":{"type":"object","required":["name","dependencyTypes"],"additionalProperties":false,"properties":{"name":{"type":"string"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}}}},"CacheOptionsType":{"type":"object","additionalProperties":false,"properties":{"folder":{"type":"string"},"strategy":{"$ref":"#/definitions/CacheStrategyType"},"compress":{"type":"boolean","default":false}}},"CacheStrategyType":{"type":"string","enum":["metadata","content"]},"ExtendsType":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]}}}
\ No newline at end of file
+/* generated - don't edit */export default {"title":"dependency-cruiser configuration","$schema":"http://json-schema.org/draft-07/schema#","$id":"https://dependency-cruiser.js.org/schema/configuration.schema.json","type":"object","additionalProperties":false,"properties":{"$schema":{"type":"string"},"forbidden":{"type":"array","items":{"$ref":"#/definitions/ForbiddenRuleType"}},"allowed":{"type":"array","items":{"$ref":"#/definitions/AllowedRuleType"}},"allowedSeverity":{"$ref":"#/definitions/SeverityType"},"required":{"type":"array","items":{"$ref":"#/definitions/RequiredRuleType"}},"options":{"$ref":"#/definitions/OptionsType"},"extends":{"$ref":"#/definitions/ExtendsType"}},"definitions":{"RuleSetType":{"type":"object","additionalProperties":false,"properties":{"forbidden":{"type":"array","items":{"$ref":"#/definitions/ForbiddenRuleType"}},"allowed":{"type":"array","items":{"$ref":"#/definitions/AllowedRuleType"}},"allowedSeverity":{"$ref":"#/definitions/SeverityType"},"required":{"type":"array","items":{"$ref":"#/definitions/RequiredRuleType"}}}},"AllowedRuleType":{"oneOf":[{"$ref":"#/definitions/RegularAllowedRuleType"},{"$ref":"#/definitions/ReachabilityAllowedRuleType"}]},"RegularAllowedRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"comment":{"type":"string"},"scope":{"type":"string","enum":["module","folder"]},"from":{"$ref":"#/definitions/FromRestrictionType"},"to":{"$ref":"#/definitions/ToRestrictionType"}}},"ReachabilityAllowedRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"comment":{"type":"string"},"scope":{"type":"string","enum":["module","folder"]},"from":{"$ref":"#/definitions/ReachabilityFromRestrictionType"},"to":{"$ref":"#/definitions/ReachabilityToRestrictionType"}}},"ForbiddenRuleType":{"oneOf":[{"$ref":"#/definitions/RegularForbiddenRuleType"},{"$ref":"#/definitions/ReachabilityForbiddenRuleType"},{"$ref":"#/definitions/DependentsForbiddenRuleType"}]},"RegularForbiddenRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"from":{"$ref":"#/definitions/FromRestrictionType"},"to":{"$ref":"#/definitions/ToRestrictionType"}}},"DependentsForbiddenRuleType":{"type":"object","required":["module","from"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"module":{"$ref":"#/definitions/DependentsModuleRestrictionType"},"from":{"$ref":"#/definitions/DependentsFromRestrictionType"}}},"ReachabilityForbiddenRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"from":{"$ref":"#/definitions/ReachabilityFromRestrictionType"},"to":{"$ref":"#/definitions/ReachabilityToRestrictionType"}}},"RequiredRuleType":{"type":"object","required":["module","to"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"module":{"$ref":"#/definitions/RequiredModuleRestrictionType"},"to":{"$ref":"#/definitions/RequiredToRestrictionType"}}},"MiniDependencyRestrictionType":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"dependencyTypesNot":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}}}}]},"FromRestrictionType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"orphan":{"type":"boolean"}}},"ReachabilityFromRestrictionType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"}}},"ToRestrictionType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"couldNotResolve":{"type":"boolean"},"circular":{"type":"boolean"},"dynamic":{"type":"boolean"},"exoticallyRequired":{"type":"boolean"},"exoticRequire":{"$ref":"#/definitions/REAsStringsType"},"exoticRequireNot":{"$ref":"#/definitions/REAsStringsType"},"preCompilationOnly":{"type":"boolean"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"dependencyTypesNot":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"moreThanOneDependencyType":{"type":"boolean"},"license":{"$ref":"#/definitions/REAsStringsType"},"licenseNot":{"$ref":"#/definitions/REAsStringsType"},"via":{"$ref":"#/definitions/MiniDependencyRestrictionType"},"viaOnly":{"$ref":"#/definitions/MiniDependencyRestrictionType"},"viaNot":{"deprecated":true,"$ref":"#/definitions/REAsStringsType"},"viaSomeNot":{"deprecated":true,"$ref":"#/definitions/REAsStringsType"},"moreUnstable":{"type":"boolean"}}},"DependentsModuleRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"numberOfDependentsLessThan":{"type":"integer","minimum":0,"maximum":100},"numberOfDependentsMoreThan":{"type":"integer","minimum":0,"maximum":100}}},"DependentsFromRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"}}},"ReachabilityToRestrictionType":{"required":["reachable"],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"reachable":{"type":"boolean"}}},"RequiredModuleRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"}}},"RequiredToRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"DependencyTypeType":{"type":"string","enum":["aliased-subpath-import","aliased-tsconfig-base-url","aliased-tsconfig-paths","aliased-tsconfig","aliased-webpack","aliased-workspace","aliased","amd-define","amd-require","amd-exotic-require","core","deprecated","dynamic-import","exotic-require","export","import-equals","import","local","localmodule","npm-bundled","npm-dev","npm-no-pkg","npm-optional","npm-peer","npm-unknown","npm","pre-compilation-only","require","triple-slash-amd-dependency","triple-slash-directive","triple-slash-file-reference","triple-slash-type-reference","type-import","type-only","undetermined","unknown"]},"REAsStringsType":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"SeverityType":{"type":"string","enum":["error","warn","info","ignore"]},"OptionsType":{"type":"object","additionalProperties":false,"properties":{"doNotFollow":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundDoNotFollowType"}]},"exclude":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundExcludeType"}]},"includeOnly":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundIncludeOnlyType"}]},"focus":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundFocusType"}]},"reaches":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundReachesType"}]},"highlight":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundHighlightType"}]},"knownViolations":{"$ref":"#/definitions/ViolationsType"},"collapse":{"oneOf":[{"type":"string"},{"type":"integer","minimum":1,"maximum":9}]},"maxDepth":{"type":"integer","minimum":0,"maximum":99},"moduleSystems":{"$ref":"#/definitions/ModuleSystemsType"},"prefix":{"type":"string"},"preserveSymlinks":{"type":"boolean"},"combinedDependencies":{"type":"boolean"},"tsConfig":{"type":"object","additionalProperties":false,"properties":{"fileName":{"type":"string"}}},"tsPreCompilationDeps":{"oneOf":[{"type":"boolean"},{"type":"string","enum":["specify"]}]},"extraExtensionsToScan":{"type":"array","items":{"type":"string"}},"externalModuleResolutionStrategy":{"type":"string","enum":["node_modules","yarn-pnp"]},"builtInModules":{"type":"object","additionalProperties":false,"properties":{"override":{"type":"array","items":{"type":"string"}},"add":{"type":"array","items":{"type":"string"}}}},"forceDeriveDependents":{"type":"boolean"},"webpackConfig":{"type":"object","additionalProperties":false,"properties":{"fileName":{"type":"string"},"env":{"oneOf":[{"type":"object"},{"type":"string"}]},"arguments":{"type":"object"}}},"enhancedResolveOptions":{"type":"object","additionalProperties":false,"properties":{"exportsFields":{"type":"array","items":{"type":"string"}},"conditionNames":{"type":"array","items":{"type":"string"}},"extensions":{"type":"array","items":{"type":"string"}},"mainFields":{"type":"array","items":{"type":"string"}},"mainFiles":{"type":"array"},"aliasFields":{"type":"array","items":{"type":"string"}},"cachedInputFileSystem":{"type":"object","additionalProperties":false,"properties":{"cacheDuration":{"type":"integer","minimum":0,"maximum":1800000}}}}},"babelConfig":{"type":"object","additionalProperties":false,"properties":{"fileName":{"type":"string"}}},"parser":{"type":"string","enum":["acorn","tsc","swc"]},"exoticRequireStrings":{"type":"array","items":{"type":"string"}},"reporterOptions":{"$ref":"#/definitions/ReporterOptionsType"},"progress":{"type":"object","additionalProperties":false,"properties":{"type":{"type":"string","enum":["cli-feedback","performance-log","ndjson","none"]},"maximumLevel":{"type":"number","enum":[-1,40,50,60,70,80,99]}}},"metrics":{"type":"boolean"},"experimentalStats":{"type":"boolean"},"baseDir":{"type":"string"},"cache":{"oneOf":[{"type":"boolean"},{"deprecated":true,"type":"string"},{"$ref":"#/definitions/CacheOptionsType"}]}}},"ModuleSystemType":{"type":"string","enum":["cjs","es6","amd","tsd"]},"ModuleSystemsType":{"type":"array","items":{"$ref":"#/definitions/ModuleSystemType"}},"CompoundExcludeType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"dynamic":{"type":"boolean"}}},"CompoundDoNotFollowType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}}}},"CompoundIncludeOnlyType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"CompoundFocusType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"depth":{"type":"number","minimum":1,"maximum":4}}},"CompoundReachesType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"CompoundHighlightType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"ReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"anon":{"$ref":"#/definitions/AnonReporterOptionsType"},"archi":{"$ref":"#/definitions/DotReporterOptionsType"},"dot":{"$ref":"#/definitions/DotReporterOptionsType"},"ddot":{"$ref":"#/definitions/DotReporterOptionsType"},"flat":{"$ref":"#/definitions/DotReporterOptionsType"},"markdown":{"$ref":"#/definitions/MarkdownReporterOptionsType"},"metrics":{"$ref":"#/definitions/MetricsReporterOptionsType"},"mermaid":{"$ref":"#/definitions/MermaidReporterOptionsType"},"text":{"$ref":"#/definitions/TextReporterOptionsType"}}},"AnonReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"wordlist":{"type":"array","items":{"type":"string"}}}},"MetricsReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"orderBy":{"type":"string","enum":["instability","moduleCount","afferentCouplings","efferentCouplings","name","size","topLevelStatementCount"]},"hideModules":{"type":"boolean"},"hideFolders":{"type":"boolean"}}},"MarkdownReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"showTitle":{"type":"boolean"},"title":{"type":"string"},"showSummary":{"type":"boolean"},"showSummaryHeader":{"type":"boolean"},"summaryHeader":{"type":"string"},"showStatsSummary":{"type":"boolean"},"showRulesSummary":{"type":"boolean"},"includeIgnoredInSummary":{"type":"boolean"},"showDetails":{"type":"boolean"},"includeIgnoredInDetails":{"type":"boolean"},"showDetailsHeader":{"type":"boolean"},"detailsHeader":{"type":"string"},"collapseDetails":{"type":"boolean"},"collapsedMessage":{"type":"string"},"noViolationsMessage":{"type":"string"},"showFooter":{"type":"boolean"}}},"MermaidReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"minify":{"type":"boolean"}}},"TextReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"highlightFocused":{"type":"boolean"}}},"DotReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"collapsePattern":{"$ref":"#/definitions/REAsStringsType"},"filters":{"$ref":"#/definitions/ReporterFiltersType"},"showMetrics":{"type":"boolean"},"theme":{"$ref":"#/definitions/DotThemeType"}}},"DotThemeType":{"type":"object","additionalProperties":false,"properties":{"replace":{"type":"boolean"},"graph":{"type":"object"},"node":{"type":"object"},"edge":{"type":"object"},"modules":{"$ref":"#/definitions/DotThemeArrayType"},"dependencies":{"$ref":"#/definitions/DotThemeArrayType"}}},"DotThemeArrayType":{"type":"array","items":{"$ref":"#/definitions/DotThemeEntryType"}},"DotThemeEntryType":{"type":"object","additionalProperties":false,"properties":{"criteria":{"type":"object"},"attributes":{"type":"object"}}},"ReporterFiltersType":{"type":"object","additionalProperties":false,"properties":{"exclude":{"$ref":"#/definitions/CompoundExcludeType"},"includeOnly":{"$ref":"#/definitions/CompoundIncludeOnlyType"},"focus":{"$ref":"#/definitions/CompoundFocusType"},"reaches":{"$ref":"#/definitions/CompoundReachesType"}}},"ViolationsType":{"type":"array","items":{"$ref":"#/definitions/ViolationType"}},"ViolationType":{"type":"object","required":["from","to","rule"],"additionalProperties":false,"properties":{"from":{"type":"string"},"to":{"type":"string"},"type":{"$ref":"#/definitions/ViolationTypeType"},"rule":{"$ref":"#/definitions/RuleSummaryType"},"cycle":{"type":"array","items":{"$ref":"#/definitions/MiniDependency"}},"via":{"type":"array","items":{"$ref":"#/definitions/MiniDependency"}},"metrics":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"from":{"type":"object","required":["instability"],"additionalProperties":false,"properties":{"instability":{"type":"number"}}},"to":{"type":"object","required":["instability"],"additionalProperties":false,"properties":{"instability":{"type":"number"}}}}},"comment":{"type":"string"}}},"RuleSummaryType":{"type":"object","required":["name","severity"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"}}},"ViolationTypeType":{"type":"string","enum":["dependency","module","reachability","cycle","instability","folder"]},"MiniDependency":{"type":"object","required":["name","dependencyTypes"],"additionalProperties":false,"properties":{"name":{"type":"string"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}}}},"CacheOptionsType":{"type":"object","additionalProperties":false,"properties":{"folder":{"type":"string"},"strategy":{"$ref":"#/definitions/CacheStrategyType"},"compress":{"type":"boolean","default":false}}},"CacheStrategyType":{"type":"string","enum":["metadata","content"]},"ExtendsType":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]}}}
\ No newline at end of file
diff --git a/src/schema/cruise-result.schema.json b/src/schema/cruise-result.schema.json
index ef9c306f..db33a34b 100644
--- a/src/schema/cruise-result.schema.json
+++ b/src/schema/cruise-result.schema.json
@@ -1311,7 +1311,9 @@
             "moduleCount",
             "afferentCouplings",
             "efferentCouplings",
-            "name"
+            "name",
+            "size",
+            "topLevelStatementCount"
           ],
           "description": "By what attribute (in addition to the names of the folders/ modules) to order the metrics by. Defaults to 'instability'."
         },
diff --git a/src/schema/cruise-result.schema.mjs b/src/schema/cruise-result.schema.mjs
index a761fe91..86b4a625 100644
--- a/src/schema/cruise-result.schema.mjs
+++ b/src/schema/cruise-result.schema.mjs
@@ -1,1 +1,1 @@
-/* generated - don't edit */export default {"title":"dependency-cruiser output format","$schema":"http://json-schema.org/draft-07/schema#","$id":"https://dependency-cruiser.js.org/schema/cruise-result.schema.json","type":"object","required":["summary","modules"],"additionalProperties":false,"properties":{"modules":{"$ref":"#/definitions/ModulesType"},"folders":{"$ref":"#/definitions/FoldersType"},"summary":{"$ref":"#/definitions/SummaryType"},"revisionData":{"$ref":"#/definitions/RevisionDataType"}},"definitions":{"ModulesType":{"type":"array","items":{"$ref":"#/definitions/ModuleType"}},"ModuleType":{"type":"object","required":["source","dependencies","valid"],"additionalProperties":false,"properties":{"source":{"type":"string"},"valid":{"type":"boolean"},"dependencies":{"$ref":"#/definitions/DependenciesType"},"dependents":{"type":"array","items":{"type":"string"}},"followable":{"type":"boolean"},"matchesDoNotFollow":{"type":"boolean"},"matchesFocus":{"type":"boolean"},"matchesReaches":{"type":"boolean"},"matchesHighlight":{"type":"boolean"},"coreModule":{"type":"boolean"},"couldNotResolve":{"type":"boolean"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"license":{"type":"string"},"orphan":{"type":"boolean"},"reachable":{"type":"array","items":{"$ref":"#/definitions/ReachableType"}},"reaches":{"type":"array","items":{"$ref":"#/definitions/ReachesType"}},"rules":{"type":"array","items":{"$ref":"#/definitions/RuleSummaryType"}},"consolidated":{"type":"boolean"},"instability":{"type":"number"},"experimentalStats":{"$ref":"#/definitions/ExperimentalStatsType"},"checksum":{"type":"string"}}},"ReachableType":{"type":"object","required":["value","asDefinedInRule","matchedFrom"],"additionalProperties":false,"properties":{"value":{"type":"boolean"},"asDefinedInRule":{"type":"string"},"matchedFrom":{"type":"string"}}},"ReachesType":{"type":"object","required":["modules","asDefinedInRule"],"additionalProperties":false,"properties":{"modules":{"type":"array","items":{"type":"object","required":["source","via"],"additionalProperties":false,"properties":{"source":{"type":"string"},"via":{"type":"array","items":{"$ref":"#/definitions/MiniDependency"}}}}},"asDefinedInRule":{"type":"string"}}},"DependenciesType":{"type":"array","items":{"$ref":"#/definitions/DependencyType"}},"DependencyType":{"type":"object","required":["circular","coreModule","couldNotResolve","dependencyTypes","exoticallyRequired","dynamic","followable","module","moduleSystem","resolved","valid"],"additionalProperties":false,"properties":{"module":{"type":"string"},"protocol":{"type":"string","enum":["data:","file:","node:"]},"mimeType":{"type":"string"},"resolved":{"type":"string"},"coreModule":{"type":"boolean"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"license":{"type":"string"},"followable":{"type":"boolean"},"dynamic":{"type":"boolean"},"exoticallyRequired":{"type":"boolean"},"exoticRequire":{"type":"string"},"matchesDoNotFollow":{"type":"boolean"},"couldNotResolve":{"type":"boolean"},"preCompilationOnly":{"type":"boolean"},"typeOnly":{"type":"boolean"},"circular":{"type":"boolean"},"cycle":{"type":"array","items":{"$ref":"#/definitions/MiniDependency"}},"moduleSystem":{"$ref":"#/definitions/ModuleSystemType"},"valid":{"type":"boolean"},"rules":{"type":"array","items":{"$ref":"#/definitions/RuleSummaryType"}},"instability":{"type":"number"}}},"DependencyTypeType":{"type":"string","enum":["aliased-subpath-import","aliased-tsconfig-base-url","aliased-tsconfig-paths","aliased-tsconfig","aliased-webpack","aliased-workspace","aliased","amd-define","amd-require","amd-exotic-require","core","deprecated","dynamic-import","exotic-require","export","import-equals","import","local","localmodule","npm-bundled","npm-dev","npm-no-pkg","npm-optional","npm-peer","npm-unknown","npm","pre-compilation-only","require","triple-slash-amd-dependency","triple-slash-directive","triple-slash-file-reference","triple-slash-type-reference","type-import","type-only","undetermined","unknown"]},"ModuleSystemType":{"type":"string","enum":["cjs","es6","amd","tsd"]},"RuleSummaryType":{"type":"object","required":["name","severity"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"}}},"SeverityType":{"type":"string","enum":["error","warn","info","ignore"]},"MiniDependency":{"type":"object","required":["name","dependencyTypes"],"additionalProperties":false,"properties":{"name":{"type":"string"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}}}},"ExperimentalStatsType":{"type":"object","required":["size","topLevelStatementCount"],"additionalProperties":false,"properties":{"topLevelStatementCount":{"type":"number"},"size":{"type":"number"}}},"FoldersType":{"type":"array","items":{"$ref":"#/definitions/FolderType"}},"FolderType":{"type":"object","required":["name","moduleCount"],"additionalProperties":false,"properties":{"name":{"type":"string"},"dependents":{"type":"array","items":{"type":"object","required":["name"],"additionalProperties":false,"properties":{"name":{"type":"string"}}}},"dependencies":{"type":"array","items":{"type":"object","required":["name","valid","circular"],"additionalProperties":false,"properties":{"name":{"type":"string"},"instability":{"type":"number"},"valid":{"type":"boolean"},"circular":{"type":"boolean"},"cycle":{"type":"array","items":{"$ref":"#/definitions/MiniDependency"}},"rules":{"type":"array","items":{"$ref":"#/definitions/RuleSummaryType"}}}}},"moduleCount":{"type":"number"},"afferentCouplings":{"type":"number"},"efferentCouplings":{"type":"number"},"instability":{"type":"number"},"experimentalStats":{"$ref":"#/definitions/ExperimentalStatsType"}}},"SummaryType":{"type":"object","required":["violations","error","warn","info","totalCruised","optionsUsed"],"additionalProperties":false,"properties":{"violations":{"$ref":"#/definitions/ViolationsType"},"error":{"type":"number"},"warn":{"type":"number"},"info":{"type":"number"},"ignore":{"type":"number"},"totalCruised":{"type":"number"},"totalDependenciesCruised":{"type":"number"},"ruleSetUsed":{"$ref":"#/definitions/RuleSetType"},"optionsUsed":{"$ref":"#/definitions/OptionsUsedType"}}},"ViolationsType":{"type":"array","items":{"$ref":"#/definitions/ViolationType"}},"ViolationType":{"type":"object","required":["from","to","rule"],"additionalProperties":false,"properties":{"from":{"type":"string"},"to":{"type":"string"},"type":{"$ref":"#/definitions/ViolationTypeType"},"rule":{"$ref":"#/definitions/RuleSummaryType"},"cycle":{"type":"array","items":{"$ref":"#/definitions/MiniDependency"}},"via":{"type":"array","items":{"$ref":"#/definitions/MiniDependency"}},"metrics":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"from":{"type":"object","required":["instability"],"additionalProperties":false,"properties":{"instability":{"type":"number"}}},"to":{"type":"object","required":["instability"],"additionalProperties":false,"properties":{"instability":{"type":"number"}}}}},"comment":{"type":"string"}}},"ViolationTypeType":{"type":"string","enum":["dependency","module","reachability","cycle","instability","folder"]},"RuleSetType":{"type":"object","additionalProperties":false,"properties":{"forbidden":{"type":"array","items":{"$ref":"#/definitions/ForbiddenRuleType"}},"allowed":{"type":"array","items":{"$ref":"#/definitions/AllowedRuleType"}},"allowedSeverity":{"$ref":"#/definitions/SeverityType"},"required":{"type":"array","items":{"$ref":"#/definitions/RequiredRuleType"}}}},"AllowedRuleType":{"oneOf":[{"$ref":"#/definitions/RegularAllowedRuleType"},{"$ref":"#/definitions/ReachabilityAllowedRuleType"}]},"RegularAllowedRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"comment":{"type":"string"},"scope":{"type":"string","enum":["module","folder"]},"from":{"$ref":"#/definitions/FromRestrictionType"},"to":{"$ref":"#/definitions/ToRestrictionType"}}},"ReachabilityAllowedRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"comment":{"type":"string"},"scope":{"type":"string","enum":["module","folder"]},"from":{"$ref":"#/definitions/ReachabilityFromRestrictionType"},"to":{"$ref":"#/definitions/ReachabilityToRestrictionType"}}},"ForbiddenRuleType":{"oneOf":[{"$ref":"#/definitions/RegularForbiddenRuleType"},{"$ref":"#/definitions/ReachabilityForbiddenRuleType"},{"$ref":"#/definitions/DependentsForbiddenRuleType"}]},"RegularForbiddenRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"from":{"$ref":"#/definitions/FromRestrictionType"},"to":{"$ref":"#/definitions/ToRestrictionType"}}},"DependentsForbiddenRuleType":{"type":"object","required":["module","from"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"module":{"$ref":"#/definitions/DependentsModuleRestrictionType"},"from":{"$ref":"#/definitions/DependentsFromRestrictionType"}}},"ReachabilityForbiddenRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"from":{"$ref":"#/definitions/ReachabilityFromRestrictionType"},"to":{"$ref":"#/definitions/ReachabilityToRestrictionType"}}},"RequiredRuleType":{"type":"object","required":["module","to"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"module":{"$ref":"#/definitions/RequiredModuleRestrictionType"},"to":{"$ref":"#/definitions/RequiredToRestrictionType"}}},"MiniDependencyRestrictionType":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"dependencyTypesNot":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}}}}]},"FromRestrictionType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"orphan":{"type":"boolean"}}},"ReachabilityFromRestrictionType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"}}},"ToRestrictionType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"couldNotResolve":{"type":"boolean"},"circular":{"type":"boolean"},"dynamic":{"type":"boolean"},"exoticallyRequired":{"type":"boolean"},"exoticRequire":{"$ref":"#/definitions/REAsStringsType"},"exoticRequireNot":{"$ref":"#/definitions/REAsStringsType"},"preCompilationOnly":{"type":"boolean"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"dependencyTypesNot":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"moreThanOneDependencyType":{"type":"boolean"},"license":{"$ref":"#/definitions/REAsStringsType"},"licenseNot":{"$ref":"#/definitions/REAsStringsType"},"via":{"$ref":"#/definitions/MiniDependencyRestrictionType"},"viaOnly":{"$ref":"#/definitions/MiniDependencyRestrictionType"},"viaNot":{"deprecated":true,"$ref":"#/definitions/REAsStringsType"},"viaSomeNot":{"deprecated":true,"$ref":"#/definitions/REAsStringsType"},"moreUnstable":{"type":"boolean"}}},"DependentsModuleRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"numberOfDependentsLessThan":{"type":"integer","minimum":0,"maximum":100},"numberOfDependentsMoreThan":{"type":"integer","minimum":0,"maximum":100}}},"DependentsFromRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"}}},"ReachabilityToRestrictionType":{"required":["reachable"],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"reachable":{"type":"boolean"}}},"RequiredModuleRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"}}},"RequiredToRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"REAsStringsType":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"OptionsUsedType":{"type":"object","additionalProperties":false,"properties":{"doNotFollow":{"$ref":"#/definitions/CompoundDoNotFollowType"},"exclude":{"$ref":"#/definitions/CompoundExcludeType"},"includeOnly":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundIncludeOnlyType"}]},"focus":{"$ref":"#/definitions/CompoundFocusType"},"reaches":{"$ref":"#/definitions/CompoundReachesType"},"highlight":{"$ref":"#/definitions/CompoundHighlightType"},"knownViolations":{"$ref":"#/definitions/ViolationsType"},"collapse":{"type":"string"},"maxDepth":{"type":"integer","minimum":0,"maximum":99},"moduleSystems":{"$ref":"#/definitions/ModuleSystemsType"},"prefix":{"type":"string"},"preserveSymlinks":{"type":"boolean"},"combinedDependencies":{"type":"boolean"},"tsConfig":{"type":"object","additionalProperties":false,"properties":{"fileName":{"type":"string"}}},"tsPreCompilationDeps":{"oneOf":[{"type":"boolean"},{"type":"string","enum":["specify"]}]},"extraExtensionsToScan":{"type":"array","items":{"type":"string"}},"externalModuleResolutionStrategy":{"type":"string","enum":["node_modules","yarn-pnp"]},"builtInModules":{"type":"object","additionalProperties":false,"properties":{"override":{"type":"array","items":{"type":"string"}},"add":{"type":"array","items":{"type":"string"}}}},"forceDeriveDependents":{"type":"boolean"},"webpackConfig":{"type":"object","additionalProperties":false,"properties":{"fileName":{"type":"string"},"env":{"oneOf":[{"type":"object"},{"type":"string"}]},"arguments":{"type":"object"}}},"enhancedResolveOptions":{"type":"object","additionalProperties":false,"properties":{"exportsFields":{"type":"array","items":{"type":"string"}},"conditionNames":{"type":"array","items":{"type":"string"}},"extensions":{"type":"array","items":{"type":"string"}},"mainFields":{"type":"array","items":{"type":"string"}},"mainFiles":{"type":"array"},"aliasFields":{"type":"array","items":{"type":"string"}},"cachedInputFileSystem":{"type":"object","additionalProperties":false,"properties":{"cacheDuration":{"type":"integer","minimum":0,"maximum":1800000}}}}},"babelConfig":{"type":"object","additionalProperties":false,"properties":{"fileName":{"type":"string"}}},"parser":{"type":"string","enum":["acorn","tsc","swc"]},"exoticRequireStrings":{"type":"array","items":{"type":"string"}},"reporterOptions":{"$ref":"#/definitions/ReporterOptionsType"},"progress":{"type":"object","additionalProperties":false,"properties":{"type":{"type":"string","enum":["cli-feedback","performance-log","ndjson","none"]},"maximumLevel":{"type":"number","enum":[-1,40,50,60,70,80,99]}}},"metrics":{"type":"boolean"},"experimentalStats":{"type":"boolean"},"baseDir":{"type":"string"},"cache":{"oneOf":[{"type":"boolean","enum":[false]},{"$ref":"#/definitions/CacheOptionsType"}]},"args":{"type":"string"},"rulesFile":{"type":"string"},"outputTo":{"type":"string"},"outputType":{"$ref":"#/definitions/OutputType"}}},"ModuleSystemsType":{"type":"array","items":{"$ref":"#/definitions/ModuleSystemType"}},"OutputType":{"oneOf":[{"type":"string","enum":["json","html","dot","ddot","cdot","archi","fdot","flat","csv","err","err-long","err-html","teamcity","anon","text","metrics","markdown","mermaid","d2","null"]},{"type":"string","pattern":"^plugin:[^:]+$"}]},"CompoundExcludeType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"dynamic":{"type":"boolean"}}},"CompoundDoNotFollowType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}}}},"CompoundIncludeOnlyType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"CompoundFocusType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"depth":{"type":"number","minimum":1,"maximum":4}}},"CompoundReachesType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"CompoundHighlightType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"ReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"anon":{"$ref":"#/definitions/AnonReporterOptionsType"},"archi":{"$ref":"#/definitions/DotReporterOptionsType"},"dot":{"$ref":"#/definitions/DotReporterOptionsType"},"ddot":{"$ref":"#/definitions/DotReporterOptionsType"},"flat":{"$ref":"#/definitions/DotReporterOptionsType"},"markdown":{"$ref":"#/definitions/MarkdownReporterOptionsType"},"metrics":{"$ref":"#/definitions/MetricsReporterOptionsType"},"mermaid":{"$ref":"#/definitions/MermaidReporterOptionsType"},"text":{"$ref":"#/definitions/TextReporterOptionsType"}}},"AnonReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"wordlist":{"type":"array","items":{"type":"string"}}}},"MetricsReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"orderBy":{"type":"string","enum":["instability","moduleCount","afferentCouplings","efferentCouplings","name"]},"hideModules":{"type":"boolean"},"hideFolders":{"type":"boolean"}}},"MarkdownReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"showTitle":{"type":"boolean"},"title":{"type":"string"},"showSummary":{"type":"boolean"},"showSummaryHeader":{"type":"boolean"},"summaryHeader":{"type":"string"},"showStatsSummary":{"type":"boolean"},"showRulesSummary":{"type":"boolean"},"includeIgnoredInSummary":{"type":"boolean"},"showDetails":{"type":"boolean"},"includeIgnoredInDetails":{"type":"boolean"},"showDetailsHeader":{"type":"boolean"},"detailsHeader":{"type":"string"},"collapseDetails":{"type":"boolean"},"collapsedMessage":{"type":"string"},"noViolationsMessage":{"type":"string"},"showFooter":{"type":"boolean"}}},"MermaidReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"minify":{"type":"boolean"}}},"TextReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"highlightFocused":{"type":"boolean"}}},"DotReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"collapsePattern":{"$ref":"#/definitions/REAsStringsType"},"filters":{"$ref":"#/definitions/ReporterFiltersType"},"showMetrics":{"type":"boolean"},"theme":{"$ref":"#/definitions/DotThemeType"}}},"DotThemeType":{"type":"object","additionalProperties":false,"properties":{"replace":{"type":"boolean"},"graph":{"type":"object"},"node":{"type":"object"},"edge":{"type":"object"},"modules":{"$ref":"#/definitions/DotThemeArrayType"},"dependencies":{"$ref":"#/definitions/DotThemeArrayType"}}},"DotThemeArrayType":{"type":"array","items":{"$ref":"#/definitions/DotThemeEntryType"}},"DotThemeEntryType":{"type":"object","additionalProperties":false,"properties":{"criteria":{"type":"object"},"attributes":{"type":"object"}}},"ReporterFiltersType":{"type":"object","additionalProperties":false,"properties":{"exclude":{"$ref":"#/definitions/CompoundExcludeType"},"includeOnly":{"$ref":"#/definitions/CompoundIncludeOnlyType"},"focus":{"$ref":"#/definitions/CompoundFocusType"},"reaches":{"$ref":"#/definitions/CompoundReachesType"}}},"CacheOptionsType":{"type":"object","additionalProperties":false,"properties":{"folder":{"type":"string"},"strategy":{"$ref":"#/definitions/CacheStrategyType"},"compress":{"type":"boolean","default":false}}},"CacheStrategyType":{"type":"string","enum":["metadata","content"]},"RevisionDataType":{"type":"object","required":["SHA1","changes"],"properties":{"cacheFormatVersion":{"type":"number"},"SHA1":{"type":"string"},"changes":{"type":"array","items":{"type":"object","required":["name","type"],"properties":{"name":{"type":"string"},"type":{"type":"string","enum":["added","copied","deleted","modified","renamed","type changed","unmerged","pairing broken","unknown","unmodified","untracked","ignored"]},"oldName":{"type":"string"},"checksum":{"type":"string"},"args":{"type":"array","items":{"type":"string"}},"rulesFile":{"type":"string"}}}}}}}}
\ No newline at end of file
+/* generated - don't edit */export default {"title":"dependency-cruiser output format","$schema":"http://json-schema.org/draft-07/schema#","$id":"https://dependency-cruiser.js.org/schema/cruise-result.schema.json","type":"object","required":["summary","modules"],"additionalProperties":false,"properties":{"modules":{"$ref":"#/definitions/ModulesType"},"folders":{"$ref":"#/definitions/FoldersType"},"summary":{"$ref":"#/definitions/SummaryType"},"revisionData":{"$ref":"#/definitions/RevisionDataType"}},"definitions":{"ModulesType":{"type":"array","items":{"$ref":"#/definitions/ModuleType"}},"ModuleType":{"type":"object","required":["source","dependencies","valid"],"additionalProperties":false,"properties":{"source":{"type":"string"},"valid":{"type":"boolean"},"dependencies":{"$ref":"#/definitions/DependenciesType"},"dependents":{"type":"array","items":{"type":"string"}},"followable":{"type":"boolean"},"matchesDoNotFollow":{"type":"boolean"},"matchesFocus":{"type":"boolean"},"matchesReaches":{"type":"boolean"},"matchesHighlight":{"type":"boolean"},"coreModule":{"type":"boolean"},"couldNotResolve":{"type":"boolean"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"license":{"type":"string"},"orphan":{"type":"boolean"},"reachable":{"type":"array","items":{"$ref":"#/definitions/ReachableType"}},"reaches":{"type":"array","items":{"$ref":"#/definitions/ReachesType"}},"rules":{"type":"array","items":{"$ref":"#/definitions/RuleSummaryType"}},"consolidated":{"type":"boolean"},"instability":{"type":"number"},"experimentalStats":{"$ref":"#/definitions/ExperimentalStatsType"},"checksum":{"type":"string"}}},"ReachableType":{"type":"object","required":["value","asDefinedInRule","matchedFrom"],"additionalProperties":false,"properties":{"value":{"type":"boolean"},"asDefinedInRule":{"type":"string"},"matchedFrom":{"type":"string"}}},"ReachesType":{"type":"object","required":["modules","asDefinedInRule"],"additionalProperties":false,"properties":{"modules":{"type":"array","items":{"type":"object","required":["source","via"],"additionalProperties":false,"properties":{"source":{"type":"string"},"via":{"type":"array","items":{"$ref":"#/definitions/MiniDependency"}}}}},"asDefinedInRule":{"type":"string"}}},"DependenciesType":{"type":"array","items":{"$ref":"#/definitions/DependencyType"}},"DependencyType":{"type":"object","required":["circular","coreModule","couldNotResolve","dependencyTypes","exoticallyRequired","dynamic","followable","module","moduleSystem","resolved","valid"],"additionalProperties":false,"properties":{"module":{"type":"string"},"protocol":{"type":"string","enum":["data:","file:","node:"]},"mimeType":{"type":"string"},"resolved":{"type":"string"},"coreModule":{"type":"boolean"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"license":{"type":"string"},"followable":{"type":"boolean"},"dynamic":{"type":"boolean"},"exoticallyRequired":{"type":"boolean"},"exoticRequire":{"type":"string"},"matchesDoNotFollow":{"type":"boolean"},"couldNotResolve":{"type":"boolean"},"preCompilationOnly":{"type":"boolean"},"typeOnly":{"type":"boolean"},"circular":{"type":"boolean"},"cycle":{"type":"array","items":{"$ref":"#/definitions/MiniDependency"}},"moduleSystem":{"$ref":"#/definitions/ModuleSystemType"},"valid":{"type":"boolean"},"rules":{"type":"array","items":{"$ref":"#/definitions/RuleSummaryType"}},"instability":{"type":"number"}}},"DependencyTypeType":{"type":"string","enum":["aliased-subpath-import","aliased-tsconfig-base-url","aliased-tsconfig-paths","aliased-tsconfig","aliased-webpack","aliased-workspace","aliased","amd-define","amd-require","amd-exotic-require","core","deprecated","dynamic-import","exotic-require","export","import-equals","import","local","localmodule","npm-bundled","npm-dev","npm-no-pkg","npm-optional","npm-peer","npm-unknown","npm","pre-compilation-only","require","triple-slash-amd-dependency","triple-slash-directive","triple-slash-file-reference","triple-slash-type-reference","type-import","type-only","undetermined","unknown"]},"ModuleSystemType":{"type":"string","enum":["cjs","es6","amd","tsd"]},"RuleSummaryType":{"type":"object","required":["name","severity"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"}}},"SeverityType":{"type":"string","enum":["error","warn","info","ignore"]},"MiniDependency":{"type":"object","required":["name","dependencyTypes"],"additionalProperties":false,"properties":{"name":{"type":"string"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}}}},"ExperimentalStatsType":{"type":"object","required":["size","topLevelStatementCount"],"additionalProperties":false,"properties":{"topLevelStatementCount":{"type":"number"},"size":{"type":"number"}}},"FoldersType":{"type":"array","items":{"$ref":"#/definitions/FolderType"}},"FolderType":{"type":"object","required":["name","moduleCount"],"additionalProperties":false,"properties":{"name":{"type":"string"},"dependents":{"type":"array","items":{"type":"object","required":["name"],"additionalProperties":false,"properties":{"name":{"type":"string"}}}},"dependencies":{"type":"array","items":{"type":"object","required":["name","valid","circular"],"additionalProperties":false,"properties":{"name":{"type":"string"},"instability":{"type":"number"},"valid":{"type":"boolean"},"circular":{"type":"boolean"},"cycle":{"type":"array","items":{"$ref":"#/definitions/MiniDependency"}},"rules":{"type":"array","items":{"$ref":"#/definitions/RuleSummaryType"}}}}},"moduleCount":{"type":"number"},"afferentCouplings":{"type":"number"},"efferentCouplings":{"type":"number"},"instability":{"type":"number"},"experimentalStats":{"$ref":"#/definitions/ExperimentalStatsType"}}},"SummaryType":{"type":"object","required":["violations","error","warn","info","totalCruised","optionsUsed"],"additionalProperties":false,"properties":{"violations":{"$ref":"#/definitions/ViolationsType"},"error":{"type":"number"},"warn":{"type":"number"},"info":{"type":"number"},"ignore":{"type":"number"},"totalCruised":{"type":"number"},"totalDependenciesCruised":{"type":"number"},"ruleSetUsed":{"$ref":"#/definitions/RuleSetType"},"optionsUsed":{"$ref":"#/definitions/OptionsUsedType"}}},"ViolationsType":{"type":"array","items":{"$ref":"#/definitions/ViolationType"}},"ViolationType":{"type":"object","required":["from","to","rule"],"additionalProperties":false,"properties":{"from":{"type":"string"},"to":{"type":"string"},"type":{"$ref":"#/definitions/ViolationTypeType"},"rule":{"$ref":"#/definitions/RuleSummaryType"},"cycle":{"type":"array","items":{"$ref":"#/definitions/MiniDependency"}},"via":{"type":"array","items":{"$ref":"#/definitions/MiniDependency"}},"metrics":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"from":{"type":"object","required":["instability"],"additionalProperties":false,"properties":{"instability":{"type":"number"}}},"to":{"type":"object","required":["instability"],"additionalProperties":false,"properties":{"instability":{"type":"number"}}}}},"comment":{"type":"string"}}},"ViolationTypeType":{"type":"string","enum":["dependency","module","reachability","cycle","instability","folder"]},"RuleSetType":{"type":"object","additionalProperties":false,"properties":{"forbidden":{"type":"array","items":{"$ref":"#/definitions/ForbiddenRuleType"}},"allowed":{"type":"array","items":{"$ref":"#/definitions/AllowedRuleType"}},"allowedSeverity":{"$ref":"#/definitions/SeverityType"},"required":{"type":"array","items":{"$ref":"#/definitions/RequiredRuleType"}}}},"AllowedRuleType":{"oneOf":[{"$ref":"#/definitions/RegularAllowedRuleType"},{"$ref":"#/definitions/ReachabilityAllowedRuleType"}]},"RegularAllowedRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"comment":{"type":"string"},"scope":{"type":"string","enum":["module","folder"]},"from":{"$ref":"#/definitions/FromRestrictionType"},"to":{"$ref":"#/definitions/ToRestrictionType"}}},"ReachabilityAllowedRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"comment":{"type":"string"},"scope":{"type":"string","enum":["module","folder"]},"from":{"$ref":"#/definitions/ReachabilityFromRestrictionType"},"to":{"$ref":"#/definitions/ReachabilityToRestrictionType"}}},"ForbiddenRuleType":{"oneOf":[{"$ref":"#/definitions/RegularForbiddenRuleType"},{"$ref":"#/definitions/ReachabilityForbiddenRuleType"},{"$ref":"#/definitions/DependentsForbiddenRuleType"}]},"RegularForbiddenRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"from":{"$ref":"#/definitions/FromRestrictionType"},"to":{"$ref":"#/definitions/ToRestrictionType"}}},"DependentsForbiddenRuleType":{"type":"object","required":["module","from"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"module":{"$ref":"#/definitions/DependentsModuleRestrictionType"},"from":{"$ref":"#/definitions/DependentsFromRestrictionType"}}},"ReachabilityForbiddenRuleType":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"from":{"$ref":"#/definitions/ReachabilityFromRestrictionType"},"to":{"$ref":"#/definitions/ReachabilityToRestrictionType"}}},"RequiredRuleType":{"type":"object","required":["module","to"],"additionalProperties":false,"properties":{"name":{"type":"string"},"severity":{"$ref":"#/definitions/SeverityType"},"scope":{"type":"string","enum":["module","folder"]},"comment":{"type":"string"},"module":{"$ref":"#/definitions/RequiredModuleRestrictionType"},"to":{"$ref":"#/definitions/RequiredToRestrictionType"}}},"MiniDependencyRestrictionType":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"dependencyTypesNot":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}}}}]},"FromRestrictionType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"orphan":{"type":"boolean"}}},"ReachabilityFromRestrictionType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"}}},"ToRestrictionType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"couldNotResolve":{"type":"boolean"},"circular":{"type":"boolean"},"dynamic":{"type":"boolean"},"exoticallyRequired":{"type":"boolean"},"exoticRequire":{"$ref":"#/definitions/REAsStringsType"},"exoticRequireNot":{"$ref":"#/definitions/REAsStringsType"},"preCompilationOnly":{"type":"boolean"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"dependencyTypesNot":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}},"moreThanOneDependencyType":{"type":"boolean"},"license":{"$ref":"#/definitions/REAsStringsType"},"licenseNot":{"$ref":"#/definitions/REAsStringsType"},"via":{"$ref":"#/definitions/MiniDependencyRestrictionType"},"viaOnly":{"$ref":"#/definitions/MiniDependencyRestrictionType"},"viaNot":{"deprecated":true,"$ref":"#/definitions/REAsStringsType"},"viaSomeNot":{"deprecated":true,"$ref":"#/definitions/REAsStringsType"},"moreUnstable":{"type":"boolean"}}},"DependentsModuleRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"numberOfDependentsLessThan":{"type":"integer","minimum":0,"maximum":100},"numberOfDependentsMoreThan":{"type":"integer","minimum":0,"maximum":100}}},"DependentsFromRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"}}},"ReachabilityToRestrictionType":{"required":["reachable"],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"},"reachable":{"type":"boolean"}}},"RequiredModuleRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"pathNot":{"$ref":"#/definitions/REAsStringsType"}}},"RequiredToRestrictionType":{"required":[],"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"REAsStringsType":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"OptionsUsedType":{"type":"object","additionalProperties":false,"properties":{"doNotFollow":{"$ref":"#/definitions/CompoundDoNotFollowType"},"exclude":{"$ref":"#/definitions/CompoundExcludeType"},"includeOnly":{"oneOf":[{"$ref":"#/definitions/REAsStringsType"},{"$ref":"#/definitions/CompoundIncludeOnlyType"}]},"focus":{"$ref":"#/definitions/CompoundFocusType"},"reaches":{"$ref":"#/definitions/CompoundReachesType"},"highlight":{"$ref":"#/definitions/CompoundHighlightType"},"knownViolations":{"$ref":"#/definitions/ViolationsType"},"collapse":{"type":"string"},"maxDepth":{"type":"integer","minimum":0,"maximum":99},"moduleSystems":{"$ref":"#/definitions/ModuleSystemsType"},"prefix":{"type":"string"},"preserveSymlinks":{"type":"boolean"},"combinedDependencies":{"type":"boolean"},"tsConfig":{"type":"object","additionalProperties":false,"properties":{"fileName":{"type":"string"}}},"tsPreCompilationDeps":{"oneOf":[{"type":"boolean"},{"type":"string","enum":["specify"]}]},"extraExtensionsToScan":{"type":"array","items":{"type":"string"}},"externalModuleResolutionStrategy":{"type":"string","enum":["node_modules","yarn-pnp"]},"builtInModules":{"type":"object","additionalProperties":false,"properties":{"override":{"type":"array","items":{"type":"string"}},"add":{"type":"array","items":{"type":"string"}}}},"forceDeriveDependents":{"type":"boolean"},"webpackConfig":{"type":"object","additionalProperties":false,"properties":{"fileName":{"type":"string"},"env":{"oneOf":[{"type":"object"},{"type":"string"}]},"arguments":{"type":"object"}}},"enhancedResolveOptions":{"type":"object","additionalProperties":false,"properties":{"exportsFields":{"type":"array","items":{"type":"string"}},"conditionNames":{"type":"array","items":{"type":"string"}},"extensions":{"type":"array","items":{"type":"string"}},"mainFields":{"type":"array","items":{"type":"string"}},"mainFiles":{"type":"array"},"aliasFields":{"type":"array","items":{"type":"string"}},"cachedInputFileSystem":{"type":"object","additionalProperties":false,"properties":{"cacheDuration":{"type":"integer","minimum":0,"maximum":1800000}}}}},"babelConfig":{"type":"object","additionalProperties":false,"properties":{"fileName":{"type":"string"}}},"parser":{"type":"string","enum":["acorn","tsc","swc"]},"exoticRequireStrings":{"type":"array","items":{"type":"string"}},"reporterOptions":{"$ref":"#/definitions/ReporterOptionsType"},"progress":{"type":"object","additionalProperties":false,"properties":{"type":{"type":"string","enum":["cli-feedback","performance-log","ndjson","none"]},"maximumLevel":{"type":"number","enum":[-1,40,50,60,70,80,99]}}},"metrics":{"type":"boolean"},"experimentalStats":{"type":"boolean"},"baseDir":{"type":"string"},"cache":{"oneOf":[{"type":"boolean","enum":[false]},{"$ref":"#/definitions/CacheOptionsType"}]},"args":{"type":"string"},"rulesFile":{"type":"string"},"outputTo":{"type":"string"},"outputType":{"$ref":"#/definitions/OutputType"}}},"ModuleSystemsType":{"type":"array","items":{"$ref":"#/definitions/ModuleSystemType"}},"OutputType":{"oneOf":[{"type":"string","enum":["json","html","dot","ddot","cdot","archi","fdot","flat","csv","err","err-long","err-html","teamcity","anon","text","metrics","markdown","mermaid","d2","null"]},{"type":"string","pattern":"^plugin:[^:]+$"}]},"CompoundExcludeType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"dynamic":{"type":"boolean"}}},"CompoundDoNotFollowType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"dependencyTypes":{"type":"array","items":{"$ref":"#/definitions/DependencyTypeType"}}}},"CompoundIncludeOnlyType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"CompoundFocusType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"},"depth":{"type":"number","minimum":1,"maximum":4}}},"CompoundReachesType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"CompoundHighlightType":{"type":"object","additionalProperties":false,"properties":{"path":{"$ref":"#/definitions/REAsStringsType"}}},"ReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"anon":{"$ref":"#/definitions/AnonReporterOptionsType"},"archi":{"$ref":"#/definitions/DotReporterOptionsType"},"dot":{"$ref":"#/definitions/DotReporterOptionsType"},"ddot":{"$ref":"#/definitions/DotReporterOptionsType"},"flat":{"$ref":"#/definitions/DotReporterOptionsType"},"markdown":{"$ref":"#/definitions/MarkdownReporterOptionsType"},"metrics":{"$ref":"#/definitions/MetricsReporterOptionsType"},"mermaid":{"$ref":"#/definitions/MermaidReporterOptionsType"},"text":{"$ref":"#/definitions/TextReporterOptionsType"}}},"AnonReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"wordlist":{"type":"array","items":{"type":"string"}}}},"MetricsReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"orderBy":{"type":"string","enum":["instability","moduleCount","afferentCouplings","efferentCouplings","name","size","topLevelStatementCount"]},"hideModules":{"type":"boolean"},"hideFolders":{"type":"boolean"}}},"MarkdownReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"showTitle":{"type":"boolean"},"title":{"type":"string"},"showSummary":{"type":"boolean"},"showSummaryHeader":{"type":"boolean"},"summaryHeader":{"type":"string"},"showStatsSummary":{"type":"boolean"},"showRulesSummary":{"type":"boolean"},"includeIgnoredInSummary":{"type":"boolean"},"showDetails":{"type":"boolean"},"includeIgnoredInDetails":{"type":"boolean"},"showDetailsHeader":{"type":"boolean"},"detailsHeader":{"type":"string"},"collapseDetails":{"type":"boolean"},"collapsedMessage":{"type":"string"},"noViolationsMessage":{"type":"string"},"showFooter":{"type":"boolean"}}},"MermaidReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"minify":{"type":"boolean"}}},"TextReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"highlightFocused":{"type":"boolean"}}},"DotReporterOptionsType":{"type":"object","additionalProperties":false,"properties":{"collapsePattern":{"$ref":"#/definitions/REAsStringsType"},"filters":{"$ref":"#/definitions/ReporterFiltersType"},"showMetrics":{"type":"boolean"},"theme":{"$ref":"#/definitions/DotThemeType"}}},"DotThemeType":{"type":"object","additionalProperties":false,"properties":{"replace":{"type":"boolean"},"graph":{"type":"object"},"node":{"type":"object"},"edge":{"type":"object"},"modules":{"$ref":"#/definitions/DotThemeArrayType"},"dependencies":{"$ref":"#/definitions/DotThemeArrayType"}}},"DotThemeArrayType":{"type":"array","items":{"$ref":"#/definitions/DotThemeEntryType"}},"DotThemeEntryType":{"type":"object","additionalProperties":false,"properties":{"criteria":{"type":"object"},"attributes":{"type":"object"}}},"ReporterFiltersType":{"type":"object","additionalProperties":false,"properties":{"exclude":{"$ref":"#/definitions/CompoundExcludeType"},"includeOnly":{"$ref":"#/definitions/CompoundIncludeOnlyType"},"focus":{"$ref":"#/definitions/CompoundFocusType"},"reaches":{"$ref":"#/definitions/CompoundReachesType"}}},"CacheOptionsType":{"type":"object","additionalProperties":false,"properties":{"folder":{"type":"string"},"strategy":{"$ref":"#/definitions/CacheStrategyType"},"compress":{"type":"boolean","default":false}}},"CacheStrategyType":{"type":"string","enum":["metadata","content"]},"RevisionDataType":{"type":"object","required":["SHA1","changes"],"properties":{"cacheFormatVersion":{"type":"number"},"SHA1":{"type":"string"},"changes":{"type":"array","items":{"type":"object","required":["name","type"],"properties":{"name":{"type":"string"},"type":{"type":"string","enum":["added","copied","deleted","modified","renamed","type changed","unmerged","pairing broken","unknown","unmodified","untracked","ignored"]},"oldName":{"type":"string"},"checksum":{"type":"string"},"args":{"type":"array","items":{"type":"string"}},"rulesFile":{"type":"string"}}}}}}}}
\ No newline at end of file
diff --git a/tools/schema/reporter-options.mjs b/tools/schema/reporter-options.mjs
index b56b863a..c5a22624 100644
--- a/tools/schema/reporter-options.mjs
+++ b/tools/schema/reporter-options.mjs
@@ -55,6 +55,8 @@ export default {
             "afferentCouplings",
             "efferentCouplings",
             "name",
+            "size",
+            "topLevelStatementCount",
           ],
           description:
             "By what attribute (in addition to the names of the folders/ modules) " +


Test patch:
diff --git a/test/report/metrics/metrics.spec.mjs b/test/report/metrics/metrics.spec.mjs
index 3f68ed1d..cddbe1e8 100644
--- a/test/report/metrics/metrics.spec.mjs
+++ b/test/report/metrics/metrics.spec.mjs
@@ -28,7 +28,32 @@ describe("[I] report/metrics", () => {
     });
 
     equal(lResult.exitCode, 0);
-    match(lResult.output, /src       1      1      1    50%/);
+    match(lResult.output, /folder  src        1      1      1    50%/);
+  });
+
+  it("emits folder metrics and experimental stats when they're in the input", () => {
+    const lResult = metrics({
+      modules: [],
+      folders: [
+        {
+          name: "src",
+          moduleCount: 1,
+          afferentCouplings: 1,
+          efferentCouplings: 1,
+          instability: 0.5,
+          experimentalStats: {
+            size: 100,
+            topLevelStatementCount: 300,
+          },
+        },
+      ],
+    });
+
+    equal(lResult.exitCode, 0);
+    match(
+      lResult.output,
+      /folder  src        1      1      1    50%         100    300/,
+    );
   });
 
   it("does not emit folder metrics when asked to hide them", () => {
@@ -81,7 +106,7 @@ describe("[I] report/metrics", () => {
     match(
       lResult.output,
       new RegExp(
-        `src/mies.js      1      1      1    50%${EOL}src/aap.js       1      1      3    25%${EOL}src/noot.js`,
+        `module  src/mies.js       1      1      1    50%${EOL}module  src/aap.js        1      1      3    25%${EOL}module  src/noot.js`,
       ),
     );
   });
@@ -118,7 +143,142 @@ describe("[I] report/metrics", () => {
     match(
       lResult.output,
       new RegExp(
-        `src/aap.js       1      1      3    25%${EOL}src/mies.js      1      1      1    50%${EOL}src/noot.js`,
+        `module  src/aap.js        1      1      3    25%${EOL}module  src/mies.js       1      1      1    50%${EOL}module  src/noot.js`,
+      ),
+    );
+  });
+
+  it("emits module metrics (sorted by size, where size is not available)", () => {
+    const lResult = metrics(
+      {
+        modules: [
+          {
+            source: "src/noot.js",
+            dependencies: [],
+            dependents: ["two"],
+            instability: 0,
+          },
+          {
+            source: "src/aap.js",
+            dependencies: ["one", "two", "three"],
+            dependents: ["four"],
+            instability: 0.25,
+          },
+          {
+            source: "src/mies.js",
+            dependencies: ["one"],
+            dependents: ["two"],
+            instability: 0.5,
+          },
+        ],
+        folders: [],
+      },
+      { orderBy: "size" },
+    );
+
+    equal(lResult.exitCode, 0);
+    match(
+      lResult.output,
+      new RegExp(
+        `module  src/aap.js        1      1      3    25%${EOL}module  src/mies.js       1      1      1    50%${EOL}module  src/noot.js`,
+      ),
+    );
+  });
+
+  it("emits module metrics + experimental stats when they're in the input", () => {
+    const lResult = metrics(
+      {
+        modules: [
+          {
+            source: "src/noot.js",
+            dependencies: [],
+            dependents: ["two"],
+            instability: 0,
+            experimentalStats: {
+              size: 1,
+              topLevelStatementCount: 3,
+            },
+          },
+          {
+            source: "src/aap.js",
+            dependencies: ["one", "two", "three"],
+            dependents: ["four"],
+            instability: 0.25,
+            experimentalStats: {
+              size: 10,
+              topLevelStatementCount: 30,
+            },
+          },
+          {
+            source: "src/mies.js",
+            dependencies: ["one"],
+            dependents: ["two"],
+            instability: 0.5,
+            experimentalStats: {
+              size: 100,
+              topLevelStatementCount: 300,
+            },
+          },
+        ],
+        folders: [],
+      },
+      { orderBy: "name" },
+    );
+
+    equal(lResult.exitCode, 0);
+    match(
+      lResult.output,
+      new RegExp(
+        `module  src/aap.js        1      1      3    25%          10     30${EOL}module  src/mies.js       1      1      1    50%         100    300${EOL}module  src/noot.js`,
+      ),
+    );
+  });
+
+  it("emits module metrics + experimental stats when they're in the input & doesn't barf when one of them isn't a number", () => {
+    const lResult = metrics(
+      {
+        modules: [
+          {
+            source: "src/noot.js",
+            dependencies: [],
+            dependents: ["two"],
+            instability: 0,
+            experimentalStats: {
+              size: 1,
+              topLevelStatementCount: 3,
+            },
+          },
+          {
+            source: "src/aap.js",
+            dependencies: ["one", "two", "three"],
+            dependents: ["four"],
+            instability: 0.25,
+            experimentalStats: {
+              size: null,
+              topLevelStatementCount: 30,
+            },
+          },
+          {
+            source: "src/mies.js",
+            dependencies: ["one"],
+            dependents: ["two"],
+            instability: 0.5,
+            experimentalStats: {
+              size: 100,
+              topLevelStatementCount: 300,
+            },
+          },
+        ],
+        folders: [],
+      },
+      { orderBy: "name" },
+    );
+
+    equal(lResult.exitCode, 0);
+    match(
+      lResult.output,
+      new RegExp(
+        `module  src/aap.js        1      1      3    25%                 30${EOL}module  src/mies.js       1      1      1    50%         100    300${EOL}module  src/noot.js`,
       ),
     );
   });