@ncukondo/reference-manager 0.25.0 → 0.26.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 +11 -2
- package/dist/chunks/{SearchableMultiSelect-B7qEWPDT.js → SearchableMultiSelect-D2IzthN4.js} +2 -2
- package/dist/chunks/{SearchableMultiSelect-B7qEWPDT.js.map → SearchableMultiSelect-D2IzthN4.js.map} +1 -1
- package/dist/chunks/{action-menu-DD0RtNVD.js → action-menu-DWdoHTFh.js} +3 -3
- package/dist/chunks/{action-menu-DD0RtNVD.js.map → action-menu-DWdoHTFh.js.map} +1 -1
- package/dist/chunks/checker-CKfdG8Ia.js +170 -0
- package/dist/chunks/checker-CKfdG8Ia.js.map +1 -0
- package/dist/chunks/crossref-client-Gs75LMVf.js +94 -0
- package/dist/chunks/crossref-client-Gs75LMVf.js.map +1 -0
- package/dist/chunks/{fix-interaction-BpfMLRNY.js → fix-interaction-DNXbmlPr.js} +79 -20
- package/dist/chunks/fix-interaction-DNXbmlPr.js.map +1 -0
- package/dist/chunks/{index-QTYx5RaF.js → index-BEQ4YIXx.js} +115 -44
- package/dist/chunks/index-BEQ4YIXx.js.map +1 -0
- package/dist/chunks/{index-PQkbePWV.js → index-k67fQbe4.js} +3 -3
- package/dist/chunks/index-k67fQbe4.js.map +1 -0
- package/dist/chunks/{index-D2HsxXnK.js → index-of6eJn8N.js} +10 -4
- package/dist/chunks/{index-D2HsxXnK.js.map → index-of6eJn8N.js.map} +1 -1
- package/dist/chunks/{index-CYEise6v.js → index-tdmbNN9b.js} +4 -4
- package/dist/chunks/{index-CYEise6v.js.map → index-tdmbNN9b.js.map} +1 -1
- package/dist/chunks/metadata-comparator-C5zfoYdK.js +137 -0
- package/dist/chunks/metadata-comparator-C5zfoYdK.js.map +1 -0
- package/dist/chunks/{pubmed-client-J18fg3fG.js → pubmed-client-CGReJIOz.js} +2 -2
- package/dist/chunks/{pubmed-client-J18fg3fG.js.map → pubmed-client-CGReJIOz.js.map} +1 -1
- package/dist/chunks/{reference-select-Qpgt9cbN.js → reference-select-i1Cnmc16.js} +3 -3
- package/dist/chunks/{reference-select-Qpgt9cbN.js.map → reference-select-i1Cnmc16.js.map} +1 -1
- package/dist/chunks/{style-select-mEMoWbM2.js → style-select-COnY01qb.js} +3 -3
- package/dist/chunks/{style-select-mEMoWbM2.js.map → style-select-COnY01qb.js.map} +1 -1
- package/dist/cli/commands/check.d.ts +2 -1
- package/dist/cli/commands/check.d.ts.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/features/check/checker.d.ts +1 -0
- package/dist/features/check/checker.d.ts.map +1 -1
- package/dist/features/check/crossref-client.d.ts +16 -0
- package/dist/features/check/crossref-client.d.ts.map +1 -1
- package/dist/features/check/fix-actions.d.ts +1 -1
- package/dist/features/check/fix-actions.d.ts.map +1 -1
- package/dist/features/check/fix-interaction.d.ts.map +1 -1
- package/dist/features/check/metadata-comparator.d.ts +37 -0
- package/dist/features/check/metadata-comparator.d.ts.map +1 -0
- package/dist/features/check/metadata-similarity.d.ts +22 -0
- package/dist/features/check/metadata-similarity.d.ts.map +1 -0
- package/dist/features/check/types.d.ts +6 -1
- package/dist/features/check/types.d.ts.map +1 -1
- package/dist/features/operations/check.d.ts +1 -0
- package/dist/features/operations/check.d.ts.map +1 -1
- package/dist/mcp/tools/check.d.ts +1 -0
- package/dist/mcp/tools/check.d.ts.map +1 -1
- package/dist/server/routes/check.d.ts.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +1 -1
- package/dist/chunks/checker-7pzK2XSC.js +0 -92
- package/dist/chunks/checker-7pzK2XSC.js.map +0 -1
- package/dist/chunks/crossref-client-DGNz4PNW.js +0 -52
- package/dist/chunks/crossref-client-DGNz4PNW.js.map +0 -1
- package/dist/chunks/fix-interaction-BpfMLRNY.js.map +0 -1
- package/dist/chunks/index-PQkbePWV.js.map +0 -1
- package/dist/chunks/index-QTYx5RaF.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fix-interaction.d.ts","sourceRoot":"","sources":["../../../src/features/check/fix-interaction.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAKhE,OAAO,KAAK,EAAgB,WAAW,EAAE,MAAM,YAAY,CAAC;AAE5D,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;
|
|
1
|
+
{"version":3,"file":"fix-interaction.d.ts","sourceRoot":"","sources":["../../../src/features/check/fix-interaction.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAKhE,OAAO,KAAK,EAAgB,WAAW,EAAE,MAAM,YAAY,CAAC;AAE5D,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAgGD,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,WAAW,EAAE,EACtB,OAAO,EAAE,QAAQ,EACjB,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,GAAG,SAAS,GAC5C,OAAO,CAAC,oBAAoB,CAAC,CAoB/B"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metadata comparator for classifying differences between local and remote metadata.
|
|
3
|
+
*/
|
|
4
|
+
import type { RemoteMetadata } from "./crossref-client.js";
|
|
5
|
+
export interface MetadataComparisonResult {
|
|
6
|
+
classification: "metadata_mismatch" | "metadata_outdated" | "no_change";
|
|
7
|
+
changedFields: string[];
|
|
8
|
+
fieldDiffs: Array<{
|
|
9
|
+
field: string;
|
|
10
|
+
local: string | null;
|
|
11
|
+
remote: string | null;
|
|
12
|
+
}>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Local item fields relevant for metadata comparison.
|
|
16
|
+
*/
|
|
17
|
+
export interface LocalMetadataFields {
|
|
18
|
+
title?: string;
|
|
19
|
+
author?: Array<{
|
|
20
|
+
family?: string;
|
|
21
|
+
given?: string;
|
|
22
|
+
}>;
|
|
23
|
+
"container-title"?: string;
|
|
24
|
+
type?: string;
|
|
25
|
+
page?: string;
|
|
26
|
+
volume?: string;
|
|
27
|
+
issue?: string;
|
|
28
|
+
issued?: {
|
|
29
|
+
"date-parts"?: number[][];
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Compare local metadata fields against remote (Crossref) metadata.
|
|
34
|
+
* Classifies differences as metadata_mismatch, metadata_outdated, or no_change.
|
|
35
|
+
*/
|
|
36
|
+
export declare function compareMetadata(local: LocalMetadataFields, remote: RemoteMetadata): MetadataComparisonResult;
|
|
37
|
+
//# sourceMappingURL=metadata-comparator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata-comparator.d.ts","sourceRoot":"","sources":["../../../src/features/check/metadata-comparator.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,MAAM,WAAW,wBAAwB;IACvC,cAAc,EAAE,mBAAmB,GAAG,mBAAmB,GAAG,WAAW,CAAC;IACxE,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,EAAE,KAAK,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;KACvB,CAAC,CAAC;CACJ;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,EAAE,EAAE,CAAA;KAAE,CAAC;CACxC;AAsHD;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,mBAAmB,EAC1B,MAAM,EAAE,cAAc,GACrB,wBAAwB,CAe1B"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metadata similarity functions for comparing local vs remote reference metadata.
|
|
3
|
+
*/
|
|
4
|
+
type AuthorName = {
|
|
5
|
+
family?: string;
|
|
6
|
+
given?: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Check if two titles are similar using Jaccard similarity and Containment coefficient.
|
|
10
|
+
* Returns true (similar) if Jaccard >= 0.5 OR Containment >= 0.8.
|
|
11
|
+
* Returns true if either title is empty/undefined (not enough data to compare).
|
|
12
|
+
*/
|
|
13
|
+
export declare function isTitleSimilar(local: string | undefined, remote: string | undefined): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Check if author lists are similar using family name overlap ratio.
|
|
16
|
+
* Overlap = |local_families ∩ remote_families| / |local_families|
|
|
17
|
+
* Returns true (similar) if overlap >= 0.5.
|
|
18
|
+
* Returns true if either side has no authors (not enough data).
|
|
19
|
+
*/
|
|
20
|
+
export declare function isAuthorSimilar(local: AuthorName[] | undefined, remote: AuthorName[] | undefined): boolean;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=metadata-similarity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata-similarity.d.ts","sourceRoot":"","sources":["../../../src/features/check/metadata-similarity.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,KAAK,UAAU,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAWtD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAuB7F;AAeD;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,UAAU,EAAE,GAAG,SAAS,EAC/B,MAAM,EAAE,UAAU,EAAE,GAAG,SAAS,GAC/B,OAAO,CAoBT"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Check feature types
|
|
3
3
|
*/
|
|
4
|
-
export type CheckStatus = "ok" | "retracted" | "concern" | "version_changed" | "
|
|
4
|
+
export type CheckStatus = "ok" | "retracted" | "concern" | "version_changed" | "metadata_mismatch" | "metadata_outdated";
|
|
5
5
|
export interface CheckFinding {
|
|
6
6
|
type: CheckStatus;
|
|
7
7
|
message: string;
|
|
@@ -10,6 +10,11 @@ export interface CheckFinding {
|
|
|
10
10
|
retractionDate?: string;
|
|
11
11
|
newDoi?: string;
|
|
12
12
|
updatedFields?: string[];
|
|
13
|
+
fieldDiffs?: Array<{
|
|
14
|
+
field: string;
|
|
15
|
+
local: string | null;
|
|
16
|
+
remote: string | null;
|
|
17
|
+
}>;
|
|
13
18
|
};
|
|
14
19
|
}
|
|
15
20
|
export interface CheckResult {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/features/check/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/features/check/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,WAAW,GACnB,IAAI,GACJ,WAAW,GACX,SAAS,GACT,iBAAiB,GACjB,mBAAmB,GACnB,mBAAmB,CAAC;AAExB,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE;QACR,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;QACzB,UAAU,CAAC,EAAE,KAAK,CAAC;YACjB,KAAK,EAAE,MAAM,CAAC;YACd,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;YACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;SACvB,CAAC,CAAC;KACJ,CAAC;CACH;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,IAAI,GAAG,SAAS,GAAG,SAAS,CAAC;IACrC,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../src/features/operations/check.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAChF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE;YAAE,KAAK,CAAC,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;CAC3E;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,EAAE,EAAE,MAAM,CAAC;QACX,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAiBD,wBAAsB,eAAe,CACnC,OAAO,EAAE,QAAQ,EACjB,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,oBAAoB,CAAC,
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../src/features/operations/check.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAChF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE;YAAE,KAAK,CAAC,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;CAC3E;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,EAAE,EAAE,MAAM,CAAC;QACX,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAiBD,wBAAsB,eAAe,CACnC,OAAO,EAAE,QAAQ,EACjB,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,oBAAoB,CAAC,CA4B/B"}
|
|
@@ -5,6 +5,7 @@ export interface CheckToolParams {
|
|
|
5
5
|
all?: boolean | undefined;
|
|
6
6
|
skipDays?: number | undefined;
|
|
7
7
|
save?: boolean | undefined;
|
|
8
|
+
metadata?: boolean | undefined;
|
|
8
9
|
}
|
|
9
10
|
export declare function registerCheckTool(server: McpServer, getLibraryOperations: () => ILibraryOperations): void;
|
|
10
11
|
//# sourceMappingURL=check.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/check.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGzE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iDAAiD,CAAC;AAE1F,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC3B,GAAG,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/check.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGzE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iDAAiD,CAAC;AAE1F,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC3B,GAAG,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAChC;AAyBD,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,EACjB,oBAAoB,EAAE,MAAM,kBAAkB,GAC7C,IAAI,CA0CN"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../src/server/routes/check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../src/server/routes/check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AA6BrD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsBvD"}
|
package/dist/server.js
CHANGED
package/package.json
CHANGED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
async function checkReference(item, config) {
|
|
2
|
-
const id = item.id;
|
|
3
|
-
const uuid = item.custom?.uuid ?? "";
|
|
4
|
-
const checkedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
5
|
-
const findings = [];
|
|
6
|
-
const checkedSources = [];
|
|
7
|
-
const hasDoi = !!item.DOI;
|
|
8
|
-
const hasPmid = !!item.PMID;
|
|
9
|
-
if (!hasDoi && !hasPmid) {
|
|
10
|
-
return { id, uuid, status: "skipped", findings: [], checkedAt, checkedSources: [] };
|
|
11
|
-
}
|
|
12
|
-
if (hasDoi) {
|
|
13
|
-
checkedSources.push("crossref");
|
|
14
|
-
const crossrefFindings = await checkCrossref(item.DOI, config);
|
|
15
|
-
findings.push(...crossrefFindings);
|
|
16
|
-
}
|
|
17
|
-
if (hasPmid) {
|
|
18
|
-
checkedSources.push("pubmed");
|
|
19
|
-
const pubmedFindings = await checkPubmed(item.PMID, config);
|
|
20
|
-
for (const pf of pubmedFindings) {
|
|
21
|
-
if (!findings.some((f) => f.type === pf.type)) {
|
|
22
|
-
findings.push(pf);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
const status = findings.length > 0 ? "warning" : "ok";
|
|
27
|
-
return { id, uuid, status, findings, checkedAt, checkedSources };
|
|
28
|
-
}
|
|
29
|
-
async function checkCrossref(doi, config) {
|
|
30
|
-
const { queryCrossref } = await import("./crossref-client-DGNz4PNW.js");
|
|
31
|
-
const crossrefConfig = config?.email ? { email: config.email } : void 0;
|
|
32
|
-
const result = await queryCrossref(doi, crossrefConfig);
|
|
33
|
-
if (!result.success) return [];
|
|
34
|
-
const findings = [];
|
|
35
|
-
for (const update of result.updates) {
|
|
36
|
-
const finding = mapCrossrefUpdate(update);
|
|
37
|
-
if (finding) {
|
|
38
|
-
findings.push(finding);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return findings;
|
|
42
|
-
}
|
|
43
|
-
async function checkPubmed(pmid, config) {
|
|
44
|
-
const { queryPubmed } = await import("./pubmed-client-J18fg3fG.js");
|
|
45
|
-
const result = await queryPubmed(pmid, config?.pubmed);
|
|
46
|
-
if (!result.success) return [];
|
|
47
|
-
const findings = [];
|
|
48
|
-
if (result.isRetracted) {
|
|
49
|
-
findings.push({
|
|
50
|
-
type: "retracted",
|
|
51
|
-
message: "This article is marked as retracted in PubMed"
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
if (result.hasConcern) {
|
|
55
|
-
findings.push({
|
|
56
|
-
type: "concern",
|
|
57
|
-
message: "Expression of concern noted in PubMed"
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
return findings;
|
|
61
|
-
}
|
|
62
|
-
function mapCrossrefUpdate(update) {
|
|
63
|
-
const doiDetail = update.doi ? { retractionDoi: update.doi } : {};
|
|
64
|
-
const dateDetail = update.date ? { retractionDate: update.date } : {};
|
|
65
|
-
const newDoiDetail = update.doi ? { newDoi: update.doi } : {};
|
|
66
|
-
switch (update.type) {
|
|
67
|
-
case "retraction":
|
|
68
|
-
return {
|
|
69
|
-
type: "retracted",
|
|
70
|
-
message: update.date ? `This article was retracted on ${update.date}` : "This article was retracted",
|
|
71
|
-
details: { ...doiDetail, ...dateDetail }
|
|
72
|
-
};
|
|
73
|
-
case "expression-of-concern":
|
|
74
|
-
return {
|
|
75
|
-
type: "concern",
|
|
76
|
-
message: update.date ? `Expression of concern issued on ${update.date}` : "Expression of concern issued",
|
|
77
|
-
details: { ...doiDetail, ...dateDetail }
|
|
78
|
-
};
|
|
79
|
-
case "new_version":
|
|
80
|
-
return {
|
|
81
|
-
type: "version_changed",
|
|
82
|
-
message: update.doi ? `Published version available: ${update.doi}` : "Published version available",
|
|
83
|
-
details: newDoiDetail
|
|
84
|
-
};
|
|
85
|
-
default:
|
|
86
|
-
return null;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
export {
|
|
90
|
-
checkReference
|
|
91
|
-
};
|
|
92
|
-
//# sourceMappingURL=checker-7pzK2XSC.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"checker-7pzK2XSC.js","sources":["../../src/features/check/checker.ts"],"sourcesContent":["import type { CslItem } from \"../../core/csl-json/types.js\";\nimport type { CrossrefUpdateInfo } from \"./crossref-client.js\";\nimport type { CheckFinding, CheckResult } from \"./types.js\";\n\nexport interface CheckConfig {\n email?: string;\n pubmed?: { email?: string; apiKey?: string };\n}\n\n/**\n * Check a single reference against external sources for status changes.\n *\n * @param item - The CSL-JSON item to check\n * @param config - Optional config for API credentials\n * @returns Check result with findings\n */\nexport async function checkReference(item: CslItem, config?: CheckConfig): Promise<CheckResult> {\n const id = item.id;\n const uuid = (item.custom?.uuid as string) ?? \"\";\n const checkedAt = new Date().toISOString();\n const findings: CheckFinding[] = [];\n const checkedSources: string[] = [];\n\n const hasDoi = !!item.DOI;\n const hasPmid = !!item.PMID;\n\n // Skip references with neither DOI nor PMID\n if (!hasDoi && !hasPmid) {\n return { id, uuid, status: \"skipped\", findings: [], checkedAt, checkedSources: [] };\n }\n\n // Query Crossref if DOI is present\n if (hasDoi) {\n checkedSources.push(\"crossref\");\n const crossrefFindings = await checkCrossref(item.DOI as string, config);\n findings.push(...crossrefFindings);\n }\n\n // Query PubMed if PMID is present\n if (hasPmid) {\n checkedSources.push(\"pubmed\");\n const pubmedFindings = await checkPubmed(item.PMID as string, config);\n // Only add PubMed findings that aren't already found via Crossref\n for (const pf of pubmedFindings) {\n if (!findings.some((f) => f.type === pf.type)) {\n findings.push(pf);\n }\n }\n }\n\n const status = findings.length > 0 ? \"warning\" : \"ok\";\n return { id, uuid, status, findings, checkedAt, checkedSources };\n}\n\n/**\n * Query Crossref and return findings.\n */\nasync function checkCrossref(doi: string, config?: CheckConfig): Promise<CheckFinding[]> {\n const { queryCrossref } = await import(\"./crossref-client.js\");\n const crossrefConfig = config?.email ? { email: config.email } : undefined;\n const result = await queryCrossref(doi, crossrefConfig);\n if (!result.success) return [];\n\n const findings: CheckFinding[] = [];\n for (const update of result.updates) {\n const finding = mapCrossrefUpdate(update);\n if (finding) {\n findings.push(finding);\n }\n }\n return findings;\n}\n\n/**\n * Query PubMed and return findings.\n */\nasync function checkPubmed(pmid: string, config?: CheckConfig): Promise<CheckFinding[]> {\n const { queryPubmed } = await import(\"./pubmed-client.js\");\n const result = await queryPubmed(pmid, config?.pubmed);\n if (!result.success) return [];\n\n const findings: CheckFinding[] = [];\n if (result.isRetracted) {\n findings.push({\n type: \"retracted\",\n message: \"This article is marked as retracted in PubMed\",\n });\n }\n if (result.hasConcern) {\n findings.push({\n type: \"concern\",\n message: \"Expression of concern noted in PubMed\",\n });\n }\n return findings;\n}\n\n/**\n * Map a Crossref update-to entry to a CheckFinding.\n */\nfunction mapCrossrefUpdate(update: CrossrefUpdateInfo): CheckFinding | null {\n const doiDetail = update.doi ? { retractionDoi: update.doi } : {};\n const dateDetail = update.date ? { retractionDate: update.date } : {};\n const newDoiDetail = update.doi ? { newDoi: update.doi } : {};\n\n switch (update.type) {\n case \"retraction\":\n return {\n type: \"retracted\",\n message: update.date\n ? `This article was retracted on ${update.date}`\n : \"This article was retracted\",\n details: { ...doiDetail, ...dateDetail },\n };\n case \"expression-of-concern\":\n return {\n type: \"concern\",\n message: update.date\n ? `Expression of concern issued on ${update.date}`\n : \"Expression of concern issued\",\n details: { ...doiDetail, ...dateDetail },\n };\n case \"new_version\":\n return {\n type: \"version_changed\",\n message: update.doi\n ? `Published version available: ${update.doi}`\n : \"Published version available\",\n details: newDoiDetail,\n };\n default:\n return null;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { g as getRateLimiter } from "./index-D2HsxXnK.js";
|
|
2
|
-
const CROSSREF_API_BASE = "https://api.crossref.org/works";
|
|
3
|
-
function formatDateParts(updated) {
|
|
4
|
-
if (!updated || typeof updated !== "object") return {};
|
|
5
|
-
const dateParts = updated["date-parts"];
|
|
6
|
-
if (!Array.isArray(dateParts) || dateParts.length === 0) return {};
|
|
7
|
-
const parts = dateParts[0];
|
|
8
|
-
if (!Array.isArray(parts) || parts.length === 0) return {};
|
|
9
|
-
const [year, month, day] = parts;
|
|
10
|
-
const m = String(month ?? 1).padStart(2, "0");
|
|
11
|
-
const d = String(day ?? 1).padStart(2, "0");
|
|
12
|
-
return { date: `${year}-${m}-${d}` };
|
|
13
|
-
}
|
|
14
|
-
async function queryCrossref(doi, config) {
|
|
15
|
-
const rateLimiter = getRateLimiter("crossref", {});
|
|
16
|
-
await rateLimiter.acquire();
|
|
17
|
-
try {
|
|
18
|
-
const url = new URL(`${CROSSREF_API_BASE}/${encodeURIComponent(doi)}`);
|
|
19
|
-
if (config?.email) {
|
|
20
|
-
url.searchParams.set("mailto", config.email);
|
|
21
|
-
}
|
|
22
|
-
const response = await fetch(url.toString());
|
|
23
|
-
if (!response.ok) {
|
|
24
|
-
return {
|
|
25
|
-
success: false,
|
|
26
|
-
error: `Crossref API returned ${response.status} ${response.statusText}`
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
const data = await response.json();
|
|
30
|
-
const message = data.message;
|
|
31
|
-
const updateTo = message?.["update-to"] ?? [];
|
|
32
|
-
const updates = updateTo.map((e) => {
|
|
33
|
-
const datePart = formatDateParts(e.updated);
|
|
34
|
-
return {
|
|
35
|
-
type: String(e.type ?? ""),
|
|
36
|
-
...e.DOI ? { doi: String(e.DOI) } : {},
|
|
37
|
-
...e.label ? { label: String(e.label) } : {},
|
|
38
|
-
...datePart.date ? { date: datePart.date } : {}
|
|
39
|
-
};
|
|
40
|
-
});
|
|
41
|
-
return { success: true, updates };
|
|
42
|
-
} catch (error) {
|
|
43
|
-
return {
|
|
44
|
-
success: false,
|
|
45
|
-
error: error instanceof Error ? error.message : String(error)
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
export {
|
|
50
|
-
queryCrossref
|
|
51
|
-
};
|
|
52
|
-
//# sourceMappingURL=crossref-client-DGNz4PNW.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"crossref-client-DGNz4PNW.js","sources":["../../src/features/check/crossref-client.ts"],"sourcesContent":["import { getRateLimiter } from \"../import/rate-limiter.js\";\n\nconst CROSSREF_API_BASE = \"https://api.crossref.org/works\";\n\nexport interface CrossrefUpdateInfo {\n type: string;\n doi?: string;\n label?: string;\n date?: string;\n}\n\nexport type CrossrefResult =\n | { success: true; updates: CrossrefUpdateInfo[] }\n | { success: false; error: string };\n\n/**\n * Format date-parts from Crossref API response to ISO date string.\n */\nfunction formatDateParts(updated: unknown): { date?: string } {\n if (!updated || typeof updated !== \"object\") return {};\n const dateParts = (updated as Record<string, unknown>)[\"date-parts\"];\n if (!Array.isArray(dateParts) || dateParts.length === 0) return {};\n const parts = dateParts[0] as number[];\n if (!Array.isArray(parts) || parts.length === 0) return {};\n const [year, month, day] = parts;\n const m = String(month ?? 1).padStart(2, \"0\");\n const d = String(day ?? 1).padStart(2, \"0\");\n return { date: `${year}-${m}-${d}` };\n}\n\n/**\n * Query Crossref REST API for a DOI and extract update-to information.\n *\n * @param doi - The DOI to query\n * @param config - Optional config with email for polite pool\n * @returns Crossref result with update information\n */\nexport async function queryCrossref(\n doi: string,\n config?: { email?: string }\n): Promise<CrossrefResult> {\n const rateLimiter = getRateLimiter(\"crossref\", {});\n await rateLimiter.acquire();\n\n try {\n const url = new URL(`${CROSSREF_API_BASE}/${encodeURIComponent(doi)}`);\n if (config?.email) {\n url.searchParams.set(\"mailto\", config.email);\n }\n const response = await fetch(url.toString());\n\n if (!response.ok) {\n return {\n success: false,\n error: `Crossref API returned ${response.status} ${response.statusText}`,\n };\n }\n\n const data = (await response.json()) as Record<string, unknown>;\n const message = data.message as Record<string, unknown> | undefined;\n\n const updateTo = (message?.[\"update-to\"] ?? []) as Record<string, unknown>[];\n const updates: CrossrefUpdateInfo[] = updateTo.map((e) => {\n const datePart = formatDateParts(e.updated);\n return {\n type: String(e.type ?? \"\"),\n ...(e.DOI ? { doi: String(e.DOI) } : {}),\n ...(e.label ? { label: String(e.label) } : {}),\n ...(datePart.date ? { date: datePart.date } : {}),\n };\n });\n\n return { success: true, updates };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n"],"names":[],"mappings":";AAEA,MAAM,oBAAoB;AAgB1B,SAAS,gBAAgB,SAAqC;AAC5D,MAAI,CAAC,WAAW,OAAO,YAAY,iBAAiB,CAAA;AACpD,QAAM,YAAa,QAAoC,YAAY;AACnE,MAAI,CAAC,MAAM,QAAQ,SAAS,KAAK,UAAU,WAAW,EAAG,QAAO,CAAA;AAChE,QAAM,QAAQ,UAAU,CAAC;AACzB,MAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW,EAAG,QAAO,CAAA;AACxD,QAAM,CAAC,MAAM,OAAO,GAAG,IAAI;AAC3B,QAAM,IAAI,OAAO,SAAS,CAAC,EAAE,SAAS,GAAG,GAAG;AAC5C,QAAM,IAAI,OAAO,OAAO,CAAC,EAAE,SAAS,GAAG,GAAG;AAC1C,SAAO,EAAE,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAA;AAClC;AASA,eAAsB,cACpB,KACA,QACyB;AACzB,QAAM,cAAc,eAAe,YAAY,EAAE;AACjD,QAAM,YAAY,QAAA;AAElB,MAAI;AACF,UAAM,MAAM,IAAI,IAAI,GAAG,iBAAiB,IAAI,mBAAmB,GAAG,CAAC,EAAE;AACrE,QAAI,QAAQ,OAAO;AACjB,UAAI,aAAa,IAAI,UAAU,OAAO,KAAK;AAAA,IAC7C;AACA,UAAM,WAAW,MAAM,MAAM,IAAI,UAAU;AAE3C,QAAI,CAAC,SAAS,IAAI;AAChB,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,yBAAyB,SAAS,MAAM,IAAI,SAAS,UAAU;AAAA,MAAA;AAAA,IAE1E;AAEA,UAAM,OAAQ,MAAM,SAAS,KAAA;AAC7B,UAAM,UAAU,KAAK;AAErB,UAAM,WAAY,UAAU,WAAW,KAAK,CAAA;AAC5C,UAAM,UAAgC,SAAS,IAAI,CAAC,MAAM;AACxD,YAAM,WAAW,gBAAgB,EAAE,OAAO;AAC1C,aAAO;AAAA,QACL,MAAM,OAAO,EAAE,QAAQ,EAAE;AAAA,QACzB,GAAI,EAAE,MAAM,EAAE,KAAK,OAAO,EAAE,GAAG,EAAA,IAAM,CAAA;AAAA,QACrC,GAAI,EAAE,QAAQ,EAAE,OAAO,OAAO,EAAE,KAAK,EAAA,IAAM,CAAA;AAAA,QAC3C,GAAI,SAAS,OAAO,EAAE,MAAM,SAAS,KAAA,IAAS,CAAA;AAAA,MAAC;AAAA,IAEnD,CAAC;AAED,WAAO,EAAE,SAAS,MAAM,QAAA;AAAA,EAC1B,SAAS,OAAO;AACd,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,IAAA;AAAA,EAEhE;AACF;"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fix-interaction-BpfMLRNY.js","sources":["../../src/features/check/fix-actions.ts","../../src/features/check/fix-interaction.ts"],"sourcesContent":["import type { CslItem } from \"../../core/csl-json/types.js\";\nimport type { ILibrary } from \"../../core/library-interface.js\";\nimport type { CheckFinding } from \"./types.js\";\n\nexport type FixActionType =\n | \"add_retracted_tag\"\n | \"add_retraction_note\"\n | \"remove_from_library\"\n | \"update_from_published\"\n | \"add_version_tag\"\n | \"add_concern_tag\"\n | \"add_concern_note\"\n | \"skip\";\n\nexport interface FixAction {\n type: FixActionType;\n label: string;\n}\n\nexport interface FixActionResult {\n applied: boolean;\n message: string;\n removed?: boolean;\n}\n\nexport function getFixActionsForFinding(finding: CheckFinding): FixAction[] {\n switch (finding.type) {\n case \"retracted\":\n return [\n { type: \"add_retracted_tag\", label: 'Add tag \"retracted\"' },\n { type: \"add_retraction_note\", label: \"Add note with retraction details\" },\n { type: \"remove_from_library\", label: \"Remove from library\" },\n { type: \"skip\", label: \"Skip\" },\n ];\n case \"version_changed\":\n return [\n { type: \"update_from_published\", label: \"Update metadata from published version\" },\n { type: \"add_version_tag\", label: 'Add tag \"has-published-version\"' },\n { type: \"skip\", label: \"Skip\" },\n ];\n case \"concern\":\n return [\n { type: \"add_concern_tag\", label: 'Add tag \"expression-of-concern\"' },\n { type: \"add_concern_note\", label: \"Add note with concern details\" },\n { type: \"skip\", label: \"Skip\" },\n ];\n default:\n return [];\n }\n}\n\nfunction addTag(item: CslItem, tag: string): string[] {\n const existing = (item.custom?.tags as string[] | undefined) ?? [];\n if (existing.includes(tag)) {\n return existing;\n }\n return [...existing, tag];\n}\n\nfunction buildNoteText(prefix: string, finding: CheckFinding): string {\n const parts = [prefix];\n if (finding.details?.retractionDate) {\n parts.push(`Date: ${finding.details.retractionDate}`);\n }\n if (finding.details?.retractionDoi) {\n parts.push(`DOI: ${finding.details.retractionDoi}`);\n }\n return parts.join(\". \");\n}\n\nfunction appendNote(existingNote: string | undefined, newNote: string): string {\n if (existingNote) {\n return `${existingNote}\\n\\n${newNote}`;\n }\n return newNote;\n}\n\nasync function applyTagAction(\n library: ILibrary,\n item: CslItem,\n tag: string\n): Promise<FixActionResult> {\n const tags = addTag(item, tag);\n await library.update(item.id, { custom: { ...item.custom, tags } } as Partial<CslItem>, {\n idType: \"id\",\n });\n await library.save();\n return { applied: true, message: `Added tag \"${tag}\"` };\n}\n\nasync function applyNoteAction(\n library: ILibrary,\n item: CslItem,\n prefix: string,\n finding: CheckFinding\n): Promise<FixActionResult> {\n const noteText = buildNoteText(prefix, finding);\n const note = appendNote(item.note, noteText);\n await library.update(item.id, { note } as Partial<CslItem>, { idType: \"id\" });\n await library.save();\n return { applied: true, message: `Added note: ${noteText}` };\n}\n\nexport async function applyFixAction(\n library: ILibrary,\n item: CslItem,\n finding: CheckFinding,\n actionType: FixActionType\n): Promise<FixActionResult> {\n switch (actionType) {\n case \"add_retracted_tag\":\n return applyTagAction(library, item, \"retracted\");\n\n case \"add_retraction_note\":\n return applyNoteAction(library, item, \"RETRACTED\", finding);\n\n case \"add_concern_tag\":\n return applyTagAction(library, item, \"expression-of-concern\");\n\n case \"add_concern_note\":\n return applyNoteAction(library, item, \"EXPRESSION OF CONCERN\", finding);\n\n case \"add_version_tag\":\n return applyTagAction(library, item, \"has-published-version\");\n\n case \"remove_from_library\": {\n const removeResult = await library.remove(item.id, { idType: \"id\" });\n if (!removeResult.removed) {\n return { applied: false, message: `Failed to remove ${item.id}` };\n }\n await library.save();\n return { applied: true, message: `Removed ${item.id}`, removed: true };\n }\n\n case \"update_from_published\": {\n const newDoi = finding.details?.newDoi;\n if (!newDoi) {\n return { applied: false, message: \"No published DOI available in finding details\" };\n }\n const { fetchDoi } = await import(\"../import/fetcher.js\");\n const fetchResult = await fetchDoi(newDoi);\n if (!fetchResult.success) {\n return {\n applied: false,\n message: `Failed to fetch metadata for ${newDoi}: ${fetchResult.error}`,\n };\n }\n // Update with fetched metadata, preserving id and custom fields\n const { id: _id, custom: _custom, ...metadata } = fetchResult.item;\n await library.update(item.id, metadata as Partial<CslItem>, { idType: \"id\" });\n await library.save();\n return { applied: true, message: `Updated metadata from ${newDoi}` };\n }\n\n case \"skip\":\n return { applied: true, message: \"Skipped\" };\n\n default:\n return { applied: false, message: `Unknown action: ${actionType}` };\n }\n}\n","import { render } from \"ink\";\nimport { createElement } from \"react\";\nimport type { CslItem } from \"../../core/csl-json/types.js\";\nimport type { ILibrary } from \"../../core/library-interface.js\";\nimport { restoreStdinAfterInk } from \"../interactive/alternate-screen.js\";\nimport { Select } from \"../interactive/components/index.js\";\nimport type { SelectOption } from \"../interactive/components/index.js\";\nimport { type FixActionType, applyFixAction, getFixActionsForFinding } from \"./fix-actions.js\";\nimport type { CheckFinding, CheckResult } from \"./types.js\";\n\nexport interface FixInteractionResult {\n totalFindings: number;\n applied: number;\n skipped: number;\n removed: string[];\n}\n\nfunction selectFixAction(\n message: string,\n options: SelectOption<FixActionType>[]\n): Promise<FixActionType | null> {\n return new Promise<FixActionType | null>((resolve) => {\n let selected: FixActionType | null = null;\n\n const { waitUntilExit } = render(\n createElement(Select<FixActionType>, {\n options,\n message,\n onSelect: (value: FixActionType) => {\n selected = value;\n },\n onCancel: () => {\n selected = null;\n },\n })\n );\n\n waitUntilExit()\n .then(() => {\n restoreStdinAfterInk();\n resolve(selected);\n })\n .catch(() => {\n restoreStdinAfterInk();\n resolve(null);\n });\n });\n}\n\nfunction getStatusLabel(type: string): string {\n switch (type) {\n case \"retracted\":\n return \"RETRACTED\";\n case \"concern\":\n return \"CONCERN\";\n case \"version_changed\":\n return \"VERSION\";\n default:\n return \"WARNING\";\n }\n}\n\nfunction buildSelectOptions(finding: CheckFinding): SelectOption<FixActionType>[] {\n return getFixActionsForFinding(finding).map((a) => ({\n label: a.label,\n value: a.type,\n }));\n}\n\nasync function processFinding(\n result: FixInteractionResult,\n library: ILibrary,\n item: CslItem,\n resultId: string,\n finding: CheckFinding\n): Promise<void> {\n result.totalFindings++;\n const options = buildSelectOptions(finding);\n if (options.length === 0) return;\n\n const label = getStatusLabel(finding.type);\n const message = `[${label}] ${resultId}: ${finding.message}`;\n const selectedAction = await selectFixAction(message, options);\n\n if (selectedAction === null) {\n result.skipped++;\n return;\n }\n\n const actionResult = await applyFixAction(library, item, finding, selectedAction);\n\n if (!actionResult.applied) {\n process.stderr.write(` Error: ${actionResult.message}\\n`);\n return;\n }\n\n process.stderr.write(` ${actionResult.message}\\n`);\n if (selectedAction === \"skip\") {\n result.skipped++;\n } else {\n result.applied++;\n if (actionResult.removed) {\n result.removed.push(resultId);\n }\n }\n}\n\nexport async function runFixInteraction(\n results: CheckResult[],\n library: ILibrary,\n findItem: (id: string) => CslItem | undefined\n): Promise<FixInteractionResult> {\n const interactionResult: FixInteractionResult = {\n totalFindings: 0,\n applied: 0,\n skipped: 0,\n removed: [],\n };\n\n const warningResults = results.filter((r) => r.status === \"warning\");\n\n for (const checkResult of warningResults) {\n const item = findItem(checkResult.id);\n if (!item) continue;\n\n for (const finding of checkResult.findings) {\n await processFinding(interactionResult, library, item, checkResult.id, finding);\n }\n }\n\n return interactionResult;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-PQkbePWV.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
|