@refract-org/analyzers 0.2.1
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 +38 -0
- package/dist/src/category-tracker.d.ts +8 -0
- package/dist/src/category-tracker.d.ts.map +1 -0
- package/dist/src/category-tracker.js +60 -0
- package/dist/src/category-tracker.js.map +1 -0
- package/dist/src/citation-tracker.d.ts +13 -0
- package/dist/src/citation-tracker.d.ts.map +1 -0
- package/dist/src/citation-tracker.js +200 -0
- package/dist/src/citation-tracker.js.map +1 -0
- package/dist/src/claim-differ.d.ts +2 -0
- package/dist/src/claim-differ.d.ts.map +1 -0
- package/dist/src/claim-differ.js +6 -0
- package/dist/src/claim-differ.js.map +1 -0
- package/dist/src/edit-cluster-detector.d.ts +14 -0
- package/dist/src/edit-cluster-detector.d.ts.map +1 -0
- package/dist/src/edit-cluster-detector.js +57 -0
- package/dist/src/edit-cluster-detector.js.map +1 -0
- package/dist/src/heuristic-classifier.d.ts +9 -0
- package/dist/src/heuristic-classifier.d.ts.map +1 -0
- package/dist/src/heuristic-classifier.js +33 -0
- package/dist/src/heuristic-classifier.js.map +1 -0
- package/dist/src/index.d.ts +70 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +16 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/observation-differ.d.ts +8 -0
- package/dist/src/observation-differ.d.ts.map +1 -0
- package/dist/src/observation-differ.js +16 -0
- package/dist/src/observation-differ.js.map +1 -0
- package/dist/src/page-move-detector.d.ts +11 -0
- package/dist/src/page-move-detector.d.ts.map +1 -0
- package/dist/src/page-move-detector.js +21 -0
- package/dist/src/page-move-detector.js.map +1 -0
- package/dist/src/protection-tracker.d.ts +23 -0
- package/dist/src/protection-tracker.d.ts.map +1 -0
- package/dist/src/protection-tracker.js +74 -0
- package/dist/src/protection-tracker.js.map +1 -0
- package/dist/src/revert-detector.d.ts +3 -0
- package/dist/src/revert-detector.d.ts.map +1 -0
- package/dist/src/revert-detector.js +43 -0
- package/dist/src/revert-detector.js.map +1 -0
- package/dist/src/section-differ.d.ts +26 -0
- package/dist/src/section-differ.d.ts.map +1 -0
- package/dist/src/section-differ.js +268 -0
- package/dist/src/section-differ.js.map +1 -0
- package/dist/src/talk-activity-detector.d.ts +16 -0
- package/dist/src/talk-activity-detector.d.ts.map +1 -0
- package/dist/src/talk-activity-detector.js +76 -0
- package/dist/src/talk-activity-detector.js.map +1 -0
- package/dist/src/talk-correlator.d.ts +7 -0
- package/dist/src/talk-correlator.d.ts.map +1 -0
- package/dist/src/talk-correlator.js +53 -0
- package/dist/src/talk-correlator.js.map +1 -0
- package/dist/src/talk-section-parser.d.ts +22 -0
- package/dist/src/talk-section-parser.d.ts.map +1 -0
- package/dist/src/talk-section-parser.js +109 -0
- package/dist/src/talk-section-parser.js.map +1 -0
- package/dist/src/template-tracker.d.ts +12 -0
- package/dist/src/template-tracker.d.ts.map +1 -0
- package/dist/src/template-tracker.js +225 -0
- package/dist/src/template-tracker.js.map +1 -0
- package/dist/src/wikilink-extractor.d.ts +8 -0
- package/dist/src/wikilink-extractor.d.ts.map +1 -0
- package/dist/src/wikilink-extractor.js +81 -0
- package/dist/src/wikilink-extractor.js.map +1 -0
- package/dist/src/wikitext-parser.d.ts +15 -0
- package/dist/src/wikitext-parser.d.ts.map +1 -0
- package/dist/src/wikitext-parser.js +85 -0
- package/dist/src/wikitext-parser.js.map +1 -0
- package/dist/tsconfig 2.tsbuildinfo +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +28 -0
- package/src/__tests__/category-tracker.test.ts +79 -0
- package/src/__tests__/citation-tracker.test.ts +185 -0
- package/src/__tests__/edit-cluster-detector.test.ts +79 -0
- package/src/__tests__/heuristic-classifier.test.ts +67 -0
- package/src/__tests__/observation-differ.test.ts +58 -0
- package/src/__tests__/page-move-detector.test.ts +64 -0
- package/src/__tests__/protection-tracker.test.ts +72 -0
- package/src/__tests__/revert-detector.test.ts +76 -0
- package/src/__tests__/section-differ.test.ts +120 -0
- package/src/__tests__/talk-activity-detector.test.ts +112 -0
- package/src/__tests__/talk-correlator.test.ts +71 -0
- package/src/__tests__/talk-section-parser.test.ts +105 -0
- package/src/__tests__/template-tracker.test.ts +159 -0
- package/src/__tests__/wikilink-extractor.test.ts +101 -0
- package/src/__tests__/wikitext-parser.test.ts +142 -0
- package/src/category-tracker.ts +75 -0
- package/src/citation-tracker.ts +226 -0
- package/src/claim-differ.ts +4 -0
- package/src/edit-cluster-detector.ts +78 -0
- package/src/heuristic-classifier.ts +59 -0
- package/src/index.ts +88 -0
- package/src/observation-differ.ts +26 -0
- package/src/page-move-detector.ts +32 -0
- package/src/protection-tracker.ts +103 -0
- package/src/revert-detector.ts +51 -0
- package/src/section-differ.ts +315 -0
- package/src/talk-activity-detector.ts +105 -0
- package/src/talk-correlator.ts +70 -0
- package/src/talk-section-parser.ts +151 -0
- package/src/template-tracker.ts +253 -0
- package/src/wikilink-extractor.ts +100 -0
- package/src/wikitext-parser.ts +92 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observation-differ.js","sourceRoot":"","sources":["../../src/observation-differ.ts"],"names":[],"mappings":"AAQA,SAAS,QAAQ,CAAC,KAAoB;IACpC,OAAO,GAAG,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,cAAc,IAAI,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;AAC7F,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAsB,EAAE,OAAwB;IAC/E,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC/C,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEnD,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrE,MAAM,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1E,MAAM,cAAc,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE1E,OAAO;QACL,GAAG,EAAE,SAAS;QACd,QAAQ,EAAE,cAAc;QACxB,SAAS,EAAE,eAAe;KAC3B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { EvidenceEvent } from "@refract-org/evidence-graph";
|
|
2
|
+
interface PageMoveRecord {
|
|
3
|
+
oldTitle: string;
|
|
4
|
+
newTitle: string;
|
|
5
|
+
timestamp: string;
|
|
6
|
+
revId: number;
|
|
7
|
+
comment: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function buildPageMoveEvents(moves: PageMoveRecord[]): EvidenceEvent[];
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=page-move-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-move-detector.d.ts","sourceRoot":"","sources":["../../src/page-move-detector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAiB,MAAM,6BAA6B,CAAC;AAEhF,UAAU,cAAc;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,aAAa,EAAE,CAqB5E"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export function buildPageMoveEvents(moves) {
|
|
2
|
+
const events = [];
|
|
3
|
+
for (const move of moves) {
|
|
4
|
+
const layer = "observed";
|
|
5
|
+
events.push({
|
|
6
|
+
eventType: "page_moved",
|
|
7
|
+
fromRevisionId: 0,
|
|
8
|
+
toRevisionId: move.revId,
|
|
9
|
+
section: "",
|
|
10
|
+
before: move.oldTitle,
|
|
11
|
+
after: move.newTitle,
|
|
12
|
+
deterministicFacts: [
|
|
13
|
+
{ fact: "page_moved", detail: `from=${move.oldTitle} to=${move.newTitle} comment=${move.comment}` },
|
|
14
|
+
],
|
|
15
|
+
layer,
|
|
16
|
+
timestamp: move.timestamp,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
return events;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=page-move-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-move-detector.js","sourceRoot":"","sources":["../../src/page-move-detector.ts"],"names":[],"mappings":"AAUA,MAAM,UAAU,mBAAmB,CAAC,KAAuB;IACzD,MAAM,MAAM,GAAoB,EAAE,CAAC;IAEnC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAkB,UAAU,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC;YACV,SAAS,EAAE,YAAY;YACvB,cAAc,EAAE,CAAC;YACjB,YAAY,EAAE,IAAI,CAAC,KAAK;YACxB,OAAO,EAAE,EAAE;YACX,MAAM,EAAE,IAAI,CAAC,QAAQ;YACrB,KAAK,EAAE,IAAI,CAAC,QAAQ;YACpB,kBAAkB,EAAE;gBAClB,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,IAAI,CAAC,QAAQ,OAAO,IAAI,CAAC,QAAQ,YAAY,IAAI,CAAC,OAAO,EAAE,EAAE;aACpG;YACD,KAAK;YACL,SAAS,EAAE,IAAI,CAAC,SAAS;SAC1B,CAAC,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface ProtectionLogRecord {
|
|
2
|
+
logId: number;
|
|
3
|
+
pageTitle: string;
|
|
4
|
+
timestamp: string;
|
|
5
|
+
comment: string;
|
|
6
|
+
action: "protect" | "unprotect" | "modify";
|
|
7
|
+
}
|
|
8
|
+
export interface ProtectionState {
|
|
9
|
+
level: string;
|
|
10
|
+
sinceTimestamp: string;
|
|
11
|
+
sinceLogId: number;
|
|
12
|
+
}
|
|
13
|
+
export interface ProtectionChange {
|
|
14
|
+
type: "added" | "removed" | "modified";
|
|
15
|
+
logEvent: ProtectionLogRecord;
|
|
16
|
+
}
|
|
17
|
+
export interface ProtectionTracker {
|
|
18
|
+
buildState(logs: ProtectionLogRecord[]): Map<string, ProtectionState>;
|
|
19
|
+
diffState(before: Map<string, ProtectionState>, after: Map<string, ProtectionState>): ProtectionChange[];
|
|
20
|
+
findLogsBetween(logs: ProtectionLogRecord[], fromTimestamp: string, toTimestamp: string): ProtectionLogRecord[];
|
|
21
|
+
}
|
|
22
|
+
export declare const protectionTracker: ProtectionTracker;
|
|
23
|
+
//# sourceMappingURL=protection-tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protection-tracker.d.ts","sourceRoot":"","sources":["../../src/protection-tracker.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;CAC5C;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,UAAU,CAAC;IACvC,QAAQ,EAAE,mBAAmB,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,CAAC,IAAI,EAAE,mBAAmB,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACtE,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,gBAAgB,EAAE,CAAC;IACzG,eAAe,CAAC,IAAI,EAAE,mBAAmB,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,mBAAmB,EAAE,CAAC;CACjH;AAED,eAAO,MAAM,iBAAiB,EAAE,iBA6E/B,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export const protectionTracker = {
|
|
2
|
+
buildState(logs) {
|
|
3
|
+
const state = new Map();
|
|
4
|
+
const sorted = [...logs].map((l) => ({ l, ts: new Date(l.timestamp).getTime() }));
|
|
5
|
+
sorted.sort((a, b) => a.ts - b.ts);
|
|
6
|
+
for (const { l: log } of sorted) {
|
|
7
|
+
if (log.action === "protect" || log.action === "modify") {
|
|
8
|
+
state.set(log.pageTitle, {
|
|
9
|
+
level: log.action === "protect" ? "protected" : "modified",
|
|
10
|
+
sinceTimestamp: log.timestamp,
|
|
11
|
+
sinceLogId: log.logId,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
else if (log.action === "unprotect") {
|
|
15
|
+
state.delete(log.pageTitle);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return state;
|
|
19
|
+
},
|
|
20
|
+
diffState(before, after) {
|
|
21
|
+
const changes = [];
|
|
22
|
+
const allTitles = new Set([...before.keys(), ...after.keys()]);
|
|
23
|
+
for (const title of allTitles) {
|
|
24
|
+
const b = before.get(title);
|
|
25
|
+
const a = after.get(title);
|
|
26
|
+
if (!b && a) {
|
|
27
|
+
changes.push({
|
|
28
|
+
type: "added",
|
|
29
|
+
logEvent: {
|
|
30
|
+
logId: a.sinceLogId,
|
|
31
|
+
pageTitle: title,
|
|
32
|
+
timestamp: a.sinceTimestamp,
|
|
33
|
+
comment: "",
|
|
34
|
+
action: "protect",
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
else if (b && !a) {
|
|
39
|
+
changes.push({
|
|
40
|
+
type: "removed",
|
|
41
|
+
logEvent: {
|
|
42
|
+
logId: b.sinceLogId,
|
|
43
|
+
pageTitle: title,
|
|
44
|
+
timestamp: b.sinceTimestamp,
|
|
45
|
+
comment: "",
|
|
46
|
+
action: "unprotect",
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
else if (b && a && b.sinceLogId !== a.sinceLogId) {
|
|
51
|
+
changes.push({
|
|
52
|
+
type: "modified",
|
|
53
|
+
logEvent: {
|
|
54
|
+
logId: a.sinceLogId,
|
|
55
|
+
pageTitle: title,
|
|
56
|
+
timestamp: a.sinceTimestamp,
|
|
57
|
+
comment: "",
|
|
58
|
+
action: "modify",
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return changes;
|
|
64
|
+
},
|
|
65
|
+
findLogsBetween(logs, fromTimestamp, toTimestamp) {
|
|
66
|
+
const from = new Date(fromTimestamp).getTime();
|
|
67
|
+
const to = new Date(toTimestamp).getTime();
|
|
68
|
+
return logs.filter((l) => {
|
|
69
|
+
const t = new Date(l.timestamp).getTime();
|
|
70
|
+
return t > from && t <= to;
|
|
71
|
+
});
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=protection-tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protection-tracker.js","sourceRoot":"","sources":["../../src/protection-tracker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"revert-detector.d.ts","sourceRoot":"","sources":["../../src/revert-detector.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAe,cAAc,EAAE,MAAM,YAAY,CAAC;AAW9D,eAAO,MAAM,cAAc,EAAE,cAsC5B,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const REVERT_PATTERNS = [
|
|
2
|
+
/\brevert/i,
|
|
3
|
+
/\bundid\s+revision/i,
|
|
4
|
+
/\brvv\b/i,
|
|
5
|
+
/\brollback\b/i,
|
|
6
|
+
/\brestore/i,
|
|
7
|
+
/\[\[WP:ROLLBACK\]\]/i,
|
|
8
|
+
];
|
|
9
|
+
export const revertDetector = {
|
|
10
|
+
isRevert(comment) {
|
|
11
|
+
return REVERT_PATTERNS.some((pattern) => pattern.test(comment));
|
|
12
|
+
},
|
|
13
|
+
detectRevertChain(revisions) {
|
|
14
|
+
const chains = [];
|
|
15
|
+
const sorted = [...revisions].sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
|
|
16
|
+
let i = 0;
|
|
17
|
+
while (i < sorted.length) {
|
|
18
|
+
const rev = sorted[i];
|
|
19
|
+
if (!this.isRevert(rev.comment)) {
|
|
20
|
+
i++;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const existing = chains.find((c) => rev.revId <= c.endRevisionId + 1 && rev.revId >= c.startRevisionId - 1);
|
|
24
|
+
if (existing) {
|
|
25
|
+
existing.startRevisionId = Math.min(existing.startRevisionId, rev.revId);
|
|
26
|
+
existing.endRevisionId = Math.max(existing.endRevisionId, rev.revId);
|
|
27
|
+
existing.participants++;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
const revertedToMatch = rev.comment.match(/revision\s+(\d+)/i);
|
|
31
|
+
chains.push({
|
|
32
|
+
startRevisionId: rev.revId,
|
|
33
|
+
endRevisionId: rev.revId,
|
|
34
|
+
revertedToRevisionId: revertedToMatch ? parseInt(revertedToMatch[1], 10) : rev.revId - 1,
|
|
35
|
+
participants: 1,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
i++;
|
|
39
|
+
}
|
|
40
|
+
return chains;
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=revert-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"revert-detector.js","sourceRoot":"","sources":["../../src/revert-detector.ts"],"names":[],"mappings":"AAGA,MAAM,eAAe,GAAG;IACtB,WAAW;IACX,qBAAqB;IACrB,UAAU;IACV,eAAe;IACf,YAAY;IACZ,sBAAsB;CACvB,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAmB;IAC5C,QAAQ,CAAC,OAAe;QACtB,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,iBAAiB,CAAC,SAAqB;QACrC,MAAM,MAAM,GAAkB,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QAEhH,IAAI,CAAC,GAAG,CAAC,CAAC;QACV,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;YACzB,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACtB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;gBAChC,CAAC,EAAE,CAAC;gBACJ,SAAS;YACX,CAAC;YAED,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC,aAAa,GAAG,CAAC,IAAI,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC,eAAe,GAAG,CAAC,CAAC,CAAC;YAE5G,IAAI,QAAQ,EAAE,CAAC;gBACb,QAAQ,CAAC,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,eAAe,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;gBACzE,QAAQ,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,aAAa,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;gBACrE,QAAQ,CAAC,YAAY,EAAE,CAAC;YAC1B,CAAC;iBAAM,CAAC;gBACN,MAAM,eAAe,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;gBAC/D,MAAM,CAAC,IAAI,CAAC;oBACV,eAAe,EAAE,GAAG,CAAC,KAAK;oBAC1B,aAAa,EAAE,GAAG,CAAC,KAAK;oBACxB,oBAAoB,EAAE,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC;oBACxF,YAAY,EAAE,CAAC;iBAChB,CAAC,CAAC;YACL,CAAC;YAED,CAAC,EAAE,CAAC;QACN,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { SectionDiffer } from "./index.js";
|
|
2
|
+
export declare const sectionDiffer: SectionDiffer;
|
|
3
|
+
export interface SectionEvent {
|
|
4
|
+
revisionId: number;
|
|
5
|
+
timestamp: string;
|
|
6
|
+
eventType: "created" | "modified" | "removed" | "renamed";
|
|
7
|
+
content?: string;
|
|
8
|
+
oldName?: string;
|
|
9
|
+
newName?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface SectionLineage {
|
|
12
|
+
sectionName: string;
|
|
13
|
+
level: number;
|
|
14
|
+
firstSeenRevisionId: number;
|
|
15
|
+
firstSeenAt: string;
|
|
16
|
+
lastSeenRevisionId?: number;
|
|
17
|
+
lastSeenAt?: string;
|
|
18
|
+
events: SectionEvent[];
|
|
19
|
+
isActive: boolean;
|
|
20
|
+
}
|
|
21
|
+
export declare function buildSectionLineage(revisions: Array<{
|
|
22
|
+
revId: number;
|
|
23
|
+
timestamp: string;
|
|
24
|
+
content: string;
|
|
25
|
+
}>): SectionLineage[];
|
|
26
|
+
//# sourceMappingURL=section-differ.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"section-differ.d.ts","sourceRoot":"","sources":["../../src/section-differ.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,eAAO,MAAM,aAAa,EAAE,aA+H3B,CAAC;AAEF,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;IAC1D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,mBAAmB,EAAE,MAAM,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,GACtE,cAAc,EAAE,CA4JlB"}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
export const sectionDiffer = {
|
|
2
|
+
extractSections(wikitext) {
|
|
3
|
+
const sections = [];
|
|
4
|
+
const lines = wikitext.split("\n");
|
|
5
|
+
const headerRegex = /^(=+)\s*([^=]+?)\s*\1$/;
|
|
6
|
+
// Pre-compute byte offsets of each line from a single TextEncoder pass
|
|
7
|
+
const bytes = new TextEncoder().encode(wikitext);
|
|
8
|
+
const lineByteOffsets = [0];
|
|
9
|
+
for (let i = 0, lineIdx = 0; i < bytes.length; i++) {
|
|
10
|
+
if (bytes[i] === 0x0a) {
|
|
11
|
+
lineByteOffsets[++lineIdx] = i + 1;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
while (lineByteOffsets.length <= lines.length) {
|
|
15
|
+
lineByteOffsets.push(bytes.length);
|
|
16
|
+
}
|
|
17
|
+
const headerMatches = [];
|
|
18
|
+
for (let i = 0; i < lines.length; i++) {
|
|
19
|
+
const match = headerRegex.exec(lines[i]);
|
|
20
|
+
if (match) {
|
|
21
|
+
headerMatches.push({
|
|
22
|
+
index: i,
|
|
23
|
+
offset: lineByteOffsets[i],
|
|
24
|
+
level: match[1].length,
|
|
25
|
+
title: match[2].trim(),
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (headerMatches.length === 0) {
|
|
30
|
+
sections.push({
|
|
31
|
+
title: "",
|
|
32
|
+
level: 1,
|
|
33
|
+
content: wikitext.trim(),
|
|
34
|
+
byteOffset: 0,
|
|
35
|
+
});
|
|
36
|
+
return sections;
|
|
37
|
+
}
|
|
38
|
+
const leadEnd = headerMatches[0].offset;
|
|
39
|
+
const leadContent = wikitext.slice(0, leadEnd).trim();
|
|
40
|
+
if (leadContent) {
|
|
41
|
+
sections.push({
|
|
42
|
+
title: "",
|
|
43
|
+
level: 1,
|
|
44
|
+
content: leadContent,
|
|
45
|
+
byteOffset: 0,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
for (let i = 0; i < headerMatches.length; i++) {
|
|
49
|
+
const header = headerMatches[i];
|
|
50
|
+
const nextOffset = i + 1 < headerMatches.length ? headerMatches[i + 1].offset : bytes.length;
|
|
51
|
+
const headerEnd = lineByteOffsets[header.index + 1] ?? bytes.length;
|
|
52
|
+
const content = wikitext.slice(headerEnd, nextOffset).trim();
|
|
53
|
+
sections.push({
|
|
54
|
+
title: header.title,
|
|
55
|
+
level: header.level,
|
|
56
|
+
content,
|
|
57
|
+
byteOffset: header.offset,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return sections;
|
|
61
|
+
},
|
|
62
|
+
diffSections(before, after) {
|
|
63
|
+
const changes = [];
|
|
64
|
+
const beforeByTitle = new Map();
|
|
65
|
+
const afterByTitle = new Map();
|
|
66
|
+
for (const s of before) {
|
|
67
|
+
const key = sectionKey(s);
|
|
68
|
+
beforeByTitle.set(key, s);
|
|
69
|
+
}
|
|
70
|
+
for (const s of after) {
|
|
71
|
+
const key = sectionKey(s);
|
|
72
|
+
afterByTitle.set(key, s);
|
|
73
|
+
}
|
|
74
|
+
const seenAfter = new Set();
|
|
75
|
+
for (const [key, afterSection] of afterByTitle) {
|
|
76
|
+
seenAfter.add(key);
|
|
77
|
+
const beforeSection = beforeByTitle.get(key);
|
|
78
|
+
if (!beforeSection) {
|
|
79
|
+
changes.push({
|
|
80
|
+
section: afterSection.title || "(lead)",
|
|
81
|
+
changeType: "added",
|
|
82
|
+
toContent: afterSection.content,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
else if (beforeSection.content !== afterSection.content) {
|
|
86
|
+
changes.push({
|
|
87
|
+
section: afterSection.title || "(lead)",
|
|
88
|
+
changeType: "modified",
|
|
89
|
+
fromContent: beforeSection.content,
|
|
90
|
+
toContent: afterSection.content,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
changes.push({
|
|
95
|
+
section: afterSection.title || "(lead)",
|
|
96
|
+
changeType: "unchanged",
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
for (const [key, beforeSection] of beforeByTitle) {
|
|
101
|
+
if (!seenAfter.has(key)) {
|
|
102
|
+
changes.push({
|
|
103
|
+
section: beforeSection.title || "(lead)",
|
|
104
|
+
changeType: "removed",
|
|
105
|
+
fromContent: beforeSection.content,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return changes;
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
export function buildSectionLineage(revisions) {
|
|
113
|
+
if (revisions.length === 0)
|
|
114
|
+
return [];
|
|
115
|
+
const allSections = revisions.map((r) => sectionDiffer.extractSections(r.content));
|
|
116
|
+
const lineages = new Map();
|
|
117
|
+
const firstSections = allSections[0];
|
|
118
|
+
for (const section of firstSections) {
|
|
119
|
+
const key = sectionKey(section);
|
|
120
|
+
lineages.set(key, {
|
|
121
|
+
sectionName: section.title || "(lead)",
|
|
122
|
+
level: section.level,
|
|
123
|
+
firstSeenRevisionId: revisions[0].revId,
|
|
124
|
+
firstSeenAt: revisions[0].timestamp,
|
|
125
|
+
lastSeenRevisionId: revisions[0].revId,
|
|
126
|
+
lastSeenAt: revisions[0].timestamp,
|
|
127
|
+
events: [
|
|
128
|
+
{
|
|
129
|
+
revisionId: revisions[0].revId,
|
|
130
|
+
timestamp: revisions[0].timestamp,
|
|
131
|
+
eventType: "created",
|
|
132
|
+
content: section.content,
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
isActive: true,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
for (let i = 0; i < revisions.length - 1; i++) {
|
|
139
|
+
const prevRev = revisions[i];
|
|
140
|
+
const currRev = revisions[i + 1];
|
|
141
|
+
const prevSections = allSections[i];
|
|
142
|
+
const currSections = allSections[i + 1];
|
|
143
|
+
const prevByKey = new Map();
|
|
144
|
+
const currByKey = new Map();
|
|
145
|
+
for (const s of prevSections)
|
|
146
|
+
prevByKey.set(sectionKey(s), s);
|
|
147
|
+
for (const s of currSections)
|
|
148
|
+
currByKey.set(sectionKey(s), s);
|
|
149
|
+
const prevKeys = new Set(prevByKey.keys());
|
|
150
|
+
const currKeys = new Set(currByKey.keys());
|
|
151
|
+
const removedKeys = [...prevKeys].filter((k) => !currKeys.has(k));
|
|
152
|
+
const addedKeys = [...currKeys].filter((k) => !prevKeys.has(k));
|
|
153
|
+
const renamedFromTo = new Map();
|
|
154
|
+
const contentToAddKey = new Map();
|
|
155
|
+
for (const addKey of addedKeys) {
|
|
156
|
+
const section = currByKey.get(addKey);
|
|
157
|
+
if (!section)
|
|
158
|
+
continue;
|
|
159
|
+
contentToAddKey.set(section.content, addKey);
|
|
160
|
+
}
|
|
161
|
+
for (const remKey of removedKeys) {
|
|
162
|
+
const remSection = prevByKey.get(remKey);
|
|
163
|
+
if (!remSection)
|
|
164
|
+
continue;
|
|
165
|
+
const addKey = contentToAddKey.get(remSection.content);
|
|
166
|
+
if (addKey) {
|
|
167
|
+
renamedFromTo.set(remKey, addKey);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const renamedToSet = new Set(renamedFromTo.values());
|
|
171
|
+
for (const key of removedKeys) {
|
|
172
|
+
if (renamedFromTo.has(key)) {
|
|
173
|
+
const newKey = renamedFromTo.get(key);
|
|
174
|
+
const oldSection = prevByKey.get(key);
|
|
175
|
+
const newSection = newKey ? currByKey.get(newKey) : undefined;
|
|
176
|
+
if (!newKey || !oldSection || !newSection)
|
|
177
|
+
continue;
|
|
178
|
+
const lineage = lineages.get(key);
|
|
179
|
+
if (lineage) {
|
|
180
|
+
lineage.events.push({
|
|
181
|
+
revisionId: currRev.revId,
|
|
182
|
+
timestamp: currRev.timestamp,
|
|
183
|
+
eventType: "renamed",
|
|
184
|
+
content: oldSection.content,
|
|
185
|
+
oldName: oldSection.title || "(lead)",
|
|
186
|
+
newName: newSection.title || "(lead)",
|
|
187
|
+
});
|
|
188
|
+
lineage.sectionName = newSection.title || "(lead)";
|
|
189
|
+
lineage.level = newSection.level;
|
|
190
|
+
lineage.lastSeenRevisionId = currRev.revId;
|
|
191
|
+
lineage.lastSeenAt = currRev.timestamp;
|
|
192
|
+
lineage.isActive = true;
|
|
193
|
+
lineages.set(newKey, lineage);
|
|
194
|
+
lineages.delete(key);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
const section = prevByKey.get(key);
|
|
199
|
+
if (!section)
|
|
200
|
+
continue;
|
|
201
|
+
const lineage = lineages.get(key);
|
|
202
|
+
if (lineage) {
|
|
203
|
+
lineage.events.push({
|
|
204
|
+
revisionId: currRev.revId,
|
|
205
|
+
timestamp: currRev.timestamp,
|
|
206
|
+
eventType: "removed",
|
|
207
|
+
content: section.content,
|
|
208
|
+
});
|
|
209
|
+
lineage.lastSeenRevisionId = prevRev.revId;
|
|
210
|
+
lineage.lastSeenAt = prevRev.timestamp;
|
|
211
|
+
lineage.isActive = false;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
for (const key of addedKeys) {
|
|
216
|
+
if (!renamedToSet.has(key)) {
|
|
217
|
+
const section = currByKey.get(key);
|
|
218
|
+
if (!section)
|
|
219
|
+
continue;
|
|
220
|
+
const lineage = {
|
|
221
|
+
sectionName: section.title || "(lead)",
|
|
222
|
+
level: section.level,
|
|
223
|
+
firstSeenRevisionId: currRev.revId,
|
|
224
|
+
firstSeenAt: currRev.timestamp,
|
|
225
|
+
lastSeenRevisionId: currRev.revId,
|
|
226
|
+
lastSeenAt: currRev.timestamp,
|
|
227
|
+
events: [
|
|
228
|
+
{
|
|
229
|
+
revisionId: currRev.revId,
|
|
230
|
+
timestamp: currRev.timestamp,
|
|
231
|
+
eventType: "created",
|
|
232
|
+
content: section.content,
|
|
233
|
+
},
|
|
234
|
+
],
|
|
235
|
+
isActive: true,
|
|
236
|
+
};
|
|
237
|
+
lineages.set(key, lineage);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
for (const key of prevKeys) {
|
|
241
|
+
if (currKeys.has(key) && !renamedFromTo.has(key)) {
|
|
242
|
+
const prevSection = prevByKey.get(key);
|
|
243
|
+
const currSection = currByKey.get(key);
|
|
244
|
+
if (!prevSection || !currSection)
|
|
245
|
+
continue;
|
|
246
|
+
const lineage = lineages.get(key);
|
|
247
|
+
if (lineage) {
|
|
248
|
+
if (prevSection.content !== currSection.content) {
|
|
249
|
+
lineage.events.push({
|
|
250
|
+
revisionId: currRev.revId,
|
|
251
|
+
timestamp: currRev.timestamp,
|
|
252
|
+
eventType: "modified",
|
|
253
|
+
content: currSection.content,
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
lineage.lastSeenRevisionId = currRev.revId;
|
|
257
|
+
lineage.lastSeenAt = currRev.timestamp;
|
|
258
|
+
lineage.isActive = true;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return [...lineages.values()].sort((a, b) => a.sectionName.localeCompare(b.sectionName));
|
|
264
|
+
}
|
|
265
|
+
function sectionKey(s) {
|
|
266
|
+
return `${s.level}:${s.title.toLowerCase()}`;
|
|
267
|
+
}
|
|
268
|
+
//# sourceMappingURL=section-differ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"section-differ.js","sourceRoot":"","sources":["../../src/section-differ.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { EvidenceEvent, Revision } from "@refract-org/evidence-graph";
|
|
2
|
+
export interface TalkActivityOptions {
|
|
3
|
+
lookbackWindowMs?: number;
|
|
4
|
+
spikeFactor?: number;
|
|
5
|
+
movingAveragePeriods?: number;
|
|
6
|
+
}
|
|
7
|
+
export interface TalkActivityResult {
|
|
8
|
+
spikes: EvidenceEvent[];
|
|
9
|
+
activityByDay: Array<{
|
|
10
|
+
date: string;
|
|
11
|
+
count: number;
|
|
12
|
+
}>;
|
|
13
|
+
movingAverage: number;
|
|
14
|
+
}
|
|
15
|
+
export declare function detectTalkActivitySpikes(talkRevisions: Revision[], articleRevisions: Revision[], options?: TalkActivityOptions): TalkActivityResult;
|
|
16
|
+
//# sourceMappingURL=talk-activity-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"talk-activity-detector.d.ts","sourceRoot":"","sources":["../../src/talk-activity-detector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAM3E,MAAM,WAAW,mBAAmB;IAClC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,aAAa,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtD,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,wBAAwB,CACtC,aAAa,EAAE,QAAQ,EAAE,EACzB,gBAAgB,EAAE,QAAQ,EAAE,EAC5B,OAAO,CAAC,EAAE,mBAAmB,GAC5B,kBAAkB,CAmEpB"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
const DEFAULT_SPIKE_WINDOW_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
2
|
+
const DEFAULT_SPIKE_FACTOR = 3.0;
|
|
3
|
+
const DEFAULT_MA_PERIODS = 4;
|
|
4
|
+
export function detectTalkActivitySpikes(talkRevisions, articleRevisions, options) {
|
|
5
|
+
const windowMs = options?.lookbackWindowMs ?? DEFAULT_SPIKE_WINDOW_MS;
|
|
6
|
+
const spikeFactor = options?.spikeFactor ?? DEFAULT_SPIKE_FACTOR;
|
|
7
|
+
const maPeriods = options?.movingAveragePeriods ?? DEFAULT_MA_PERIODS;
|
|
8
|
+
const spikes = [];
|
|
9
|
+
if (talkRevisions.length === 0) {
|
|
10
|
+
return { spikes, activityByDay: [], movingAverage: 0 };
|
|
11
|
+
}
|
|
12
|
+
const dailyCounts = bucketByDay(talkRevisions);
|
|
13
|
+
const sortedDays = Object.keys(dailyCounts).sort();
|
|
14
|
+
if (sortedDays.length < maPeriods) {
|
|
15
|
+
return { spikes, activityByDay: dailyActivity(dailyCounts), movingAverage: 0 };
|
|
16
|
+
}
|
|
17
|
+
const recentEnd = Date.now();
|
|
18
|
+
const recentStart = recentEnd - windowMs;
|
|
19
|
+
const recentDays = sortedDays.filter((d) => new Date(d).getTime() >= recentStart);
|
|
20
|
+
const movingAverages = [];
|
|
21
|
+
for (let i = maPeriods - 1; i < sortedDays.length; i++) {
|
|
22
|
+
let sum = 0;
|
|
23
|
+
for (let j = i - (maPeriods - 1); j <= i; j++) {
|
|
24
|
+
sum += dailyCounts[sortedDays[j]];
|
|
25
|
+
}
|
|
26
|
+
movingAverages.push(sum / maPeriods);
|
|
27
|
+
}
|
|
28
|
+
const latestMA = movingAverages.length > 0 ? movingAverages[movingAverages.length - 1] : 0;
|
|
29
|
+
const threshold = Math.max(latestMA * spikeFactor, 3);
|
|
30
|
+
for (const day of recentDays) {
|
|
31
|
+
const count = dailyCounts[day];
|
|
32
|
+
if (count >= threshold) {
|
|
33
|
+
const nearbyArticleEdits = articleRevisions.filter((r) => {
|
|
34
|
+
const t = new Date(r.timestamp);
|
|
35
|
+
const dayStart = new Date(day).getTime();
|
|
36
|
+
const dayEnd = dayStart + 24 * 60 * 60 * 1000;
|
|
37
|
+
return t.getTime() >= dayStart && t.getTime() < dayEnd;
|
|
38
|
+
});
|
|
39
|
+
spikes.push({
|
|
40
|
+
eventType: "talk_activity_spike",
|
|
41
|
+
fromRevisionId: 0,
|
|
42
|
+
toRevisionId: 0,
|
|
43
|
+
section: "",
|
|
44
|
+
before: "",
|
|
45
|
+
after: "",
|
|
46
|
+
deterministicFacts: [
|
|
47
|
+
{
|
|
48
|
+
fact: "talk_activity_spike",
|
|
49
|
+
detail: `date=${day} talk_edits=${count} moving_average=${latestMA.toFixed(1)} threshold=${threshold.toFixed(1)} nearby_article_edits=${nearbyArticleEdits.length}`,
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
layer: "observed",
|
|
53
|
+
timestamp: new Date(day).toISOString(),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
spikes,
|
|
59
|
+
activityByDay: dailyActivity(dailyCounts),
|
|
60
|
+
movingAverage: latestMA,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function bucketByDay(revisions) {
|
|
64
|
+
const buckets = {};
|
|
65
|
+
for (const r of revisions) {
|
|
66
|
+
const day = r.timestamp.slice(0, 10);
|
|
67
|
+
buckets[day] = (buckets[day] ?? 0) + 1;
|
|
68
|
+
}
|
|
69
|
+
return buckets;
|
|
70
|
+
}
|
|
71
|
+
function dailyActivity(counts) {
|
|
72
|
+
return Object.entries(counts)
|
|
73
|
+
.map(([date, count]) => ({ date, count }))
|
|
74
|
+
.sort((a, b) => a.date.localeCompare(b.date));
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=talk-activity-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"talk-activity-detector.js","sourceRoot":"","sources":["../../src/talk-activity-detector.ts"],"names":[],"mappings":"AAEA,MAAM,uBAAuB,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,SAAS;AAClE,MAAM,oBAAoB,GAAG,GAAG,CAAC;AACjC,MAAM,kBAAkB,GAAG,CAAC,CAAC;AAc7B,MAAM,UAAU,wBAAwB,CACtC,aAAyB,EACzB,gBAA4B,EAC5B,OAA6B;IAE7B,MAAM,QAAQ,GAAG,OAAO,EAAE,gBAAgB,IAAI,uBAAuB,CAAC;IACtE,MAAM,WAAW,GAAG,OAAO,EAAE,WAAW,IAAI,oBAAoB,CAAC;IACjE,MAAM,SAAS,GAAG,OAAO,EAAE,oBAAoB,IAAI,kBAAkB,CAAC;IACtE,MAAM,MAAM,GAAoB,EAAE,CAAC;IAEnC,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE,EAAE,aAAa,EAAE,CAAC,EAAE,CAAC;IACzD,CAAC;IAED,MAAM,WAAW,GAAG,WAAW,CAAC,aAAa,CAAC,CAAC;IAC/C,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC;IAEnD,IAAI,UAAU,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;QAClC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,CAAC,WAAW,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,CAAC;IACjF,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,MAAM,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC;IACzC,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,WAAW,CAAC,CAAC;IAElF,MAAM,cAAc,GAAa,EAAE,CAAC;IACpC,KAAK,IAAI,CAAC,GAAG,SAAS,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvD,IAAI,GAAG,GAAG,CAAC,CAAC;QACZ,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9C,GAAG,IAAI,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;QACpC,CAAC;QACD,cAAc,CAAC,IAAI,CAAC,GAAG,GAAG,SAAS,CAAC,CAAC;IACvC,CAAC;IAED,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3F,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,GAAG,WAAW,EAAE,CAAC,CAAC,CAAC;IAEtD,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,KAAK,IAAI,SAAS,EAAE,CAAC;YACvB,MAAM,kBAAkB,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;gBACvD,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;gBAChC,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC;gBACzC,MAAM,MAAM,GAAG,QAAQ,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;gBAC9C,OAAO,CAAC,CAAC,OAAO,EAAE,IAAI,QAAQ,IAAI,CAAC,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC;YACzD,CAAC,CAAC,CAAC;YAEH,MAAM,CAAC,IAAI,CAAC;gBACV,SAAS,EAAE,qBAAqB;gBAChC,cAAc,EAAE,CAAC;gBACjB,YAAY,EAAE,CAAC;gBACf,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,EAAE;gBACV,KAAK,EAAE,EAAE;gBACT,kBAAkB,EAAE;oBAClB;wBACE,IAAI,EAAE,qBAAqB;wBAC3B,MAAM,EAAE,QAAQ,GAAG,eAAe,KAAK,mBAAmB,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,yBAAyB,kBAAkB,CAAC,MAAM,EAAE;qBACpK;iBACF;gBACD,KAAK,EAAE,UAAU;gBACjB,SAAS,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE;aACvC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO;QACL,MAAM;QACN,aAAa,EAAE,aAAa,CAAC,WAAW,CAAC;QACzC,aAAa,EAAE,QAAQ;KACxB,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,SAAqB;IACxC,MAAM,OAAO,GAA2B,EAAE,CAAC;IAC3C,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;QAC1B,MAAM,GAAG,GAAG,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACrC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,aAAa,CAAC,MAA8B;IACnD,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;SAC1B,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;SACzC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { EvidenceEvent, Revision } from "@refract-org/evidence-graph";
|
|
2
|
+
export interface TalkCorrelationOptions {
|
|
3
|
+
windowBeforeMs?: number;
|
|
4
|
+
windowAfterMs?: number;
|
|
5
|
+
}
|
|
6
|
+
export declare function correlateTalkRevisions(articleRevs: Revision[], talkRevs: Revision[], options?: TalkCorrelationOptions): EvidenceEvent[];
|
|
7
|
+
//# sourceMappingURL=talk-correlator.d.ts.map
|