@natlibfi/marc-record-validators-melinda 12.1.0-alpha.1 → 13.0.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.
Files changed (425) hide show
  1. package/.github/workflows/melinda-node-tests-and-publish.yml +17 -17
  2. package/README.md +1 -1
  3. package/dist/addMissingField041.js +6 -3
  4. package/dist/addMissingField041.js.map +2 -2
  5. package/dist/addMissingField336.js +7 -4
  6. package/dist/addMissingField336.js.map +2 -2
  7. package/dist/addMissingField337.js +6 -3
  8. package/dist/addMissingField337.js.map +2 -2
  9. package/dist/addMissingField338.js +8 -5
  10. package/dist/addMissingField338.js.map +2 -2
  11. package/dist/cyrillux-usemarcon-replacement.js +5 -2
  12. package/dist/cyrillux-usemarcon-replacement.js.map +2 -2
  13. package/dist/cyrillux.js +24 -18
  14. package/dist/cyrillux.js.map +2 -2
  15. package/dist/dataProvenanceUtils.js +19 -0
  16. package/dist/dataProvenanceUtils.js.map +7 -0
  17. package/dist/disambiguateSeriesStatements.js +2 -1
  18. package/dist/disambiguateSeriesStatements.js.map +2 -2
  19. package/dist/disambiguateSeriesStatements.test.js +1 -7
  20. package/dist/disambiguateSeriesStatements.test.js.map +2 -2
  21. package/dist/drop-terms.js +123 -0
  22. package/dist/drop-terms.js.map +7 -0
  23. package/dist/drop-terms.test.js +56 -0
  24. package/dist/drop-terms.test.js.map +7 -0
  25. package/dist/field-008-18-34-character-groups.test.js +1 -7
  26. package/dist/field-008-18-34-character-groups.test.js.map +2 -2
  27. package/dist/field-505-separators.test.js +1 -7
  28. package/dist/field-505-separators.test.js.map +2 -2
  29. package/dist/field-521-fix.test.js +1 -7
  30. package/dist/field-521-fix.test.js.map +2 -2
  31. package/dist/fix-33X.js +7 -4
  32. package/dist/fix-33X.js.map +2 -2
  33. package/dist/fix-33X.test.js +1 -1
  34. package/dist/fix-33X.test.js.map +1 -1
  35. package/dist/fix-country-codes.js +5 -0
  36. package/dist/fix-country-codes.js.map +2 -2
  37. package/dist/fix-country-codes.test.js +1 -7
  38. package/dist/fix-country-codes.test.js.map +2 -2
  39. package/dist/fix-language-codes.js +5 -1
  40. package/dist/fix-language-codes.js.map +2 -2
  41. package/dist/fix-sami-041.js +109 -0
  42. package/dist/fix-sami-041.js.map +7 -0
  43. package/dist/fix-sami-041.test.js +40 -0
  44. package/dist/fix-sami-041.test.js.map +7 -0
  45. package/dist/fixRelatorTerms.js +2 -0
  46. package/dist/fixRelatorTerms.js.map +2 -2
  47. package/dist/fixRelatorTerms.test.js +1 -7
  48. package/dist/fixRelatorTerms.test.js.map +2 -2
  49. package/dist/index.js +18 -4
  50. package/dist/index.js.map +2 -2
  51. package/dist/indicator-fixes.js +15 -1
  52. package/dist/indicator-fixes.js.map +2 -2
  53. package/dist/indicator-fixes.test.js +1 -7
  54. package/dist/indicator-fixes.test.js.map +2 -2
  55. package/dist/item-language.js +41 -39
  56. package/dist/item-language.js.map +2 -2
  57. package/dist/item-language.test.js +3 -3
  58. package/dist/item-language.test.js.map +2 -2
  59. package/dist/melindaCustomMergeFields.js +31 -0
  60. package/dist/melindaCustomMergeFields.js.map +2 -2
  61. package/dist/merge-fields/controlSubfields.js.map +2 -2
  62. package/dist/merge-fields/counterpartField.js +149 -152
  63. package/dist/merge-fields/counterpartField.js.map +3 -3
  64. package/dist/merge-fields/dataProvenance.js +6 -20
  65. package/dist/merge-fields/dataProvenance.js.map +2 -2
  66. package/dist/merge-fields/index.js +1 -1
  67. package/dist/merge-fields/index.js.map +2 -2
  68. package/dist/merge-fields/mergableIndicator.js +1 -5
  69. package/dist/merge-fields/mergableIndicator.js.map +2 -2
  70. package/dist/merge-fields/mergableTag.js +2 -0
  71. package/dist/merge-fields/mergableTag.js.map +2 -2
  72. package/dist/merge-fields/mergeConfig.js +2 -0
  73. package/dist/merge-fields/mergeConfig.js.map +2 -2
  74. package/dist/merge-fields/mergeConstraints.js +38 -35
  75. package/dist/merge-fields/mergeConstraints.js.map +3 -3
  76. package/dist/merge-fields/mergeField.js +4 -3
  77. package/dist/merge-fields/mergeField.js.map +2 -2
  78. package/dist/merge-fields/mergeOrAddSubfield.js +8 -7
  79. package/dist/merge-fields/mergeOrAddSubfield.js.map +2 -2
  80. package/dist/merge-fields/mergeSubfield.js +5 -1
  81. package/dist/merge-fields/mergeSubfield.js.map +2 -2
  82. package/dist/merge-fields/worldKnowledge.js +52 -0
  83. package/dist/merge-fields/worldKnowledge.js.map +2 -2
  84. package/dist/merge-fields.test.js +4 -9
  85. package/dist/merge-fields.test.js.map +2 -2
  86. package/dist/mergeField500Lisapainokset.test.js +1 -7
  87. package/dist/mergeField500Lisapainokset.test.js.map +2 -2
  88. package/dist/mergeRelatorTermFields.js +9 -6
  89. package/dist/mergeRelatorTermFields.js.map +2 -2
  90. package/dist/mergeRelatorTermFields.test.js +1 -7
  91. package/dist/mergeRelatorTermFields.test.js.map +2 -2
  92. package/dist/multiple-subfield-0.test.js +1 -7
  93. package/dist/multiple-subfield-0.test.js.map +2 -2
  94. package/dist/normalize-dashes.js +9 -6
  95. package/dist/normalize-dashes.js.map +2 -2
  96. package/dist/normalize-dashes.test.js +1 -7
  97. package/dist/normalize-dashes.test.js.map +2 -2
  98. package/dist/normalize-identifiers.js.map +2 -2
  99. package/dist/normalize-identifiers.test.js +1 -7
  100. package/dist/normalize-identifiers.test.js.map +2 -2
  101. package/dist/normalize-qualifying-information.test.js +1 -7
  102. package/dist/normalize-qualifying-information.test.js.map +2 -2
  103. package/dist/normalize-utf8-diacritics.js.map +2 -2
  104. package/dist/normalize-utf8-diacritics.test.js +1 -7
  105. package/dist/normalize-utf8-diacritics.test.js.map +2 -2
  106. package/dist/normalizeFieldForComparison.js +24 -14
  107. package/dist/normalizeFieldForComparison.js.map +2 -2
  108. package/dist/normalizeSubfieldValueForComparison.js.map +1 -1
  109. package/dist/prepublicationUtils.js +1 -1
  110. package/dist/prepublicationUtils.js.map +2 -2
  111. package/dist/punctuation.test.js +1 -7
  112. package/dist/punctuation.test.js.map +2 -2
  113. package/dist/punctuation2.js +15 -12
  114. package/dist/punctuation2.js.map +2 -2
  115. package/dist/punctuation2.test.js +1 -7
  116. package/dist/punctuation2.test.js.map +2 -2
  117. package/dist/reindexSubfield6OccurenceNumbers.js +11 -10
  118. package/dist/reindexSubfield6OccurenceNumbers.js.map +2 -2
  119. package/dist/reindexSubfield6OccurenceNumbers.test.js +1 -7
  120. package/dist/reindexSubfield6OccurenceNumbers.test.js.map +2 -2
  121. package/dist/remove-041-zxx.js +56 -0
  122. package/dist/remove-041-zxx.js.map +7 -0
  123. package/dist/remove-041-zxx.test.js +40 -0
  124. package/dist/remove-041-zxx.test.js.map +7 -0
  125. package/dist/removeDuplicateDataFields.js +4 -26
  126. package/dist/removeDuplicateDataFields.js.map +2 -2
  127. package/dist/removeDuplicateDataFields.test.js +1 -7
  128. package/dist/removeDuplicateDataFields.test.js.map +2 -2
  129. package/dist/removeInferiorDataFields.js +82 -45
  130. package/dist/removeInferiorDataFields.js.map +3 -3
  131. package/dist/removeInferiorDataFields.test.js +5 -9
  132. package/dist/removeInferiorDataFields.test.js.map +2 -2
  133. package/dist/resolveOrphanedSubfield6s.js +4 -5
  134. package/dist/resolveOrphanedSubfield6s.js.map +2 -2
  135. package/dist/resolveOrphanedSubfield6s.test.js +1 -7
  136. package/dist/resolveOrphanedSubfield6s.test.js.map +2 -2
  137. package/dist/sanitize-vocabulary-source-codes.test.js +1 -7
  138. package/dist/sanitize-vocabulary-source-codes.test.js.map +2 -2
  139. package/dist/sortFields.js +16 -1
  140. package/dist/sortFields.js.map +2 -2
  141. package/dist/sortFields.test.js +1 -7
  142. package/dist/sortFields.test.js.map +2 -2
  143. package/dist/sortRelatorTerms.test.js +1 -7
  144. package/dist/sortRelatorTerms.test.js.map +2 -2
  145. package/dist/sortSubfields.js +27 -21
  146. package/dist/sortSubfields.js.map +2 -2
  147. package/dist/sortSubfields.test.js +1 -7
  148. package/dist/sortSubfields.test.js.map +2 -2
  149. package/dist/stripPunctuation.js +7 -3
  150. package/dist/stripPunctuation.js.map +2 -2
  151. package/dist/stripPunctuation.test.js +1 -7
  152. package/dist/stripPunctuation.test.js.map +2 -2
  153. package/dist/subfield6Utils.js +2 -12
  154. package/dist/subfield6Utils.js.map +2 -2
  155. package/dist/subfield8Utils.js +0 -5
  156. package/dist/subfield8Utils.js.map +2 -2
  157. package/dist/subfieldValueNormalizations.test.js +1 -7
  158. package/dist/subfieldValueNormalizations.test.js.map +2 -2
  159. package/dist/sync-007-and-300.test.js +1 -7
  160. package/dist/sync-007-and-300.test.js.map +2 -2
  161. package/dist/sync-language.js +103 -0
  162. package/dist/sync-language.js.map +7 -0
  163. package/dist/sync-language.test.js +40 -0
  164. package/dist/sync-language.test.js.map +7 -0
  165. package/dist/translate-terms.js +124 -87
  166. package/dist/translate-terms.js.map +3 -3
  167. package/dist/translate-terms.test.js +5 -8
  168. package/dist/translate-terms.test.js.map +2 -2
  169. package/dist/typeOfDate-008.js +3 -1
  170. package/dist/typeOfDate-008.js.map +2 -2
  171. package/dist/update-field-540.js.map +2 -2
  172. package/dist/update-field-540.test.js +1 -7
  173. package/dist/update-field-540.test.js.map +2 -2
  174. package/dist/urn.js +13 -12
  175. package/dist/urn.js.map +2 -2
  176. package/dist/urn.test.js +1 -7
  177. package/dist/urn.test.js.map +2 -2
  178. package/dist/utils.js +29 -3
  179. package/dist/utils.js.map +2 -2
  180. package/package.json +20 -27
  181. package/src/addMissingField041.js +8 -4
  182. package/src/addMissingField336.js +10 -5
  183. package/src/addMissingField337.js +9 -5
  184. package/src/addMissingField338.js +11 -6
  185. package/src/cyrillux-usemarcon-replacement.js +9 -5
  186. package/src/cyrillux.js +34 -23
  187. package/src/dataProvenanceUtils.js +21 -0
  188. package/src/disambiguateSeriesStatements.js +4 -1
  189. package/src/disambiguateSeriesStatements.test.js +3 -8
  190. package/src/drop-terms.js +164 -0
  191. package/src/drop-terms.test.js +81 -0
  192. package/src/field-008-18-34-character-groups.test.js +3 -8
  193. package/src/field-505-separators.test.js +3 -8
  194. package/src/field-521-fix.test.js +3 -8
  195. package/src/fix-33X.js +10 -6
  196. package/src/fix-33X.test.js +1 -1
  197. package/src/fix-country-codes.js +7 -3
  198. package/src/fix-country-codes.test.js +3 -8
  199. package/src/fix-language-codes.js +8 -4
  200. package/src/fix-sami-041.js +147 -0
  201. package/src/fix-sami-041.test.js +52 -0
  202. package/src/fixRelatorTerms.js +5 -0
  203. package/src/fixRelatorTerms.test.js +3 -8
  204. package/src/index.js +20 -7
  205. package/src/indicator-fixes.js +22 -7
  206. package/src/indicator-fixes.test.js +3 -8
  207. package/src/item-language.js +49 -42
  208. package/src/item-language.test.js +3 -3
  209. package/src/melindaCustomMergeFields.js +31 -0
  210. package/src/merge-fields/controlSubfields.js +0 -1
  211. package/src/merge-fields/counterpartField.js +191 -290
  212. package/src/merge-fields/dataProvenance.js +8 -25
  213. package/src/merge-fields/index.js +1 -1
  214. package/src/merge-fields/mergableIndicator.js +4 -5
  215. package/src/merge-fields/mergableTag.js +2 -0
  216. package/src/merge-fields/mergeConfig.js +2 -1
  217. package/src/merge-fields/mergeConstraints.js +41 -36
  218. package/src/merge-fields/mergeField.js +4 -7
  219. package/src/merge-fields/mergeOrAddSubfield.js +8 -7
  220. package/src/merge-fields/mergeSubfield.js +11 -2
  221. package/src/merge-fields/worldKnowledge.js +77 -3
  222. package/src/merge-fields.test.js +5 -10
  223. package/src/mergeField500Lisapainokset.test.js +3 -8
  224. package/src/mergeRelatorTermFields.js +12 -11
  225. package/src/mergeRelatorTermFields.test.js +3 -8
  226. package/src/multiple-subfield-0.test.js +3 -8
  227. package/src/normalize-dashes.js +13 -7
  228. package/src/normalize-dashes.test.js +3 -8
  229. package/src/normalize-identifiers.js +12 -19
  230. package/src/normalize-identifiers.test.js +3 -8
  231. package/src/normalize-qualifying-information.test.js +3 -8
  232. package/src/normalize-utf8-diacritics.js +6 -3
  233. package/src/normalize-utf8-diacritics.test.js +3 -8
  234. package/src/normalizeFieldForComparison.js +39 -22
  235. package/src/normalizeSubfieldValueForComparison.js +2 -2
  236. package/src/prepublicationUtils.js +1 -1
  237. package/src/punctuation.test.js +3 -8
  238. package/src/punctuation2.js +44 -40
  239. package/src/punctuation2.test.js +3 -8
  240. package/src/reindexSubfield6OccurenceNumbers.js +13 -11
  241. package/src/reindexSubfield6OccurenceNumbers.test.js +3 -8
  242. package/src/remove-041-zxx.js +85 -0
  243. package/src/remove-041-zxx.test.js +52 -0
  244. package/src/removeDuplicateDataFields.js +30 -28
  245. package/src/removeDuplicateDataFields.test.js +3 -8
  246. package/src/removeInferiorDataFields.js +126 -71
  247. package/src/removeInferiorDataFields.test.js +7 -10
  248. package/src/resolveOrphanedSubfield6s.js +7 -5
  249. package/src/resolveOrphanedSubfield6s.test.js +3 -8
  250. package/src/sanitize-vocabulary-source-codes.test.js +3 -8
  251. package/src/sortFields.js +20 -1
  252. package/src/sortFields.test.js +3 -8
  253. package/src/sortRelatorTerms.test.js +3 -8
  254. package/src/sortSubfields.js +31 -25
  255. package/src/sortSubfields.test.js +3 -8
  256. package/src/stripPunctuation.js +10 -5
  257. package/src/stripPunctuation.test.js +3 -8
  258. package/src/subfield6Utils.js +31 -33
  259. package/src/subfield8Utils.js +10 -7
  260. package/src/subfieldValueNormalizations.test.js +3 -8
  261. package/src/sync-007-and-300.test.js +3 -8
  262. package/src/sync-language.js +148 -0
  263. package/src/sync-language.test.js +52 -0
  264. package/src/translate-terms.js +168 -109
  265. package/src/translate-terms.test.js +12 -16
  266. package/src/typeOfDate-008.js +4 -1
  267. package/src/update-field-540.js +7 -5
  268. package/src/update-field-540.test.js +3 -8
  269. package/src/urn.js +17 -13
  270. package/src/urn.test.js +3 -8
  271. package/src/utils.js +39 -12
  272. package/test-fixtures/cyrillux/f02b/expectedResult.json +23 -0
  273. package/test-fixtures/cyrillux/f02b/metadata.json +11 -0
  274. package/test-fixtures/cyrillux/f02b/record.json +14 -0
  275. package/test-fixtures/cyrillux/f14/expectedResult.json +32 -0
  276. package/test-fixtures/cyrillux/f14/metadata.json +10 -0
  277. package/test-fixtures/cyrillux/f14/record.json +14 -0
  278. package/test-fixtures/drop-terms/01/expectedResult.json +31 -0
  279. package/test-fixtures/drop-terms/01/metadata.json +6 -0
  280. package/test-fixtures/drop-terms/01/record.json +35 -0
  281. package/test-fixtures/drop-terms/02/expectedResult.json +7 -0
  282. package/test-fixtures/drop-terms/02/metadata.json +6 -0
  283. package/test-fixtures/drop-terms/02/record.json +40 -0
  284. package/test-fixtures/drop-terms/03/expectedResult.json +6 -0
  285. package/test-fixtures/drop-terms/03/metadata.json +18 -0
  286. package/test-fixtures/drop-terms/03/record.json +39 -0
  287. package/test-fixtures/drop-terms/04/expectedResult.json +6 -0
  288. package/test-fixtures/drop-terms/04/metadata.json +19 -0
  289. package/test-fixtures/drop-terms/04/record.json +24 -0
  290. package/test-fixtures/fix-language-codes/02/metadata.json +1 -1
  291. package/test-fixtures/fix-relator-terms/f02/metadata.json +1 -1
  292. package/test-fixtures/fix-relator-terms/f04/expectedResult.json +18 -0
  293. package/test-fixtures/fix-relator-terms/f04/metadata.json +5 -0
  294. package/test-fixtures/fix-relator-terms/f04/record.json +20 -0
  295. package/test-fixtures/fix-sami-041/01/expectedResult.json +6 -0
  296. package/test-fixtures/fix-sami-041/01/metadata.json +4 -0
  297. package/test-fixtures/fix-sami-041/01/record.json +14 -0
  298. package/test-fixtures/fix-sami-041/02/expectedResult.json +10 -0
  299. package/test-fixtures/fix-sami-041/02/metadata.json +4 -0
  300. package/test-fixtures/fix-sami-041/02/record.json +8 -0
  301. package/test-fixtures/fix-sami-041/03/expectedResult.json +5 -0
  302. package/test-fixtures/fix-sami-041/03/metadata.json +5 -0
  303. package/test-fixtures/fix-sami-041/03/record.json +8 -0
  304. package/test-fixtures/fix-sami-041/04/expectedResult.json +7 -0
  305. package/test-fixtures/fix-sami-041/04/metadata.json +4 -0
  306. package/test-fixtures/fix-sami-041/04/record.json +10 -0
  307. package/test-fixtures/fix-sami-041/05/expectedResult.json +10 -0
  308. package/test-fixtures/fix-sami-041/05/metadata.json +6 -0
  309. package/test-fixtures/fix-sami-041/05/record.json +8 -0
  310. package/test-fixtures/fix-sami-041/06/expectedResult.json +10 -0
  311. package/test-fixtures/fix-sami-041/06/metadata.json +4 -0
  312. package/test-fixtures/fix-sami-041/06/record.json +9 -0
  313. package/test-fixtures/indicator-fixes/11/expectedResult.json +10 -0
  314. package/test-fixtures/indicator-fixes/11/metadata.json +4 -0
  315. package/test-fixtures/indicator-fixes/11/record.json +10 -0
  316. package/test-fixtures/merge-fields/f042_01/expectedResult.json +12 -0
  317. package/test-fixtures/merge-fields/f042_01/metadata.json +6 -0
  318. package/test-fixtures/merge-fields/f042_01/record.json +13 -0
  319. package/test-fixtures/merge-fields/f05/metadata.json +1 -1
  320. package/test-fixtures/merge-fields/f06/expectedResult.json +42 -0
  321. package/test-fixtures/merge-fields/f06/metadata.json +6 -0
  322. package/test-fixtures/merge-fields/f06/record.json +41 -0
  323. package/test-fixtures/merge-fields/f07/expectedResult.json +18 -0
  324. package/test-fixtures/merge-fields/f07/metadata.json +6 -0
  325. package/test-fixtures/merge-fields/f07/record.json +18 -0
  326. package/test-fixtures/merge-fields/f08/expectedResult.json +12 -0
  327. package/test-fixtures/merge-fields/f08/metadata.json +7 -0
  328. package/test-fixtures/merge-fields/f08/record.json +10 -0
  329. package/test-fixtures/merge-fields/f09/expectedResult.json +14 -0
  330. package/test-fixtures/merge-fields/f09/metadata.json +6 -0
  331. package/test-fixtures/merge-fields/f09/record.json +14 -0
  332. package/test-fixtures/merge-fields/f10/expectedResult.json +25 -0
  333. package/test-fixtures/merge-fields/f10/metadata.json +6 -0
  334. package/test-fixtures/merge-fields/f10/record.json +25 -0
  335. package/test-fixtures/merge-fields/f11/expectedResult.json +40 -0
  336. package/test-fixtures/merge-fields/f11/metadata.json +7 -0
  337. package/test-fixtures/merge-fields/f11/record.json +50 -0
  338. package/test-fixtures/merge-fields/f12/expectedResult.json +17 -0
  339. package/test-fixtures/merge-fields/f12/metadata.json +6 -0
  340. package/test-fixtures/merge-fields/f12/record.json +25 -0
  341. package/test-fixtures/merge-fields/f13/expectedResult.json +18 -0
  342. package/test-fixtures/merge-fields/f13/metadata.json +6 -0
  343. package/test-fixtures/merge-fields/f13/record.json +28 -0
  344. package/test-fixtures/merge-fields/f14/expectedResult.json +25 -0
  345. package/test-fixtures/merge-fields/f14/metadata.json +6 -0
  346. package/test-fixtures/merge-fields/f14/record.json +25 -0
  347. package/test-fixtures/merge-fields/f15/expectedResult.json +8 -0
  348. package/test-fixtures/merge-fields/f15/metadata.json +6 -0
  349. package/test-fixtures/merge-fields/f15/record.json +9 -0
  350. package/test-fixtures/merge-fields/f16/expectedResult.json +12 -0
  351. package/test-fixtures/merge-fields/f16/metadata.json +7 -0
  352. package/test-fixtures/merge-fields/f16/record.json +13 -0
  353. package/test-fixtures/merge-fields/f300_01/expectedResult.json +9 -0
  354. package/test-fixtures/merge-fields/f300_01/metadata.json +6 -0
  355. package/test-fixtures/merge-fields/f300_01/record.json +8 -0
  356. package/test-fixtures/merge-fields/f300_02/expectedResult.json +13 -0
  357. package/test-fixtures/merge-fields/f300_02/metadata.json +6 -0
  358. package/test-fixtures/merge-fields/f300_02/record.json +16 -0
  359. package/test-fixtures/merge-fields/f300_03/expectedResult.json +13 -0
  360. package/test-fixtures/merge-fields/f300_03/metadata.json +6 -0
  361. package/test-fixtures/merge-fields/f300_03/record.json +16 -0
  362. package/test-fixtures/merge-fields/f490_01/expectedResult.json +13 -0
  363. package/test-fixtures/merge-fields/f490_01/metadata.json +6 -0
  364. package/test-fixtures/merge-fields/f490_01/record.json +16 -0
  365. package/test-fixtures/remove-041-zxx/01/expectedResult.json +5 -0
  366. package/test-fixtures/remove-041-zxx/01/metadata.json +5 -0
  367. package/test-fixtures/remove-041-zxx/01/record.json +10 -0
  368. package/test-fixtures/remove-041-zxx/02/expectedResult.json +7 -0
  369. package/test-fixtures/remove-041-zxx/02/metadata.json +5 -0
  370. package/test-fixtures/remove-041-zxx/02/record.json +9 -0
  371. package/test-fixtures/remove-041-zxx/11/expectedResult.json +10 -0
  372. package/test-fixtures/remove-041-zxx/11/metadata.json +5 -0
  373. package/test-fixtures/remove-041-zxx/11/record.json +9 -0
  374. package/test-fixtures/remove-041-zxx/12/expectedResult.json +10 -0
  375. package/test-fixtures/remove-041-zxx/12/metadata.json +5 -0
  376. package/test-fixtures/remove-041-zxx/12/record.json +9 -0
  377. package/test-fixtures/remove-inferior-datafields/f17/expectedResult.json +11 -0
  378. package/test-fixtures/remove-inferior-datafields/f17/metadata.json +5 -0
  379. package/test-fixtures/remove-inferior-datafields/f17/record.json +15 -0
  380. package/test-fixtures/remove-inferior-datafields/f18/expectedResult.json +13 -0
  381. package/test-fixtures/remove-inferior-datafields/f18/metadata.json +5 -0
  382. package/test-fixtures/remove-inferior-datafields/f18/record.json +18 -0
  383. package/test-fixtures/remove-inferior-datafields/f19/expectedResult.json +17 -0
  384. package/test-fixtures/remove-inferior-datafields/f19/metadata.json +5 -0
  385. package/test-fixtures/remove-inferior-datafields/f19/record.json +18 -0
  386. package/test-fixtures/remove-inferior-datafields/f20/expectedResult.json +15 -0
  387. package/test-fixtures/remove-inferior-datafields/f20/metadata.json +5 -0
  388. package/test-fixtures/remove-inferior-datafields/f20/record.json +29 -0
  389. package/test-fixtures/sort-fields/15/input.json +9 -0
  390. package/test-fixtures/sort-fields/15/metadata.json +5 -0
  391. package/test-fixtures/sort-fields/15/result.json +10 -0
  392. package/test-fixtures/sync-language/01/expectedResult.json +5 -0
  393. package/test-fixtures/sync-language/01/metadata.json +5 -0
  394. package/test-fixtures/sync-language/01/record.json +7 -0
  395. package/test-fixtures/sync-language/02/expectedResult.json +6 -0
  396. package/test-fixtures/sync-language/02/metadata.json +5 -0
  397. package/test-fixtures/sync-language/02/record.json +10 -0
  398. package/test-fixtures/sync-language/03/expectedResult.json +6 -0
  399. package/test-fixtures/sync-language/03/metadata.json +5 -0
  400. package/test-fixtures/sync-language/03/record.json +6 -0
  401. package/test-fixtures/sync-language/10/expectedResult.json +10 -0
  402. package/test-fixtures/sync-language/10/metadata.json +5 -0
  403. package/test-fixtures/sync-language/10/record.json +8 -0
  404. package/test-fixtures/sync-language/11/expectedResult.json +10 -0
  405. package/test-fixtures/sync-language/11/metadata.json +5 -0
  406. package/test-fixtures/sync-language/11/record.json +7 -0
  407. package/test-fixtures/sync-language/12/expectedResult.json +9 -0
  408. package/test-fixtures/sync-language/12/metadata.json +6 -0
  409. package/test-fixtures/sync-language/12/record.json +6 -0
  410. package/test-fixtures/sync-language/13/expectedResult.json +10 -0
  411. package/test-fixtures/sync-language/13/metadata.json +5 -0
  412. package/test-fixtures/sync-language/13/record.json +8 -0
  413. package/test-fixtures/sync-language/14/expectedResult.json +9 -0
  414. package/test-fixtures/sync-language/14/metadata.json +5 -0
  415. package/test-fixtures/sync-language/14/record.json +7 -0
  416. package/test-fixtures/sync-language/15/expectedResult.json +9 -0
  417. package/test-fixtures/sync-language/15/metadata.json +5 -0
  418. package/test-fixtures/sync-language/15/record.json +7 -0
  419. package/test-fixtures/translate-terms/05/expectedResult.json +12 -0
  420. package/test-fixtures/translate-terms/05/metadata.json +7 -0
  421. package/test-fixtures/translate-terms/05/record.json +11 -0
  422. package/test-fixtures/translate-terms/06/expectedResult.json +12 -0
  423. package/test-fixtures/translate-terms/06/metadata.json +7 -0
  424. package/test-fixtures/translate-terms/06/record.json +11 -0
  425. package/test-fixtures/translate-terms-data.js +23 -0
@@ -1,41 +1,24 @@
1
1
  // See https://www.loc.gov/marc/bibliographic/bdapndxj.html for details
2
2
 
3
- import {subfieldArraysContainSameData} from "../utils.js";
4
-
5
- export function tagToDataProvenanceSubfieldCode(tag) {
6
- if ( ['533', '800', '810', '811', '830'].includes(tag)) {
7
- return 'y';
8
- }
9
- if ( tag === '856' || tag === '857' ) {
10
- return 'e';
11
- }
12
-
13
- if ( tag.match(/^7[678]/u) ) {
14
- return 'l'
15
- }
16
-
17
- if ( tag.match(/^00/u)) {
18
- return undefined;
19
- }
20
- return '7';
21
- }
22
-
3
+ import {subfieldArraysContainSameData} from '../utils.js';
4
+ import {tagToDataProvenanceSubfieldCode} from '../dataProvenanceUtils.js';
23
5
 
24
6
  export function provenanceSubfieldsPermitMerge(baseField, sourceField) {
25
- const provinanceSubfieldCode = tagToDataProvenanceSubfieldCode(baseField.tag);
26
7
  if (!baseField.subfields) {
27
8
  return true;
28
9
  }
29
- if (provinanceSubfieldCode === undefined) {
10
+ const provenanceSubfieldCode = tagToDataProvenanceSubfieldCode(baseField.tag);
11
+
12
+ if (provenanceSubfieldCode === undefined) {
30
13
  return false;
31
14
  }
32
15
 
33
- const baseProvinanceSubfields = baseField.subfields.filter(sf => sf.code === provinanceSubfieldCode);
34
- const sourceProvinanceSubfields = sourceField.subfields.filter(sf => sf.code === provinanceSubfieldCode);
16
+ const baseProvenanceSubfields = baseField.subfields.filter(sf => sf.code === provenanceSubfieldCode);
17
+ const sourceProvenanceSubfields = sourceField.subfields.filter(sf => sf.code === provenanceSubfieldCode);
35
18
 
36
19
  // Currently we just compare two arrays. Later on we might do something more sophisticated with specific $7 data provenance category/relationship codes,
37
20
  // or actual values.
38
21
 
39
- return subfieldArraysContainSameData(baseProvinanceSubfields, sourceProvinanceSubfields);
22
+ return subfieldArraysContainSameData(baseProvenanceSubfields, sourceProvenanceSubfields);
40
23
 
41
24
  }
@@ -49,7 +49,7 @@ export default function (defaultTagPattern = undefined) {
49
49
  }
50
50
 
51
51
  function fix(record, config = undefined) {
52
- const config2 = config || defaultConfig;
52
+ const config2 = config || defaultConfig.mergeConfiguration;
53
53
  record.internalMerge = true;
54
54
  mergeFieldsWithinRecord(record, config2);
55
55
  delete record.internalMerge;
@@ -1,11 +1,11 @@
1
- import createDebugLogger from 'debug';
2
- import {marc21GetTagsLegalInd1Value, marc21GetTagsLegalInd2Value, nvdebug} from '../utils.js';
1
+ //import createDebugLogger from 'debug';
2
+ import {marc21GetTagsLegalInd1Value, marc21GetTagsLegalInd2Value} from '../utils.js';
3
3
 
4
4
  // Specs: https://workgroups.helsinki.fi/x/K1ohCw (though we occasionally differ from them)...
5
5
 
6
- const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:merge-fields:mergableIndicator');
6
+ //const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:merge-fields:mergableIndicator');
7
7
  //const debugData = debug.extend('data');
8
- const debugDev = debug.extend('dev');
8
+ //const debugDev = debug.extend('dev');
9
9
 
10
10
  const ind1NonFilingChars = ['130', '630', '730', '740'];
11
11
  const ind2NonFilingChars = ['222', '240', '242', '243', '245', '830'];
@@ -20,7 +20,6 @@ function marc21NoNeedToCheckInd1(tag) {
20
20
 
21
21
  function marc21NoNeedToCheckInd2(tag) {
22
22
  const cands = marc21GetTagsLegalInd2Value(tag);
23
- nvdebug(`CHECK IND2 ${typeof cands} FOR ${tag}`, debugDev);
24
23
  if (typeof cands === 'string') { // single cand
25
24
  return true;
26
25
  }
@@ -7,6 +7,7 @@
7
7
 
8
8
  const defaultNonMergableFields = [
9
9
  '066', // 066 - Character sets present (NR)
10
+ '361',
10
11
  '382', // 382: merging would be madness due to $n position etc...
11
12
  // However, this will miss cases, where only $5 or $9 differs... Such is!
12
13
  // 59X: always copy, never merge. NB! No specs exist!
@@ -52,6 +53,7 @@ const defaultNonMergableFields = [
52
53
  '854',
53
54
  '855',
54
55
  // '856' is mergable, but a pain in the ass
56
+ '857',
55
57
  '863',
56
58
  '864',
57
59
  '865',
@@ -30,9 +30,10 @@ export const mergeConfig = {
30
30
  '246': {'0': 1, '1': 1, '2': 1, '3': 1, '4': 1, '5': 1, '6': 1, '7': 1, '8': 1, ' ': 2},
31
31
  '363': {'0': 1, '1': 1, ' ': 2},
32
32
  '382': {'0': 1, '1': 1, ' ': 2},
33
- '730': ['2', ' ']
33
+ '730': ['2', ' '] // If this is ok, it ok for 700, 710 and 711 as well...
34
34
  },
35
35
  'comment #4': 'List indicators that do not block merge here. Non-filing indicators do not prevent field merge (their support is hard-coded). They are mainly listed here as an example.',
36
+ // Actually I wouldn't want to ignore X00ind1=3 vs other values such as IND1=1... However, this is not currently supported.
36
37
  'ignoreIndicator1': ['100', '110', '111', '130', '210', '242', '245', '246', '247', '307', '490', '505', '506', '510', '511', '516', '520', '521', '522', '524', '526', '583', '586', '600', '610', '630', '650', '651', '655', '700', '710', '730', '740', '760', '762', '765', '767', '770', '772', '773', '774', '775', '776', '777', '780', '785', '786', '787', '788', '800', '810'],
37
38
  'ignoreIndicator2': ['017', '222', '240', '242', '243', '245', '760', '762', '765', '767', '770', '773', '774', '775', '776', '777', '786', '787', '788', '830'],
38
39
  'comment #5': 'If one indicator has value, and the other has not, it does not necessarily mean mismatch',
@@ -3,19 +3,20 @@ const debug = createDebugLogger('@natlibfi/melinda-marc-record-merge-reducers:me
3
3
  //const debugData = debug.extend('data');
4
4
  const debugDev = debug.extend('dev');
5
5
 
6
- // Specs: https://workgroups.helsinki.fi/x/K1ohCw (though we occasionally differ from them)...
7
-
8
- // "key" is an unique key that must match (be absent or exist+be identical) in both.
9
- // "paired" refers to a field that must either exist in both or be absent in both (negative XOR). Typically it's not defined.
6
+ // "required": both fields bust have the subfield and the value must be same.
7
+ // "paired": subfield bust either exists (with value match) or not exist in both fields (negative XOR). Sort of an optional version of 'required'
8
+ // "key": one or both fields lack the subfield OR both fields have it and theor values match.
9
+ // There are typically NR subfields but the system should support multival repeatable subfields. However, (R) support is considered experimental.
10
10
  // NB: key+paired with identical values is an attempt to prevent copy for (ET) fields, and to force separate fields on (T) fields.
11
11
  // NB! If base has eg. no 264, two+ 264 fields can be copied from the source.
12
12
 
13
13
  // NB! not all X00 fields have, say, $x subfield. However, we can still share them...
14
14
  // $h is non-1XX?, $i is 7XX only, $w is 8XX only...
15
- const keyX00 = 'abcjloqrtuwx'; // Shared: $abcdefg...
16
- const keyX10 = 'abcdfghlnoprstuwx';
17
- const keyX11 = 'acdefghlnpqstuwx';
15
+ const keyX00 = 'abcjklnoqrstuwx'; // Shared: $abcdefg...
16
+ const keyX10 = 'abcdfghklnoprstuwx';
17
+ const keyX11 = 'acdefghklnpqstuwx';
18
18
  const keyX30 = 'adfghklmnoprstvwxyz';
19
+ const pairedTitleSubfields = 'iklmnoprst'
19
20
 
20
21
  const mergeConstraints = [
21
22
  {'tag': '010', 'required': 'a', 'key': 'a'},
@@ -24,7 +25,7 @@ const mergeConstraints = [
24
25
  {'tag': '016', 'required': 'a', 'key': 'a2'},
25
26
  {'tag': '017', 'required': 'a', 'key': 'a'},
26
27
  {'tag': '018', 'required': 'a', 'key': 'a'},
27
- {'tag': '020', 'required': '', 'paired': 'a', 'key': 'a'}, // NB! how to handle $z-only cases? 'required-fallback'='z'?
28
+ {'tag': '020', 'required': '', 'paired': 'a', 'key': 'az'}, // NB! $a foo $z lorum and $a foo $z ipsum would not merge! Due to common denominator and f020$z onlies this is the best we can done. This could be handled if 020 would have multiple merge constrains: one for f020$a, and one for f020$z...
28
29
  {'tag': '022', 'required': '', 'paired': 'a', 'key': 'alz'},
29
30
  {'tag': '024', 'required': '', 'paired': 'a', 'key': 'ad'},
30
31
  {'tag': '025', 'required': 'a', 'key': 'a'},
@@ -41,8 +42,8 @@ const mergeConstraints = [
41
42
  {'tag': '037', 'required': 'b', 'key': 'ab'},
42
43
  {'tag': '039', 'required': 'a'},
43
44
  {'tag': '040', 'required': '', 'key': ''},
44
- {'tag': '041', 'required': '', 'paired': '2', 'key': ''}, // Don't put $2 in 'key'! hasCommonNominator() would get into trouble with it...
45
- {'tag': '042', 'required': 'a', 'key': ''}, // NB: preprocessor hacks applied
45
+ {'tag': '041', 'required': '', 'paired': '2', 'key': 'ad'}, // Don't put $2 in 'key'! hasCommonNominator() would get into trouble with it...
46
+ {'tag': '042', 'required': '', 'key': ''}, // Contents (supposedly $a subfields) can be anything, and still merge... (042 $a foo + 042 $b bar is perfectly mergeable)
46
47
  {'tag': '043', 'required': 'a', 'key': 'abc'},
47
48
  {'tag': '044', 'required': '', 'key': 'abc', 'paired': 'abc'},
48
49
  {'tag': '045', 'required': '', 'key': 'abc', 'paired': 'abc'}, // (ET) // 045 is problematic either-$a or $b or $c...
@@ -69,11 +70,11 @@ const mergeConstraints = [
69
70
  {'tag': '086', 'required': '', 'paired': 'a', 'key': 'a'},
70
71
  {'tag': '088', 'required': '', 'paired': 'a', 'key': 'a'},
71
72
  // NB! 100, 110 and 111 may have title parts that are handled elsewhere
72
- {'tag': '100', 'required': 'a', 'paired': 't', 'key': keyX00},
73
- {'tag': '110', 'required': 'a', 'paired': 'bt', 'key': keyX10},
74
- {'tag': '111', 'required': 'a', 'paired': 't', 'key': keyX11},
73
+ {'tag': '100', 'required': 'a', 'paired': `b${pairedTitleSubfields}`, 'key': keyX00},
74
+ {'tag': '110', 'required': 'a', 'paired': `b${pairedTitleSubfields}`, 'key': keyX10},
75
+ {'tag': '111', 'required': 'a', 'paired': pairedTitleSubfields, 'key': keyX11},
75
76
  // NB! 130 has no name part, key is used for title part
76
- {'tag': '130', 'required': 'a', 'key': keyX30},
77
+ {'tag': '130', 'required': 'a', paired: pairedTitleSubfields, 'key': keyX30},
77
78
  {'tag': '210', 'required': 'a', 'key': 'ab'},
78
79
  {'tag': '222', 'required': 'a', 'key': 'ab'},
79
80
  {'tag': '240', 'required': 'a', 'key': 'adfghklmnoprs'},
@@ -95,7 +96,7 @@ const mergeConstraints = [
95
96
  //{'tag': '264', 'required': '', 'paired': 'abc', 'key': 'abc'}, // NB "S.l." normalizations?" not implemented
96
97
  {'tag': '264', 'required': '', 'key': 'abc'}, // NB "S.l." normalizations?" not implemented
97
98
  // SKIP TAG 270 ON PURPOSE! Melinda's N=43.
98
- {'tag': '300', 'required': 'a', 'key': 'abcefg'},
99
+ {'tag': '300', 'required': '', 'key': 'abcefg'},
99
100
  {'tag': '306', 'required': 'a', 'key': 'a'},
100
101
  // SKIP TAG 307 ON PURPOSE! N=0
101
102
  {'tag': '310', 'required': 'a', 'key': 'ab'},
@@ -105,7 +106,7 @@ const mergeConstraints = [
105
106
  {'tag': '337', 'required': 'b2', 'key': 'ab2'}, // MET-88: don't merge different $a subfields
106
107
  {'tag': '338', 'required': 'b2', 'key': 'ab2'}, // / MET-88: don't merge different $a subfields
107
108
  {'tag': '340', 'required': '', 'paired': 'abcdefghijkmnop', 'key': 'abcdefghijkmnop'},
108
- {'tag': '341', 'required': '', 'paired': 'abcde', 'key': 'abcde'}, // NEW! Starting to appear!
109
+ {'tag': '341', 'required': '', 'paired': 'a2', 'key': 'abcde2'}, // NEW! Starting to appear!
109
110
  {'tag': '342', 'required': '', 'paired': 'abcdefghijklmnopqrstuvw', 'key': 'abcdefghijklmnopqrstuvw'}, // SKIP 342. NOT SEEN!
110
111
  {'tag': '343', 'required': '', 'paired': 'abcdefghi', 'key': 'abcdefghi'}, // SKIP 343.
111
112
  {'tag': '344', 'required': '', 'paired': 'abcdefgh', 'key': 'abcdefgh'},
@@ -132,7 +133,7 @@ const mergeConstraints = [
132
133
  {'tag': '385', 'required': 'a', 'paired': 'abmn', 'key': 'abmn'},
133
134
  {'tag': '386', 'required': 'a', 'paired': 'abmn', 'key': 'abmn'},
134
135
  {'tag': '388', 'required': 'a', 'key': 'a'},
135
- {'tag': '490', 'required': 'a', 'key': 'axvl'},
136
+ {'tag': '490', 'required': '', 'key': 'axvl'},
136
137
  {'tag': '500', 'required': 'a', 'key': 'a'},
137
138
  {'tag': '501', 'required': 'a', 'key': 'a'},
138
139
  {'tag': '502', 'required': 'a', 'key': 'abcdgo'},
@@ -195,10 +196,10 @@ const mergeConstraints = [
195
196
  {'tag': '597', 'required': ''},
196
197
  {'tag': '598', 'required': ''},
197
198
  {'tag': '599', 'required': ''},
198
- {'tag': '600', 'required': 'a', 'paired': 'tvxyz', 'key': keyX00},
199
- {'tag': '610', 'required': 'a', 'paired': 'btvxyz', 'key': keyX10},
200
- {'tag': '611', 'required': 'a', 'paired': 'tvxyz', 'key': keyX11},
201
- {'tag': '630', 'required': 'a', 'paired': 'atvxyz', 'key': keyX30},
199
+ {'tag': '600', 'required': 'a', 'paired': `b${pairedTitleSubfields}vxyz`, 'key': keyX00},
200
+ {'tag': '610', 'required': 'a', 'paired': `b${pairedTitleSubfields}vxyz`, 'key': keyX10},
201
+ {'tag': '611', 'required': 'a', 'paired': `${pairedTitleSubfields}vxyz`, 'key': keyX11},
202
+ {'tag': '630', 'required': 'a', 'paired': `${pairedTitleSubfields}vxyz`, 'key': keyX30},
202
203
  // NB! 700, 710 and 711 may have title parts that are handled elsewhere
203
204
  {'tag': '647', 'required': 'a', 'paired': 'avxyz', 'key': 'acdgvxyz02'},
204
205
  {'tag': '648', 'required': 'a', 'paired': 'avxyz', 'key': 'avxyz02'},
@@ -212,12 +213,12 @@ const mergeConstraints = [
212
213
  {'tag': '658', 'required': 'a', 'paired': 'abcd'}, // N=0
213
214
  {'tag': '662', 'required': '', 'paired': 'abcdefgh'}, // N=0
214
215
  {'tag': '688', 'required': 'a'}, // N=0
215
- {'tag': '700', 'required': 'a', 'paired': 't', 'key': keyX00}, // h/i/m/o/r/s/x are missing from 100
216
- {'tag': '710', 'required': 'a', 'paired': 'bt', 'key': keyX10}, // h/j/m/o/r/s/x are missing from 110
217
- {'tag': '711', 'required': 'a', 'paired': 'cdeflns', 'key': keyX11}, // h/i/s/x are missing from 711
216
+ {'tag': '700', 'required': 'a', 'paired': `b${pairedTitleSubfields}x`, 'key': keyX00}, // h/i/m/o/r/s/x are missing from 100, NB! 's' is repeatable, but we are not merging them here!
217
+ {'tag': '710', 'required': 'a', 'paired': `b${pairedTitleSubfields}x`, 'key': keyX10}, // h/j/m/o/r/s/x are missing from 110
218
+ {'tag': '711', 'required': 'a', 'paired': `cdef${pairedTitleSubfields}x`, 'key': keyX11}, // h/i/s/x are missing from 711
218
219
  {'tag': '720', 'required': 'a', 'key': 'a'},
219
220
  // NB! 730 has no name part, key is used for title part
220
- {'tag': '730', 'required': 'a', 'key': keyX30}, // NB: 130->730 magic subfields might not agree...
221
+ {'tag': '730', 'required': 'a', 'paired': `df${pairedTitleSubfields}x`, 'key': keyX30}, // NB: 130->730 magic subfields might not agree...
221
222
  {'tag': '740', 'required': 'a', 'key': 'ahnp'},
222
223
  {'tag': '751', 'required': 'a', 'key': 'a'}, // N=11, kaikissa pelkkä $a
223
224
  {'tag': '752', 'required': '', 'key': 'abcdefgh'}, // N=12234
@@ -242,7 +243,7 @@ const mergeConstraints = [
242
243
  {'tag': '786', 'required': '', 'paired': 'abcrstuxyz', 'key': 'abcdhijmprstuxyz4'},
243
244
  {'tag': '787', 'required': '', 'paired': 'abcdhmstuxyz4'},
244
245
  {'tag': '788', 'required': '', 'paired': 'stx', 'key': 'abdestx'},
245
- {'tag': '800', 'required': 'a', 'paired': 't', 'key': keyX00},
246
+ {'tag': '800', 'required': 'a', 'paired': 'bt', 'key': keyX00},
246
247
  {'tag': '810', 'required': 'a', 'paired': 'bt', 'key': keyX10},
247
248
  {'tag': '811', 'required': 'a', 'paired': 't', 'key': keyX11},
248
249
  {'tag': '830', 'required': 'a', 'key': keyX30},
@@ -289,22 +290,26 @@ const mergeConstraints = [
289
290
  {'tag': 'SID', 'required': ''}
290
291
  ];
291
292
 
292
- function constraintToValue(tagsConstraints, constraintName) {
293
- if (constraintName in tagsConstraints) {
294
- return tagsConstraints[constraintName];
295
- }
296
- return null; // NB! "" might mean "apply to everything" (eg. 040.key) while null means that it is not applied.
297
- }
298
293
 
299
- export function getMergeConstraintsForTag(tag, constraintName) {
294
+ export function getMergeConstraintsForTag(tag, constraintName = undefined) {
300
295
  const tagsConstraintsArray = mergeConstraints.filter(entry => tag === entry.tag);
301
296
  if (tagsConstraintsArray.length === 0) {
302
- debugDev(`WARNING\tNo key found for ${tag}. Returning NULL!`);
303
- return null;
297
+ debugDev(`WARNING\tNo key found for ${tag}!`);
298
+ }
299
+ if (!constraintName) {
300
+ return tagsConstraintsArray;
304
301
  }
305
302
  // NB! should we support multiple contains for a field? Eg. 505$a vs 505($tg)+
306
303
  if (tagsConstraintsArray.length > 1) {
307
304
  debugDev(`WARNING\tMultiple values for '${constraintName}' (N=${tagsConstraintsArray.length}) found in ${tag}. Using first values.`);
308
305
  }
309
- return constraintToValue(tagsConstraintsArray[0], constraintName);
306
+ //return constraintToValue(tagsConstraintsArray[0], constraintName);
307
+ return tagsConstraintsArray.map(c => constraintToValue(c, constraintName));
308
+
309
+ function constraintToValue(tagsConstraints, constraintName) {
310
+ if (constraintName in tagsConstraints) {
311
+ return tagsConstraints[constraintName];
312
+ }
313
+ return null; // NB! "" might mean "apply to everything" (eg. 040.key) while null means that it is not applied.
314
+ }
310
315
  }
@@ -2,19 +2,16 @@
2
2
  import createDebugLogger from 'debug';
3
3
  import {fieldToString, fieldsToString, fieldsAreIdentical, nvdebug, hasCopyright, removeCopyright, subfieldToString} from '../utils.js';
4
4
  import {fieldGetOccurrenceNumberPairs} from '../subfield6Utils.js';
5
- import {cloneAndNormalizeFieldForComparison, cloneAndRemovePunctuation, isEnnakkotietoSubfieldG} from '../normalizeFieldForComparison.js';
5
+ import {cloneAndNormalizeFieldForComparison, cloneAndRemovePunctuation} from '../normalizeFieldForComparison.js';
6
6
  import {mergeOrAddSubfield} from './mergeOrAddSubfield.js';
7
7
  import {mergeIndicators} from './mergeIndicator.js';
8
8
  import {mergableTag} from './mergableTag.js';
9
9
  import {getCounterpart} from './counterpartField.js';
10
+ import {isEnnakkotietoSubfield} from '../prepublicationUtils.js';
10
11
  //import {default as normalizeEncoding} from '@natlibfi/marc-record-validators-melinda/dist/normalize-utf8-diacritics';
11
12
  //import {postprocessRecords} from './mergeOrAddPostprocess.js';
12
13
  //import {preprocessBeforeAdd} from './processFilter.js';
13
14
 
14
- //import fs from 'fs';
15
- //import path from 'path';
16
-
17
-
18
15
  //const defaultConfig = JSON.parse(fs.readFileSync(path.join(__dirname, '..', '..', 'src', 'reducers', 'config.json'), 'utf8'));
19
16
 
20
17
  // Specs: https://workgroups.helsinki.fi/x/K1ohCw (though we occasionally differ from them)...
@@ -25,7 +22,7 @@ const debugDev = debug.extend('dev');
25
22
 
26
23
  // NB! Can we do this via config.json?
27
24
  function removeEnnakkotieto(field) {
28
- const tmp = field.subfields.filter(subfield => !isEnnakkotietoSubfieldG(subfield));
25
+ const tmp = field.subfields.filter(subfield => !isEnnakkotietoSubfield(subfield));
29
26
  // remove only iff some other subfield remains
30
27
  if (tmp.length > 0) {
31
28
  field.subfields = tmp;
@@ -59,7 +56,7 @@ function mergeField2(baseRecord, baseField, sourceField, config, candFieldPairs8
59
56
  // If a base ennakkotieto is merged with real data, remove ennakkotieto subfield:
60
57
  // (If our prepub normalizations are ok, this should not be needed.
61
58
  // However, it's simple and works well enough, so let's keep it here.)
62
- if (baseField.subfields?.find(sf => isEnnakkotietoSubfieldG(sf)) && !sourceField.subfields?.find(sf => isEnnakkotietoSubfieldG(sf))) {
59
+ if (baseField.subfields?.find(sf => isEnnakkotietoSubfield(sf)) && !sourceField.subfields?.find(sf => isEnnakkotietoSubfield(sf))) {
63
60
  removeEnnakkotieto(baseField);
64
61
  baseField.merged = 1;
65
62
  }
@@ -1,12 +1,13 @@
1
1
  import createDebugLogger from 'debug';
2
- import {cloneAndNormalizeFieldForComparison, isEnnakkotietoSubfieldG} from '../normalizeFieldForComparison.js';
2
+ import {cloneAndNormalizeFieldForComparison} from '../normalizeFieldForComparison.js';
3
3
  import {normalizeAs, normalizeControlSubfieldValue} from '../normalize-identifiers.js';
4
- import {fieldHasSubfield, fieldToString, isControlSubfieldCode, nvdebug, subfieldIsRepeatable, subfieldToString} from '../utils.js';
4
+ import {fieldHasSubfield, fieldToString, isContentSubfieldCode, nvdebug, subfieldIsRepeatable, subfieldToString} from '../utils.js';
5
5
  import {mergeSubfield} from './mergeSubfield.js';
6
6
  import {sortAdjacentSubfields} from '../sortSubfields.js';
7
7
 
8
8
  import {valueCarriesMeaning} from './worldKnowledge.js';
9
9
  import {resetSubfield6Tag} from '../subfield6Utils.js';
10
+ import {isEnnakkotietoSubfield} from '../prepublicationUtils.js';
10
11
 
11
12
  const debug = createDebugLogger('@natlibfi/melinda-marc-record-merge-reducers:mergeOrAddSubfield');
12
13
  //const debugData = debug.extend('data');
@@ -25,11 +26,11 @@ function catalogingSourceModifyingAgencyCandIsOriginalCatalogingSourceAgencyInTa
25
26
  return false;
26
27
  }
27
28
 
28
- function ennakkotietoInSubfieldG(candSubfieldData) {
29
- if (isEnnakkotietoSubfieldG({'code': candSubfieldData.code, 'value': candSubfieldData.originalValue})) {
29
+ function dataContainsPrepublicationSubfield(candSubfieldData) {
30
+ if (isEnnakkotietoSubfield({'code': candSubfieldData.code, 'value': candSubfieldData.originalValue})) {
30
31
  // Skip just ‡g subfield or the whole field?
31
32
  // We decided to skip just this subfield. We want at least $0 and maybe even more from ennakkotieto.
32
- debugDev(`Skip '‡g ${candSubfieldData.originalValue}'`);
33
+ debugDev(`Skip '‡${candSubfieldData.code} ${candSubfieldData.originalValue}'`);
33
34
  return true;
34
35
  }
35
36
  return false;
@@ -75,7 +76,7 @@ function skipNormalizedComparison(tag, subfieldCode, subfieldValue) {
75
76
  }
76
77
 
77
78
  function mergeOrAddSubfieldNotRequired(targetField, candSubfieldData) {
78
- if (catalogingSourceModifyingAgencyCandIsOriginalCatalogingSourceAgencyInTargetField(targetField, candSubfieldData) || ennakkotietoInSubfieldG(candSubfieldData)) {
79
+ if (catalogingSourceModifyingAgencyCandIsOriginalCatalogingSourceAgencyInTargetField(targetField, candSubfieldData) || dataContainsPrepublicationSubfield(candSubfieldData)) {
79
80
  return true;
80
81
  }
81
82
 
@@ -126,7 +127,7 @@ function addSubfield(targetField, candSubfield) {
126
127
  }
127
128
 
128
129
  function setPunctuationFlag(field, addedSubfield) {
129
- if (isControlSubfieldCode(addedSubfield.code)) { // These are never punctuation related
130
+ if (!isContentSubfieldCode(addedSubfield.code, field.tag)) { // These are never punctuation related
130
131
  return;
131
132
  }
132
133
  field.useExternalEndPunctuation = 1;
@@ -1,6 +1,6 @@
1
1
  import createDebugLogger from 'debug';
2
2
  import {partsAgree, subfieldContainsPartData} from '../normalizeSubfieldValueForComparison.js';
3
- import {valueCarriesMeaning} from './worldKnowledge.js';
3
+ import {getSynonyms, valueCarriesMeaning} from './worldKnowledge.js';
4
4
  import {nvdebug} from '../utils.js';
5
5
  import {tagAndSubfieldCodeReferToIsbn} from '../normalizeFieldForComparison.js';
6
6
  import {canContainOptionalQualifier, splitToNameAndQualifier} from './counterpartField.js';
@@ -88,7 +88,7 @@ function isPehmeakantinen(value) {
88
88
  return ['mjuka pärmar', 'paperback', 'pehmeäkantinen', 'softcover'].includes(value);
89
89
  }
90
90
 
91
- function isItsenainenJatkoOsa(value) {
91
+ function isItsenainenJatkoOsa(value) { // Probably movable to synonyms...
92
92
  if (value.match(/^Fristående fortsättning på verket[^a-z]*$/ui)) {
93
93
  return true;
94
94
  }
@@ -142,6 +142,15 @@ function pairHttpAndHttps(candSubfield, relevantSubfields) {
142
142
  }
143
143
 
144
144
  function isSynonym(field, candSubfield, relevantSubfields) {
145
+
146
+ const finnishForm = getSynonyms(candSubfield.value, field.tag, candSubfield.code, 'fin');
147
+ if (finnishForm && finnishForm === relevantSubfields.some(sf => finnishForm === getSynonyms(sf.value, field.tag, candSubfield.code, 'fin'))) {
148
+ // NB! There's currently no intelligence (such as checking cat language from 040$b): the preferred value is the one in base.
149
+ // We might later on create a separate translation validator/fixer...
150
+ return true;
151
+ }
152
+
153
+
145
154
  if (candSubfield.code === 'q' && ['015', '020', '024', '028'].includes(field.tag)) {
146
155
  return coverTypesMatch(candSubfield, relevantSubfields);
147
156
  }
@@ -1,4 +1,12 @@
1
- //import {nvdebug} from '../utils';
1
+ //import {nvdebug} from '../utils.js';
2
+ //import createDebugLogger from 'debug';
3
+
4
+ // NB! This file (or at least synonyms) should eventually be moved away from merge to '..'.
5
+
6
+ //const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:worldKnowledge');
7
+ //const debugData = debug.extend('data');
8
+ //const debugDev = debug.extend('dev');
9
+
2
10
 
3
11
  export function valueCarriesMeaning(tag, subfieldCode, value) {
4
12
  // Some data is pretty meaningless and as meaningless is pretty close to nothing, this meaningless data should no prevent merge.
@@ -20,11 +28,77 @@ export function valueCarriesMeaning(tag, subfieldCode, value) {
20
28
  return true;
21
29
  }
22
30
 
31
+ const synonyms = [
32
+ {tags: ['700', '710', '711', '730'], code: 'i', 'fin': 'Sisältää (ekspressio)', 'swe': 'Innehåller (uttryck)'},
33
+ {tags: ['700', '710', '711', '730'], code: 'i', 'fin': 'Sisältää (teos)', 'swe': 'Innehåller (verk)'},
34
+ {tags: ['700', '710', '711', '730'], code: 'l', 'fin': 'Englanti', 'swe': 'Engelska'},
35
+ {tags: ['700', '710', '711', '730'], code: 'l', 'fin': 'Ruotsi', 'swe': 'Svenska'},
36
+ {tags: ['700', '710', '711', '730'], code: 'l', 'fin': 'Suomi', 'swe': 'Finska'}
37
+ // There might eventually be need for a list of terms is given language (eg. engl. paperback and softcover)
38
+ ];
39
+
40
+ export function getSynonyms(term, tag = undefined, subfieldCode = undefined, preferredLanguage = undefined, ignoreCase = true, relevantLanguagesString = 'fin swe',) {
41
+ if (!term) {
42
+ return [];
43
+ }
44
+ //nvdebug(`WP1 CANDS: ${synonyms.length} FOR '${term}'`, debugDev);
45
+ const relevantLanguges = relevantLanguagesString.split(/\s+/u);
46
+ const normalizedTerm = ignoreCase ? term.toLowerCase() : term;
47
+ const synonymsWithTag = tag ? synonyms.filter(s => s.tags.includes(tag)) : synonyms;
48
+ if (synonymsWithTag.length === 0) {
49
+ return [];
50
+ }
51
+ //nvdebug(`WP2 (FILTER ${tag}) CANDS: ${synonymsWithTag.length}`, debugDev);
52
+ const synonymsWithTagAndCode = subfieldCode ? synonymsWithTag.filter(s => s.code === subfieldCode) : synonymsWithTag;
53
+ //nvdebug(`WP3 (FILTER $${subfieldCode}) CANDS: ${synonymsWithTagAndCode.length}:\n${JSON.stringify(synonymsWithTagAndCode)}`, debugDev);
54
+ const matchingSynonyms = synonymsWithTagAndCode.filter(s => termAndLangMatch(s));
55
+
56
+ if (preferredLanguage && matchingSynonyms.length > 0) {
57
+ //console.log(`USING PREFERRED LANG '${preferredLanguage}' for TERM '${term}':\n${JSON.stringify(matchingSynonyms)}`, debugDev);
58
+ return matchingSynonyms.map(s => s[preferredLanguage]);
59
+ }
60
+ return matchingSynonyms;
61
+
62
+ function termAndLangMatch(synonym) {
63
+ if (relevantLanguges.includes('fin')) {
64
+ if (ignoreCase && synonym.fin.toLowerCase() === normalizedTerm ) {
65
+ return true;
66
+ }
67
+ if (!ignoreCase && synonym.fin === term) {
68
+ return true;
69
+ }
70
+ }
71
+
72
+ if (relevantLanguges.includes('swe')) {
73
+ if (ignoreCase && synonym.swe.toLowerCase() === normalizedTerm ) {
74
+ return true;
75
+ }
76
+ if (!ignoreCase && synonym.swe === term) {
77
+ return true;
78
+ }
79
+ }
80
+ return false;
81
+ }
82
+ }
83
+
84
+ export function getSynonym(tag, subfieldCode, originalValue) {
85
+ const finnishForm = getSynonyms(originalValue, tag, subfieldCode, 'fin');
86
+ if (finnishForm.length === 1) {
87
+ //nvdebug(`FINNISH FORM FOR ${tag}$${subfieldCode}: '${finnishForm[0]}'`, debugDev);
88
+ return finnishForm[0];
89
+ }
90
+ return originalValue;
91
+ }
92
+
23
93
  export function normalizeForSamenessCheck(tag, subfieldCode, originalValue) {
24
94
  // NB! These work only for non-repeatable subfields!
25
95
  // Repeatable subfields are currently handled in mergeSubfields.js. Only non-repeatable subfields block field merge,
26
- // (This split is suboptiomal... Minimum fix: make this disctinction cleaner...)
27
- if (subfieldCode === 'a' && ['100', '600', '700', '800'].includes(tag)) {
96
+ // (This split is suboptiomal... Minimum fix: make this distinction cleaner...)
97
+
98
+ //nvdebug(`TRYING TO DO ${tag}$${subfieldCode} '${originalValue}'`, debugDev);
99
+ originalValue = getSynonym(tag, subfieldCode, originalValue);
100
+
101
+ if (subfieldCode === 'a' && ['100', '600', '700', '800'].includes(tag)) { // "Etunimi Sukunimi"...
28
102
  return normalizePersonalName(originalValue);
29
103
  }
30
104
 
@@ -1,10 +1,10 @@
1
- import assert from 'node:assert';
1
+ import assert from 'node:assert/strict';
2
2
  import {MarcRecord} from '@natlibfi/marc-record';
3
3
  import validatorFactory from './merge-fields/index.js';
4
4
  import {READERS} from '@natlibfi/fixura';
5
5
  import generateTests from '@natlibfi/fixugen';
6
6
  import createDebugLogger from 'debug';
7
- import { nvdebug } from './utils.js';
7
+
8
8
 
9
9
  generateTests({
10
10
  callback,
@@ -30,13 +30,8 @@ async function testValidatorFactory() {
30
30
  assert.equal(typeof validator.validate, 'function');
31
31
  }
32
32
 
33
- async function callback({getFixture, enabled = true, fix = false, tagPattern = false}) {
34
- if (enabled === false) {
35
- debug('TEST SKIPPED!');
36
- return;
37
- }
38
-
39
- nvdebug(`TAG PATTERN: ${tagPattern}`);
33
+ async function callback({getFixture, fix = false, tagPattern = false}) {
34
+ debug(`Run test using tag pattern ${tagPattern}`);
40
35
 
41
36
  const validator = await validatorFactory(tagPattern);
42
37
  const record = new MarcRecord(getFixture('record.json'));
@@ -51,5 +46,5 @@ async function callback({getFixture, enabled = true, fix = false, tagPattern = f
51
46
  }
52
47
 
53
48
  await validator.fix(record);
54
- assert.deepEqual(record, expectedResult);
49
+ assert.deepEqual(record, new MarcRecord(expectedResult));
55
50
  }
@@ -3,7 +3,7 @@ import {MarcRecord} from '@natlibfi/marc-record';
3
3
  import validatorFactory from './mergeField500Lisapainokset.js';
4
4
  import {READERS} from '@natlibfi/fixura';
5
5
  import generateTests from '@natlibfi/fixugen';
6
- import createDebugLogger from 'debug';
6
+ //import createDebugLogger from 'debug';
7
7
 
8
8
  generateTests({
9
9
  callback,
@@ -19,7 +19,7 @@ generateTests({
19
19
  }
20
20
  }
21
21
  });
22
- const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda/mergeField500Lisapainokset:test');
22
+ //const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda/mergeField500Lisapainokset:test');
23
23
 
24
24
  async function testValidatorFactory() {
25
25
  const validator = await validatorFactory();
@@ -29,12 +29,7 @@ async function testValidatorFactory() {
29
29
  assert.equal(typeof validator.validate, 'function');
30
30
  }
31
31
 
32
- async function callback({getFixture, enabled = true, fix = false}) {
33
- if (enabled === false) {
34
- debug('TEST SKIPPED!');
35
- return;
36
- }
37
-
32
+ async function callback({getFixture, fix = false}) {
38
33
  const validator = await validatorFactory();
39
34
  const record = new MarcRecord(getFixture('record.json'));
40
35
  const expectedResult = getFixture('expectedResult.json');
@@ -11,11 +11,12 @@ import {fieldFixPunctuation, fieldStripPunctuation} from './punctuation2.js';
11
11
  import {fieldToString, nvdebug} from './utils.js';
12
12
  import {sortAdjacentSubfields} from './sortSubfields.js';
13
13
  import {sortAdjacentRelatorTerms, tagToRelatorTermSubfieldCode} from './sortRelatorTerms.js';
14
- //import createDebugLogger from 'debug';
15
- /*
16
- //const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:mergeRelatorTermFields');
14
+ import createDebugLogger from 'debug';
15
+
16
+ const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:mergeRelatorTermFields');
17
17
  //const debugData = debug.extend('data');
18
- */
18
+ const debugDev = debug.extend('dev');
19
+
19
20
 
20
21
  export default function () {
21
22
 
@@ -80,31 +81,31 @@ function copyRelatorSubfields(fromField, toField) {
80
81
 
81
82
  function mergeRelatorTermFields(record, fix = false) {
82
83
  // NV: 111/711, 751 and 752 where so rare that I did not add them here. Can't remember why I skipped 6XX and 8XX...
83
- let fields = record.get('(?:[17][01]0|720)');
84
+ let fields = record.get('(?:[17][01]0|720)');
84
85
  let result = [];
85
86
  const comparisonFieldsAsString = fields.map(f => fieldToString(createNormalizedCloneWithoutRelatorTerms(f)));
86
87
 
87
- nvdebug(`mergeRelatorTermFields(): ${fields.length} cand field(s) found`);
88
+ nvdebug(`mergeRelatorTermFields(): ${fields.length} cand field(s) found`, debugDev);
88
89
  for(let i=0; i < fields.length-1; i++) {
89
90
  let currField = fields[i];
90
91
  if (currField.deleted) {
91
92
  continue;
92
93
  }
93
- nvdebug(`RT: Trying to pair ${comparisonFieldsAsString[i]}/${i}`);
94
+ nvdebug(`RT: Trying to pair ${comparisonFieldsAsString[i]}/${i}`, debugDev);
94
95
  for (let j=i+1; j < fields.length; j++) {
95
- nvdebug(` Compare with ${comparisonFieldsAsString[j]}/${j}`);
96
+ nvdebug(` Compare with ${comparisonFieldsAsString[j]}/${j}`, debugDev);
96
97
  let mergableField = fields[j];
97
98
  // Skip 1/7 from 1XX/7XX for similarity check:
98
99
  if ( comparisonFieldsAsString[i].substring(1) !== comparisonFieldsAsString[j].substring(1)) {
99
- nvdebug(" NOT PAIR");
100
+ nvdebug(" NOT PAIR", debugDev);
100
101
  continue;
101
102
  }
102
103
  if (mergableField.deleted) {
103
- nvdebug(" DELETED");
104
+ nvdebug(" DELETED", debugDev);
104
105
  continue;
105
106
  }
106
107
  const str = `MERGE RELATOR TERM FIELD: ${fieldToString(mergableField)}`;
107
- nvdebug(str);
108
+ nvdebug(str, debugDev);
108
109
 
109
110
  if(!result.includes(str)) {
110
111
  result.push(str)