flakeradar 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.
Files changed (72) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +309 -0
  3. package/bin/flakeradar.js +11 -0
  4. package/dist/analysis/classify.d.ts +10 -0
  5. package/dist/analysis/classify.d.ts.map +1 -0
  6. package/dist/analysis/classify.js +163 -0
  7. package/dist/analysis/classify.js.map +1 -0
  8. package/dist/analysis/flakiness.d.ts +11 -0
  9. package/dist/analysis/flakiness.d.ts.map +1 -0
  10. package/dist/analysis/flakiness.js +177 -0
  11. package/dist/analysis/flakiness.js.map +1 -0
  12. package/dist/cli.d.ts +5 -0
  13. package/dist/cli.d.ts.map +1 -0
  14. package/dist/cli.js +77 -0
  15. package/dist/cli.js.map +1 -0
  16. package/dist/color.d.ts +19 -0
  17. package/dist/color.d.ts.map +1 -0
  18. package/dist/color.js +36 -0
  19. package/dist/color.js.map +1 -0
  20. package/dist/commands/analyze.d.ts +4 -0
  21. package/dist/commands/analyze.d.ts.map +1 -0
  22. package/dist/commands/analyze.js +106 -0
  23. package/dist/commands/analyze.js.map +1 -0
  24. package/dist/commands/run.d.ts +4 -0
  25. package/dist/commands/run.d.ts.map +1 -0
  26. package/dist/commands/run.js +116 -0
  27. package/dist/commands/run.js.map +1 -0
  28. package/dist/commands/shared.d.ts +16 -0
  29. package/dist/commands/shared.d.ts.map +1 -0
  30. package/dist/commands/shared.js +44 -0
  31. package/dist/commands/shared.js.map +1 -0
  32. package/dist/index.d.ts +14 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +13 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/junit/parser.d.ts +11 -0
  37. package/dist/junit/parser.d.ts.map +1 -0
  38. package/dist/junit/parser.js +98 -0
  39. package/dist/junit/parser.js.map +1 -0
  40. package/dist/junit/xml.d.ts +27 -0
  41. package/dist/junit/xml.d.ts.map +1 -0
  42. package/dist/junit/xml.js +238 -0
  43. package/dist/junit/xml.js.map +1 -0
  44. package/dist/report/json.d.ts +7 -0
  45. package/dist/report/json.d.ts.map +1 -0
  46. package/dist/report/json.js +38 -0
  47. package/dist/report/json.js.map +1 -0
  48. package/dist/report/markdown.d.ts +7 -0
  49. package/dist/report/markdown.d.ts.map +1 -0
  50. package/dist/report/markdown.js +75 -0
  51. package/dist/report/markdown.js.map +1 -0
  52. package/dist/report/terminal.d.ts +4 -0
  53. package/dist/report/terminal.d.ts.map +1 -0
  54. package/dist/report/terminal.js +101 -0
  55. package/dist/report/terminal.js.map +1 -0
  56. package/dist/runner/runner.d.ts +45 -0
  57. package/dist/runner/runner.d.ts.map +1 -0
  58. package/dist/runner/runner.js +125 -0
  59. package/dist/runner/runner.js.map +1 -0
  60. package/dist/types.d.ts +87 -0
  61. package/dist/types.d.ts.map +1 -0
  62. package/dist/types.js +2 -0
  63. package/dist/types.js.map +1 -0
  64. package/dist/util/args.d.ts +23 -0
  65. package/dist/util/args.d.ts.map +1 -0
  66. package/dist/util/args.js +83 -0
  67. package/dist/util/args.js.map +1 -0
  68. package/dist/util/glob.d.ts +11 -0
  69. package/dist/util/glob.d.ts.map +1 -0
  70. package/dist/util/glob.js +104 -0
  71. package/dist/util/glob.js.map +1 -0
  72. package/package.json +62 -0
@@ -0,0 +1,44 @@
1
+ import { renderJson } from "../report/json.js";
2
+ import { renderMarkdown } from "../report/markdown.js";
3
+ import { renderTerminal } from "../report/terminal.js";
4
+ export function resolveFormat(args) {
5
+ if (args.bools.has("json"))
6
+ return "json";
7
+ if (args.bools.has("markdown"))
8
+ return "markdown";
9
+ return "terminal";
10
+ }
11
+ export function renderReport(report, format) {
12
+ switch (format) {
13
+ case "json":
14
+ return renderJson(report);
15
+ case "markdown":
16
+ return renderMarkdown(report);
17
+ case "terminal":
18
+ return renderTerminal(report);
19
+ }
20
+ }
21
+ /**
22
+ * Exit code convention:
23
+ * 0 success
24
+ * 1 usage / input error
25
+ * 2 flaky (or always-failing) tests detected AND --fail-on-flaky was set
26
+ */
27
+ export function exitCodeFor(report, failOnFlaky) {
28
+ if (!failOnFlaky)
29
+ return 0;
30
+ const bad = report.summary.flakyCount + report.summary.alwaysFailCount;
31
+ return bad > 0 ? 2 : 0;
32
+ }
33
+ export function parseRunCount(raw, fallback) {
34
+ if (raw === undefined)
35
+ return fallback;
36
+ const n = Number(raw);
37
+ if (!Number.isInteger(n) || n < 1) {
38
+ throw new UsageError(`--runs must be a positive integer (got "${raw}")`);
39
+ }
40
+ return n;
41
+ }
42
+ export class UsageError extends Error {
43
+ }
44
+ //# sourceMappingURL=shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/commands/shared.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAMvD,MAAM,UAAU,aAAa,CAAC,IAAgB;IAC5C,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IAC1C,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC;QAAE,OAAO,UAAU,CAAC;IAClD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAsB,EAAE,MAAc;IACjE,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,MAAM;YACT,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC;QAC5B,KAAK,UAAU;YACb,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC;QAChC,KAAK,UAAU;YACb,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC;IAClC,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,MAAsB,EAAE,WAAoB;IACtE,IAAI,CAAC,WAAW;QAAE,OAAO,CAAC,CAAC;IAC3B,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC;IACvE,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAuB,EAAE,QAAgB;IACrE,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC;IACvC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IACtB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,UAAU,CAAC,2CAA2C,GAAG,IAAI,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,OAAO,UAAW,SAAQ,KAAK;CAAG"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Public API. `flakeradar` is primarily a CLI, but the analysis engine is
3
+ * usable as a library too — handy for building custom CI integrations.
4
+ */
5
+ export { analyze, runFromResults, compareFlaky } from "./analysis/flakiness.js";
6
+ export { classifyCause, causeLabel } from "./analysis/classify.js";
7
+ export { parseJUnitXml } from "./junit/parser.js";
8
+ export { parseXml, decodeEntities } from "./junit/xml.js";
9
+ export { renderJson } from "./report/json.js";
10
+ export { renderMarkdown } from "./report/markdown.js";
11
+ export { renderTerminal } from "./report/terminal.js";
12
+ export { main, getVersion } from "./cli.js";
13
+ export type { AnalysisReport, CauseCategory, CauseGuess, Run, SuiteSummary, TestResult, TestStatus, TestVerdict, } from "./types.js";
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC5C,YAAY,EACV,cAAc,EACd,aAAa,EACb,UAAU,EACV,GAAG,EACH,YAAY,EACZ,UAAU,EACV,UAAU,EACV,WAAW,GACZ,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Public API. `flakeradar` is primarily a CLI, but the analysis engine is
3
+ * usable as a library too — handy for building custom CI integrations.
4
+ */
5
+ export { analyze, runFromResults, compareFlaky } from "./analysis/flakiness.js";
6
+ export { classifyCause, causeLabel } from "./analysis/classify.js";
7
+ export { parseJUnitXml } from "./junit/parser.js";
8
+ export { parseXml, decodeEntities } from "./junit/xml.js";
9
+ export { renderJson } from "./report/json.js";
10
+ export { renderMarkdown } from "./report/markdown.js";
11
+ export { renderTerminal } from "./report/terminal.js";
12
+ export { main, getVersion } from "./cli.js";
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { TestResult } from "../types.js";
2
+ /**
3
+ * Parse a single JUnit XML document into a flat list of test results.
4
+ *
5
+ * Handles both `<testsuites>` and bare `<testsuite>` roots, plus the common
6
+ * dialects emitted by pytest, Jest, Gradle/Maven (Surefire), RSpec, PHPUnit,
7
+ * gotestsum, and others. Malformed reports yield an empty list rather than
8
+ * throwing, so one bad file never aborts a whole analysis.
9
+ */
10
+ export declare function parseJUnitXml(xml: string, source?: string): TestResult[];
11
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/junit/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,aAAa,CAAC;AAG1D;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,SAAa,GAAG,UAAU,EAAE,CAY5E"}
@@ -0,0 +1,98 @@
1
+ import { findAll, parseXml, XmlParseError } from "./xml.js";
2
+ /**
3
+ * Parse a single JUnit XML document into a flat list of test results.
4
+ *
5
+ * Handles both `<testsuites>` and bare `<testsuite>` roots, plus the common
6
+ * dialects emitted by pytest, Jest, Gradle/Maven (Surefire), RSpec, PHPUnit,
7
+ * gotestsum, and others. Malformed reports yield an empty list rather than
8
+ * throwing, so one bad file never aborts a whole analysis.
9
+ */
10
+ export function parseJUnitXml(xml, source = "<memory>") {
11
+ let root;
12
+ try {
13
+ root = parseXml(xml);
14
+ }
15
+ catch (err) {
16
+ if (err instanceof XmlParseError)
17
+ return [];
18
+ throw err;
19
+ }
20
+ const testcases = findAll(root, "testcase");
21
+ // If the root itself is a <testcase> (degenerate), include it too.
22
+ if (root.name === "testcase")
23
+ testcases.unshift(root);
24
+ return testcases.map((tc) => toResult(tc, source));
25
+ }
26
+ function toResult(tc, source) {
27
+ const name = firstNonEmpty(tc.attrs["name"], "<unnamed>");
28
+ const classname = firstNonEmpty(tc.attrs["classname"], tc.attrs["class"], "");
29
+ const status = resolveStatus(tc);
30
+ const durationMs = parseDuration(tc.attrs["time"]);
31
+ let message = null;
32
+ let details = null;
33
+ if (status === "failed" || status === "error") {
34
+ const node = child(tc, status === "failed" ? "failure" : "error") ?? child(tc, "failure") ?? child(tc, "error");
35
+ if (node) {
36
+ message = firstNonEmpty(node.attrs["message"], firstLine(node.text)) || null;
37
+ details = node.text.trim() || null;
38
+ }
39
+ }
40
+ return {
41
+ id: makeId(classname, name),
42
+ name,
43
+ classname,
44
+ status,
45
+ durationMs,
46
+ message: clip(message, 500),
47
+ details: clip(details, 4000),
48
+ // `source` is retained implicitly via the run label; kept out of the id.
49
+ };
50
+ }
51
+ function resolveStatus(tc) {
52
+ if (child(tc, "failure"))
53
+ return "failed";
54
+ if (child(tc, "error"))
55
+ return "error";
56
+ if (child(tc, "skipped"))
57
+ return "skipped";
58
+ // Some emitters use a `status` attribute instead of child nodes.
59
+ const attr = (tc.attrs["status"] ?? "").toLowerCase();
60
+ if (attr === "fail" || attr === "failed")
61
+ return "failed";
62
+ if (attr === "error" || attr === "broken")
63
+ return "error";
64
+ if (attr === "skipped" || attr === "ignored" || attr === "disabled")
65
+ return "skipped";
66
+ return "passed";
67
+ }
68
+ function makeId(classname, name) {
69
+ return classname ? `${classname}::${name}` : name;
70
+ }
71
+ function parseDuration(time) {
72
+ if (time === undefined || time === "")
73
+ return null;
74
+ const seconds = Number(time);
75
+ if (!Number.isFinite(seconds) || seconds < 0)
76
+ return null;
77
+ return Math.round(seconds * 1000);
78
+ }
79
+ function child(node, name) {
80
+ return node.children.find((c) => c.name === name);
81
+ }
82
+ function firstNonEmpty(...values) {
83
+ for (const v of values) {
84
+ if (v !== undefined && v.trim() !== "")
85
+ return v;
86
+ }
87
+ return "";
88
+ }
89
+ function firstLine(text) {
90
+ const line = text.split("\n").map((l) => l.trim()).find((l) => l.length > 0);
91
+ return line ?? "";
92
+ }
93
+ function clip(value, max) {
94
+ if (value === null)
95
+ return null;
96
+ return value.length > max ? `${value.slice(0, max)}…` : value;
97
+ }
98
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/junit/parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Minimal, dependency-free XML parser scoped to what JUnit reports need:
3
+ * elements, attributes, text, CDATA, comments, self-closing tags, and the
4
+ * standard XML entities. It is intentionally lenient — real-world CI tools emit
5
+ * slightly non-conformant XML, and we would rather extract signal than reject.
6
+ */
7
+ export interface XmlNode {
8
+ name: string;
9
+ attrs: Record<string, string>;
10
+ children: XmlNode[];
11
+ /** Concatenated direct text + CDATA content of this element. */
12
+ text: string;
13
+ }
14
+ export declare class XmlParseError extends Error {
15
+ }
16
+ /** Decode the five predefined XML entities plus numeric character references. */
17
+ export declare function decodeEntities(input: string): string;
18
+ /**
19
+ * Parse a full XML document and return its root element.
20
+ * Throws {@link XmlParseError} when no root element can be found.
21
+ */
22
+ export declare function parseXml(input: string): XmlNode;
23
+ /** Return direct child elements matching `name` (case-sensitive). */
24
+ export declare function childrenNamed(node: XmlNode, name: string): XmlNode[];
25
+ /** Recursively collect all descendant elements matching `name`. */
26
+ export declare function findAll(node: XmlNode, name: string, acc?: XmlNode[]): XmlNode[];
27
+ //# sourceMappingURL=xml.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xml.d.ts","sourceRoot":"","sources":["../../src/junit/xml.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;CACd;AAED,qBAAa,aAAc,SAAQ,KAAK;CAAG;AAM3C,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CA+BpD;AAqBD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAS/C;AAmJD,qEAAqE;AACrE,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE,CAEpE;AAED,mEAAmE;AACnE,wBAAgB,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,GAAE,OAAO,EAAO,GAAG,OAAO,EAAE,CAMnF"}
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Minimal, dependency-free XML parser scoped to what JUnit reports need:
3
+ * elements, attributes, text, CDATA, comments, self-closing tags, and the
4
+ * standard XML entities. It is intentionally lenient — real-world CI tools emit
5
+ * slightly non-conformant XML, and we would rather extract signal than reject.
6
+ */
7
+ export class XmlParseError extends Error {
8
+ }
9
+ const NAME_START = /[A-Za-z_:]/;
10
+ const NAME_CHAR = /[A-Za-z0-9_:.\-]/;
11
+ const WS = /\s/;
12
+ /** Decode the five predefined XML entities plus numeric character references. */
13
+ export function decodeEntities(input) {
14
+ if (input.indexOf("&") === -1)
15
+ return input;
16
+ return input.replace(/&(#x?[0-9a-fA-F]+|[a-zA-Z][a-zA-Z0-9]*);/g, (whole, body) => {
17
+ switch (body) {
18
+ case "amp":
19
+ return "&";
20
+ case "lt":
21
+ return "<";
22
+ case "gt":
23
+ return ">";
24
+ case "quot":
25
+ return '"';
26
+ case "apos":
27
+ return "'";
28
+ default:
29
+ break;
30
+ }
31
+ if (body[0] === "#") {
32
+ const isHex = body[1] === "x" || body[1] === "X";
33
+ const digits = isHex ? body.slice(2) : body.slice(1);
34
+ const code = parseInt(digits, isHex ? 16 : 10);
35
+ if (Number.isNaN(code) || code < 0 || code > 0x10ffff)
36
+ return whole;
37
+ try {
38
+ return String.fromCodePoint(code);
39
+ }
40
+ catch {
41
+ return whole;
42
+ }
43
+ }
44
+ // Unknown named entity: leave it untouched rather than losing data.
45
+ return whole;
46
+ });
47
+ }
48
+ class Cursor {
49
+ s;
50
+ i;
51
+ constructor(s, i = 0) {
52
+ this.s = s;
53
+ this.i = i;
54
+ }
55
+ get eof() {
56
+ return this.i >= this.s.length;
57
+ }
58
+ peek(offset = 0) {
59
+ return this.s[this.i + offset] ?? "";
60
+ }
61
+ startsWith(token) {
62
+ return this.s.startsWith(token, this.i);
63
+ }
64
+ skipWhitespace() {
65
+ while (!this.eof && WS.test(this.s[this.i]))
66
+ this.i++;
67
+ }
68
+ }
69
+ /**
70
+ * Parse a full XML document and return its root element.
71
+ * Throws {@link XmlParseError} when no root element can be found.
72
+ */
73
+ export function parseXml(input) {
74
+ const cur = new Cursor(stripBom(input));
75
+ skipProlog(cur);
76
+ cur.skipWhitespace();
77
+ if (cur.peek() !== "<") {
78
+ throw new XmlParseError("no root element found");
79
+ }
80
+ const root = parseElement(cur);
81
+ return root;
82
+ }
83
+ function stripBom(s) {
84
+ return s.charCodeAt(0) === 0xfeff ? s.slice(1) : s;
85
+ }
86
+ /** Skip declarations, comments, doctype and stray whitespace before the root. */
87
+ function skipProlog(cur) {
88
+ for (;;) {
89
+ cur.skipWhitespace();
90
+ if (cur.startsWith("<?")) {
91
+ const end = cur.s.indexOf("?>", cur.i);
92
+ cur.i = end === -1 ? cur.s.length : end + 2;
93
+ continue;
94
+ }
95
+ if (cur.startsWith("<!--")) {
96
+ const end = cur.s.indexOf("-->", cur.i);
97
+ cur.i = end === -1 ? cur.s.length : end + 3;
98
+ continue;
99
+ }
100
+ if (cur.startsWith("<!")) {
101
+ // DOCTYPE or similar — skip to the next '>' (JUnit never nests these).
102
+ const end = cur.s.indexOf(">", cur.i);
103
+ cur.i = end === -1 ? cur.s.length : end + 1;
104
+ continue;
105
+ }
106
+ return;
107
+ }
108
+ }
109
+ function parseName(cur) {
110
+ const start = cur.i;
111
+ if (!NAME_START.test(cur.peek())) {
112
+ throw new XmlParseError(`invalid tag name at offset ${cur.i}`);
113
+ }
114
+ cur.i++;
115
+ while (!cur.eof && NAME_CHAR.test(cur.peek()))
116
+ cur.i++;
117
+ return cur.s.slice(start, cur.i);
118
+ }
119
+ function parseAttributes(cur) {
120
+ const attrs = {};
121
+ for (;;) {
122
+ cur.skipWhitespace();
123
+ const c = cur.peek();
124
+ if (c === ">" || c === "/" || c === "")
125
+ return attrs;
126
+ const name = parseName(cur);
127
+ cur.skipWhitespace();
128
+ if (cur.peek() === "=") {
129
+ cur.i++;
130
+ cur.skipWhitespace();
131
+ const quote = cur.peek();
132
+ if (quote === '"' || quote === "'") {
133
+ cur.i++;
134
+ const end = cur.s.indexOf(quote, cur.i);
135
+ const raw = end === -1 ? cur.s.slice(cur.i) : cur.s.slice(cur.i, end);
136
+ cur.i = end === -1 ? cur.s.length : end + 1;
137
+ attrs[name] = decodeEntities(raw);
138
+ }
139
+ else {
140
+ // Unquoted attribute value (non-conformant but seen in the wild).
141
+ const start = cur.i;
142
+ while (!cur.eof && !WS.test(cur.peek()) && cur.peek() !== ">" && cur.peek() !== "/")
143
+ cur.i++;
144
+ attrs[name] = decodeEntities(cur.s.slice(start, cur.i));
145
+ }
146
+ }
147
+ else {
148
+ attrs[name] = "";
149
+ }
150
+ }
151
+ }
152
+ function parseElement(cur) {
153
+ if (cur.peek() !== "<")
154
+ throw new XmlParseError(`expected '<' at offset ${cur.i}`);
155
+ cur.i++; // consume '<'
156
+ const name = parseName(cur);
157
+ const attrs = parseAttributes(cur);
158
+ cur.skipWhitespace();
159
+ const node = { name, attrs, children: [], text: "" };
160
+ if (cur.startsWith("/>")) {
161
+ cur.i += 2;
162
+ return node;
163
+ }
164
+ if (cur.peek() !== ">") {
165
+ throw new XmlParseError(`malformed tag <${name}> at offset ${cur.i}`);
166
+ }
167
+ cur.i++; // consume '>'
168
+ parseContent(cur, node);
169
+ return node;
170
+ }
171
+ function parseContent(cur, node) {
172
+ // Ordinary text is entity-decoded as it is appended; CDATA is appended raw.
173
+ // Accumulating already-decoded text avoids re-decoding CDATA at flush time.
174
+ let textBuf = "";
175
+ const flushText = () => {
176
+ if (textBuf.length > 0) {
177
+ node.text += textBuf;
178
+ textBuf = "";
179
+ }
180
+ };
181
+ for (;;) {
182
+ if (cur.eof) {
183
+ // Unterminated element — accept what we have rather than throwing.
184
+ flushText();
185
+ return;
186
+ }
187
+ if (cur.peek() === "<") {
188
+ if (cur.startsWith("<![CDATA[")) {
189
+ const end = cur.s.indexOf("]]>", cur.i);
190
+ const body = end === -1 ? cur.s.slice(cur.i + 9) : cur.s.slice(cur.i + 9, end);
191
+ textBuf += body; // CDATA is literal — no entity decoding.
192
+ cur.i = end === -1 ? cur.s.length : end + 3;
193
+ continue;
194
+ }
195
+ if (cur.startsWith("<!--")) {
196
+ const end = cur.s.indexOf("-->", cur.i);
197
+ cur.i = end === -1 ? cur.s.length : end + 3;
198
+ continue;
199
+ }
200
+ if (cur.startsWith("</")) {
201
+ flushText();
202
+ cur.i += 2;
203
+ parseName(cur); // closing tag name (not validated against opener)
204
+ const gt = cur.s.indexOf(">", cur.i);
205
+ cur.i = gt === -1 ? cur.s.length : gt + 1;
206
+ return;
207
+ }
208
+ // Nested child element.
209
+ flushText();
210
+ node.children.push(parseElement(cur));
211
+ continue;
212
+ }
213
+ // Ordinary text — accumulate (decoded) until the next '<'.
214
+ const next = cur.s.indexOf("<", cur.i);
215
+ if (next === -1) {
216
+ textBuf += decodeEntities(cur.s.slice(cur.i));
217
+ cur.i = cur.s.length;
218
+ }
219
+ else {
220
+ textBuf += decodeEntities(cur.s.slice(cur.i, next));
221
+ cur.i = next;
222
+ }
223
+ }
224
+ }
225
+ /** Return direct child elements matching `name` (case-sensitive). */
226
+ export function childrenNamed(node, name) {
227
+ return node.children.filter((c) => c.name === name);
228
+ }
229
+ /** Recursively collect all descendant elements matching `name`. */
230
+ export function findAll(node, name, acc = []) {
231
+ for (const child of node.children) {
232
+ if (child.name === name)
233
+ acc.push(child);
234
+ findAll(child, name, acc);
235
+ }
236
+ return acc;
237
+ }
238
+ //# sourceMappingURL=xml.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xml.js","sourceRoot":"","sources":["../../src/junit/xml.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { AnalysisReport } from "../types.js";
2
+ /**
3
+ * Render the report as stable, machine-readable JSON for CI consumers.
4
+ * The shape mirrors {@link AnalysisReport} plus a schema version.
5
+ */
6
+ export declare function renderJson(report: AnalysisReport): string;
7
+ //# sourceMappingURL=json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../src/report/json.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAQzD"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Render the report as stable, machine-readable JSON for CI consumers.
3
+ * The shape mirrors {@link AnalysisReport} plus a schema version.
4
+ */
5
+ export function renderJson(report) {
6
+ const payload = {
7
+ schema: "flakeradar/v1",
8
+ summary: report.summary,
9
+ flaky: report.flaky.map(serializeVerdict),
10
+ alwaysFailing: report.alwaysFailing.map(serializeVerdict),
11
+ };
12
+ return JSON.stringify(payload, null, 2);
13
+ }
14
+ function serializeVerdict(v) {
15
+ return {
16
+ id: v.id,
17
+ name: v.name,
18
+ classname: v.classname,
19
+ runsSeen: v.runsSeen,
20
+ passes: v.passes,
21
+ failures: v.failures,
22
+ skips: v.skips,
23
+ failureRate: round(v.failureRate, 4),
24
+ flips: v.flips,
25
+ flaky: v.flaky,
26
+ alwaysFails: v.alwaysFails,
27
+ score: v.score,
28
+ cause: v.cause
29
+ ? { category: v.cause.category, confidence: v.cause.confidence, hint: v.cause.hint }
30
+ : null,
31
+ sampleMessages: v.sampleMessages,
32
+ };
33
+ }
34
+ function round(n, digits) {
35
+ const f = 10 ** digits;
36
+ return Math.round(n * f) / f;
37
+ }
38
+ //# sourceMappingURL=json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/report/json.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,MAAsB;IAC/C,MAAM,OAAO,GAAG;QACd,MAAM,EAAE,eAAe;QACvB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC;QACzC,aAAa,EAAE,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,gBAAgB,CAAC;KAC1D,CAAC;IACF,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAC1C,CAAC;AAED,SAAS,gBAAgB,CAAC,CAAkC;IAC1D,OAAO;QACL,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,SAAS,EAAE,CAAC,CAAC,SAAS;QACtB,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;QACpC,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,KAAK,EAAE,CAAC,CAAC,KAAK;YACZ,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE;YACpF,CAAC,CAAC,IAAI;QACR,cAAc,EAAE,CAAC,CAAC,cAAc;KACjC,CAAC;AACJ,CAAC;AAED,SAAS,KAAK,CAAC,CAAS,EAAE,MAAc;IACtC,MAAM,CAAC,GAAG,EAAE,IAAI,MAAM,CAAC;IACvB,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { AnalysisReport } from "../types.js";
2
+ /**
3
+ * Render a GitHub-flavored Markdown report — designed to be pasted straight
4
+ * into an issue or PR comment. This is the shareable artifact.
5
+ */
6
+ export declare function renderMarkdown(report: AnalysisReport): string;
7
+ //# sourceMappingURL=markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/report/markdown.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAe,MAAM,aAAa,CAAC;AAU/D;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CA4C7D"}
@@ -0,0 +1,75 @@
1
+ import { causeLabel } from "../analysis/classify.js";
2
+ const pct = (n) => `${Math.round(n * 100)}%`;
3
+ const ratio = (v) => `${v.failures}/${v.passes + v.failures}`;
4
+ /** Escape pipe and backtick so test ids don't break Markdown tables. */
5
+ function esc(s) {
6
+ return s.replace(/\|/g, "\\|").replace(/`/g, "\\`");
7
+ }
8
+ /**
9
+ * Render a GitHub-flavored Markdown report — designed to be pasted straight
10
+ * into an issue or PR comment. This is the shareable artifact.
11
+ */
12
+ export function renderMarkdown(report) {
13
+ const { summary, flaky, alwaysFailing } = report;
14
+ const out = [];
15
+ out.push("## 🛰️ flakeradar report");
16
+ out.push("");
17
+ out.push(`**${summary.flakyCount}** flaky · ` +
18
+ `**${summary.alwaysFailCount}** always-failing · ` +
19
+ `**${summary.uniqueTests}** tests across **${summary.totalRuns}** runs · ` +
20
+ `green-run rate **${pct(summary.greenRunRate)}**` +
21
+ (summary.crashedRuns > 0 ? ` · ⚠️ **${summary.crashedRuns}** crashed run(s)` : ""));
22
+ out.push("");
23
+ if (flaky.length === 0) {
24
+ out.push("✅ **No flaky tests detected** — every test was consistent across all runs.");
25
+ }
26
+ else {
27
+ out.push("### Flaky tests (ranked)");
28
+ out.push("");
29
+ out.push("| # | Test | Fails | Rate | Flips | Likely cause | Conf |");
30
+ out.push("|---|------|:-----:|:----:|:-----:|--------------|:----:|");
31
+ flaky.forEach((v, i) => {
32
+ const cause = v.cause ? causeLabel(v.cause.category) : "-";
33
+ const conf = v.cause ? pct(v.cause.confidence) : "-";
34
+ out.push(`| ${i + 1} | \`${esc(v.id)}\` | ${ratio(v)} | ${pct(v.failureRate)} | ${v.flips} | ${cause} | ${conf} |`);
35
+ });
36
+ out.push("");
37
+ out.push(renderDetails(flaky));
38
+ }
39
+ if (alwaysFailing.length > 0) {
40
+ out.push("");
41
+ out.push("### Always-failing (likely real bugs, not flakiness)");
42
+ out.push("");
43
+ for (const v of alwaysFailing.slice(0, 20)) {
44
+ out.push(`- \`${esc(v.id)}\` — failed ${v.failures}/${v.failures} runs`);
45
+ }
46
+ if (alwaysFailing.length > 20)
47
+ out.push(`- …and ${alwaysFailing.length - 20} more`);
48
+ }
49
+ out.push("");
50
+ out.push("<sub>Generated by <a href=\"https://github.com/shravnn/flakeradar\">flakeradar</a>.</sub>");
51
+ return out.join("\n");
52
+ }
53
+ function renderDetails(flaky) {
54
+ const out = [];
55
+ out.push("<details><summary>Failure samples &amp; suggested fixes</summary>");
56
+ out.push("");
57
+ for (const v of flaky.slice(0, 15)) {
58
+ out.push(`**\`${esc(v.id)}\`** — ${ratio(v)} failed (${pct(v.failureRate)})`);
59
+ if (v.cause) {
60
+ out.push("");
61
+ out.push(`> **${causeLabel(v.cause.category)}** (${pct(v.cause.confidence)} confident): ${v.cause.hint}`);
62
+ }
63
+ if (v.sampleMessages.length > 0) {
64
+ out.push("");
65
+ out.push("```");
66
+ for (const m of v.sampleMessages)
67
+ out.push(m);
68
+ out.push("```");
69
+ }
70
+ out.push("");
71
+ }
72
+ out.push("</details>");
73
+ return out.join("\n");
74
+ }
75
+ //# sourceMappingURL=markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/report/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAGrD,MAAM,GAAG,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC;AAC7D,MAAM,KAAK,GAAG,CAAC,CAAc,EAAU,EAAE,CAAC,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC;AAEnF,wEAAwE;AACxE,SAAS,GAAG,CAAC,CAAS;IACpB,OAAO,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AACtD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,MAAsB;IACnD,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,MAAM,CAAC;IACjD,MAAM,GAAG,GAAa,EAAE,CAAC;IAEzB,GAAG,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;IACrC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACb,GAAG,CAAC,IAAI,CACN,KAAK,OAAO,CAAC,UAAU,aAAa;QAClC,KAAK,OAAO,CAAC,eAAe,sBAAsB;QAClD,KAAK,OAAO,CAAC,WAAW,qBAAqB,OAAO,CAAC,SAAS,YAAY;QAC1E,oBAAoB,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI;QACjD,CAAC,OAAO,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,OAAO,CAAC,WAAW,mBAAmB,CAAC,CAAC,CAAC,EAAE,CAAC,CACrF,CAAC;IACF,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEb,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,GAAG,CAAC,IAAI,CAAC,4EAA4E,CAAC,CAAC;IACzF,CAAC;SAAM,CAAC;QACN,GAAG,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;QACrC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACb,GAAG,CAAC,IAAI,CAAC,2DAA2D,CAAC,CAAC;QACtE,GAAG,CAAC,IAAI,CAAC,2DAA2D,CAAC,CAAC;QACtE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACrB,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;YAC3D,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;YACrD,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,KAAK,MAAM,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC;QACtH,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACb,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;IACjC,CAAC;IAED,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACb,GAAG,CAAC,IAAI,CAAC,sDAAsD,CAAC,CAAC;QACjE,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACb,KAAK,MAAM,CAAC,IAAI,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;YAC3C,GAAG,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,QAAQ,OAAO,CAAC,CAAC;QAC3E,CAAC;QACD,IAAI,aAAa,CAAC,MAAM,GAAG,EAAE;YAAE,GAAG,CAAC,IAAI,CAAC,UAAU,aAAa,CAAC,MAAM,GAAG,EAAE,OAAO,CAAC,CAAC;IACtF,CAAC;IAED,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACb,GAAG,CAAC,IAAI,CAAC,2FAA2F,CAAC,CAAC;IACtG,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACxB,CAAC;AAED,SAAS,aAAa,CAAC,KAAoB;IACzC,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,GAAG,CAAC,IAAI,CAAC,mEAAmE,CAAC,CAAC;IAC9E,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACb,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;QACnC,GAAG,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,KAAK,CAAC,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAC9E,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;YACZ,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACb,GAAG,CAAC,IAAI,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QAC5G,CAAC;QACD,IAAI,CAAC,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACb,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChB,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,cAAc;gBAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC9C,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClB,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,CAAC;IACD,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACvB,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACxB,CAAC"}