@eten-tech-foundation/scripture-utilities 0.1.5 → 0.1.6

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/dist/index.js CHANGED
@@ -1,10 +1,87 @@
1
- import { DOMParser as g, DOMImplementation as J } from "@xmldom/xmldom";
2
- const y = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
1
+ import { DOMImplementation as g, DOMParser as M } from "@xmldom/xmldom";
2
+ const j = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
3
3
  function m(e) {
4
- if (y.has(e))
4
+ if (j.has(e))
5
5
  throw new Error(`The key "${e}" is not allowed to avoid prototype pollution.`);
6
6
  }
7
- const T = "USJ", O = "3.1", H = Object.freeze({ type: T, version: O, content: [] }), I = [
7
+ const A = "$", O = ".content[";
8
+ function I(e) {
9
+ const t = e.split(O);
10
+ if (t.shift() !== A)
11
+ throw new Error(`indexesFromJsonPath: jsonPath didn't start with '${A}'`);
12
+ return t.map((r) => parseInt(r, 10));
13
+ }
14
+ function D(e) {
15
+ return e.reduce(
16
+ (t, n) => `${t}${O}${n}]`,
17
+ A
18
+ );
19
+ }
20
+ function v(e) {
21
+ return e != null && "jsonPath" in e && !("offset" in e) && !("closingMarkerOffset" in e) && !("propertyOffset" in e) && !("keyName" in e);
22
+ }
23
+ function U(e) {
24
+ return e != null && "jsonPath" in e && "closingMarkerOffset" in e;
25
+ }
26
+ function J(e) {
27
+ return e != null && "jsonPath" in e && "offset" in e && !("propertyOffset" in e) && !("keyName" in e);
28
+ }
29
+ function L(e) {
30
+ return e != null && "jsonPath" in e && "propertyOffset" in e;
31
+ }
32
+ function C(e) {
33
+ return e != null && "jsonPath" in e && "keyName" in e && "keyOffset" in e;
34
+ }
35
+ function X(e) {
36
+ return e != null && "jsonPath" in e && "keyName" in e && !("keyOffset" in e) && !("keyClosingMarkerOffset" in e);
37
+ }
38
+ function _(e) {
39
+ return e != null && "jsonPath" in e && "keyName" in e && "keyClosingMarkerOffset" in e;
40
+ }
41
+ function w(e) {
42
+ return e === void 0 ? "undefined" : e === null ? "null" : _(e) ? "UsjClosingAttributeMarkerLocation" : C(e) ? "UsjAttributeKeyLocation" : X(e) ? "UsjAttributeMarkerLocation" : L(e) ? "UsjPropertyValueLocation" : U(e) ? "UsjClosingMarkerLocation" : J(e) ? "UsjTextContentLocation" : v(e) ? "UsjMarkerLocation" : "Unknown";
43
+ }
44
+ const d = "usx", T = "3.1", K = `<${d} version="${T}" />`;
45
+ let u, c;
46
+ function x(e) {
47
+ const t = new g().createDocument("", d);
48
+ return t.documentElement && (t.documentElement.setAttribute("version", T), k(e, t)), t.toString();
49
+ }
50
+ function k(e, t) {
51
+ if (t.documentElement) {
52
+ for (const [n, r] of e.content.entries()) {
53
+ const o = n === e.content.length - 1;
54
+ y(r, t.documentElement, t, o);
55
+ }
56
+ return t.documentElement ?? void 0;
57
+ }
58
+ }
59
+ function y(e, t, n, r) {
60
+ let o, f, i;
61
+ if (typeof e == "string") o = n.createTextNode(e);
62
+ else if (f = e.type.replace("table:", ""), o = n.createElement(f), R(o, e), e.content)
63
+ for (const [s, l] of e.content.entries()) {
64
+ const p = s === e.content.length - 1;
65
+ y(l, o, n, p);
66
+ }
67
+ c && (f === "verse" || t.tagName === "para" && r) && (i = S(n, c), c = void 0), f === "verse" && typeof e != "string" && e.sid !== void 0 && (c = e.sid), u && (f === "chapter" || f === "para" && r) && (i = h(n, u), u = void 0), f === "chapter" && typeof e != "string" && e.sid !== void 0 && (u = e.sid);
68
+ const a = t.nodeName === d && (i == null ? void 0 : i.tagName) === "verse";
69
+ i && (!r || a) && t.appendChild(i), t.appendChild(o), i && r && !a && t.appendChild(i), r && t.nodeName === d && (c && t.appendChild(S(n, c)), u && t.appendChild(h(n, u)), c = void 0, u = void 0);
70
+ }
71
+ function R(e, t) {
72
+ t.marker && (t.type === "unmatched" ? e.setAttribute("marker", t.marker) : e.setAttribute("style", t.marker));
73
+ for (const [n, r] of Object.entries(t))
74
+ r && !["type", "marker", "content"].includes(n) && e.setAttribute(n, r);
75
+ }
76
+ function S(e, t) {
77
+ const n = e.createElement("verse");
78
+ return n.setAttribute("eid", t), n;
79
+ }
80
+ function h(e, t) {
81
+ const n = e.createElement("chapter");
82
+ return n.setAttribute("eid", t), n;
83
+ }
84
+ const N = "USJ", P = "3.1", G = Object.freeze({ type: N, version: P, content: [] }), $ = [
8
85
  "type",
9
86
  "marker",
10
87
  "content",
@@ -18,10 +95,10 @@ const T = "USJ", O = "3.1", H = Object.freeze({ type: T, version: O, content: []
18
95
  "align",
19
96
  "category"
20
97
  ];
21
- function V(e) {
22
- return M.includes(e);
98
+ function F(e) {
99
+ return V.includes(e);
23
100
  }
24
- const M = [
101
+ const V = [
25
102
  // Old Testament
26
103
  "GEN",
27
104
  "EXO",
@@ -142,108 +219,67 @@ const M = [
142
219
  "XXE",
143
220
  "XXF",
144
221
  "XXG"
145
- ], l = "usx", N = "3.1", C = `<${l} version="${N}" />`;
146
- function D(e) {
147
- const n = new g().parseFromString(e, "text/xml");
148
- return X(n.documentElement);
222
+ ];
223
+ function Z(e) {
224
+ const n = new M().parseFromString(e, "text/xml");
225
+ return B(n.documentElement);
149
226
  }
150
- function X(e) {
227
+ function B(e) {
151
228
  const [t] = e ? b(e) : [{ content: [] }];
152
- return t.type = T, t.version = O, t;
229
+ return t.type = N, t.version = P, t;
153
230
  }
154
231
  function b(e) {
155
232
  const t = {};
156
- let n = e.tagName, o, s, c = "append";
233
+ let n = e.tagName, r, o, f = "append";
157
234
  if (["row", "cell"].includes(n) && (n = "table:" + n), e.attributes)
158
- for (const r of Array.from(e.attributes))
159
- m(r.name), t[r.name] = r.value;
160
- t.style && (o = t.style, delete t.style), t.vid && delete t.vid, t.status && delete t.status;
235
+ for (const s of Array.from(e.attributes))
236
+ m(s.name), t[s.name] = s.value;
237
+ t.style && (r = t.style, delete t.style), t.vid && delete t.vid, t.status && delete t.status;
161
238
  let i = { type: n };
162
- o && (i.marker = o), i = { ...i, ...t }, e.firstChild && e.firstChild.nodeType === e.firstChild.TEXT_NODE && e.firstChild.nodeValue && E(e.firstChild.nodeValue) !== "" && (s = e.firstChild.nodeValue);
163
- const f = Array.from(e.childNodes);
164
- i.content = [], s && i.content.push(s);
165
- for (const r of f) {
166
- if (r.tagName === void 0)
239
+ r && (i.marker = r), i = { ...i, ...t }, e.firstChild && e.firstChild.nodeType === e.firstChild.TEXT_NODE && e.firstChild.nodeValue && E(e.firstChild.nodeValue) !== "" && (o = e.firstChild.nodeValue);
240
+ const a = Array.from(e.childNodes);
241
+ i.content = [], o && i.content.push(o);
242
+ for (const s of a) {
243
+ if (s.tagName === void 0)
167
244
  continue;
168
- const [u, S] = b(r);
169
- switch (S) {
245
+ const [l, p] = b(s);
246
+ switch (p) {
170
247
  case "append":
171
- i.content.push(u);
248
+ i.content.push(l);
172
249
  break;
173
250
  case "merge":
174
- i.content = i.content.concat(u);
251
+ i.content = i.content.concat(l);
175
252
  break;
176
253
  }
177
- r.nextSibling && r.nextSibling.nodeType === r.nextSibling.TEXT_NODE && r.nextSibling.nodeValue && (E(r.nextSibling.nodeValue) !== "" || r.nextSibling.nodeValue === " ") && i.content.push(r.nextSibling.nodeValue);
254
+ s.nextSibling && s.nextSibling.nodeType === s.nextSibling.TEXT_NODE && s.nextSibling.nodeValue && (E(s.nextSibling.nodeValue) !== "" || s.nextSibling.nodeValue === " ") && i.content.push(s.nextSibling.nodeValue);
178
255
  }
179
- return i.content.length === 0 && i.type !== l && delete i.content, "eid" in i && ["verse", "chapter"].includes(n) && (c = "ignore"), [i, c];
256
+ return i.content.length === 0 && i.type !== d && delete i.content, "eid" in i && ["verse", "chapter"].includes(n) && (f = "ignore"), [i, f];
180
257
  }
181
258
  function E(e) {
182
259
  return e.replace(/(^[ \t\n\r\f\v]+)|([ \t\n\r\f\v]+$)/g, "");
183
260
  }
184
- let d, a;
185
- function U(e) {
186
- const t = new J().createDocument("", l);
187
- return t.documentElement && (t.documentElement.setAttribute("version", N), _(e, t)), t.toString();
188
- }
189
- function _(e, t) {
190
- if (t.documentElement) {
191
- for (const [n, o] of e.content.entries()) {
192
- const s = n === e.content.length - 1;
193
- v(o, t.documentElement, t, s);
194
- }
195
- return t.documentElement ?? void 0;
196
- }
197
- }
198
- function v(e, t, n, o) {
199
- let s, c, i;
200
- if (typeof e == "string") s = n.createTextNode(e);
201
- else if (c = e.type.replace("table:", ""), s = n.createElement(c), R(s, e), e.content)
202
- for (const [r, u] of e.content.entries()) {
203
- const S = r === e.content.length - 1;
204
- v(u, s, n, S);
205
- }
206
- a && (c === "verse" || t.tagName === "para" && o) && (i = p(n, a), a = void 0), c === "verse" && typeof e != "string" && e.sid !== void 0 && (a = e.sid), d && (c === "chapter" || c === "para" && o) && (i = h(n, d), d = void 0), c === "chapter" && typeof e != "string" && e.sid !== void 0 && (d = e.sid);
207
- const f = t.nodeName === l && (i == null ? void 0 : i.tagName) === "verse";
208
- i && (!o || f) && t.appendChild(i), t.appendChild(s), i && o && !f && t.appendChild(i), o && t.nodeName === l && (a && t.appendChild(p(n, a)), d && t.appendChild(h(n, d)), a = void 0, d = void 0);
209
- }
210
- function R(e, t) {
211
- t.marker && (t.type === "unmatched" ? e.setAttribute("marker", t.marker) : e.setAttribute("style", t.marker));
212
- for (const [n, o] of Object.entries(t))
213
- o && !["type", "marker", "content"].includes(n) && e.setAttribute(n, o);
214
- }
215
- function p(e, t) {
216
- const n = e.createElement("verse");
217
- return n.setAttribute("eid", t), n;
218
- }
219
- function h(e, t) {
220
- const n = e.createElement("chapter");
221
- return n.setAttribute("eid", t), n;
222
- }
223
- const A = "$", P = ".content[";
224
- function w(e) {
225
- const t = e.split(P);
226
- if (t.shift() !== A)
227
- throw new Error(`indexesFromJsonPath: jsonPath didn't start with '${A}'`);
228
- return t.map((o) => parseInt(o, 10));
229
- }
230
- function L(e) {
231
- return e.reduce((t, n) => `${t}${P}${n}]`, A);
232
- }
233
261
  export {
234
- H as EMPTY_USJ,
235
- C as EMPTY_USX,
236
- I as MARKER_OBJECT_PROPS,
237
- T as USJ_TYPE,
238
- O as USJ_VERSION,
239
- l as USX_TYPE,
240
- N as USX_VERSION,
241
- M as VALID_BOOK_CODES,
262
+ G as EMPTY_USJ,
263
+ K as EMPTY_USX,
264
+ $ as MARKER_OBJECT_PROPS,
265
+ N as USJ_TYPE,
266
+ P as USJ_VERSION,
267
+ d as USX_TYPE,
268
+ T as USX_VERSION,
269
+ V as VALID_BOOK_CODES,
242
270
  m as assertSafeKey,
243
- w as indexesFromUsjJsonPath,
244
- V as isValidBookCode,
245
- L as usjJsonPathFromIndexes,
246
- U as usjToUsxString,
247
- D as usxStringToUsj
271
+ w as getUsjDocumentLocationTypeName,
272
+ I as indexesFromUsjJsonPath,
273
+ C as isUsjAttributeKeyLocation,
274
+ X as isUsjAttributeMarkerLocation,
275
+ _ as isUsjClosingAttributeMarkerLocation,
276
+ U as isUsjClosingMarkerLocation,
277
+ v as isUsjMarkerLocation,
278
+ L as isUsjPropertyValueLocation,
279
+ J as isUsjTextContentLocation,
280
+ F as isValidBookCode,
281
+ D as usjJsonPathFromIndexes,
282
+ x as usjToUsxString,
283
+ Z as usxStringToUsj
248
284
  };
249
285
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/converters/usj/converter.utils.ts","../src/converters/usj/usj.model.ts","../src/converters/usj/usx.model.ts","../src/converters/usj/usx-to-usj.ts","../src/converters/usj/usj-to-usx.ts","../src/converters/usj/jsonpath-indexes.ts"],"sourcesContent":["/* Utility functions for converters */\n\nconst UNSAFE_KEYS = new Set([\"__proto__\", \"prototype\", \"constructor\"]);\n\n/**\n * Avoid prototype pollution by disallowing unsafe keys.\n * @param key - The array key to validate.\n *\n * @public\n */\nexport function assertSafeKey(key: string): void {\n if (!UNSAFE_KEYS.has(key)) return;\n\n throw new Error(`The key \"${key}\" is not allowed to avoid prototype pollution.`);\n}\n","/**\n * Unified Scripture JSON (USJ) - The JSON variant of USFM and USX data models.\n * These types follow this schema:\n * @see https://github.com/usfm-bible/tcdocs/blob/usj/grammar/usj.js\n */\n\n/**\n * The USJ spec type\n * @public\n */\nexport const USJ_TYPE = \"USJ\";\n\n/**\n * The USJ spec version\n * @public\n */\nexport const USJ_VERSION = \"3.1\";\n\n/**\n * An empty USJ object\n * @public\n */\nexport const EMPTY_USJ = Object.freeze<Usj>({ type: USJ_TYPE, version: USJ_VERSION, content: [] });\n\n/**\n * List of known properties of `MarkerObject`\n * @public\n */\nexport const MARKER_OBJECT_PROPS: (keyof MarkerObject)[] = [\n \"type\",\n \"marker\",\n \"content\",\n \"sid\",\n \"eid\",\n \"number\",\n \"code\",\n \"altnumber\",\n \"pubnumber\",\n \"caller\",\n \"align\",\n \"category\",\n];\n\n/**\n * Single piece of Scripture content\n * @public\n */\nexport type MarkerContent = string | MarkerObject;\n\n/**\n * A Scripture Marker and its contents\n * @public\n */\nexport interface MarkerObject {\n /**\n * The kind/category of node or element this is, corresponding the USFM marker and USX node\n * @example `para`, `verse`, `char`\n */\n type: string;\n /**\n * The corresponding marker in USFM or style in USX\n * @example `p`, `v`, `nd`\n */\n marker?: string;\n /** This marker's contents laid out in order */\n content?: MarkerContent[];\n /** Indicates the Book-chapter-verse value in the paragraph based structure */\n sid?: string;\n /** Milestone end ID, matches start ID (not currently included in USJ spec) */\n eid?: string;\n /** Chapter number or verse number */\n number?: string;\n /** The 3-letter book code in ID element */\n code?: BookCode;\n /** Alternate chapter number or verse number */\n altnumber?: string;\n /** Published character of chapter or verse */\n pubnumber?: string;\n /** Caller character for footnotes and cross-refs */\n caller?: string;\n /** Alignment of table cells */\n align?: string;\n /** Category of extended study bible sections */\n category?: string;\n}\n\n/**\n * Scripture data represented in JSON format. Data compatible transformation from USX/USFM\n * @public\n */\nexport interface Usj {\n /** The USJ spec type */\n type: typeof USJ_TYPE;\n /** The USJ spec version */\n version: typeof USJ_VERSION;\n /** The JSON representation of scripture contents from USFM/USX */\n content: MarkerContent[];\n}\n\n/**\n * Check if the given code is a valid 3-letter Scripture book code.\n * @public\n */\nexport function isValidBookCode(code: string): boolean {\n return VALID_BOOK_CODES.includes(code as BookCode);\n}\n\n/**\n * 3-letter Scripture book code\n * @public\n */\nexport type BookCode = (typeof VALID_BOOK_CODES)[number];\n\n/**\n * List of valid 3-letter Scripture book codes\n * @public\n */\nexport const VALID_BOOK_CODES = [\n // Old Testament\n \"GEN\",\n \"EXO\",\n \"LEV\",\n \"NUM\",\n \"DEU\",\n \"JOS\",\n \"JDG\",\n \"RUT\",\n \"1SA\",\n \"2SA\",\n \"1KI\",\n \"2KI\",\n \"1CH\",\n \"2CH\",\n \"EZR\",\n \"NEH\",\n \"EST\",\n \"JOB\",\n \"PSA\",\n \"PRO\",\n \"ECC\",\n \"SNG\",\n \"ISA\",\n \"JER\",\n \"LAM\",\n \"EZK\",\n \"DAN\",\n \"HOS\",\n \"JOL\",\n \"AMO\",\n \"OBA\",\n \"JON\",\n \"MIC\",\n \"NAM\",\n \"HAB\",\n \"ZEP\",\n \"HAG\",\n \"ZEC\",\n \"MAL\",\n // New Testament\n \"MAT\",\n \"MRK\",\n \"LUK\",\n \"JHN\",\n \"ACT\",\n \"ROM\",\n \"1CO\",\n \"2CO\",\n \"GAL\",\n \"EPH\",\n \"PHP\",\n \"COL\",\n \"1TH\",\n \"2TH\",\n \"1TI\",\n \"2TI\",\n \"TIT\",\n \"PHM\",\n \"HEB\",\n \"JAS\",\n \"1PE\",\n \"2PE\",\n \"1JN\",\n \"2JN\",\n \"3JN\",\n \"JUD\",\n \"REV\",\n // Deuterocanon\n \"TOB\",\n \"JDT\",\n \"ESG\",\n \"WIS\",\n \"SIR\",\n \"BAR\",\n \"LJE\",\n \"S3Y\",\n \"SUS\",\n \"BEL\",\n \"1MA\",\n \"2MA\",\n \"3MA\",\n \"4MA\",\n \"1ES\",\n \"2ES\",\n \"MAN\",\n \"PS2\",\n \"ODA\",\n \"PSS\",\n \"EZA\",\n \"5EZ\",\n \"6EZ\",\n \"DAG\",\n \"PS3\",\n \"2BA\",\n \"LBA\",\n \"JUB\",\n \"ENO\",\n \"1MQ\",\n \"2MQ\",\n \"3MQ\",\n \"REP\",\n \"4BA\",\n \"LAO\",\n // Non scripture\n \"FRT\",\n \"BAK\",\n \"OTH\",\n \"INT\",\n \"CNC\",\n \"GLO\",\n \"TDX\",\n \"NDX\",\n \"XXA\",\n \"XXB\",\n \"XXC\",\n \"XXD\",\n \"XXE\",\n \"XXF\",\n \"XXG\",\n] as const;\n","/**\n * Unified Scripture XML (USX).\n * These types follow this schema:\n * @see https://github.com/usfm-bible/tcdocs/blob/main/grammar/usx.rng\n */\n\n/**\n * The USX spec type\n * @public\n */\nexport const USX_TYPE = \"usx\";\n\n/**\n * The USX spec version\n * @public\n */\nexport const USX_VERSION = \"3.1\";\n\n/**\n * An empty USX string\n * @public\n */\nexport const EMPTY_USX = `<${USX_TYPE} version=\"${USX_VERSION}\" />`;\n","/**\n * Convert Scripture from USX to USJ.\n * Adapted to TypeScript from this file:\n * @see https://github.com/usfm-bible/usfmtc/blob/0afa385a1f282b286cc6bff7bbc953ae788aa10c/src/usfmtc/usjproc.py\n */\n\nimport { DOMParser, Element } from \"@xmldom/xmldom\";\nimport { MarkerContent, MarkerObject, USJ_TYPE, USJ_VERSION, Usj } from \"./usj.model.js\";\nimport { USX_TYPE } from \"./usx.model.js\";\nimport { assertSafeKey } from \"./converter.utils.js\";\n\ntype Action = \"append\" | \"merge\" | \"ignore\";\ninterface Attribs {\n [name: string]: string;\n}\n\n/**\n * Converts a USX string to a USJ object.\n *\n * @param usxString - The USX string to convert.\n * @returns The converted USJ object.\n *\n * @public\n */\nexport function usxStringToUsj(usxString: string): Usj {\n const parser = new DOMParser();\n const inputUsxDom = parser.parseFromString(usxString, \"text/xml\");\n return usxDomToUsj(inputUsxDom.documentElement);\n}\n\nexport function usxDomToUsj(inputUsxDom: Element | null): Usj {\n const [outputJson] = inputUsxDom\n ? convertUsxRecurse(inputUsxDom)\n : [{ content: [] as MarkerContent[] } as Usj];\n outputJson.type = USJ_TYPE;\n outputJson.version = USJ_VERSION;\n return outputJson;\n}\n\nfunction convertUsxRecurse<T extends Usj | MarkerObject = Usj>(\n inputUsxElement: Element,\n): [outputJson: T, action: Action] {\n const attribs: Attribs = {};\n let type: string = inputUsxElement.tagName;\n let marker: string | undefined;\n let text: string | undefined;\n let action: Action = \"append\";\n\n if ([\"row\", \"cell\"].includes(type)) type = \"table:\" + type;\n if (inputUsxElement.attributes) {\n for (const attrib of Array.from(inputUsxElement.attributes)) {\n assertSafeKey(attrib.name);\n attribs[attrib.name] = attrib.value;\n }\n }\n\n if (attribs.style) {\n marker = attribs.style;\n delete attribs.style;\n }\n // dropping because presence of vid in para elements is not consistent in USX\n if (attribs.vid) delete attribs.vid;\n // Not dropping `attribs.closed` for backwards compatibility.\n // dropping because it is nonstandard derived metadata that could get out of date\n if (attribs.status) delete attribs.status;\n\n let outObj: T = { type } as T;\n if (marker) (outObj as MarkerObject).marker = marker;\n outObj = { ...outObj, ...attribs };\n\n if (\n inputUsxElement.firstChild &&\n inputUsxElement.firstChild.nodeType === inputUsxElement.firstChild.TEXT_NODE &&\n inputUsxElement.firstChild.nodeValue &&\n asciiTrim(inputUsxElement.firstChild.nodeValue) !== \"\"\n ) {\n text = inputUsxElement.firstChild.nodeValue;\n }\n\n const children = Array.from(inputUsxElement.childNodes);\n outObj.content = [];\n\n if (text) {\n outObj.content.push(text);\n }\n\n for (const child of children) {\n // ChildNodes are Elements.\n if ((child as Element).tagName === undefined) {\n continue;\n }\n // ChildNodes are Elements.\n const [childDict, whatToDo] = convertUsxRecurse<MarkerObject>(child as Element);\n\n switch (whatToDo) {\n case \"append\":\n outObj.content.push(childDict);\n break;\n case \"merge\":\n outObj.content = outObj.content.concat(childDict);\n break;\n case \"ignore\":\n break;\n default:\n break;\n }\n\n // Handle tail text\n if (\n child.nextSibling &&\n child.nextSibling.nodeType === child.nextSibling.TEXT_NODE &&\n child.nextSibling.nodeValue &&\n (asciiTrim(child.nextSibling.nodeValue) !== \"\" || child.nextSibling.nodeValue === \" \")\n ) {\n outObj.content.push(child.nextSibling.nodeValue);\n }\n }\n\n // For backward compatibility, not deleting content for type: chapter, verse, optbreak, ms OR\n // marker: va, ca, b.\n if (outObj.content.length === 0 && outObj.type !== USX_TYPE) {\n delete outObj.content;\n }\n\n if (\"eid\" in outObj && [\"verse\", \"chapter\"].includes(type)) {\n action = \"ignore\";\n }\n\n return [outObj, action];\n}\n\n/**\n * Removes leading and trailing ASCII whitespace.\n *\n * Only trim ASCII whitespace characters: space, tab, line feed, carriage return, form feed,\n * vertical tab.\n * @param str - The string to remove whitespace from.\n * @returns the string with leading and trailing whitespace removed.\n */\nfunction asciiTrim(str: string): string {\n return str.replace(/(^[ \\t\\n\\r\\f\\v]+)|([ \\t\\n\\r\\f\\v]+$)/g, \"\");\n}\n","/**\n * Convert Scripture from USJ to USX.\n * Adapted to TypeScript from this file:\n * @see https://github.com/usfm-bible/usfmtc/blob/0afa385a1f282b286cc6bff7bbc953ae788aa10c/src/usfmtc/usjproc.py\n */\n\nimport { DOMImplementation, Document, Element, Text } from \"@xmldom/xmldom\";\nimport { MarkerContent, MarkerObject, Usj } from \"./usj.model.js\";\nimport { USX_TYPE, USX_VERSION } from \"./usx.model.js\";\n\nlet chapterEid: string | undefined;\nlet verseEid: string | undefined;\n\n/**\n * Converts a USJ object to a USX string.\n *\n * @param usj - The USJ object to convert\n * @returns The converted USX string.\n *\n * @public\n */\nexport function usjToUsxString(usj: Usj): string {\n const usxDoc = new DOMImplementation().createDocument(\"\", USX_TYPE);\n if (usxDoc.documentElement) {\n usxDoc.documentElement.setAttribute(\"version\", USX_VERSION);\n usjToUsxDom(usj, usxDoc);\n }\n return usxDoc.toString();\n}\n\nexport function usjToUsxDom(usj: Usj, usxDoc: Document): Element | undefined {\n if (!usxDoc.documentElement) return undefined;\n\n for (const [index, markerContent] of usj.content.entries()) {\n const isLastItem = index === usj.content.length - 1;\n convertUsjRecurse(markerContent, usxDoc.documentElement, usxDoc, isLastItem);\n }\n return usxDoc.documentElement ?? undefined;\n}\n\nfunction convertUsjRecurse(\n markerContent: MarkerContent,\n parentElement: Element,\n usxDoc: Document,\n isLastItem: boolean,\n) {\n let element: Text | Element;\n let type: string | undefined;\n let eidElement: Element | undefined;\n if (typeof markerContent === \"string\") element = usxDoc.createTextNode(markerContent);\n else {\n type = markerContent.type.replace(\"table:\", \"\");\n element = usxDoc.createElement(type);\n setAttributes(element, markerContent);\n if (markerContent.content) {\n for (const [index, item] of markerContent.content.entries()) {\n const _isLastItem = index === markerContent.content.length - 1;\n convertUsjRecurse(item, element, usxDoc, _isLastItem);\n }\n }\n }\n\n // Create chapter and verse end elements from SID attributes.\n if (verseEid && (type === \"verse\" || (parentElement.tagName === \"para\" && isLastItem))) {\n eidElement = createVerseEndElement(usxDoc, verseEid);\n verseEid = undefined;\n }\n if (type === \"verse\" && typeof markerContent !== \"string\" && markerContent.sid !== undefined)\n verseEid = markerContent.sid;\n\n if (chapterEid && (type === \"chapter\" || (type === \"para\" && isLastItem))) {\n eidElement = createChapterEndElement(usxDoc, chapterEid);\n chapterEid = undefined;\n }\n if (type === \"chapter\" && typeof markerContent !== \"string\" && markerContent.sid !== undefined)\n chapterEid = markerContent.sid;\n\n // Append to parent.\n const isVerseInImpliedPara =\n parentElement.nodeName === USX_TYPE && eidElement?.tagName === \"verse\";\n if (eidElement && (!isLastItem || isVerseInImpliedPara)) parentElement.appendChild(eidElement);\n parentElement.appendChild(element);\n if (eidElement && isLastItem && !isVerseInImpliedPara) parentElement.appendChild(eidElement);\n\n // Allow for final chapter and verse end elements at the end of an implied para.\n if (isLastItem && parentElement.nodeName === USX_TYPE) {\n if (verseEid) parentElement.appendChild(createVerseEndElement(usxDoc, verseEid));\n if (chapterEid) parentElement.appendChild(createChapterEndElement(usxDoc, chapterEid));\n verseEid = undefined;\n chapterEid = undefined;\n }\n}\n\nfunction setAttributes(element: Element, markerContent: MarkerObject) {\n if (markerContent.marker) {\n if (markerContent.type === \"unmatched\") element.setAttribute(\"marker\", markerContent.marker);\n else element.setAttribute(\"style\", markerContent.marker);\n }\n for (const [key, value] of Object.entries(markerContent)) {\n if (value && ![\"type\", \"marker\", \"content\"].includes(key)) {\n element.setAttribute(key, value as string);\n }\n }\n}\n\nfunction createVerseEndElement(usxDoc: Document, verseEid: string): Element {\n const eidElement = usxDoc.createElement(\"verse\");\n eidElement.setAttribute(\"eid\", verseEid);\n return eidElement;\n}\n\nfunction createChapterEndElement(usxDoc: Document, chapterEid: string): Element {\n const eidElement = usxDoc.createElement(\"chapter\");\n eidElement.setAttribute(\"eid\", chapterEid);\n return eidElement;\n}\n","const JSON_PATH_START = \"$\";\nconst JSON_PATH_CONTENT = \".content[\";\n\n/**\n * Converts a USJ JSONPath string into an array of indexes.\n *\n * @param jsonPath - The USJ JSONPath string to convert. It must start with `$` and contain `.content[index]` segments.\n * @returns An array of numeric indexes extracted from the JSONPath.\n * @throws Will throw an error if the JSONPath does not start with `$`.\n *\n * @public\n */\nexport function indexesFromUsjJsonPath(jsonPath: string): number[] {\n const path = jsonPath.split(JSON_PATH_CONTENT);\n if (path.shift() !== JSON_PATH_START)\n throw new Error(`indexesFromJsonPath: jsonPath didn't start with '${JSON_PATH_START}'`);\n\n const indexes = path.map((str) => parseInt(str, 10));\n return indexes;\n}\n\n/**\n * Converts an array of indexes into a USJ JSONPath string.\n *\n * @param indexes - An array of numeric indexes to convert.\n * @returns A USJ JSONPath string constructed from the indexes.\n *\n * @public\n */\nexport function usjJsonPathFromIndexes(indexes: number[]): string {\n return indexes.reduce((path, index) => `${path}${JSON_PATH_CONTENT}${index}]`, JSON_PATH_START);\n}\n"],"names":["UNSAFE_KEYS","assertSafeKey","key","USJ_TYPE","USJ_VERSION","EMPTY_USJ","MARKER_OBJECT_PROPS","isValidBookCode","code","VALID_BOOK_CODES","USX_TYPE","USX_VERSION","EMPTY_USX","usxStringToUsj","usxString","inputUsxDom","DOMParser","usxDomToUsj","outputJson","convertUsxRecurse","inputUsxElement","attribs","type","marker","text","action","attrib","outObj","asciiTrim","children","child","childDict","whatToDo","str","chapterEid","verseEid","usjToUsxString","usj","usxDoc","DOMImplementation","usjToUsxDom","index","markerContent","isLastItem","convertUsjRecurse","parentElement","element","eidElement","setAttributes","item","_isLastItem","createVerseEndElement","createChapterEndElement","isVerseInImpliedPara","value","JSON_PATH_START","JSON_PATH_CONTENT","indexesFromUsjJsonPath","jsonPath","path","usjJsonPathFromIndexes","indexes"],"mappings":";AAEA,MAAMA,IAAc,oBAAI,IAAI,CAAC,aAAa,aAAa,aAAa,CAAC;AAQ9D,SAASC,EAAcC,GAAmB;AAC/C,MAAKF,EAAY,IAAIE,CAAG;AAExB,UAAM,IAAI,MAAM,YAAYA,CAAG,gDAAgD;AACjF;ACJO,MAAMC,IAAW,OAMXC,IAAc,OAMdC,IAAY,OAAO,OAAY,EAAE,MAAMF,GAAU,SAASC,GAAa,SAAS,GAAC,CAAG,GAMpFE,IAA8C;AAAA,EACzD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AA8DO,SAASC,EAAgBC,GAAuB;AACrD,SAAOC,EAAiB,SAASD,CAAgB;AACnD;AAYO,MAAMC,IAAmB;AAAA;AAAA,EAE9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GCpOaC,IAAW,OAMXC,IAAc,OAMdC,IAAY,IAAIF,CAAQ,aAAaC,CAAW;ACEtD,SAASE,EAAeC,GAAwB;AAErD,QAAMC,IADS,IAAIC,EAAA,EACQ,gBAAgBF,GAAW,UAAU;AAChE,SAAOG,EAAYF,EAAY,eAAe;AAChD;AAEO,SAASE,EAAYF,GAAkC;AAC5D,QAAM,CAACG,CAAU,IAAIH,IACjBI,EAAkBJ,CAAW,IAC7B,CAAC,EAAE,SAAS,CAAA,GAA8B;AAC9C,SAAAG,EAAW,OAAOf,GAClBe,EAAW,UAAUd,GACdc;AACT;AAEA,SAASC,EACPC,GACiC;AACjC,QAAMC,IAAmB,CAAA;AACzB,MAAIC,IAAeF,EAAgB,SAC/BG,GACAC,GACAC,IAAiB;AAGrB,MADI,CAAC,OAAO,MAAM,EAAE,SAASH,CAAI,UAAU,WAAWA,IAClDF,EAAgB;AAClB,eAAWM,KAAU,MAAM,KAAKN,EAAgB,UAAU;AACxD,MAAAnB,EAAcyB,EAAO,IAAI,GACzBL,EAAQK,EAAO,IAAI,IAAIA,EAAO;AAIlC,EAAIL,EAAQ,UACVE,IAASF,EAAQ,OACjB,OAAOA,EAAQ,QAGbA,EAAQ,OAAK,OAAOA,EAAQ,KAG5BA,EAAQ,UAAQ,OAAOA,EAAQ;AAEnC,MAAIM,IAAY,EAAE,MAAAL,EAAA;AAClB,EAAIC,MAASI,EAAwB,SAASJ,IAC9CI,IAAS,EAAE,GAAGA,GAAQ,GAAGN,EAAA,GAGvBD,EAAgB,cAChBA,EAAgB,WAAW,aAAaA,EAAgB,WAAW,aACnEA,EAAgB,WAAW,aAC3BQ,EAAUR,EAAgB,WAAW,SAAS,MAAM,OAEpDI,IAAOJ,EAAgB,WAAW;AAGpC,QAAMS,IAAW,MAAM,KAAKT,EAAgB,UAAU;AACtD,EAAAO,EAAO,UAAU,CAAA,GAEbH,KACFG,EAAO,QAAQ,KAAKH,CAAI;AAG1B,aAAWM,KAASD,GAAU;AAE5B,QAAKC,EAAkB,YAAY;AACjC;AAGF,UAAM,CAACC,GAAWC,CAAQ,IAAIb,EAAgCW,CAAgB;AAE9E,YAAQE,GAAA;AAAA,MACN,KAAK;AACH,QAAAL,EAAO,QAAQ,KAAKI,CAAS;AAC7B;AAAA,MACF,KAAK;AACH,QAAAJ,EAAO,UAAUA,EAAO,QAAQ,OAAOI,CAAS;AAChD;AAAA,IAIA;AAIJ,IACED,EAAM,eACNA,EAAM,YAAY,aAAaA,EAAM,YAAY,aACjDA,EAAM,YAAY,cACjBF,EAAUE,EAAM,YAAY,SAAS,MAAM,MAAMA,EAAM,YAAY,cAAc,QAElFH,EAAO,QAAQ,KAAKG,EAAM,YAAY,SAAS;AAAA,EAEnD;AAIA,SAAIH,EAAO,QAAQ,WAAW,KAAKA,EAAO,SAASjB,KACjD,OAAOiB,EAAO,SAGZ,SAASA,KAAU,CAAC,SAAS,SAAS,EAAE,SAASL,CAAI,MACvDG,IAAS,WAGJ,CAACE,GAAQF,CAAM;AACxB;AAUA,SAASG,EAAUK,GAAqB;AACtC,SAAOA,EAAI,QAAQ,wCAAwC,EAAE;AAC/D;ACnIA,IAAIC,GACAC;AAUG,SAASC,EAAeC,GAAkB;AAC/C,QAAMC,IAAS,IAAIC,EAAA,EAAoB,eAAe,IAAI7B,CAAQ;AAClE,SAAI4B,EAAO,oBACTA,EAAO,gBAAgB,aAAa,WAAW3B,CAAW,GAC1D6B,EAAYH,GAAKC,CAAM,IAElBA,EAAO,SAAA;AAChB;AAEO,SAASE,EAAYH,GAAUC,GAAuC;AAC3E,MAAKA,EAAO,iBAEZ;AAAA,eAAW,CAACG,GAAOC,CAAa,KAAKL,EAAI,QAAQ,WAAW;AAC1D,YAAMM,IAAaF,MAAUJ,EAAI,QAAQ,SAAS;AAClD,MAAAO,EAAkBF,GAAeJ,EAAO,iBAAiBA,GAAQK,CAAU;AAAA,IAC7E;AACA,WAAOL,EAAO,mBAAmB;AAAA;AACnC;AAEA,SAASM,EACPF,GACAG,GACAP,GACAK,GACA;AACA,MAAIG,GACAxB,GACAyB;AACJ,MAAI,OAAOL,KAAkB,SAAU,CAAAI,IAAUR,EAAO,eAAeI,CAAa;AAAA,WAElFpB,IAAOoB,EAAc,KAAK,QAAQ,UAAU,EAAE,GAC9CI,IAAUR,EAAO,cAAchB,CAAI,GACnC0B,EAAcF,GAASJ,CAAa,GAChCA,EAAc;AAChB,eAAW,CAACD,GAAOQ,CAAI,KAAKP,EAAc,QAAQ,WAAW;AAC3D,YAAMQ,IAAcT,MAAUC,EAAc,QAAQ,SAAS;AAC7D,MAAAE,EAAkBK,GAAMH,GAASR,GAAQY,CAAW;AAAA,IACtD;AAKJ,EAAIf,MAAab,MAAS,WAAYuB,EAAc,YAAY,UAAUF,OACxEI,IAAaI,EAAsBb,GAAQH,CAAQ,GACnDA,IAAW,SAETb,MAAS,WAAW,OAAOoB,KAAkB,YAAYA,EAAc,QAAQ,WACjFP,IAAWO,EAAc,MAEvBR,MAAeZ,MAAS,aAAcA,MAAS,UAAUqB,OAC3DI,IAAaK,EAAwBd,GAAQJ,CAAU,GACvDA,IAAa,SAEXZ,MAAS,aAAa,OAAOoB,KAAkB,YAAYA,EAAc,QAAQ,WACnFR,IAAaQ,EAAc;AAG7B,QAAMW,IACJR,EAAc,aAAanC,MAAYqC,KAAA,gBAAAA,EAAY,aAAY;AACjE,EAAIA,MAAe,CAACJ,KAAcU,MAAuBR,EAAc,YAAYE,CAAU,GAC7FF,EAAc,YAAYC,CAAO,GAC7BC,KAAcJ,KAAc,CAACU,KAAsBR,EAAc,YAAYE,CAAU,GAGvFJ,KAAcE,EAAc,aAAanC,MACvCyB,KAAUU,EAAc,YAAYM,EAAsBb,GAAQH,CAAQ,CAAC,GAC3ED,KAAYW,EAAc,YAAYO,EAAwBd,GAAQJ,CAAU,CAAC,GACrFC,IAAW,QACXD,IAAa;AAEjB;AAEA,SAASc,EAAcF,GAAkBJ,GAA6B;AACpE,EAAIA,EAAc,WACZA,EAAc,SAAS,gBAAqB,aAAa,UAAUA,EAAc,MAAM,IACtFI,EAAQ,aAAa,SAASJ,EAAc,MAAM;AAEzD,aAAW,CAACxC,GAAKoD,CAAK,KAAK,OAAO,QAAQZ,CAAa;AACrD,IAAIY,KAAS,CAAC,CAAC,QAAQ,UAAU,SAAS,EAAE,SAASpD,CAAG,KACtD4C,EAAQ,aAAa5C,GAAKoD,CAAe;AAG/C;AAEA,SAASH,EAAsBb,GAAkBH,GAA2B;AAC1E,QAAMY,IAAaT,EAAO,cAAc,OAAO;AAC/C,SAAAS,EAAW,aAAa,OAAOZ,CAAQ,GAChCY;AACT;AAEA,SAASK,EAAwBd,GAAkBJ,GAA6B;AAC9E,QAAMa,IAAaT,EAAO,cAAc,SAAS;AACjD,SAAAS,EAAW,aAAa,OAAOb,CAAU,GAClCa;AACT;ACnHA,MAAMQ,IAAkB,KAClBC,IAAoB;AAWnB,SAASC,EAAuBC,GAA4B;AACjE,QAAMC,IAAOD,EAAS,MAAMF,CAAiB;AAC7C,MAAIG,EAAK,YAAYJ;AACnB,UAAM,IAAI,MAAM,oDAAoDA,CAAe,GAAG;AAGxF,SADgBI,EAAK,IAAI,CAAC1B,MAAQ,SAASA,GAAK,EAAE,CAAC;AAErD;AAUO,SAAS2B,EAAuBC,GAA2B;AAChE,SAAOA,EAAQ,OAAO,CAACF,GAAMlB,MAAU,GAAGkB,CAAI,GAAGH,CAAiB,GAAGf,CAAK,KAAKc,CAAe;AAChG;"}
1
+ {"version":3,"file":"index.js","sources":["../src/converters/usj/converter.utils.ts","../src/converters/usj/jsonpath-indexes.ts","../src/converters/usj/usj-document-location.utils.ts","../src/converters/usj/usx.model.ts","../src/converters/usj/usj-to-usx.ts","../src/converters/usj/usj.model.ts","../src/converters/usj/usx-to-usj.ts"],"sourcesContent":["/* Utility functions for converters */\n\nconst UNSAFE_KEYS = new Set([\"__proto__\", \"prototype\", \"constructor\"]);\n\n/**\n * Avoid prototype pollution by disallowing unsafe keys.\n * @param key - The array key to validate.\n *\n * @public\n */\nexport function assertSafeKey(key: string): void {\n if (!UNSAFE_KEYS.has(key)) return;\n\n throw new Error(`The key \"${key}\" is not allowed to avoid prototype pollution.`);\n}\n","import type { ContentJsonPath } from \"./usj-document-location.model.js\";\n\nconst JSON_PATH_START = \"$\";\nconst JSON_PATH_CONTENT = \".content[\";\n\n/**\n * Converts a USJ JSONPath string into an array of indexes.\n *\n * @param jsonPath - The USJ JSONPath string to convert. It must start with `$` and contain `.content[index]` segments.\n * @returns An array of numeric indexes extracted from the JSONPath.\n * @throws Will throw an error if the JSONPath does not start with `$`.\n *\n * @public\n */\nexport function indexesFromUsjJsonPath(jsonPath: string): number[] {\n const path = jsonPath.split(JSON_PATH_CONTENT);\n if (path.shift() !== JSON_PATH_START)\n throw new Error(`indexesFromJsonPath: jsonPath didn't start with '${JSON_PATH_START}'`);\n\n const indexes = path.map((str) => parseInt(str, 10));\n return indexes;\n}\n\n/**\n * Converts an array of indexes into a USJ JSONPath string.\n *\n * @param indexes - An array of numeric indexes to convert.\n * @returns A USJ JSONPath string constructed from the indexes.\n *\n * @public\n */\nexport function usjJsonPathFromIndexes(indexes: number[]): ContentJsonPath {\n return indexes.reduce<string>(\n (path, index) => `${path}${JSON_PATH_CONTENT}${index}]`,\n JSON_PATH_START,\n ) as ContentJsonPath;\n}\n","/**\n * Type guards for {@link UsjDocumentLocation} subtypes.\n *\n * These guards enable runtime type narrowing to distinguish between the different\n * location types in a USJ document.\n */\n\nimport type {\n UsjDocumentLocation,\n UsjMarkerLocation,\n UsjClosingMarkerLocation,\n UsjTextContentLocation,\n UsjPropertyValueLocation,\n UsjAttributeKeyLocation,\n UsjAttributeMarkerLocation,\n UsjClosingAttributeMarkerLocation,\n} from \"./usj-document-location.model.js\";\n\n/**\n * Type guard to check if a location is a {@link UsjMarkerLocation}.\n *\n * A marker location points to the very beginning of a marker (at the backslash in USFM).\n * It only has a `jsonPath` property with no offset properties.\n *\n * @param location - The location to check.\n * @returns `true` if the location is a `UsjMarkerLocation`, `false` otherwise.\n *\n * @public\n */\nexport function isUsjMarkerLocation(\n location: UsjDocumentLocation | undefined | null,\n): location is UsjMarkerLocation {\n return (\n location != null &&\n \"jsonPath\" in location &&\n !(\"offset\" in location) &&\n !(\"closingMarkerOffset\" in location) &&\n !(\"propertyOffset\" in location) &&\n !(\"keyName\" in location)\n );\n}\n\n/**\n * Type guard to check if a location is a {@link UsjClosingMarkerLocation}.\n *\n * A closing marker location points to a specific point in the closing marker representation\n * of a marker object (e.g., `\\nd*` in USFM).\n *\n * @param location - The location to check.\n * @returns `true` if the location is a `UsjClosingMarkerLocation`, `false` otherwise.\n *\n * @public\n */\nexport function isUsjClosingMarkerLocation(\n location: UsjDocumentLocation | undefined | null,\n): location is UsjClosingMarkerLocation {\n return location != null && \"jsonPath\" in location && \"closingMarkerOffset\" in location;\n}\n\n/**\n * Type guard to check if a location is a {@link UsjTextContentLocation}.\n *\n * A text content location points to a specific character offset within a text content string\n * in a marker's content array.\n *\n * @param location - The location to check.\n * @returns `true` if the location is a `UsjTextContentLocation`, `false` otherwise.\n *\n * @public\n */\nexport function isUsjTextContentLocation(\n location: UsjDocumentLocation | undefined | null,\n): location is UsjTextContentLocation {\n return (\n location != null &&\n \"jsonPath\" in location &&\n \"offset\" in location &&\n !(\"propertyOffset\" in location) &&\n !(\"keyName\" in location)\n );\n}\n\n/**\n * Type guard to check if a location is a {@link UsjPropertyValueLocation}.\n *\n * A property value location points to a specific character offset within a property value\n * (such as `marker` or an attribute value).\n *\n * @param location - The location to check.\n * @returns `true` if the location is a `UsjPropertyValueLocation`, `false` otherwise.\n *\n * @public\n */\nexport function isUsjPropertyValueLocation(\n location: UsjDocumentLocation | undefined | null,\n): location is UsjPropertyValueLocation {\n return location != null && \"jsonPath\" in location && \"propertyOffset\" in location;\n}\n\n/**\n * Type guard to check if a location is a {@link UsjAttributeKeyLocation}.\n *\n * An attribute key location points to a specific character offset within an attribute's key string.\n *\n * @param location - The location to check.\n * @returns `true` if the location is a `UsjAttributeKeyLocation`, `false` otherwise.\n *\n * @public\n */\nexport function isUsjAttributeKeyLocation(\n location: UsjDocumentLocation | undefined | null,\n): location is UsjAttributeKeyLocation {\n return (\n location != null && \"jsonPath\" in location && \"keyName\" in location && \"keyOffset\" in location\n );\n}\n\n/**\n * Type guard to check if a location is a {@link UsjAttributeMarkerLocation}.\n *\n * An attribute marker location points to the beginning of an attribute marker\n * (at the backslash in USFM, e.g., `\\ca` for chapter alternate number).\n *\n * @param location - The location to check.\n * @returns `true` if the location is a `UsjAttributeMarkerLocation`, `false` otherwise.\n *\n * @public\n */\nexport function isUsjAttributeMarkerLocation(\n location: UsjDocumentLocation | undefined | null,\n): location is UsjAttributeMarkerLocation {\n return (\n location != null &&\n \"jsonPath\" in location &&\n \"keyName\" in location &&\n !(\"keyOffset\" in location) &&\n !(\"keyClosingMarkerOffset\" in location)\n );\n}\n\n/**\n * Type guard to check if a location is a {@link UsjClosingAttributeMarkerLocation}.\n *\n * A closing attribute marker location points to a specific point in the closing marker\n * representation of an attribute marker (e.g., `\\ca*` in USFM).\n *\n * @param location - The location to check.\n * @returns `true` if the location is a `UsjClosingAttributeMarkerLocation`, `false` otherwise.\n *\n * @public\n */\nexport function isUsjClosingAttributeMarkerLocation(\n location: UsjDocumentLocation | undefined | null,\n): location is UsjClosingAttributeMarkerLocation {\n return (\n location != null &&\n \"jsonPath\" in location &&\n \"keyName\" in location &&\n \"keyClosingMarkerOffset\" in location\n );\n}\n\n/**\n * Gets a human-readable name for the type of a {@link UsjDocumentLocation}.\n *\n * Useful for error messages when an unsupported location type is encountered.\n *\n * @param location - The location to get the type name for.\n * @returns A string describing the location type, or \"undefined\" / \"null\" if the location is not\n * provided.\n *\n * @public\n */\nexport function getUsjDocumentLocationTypeName(\n location: UsjDocumentLocation | undefined | null,\n): string {\n if (location === undefined) return \"undefined\";\n if (location === null) return \"null\";\n if (isUsjClosingAttributeMarkerLocation(location)) return \"UsjClosingAttributeMarkerLocation\";\n if (isUsjAttributeKeyLocation(location)) return \"UsjAttributeKeyLocation\";\n if (isUsjAttributeMarkerLocation(location)) return \"UsjAttributeMarkerLocation\";\n if (isUsjPropertyValueLocation(location)) return \"UsjPropertyValueLocation\";\n if (isUsjClosingMarkerLocation(location)) return \"UsjClosingMarkerLocation\";\n if (isUsjTextContentLocation(location)) return \"UsjTextContentLocation\";\n if (isUsjMarkerLocation(location)) return \"UsjMarkerLocation\";\n return \"Unknown\";\n}\n","/**\n * Unified Scripture XML (USX).\n * These types follow this schema:\n * @see https://github.com/usfm-bible/tcdocs/blob/main/grammar/usx.rng\n */\n\n/**\n * The USX spec type\n * @public\n */\nexport const USX_TYPE = \"usx\";\n\n/**\n * The USX spec version\n * @public\n */\nexport const USX_VERSION = \"3.1\";\n\n/**\n * An empty USX string\n * @public\n */\nexport const EMPTY_USX = `<${USX_TYPE} version=\"${USX_VERSION}\" />`;\n","/**\n * Convert Scripture from USJ to USX.\n * Adapted to TypeScript from this file:\n * @see https://github.com/usfm-bible/usfmtc/blob/0afa385a1f282b286cc6bff7bbc953ae788aa10c/src/usfmtc/usjproc.py\n */\n\nimport { DOMImplementation, Document, Element, Text } from \"@xmldom/xmldom\";\nimport { MarkerContent, MarkerObject, Usj } from \"./usj.model.js\";\nimport { USX_TYPE, USX_VERSION } from \"./usx.model.js\";\n\nlet chapterEid: string | undefined;\nlet verseEid: string | undefined;\n\n/**\n * Converts a USJ object to a USX string.\n *\n * @param usj - The USJ object to convert\n * @returns The converted USX string.\n *\n * @public\n */\nexport function usjToUsxString(usj: Usj): string {\n const usxDoc = new DOMImplementation().createDocument(\"\", USX_TYPE);\n if (usxDoc.documentElement) {\n usxDoc.documentElement.setAttribute(\"version\", USX_VERSION);\n usjToUsxDom(usj, usxDoc);\n }\n return usxDoc.toString();\n}\n\nexport function usjToUsxDom(usj: Usj, usxDoc: Document): Element | undefined {\n if (!usxDoc.documentElement) return undefined;\n\n for (const [index, markerContent] of usj.content.entries()) {\n const isLastItem = index === usj.content.length - 1;\n convertUsjRecurse(markerContent, usxDoc.documentElement, usxDoc, isLastItem);\n }\n return usxDoc.documentElement ?? undefined;\n}\n\nfunction convertUsjRecurse(\n markerContent: MarkerContent,\n parentElement: Element,\n usxDoc: Document,\n isLastItem: boolean,\n) {\n let element: Text | Element;\n let type: string | undefined;\n let eidElement: Element | undefined;\n if (typeof markerContent === \"string\") element = usxDoc.createTextNode(markerContent);\n else {\n type = markerContent.type.replace(\"table:\", \"\");\n element = usxDoc.createElement(type);\n setAttributes(element, markerContent);\n if (markerContent.content) {\n for (const [index, item] of markerContent.content.entries()) {\n const _isLastItem = index === markerContent.content.length - 1;\n convertUsjRecurse(item, element, usxDoc, _isLastItem);\n }\n }\n }\n\n // Create chapter and verse end elements from SID attributes.\n if (verseEid && (type === \"verse\" || (parentElement.tagName === \"para\" && isLastItem))) {\n eidElement = createVerseEndElement(usxDoc, verseEid);\n verseEid = undefined;\n }\n if (type === \"verse\" && typeof markerContent !== \"string\" && markerContent.sid !== undefined)\n verseEid = markerContent.sid;\n\n if (chapterEid && (type === \"chapter\" || (type === \"para\" && isLastItem))) {\n eidElement = createChapterEndElement(usxDoc, chapterEid);\n chapterEid = undefined;\n }\n if (type === \"chapter\" && typeof markerContent !== \"string\" && markerContent.sid !== undefined)\n chapterEid = markerContent.sid;\n\n // Append to parent.\n const isVerseInImpliedPara =\n parentElement.nodeName === USX_TYPE && eidElement?.tagName === \"verse\";\n if (eidElement && (!isLastItem || isVerseInImpliedPara)) parentElement.appendChild(eidElement);\n parentElement.appendChild(element);\n if (eidElement && isLastItem && !isVerseInImpliedPara) parentElement.appendChild(eidElement);\n\n // Allow for final chapter and verse end elements at the end of an implied para.\n if (isLastItem && parentElement.nodeName === USX_TYPE) {\n if (verseEid) parentElement.appendChild(createVerseEndElement(usxDoc, verseEid));\n if (chapterEid) parentElement.appendChild(createChapterEndElement(usxDoc, chapterEid));\n verseEid = undefined;\n chapterEid = undefined;\n }\n}\n\nfunction setAttributes(element: Element, markerContent: MarkerObject) {\n if (markerContent.marker) {\n if (markerContent.type === \"unmatched\") element.setAttribute(\"marker\", markerContent.marker);\n else element.setAttribute(\"style\", markerContent.marker);\n }\n for (const [key, value] of Object.entries(markerContent)) {\n if (value && ![\"type\", \"marker\", \"content\"].includes(key)) {\n element.setAttribute(key, value as string);\n }\n }\n}\n\nfunction createVerseEndElement(usxDoc: Document, verseEid: string): Element {\n const eidElement = usxDoc.createElement(\"verse\");\n eidElement.setAttribute(\"eid\", verseEid);\n return eidElement;\n}\n\nfunction createChapterEndElement(usxDoc: Document, chapterEid: string): Element {\n const eidElement = usxDoc.createElement(\"chapter\");\n eidElement.setAttribute(\"eid\", chapterEid);\n return eidElement;\n}\n","/**\n * Unified Scripture JSON (USJ) - The JSON variant of USFM and USX data models.\n * These types follow this schema:\n * @see https://github.com/usfm-bible/tcdocs/blob/usj/grammar/usj.js\n */\n\n/**\n * The USJ spec type\n * @public\n */\nexport const USJ_TYPE = \"USJ\";\n\n/**\n * The USJ spec version\n * @public\n */\nexport const USJ_VERSION = \"3.1\";\n\n/**\n * An empty USJ object\n * @public\n */\nexport const EMPTY_USJ = Object.freeze<Usj>({ type: USJ_TYPE, version: USJ_VERSION, content: [] });\n\n/**\n * List of known properties of `MarkerObject`\n * @public\n */\nexport const MARKER_OBJECT_PROPS: (keyof MarkerObject)[] = [\n \"type\",\n \"marker\",\n \"content\",\n \"sid\",\n \"eid\",\n \"number\",\n \"code\",\n \"altnumber\",\n \"pubnumber\",\n \"caller\",\n \"align\",\n \"category\",\n];\n\n/**\n * Single piece of Scripture content\n * @public\n */\nexport type MarkerContent = string | MarkerObject;\n\n/**\n * A Scripture Marker and its contents\n * @public\n */\nexport interface MarkerObject {\n /**\n * The kind/category of node or element this is, corresponding the USFM marker and USX node\n * @example `para`, `verse`, `char`\n */\n type: string;\n /**\n * The corresponding marker in USFM or style in USX\n * @example `p`, `v`, `nd`\n */\n marker?: string;\n /** This marker's contents laid out in order */\n content?: MarkerContent[];\n /** Indicates the Book-chapter-verse value in the paragraph based structure */\n sid?: string;\n /** Milestone end ID, matches start ID (not currently included in USJ spec) */\n eid?: string;\n /** Chapter number or verse number */\n number?: string;\n /** The 3-letter book code in ID element */\n code?: BookCode;\n /** Alternate chapter number or verse number */\n altnumber?: string;\n /** Published character of chapter or verse */\n pubnumber?: string;\n /** Caller character for footnotes and cross-refs */\n caller?: string;\n /** Alignment of table cells */\n align?: string;\n /** Category of extended study bible sections */\n category?: string;\n}\n\n/**\n * Scripture data represented in JSON format. Data compatible transformation from USX/USFM\n * @public\n */\nexport interface Usj {\n /** The USJ spec type */\n type: typeof USJ_TYPE;\n /** The USJ spec version */\n version: typeof USJ_VERSION;\n /** The JSON representation of scripture contents from USFM/USX */\n content: MarkerContent[];\n}\n\n/**\n * Check if the given code is a valid 3-letter Scripture book code.\n * @public\n */\nexport function isValidBookCode(code: string): boolean {\n return VALID_BOOK_CODES.includes(code as BookCode);\n}\n\n/**\n * 3-letter Scripture book code\n * @public\n */\nexport type BookCode = (typeof VALID_BOOK_CODES)[number];\n\n/**\n * List of valid 3-letter Scripture book codes\n * @public\n */\nexport const VALID_BOOK_CODES = [\n // Old Testament\n \"GEN\",\n \"EXO\",\n \"LEV\",\n \"NUM\",\n \"DEU\",\n \"JOS\",\n \"JDG\",\n \"RUT\",\n \"1SA\",\n \"2SA\",\n \"1KI\",\n \"2KI\",\n \"1CH\",\n \"2CH\",\n \"EZR\",\n \"NEH\",\n \"EST\",\n \"JOB\",\n \"PSA\",\n \"PRO\",\n \"ECC\",\n \"SNG\",\n \"ISA\",\n \"JER\",\n \"LAM\",\n \"EZK\",\n \"DAN\",\n \"HOS\",\n \"JOL\",\n \"AMO\",\n \"OBA\",\n \"JON\",\n \"MIC\",\n \"NAM\",\n \"HAB\",\n \"ZEP\",\n \"HAG\",\n \"ZEC\",\n \"MAL\",\n // New Testament\n \"MAT\",\n \"MRK\",\n \"LUK\",\n \"JHN\",\n \"ACT\",\n \"ROM\",\n \"1CO\",\n \"2CO\",\n \"GAL\",\n \"EPH\",\n \"PHP\",\n \"COL\",\n \"1TH\",\n \"2TH\",\n \"1TI\",\n \"2TI\",\n \"TIT\",\n \"PHM\",\n \"HEB\",\n \"JAS\",\n \"1PE\",\n \"2PE\",\n \"1JN\",\n \"2JN\",\n \"3JN\",\n \"JUD\",\n \"REV\",\n // Deuterocanon\n \"TOB\",\n \"JDT\",\n \"ESG\",\n \"WIS\",\n \"SIR\",\n \"BAR\",\n \"LJE\",\n \"S3Y\",\n \"SUS\",\n \"BEL\",\n \"1MA\",\n \"2MA\",\n \"3MA\",\n \"4MA\",\n \"1ES\",\n \"2ES\",\n \"MAN\",\n \"PS2\",\n \"ODA\",\n \"PSS\",\n \"EZA\",\n \"5EZ\",\n \"6EZ\",\n \"DAG\",\n \"PS3\",\n \"2BA\",\n \"LBA\",\n \"JUB\",\n \"ENO\",\n \"1MQ\",\n \"2MQ\",\n \"3MQ\",\n \"REP\",\n \"4BA\",\n \"LAO\",\n // Non scripture\n \"FRT\",\n \"BAK\",\n \"OTH\",\n \"INT\",\n \"CNC\",\n \"GLO\",\n \"TDX\",\n \"NDX\",\n \"XXA\",\n \"XXB\",\n \"XXC\",\n \"XXD\",\n \"XXE\",\n \"XXF\",\n \"XXG\",\n] as const;\n","/**\n * Convert Scripture from USX to USJ.\n * Adapted to TypeScript from this file:\n * @see https://github.com/usfm-bible/usfmtc/blob/0afa385a1f282b286cc6bff7bbc953ae788aa10c/src/usfmtc/usjproc.py\n */\n\nimport { DOMParser, Element } from \"@xmldom/xmldom\";\nimport { MarkerContent, MarkerObject, USJ_TYPE, USJ_VERSION, Usj } from \"./usj.model.js\";\nimport { USX_TYPE } from \"./usx.model.js\";\nimport { assertSafeKey } from \"./converter.utils.js\";\n\ntype Action = \"append\" | \"merge\" | \"ignore\";\ninterface Attribs {\n [name: string]: string;\n}\n\n/**\n * Converts a USX string to a USJ object.\n *\n * @param usxString - The USX string to convert.\n * @returns The converted USJ object.\n *\n * @public\n */\nexport function usxStringToUsj(usxString: string): Usj {\n const parser = new DOMParser();\n const inputUsxDom = parser.parseFromString(usxString, \"text/xml\");\n return usxDomToUsj(inputUsxDom.documentElement);\n}\n\nexport function usxDomToUsj(inputUsxDom: Element | null): Usj {\n const [outputJson] = inputUsxDom\n ? convertUsxRecurse(inputUsxDom)\n : [{ content: [] as MarkerContent[] } as Usj];\n outputJson.type = USJ_TYPE;\n outputJson.version = USJ_VERSION;\n return outputJson;\n}\n\nfunction convertUsxRecurse<T extends Usj | MarkerObject = Usj>(\n inputUsxElement: Element,\n): [outputJson: T, action: Action] {\n const attribs: Attribs = {};\n let type: string = inputUsxElement.tagName;\n let marker: string | undefined;\n let text: string | undefined;\n let action: Action = \"append\";\n\n if ([\"row\", \"cell\"].includes(type)) type = \"table:\" + type;\n if (inputUsxElement.attributes) {\n for (const attrib of Array.from(inputUsxElement.attributes)) {\n assertSafeKey(attrib.name);\n attribs[attrib.name] = attrib.value;\n }\n }\n\n if (attribs.style) {\n marker = attribs.style;\n delete attribs.style;\n }\n // dropping because presence of vid in para elements is not consistent in USX\n if (attribs.vid) delete attribs.vid;\n // Not dropping `attribs.closed` for backwards compatibility.\n // dropping because it is nonstandard derived metadata that could get out of date\n if (attribs.status) delete attribs.status;\n\n let outObj: T = { type } as T;\n if (marker) (outObj as MarkerObject).marker = marker;\n outObj = { ...outObj, ...attribs };\n\n if (\n inputUsxElement.firstChild &&\n inputUsxElement.firstChild.nodeType === inputUsxElement.firstChild.TEXT_NODE &&\n inputUsxElement.firstChild.nodeValue &&\n asciiTrim(inputUsxElement.firstChild.nodeValue) !== \"\"\n ) {\n text = inputUsxElement.firstChild.nodeValue;\n }\n\n const children = Array.from(inputUsxElement.childNodes);\n outObj.content = [];\n\n if (text) {\n outObj.content.push(text);\n }\n\n for (const child of children) {\n // ChildNodes are Elements.\n if ((child as Element).tagName === undefined) {\n continue;\n }\n // ChildNodes are Elements.\n const [childDict, whatToDo] = convertUsxRecurse<MarkerObject>(child as Element);\n\n switch (whatToDo) {\n case \"append\":\n outObj.content.push(childDict);\n break;\n case \"merge\":\n outObj.content = outObj.content.concat(childDict);\n break;\n case \"ignore\":\n break;\n default:\n break;\n }\n\n // Handle tail text\n if (\n child.nextSibling &&\n child.nextSibling.nodeType === child.nextSibling.TEXT_NODE &&\n child.nextSibling.nodeValue &&\n (asciiTrim(child.nextSibling.nodeValue) !== \"\" || child.nextSibling.nodeValue === \" \")\n ) {\n outObj.content.push(child.nextSibling.nodeValue);\n }\n }\n\n // For backward compatibility, not deleting content for type: chapter, verse, optbreak, ms OR\n // marker: va, ca, b.\n if (outObj.content.length === 0 && outObj.type !== USX_TYPE) {\n delete outObj.content;\n }\n\n if (\"eid\" in outObj && [\"verse\", \"chapter\"].includes(type)) {\n action = \"ignore\";\n }\n\n return [outObj, action];\n}\n\n/**\n * Removes leading and trailing ASCII whitespace.\n *\n * Only trim ASCII whitespace characters: space, tab, line feed, carriage return, form feed,\n * vertical tab.\n * @param str - The string to remove whitespace from.\n * @returns the string with leading and trailing whitespace removed.\n */\nfunction asciiTrim(str: string): string {\n return str.replace(/(^[ \\t\\n\\r\\f\\v]+)|([ \\t\\n\\r\\f\\v]+$)/g, \"\");\n}\n"],"names":["UNSAFE_KEYS","assertSafeKey","key","JSON_PATH_START","JSON_PATH_CONTENT","indexesFromUsjJsonPath","jsonPath","path","str","usjJsonPathFromIndexes","indexes","index","isUsjMarkerLocation","location","isUsjClosingMarkerLocation","isUsjTextContentLocation","isUsjPropertyValueLocation","isUsjAttributeKeyLocation","isUsjAttributeMarkerLocation","isUsjClosingAttributeMarkerLocation","getUsjDocumentLocationTypeName","USX_TYPE","USX_VERSION","EMPTY_USX","chapterEid","verseEid","usjToUsxString","usj","usxDoc","DOMImplementation","usjToUsxDom","markerContent","isLastItem","convertUsjRecurse","parentElement","element","type","eidElement","setAttributes","item","_isLastItem","createVerseEndElement","createChapterEndElement","isVerseInImpliedPara","value","USJ_TYPE","USJ_VERSION","EMPTY_USJ","MARKER_OBJECT_PROPS","isValidBookCode","code","VALID_BOOK_CODES","usxStringToUsj","usxString","inputUsxDom","DOMParser","usxDomToUsj","outputJson","convertUsxRecurse","inputUsxElement","attribs","marker","text","action","attrib","outObj","asciiTrim","children","child","childDict","whatToDo"],"mappings":"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AOC,EAAiB,SAASD,CAAgB;AACnD;AAYO,MAAMC,IAAmB;AAAA;AAAA,EAE9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;ACtNO,SAASC,EAAeC,GAAwB;AAErD,QAAMC,IADS,IAAIC,EAAA,EACQ,gBAAgBF,GAAW,UAAU;AAChE,SAAOG,EAAYF,EAAY,eAAe;AAChD;AAEO,SAASE,EAAYF,GAAkC;AAC5D,QAAM,CAACG,CAAU,IAAIH,IACjBI,EAAkBJ,CAAW,IAC7B,CAAC,EAAE,SAAS,CAAA,GAA8B;AAC9C,SAAAG,EAAW,OAAOZ,GAClBY,EAAW,UAAUX,GACdW;AACT;AAEA,SAASC,EACPC,GACiC;AACjC,QAAMC,IAAmB,CAAA;AACzB,MAAIxB,IAAeuB,EAAgB,SAC/BE,GACAC,GACAC,IAAiB;AAGrB,MADI,CAAC,OAAO,MAAM,EAAE,SAAS3B,CAAI,UAAU,WAAWA,IAClDuB,EAAgB;AAClB,eAAWK,KAAU,MAAM,KAAKL,EAAgB,UAAU;AACxD,MAAA1D,EAAc+D,EAAO,IAAI,GACzBJ,EAAQI,EAAO,IAAI,IAAIA,EAAO;AAIlC,EAAIJ,EAAQ,UACVC,IAASD,EAAQ,OACjB,OAAOA,EAAQ,QAGbA,EAAQ,OAAK,OAAOA,EAAQ,KAG5BA,EAAQ,UAAQ,OAAOA,EAAQ;AAEnC,MAAIK,IAAY,EAAE,MAAA7B,EAAA;AAClB,EAAIyB,MAASI,EAAwB,SAASJ,IAC9CI,IAAS,EAAE,GAAGA,GAAQ,GAAGL,EAAA,GAGvBD,EAAgB,cAChBA,EAAgB,WAAW,aAAaA,EAAgB,WAAW,aACnEA,EAAgB,WAAW,aAC3BO,EAAUP,EAAgB,WAAW,SAAS,MAAM,OAEpDG,IAAOH,EAAgB,WAAW;AAGpC,QAAMQ,IAAW,MAAM,KAAKR,EAAgB,UAAU;AACtD,EAAAM,EAAO,UAAU,CAAA,GAEbH,KACFG,EAAO,QAAQ,KAAKH,CAAI;AAG1B,aAAWM,KAASD,GAAU;AAE5B,QAAKC,EAAkB,YAAY;AACjC;AAGF,UAAM,CAACC,GAAWC,CAAQ,IAAIZ,EAAgCU,CAAgB;AAE9E,YAAQE,GAAA;AAAA,MACN,KAAK;AACH,QAAAL,EAAO,QAAQ,KAAKI,CAAS;AAC7B;AAAA,MACF,KAAK;AACH,QAAAJ,EAAO,UAAUA,EAAO,QAAQ,OAAOI,CAAS;AAChD;AAAA,IAIA;AAIJ,IACED,EAAM,eACNA,EAAM,YAAY,aAAaA,EAAM,YAAY,aACjDA,EAAM,YAAY,cACjBF,EAAUE,EAAM,YAAY,SAAS,MAAM,MAAMA,EAAM,YAAY,cAAc,QAElFH,EAAO,QAAQ,KAAKG,EAAM,YAAY,SAAS;AAAA,EAEnD;AAIA,SAAIH,EAAO,QAAQ,WAAW,KAAKA,EAAO,SAAS5C,KACjD,OAAO4C,EAAO,SAGZ,SAASA,KAAU,CAAC,SAAS,SAAS,EAAE,SAAS7B,CAAI,MACvD2B,IAAS,WAGJ,CAACE,GAAQF,CAAM;AACxB;AAUA,SAASG,EAAU1D,GAAqB;AACtC,SAAOA,EAAI,QAAQ,wCAAwC,EAAE;AAC/D;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eten-tech-foundation/scripture-utilities",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Utilities for working with Scripture data.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/eten-tech-foundation/scripture-editors/tree/main/packages/utilities#readme",
@@ -1,3 +1,5 @@
1
+ import type { ContentJsonPath } from "./usj-document-location.model.js";
2
+
1
3
  const JSON_PATH_START = "$";
2
4
  const JSON_PATH_CONTENT = ".content[";
3
5
 
@@ -27,6 +29,9 @@ export function indexesFromUsjJsonPath(jsonPath: string): number[] {
27
29
  *
28
30
  * @public
29
31
  */
30
- export function usjJsonPathFromIndexes(indexes: number[]): string {
31
- return indexes.reduce((path, index) => `${path}${JSON_PATH_CONTENT}${index}]`, JSON_PATH_START);
32
+ export function usjJsonPathFromIndexes(indexes: number[]): ContentJsonPath {
33
+ return indexes.reduce<string>(
34
+ (path, index) => `${path}${JSON_PATH_CONTENT}${index}]`,
35
+ JSON_PATH_START,
36
+ ) as ContentJsonPath;
32
37
  }