@deepcitation/deepcitation-js 1.0.8 → 1.0.9
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/lib/parsing/parseCitation.js +47 -13
- package/lib/react/utils.js +4 -2
- package/lib/types/citation.d.ts +0 -2
- package/package.json +1 -1
|
@@ -1,6 +1,50 @@
|
|
|
1
|
-
import { sha1Hash } from "../utils/sha.js";
|
|
2
1
|
import { normalizeCitations } from "./normalizeCitation.js";
|
|
3
2
|
import { generateCitationKey } from "../react/utils.js";
|
|
3
|
+
/**
|
|
4
|
+
* Parses a line_ids string that may contain individual numbers, ranges, or both.
|
|
5
|
+
* Examples: "1,2,3", "5-10", "1,5-7,10", "20-20"
|
|
6
|
+
*
|
|
7
|
+
* @param lineIdsString - The raw line_ids string (e.g., "1,5-7,10")
|
|
8
|
+
* @returns Sorted array of unique line IDs, or undefined if empty/invalid
|
|
9
|
+
*/
|
|
10
|
+
function parseLineIds(lineIdsString) {
|
|
11
|
+
if (!lineIdsString)
|
|
12
|
+
return undefined;
|
|
13
|
+
const lineIds = [];
|
|
14
|
+
const parts = lineIdsString.split(",");
|
|
15
|
+
for (const part of parts) {
|
|
16
|
+
const trimmed = part.trim();
|
|
17
|
+
if (!trimmed)
|
|
18
|
+
continue;
|
|
19
|
+
// Check if this part is a range (e.g., "5-10")
|
|
20
|
+
if (trimmed.includes("-")) {
|
|
21
|
+
const [startStr, endStr] = trimmed.split("-");
|
|
22
|
+
const start = parseInt(startStr, 10);
|
|
23
|
+
const end = parseInt(endStr, 10);
|
|
24
|
+
if (!isNaN(start) && !isNaN(end) && start <= end) {
|
|
25
|
+
// Expand the range
|
|
26
|
+
for (let i = start; i <= end; i++) {
|
|
27
|
+
lineIds.push(i);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
else if (!isNaN(start)) {
|
|
31
|
+
// If only start is valid, just use it
|
|
32
|
+
lineIds.push(start);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
// Single number
|
|
37
|
+
const num = parseInt(trimmed, 10);
|
|
38
|
+
if (!isNaN(num)) {
|
|
39
|
+
lineIds.push(num);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (lineIds.length === 0)
|
|
44
|
+
return undefined;
|
|
45
|
+
// Sort and deduplicate
|
|
46
|
+
return [...new Set(lineIds)].sort((a, b) => a - b);
|
|
47
|
+
}
|
|
4
48
|
/**
|
|
5
49
|
* Calculates the verification status of a citation based on the found highlight and search state.
|
|
6
50
|
*
|
|
@@ -55,7 +99,6 @@ export const parseCitation = (fragment, mdAttachmentId, citationCounterRef, isVe
|
|
|
55
99
|
const citationRegex = /<cite\s+file(?:_id|Id)='(\w{0,25})'\s+start_page[\_a-zA-Z]*='page[\_a-zA-Z]*(\d+)_index_(\d+)'\s+full_phrase='((?:[^'\\]|\\.)*)'\s+key_span='((?:[^'\\]|\\.)*)'\s+line(?:_ids|Ids)='([^']+)'(?:\s+(value|reasoning)='((?:[^'\\]|\\.)*)')?\s*\/>/g;
|
|
56
100
|
const citationMatches = [...middleCite.matchAll(citationRegex)];
|
|
57
101
|
const match = citationMatches?.[0];
|
|
58
|
-
const rawCitationMd = match?.[0];
|
|
59
102
|
const pageNumber = match?.[2] ? parseInt(match?.[2]) : undefined;
|
|
60
103
|
let fileId = match?.[1];
|
|
61
104
|
let attachmentId = fileId?.length === 20 ? fileId : mdAttachmentId || match?.[1];
|
|
@@ -75,15 +118,9 @@ export const parseCitation = (fragment, mdAttachmentId, citationCounterRef, isVe
|
|
|
75
118
|
}
|
|
76
119
|
let lineIds;
|
|
77
120
|
try {
|
|
78
|
-
// match[
|
|
121
|
+
// match[6] is line_ids
|
|
79
122
|
const lineIdsString = match?.[6]?.replace(/[A-Za-z_[\](){}:]/g, "");
|
|
80
|
-
lineIds = lineIdsString
|
|
81
|
-
? lineIdsString
|
|
82
|
-
.split(",")
|
|
83
|
-
.map((id) => (isNaN(parseInt(id)) ? undefined : parseInt(id)))
|
|
84
|
-
.filter((id) => id !== undefined)
|
|
85
|
-
.sort((a, b) => a - b)
|
|
86
|
-
: undefined;
|
|
123
|
+
lineIds = lineIdsString ? parseLineIds(lineIdsString) : undefined;
|
|
87
124
|
}
|
|
88
125
|
catch (e) {
|
|
89
126
|
if (isVerbose)
|
|
@@ -116,16 +153,13 @@ export const parseCitation = (fragment, mdAttachmentId, citationCounterRef, isVe
|
|
|
116
153
|
}
|
|
117
154
|
timestamps = { startTime, endTime };
|
|
118
155
|
}
|
|
119
|
-
const fragmentContext = sha1Hash(fragment).toString().slice(0, 8);
|
|
120
156
|
const citation = {
|
|
121
|
-
fragmentContext,
|
|
122
157
|
fileId: attachmentId,
|
|
123
158
|
pageNumber,
|
|
124
159
|
fullPhrase,
|
|
125
160
|
keySpan,
|
|
126
161
|
citationNumber,
|
|
127
162
|
lineIds,
|
|
128
|
-
rawCitationMd,
|
|
129
163
|
beforeCite,
|
|
130
164
|
value,
|
|
131
165
|
timestamps,
|
package/lib/react/utils.js
CHANGED
|
@@ -13,7 +13,6 @@ export function generateCitationKey(citation) {
|
|
|
13
13
|
citation.lineIds?.join(",") || "",
|
|
14
14
|
citation.timestamps?.startTime || "",
|
|
15
15
|
citation.timestamps?.endTime || "",
|
|
16
|
-
citation.fragmentContext || "",
|
|
17
16
|
];
|
|
18
17
|
return sha1Hash(keyParts.join("|")).slice(0, 16);
|
|
19
18
|
}
|
|
@@ -31,7 +30,10 @@ export function generateCitationInstanceId(citationKey) {
|
|
|
31
30
|
export function getCitationDisplayText(citation, options = {}) {
|
|
32
31
|
const { displayCitationValue = false, fallbackDisplay } = options;
|
|
33
32
|
if (displayCitationValue) {
|
|
34
|
-
return citation.value ||
|
|
33
|
+
return (citation.value ||
|
|
34
|
+
citation.citationNumber?.toString() ||
|
|
35
|
+
fallbackDisplay ||
|
|
36
|
+
"");
|
|
35
37
|
}
|
|
36
38
|
return citation.citationNumber?.toString() || "";
|
|
37
39
|
}
|
package/lib/types/citation.d.ts
CHANGED