@donativo/roux 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +335 -0
- package/dist/analysis/age.d.ts +3 -0
- package/dist/analysis/age.js +32 -0
- package/dist/analysis/age.js.map +1 -0
- package/dist/analysis/authors.d.ts +3 -0
- package/dist/analysis/authors.js +18 -0
- package/dist/analysis/authors.js.map +1 -0
- package/dist/analysis/churn.d.ts +5 -0
- package/dist/analysis/churn.js +39 -0
- package/dist/analysis/churn.js.map +1 -0
- package/dist/analysis/communication.d.ts +3 -0
- package/dist/analysis/communication.js +44 -0
- package/dist/analysis/communication.js.map +1 -0
- package/dist/analysis/coupling.d.ts +4 -0
- package/dist/analysis/coupling.js +84 -0
- package/dist/analysis/coupling.js.map +1 -0
- package/dist/analysis/entity-effort.d.ts +3 -0
- package/dist/analysis/entity-effort.js +36 -0
- package/dist/analysis/entity-effort.js.map +1 -0
- package/dist/analysis/entity-ownership.d.ts +3 -0
- package/dist/analysis/entity-ownership.js +35 -0
- package/dist/analysis/entity-ownership.js.map +1 -0
- package/dist/analysis/fragmentation.d.ts +3 -0
- package/dist/analysis/fragmentation.js +53 -0
- package/dist/analysis/fragmentation.js.map +1 -0
- package/dist/analysis/identity.d.ts +3 -0
- package/dist/analysis/identity.js +12 -0
- package/dist/analysis/identity.js.map +1 -0
- package/dist/analysis/index.d.ts +4 -0
- package/dist/analysis/index.js +59 -0
- package/dist/analysis/index.js.map +1 -0
- package/dist/analysis/main-dev-by-revs.d.ts +3 -0
- package/dist/analysis/main-dev-by-revs.js +36 -0
- package/dist/analysis/main-dev-by-revs.js.map +1 -0
- package/dist/analysis/main-dev.d.ts +3 -0
- package/dist/analysis/main-dev.js +38 -0
- package/dist/analysis/main-dev.js.map +1 -0
- package/dist/analysis/messages.d.ts +3 -0
- package/dist/analysis/messages.js +27 -0
- package/dist/analysis/messages.js.map +1 -0
- package/dist/analysis/refactoring-main-dev.d.ts +3 -0
- package/dist/analysis/refactoring-main-dev.js +37 -0
- package/dist/analysis/refactoring-main-dev.js.map +1 -0
- package/dist/analysis/revisions.d.ts +3 -0
- package/dist/analysis/revisions.js +16 -0
- package/dist/analysis/revisions.js.map +1 -0
- package/dist/analysis/summary.d.ts +3 -0
- package/dist/analysis/summary.js +12 -0
- package/dist/analysis/summary.js.map +1 -0
- package/dist/analysis/types.d.ts +18 -0
- package/dist/analysis/types.js +8 -0
- package/dist/analysis/types.js.map +1 -0
- package/dist/app.d.ts +12 -0
- package/dist/app.js +54 -0
- package/dist/app.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +79 -0
- package/dist/cli.js.map +1 -0
- package/dist/git.d.ts +7 -0
- package/dist/git.js +24 -0
- package/dist/git.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/output/csv.d.ts +1 -0
- package/dist/output/csv.js +19 -0
- package/dist/output/csv.js.map +1 -0
- package/dist/output/json.d.ts +1 -0
- package/dist/output/json.js +4 -0
- package/dist/output/json.js.map +1 -0
- package/dist/parsers/git.d.ts +2 -0
- package/dist/parsers/git.js +41 -0
- package/dist/parsers/git.js.map +1 -0
- package/dist/parsers/git2.d.ts +2 -0
- package/dist/parsers/git2.js +72 -0
- package/dist/parsers/git2.js.map +1 -0
- package/dist/parsers/index.d.ts +7 -0
- package/dist/parsers/index.js +7 -0
- package/dist/parsers/index.js.map +1 -0
- package/dist/parsers/types.d.ts +9 -0
- package/dist/parsers/types.js +2 -0
- package/dist/parsers/types.js.map +1 -0
- package/dist/transforms/grouper.d.ts +11 -0
- package/dist/transforms/grouper.js +57 -0
- package/dist/transforms/grouper.js.map +1 -0
- package/dist/transforms/team-mapper.d.ts +7 -0
- package/dist/transforms/team-mapper.js +51 -0
- package/dist/transforms/team-mapper.js.map +1 -0
- package/dist/transforms/temporal-grouper.d.ts +2 -0
- package/dist/transforms/temporal-grouper.js +42 -0
- package/dist/transforms/temporal-grouper.js.map +1 -0
- package/dist/utils/dataset.d.ts +2 -0
- package/dist/utils/dataset.js +34 -0
- package/dist/utils/dataset.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-effort.js","sourceRoot":"","sources":["../../src/analysis/entity-effort.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE3C,MAAM,UAAU,YAAY,CAC1B,IAAoB,EACpB,QAAyB;IAEzB,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACzC,MAAM,MAAM,GAA8B,EAAE,CAAC;IAE7C,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,QAAQ,EAAE,CAAC;QACtC,2DAA2D;QAC3D,MAAM,UAAU,GAAG,IAAI,GAAG,EAAuB,CAAC;QAClD,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,IAAI,GAAG,EAAU,CAAC;YAC3D,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YAChB,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACjC,CAAC;QAED,sCAAsC;QACtC,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,KAAK,MAAM,IAAI,IAAI,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC;YACvC,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC;QACzB,CAAC;QAED,6BAA6B;QAC7B,MAAM,UAAU,GAA8B,EAAE,CAAC;QACjD,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,UAAU,EAAE,CAAC;YACxC,UAAU,CAAC,IAAI,CAAC;gBACd,MAAM,EAAE,MAAgB;gBACxB,MAAM;gBACN,aAAa,EAAE,IAAI,CAAC,IAAI;gBACxB,YAAY,EAAE,SAAS;aACxB,CAAC,CAAC;QACL,CAAC;QAED,yCAAyC;QACzC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAE,CAAC,CAAC,aAAa,CAAY,GAAI,CAAC,CAAC,aAAa,CAAY,CAAC,CAAC;QACvF,MAAM,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,CAAC;IAC7B,CAAC;IAED,yEAAyE;IACzE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAE,CAAC,CAAC,MAAiB,CAAC,aAAa,CAAC,CAAC,CAAC,MAAgB,CAAC,CAAC,CAAC;IAE9E,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { groupBy } from "../utils/dataset";
|
|
2
|
+
/** Normalize binary (-1) to 0 */
|
|
3
|
+
function loc(value) {
|
|
4
|
+
return value < 0 ? 0 : value;
|
|
5
|
+
}
|
|
6
|
+
export function entityOwnership(data, _options) {
|
|
7
|
+
const byEntity = groupBy(data, "entity");
|
|
8
|
+
const result = [];
|
|
9
|
+
for (const [entity, mods] of byEntity) {
|
|
10
|
+
const byAuthor = new Map();
|
|
11
|
+
for (const m of mods) {
|
|
12
|
+
const stats = byAuthor.get(m.author) ?? { added: 0, deleted: 0 };
|
|
13
|
+
stats.added += loc(m.locAdded);
|
|
14
|
+
stats.deleted += loc(m.locDeleted);
|
|
15
|
+
byAuthor.set(m.author, stats);
|
|
16
|
+
}
|
|
17
|
+
for (const [author, stats] of byAuthor) {
|
|
18
|
+
result.push({
|
|
19
|
+
entity: entity,
|
|
20
|
+
author,
|
|
21
|
+
added: stats.added,
|
|
22
|
+
deleted: stats.deleted,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
// Sort by entity asc, then by added desc within entity
|
|
27
|
+
result.sort((a, b) => {
|
|
28
|
+
const entityCmp = a.entity.localeCompare(b.entity);
|
|
29
|
+
if (entityCmp !== 0)
|
|
30
|
+
return entityCmp;
|
|
31
|
+
return b.added - a.added;
|
|
32
|
+
});
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=entity-ownership.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-ownership.js","sourceRoot":"","sources":["../../src/analysis/entity-ownership.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE3C,iCAAiC;AACjC,SAAS,GAAG,CAAC,KAAa;IACxB,OAAO,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,IAAoB,EACpB,QAAyB;IAEzB,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACzC,MAAM,MAAM,GAA8B,EAAE,CAAC;IAE7C,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,QAAQ,EAAE,CAAC;QACtC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA8C,CAAC;QACvE,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;YACjE,KAAK,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;YAC/B,KAAK,CAAC,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;YACnC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAChC,CAAC;QACD,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,QAAQ,EAAE,CAAC;YACvC,MAAM,CAAC,IAAI,CAAC;gBACV,MAAM,EAAE,MAAgB;gBACxB,MAAM;gBACN,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,OAAO,EAAE,KAAK,CAAC,OAAO;aACvB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,uDAAuD;IACvD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACnB,MAAM,SAAS,GAAI,CAAC,CAAC,MAAiB,CAAC,aAAa,CAAC,CAAC,CAAC,MAAgB,CAAC,CAAC;QACzE,IAAI,SAAS,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC;QACtC,OAAQ,CAAC,CAAC,KAAgB,GAAI,CAAC,CAAC,KAAgB,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { groupBy } from "../utils/dataset";
|
|
2
|
+
/**
|
|
3
|
+
* Format to 2 significant figures as a string, matching code-maat's
|
|
4
|
+
* ratio->centi-float-precision. Uses toPrecision(2) for non-zero values,
|
|
5
|
+
* which produces strings like "0.51", "0.091", "0.0050".
|
|
6
|
+
* For zero, returns "0.0" to match Clojure's (double 0) formatting.
|
|
7
|
+
*/
|
|
8
|
+
function formatPrecision2(v) {
|
|
9
|
+
if (v === 0)
|
|
10
|
+
return "0.0";
|
|
11
|
+
const s = v.toPrecision(2);
|
|
12
|
+
// toPrecision may return scientific notation for very small numbers
|
|
13
|
+
return String(parseFloat(s));
|
|
14
|
+
}
|
|
15
|
+
export function fragmentation(data, _options) {
|
|
16
|
+
const byEntity = groupBy(data, "entity");
|
|
17
|
+
const intermediate = [];
|
|
18
|
+
for (const [entity, mods] of byEntity) {
|
|
19
|
+
// Count unique revisions per author
|
|
20
|
+
const authorRevs = new Map();
|
|
21
|
+
for (const m of mods) {
|
|
22
|
+
const revs = authorRevs.get(m.author) ?? new Set();
|
|
23
|
+
revs.add(m.rev);
|
|
24
|
+
authorRevs.set(m.author, revs);
|
|
25
|
+
}
|
|
26
|
+
// total-revs = sum of all author-revs
|
|
27
|
+
let totalRevs = 0;
|
|
28
|
+
for (const revs of authorRevs.values()) {
|
|
29
|
+
totalRevs += revs.size;
|
|
30
|
+
}
|
|
31
|
+
// fractal = 1 - sum((author_revs / total_revs)^2)
|
|
32
|
+
let sumSquares = 0;
|
|
33
|
+
for (const revs of authorRevs.values()) {
|
|
34
|
+
const fraction = revs.size / totalRevs;
|
|
35
|
+
sumSquares += fraction * fraction;
|
|
36
|
+
}
|
|
37
|
+
// Use high-precision intermediate to avoid FP accumulation errors
|
|
38
|
+
const fractal = 1 - parseFloat(sumSquares.toPrecision(10));
|
|
39
|
+
intermediate.push({
|
|
40
|
+
entity: entity,
|
|
41
|
+
fractal,
|
|
42
|
+
totalRevs,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
// Sort by fractal value descending (numerically), then by totalRevs descending
|
|
46
|
+
intermediate.sort((a, b) => b.fractal - a.fractal || b.totalRevs - a.totalRevs);
|
|
47
|
+
return intermediate.map((r) => ({
|
|
48
|
+
entity: r.entity,
|
|
49
|
+
"fractal-value": formatPrecision2(r.fractal),
|
|
50
|
+
"total-revs": r.totalRevs,
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=fragmentation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fragmentation.js","sourceRoot":"","sources":["../../src/analysis/fragmentation.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAW,MAAM,kBAAkB,CAAC;AAEpD;;;;;GAKG;AACH,SAAS,gBAAgB,CAAC,CAAS;IACjC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1B,MAAM,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAC3B,oEAAoE;IACpE,OAAO,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,IAAoB,EACpB,QAAyB;IAEzB,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACzC,MAAM,YAAY,GAA6D,EAAE,CAAC;IAElF,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,QAAQ,EAAE,CAAC;QACtC,oCAAoC;QACpC,MAAM,UAAU,GAAG,IAAI,GAAG,EAAuB,CAAC;QAClD,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,IAAI,GAAG,EAAU,CAAC;YAC3D,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YAChB,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACjC,CAAC;QAED,sCAAsC;QACtC,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,KAAK,MAAM,IAAI,IAAI,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC;YACvC,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC;QACzB,CAAC;QAED,kDAAkD;QAClD,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,KAAK,MAAM,IAAI,IAAI,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC;YACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC;YACvC,UAAU,IAAI,QAAQ,GAAG,QAAQ,CAAC;QACpC,CAAC;QACD,kEAAkE;QAClE,MAAM,OAAO,GAAG,CAAC,GAAG,UAAU,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;QAE3D,YAAY,CAAC,IAAI,CAAC;YAChB,MAAM,EAAE,MAAgB;YACxB,OAAO;YACP,SAAS;SACV,CAAC,CAAC;IACL,CAAC;IAED,+EAA+E;IAC/E,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC;IAEhF,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC9B,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,eAAe,EAAE,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC;QAC5C,YAAY,EAAE,CAAC,CAAC,SAAS;KAC1B,CAAC,CAAC,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function identity(data, _options) {
|
|
2
|
+
return data.map((m) => ({
|
|
3
|
+
author: m.author,
|
|
4
|
+
rev: m.rev,
|
|
5
|
+
date: m.date,
|
|
6
|
+
entity: m.entity,
|
|
7
|
+
message: m.message ?? "-",
|
|
8
|
+
"loc-added": m.locAdded < 0 ? "-" : m.locAdded,
|
|
9
|
+
"loc-deleted": m.locDeleted < 0 ? "-" : m.locDeleted,
|
|
10
|
+
}));
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/analysis/identity.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,QAAQ,CACtB,IAAoB,EACpB,QAAyB;IAEzB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACtB,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,GAAG,EAAE,CAAC,CAAC,GAAG;QACV,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,GAAG;QACzB,WAAW,EAAE,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ;QAC9C,aAAa,EAAE,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU;KACrD,CAAC,CAAC,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { summary } from "./summary";
|
|
2
|
+
import { authors } from "./authors";
|
|
3
|
+
import { revisions } from "./revisions";
|
|
4
|
+
import { coupling, sumOfCoupling } from "./coupling";
|
|
5
|
+
import { absoluteChurn, churnByEntity, churnByAuthor } from "./churn";
|
|
6
|
+
import { age } from "./age";
|
|
7
|
+
import { entityOwnership } from "./entity-ownership";
|
|
8
|
+
import { mainDev } from "./main-dev";
|
|
9
|
+
import { mainDevByRevs } from "./main-dev-by-revs";
|
|
10
|
+
import { refactoringMainDev } from "./refactoring-main-dev";
|
|
11
|
+
import { entityEffort } from "./entity-effort";
|
|
12
|
+
import { fragmentation } from "./fragmentation";
|
|
13
|
+
import { communication } from "./communication";
|
|
14
|
+
import { messages } from "./messages";
|
|
15
|
+
import { identity } from "./identity";
|
|
16
|
+
/** Column headers for each analysis, used when results are empty */
|
|
17
|
+
export const analysisHeaders = {
|
|
18
|
+
summary: ["statistic", "value"],
|
|
19
|
+
authors: ["entity", "n-authors", "n-revs"],
|
|
20
|
+
revisions: ["entity", "n-revs"],
|
|
21
|
+
coupling: ["entity", "coupled", "degree", "average-revs"],
|
|
22
|
+
soc: ["entity", "soc"],
|
|
23
|
+
"abs-churn": ["date", "added", "deleted", "commits"],
|
|
24
|
+
"entity-churn": ["entity", "added", "deleted", "commits"],
|
|
25
|
+
"author-churn": ["author", "added", "deleted", "commits"],
|
|
26
|
+
age: ["entity", "age-months"],
|
|
27
|
+
"entity-ownership": ["entity", "author", "added", "deleted"],
|
|
28
|
+
"main-dev": ["entity", "main-dev", "added", "total-added", "ownership"],
|
|
29
|
+
"main-dev-by-revs": ["entity", "main-dev", "added", "total-added", "ownership"],
|
|
30
|
+
"refactoring-main-dev": ["entity", "main-dev", "removed", "total-removed", "ownership"],
|
|
31
|
+
"entity-effort": ["entity", "author", "author-revs", "total-revs"],
|
|
32
|
+
fragmentation: ["entity", "fractal-value", "total-revs"],
|
|
33
|
+
communication: ["author", "peer", "shared", "average", "strength"],
|
|
34
|
+
messages: ["entity", "matches"],
|
|
35
|
+
identity: ["author", "rev", "date", "entity", "message", "loc-added", "loc-deleted"],
|
|
36
|
+
};
|
|
37
|
+
export const analyses = {
|
|
38
|
+
// Phase 1
|
|
39
|
+
summary,
|
|
40
|
+
authors,
|
|
41
|
+
revisions,
|
|
42
|
+
coupling,
|
|
43
|
+
soc: sumOfCoupling,
|
|
44
|
+
"abs-churn": absoluteChurn,
|
|
45
|
+
"entity-churn": churnByEntity,
|
|
46
|
+
"author-churn": churnByAuthor,
|
|
47
|
+
// Phase 2
|
|
48
|
+
age,
|
|
49
|
+
"entity-ownership": entityOwnership,
|
|
50
|
+
"main-dev": mainDev,
|
|
51
|
+
"main-dev-by-revs": mainDevByRevs,
|
|
52
|
+
"refactoring-main-dev": refactoringMainDev,
|
|
53
|
+
"entity-effort": entityEffort,
|
|
54
|
+
fragmentation,
|
|
55
|
+
communication,
|
|
56
|
+
messages,
|
|
57
|
+
identity,
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/analysis/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { groupBy } from "../utils/dataset";
|
|
2
|
+
function formatOwnership(ratio) {
|
|
3
|
+
const rounded = Math.round(ratio * 100) / 100;
|
|
4
|
+
const s = String(rounded);
|
|
5
|
+
return s.includes(".") ? s : s + ".0";
|
|
6
|
+
}
|
|
7
|
+
export function mainDevByRevs(data, _options) {
|
|
8
|
+
const byEntity = groupBy(data, "entity");
|
|
9
|
+
const result = [];
|
|
10
|
+
for (const [entity, mods] of byEntity) {
|
|
11
|
+
const byAuthor = groupBy(mods, "author");
|
|
12
|
+
let bestAuthor = "";
|
|
13
|
+
let bestRevs = 0;
|
|
14
|
+
let totalRevs = 0;
|
|
15
|
+
for (const [author, authorMods] of byAuthor) {
|
|
16
|
+
const uniqueRevs = new Set(authorMods.map((m) => m.rev)).size;
|
|
17
|
+
totalRevs += uniqueRevs;
|
|
18
|
+
if (uniqueRevs >= bestRevs) {
|
|
19
|
+
bestRevs = uniqueRevs;
|
|
20
|
+
bestAuthor = author;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (totalRevs > 0) {
|
|
24
|
+
result.push({
|
|
25
|
+
entity: entity,
|
|
26
|
+
"main-dev": bestAuthor,
|
|
27
|
+
added: bestRevs,
|
|
28
|
+
"total-added": totalRevs,
|
|
29
|
+
ownership: formatOwnership(bestRevs / totalRevs),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
result.sort((a, b) => a.entity.localeCompare(b.entity));
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=main-dev-by-revs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main-dev-by-revs.js","sourceRoot":"","sources":["../../src/analysis/main-dev-by-revs.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE3C,SAAS,eAAe,CAAC,KAAa;IACpC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;IAC9C,MAAM,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAC1B,OAAO,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,IAAoB,EACpB,QAAyB;IAEzB,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACzC,MAAM,MAAM,GAA8B,EAAE,CAAC;IAE7C,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,QAAQ,EAAE,CAAC;QACtC,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACzC,IAAI,UAAU,GAAG,EAAE,CAAC;QACpB,IAAI,QAAQ,GAAG,CAAC,CAAC;QACjB,IAAI,SAAS,GAAG,CAAC,CAAC;QAElB,KAAK,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,IAAI,QAAQ,EAAE,CAAC;YAC5C,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YAC9D,SAAS,IAAI,UAAU,CAAC;YACxB,IAAI,UAAU,IAAI,QAAQ,EAAE,CAAC;gBAC3B,QAAQ,GAAG,UAAU,CAAC;gBACtB,UAAU,GAAG,MAAgB,CAAC;YAChC,CAAC;QACH,CAAC;QAED,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;YAClB,MAAM,CAAC,IAAI,CAAC;gBACV,MAAM,EAAE,MAAgB;gBACxB,UAAU,EAAE,UAAU;gBACtB,KAAK,EAAE,QAAQ;gBACf,aAAa,EAAE,SAAS;gBACxB,SAAS,EAAE,eAAe,CAAC,QAAQ,GAAG,SAAS,CAAC;aACjD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAClB,CAAC,CAAC,MAAiB,CAAC,aAAa,CAAC,CAAC,CAAC,MAAgB,CAAC,CACvD,CAAC;IACF,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { groupBy } from "../utils/dataset";
|
|
2
|
+
/** Format ownership ratio to match code-maat's Clojure double formatting */
|
|
3
|
+
function formatOwnership(ratio) {
|
|
4
|
+
const rounded = Math.round(ratio * 100) / 100;
|
|
5
|
+
const s = String(rounded);
|
|
6
|
+
return s.includes(".") ? s : s + ".0";
|
|
7
|
+
}
|
|
8
|
+
export function mainDev(data, _options) {
|
|
9
|
+
const byEntity = groupBy(data, "entity");
|
|
10
|
+
const result = [];
|
|
11
|
+
for (const [entity, mods] of byEntity) {
|
|
12
|
+
const byAuthor = groupBy(mods, "author");
|
|
13
|
+
let bestAuthor = "";
|
|
14
|
+
let bestAdded = 0;
|
|
15
|
+
let totalAdded = 0;
|
|
16
|
+
for (const [author, authorMods] of byAuthor) {
|
|
17
|
+
const added = authorMods.reduce((sum, m) => sum + Math.max(0, m.locAdded), 0);
|
|
18
|
+
totalAdded += added;
|
|
19
|
+
if (added >= bestAdded) {
|
|
20
|
+
bestAdded = added;
|
|
21
|
+
bestAuthor = author;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const ownership = totalAdded > 0
|
|
25
|
+
? formatOwnership(bestAdded / totalAdded)
|
|
26
|
+
: "0.0";
|
|
27
|
+
result.push({
|
|
28
|
+
entity: entity,
|
|
29
|
+
"main-dev": bestAuthor,
|
|
30
|
+
added: bestAdded,
|
|
31
|
+
"total-added": totalAdded,
|
|
32
|
+
ownership,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
result.sort((a, b) => a.entity.localeCompare(b.entity));
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=main-dev.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main-dev.js","sourceRoot":"","sources":["../../src/analysis/main-dev.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE3C,4EAA4E;AAC5E,SAAS,eAAe,CAAC,KAAa;IACpC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;IAC9C,MAAM,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAC1B,OAAO,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,OAAO,CACrB,IAAoB,EACpB,QAAyB;IAEzB,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACzC,MAAM,MAAM,GAA8B,EAAE,CAAC;IAE7C,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,QAAQ,EAAE,CAAC;QACtC,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACzC,IAAI,UAAU,GAAG,EAAE,CAAC;QACpB,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,IAAI,UAAU,GAAG,CAAC,CAAC;QAEnB,KAAK,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,IAAI,QAAQ,EAAE,CAAC;YAC5C,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAC7B,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,EACzC,CAAC,CACF,CAAC;YACF,UAAU,IAAI,KAAK,CAAC;YACpB,IAAI,KAAK,IAAI,SAAS,EAAE,CAAC;gBACvB,SAAS,GAAG,KAAK,CAAC;gBAClB,UAAU,GAAG,MAAgB,CAAC;YAChC,CAAC;QACH,CAAC;QAED,MAAM,SAAS,GAAG,UAAU,GAAG,CAAC;YAC9B,CAAC,CAAC,eAAe,CAAC,SAAS,GAAG,UAAU,CAAC;YACzC,CAAC,CAAC,KAAK,CAAC;QACV,MAAM,CAAC,IAAI,CAAC;YACV,MAAM,EAAE,MAAgB;YACxB,UAAU,EAAE,UAAU;YACtB,KAAK,EAAE,SAAS;YAChB,aAAa,EAAE,UAAU;YACzB,SAAS;SACV,CAAC,CAAC;IACL,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAClB,CAAC,CAAC,MAAiB,CAAC,aAAa,CAAC,CAAC,CAAC,MAAgB,CAAC,CACvD,CAAC;IACF,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { groupBy, orderBy } from "../utils/dataset";
|
|
2
|
+
export function messages(data, options) {
|
|
3
|
+
if (!options.expressionToMatch) {
|
|
4
|
+
throw new Error("Messages analysis requires --expression-to-match (-e) option");
|
|
5
|
+
}
|
|
6
|
+
// Entries with message "-" are dash placeholders (format has no real messages)
|
|
7
|
+
const dashEntries = data.filter((m) => m.message === "-");
|
|
8
|
+
// If ALL entries have dash placeholder messages, the format doesn't support messages
|
|
9
|
+
if (dashEntries.length > 0 && dashEntries.length === data.length) {
|
|
10
|
+
throw new Error("Cannot do a messages analysis without commit messages. " +
|
|
11
|
+
"The input log format may not include messages.");
|
|
12
|
+
}
|
|
13
|
+
// Filter out dash placeholders before matching
|
|
14
|
+
const withMessages = data.filter((m) => m.message && m.message !== "-");
|
|
15
|
+
const regex = new RegExp(options.expressionToMatch);
|
|
16
|
+
const byEntity = groupBy(withMessages, "entity");
|
|
17
|
+
const result = [];
|
|
18
|
+
for (const [entity, mods] of byEntity) {
|
|
19
|
+
const matches = mods.filter((m) => m.message && regex.test(m.message))
|
|
20
|
+
.length;
|
|
21
|
+
if (matches > 0) {
|
|
22
|
+
result.push({ entity: entity, matches });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return orderBy(result, "matches", "desc");
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/analysis/messages.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,UAAU,QAAQ,CACtB,IAAoB,EACpB,OAAwB;IAExB,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CACb,8DAA8D,CAC/D,CAAC;IACJ,CAAC;IAED,+EAA+E;IAC/E,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,GAAG,CAAC,CAAC;IAE1D,qFAAqF;IACrF,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,IAAI,WAAW,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;QACjE,MAAM,IAAI,KAAK,CACb,yDAAyD;YACzD,gDAAgD,CACjD,CAAC;IACJ,CAAC;IAED,+CAA+C;IAC/C,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,KAAK,GAAG,CAAC,CAAC;IAExE,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACpD,MAAM,QAAQ,GAAG,OAAO,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;IACjD,MAAM,MAAM,GAA8B,EAAE,CAAC;IAE7C,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,QAAQ,EAAE,CAAC;QACtC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;aACnE,MAAM,CAAC;QACV,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAChB,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAgB,EAAE,OAAO,EAAE,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { groupBy } from "../utils/dataset";
|
|
2
|
+
function formatOwnership(ratio) {
|
|
3
|
+
const rounded = Math.round(ratio * 100) / 100;
|
|
4
|
+
const s = String(rounded);
|
|
5
|
+
return s.includes(".") ? s : s + ".0";
|
|
6
|
+
}
|
|
7
|
+
export function refactoringMainDev(data, _options) {
|
|
8
|
+
const byEntity = groupBy(data, "entity");
|
|
9
|
+
const result = [];
|
|
10
|
+
for (const [entity, mods] of byEntity) {
|
|
11
|
+
const byAuthor = groupBy(mods, "author");
|
|
12
|
+
let bestAuthor = "";
|
|
13
|
+
let bestDeleted = 0;
|
|
14
|
+
let totalDeleted = 0;
|
|
15
|
+
for (const [author, authorMods] of byAuthor) {
|
|
16
|
+
const deleted = authorMods.reduce((sum, m) => sum + Math.max(0, m.locDeleted), 0);
|
|
17
|
+
totalDeleted += deleted;
|
|
18
|
+
if (deleted >= bestDeleted) {
|
|
19
|
+
bestDeleted = deleted;
|
|
20
|
+
bestAuthor = author;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const ownership = totalDeleted > 0
|
|
24
|
+
? formatOwnership(bestDeleted / totalDeleted)
|
|
25
|
+
: "0.0";
|
|
26
|
+
result.push({
|
|
27
|
+
entity: entity,
|
|
28
|
+
"main-dev": bestAuthor,
|
|
29
|
+
removed: bestDeleted,
|
|
30
|
+
"total-removed": totalDeleted,
|
|
31
|
+
ownership,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
result.sort((a, b) => a.entity.localeCompare(b.entity));
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=refactoring-main-dev.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refactoring-main-dev.js","sourceRoot":"","sources":["../../src/analysis/refactoring-main-dev.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE3C,SAAS,eAAe,CAAC,KAAa;IACpC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;IAC9C,MAAM,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAC1B,OAAO,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,IAAoB,EACpB,QAAyB;IAEzB,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACzC,MAAM,MAAM,GAA8B,EAAE,CAAC;IAE7C,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,QAAQ,EAAE,CAAC;QACtC,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACzC,IAAI,UAAU,GAAG,EAAE,CAAC;QACpB,IAAI,WAAW,GAAG,CAAC,CAAC;QACpB,IAAI,YAAY,GAAG,CAAC,CAAC;QAErB,KAAK,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,IAAI,QAAQ,EAAE,CAAC;YAC5C,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAC/B,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,EAC3C,CAAC,CACF,CAAC;YACF,YAAY,IAAI,OAAO,CAAC;YACxB,IAAI,OAAO,IAAI,WAAW,EAAE,CAAC;gBAC3B,WAAW,GAAG,OAAO,CAAC;gBACtB,UAAU,GAAG,MAAgB,CAAC;YAChC,CAAC;QACH,CAAC;QAED,MAAM,SAAS,GAAG,YAAY,GAAG,CAAC;YAChC,CAAC,CAAC,eAAe,CAAC,WAAW,GAAG,YAAY,CAAC;YAC7C,CAAC,CAAC,KAAK,CAAC;QACV,MAAM,CAAC,IAAI,CAAC;YACV,MAAM,EAAE,MAAgB;YACxB,UAAU,EAAE,UAAU;YACtB,OAAO,EAAE,WAAW;YACpB,eAAe,EAAE,YAAY;YAC7B,SAAS;SACV,CAAC,CAAC;IACL,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAClB,CAAC,CAAC,MAAiB,CAAC,aAAa,CAAC,CAAC,CAAC,MAAgB,CAAC,CACvD,CAAC;IACF,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { groupBy, orderBy } from "../utils/dataset";
|
|
2
|
+
export function revisions(data, options) {
|
|
3
|
+
const byEntity = groupBy(data, "entity");
|
|
4
|
+
const result = [];
|
|
5
|
+
for (const [entity, mods] of byEntity) {
|
|
6
|
+
const nRevs = mods.length;
|
|
7
|
+
if (nRevs >= options.minRevs) {
|
|
8
|
+
result.push({
|
|
9
|
+
entity: entity,
|
|
10
|
+
"n-revs": nRevs,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return orderBy(result, "n-revs", "desc");
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=revisions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"revisions.js","sourceRoot":"","sources":["../../src/analysis/revisions.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,UAAU,SAAS,CACvB,IAAoB,EACpB,OAAwB;IAExB,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACzC,MAAM,MAAM,GAA8B,EAAE,CAAC;IAE7C,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,QAAQ,EAAE,CAAC;QACtC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,KAAK,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YAC7B,MAAM,CAAC,IAAI,CAAC;gBACV,MAAM,EAAE,MAAgB;gBACxB,QAAQ,EAAE,KAAK;aAChB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function summary(data, _options) {
|
|
2
|
+
const commits = new Set(data.map((m) => m.rev));
|
|
3
|
+
const entities = new Set(data.map((m) => m.entity));
|
|
4
|
+
const authors = new Set(data.map((m) => m.author));
|
|
5
|
+
return [
|
|
6
|
+
{ statistic: "number-of-commits", value: commits.size },
|
|
7
|
+
{ statistic: "number-of-entities", value: entities.size },
|
|
8
|
+
{ statistic: "number-of-entities-changed", value: data.length },
|
|
9
|
+
{ statistic: "number-of-authors", value: authors.size },
|
|
10
|
+
];
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=summary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summary.js","sourceRoot":"","sources":["../../src/analysis/summary.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,OAAO,CACrB,IAAoB,EACpB,QAAyB;IAEzB,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IAEnD,OAAO;QACL,EAAE,SAAS,EAAE,mBAAmB,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE;QACvD,EAAE,SAAS,EAAE,oBAAoB,EAAE,KAAK,EAAE,QAAQ,CAAC,IAAI,EAAE;QACzD,EAAE,SAAS,EAAE,4BAA4B,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE;QAC/D,EAAE,SAAS,EAAE,mBAAmB,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE;KACxD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Modification } from "../parsers/types";
|
|
2
|
+
export interface AnalysisOptions {
|
|
3
|
+
minRevs: number;
|
|
4
|
+
minSharedRevs: number;
|
|
5
|
+
minCoupling: number;
|
|
6
|
+
maxCoupling: number;
|
|
7
|
+
maxChangesetSize: number;
|
|
8
|
+
verboseResults?: boolean;
|
|
9
|
+
ageTimeNow?: string;
|
|
10
|
+
expressionToMatch?: string;
|
|
11
|
+
groupFile?: string;
|
|
12
|
+
teamMapFile?: string;
|
|
13
|
+
temporalPeriod?: number;
|
|
14
|
+
outputFormat?: "csv" | "json";
|
|
15
|
+
logFormat?: "git2" | "git";
|
|
16
|
+
}
|
|
17
|
+
export declare const defaultOptions: AnalysisOptions;
|
|
18
|
+
export type AnalysisFn = (data: Modification[], options: AnalysisOptions) => Record<string, unknown>[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/analysis/types.ts"],"names":[],"mappings":"AAkBA,MAAM,CAAC,MAAM,cAAc,GAAoB;IAC7C,OAAO,EAAE,CAAC;IACV,aAAa,EAAE,CAAC;IAChB,WAAW,EAAE,EAAE;IACf,WAAW,EAAE,GAAG;IAChB,gBAAgB,EAAE,EAAE;CACrB,CAAC"}
|
package/dist/app.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type AnalysisOptions } from "./analysis/types";
|
|
2
|
+
export interface AppOptions extends Partial<AnalysisOptions> {
|
|
3
|
+
log?: string;
|
|
4
|
+
repo?: string;
|
|
5
|
+
input?: string;
|
|
6
|
+
analysis: string;
|
|
7
|
+
rows?: number;
|
|
8
|
+
after?: string;
|
|
9
|
+
before?: string;
|
|
10
|
+
rev?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function run(opts: AppOptions): string;
|
package/dist/app.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { readFileSync } from "fs";
|
|
2
|
+
import { parsers } from "./parsers";
|
|
3
|
+
import { analyses, analysisHeaders } from "./analysis";
|
|
4
|
+
import { defaultOptions } from "./analysis/types";
|
|
5
|
+
import { toCSV } from "./output/csv";
|
|
6
|
+
import { toJSON } from "./output/json";
|
|
7
|
+
import { generateGitLog } from "./git";
|
|
8
|
+
import { parseGroupConfig, applyGrouping } from "./transforms/grouper";
|
|
9
|
+
import { parseTeamConfig, applyTeamMapping } from "./transforms/team-mapper";
|
|
10
|
+
import { applyTemporalGrouping } from "./transforms/temporal-grouper";
|
|
11
|
+
function getLogText(opts) {
|
|
12
|
+
if (opts.input)
|
|
13
|
+
return opts.input;
|
|
14
|
+
if (opts.log)
|
|
15
|
+
return readFileSync(opts.log, "utf-8");
|
|
16
|
+
return generateGitLog({ repo: opts.repo, after: opts.after, before: opts.before, rev: opts.rev });
|
|
17
|
+
}
|
|
18
|
+
export function run(opts) {
|
|
19
|
+
const analysisFn = analyses[opts.analysis];
|
|
20
|
+
if (!analysisFn) {
|
|
21
|
+
const available = Object.keys(analyses).join(", ");
|
|
22
|
+
throw new Error(`Unknown analysis "${opts.analysis}". Available: ${available}`);
|
|
23
|
+
}
|
|
24
|
+
const text = getLogText(opts);
|
|
25
|
+
// Filter out undefined values so defaults aren't overridden
|
|
26
|
+
const defined = Object.fromEntries(Object.entries(opts).filter(([, v]) => v !== undefined));
|
|
27
|
+
const options = { ...defaultOptions, ...defined };
|
|
28
|
+
const format = options.logFormat ?? "git2";
|
|
29
|
+
const parser = parsers[format];
|
|
30
|
+
if (!parser) {
|
|
31
|
+
throw new Error(`Unknown log format "${format}". Available: ${Object.keys(parsers).join(", ")}`);
|
|
32
|
+
}
|
|
33
|
+
let modifications = parser(text);
|
|
34
|
+
if (options.groupFile) {
|
|
35
|
+
const specs = parseGroupConfig(options.groupFile);
|
|
36
|
+
modifications = applyGrouping(modifications, specs);
|
|
37
|
+
}
|
|
38
|
+
if (options.temporalPeriod) {
|
|
39
|
+
modifications = applyTemporalGrouping(modifications, options.temporalPeriod);
|
|
40
|
+
}
|
|
41
|
+
if (options.teamMapFile) {
|
|
42
|
+
const teamMap = parseTeamConfig(options.teamMapFile);
|
|
43
|
+
modifications = applyTeamMapping(modifications, teamMap);
|
|
44
|
+
}
|
|
45
|
+
let result = analysisFn(modifications, options);
|
|
46
|
+
if (opts.rows && opts.rows > 0) {
|
|
47
|
+
result = result.slice(0, opts.rows);
|
|
48
|
+
}
|
|
49
|
+
if (options.outputFormat === "json") {
|
|
50
|
+
return toJSON(result);
|
|
51
|
+
}
|
|
52
|
+
return toCSV(result, analysisHeaders[opts.analysis]);
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=app.js.map
|
package/dist/app.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|