node-sword-interface 1.0.112 → 1.0.113

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/API.md CHANGED
@@ -49,6 +49,7 @@ This is the main class of node-sword-interface and it provides a set of static f
49
49
  * [.refreshLocalModules()](#NodeSwordInterface+refreshLocalModules)
50
50
  * [.saveModuleUnlockKey(moduleCode, key)](#NodeSwordInterface+saveModuleUnlockKey)
51
51
  * [.isModuleReadable(moduleCode)](#NodeSwordInterface+isModuleReadable) ⇒ <code>Boolean</code>
52
+ * [.mapVerseReference(sourceOsisRef, sourceModuleName, targetModuleName, [allowRange])](#NodeSwordInterface+mapVerseReference) ⇒ <code>String</code>
52
53
  * [.getModuleDescription(repositoryName, moduleCode)](#NodeSwordInterface+getModuleDescription) ⇒ <code>String</code>
53
54
  * [.enableMarkup()](#NodeSwordInterface+enableMarkup)
54
55
  * [.disableMarkup()](#NodeSwordInterface+disableMarkup)
@@ -311,6 +312,21 @@ Checks whether the module is readable.
311
312
  | --- | --- | --- |
312
313
  | moduleCode | <code>String</code> | The module code of the SWORD module. |
313
314
 
315
+ <a name="NodeSwordInterface+mapVerseReference"></a>
316
+
317
+ ### nodeSwordInterface.mapVerseReference(sourceOsisRef, sourceModuleName, targetModuleName, [allowRange]) ⇒ <code>String</code>
318
+ Maps a verse reference from one module's versification to another module's versification.
319
+
320
+ **Kind**: instance method of [<code>NodeSwordInterface</code>](#NodeSwordInterface)
321
+ **Returns**: <code>String</code> - The mapped OSIS reference in the target module's versification.
322
+
323
+ | Param | Type | Default | Description |
324
+ | --- | --- | --- | --- |
325
+ | sourceOsisRef | <code>String</code> | | The OSIS reference in the source module's versification (e.g. "Ps.13.1"). |
326
+ | sourceModuleName | <code>String</code> | | The module code of the source SWORD module. |
327
+ | targetModuleName | <code>String</code> | | The module code of the target SWORD module. |
328
+ | [allowRange] | <code>Boolean</code> | <code>false</code> | If true, may return a verse range (e.g. "Ps.50.1-Ps.50.3"). If false, returns only the first verse of a possible range. |
329
+
314
330
  <a name="NodeSwordInterface+getModuleDescription"></a>
315
331
 
316
332
  ### nodeSwordInterface.getModuleDescription(repositoryName, moduleCode) ⇒ <code>String</code>
@@ -352,11 +368,11 @@ If no entry exists for the given key the return value is undefined.
352
368
 
353
369
  **Kind**: instance method of [<code>NodeSwordInterface</code>](#NodeSwordInterface)
354
370
 
355
- | Param | Type | Description |
356
- | --- | --- | --- |
357
- | moduleCode | <code>String</code> | The module code of the SWORD module. |
358
- | key | <code>String</code> | The key of the entry. |
359
- | processImageUrls | <code>Boolean</code> | Whether to pre-process image URLs with platform-specific file paths (Optional, default: false). |
371
+ | Param | Type | Default | Description |
372
+ | --- | --- | --- | --- |
373
+ | moduleCode | <code>String</code> | | The module code of the SWORD module. |
374
+ | key | <code>String</code> | | The key of the entry. |
375
+ | processImageUrls | <code>Boolean</code> | <code>false</code> | Whether to pre-process image URLs with platform-specific file paths (Optional, default: false). |
360
376
 
361
377
  <a name="NodeSwordInterface+getReferenceText"></a>
362
378
 
package/index.js CHANGED
@@ -342,6 +342,19 @@ class NodeSwordInterface {
342
342
  return this.nativeInterface.isModuleReadable(moduleCode);
343
343
  }
344
344
 
345
+ /**
346
+ * Maps a verse reference from one module's versification to another module's versification.
347
+ *
348
+ * @param {String} sourceOsisRef - The OSIS reference in the source module's versification (e.g. "Ps.13.1").
349
+ * @param {String} sourceModuleName - The module code of the source SWORD module.
350
+ * @param {String} targetModuleName - The module code of the target SWORD module.
351
+ * @param {Boolean} [allowRange=false] - If true, may return a verse range (e.g. "Ps.50.1-Ps.50.3"). If false, returns only the first verse of a possible range.
352
+ * @return {String} The mapped OSIS reference in the target module's versification.
353
+ */
354
+ mapVerseReference(sourceOsisRef, sourceModuleName, targetModuleName, allowRange = false) {
355
+ return this.nativeInterface.mapVerseReference(sourceOsisRef, sourceModuleName, targetModuleName, allowRange);
356
+ }
357
+
345
358
  /**
346
359
  * Returns the description of a module.
347
360
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-sword-interface",
3
- "version": "1.0.112",
3
+ "version": "1.0.113",
4
4
  "description": "Javascript (N-API) interface to SWORD library",
5
5
  "keywords": [
6
6
  "C++",
@@ -114,6 +114,7 @@ Napi::Object NodeSwordInterface::Init(Napi::Env env, Napi::Object exports)
114
114
  InstanceMethod("refreshLocalModules", &NodeSwordInterface::refreshLocalModules),
115
115
  InstanceMethod("saveModuleUnlockKey", &NodeSwordInterface::saveModuleUnlockKey),
116
116
  InstanceMethod("isModuleReadable", &NodeSwordInterface::isModuleReadable),
117
+ InstanceMethod("mapVerseReference", &NodeSwordInterface::mapVerseReference),
117
118
  InstanceMethod("getSwordTranslation", &NodeSwordInterface::getSwordTranslation),
118
119
  InstanceMethod("getBookAbbreviation", &NodeSwordInterface::getBookAbbreviation),
119
120
  InstanceMethod("getSwordVersion", &NodeSwordInterface::getSwordVersion),
@@ -1099,6 +1100,43 @@ Napi::Value NodeSwordInterface::getSwordPath(const Napi::CallbackInfo& info)
1099
1100
  return swordPath;
1100
1101
  }
1101
1102
 
1103
+ Napi::Value NodeSwordInterface::mapVerseReference(const Napi::CallbackInfo& info)
1104
+ {
1105
+ lockApi();
1106
+ Napi::Env env = info.Env();
1107
+ Napi::HandleScope scope(env);
1108
+
1109
+ if (info.Length() < 3 || info.Length() > 4) {
1110
+ Napi::TypeError::New(env, "Expected 3 or 4 parameters!").ThrowAsJavaScriptException();
1111
+ unlockApi();
1112
+ return env.Null();
1113
+ }
1114
+ if (!info[0].IsString() || !info[1].IsString() || !info[2].IsString()) {
1115
+ Napi::TypeError::New(env, "First 3 arguments must be strings!").ThrowAsJavaScriptException();
1116
+ unlockApi();
1117
+ return env.Null();
1118
+ }
1119
+
1120
+ Napi::String sourceOsisRef = info[0].As<Napi::String>();
1121
+ Napi::String sourceModuleName = info[1].As<Napi::String>();
1122
+ Napi::String targetModuleName = info[2].As<Napi::String>();
1123
+
1124
+ bool allowRange = false;
1125
+ if (info.Length() == 4) {
1126
+ if (!info[3].IsBoolean()) {
1127
+ Napi::TypeError::New(env, "Boolean expected for argument 4").ThrowAsJavaScriptException();
1128
+ unlockApi();
1129
+ return env.Null();
1130
+ }
1131
+ allowRange = info[3].As<Napi::Boolean>().Value();
1132
+ }
1133
+
1134
+ string result = this->_textProcessor->mapVerseReference(sourceOsisRef, sourceModuleName, targetModuleName, allowRange);
1135
+
1136
+ unlockApi();
1137
+ return Napi::String::New(env, result);
1138
+ }
1139
+
1102
1140
  Napi::Value NodeSwordInterface::unTarGZ(const Napi::CallbackInfo& info)
1103
1141
  {
1104
1142
  Napi::Env env = info.Env();
@@ -98,6 +98,8 @@ private:
98
98
  Napi::Value isModuleReadable(const Napi::CallbackInfo& info);
99
99
  Napi::Value refreshLocalModules(const Napi::CallbackInfo& info);
100
100
 
101
+ Napi::Value mapVerseReference(const Napi::CallbackInfo& info);
102
+
101
103
  Napi::Value getSwordTranslation(const Napi::CallbackInfo& info);
102
104
  Napi::Value getBookAbbreviation(const Napi::CallbackInfo& info);
103
105
  Napi::Value getSwordVersion(const Napi::CallbackInfo& info);
@@ -191,6 +191,111 @@ void get_strongs_entry(TextProcessor& text_processor)
191
191
  }
192
192
  }
193
193
 
194
+ void install_if_missing(ModuleInstaller& module_installer, ModuleStore& module_store, const string& repo, const string& moduleName)
195
+ {
196
+ SWModule* m = module_store.getLocalModule(moduleName);
197
+ if (m == 0) {
198
+ cout << "Installing module " << moduleName << " from " << repo << " ..." << endl;
199
+ int error = module_installer.installModule(repo, moduleName);
200
+ if (error) {
201
+ cout << " ERROR: Failed to install " << moduleName << endl;
202
+ } else {
203
+ cout << " Successfully installed " << moduleName << endl;
204
+ module_store.refreshMgr();
205
+ }
206
+ } else {
207
+ cout << "Module " << moduleName << " already installed." << endl;
208
+ }
209
+ }
210
+
211
+ void test_verse_reference_mapping(ModuleInstaller& module_installer, ModuleStore& module_store, TextProcessor& text_processor)
212
+ {
213
+ cout << "=== Verse Reference Mapping Test ===" << endl;
214
+
215
+ // Install required modules for the tests
216
+ // KJV uses KJV versification
217
+ install_if_missing(module_installer, module_store, "CrossWire", "KJV");
218
+ // RusSynodal uses Synodal versification
219
+ install_if_missing(module_installer, module_store, "CrossWire", "RusSynodal");
220
+ // VulgClementine uses Vulg versification
221
+ install_if_missing(module_installer, module_store, "CrossWire", "VulgClementine");
222
+
223
+ cout << endl;
224
+
225
+ // Test 1: Same versification (should return unchanged)
226
+ string result1 = text_processor.mapVerseReference("Gen.1.1", "KJV", "KJV");
227
+ cout << "KJV Gen.1.1 -> KJV: " << result1 << endl;
228
+
229
+ // Test 2: KJV to Synodal (Psalm numbering and superscription shift)
230
+ string result2 = text_processor.mapVerseReference("Ps.13.1", "KJV", "RusSynodal");
231
+ cout << "KJV Ps.13.1 -> RusSynodal (Synodal): " << result2 << endl;
232
+
233
+ // Test 3: KJV to Vulg (Psalm 51 -> Psalm 50, default allowRange=false returns first verse only)
234
+ string result3 = text_processor.mapVerseReference("Ps.51.1", "KJV", "VulgClementine");
235
+ cout << "KJV Ps.51.1 -> VulgClementine (Vulg, no range): " << result3 << endl;
236
+
237
+ // Test 3b: Same mapping with allowRange=true (returns full range)
238
+ string result3b = text_processor.mapVerseReference("Ps.51.1", "KJV", "VulgClementine", true);
239
+ cout << "KJV Ps.51.1 -> VulgClementine (Vulg, with range): " << result3b << endl;
240
+
241
+ // Test 3c: Reverse - take the second verse of the range (Ps.50.3) and map back to KJV
242
+ string result3c = text_processor.mapVerseReference("Ps.50.3", "VulgClementine", "KJV");
243
+ cout << "VulgClementine Ps.50.3 -> KJV: " << result3c << endl;
244
+
245
+ // Test 4: Synodal to KJV (reverse mapping)
246
+ string result4 = text_processor.mapVerseReference("Ps.12.2", "RusSynodal", "KJV");
247
+ cout << "RusSynodal Ps.12.2 -> KJV: " << result4 << endl;
248
+
249
+ // Test 5: Synodal to Vulg (non-KJV to non-KJV, routes through KJVA hub)
250
+ string result5 = text_processor.mapVerseReference("Ps.50.1", "RusSynodal", "VulgClementine");
251
+ cout << "RusSynodal Ps.50.1 -> VulgClementine (Vulg): " << result5 << endl;
252
+
253
+ // --- NT mapping tests ---
254
+ cout << endl << "--- NT Mapping Tests ---" << endl;
255
+
256
+ // Test 6: KJV Rev.13.1 -> Vulg (default: first verse only)
257
+ string result6 = text_processor.mapVerseReference("Rev.13.1", "KJV", "VulgClementine");
258
+ cout << "KJV Rev.13.1 -> VulgClementine (Vulg, no range): " << result6 << endl;
259
+
260
+ // Test 6b: Same with allowRange=true
261
+ string result6b = text_processor.mapVerseReference("Rev.13.1", "KJV", "VulgClementine", true);
262
+ cout << "KJV Rev.13.1 -> VulgClementine (Vulg, with range): " << result6b << endl;
263
+
264
+ // Test 6c: Reverse - take the second verse of the range (Rev.12.19) and map back to KJV
265
+ string result6c = text_processor.mapVerseReference("Rev.12.19", "VulgClementine", "KJV");
266
+ cout << "VulgClementine Rev.12.19 -> KJV: " << result6c << endl;
267
+
268
+ // Test 7: KJV Mark.9.1 -> Vulg (Vulg has Mark 9:1 as Mark 8:39)
269
+ string result7 = text_processor.mapVerseReference("Mark.9.1", "KJV", "VulgClementine");
270
+ cout << "KJV Mark.9.1 -> VulgClementine (Vulg): " << result7 << endl;
271
+
272
+ // Test 8: KJV Acts.19.41 -> Vulg (Vulg merges Acts 19:40-41)
273
+ string result8 = text_processor.mapVerseReference("Acts.19.41", "KJV", "VulgClementine");
274
+ cout << "KJV Acts.19.41 -> VulgClementine (Vulg): " << result8 << endl;
275
+
276
+ // Test 9: KJV 3John.1.14 -> Synodal (default: first verse only)
277
+ string result9 = text_processor.mapVerseReference("3John.1.14", "KJV", "RusSynodal");
278
+ cout << "KJV 3John.1.14 -> RusSynodal (Synodal, no range): " << result9 << endl;
279
+
280
+ // Test 9b: Same with allowRange=true (Synodal splits 3 John 1:14 into 14-15)
281
+ string result9b = text_processor.mapVerseReference("3John.1.14", "KJV", "RusSynodal", true);
282
+ cout << "KJV 3John.1.14 -> RusSynodal (Synodal, with range): " << result9b << endl;
283
+
284
+ // Test 9c: Reverse - take the second verse of the range (3John.1.15) and map back to KJV
285
+ string result9c = text_processor.mapVerseReference("3John.1.15", "RusSynodal", "KJV");
286
+ cout << "RusSynodal 3John.1.15 -> KJV: " << result9c << endl;
287
+
288
+ // Test 10: KJV Rom.16.25 -> Synodal (Synodal moves the doxology to Rom.14.24)
289
+ string result10 = text_processor.mapVerseReference("Rom.16.25", "KJV", "RusSynodal");
290
+ cout << "KJV Rom.16.25 -> RusSynodal (Synodal): " << result10 << endl;
291
+
292
+ // Test 11: KJV Mark.4.41 -> Vulg (Vulg merges Mark 4:40-41 into one verse)
293
+ string result11 = text_processor.mapVerseReference("Mark.4.41", "KJV", "VulgClementine");
294
+ cout << "KJV Mark.4.41 -> VulgClementine (Vulg): " << result11 << endl;
295
+
296
+ cout << "=== End of Mapping Test ===" << endl;
297
+ }
298
+
194
299
  int main(int argc, char** argv)
195
300
  {
196
301
  ModuleStore moduleStore;
@@ -218,7 +323,9 @@ int main(int argc, char** argv)
218
323
 
219
324
  /*show_repos(repoInterface);*/
220
325
 
221
- show_modules(repoInterface);
326
+ //show_modules(repoInterface);
327
+
328
+ test_verse_reference_mapping(moduleInstaller, moduleStore, textProcessor);
222
329
 
223
330
  /*int error = moduleInstaller.installModule("CrossWire", "UKJV");
224
331
 
@@ -245,7 +352,7 @@ int main(int argc, char** argv)
245
352
 
246
353
  //get_reference_text(moduleStore, textProcessor);
247
354
 
248
- get_book_intro(textProcessor);
355
+ //get_book_intro(textProcessor);
249
356
 
250
357
  //get_book_list(moduleHelper);
251
358
 
@@ -31,6 +31,7 @@
31
31
  #include <listkey.h>
32
32
  #include <swmodule.h>
33
33
  #include <swkey.h>
34
+ #include <versificationmgr.h>
34
35
 
35
36
  // Own includes
36
37
  #include "text_processor.hpp"
@@ -868,3 +869,66 @@ void TextProcessor::removePbElementsWithSpace(std::string& data)
868
869
  }
869
870
  }
870
871
  }
872
+
873
+ string TextProcessor::mapVerseReference(string sourceOsisRef, string sourceModuleName, string targetModuleName, bool allowRange)
874
+ {
875
+ // Look up both modules to read their versification systems
876
+ SWModule* sourceModule = this->_moduleStore.getLocalModule(sourceModuleName);
877
+ SWModule* targetModule = this->_moduleStore.getLocalModule(targetModuleName);
878
+
879
+ // Determine versification system names (default to KJV if not specified)
880
+ string sourceV11n = "KJV";
881
+ string targetV11n = "KJV";
882
+
883
+ if (sourceModule != 0) {
884
+ const char* v11nEntry = sourceModule->getConfigEntry("Versification");
885
+ if (v11nEntry != 0) {
886
+ sourceV11n = v11nEntry;
887
+ }
888
+ }
889
+
890
+ if (targetModule != 0) {
891
+ const char* v11nEntry = targetModule->getConfigEntry("Versification");
892
+ if (v11nEntry != 0) {
893
+ targetV11n = v11nEntry;
894
+ }
895
+ }
896
+
897
+ // If both modules use the same versification, no mapping is needed
898
+ if (sourceV11n == targetV11n) {
899
+ return sourceOsisRef;
900
+ }
901
+
902
+ // Get the versification systems from VersificationMgr
903
+ VersificationMgr* vMgr = VersificationMgr::getSystemVersificationMgr();
904
+ const VersificationMgr::System* sourceSys = vMgr->getVersificationSystem(sourceV11n.c_str());
905
+ const VersificationMgr::System* targetSys = vMgr->getVersificationSystem(targetV11n.c_str());
906
+
907
+ if (sourceSys == 0 || targetSys == 0) {
908
+ return sourceOsisRef;
909
+ }
910
+
911
+ // Parse the source OSIS reference using a VerseKey with the source versification
912
+ VerseKey sourceKey;
913
+ sourceKey.setVersificationSystem(sourceV11n.c_str());
914
+ sourceKey.setText(sourceOsisRef.c_str());
915
+
916
+ // Extract the components for translateVerse
917
+ const char* book = sourceKey.getOSISBookName();
918
+ int chapter = sourceKey.getChapter();
919
+ int verse = sourceKey.getVerse();
920
+ int verseEnd = verse;
921
+
922
+ // Perform the mapping
923
+ sourceSys->translateVerse(targetSys, &book, &chapter, &verse, &verseEnd);
924
+
925
+ // Build the mapped OSIS reference
926
+ stringstream result;
927
+ result << book << "." << chapter << "." << verse;
928
+
929
+ if (allowRange && verseEnd > verse) {
930
+ result << "-" << book << "." << chapter << "." << verseEnd;
931
+ }
932
+
933
+ return result.str();
934
+ }
@@ -59,6 +59,8 @@ public:
59
59
  std::string padStrongsNumber(const std::string strongsNumber);
60
60
  bool isModuleReadable(sword::SWModule* module, std::string key="John 1:1");
61
61
 
62
+ std::string mapVerseReference(std::string sourceOsisRef, std::string sourceModuleName, std::string targetModuleName, bool allowRange = false);
63
+
62
64
  private:
63
65
  std::vector<Verse> getText(std::string moduleName,
64
66
  std::string key,