@natlibfi/melinda-record-matching 2.0.1 → 2.0.7-alpha.1

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 (96) hide show
  1. package/.github/CODEOWNERS +2 -0
  2. package/.github/dependabot.yml +40 -0
  3. package/.github/workflows/melinda-node-tests.yml +70 -0
  4. package/README.md +1 -1
  5. package/dist/candidate-search/candidate-search-utils.js +3 -6
  6. package/dist/candidate-search/candidate-search-utils.js.map +1 -1
  7. package/dist/candidate-search/index.js +115 -50
  8. package/dist/candidate-search/index.js.map +1 -1
  9. package/dist/candidate-search/index.spec.js +41 -48
  10. package/dist/candidate-search/index.spec.js.map +1 -1
  11. package/dist/candidate-search/query-list/bib.js +154 -64
  12. package/dist/candidate-search/query-list/bib.js.map +1 -1
  13. package/dist/candidate-search/query-list/bib.spec.js +1 -10
  14. package/dist/candidate-search/query-list/bib.spec.js.map +1 -1
  15. package/dist/candidate-search/query-list/index.js +4 -10
  16. package/dist/candidate-search/query-list/index.js.map +1 -1
  17. package/dist/index.js +498 -50
  18. package/dist/index.js.map +1 -1
  19. package/dist/index.spec.js +60 -34
  20. package/dist/index.spec.js.map +1 -1
  21. package/dist/match-detection/features/bib/all-source-ids.js +16 -19
  22. package/dist/match-detection/features/bib/all-source-ids.js.map +1 -1
  23. package/dist/match-detection/features/bib/authors.js +31 -35
  24. package/dist/match-detection/features/bib/authors.js.map +1 -1
  25. package/dist/match-detection/features/bib/bibliographic-level.js +3 -3
  26. package/dist/match-detection/features/bib/bibliographic-level.js.map +1 -1
  27. package/dist/match-detection/features/bib/host-component.js +3 -3
  28. package/dist/match-detection/features/bib/host-component.js.map +1 -1
  29. package/dist/match-detection/features/bib/index.js +28 -13
  30. package/dist/match-detection/features/bib/index.js.map +1 -1
  31. package/dist/match-detection/features/bib/index.spec.js +9 -13
  32. package/dist/match-detection/features/bib/index.spec.js.map +1 -1
  33. package/dist/match-detection/features/bib/isbn.js +28 -6
  34. package/dist/match-detection/features/bib/isbn.js.map +1 -1
  35. package/dist/match-detection/features/bib/issn.js +0 -4
  36. package/dist/match-detection/features/bib/issn.js.map +1 -1
  37. package/dist/match-detection/features/bib/language.js +69 -41
  38. package/dist/match-detection/features/bib/language.js.map +1 -1
  39. package/dist/match-detection/features/bib/media-type.js +83 -0
  40. package/dist/match-detection/features/bib/media-type.js.map +1 -0
  41. package/dist/match-detection/features/bib/melinda-id.js +0 -4
  42. package/dist/match-detection/features/bib/melinda-id.js.map +1 -1
  43. package/dist/match-detection/features/bib/melinda-identifier-factory.js +6 -17
  44. package/dist/match-detection/features/bib/melinda-identifier-factory.js.map +1 -1
  45. package/dist/match-detection/features/bib/other-standard-identifier.js +1 -4
  46. package/dist/match-detection/features/bib/other-standard-identifier.js.map +1 -1
  47. package/dist/match-detection/features/bib/publication-time-allow-cons-years-multi.js +256 -0
  48. package/dist/match-detection/features/bib/publication-time-allow-cons-years-multi.js.map +1 -0
  49. package/dist/match-detection/features/bib/publication-time-allow-cons-years.js +71 -0
  50. package/dist/match-detection/features/bib/publication-time-allow-cons-years.js.map +1 -0
  51. package/dist/match-detection/features/bib/publication-time.js +9 -8
  52. package/dist/match-detection/features/bib/publication-time.js.map +1 -1
  53. package/dist/match-detection/features/bib/record-type.js +6 -3
  54. package/dist/match-detection/features/bib/record-type.js.map +1 -1
  55. package/dist/match-detection/features/bib/standard-identifier-factory.js +129 -39
  56. package/dist/match-detection/features/bib/standard-identifier-factory.js.map +1 -1
  57. package/dist/match-detection/features/bib/title-version-original.js +79 -0
  58. package/dist/match-detection/features/bib/title-version-original.js.map +1 -0
  59. package/dist/match-detection/features/bib/title.js +29 -22
  60. package/dist/match-detection/features/bib/title.js.map +1 -1
  61. package/dist/match-detection/features/index.js +0 -4
  62. package/dist/match-detection/features/index.js.map +1 -1
  63. package/dist/match-detection/index.js +94 -47
  64. package/dist/match-detection/index.js.map +1 -1
  65. package/dist/match-detection/index.spec.js +25 -15
  66. package/dist/match-detection/index.spec.js.map +1 -1
  67. package/dist/matching-utils.js +63 -15
  68. package/dist/matching-utils.js.map +1 -1
  69. package/package.json +27 -24
  70. package/src/candidate-search/index.js +93 -31
  71. package/src/candidate-search/index.spec.js +27 -24
  72. package/src/candidate-search/query-list/bib.js +149 -22
  73. package/src/candidate-search/query-list/index.js +1 -1
  74. package/src/index.js +310 -38
  75. package/src/index.spec.js +49 -21
  76. package/src/match-detection/features/bib/all-source-ids.js +3 -3
  77. package/src/match-detection/features/bib/authors.js +23 -16
  78. package/src/match-detection/features/bib/bibliographic-level.js +1 -1
  79. package/src/match-detection/features/bib/host-component.js +1 -1
  80. package/src/match-detection/features/bib/index.js +4 -0
  81. package/src/match-detection/features/bib/index.spec.js +10 -2
  82. package/src/match-detection/features/bib/isbn.js +21 -2
  83. package/src/match-detection/features/bib/language.js +63 -22
  84. package/src/match-detection/features/bib/media-type.js +77 -0
  85. package/src/match-detection/features/bib/melinda-identifier-factory.js +2 -3
  86. package/src/match-detection/features/bib/other-standard-identifier.js +2 -0
  87. package/src/match-detection/features/bib/publication-time-allow-cons-years-multi.js +268 -0
  88. package/src/match-detection/features/bib/publication-time-allow-cons-years.js +67 -0
  89. package/src/match-detection/features/bib/publication-time.js +9 -4
  90. package/src/match-detection/features/bib/record-type.js +5 -1
  91. package/src/match-detection/features/bib/standard-identifier-factory.js +107 -22
  92. package/src/match-detection/features/bib/title-version-original.js +78 -0
  93. package/src/match-detection/features/bib/title.js +27 -7
  94. package/src/match-detection/index.js +60 -22
  95. package/src/match-detection/index.spec.js +18 -4
  96. package/src/matching-utils.js +62 -5
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _matchingUtils = require("../../../matching-utils");
8
+ var _debug = _interopRequireDefault(require("debug"));
9
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10
+ /**
11
+ *
12
+ * @licstart The following is the entire license notice for the JavaScript code in this file.
13
+ *
14
+ * Melinda record matching modules for Javascript
15
+ *
16
+ * Copyright (C) 2020-2023 University Of Helsinki (The National Library Of Finland)
17
+ *
18
+ * This file is part of melinda-record-matching-js
19
+ *
20
+ * melinda-record-matching-js program is free software: you can redistribute it and/or modify
21
+ * it under the terms of the GNU Lesser General Public License as
22
+ * published by the Free Software Foundation, either version 3 of the
23
+ * License, or (at your option) any later version.
24
+ *
25
+ * melinda-record-matching-js is distributed in the hope that it will be useful,
26
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
27
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28
+ * GNU Lesser General Public License for more details.
29
+ *
30
+ * You should have received a copy of the GNU Affero General Public License
31
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
32
+ *
33
+ * @licend The above is the entire license notice
34
+ * for the JavaScript code in this file.
35
+ *
36
+ */
37
+ // We should also get copyright time and copyright/publication times from 26x
38
+ var _default = () => ({
39
+ name: 'Publication time, allow consequent years',
40
+ extract: ({
41
+ record
42
+ }) => {
43
+ const value = record.get(/^008$/u)?.[0]?.value || undefined;
44
+ return (0, _matchingUtils.testStringOrNumber)(value) ? [String(value).slice(7, 11)] : [];
45
+ },
46
+ compare: (a, b) => {
47
+ const debug = (0, _debug.default)('@natlibfi/melinda-record-matching:match-detection:features/bib/publication-time-allow-cons-years');
48
+ debug(`Comparing ${a[0]} to ${b[0]}`);
49
+ const [firstA] = a;
50
+ const [firstB] = b;
51
+ if (firstA === firstB) {
52
+ return 0.1;
53
+ }
54
+
55
+ // If either of years is a non string/number, values are not comparable
56
+ if (!(0, _matchingUtils.testStringOrNumber)(firstA) || !(0, _matchingUtils.testStringOrNumber)(firstB)) {
57
+ return 0;
58
+ }
59
+ const firstANumber = parseInt(firstA, 10);
60
+ const firstBNumber = parseInt(firstB, 10);
61
+ if (isNaN(firstANumber) || isNaN(firstBNumber)) {
62
+ return -1;
63
+ }
64
+
65
+ // Handle consequent years as a match
66
+ // see publication-time for a version that does not handle consequent years as a match
67
+ return firstANumber + 1 === firstBNumber || firstANumber - 1 === firstBNumber ? 0.1 : -1;
68
+ }
69
+ });
70
+ exports.default = _default;
71
+ //# sourceMappingURL=publication-time-allow-cons-years.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publication-time-allow-cons-years.js","names":["_matchingUtils","require","_debug","_interopRequireDefault","obj","__esModule","default","_default","name","extract","record","value","get","undefined","testStringOrNumber","String","slice","compare","a","b","debug","createDebugLogger","firstA","firstB","firstANumber","parseInt","firstBNumber","isNaN","exports"],"sources":["../../../../src/match-detection/features/bib/publication-time-allow-cons-years.js"],"sourcesContent":["/**\n*\n* @licstart The following is the entire license notice for the JavaScript code in this file.\n*\n* Melinda record matching modules for Javascript\n*\n* Copyright (C) 2020-2023 University Of Helsinki (The National Library Of Finland)\n*\n* This file is part of melinda-record-matching-js\n*\n* melinda-record-matching-js program is free software: you can redistribute it and/or modify\n* it under the terms of the GNU Lesser General Public License as\n* published by the Free Software Foundation, either version 3 of the\n* License, or (at your option) any later version.\n*\n* melinda-record-matching-js is distributed in the hope that it will be useful,\n* but WITHOUT ANY WARRANTY; without even the implied warranty of\n* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n* GNU Lesser General Public License for more details.\n*\n* You should have received a copy of the GNU Affero General Public License\n* along with this program. If not, see <http://www.gnu.org/licenses/>.\n*\n* @licend The above is the entire license notice\n* for the JavaScript code in this file.\n*\n*/\n\nimport {testStringOrNumber} from '../../../matching-utils';\nimport createDebugLogger from 'debug';\n\n// We should also get copyright time and copyright/publication times from 26x\n\nexport default () => ({\n name: 'Publication time, allow consequent years',\n extract: ({record}) => {\n const value = record.get(/^008$/u)?.[0]?.value || undefined;\n return testStringOrNumber(value) ? [String(value).slice(7, 11)] : [];\n },\n compare: (a, b) => {\n const debug = createDebugLogger('@natlibfi/melinda-record-matching:match-detection:features/bib/publication-time-allow-cons-years');\n debug(`Comparing ${a[0]} to ${b[0]}`);\n\n const [firstA] = a;\n const [firstB] = b;\n\n if (firstA === firstB) {\n return 0.1;\n }\n\n // If either of years is a non string/number, values are not comparable\n if (!testStringOrNumber(firstA) || !testStringOrNumber(firstB)) {\n return 0;\n }\n\n const firstANumber = parseInt(firstA, 10);\n const firstBNumber = parseInt(firstB, 10);\n\n if (isNaN(firstANumber) || isNaN(firstBNumber)) {\n return -1;\n }\n\n // Handle consequent years as a match\n // see publication-time for a version that does not handle consequent years as a match\n return firstANumber + 1 === firstBNumber || firstANumber - 1 === firstBNumber ? 0.1 : -1;\n }\n});\n"],"mappings":";;;;;;AA4BA,IAAAA,cAAA,GAAAC,OAAA;AACA,IAAAC,MAAA,GAAAC,sBAAA,CAAAF,OAAA;AAAsC,SAAAE,uBAAAC,GAAA,WAAAA,GAAA,IAAAA,GAAA,CAAAC,UAAA,GAAAD,GAAA,KAAAE,OAAA,EAAAF,GAAA;AA7BtC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;AAAA,IAAAG,QAAA,GAEeA,CAAA,MAAO;EACpBC,IAAI,EAAE,0CAA0C;EAChDC,OAAO,EAAEA,CAAC;IAACC;EAAM,CAAC,KAAK;IACrB,MAAMC,KAAK,GAAGD,MAAM,CAACE,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAED,KAAK,IAAIE,SAAS;IAC3D,OAAO,IAAAC,iCAAkB,EAACH,KAAK,CAAC,GAAG,CAACI,MAAM,CAACJ,KAAK,CAAC,CAACK,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE;EACtE,CAAC;EACDC,OAAO,EAAEA,CAACC,CAAC,EAAEC,CAAC,KAAK;IACjB,MAAMC,KAAK,GAAG,IAAAC,cAAiB,EAAC,kGAAkG,CAAC;IACnID,KAAK,CAAE,aAAYF,CAAC,CAAC,CAAC,CAAE,OAAMC,CAAC,CAAC,CAAC,CAAE,EAAC,CAAC;IAErC,MAAM,CAACG,MAAM,CAAC,GAAGJ,CAAC;IAClB,MAAM,CAACK,MAAM,CAAC,GAAGJ,CAAC;IAElB,IAAIG,MAAM,KAAKC,MAAM,EAAE;MACrB,OAAO,GAAG;IACZ;;IAEA;IACA,IAAI,CAAC,IAAAT,iCAAkB,EAACQ,MAAM,CAAC,IAAI,CAAC,IAAAR,iCAAkB,EAACS,MAAM,CAAC,EAAE;MAC9D,OAAO,CAAC;IACV;IAEA,MAAMC,YAAY,GAAGC,QAAQ,CAACH,MAAM,EAAE,EAAE,CAAC;IACzC,MAAMI,YAAY,GAAGD,QAAQ,CAACF,MAAM,EAAE,EAAE,CAAC;IAEzC,IAAII,KAAK,CAACH,YAAY,CAAC,IAAIG,KAAK,CAACD,YAAY,CAAC,EAAE;MAC9C,OAAO,CAAC,CAAC;IACX;;IAEA;IACA;IACA,OAAOF,YAAY,GAAG,CAAC,KAAKE,YAAY,IAAIF,YAAY,GAAG,CAAC,KAAKE,YAAY,GAAG,GAAG,GAAG,CAAC,CAAC;EAC1F;AACF,CAAC,CAAC;AAAAE,OAAA,CAAAtB,OAAA,GAAAC,QAAA"}
@@ -4,14 +4,14 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
-
7
+ var _matchingUtils = require("../../../matching-utils");
8
8
  /**
9
9
  *
10
10
  * @licstart The following is the entire license notice for the JavaScript code in this file.
11
11
  *
12
12
  * Melinda record matching modules for Javascript
13
13
  *
14
- * Copyright (C) 2020 University Of Helsinki (The National Library Of Finland)
14
+ * Copyright (C) 2020-2022 University Of Helsinki (The National Library Of Finland)
15
15
  *
16
16
  * This file is part of melinda-record-matching-js
17
17
  *
@@ -32,16 +32,17 @@ exports.default = void 0;
32
32
  * for the JavaScript code in this file.
33
33
  *
34
34
  */
35
+ // We should also get copyright time and copyright/publication times from 26x
36
+ // see publication-time-allow-cons-years for a version allowing consequent years to match
35
37
  var _default = () => ({
36
38
  name: 'Publication time',
37
- extract: record => {
38
- var _record$get, _record$get$;
39
-
40
- const value = ((_record$get = record.get(/^008$/u)) === null || _record$get === void 0 ? void 0 : (_record$get$ = _record$get[0]) === null || _record$get$ === void 0 ? void 0 : _record$get$.value) || '';
41
- return value ? [value.slice(7, 11)] : [];
39
+ extract: ({
40
+ record
41
+ }) => {
42
+ const value = record.get(/^008$/u)?.[0]?.value || undefined;
43
+ return (0, _matchingUtils.testStringOrNumber)(value) ? [String(value).slice(7, 11)] : [];
42
44
  },
43
45
  compare: (a, b) => a[0] === b[0] ? 0.1 : -1.0
44
46
  });
45
-
46
47
  exports.default = _default;
47
48
  //# sourceMappingURL=publication-time.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/match-detection/features/bib/publication-time.js"],"names":["name","extract","record","value","get","slice","compare","a","b"],"mappings":";;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;eAEe,OAAO;AACpBA,EAAAA,IAAI,EAAE,kBADc;AAEpBC,EAAAA,OAAO,EAAEC,MAAM,IAAI;AAAA;;AACjB,UAAMC,KAAK,GAAG,gBAAAD,MAAM,CAACE,GAAP,CAAW,QAAX,6EAAuB,CAAvB,+DAA2BD,KAA3B,KAAoC,EAAlD;AACA,WAAOA,KAAK,GAAG,CAACA,KAAK,CAACE,KAAN,CAAY,CAAZ,EAAe,EAAf,CAAD,CAAH,GAA0B,EAAtC;AACD,GALmB;AAMpBC,EAAAA,OAAO,EAAE,CAACC,CAAD,EAAIC,CAAJ,KAAUD,CAAC,CAAC,CAAD,CAAD,KAASC,CAAC,CAAC,CAAD,CAAV,GAAgB,GAAhB,GAAsB,CAAC;AANtB,CAAP,C","sourcesContent":["/**\n*\n* @licstart The following is the entire license notice for the JavaScript code in this file.\n*\n* Melinda record matching modules for Javascript\n*\n* Copyright (C) 2020 University Of Helsinki (The National Library Of Finland)\n*\n* This file is part of melinda-record-matching-js\n*\n* melinda-record-matching-js program is free software: you can redistribute it and/or modify\n* it under the terms of the GNU Lesser General Public License as\n* published by the Free Software Foundation, either version 3 of the\n* License, or (at your option) any later version.\n*\n* melinda-record-matching-js is distributed in the hope that it will be useful,\n* but WITHOUT ANY WARRANTY; without even the implied warranty of\n* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n* GNU Lesser General Public License for more details.\n*\n* You should have received a copy of the GNU Affero General Public License\n* along with this program. If not, see <http://www.gnu.org/licenses/>.\n*\n* @licend The above is the entire license notice\n* for the JavaScript code in this file.\n*\n*/\n\nexport default () => ({\n name: 'Publication time',\n extract: record => {\n const value = record.get(/^008$/u)?.[0]?.value || '';\n return value ? [value.slice(7, 11)] : [];\n },\n compare: (a, b) => a[0] === b[0] ? 0.1 : -1.0\n});\n"],"file":"publication-time.js"}
1
+ {"version":3,"file":"publication-time.js","names":["_matchingUtils","require","_default","name","extract","record","value","get","undefined","testStringOrNumber","String","slice","compare","a","b","exports","default"],"sources":["../../../../src/match-detection/features/bib/publication-time.js"],"sourcesContent":["/**\n*\n* @licstart The following is the entire license notice for the JavaScript code in this file.\n*\n* Melinda record matching modules for Javascript\n*\n* Copyright (C) 2020-2022 University Of Helsinki (The National Library Of Finland)\n*\n* This file is part of melinda-record-matching-js\n*\n* melinda-record-matching-js program is free software: you can redistribute it and/or modify\n* it under the terms of the GNU Lesser General Public License as\n* published by the Free Software Foundation, either version 3 of the\n* License, or (at your option) any later version.\n*\n* melinda-record-matching-js is distributed in the hope that it will be useful,\n* but WITHOUT ANY WARRANTY; without even the implied warranty of\n* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n* GNU Lesser General Public License for more details.\n*\n* You should have received a copy of the GNU Affero General Public License\n* along with this program. If not, see <http://www.gnu.org/licenses/>.\n*\n* @licend The above is the entire license notice\n* for the JavaScript code in this file.\n*\n*/\n\nimport {testStringOrNumber} from '../../../matching-utils';\n\n// We should also get copyright time and copyright/publication times from 26x\n// see publication-time-allow-cons-years for a version allowing consequent years to match\n\nexport default () => ({\n name: 'Publication time',\n extract: ({record}) => {\n const value = record.get(/^008$/u)?.[0]?.value || undefined;\n return testStringOrNumber(value) ? [String(value).slice(7, 11)] : [];\n },\n compare: (a, b) => a[0] === b[0] ? 0.1 : -1.0\n});\n"],"mappings":";;;;;;AA4BA,IAAAA,cAAA,GAAAC,OAAA;AA5BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AAAA,IAAAC,QAAA,GAEeA,CAAA,MAAO;EACpBC,IAAI,EAAE,kBAAkB;EACxBC,OAAO,EAAEA,CAAC;IAACC;EAAM,CAAC,KAAK;IACrB,MAAMC,KAAK,GAAGD,MAAM,CAACE,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAED,KAAK,IAAIE,SAAS;IAC3D,OAAO,IAAAC,iCAAkB,EAACH,KAAK,CAAC,GAAG,CAACI,MAAM,CAACJ,KAAK,CAAC,CAACK,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE;EACtE,CAAC;EACDC,OAAO,EAAEA,CAACC,CAAC,EAAEC,CAAC,KAAKD,CAAC,CAAC,CAAC,CAAC,KAAKC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC;AAC5C,CAAC,CAAC;AAAAC,OAAA,CAAAC,OAAA,GAAAd,QAAA"}
@@ -4,7 +4,6 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
-
8
7
  /**
9
8
  *
10
9
  * @licstart The following is the entire license notice for the JavaScript code in this file.
@@ -32,11 +31,15 @@ exports.default = void 0;
32
31
  * for the JavaScript code in this file.
33
32
  *
34
33
  */
34
+ // we could handle the case of books/notes
35
+ // Recordtype: LDR/06 - Type of Record
36
+ // Note: currently matchValidator fails all mismatching recordTypes, so this won't actually do much
35
37
  var _default = () => ({
36
38
  name: 'Record type',
37
- extract: r => r.leader[6] ? [r.leader[6]] : [],
39
+ extract: ({
40
+ record
41
+ }) => record.leader[6] ? [record.leader[6]] : [],
38
42
  compare: (a, b) => a[0] === b[0] ? 0.1 : -0.5
39
43
  });
40
-
41
44
  exports.default = _default;
42
45
  //# sourceMappingURL=record-type.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/match-detection/features/bib/record-type.js"],"names":["name","extract","r","leader","compare","a","b"],"mappings":";;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;eAEe,OAAO;AACpBA,EAAAA,IAAI,EAAE,aADc;AAEpBC,EAAAA,OAAO,EAAEC,CAAC,IAAIA,CAAC,CAACC,MAAF,CAAS,CAAT,IAAc,CAACD,CAAC,CAACC,MAAF,CAAS,CAAT,CAAD,CAAd,GAA8B,EAFxB;AAGpBC,EAAAA,OAAO,EAAE,CAACC,CAAD,EAAIC,CAAJ,KAAUD,CAAC,CAAC,CAAD,CAAD,KAASC,CAAC,CAAC,CAAD,CAAV,GAAgB,GAAhB,GAAsB,CAAC;AAHtB,CAAP,C","sourcesContent":["/**\n*\n* @licstart The following is the entire license notice for the JavaScript code in this file.\n*\n* Melinda record matching modules for Javascript\n*\n* Copyright (C) 2020 University Of Helsinki (The National Library Of Finland)\n*\n* This file is part of melinda-record-matching-js\n*\n* melinda-record-matching-js program is free software: you can redistribute it and/or modify\n* it under the terms of the GNU Lesser General Public License as\n* published by the Free Software Foundation, either version 3 of the\n* License, or (at your option) any later version.\n*\n* melinda-record-matching-js is distributed in the hope that it will be useful,\n* but WITHOUT ANY WARRANTY; without even the implied warranty of\n* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n* GNU Lesser General Public License for more details.\n*\n* You should have received a copy of the GNU Affero General Public License\n* along with this program. If not, see <http://www.gnu.org/licenses/>.\n*\n* @licend The above is the entire license notice\n* for the JavaScript code in this file.\n*\n*/\n\nexport default () => ({\n name: 'Record type',\n extract: r => r.leader[6] ? [r.leader[6]] : [],\n compare: (a, b) => a[0] === b[0] ? 0.1 : -0.5\n});\n"],"file":"record-type.js"}
1
+ {"version":3,"file":"record-type.js","names":["_default","name","extract","record","leader","compare","a","b","exports","default"],"sources":["../../../../src/match-detection/features/bib/record-type.js"],"sourcesContent":["/**\n*\n* @licstart The following is the entire license notice for the JavaScript code in this file.\n*\n* Melinda record matching modules for Javascript\n*\n* Copyright (C) 2020 University Of Helsinki (The National Library Of Finland)\n*\n* This file is part of melinda-record-matching-js\n*\n* melinda-record-matching-js program is free software: you can redistribute it and/or modify\n* it under the terms of the GNU Lesser General Public License as\n* published by the Free Software Foundation, either version 3 of the\n* License, or (at your option) any later version.\n*\n* melinda-record-matching-js is distributed in the hope that it will be useful,\n* but WITHOUT ANY WARRANTY; without even the implied warranty of\n* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n* GNU Lesser General Public License for more details.\n*\n* You should have received a copy of the GNU Affero General Public License\n* along with this program. If not, see <http://www.gnu.org/licenses/>.\n*\n* @licend The above is the entire license notice\n* for the JavaScript code in this file.\n*\n*/\n\n// we could handle the case of books/notes\n// Recordtype: LDR/06 - Type of Record\n// Note: currently matchValidator fails all mismatching recordTypes, so this won't actually do much\n\nexport default () => ({\n name: 'Record type',\n extract: ({record}) => record.leader[6] ? [record.leader[6]] : [],\n compare: (a, b) => a[0] === b[0] ? 0.1 : -0.5\n});\n"],"mappings":";;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA,IAAAA,QAAA,GAEeA,CAAA,MAAO;EACpBC,IAAI,EAAE,aAAa;EACnBC,OAAO,EAAEA,CAAC;IAACC;EAAM,CAAC,KAAKA,MAAM,CAACC,MAAM,CAAC,CAAC,CAAC,GAAG,CAACD,MAAM,CAACC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE;EACjEC,OAAO,EAAEA,CAACC,CAAC,EAAEC,CAAC,KAAKD,CAAC,CAAC,CAAC,CAAC,KAAKC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC;AAC5C,CAAC,CAAC;AAAAC,OAAA,CAAAC,OAAA,GAAAT,QAAA"}
@@ -4,18 +4,17 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
-
8
7
  var _debug = _interopRequireDefault(require("debug"));
9
-
8
+ var _matchingUtils = require("../../../matching-utils");
10
9
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
-
10
+ /* eslint-disable max-statements */
12
11
  /**
13
12
  *
14
13
  * @licstart The following is the entire license notice for the JavaScript code in this file.
15
14
  *
16
15
  * Melinda record matching modules for Javascript
17
16
  *
18
- * Copyright (C) 2020 University Of Helsinki (The National Library Of Finland)
17
+ * Copyright (C) 2020-2022 University Of Helsinki (The National Library Of Finland)
19
18
  *
20
19
  * This file is part of melinda-record-matching-js
21
20
  *
@@ -36,83 +35,175 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
36
35
  * for the JavaScript code in this file.
37
36
  *
38
37
  */
39
- const debug = (0, _debug.default)('@natlibfi/melinda-record-matching:match-detection:features:standard-identifiers');
40
- const debugData = debug.extend('data');
41
-
38
+ // Note about validity of standardIdentifiers:
39
+ // We have three types of invalid standardIdentifiers:
40
+ // 1. Formally invalid standardIdentifiers (ie. typos either in the resource or the record)
41
+ // 2. Formally valid standardIdentifiers that are used in a wrong resource
42
+ // 3. Canceled standardIdentifiers
43
+ // Matcher could and should check that a standardIdentifier found in a subfield for a valid identifier is formally valid, and if it's not formally valid, handle it as an invalid standardIdentifier
44
+ // Formally valid standardIdentifiers found in subfield for invalid identifier cannot be handled as valid standardIdentifiers, because they can be a case of type 2) or 3) invalid standardIdentifiers
45
+ // We could also do a separate handling for formally valid an formally invalid standardIdentifiers
42
46
  var _default = ({
43
47
  pattern,
44
- subfieldCodes
48
+ subfieldCodes,
49
+ identifier,
50
+ validIdentifierSubfieldCodes = ['a'],
51
+ invalidIdentifierSubfieldCodes = ['z'],
52
+ validatorAndNormalizer = undefined
45
53
  }) => {
54
+ const debug = (0, _debug.default)(`@natlibfi/melinda-record-matching:match-detection:features:standard-identifiers:${identifier}`);
55
+ const debugData = debug.extend('data');
46
56
  return {
47
57
  extract,
48
58
  compare
49
59
  };
50
-
51
- function extract(record) {
52
- const [field] = record.get(pattern);
53
-
54
- if (field) {
55
- return field.subfields.filter(({
56
- code
57
- }) => subfieldCodes.includes(code)).map(({
58
- code,
60
+ function extract({
61
+ record,
62
+ recordExternal
63
+ }) {
64
+ const label = recordExternal && recordExternal.label ? recordExternal.label : 'record';
65
+ const fields = record.get(pattern);
66
+ debugData(`${label}: ${fields.length} ${identifier}-fields `);
67
+
68
+ // extractIdentifierSubfield normalizes hyphens away from the subfield values
69
+ const identifiersFromFields = fields.map(field => (0, _matchingUtils.extractSubfieldsFromField)(field, subfieldCodes));
70
+ debugData(`${label}: IDs from fields (${identifiersFromFields.length}): ${JSON.stringify(identifiersFromFields)}`);
71
+ const allIdentifiers = identifiersFromFields.flat();
72
+ debugData(`${label}: Flat IDs from fields (${allIdentifiers.length}): ${JSON.stringify(allIdentifiers)}`);
73
+ const validatedAndNormalizedIdentifiers = validateAndNormalizeIdentifiers({
74
+ identifierSubs: allIdentifiers,
75
+ validatorAndNormalizer,
76
+ validIdentifierSubfieldCodes,
77
+ invalidIdentifierSubfieldCodes
78
+ });
79
+ const identifiers = (0, _matchingUtils.uniqueSubfields)(validatedAndNormalizedIdentifiers);
80
+ debugData(`${label}: Unique IDs from fields (${identifiers.length}): ${JSON.stringify(identifiers)}`);
81
+ return identifiers;
82
+ function validateAndNormalizeIdentifiers({
83
+ identifierSubs,
84
+ validatorAndNormalizer,
85
+ validIdentifierSubfieldCodes,
86
+ invalidIdentifierSubfieldCodes
87
+ }) {
88
+ if (validatorAndNormalizer) {
89
+ return identifierSubs.map(idSub => validateAndNormalizeIdentifier({
90
+ idSub,
91
+ validatorAndNormalizer,
92
+ validIdentifierSubfieldCodes,
93
+ invalidIdentifierSubfieldCodes
94
+ }));
95
+ }
96
+ return identifierSubs.map(idSub => normalizeHyphens(idSub));
97
+ }
98
+ function validateAndNormalizeIdentifier({
99
+ idSub,
100
+ validatorAndNormalizer,
101
+ validIdentifierSubfieldCodes,
102
+ invalidIdentifierSubfieldCodes
103
+ }) {
104
+ const {
105
+ valid,
106
+ value
107
+ } = validatorAndNormalizer(idSub.value);
108
+ if (validIdentifierSubfieldCodes.includes(idSub.code) && valid === false) {
109
+ const [code] = invalidIdentifierSubfieldCodes;
110
+ return {
111
+ code,
112
+ value
113
+ };
114
+ }
115
+ return {
116
+ code: idSub.code,
59
117
  value
60
- }) => ({
61
- code,
62
- value: value.replace(/-/ug, '')
63
- }));
118
+ };
119
+ }
120
+ function normalizeHyphens(idSub) {
121
+ return {
122
+ code: idSub.code,
123
+ value: idSub.value.replace(/-/ug, '')
124
+ };
64
125
  }
65
-
66
- return [];
67
126
  }
68
-
69
127
  function compare(a, b) {
128
+ debug(`Comparing A and B`);
70
129
  if (a.length === 0 || b.length === 0) {
71
- debugData(`No standardidentifiers to compare`);
130
+ debugData(`No standardidentifiers (${identifier}) to compare`);
72
131
  return 0;
73
132
  }
74
-
133
+ debugData(`A: ${JSON.stringify(a)}`);
134
+ debugData(`B: ${JSON.stringify(b)}`);
75
135
  if (bothHaveValidIdentifiers()) {
136
+ // Compare only valid identifiers, if both have valid idenfiers
76
137
  const {
77
138
  maxValues,
139
+ possibleMatchValues,
78
140
  matchingValues
79
141
  } = getValueCount(true);
80
- return matchingValues / maxValues * 0.75;
142
+ if (matchingValues < 1) {
143
+ debug(`Both have valid standardidentifiers (${identifier}), but none of these match.`);
144
+ return -0.75;
145
+ }
146
+ debug(`Both have valid standardidentifiers (${identifier}), ${matchingValues}/${possibleMatchValues} valid identifiers match.`);
147
+ // ignore non-matches if there is mismatching amount of values
148
+ debug(`Possible matches: ${possibleMatchValues}/${maxValues}`);
149
+ //we give some kind of penalty for mismatching amount of values instead of simple divide?
150
+ const penaltyForMissing = 0.1 * (maxValues - possibleMatchValues);
151
+ const penaltyForMisMatch = 0.2 * (possibleMatchValues - matchingValues);
152
+ debug(`\t points: penaltyForMissing: ${penaltyForMissing}`);
153
+ debug(`\t points: penaltyForMisMatch: ${penaltyForMisMatch}`);
154
+ return 0.75 - penaltyForMisMatch - penaltyForMissing;
155
+ //return matchingValues / possibleMatchValues * 0.75;
81
156
  }
82
-
157
+ // If both do not have valid identifiers, compare all identifiers
83
158
  const {
84
159
  maxValues,
85
160
  matchingValues
86
161
  } = getValueCount();
162
+ debug(`Both do NOT have valid standardidentifiers (${identifier}), ${matchingValues}/${maxValues} valid/invalid identifiers match.`);
87
163
  return matchingValues / maxValues * 0.2;
88
-
89
164
  function bothHaveValidIdentifiers() {
90
165
  const aValues = a.filter(({
91
166
  code
92
- }) => code === 'a');
167
+ }) => validIdentifierSubfieldCodes.includes(code));
93
168
  const bValues = a.filter(({
94
169
  code
95
- }) => code === 'a');
170
+ }) => validIdentifierSubfieldCodes.includes(code));
171
+ debug(`A: ${aValues.length} valid ${identifier} identifiers`);
172
+ debug(`B: ${bValues.length} valid ${identifier} identifiers`);
96
173
  return aValues.length > 0 && bValues.length > 0;
97
174
  }
98
-
99
175
  function getValueCount(validOnly = false) {
100
- const aValues = getIdentifiers(a);
101
- const bValues = getIdentifiers(b);
176
+ const aValues = getIdentifiers(a, validOnly);
177
+ const bValues = getIdentifiers(b, validOnly);
178
+ const matchingValues = getMatchingValuesAmount(aValues, bValues);
102
179
  return {
103
180
  maxValues: aValues.length > bValues.length ? aValues.length : bValues.length,
104
- matchingValues: aValues.filter(aValue => bValues.some(bValue => aValue === bValue)).length
181
+ // possibleMatchingValues: amount of identifiers in set of less identifiers (we cannot more values than these)
182
+ possibleMatchValues: aValues.length > bValues.length ? bValues.length : aValues.length,
183
+ matchingValues
105
184
  };
185
+ function getMatchingValuesAmount(aValues, bValues) {
186
+ if (bValues.length > aValues.length) {
187
+ return aValues.filter(aValue => bValues.some(bValue => aValue === bValue)).length;
188
+ }
189
+ if (aValues.length > bValues.length) {
190
+ return bValues.filter(bValue => aValues.some(aValue => bValue === aValue)).length;
191
+ }
106
192
 
107
- function getIdentifiers(values) {
193
+ // If we have same amount of values, we'll check matches both ways, to avoid mixups in cases
194
+ // there would be duplicate values
195
+ const aToB = aValues.filter(aValue => bValues.some(bValue => aValue === bValue)).length;
196
+ const bToA = bValues.filter(bValue => aValues.some(aValue => bValue === aValue)).length;
197
+ return aToB < bToA ? aToB : bToA;
198
+ }
199
+ function getIdentifiers(values, validOnly) {
108
200
  if (validOnly) {
109
201
  return values.filter(({
110
202
  code
111
- }) => code === 'a').map(({
203
+ }) => validIdentifierSubfieldCodes.includes(code)).map(({
112
204
  value
113
205
  }) => value);
114
206
  }
115
-
116
207
  return values.map(({
117
208
  value
118
209
  }) => value);
@@ -120,6 +211,5 @@ var _default = ({
120
211
  }
121
212
  }
122
213
  };
123
-
124
214
  exports.default = _default;
125
215
  //# sourceMappingURL=standard-identifier-factory.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/match-detection/features/bib/standard-identifier-factory.js"],"names":["debug","debugData","extend","pattern","subfieldCodes","extract","compare","record","field","get","subfields","filter","code","includes","map","value","replace","a","b","length","bothHaveValidIdentifiers","maxValues","matchingValues","getValueCount","aValues","bValues","validOnly","getIdentifiers","aValue","some","bValue","values"],"mappings":"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","sourcesContent":["/**\n*\n* @licstart The following is the entire license notice for the JavaScript code in this file.\n*\n* Melinda record matching modules for Javascript\n*\n* Copyright (C) 2020 University Of Helsinki (The National Library Of Finland)\n*\n* This file is part of melinda-record-matching-js\n*\n* melinda-record-matching-js program is free software: you can redistribute it and/or modify\n* it under the terms of the GNU Lesser General Public License as\n* published by the Free Software Foundation, either version 3 of the\n* License, or (at your option) any later version.\n*\n* melinda-record-matching-js is distributed in the hope that it will be useful,\n* but WITHOUT ANY WARRANTY; without even the implied warranty of\n* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n* GNU Lesser General Public License for more details.\n*\n* You should have received a copy of the GNU Affero General Public License\n* along with this program. If not, see <http://www.gnu.org/licenses/>.\n*\n* @licend The above is the entire license notice\n* for the JavaScript code in this file.\n*\n*/\n\nimport createDebugLogger from 'debug';\n\nconst debug = createDebugLogger('@natlibfi/melinda-record-matching:match-detection:features:standard-identifiers');\nconst debugData = debug.extend('data');\n\nexport default ({pattern, subfieldCodes}) => {\n return {extract, compare};\n\n function extract(record) {\n const [field] = record.get(pattern);\n\n if (field) {\n return field.subfields\n .filter(({code}) => subfieldCodes.includes(code))\n .map(({code, value}) => ({code, value: value.replace(/-/ug, '')}));\n }\n\n return [];\n }\n\n function compare(a, b) {\n if (a.length === 0 || b.length === 0) {\n debugData(`No standardidentifiers to compare`);\n return 0;\n }\n\n if (bothHaveValidIdentifiers()) {\n const {maxValues, matchingValues} = getValueCount(true);\n return matchingValues / maxValues * 0.75;\n }\n\n const {maxValues, matchingValues} = getValueCount();\n return matchingValues / maxValues * 0.2;\n\n function bothHaveValidIdentifiers() {\n const aValues = a.filter(({code}) => code === 'a');\n const bValues = a.filter(({code}) => code === 'a');\n return aValues.length > 0 && bValues.length > 0;\n }\n\n function getValueCount(validOnly = false) {\n const aValues = getIdentifiers(a);\n const bValues = getIdentifiers(b);\n\n return {\n maxValues: aValues.length > bValues.length ? aValues.length : bValues.length,\n matchingValues: aValues.filter(aValue => bValues.some(bValue => aValue === bValue)).length\n };\n\n function getIdentifiers(values) {\n if (validOnly) {\n return values\n .filter(({code}) => code === 'a')\n .map(({value}) => value);\n }\n\n return values.map(({value}) => value);\n }\n }\n }\n};\n"],"file":"standard-identifier-factory.js"}
1
+ {"version":3,"file":"standard-identifier-factory.js","names":["_debug","_interopRequireDefault","require","_matchingUtils","obj","__esModule","default","_default","pattern","subfieldCodes","identifier","validIdentifierSubfieldCodes","invalidIdentifierSubfieldCodes","validatorAndNormalizer","undefined","debug","createDebugLogger","debugData","extend","extract","compare","record","recordExternal","label","fields","get","length","identifiersFromFields","map","field","extractSubfieldsFromField","JSON","stringify","allIdentifiers","flat","validatedAndNormalizedIdentifiers","validateAndNormalizeIdentifiers","identifierSubs","identifiers","uniqueSubfields","idSub","validateAndNormalizeIdentifier","normalizeHyphens","valid","value","includes","code","replace","a","b","bothHaveValidIdentifiers","maxValues","possibleMatchValues","matchingValues","getValueCount","penaltyForMissing","penaltyForMisMatch","aValues","filter","bValues","validOnly","getIdentifiers","getMatchingValuesAmount","aValue","some","bValue","aToB","bToA","values","exports"],"sources":["../../../../src/match-detection/features/bib/standard-identifier-factory.js"],"sourcesContent":["/* eslint-disable max-statements */\n/**\n*\n* @licstart The following is the entire license notice for the JavaScript code in this file.\n*\n* Melinda record matching modules for Javascript\n*\n* Copyright (C) 2020-2022 University Of Helsinki (The National Library Of Finland)\n*\n* This file is part of melinda-record-matching-js\n*\n* melinda-record-matching-js program is free software: you can redistribute it and/or modify\n* it under the terms of the GNU Lesser General Public License as\n* published by the Free Software Foundation, either version 3 of the\n* License, or (at your option) any later version.\n*\n* melinda-record-matching-js is distributed in the hope that it will be useful,\n* but WITHOUT ANY WARRANTY; without even the implied warranty of\n* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n* GNU Lesser General Public License for more details.\n*\n* You should have received a copy of the GNU Affero General Public License\n* along with this program. If not, see <http://www.gnu.org/licenses/>.\n*\n* @licend The above is the entire license notice\n* for the JavaScript code in this file.\n*\n*/\n\nimport createDebugLogger from 'debug';\nimport {extractSubfieldsFromField, uniqueSubfields} from '../../../matching-utils';\n\n// Note about validity of standardIdentifiers:\n// We have three types of invalid standardIdentifiers:\n// 1. Formally invalid standardIdentifiers (ie. typos either in the resource or the record)\n// 2. Formally valid standardIdentifiers that are used in a wrong resource\n// 3. Canceled standardIdentifiers\n\n// Matcher could and should check that a standardIdentifier found in a subfield for a valid identifier is formally valid, and if it's not formally valid, handle it as an invalid standardIdentifier\n// Formally valid standardIdentifiers found in subfield for invalid identifier cannot be handled as valid standardIdentifiers, because they can be a case of type 2) or 3) invalid standardIdentifiers\n// We could also do a separate handling for formally valid an formally invalid standardIdentifiers\n\nexport default ({pattern, subfieldCodes, identifier, validIdentifierSubfieldCodes = ['a'], invalidIdentifierSubfieldCodes = ['z'], validatorAndNormalizer = undefined}) => {\n const debug = createDebugLogger(`@natlibfi/melinda-record-matching:match-detection:features:standard-identifiers:${identifier}`);\n const debugData = debug.extend('data');\n\n return {extract, compare};\n\n function extract({record, recordExternal}) {\n const label = recordExternal && recordExternal.label ? recordExternal.label : 'record';\n const fields = record.get(pattern);\n debugData(`${label}: ${fields.length} ${identifier}-fields `);\n\n // extractIdentifierSubfield normalizes hyphens away from the subfield values\n const identifiersFromFields = fields.map(field => extractSubfieldsFromField(field, subfieldCodes));\n debugData(`${label}: IDs from fields (${identifiersFromFields.length}): ${JSON.stringify(identifiersFromFields)}`);\n const allIdentifiers = identifiersFromFields.flat();\n debugData(`${label}: Flat IDs from fields (${allIdentifiers.length}): ${JSON.stringify(allIdentifiers)}`);\n\n const validatedAndNormalizedIdentifiers = validateAndNormalizeIdentifiers({identifierSubs: allIdentifiers, validatorAndNormalizer, validIdentifierSubfieldCodes, invalidIdentifierSubfieldCodes});\n\n const identifiers = uniqueSubfields(validatedAndNormalizedIdentifiers);\n\n debugData(`${label}: Unique IDs from fields (${identifiers.length}): ${JSON.stringify(identifiers)}`);\n return identifiers;\n\n function validateAndNormalizeIdentifiers({identifierSubs, validatorAndNormalizer, validIdentifierSubfieldCodes, invalidIdentifierSubfieldCodes}) {\n if (validatorAndNormalizer) {\n return identifierSubs.map((idSub) => validateAndNormalizeIdentifier({idSub, validatorAndNormalizer, validIdentifierSubfieldCodes, invalidIdentifierSubfieldCodes}));\n }\n return identifierSubs.map((idSub) => normalizeHyphens(idSub));\n }\n\n function validateAndNormalizeIdentifier({idSub, validatorAndNormalizer, validIdentifierSubfieldCodes, invalidIdentifierSubfieldCodes}) {\n const {valid, value} = validatorAndNormalizer(idSub.value);\n if (validIdentifierSubfieldCodes.includes(idSub.code) && valid === false) {\n const [code] = invalidIdentifierSubfieldCodes;\n return {code, value};\n }\n return {code: idSub.code, value};\n }\n\n function normalizeHyphens(idSub) {\n return {code: idSub.code, value: idSub.value.replace(/-/ug, '')};\n }\n\n\n }\n\n function compare(a, b) {\n debug(`Comparing A and B`);\n if (a.length === 0 || b.length === 0) {\n debugData(`No standardidentifiers (${identifier}) to compare`);\n return 0;\n }\n\n debugData(`A: ${JSON.stringify(a)}`);\n debugData(`B: ${JSON.stringify(b)}`);\n\n\n if (bothHaveValidIdentifiers()) {\n // Compare only valid identifiers, if both have valid idenfiers\n const {maxValues, possibleMatchValues, matchingValues} = getValueCount(true);\n if (matchingValues < 1) {\n debug(`Both have valid standardidentifiers (${identifier}), but none of these match.`);\n return -0.75;\n }\n debug(`Both have valid standardidentifiers (${identifier}), ${matchingValues}/${possibleMatchValues} valid identifiers match.`);\n // ignore non-matches if there is mismatching amount of values\n debug(`Possible matches: ${possibleMatchValues}/${maxValues}`);\n //we give some kind of penalty for mismatching amount of values instead of simple divide?\n const penaltyForMissing = 0.1 * (maxValues - possibleMatchValues);\n const penaltyForMisMatch = 0.2 * (possibleMatchValues - matchingValues);\n debug(`\\t points: penaltyForMissing: ${penaltyForMissing}`);\n debug(`\\t points: penaltyForMisMatch: ${penaltyForMisMatch}`);\n\n return 0.75 - penaltyForMisMatch - penaltyForMissing;\n //return matchingValues / possibleMatchValues * 0.75;\n }\n // If both do not have valid identifiers, compare all identifiers\n const {maxValues, matchingValues} = getValueCount();\n debug(`Both do NOT have valid standardidentifiers (${identifier}), ${matchingValues}/${maxValues} valid/invalid identifiers match.`);\n\n return matchingValues / maxValues * 0.2;\n\n function bothHaveValidIdentifiers() {\n const aValues = a.filter(({code}) => validIdentifierSubfieldCodes.includes(code));\n const bValues = a.filter(({code}) => validIdentifierSubfieldCodes.includes(code));\n debug(`A: ${aValues.length} valid ${identifier} identifiers`);\n debug(`B: ${bValues.length} valid ${identifier} identifiers`);\n return aValues.length > 0 && bValues.length > 0;\n }\n\n function getValueCount(validOnly = false) {\n const aValues = getIdentifiers(a, validOnly);\n const bValues = getIdentifiers(b, validOnly);\n\n const matchingValues = getMatchingValuesAmount(aValues, bValues);\n\n return {\n maxValues: aValues.length > bValues.length ? aValues.length : bValues.length,\n // possibleMatchingValues: amount of identifiers in set of less identifiers (we cannot more values than these)\n possibleMatchValues: aValues.length > bValues.length ? bValues.length : aValues.length,\n matchingValues\n };\n\n function getMatchingValuesAmount(aValues, bValues) {\n if (bValues.length > aValues.length) {\n return aValues.filter(aValue => bValues.some(bValue => aValue === bValue)).length;\n }\n if (aValues.length > bValues.length) {\n return bValues.filter(bValue => aValues.some(aValue => bValue === aValue)).length;\n }\n\n // If we have same amount of values, we'll check matches both ways, to avoid mixups in cases\n // there would be duplicate values\n const aToB = aValues.filter(aValue => bValues.some(bValue => aValue === bValue)).length;\n const bToA = bValues.filter(bValue => aValues.some(aValue => bValue === aValue)).length;\n\n return aToB < bToA ? aToB : bToA;\n }\n\n function getIdentifiers(values, validOnly) {\n if (validOnly) {\n return values\n .filter(({code}) => validIdentifierSubfieldCodes.includes(code))\n .map(({value}) => value);\n }\n\n return values.map(({value}) => value);\n }\n }\n }\n};\n"],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _debug = _interopRequireDefault(require("debug"));
8
+ var _natural = require("natural");
9
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10
+ /**
11
+ *
12
+ * @licstart The following is the entire license notice for the JavaScript code in this file.
13
+ *
14
+ * Melinda record matching modules for Javascript
15
+ *
16
+ * Copyright (C) 2020 University Of Helsinki (The National Library Of Finland)
17
+ *
18
+ * This file is part of melinda-record-matching-js
19
+ *
20
+ * melinda-record-matching-js program is free software: you can redistribute it and/or modify
21
+ * it under the terms of the GNU Lesser General Public License as
22
+ * published by the Free Software Foundation, either version 3 of the
23
+ * License, or (at your option) any later version.
24
+ *
25
+ * melinda-record-matching-js is distributed in the hope that it will be useful,
26
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
27
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28
+ * GNU Lesser General Public License for more details.
29
+ *
30
+ * You should have received a copy of the GNU Affero General Public License
31
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
32
+ *
33
+ * @licend The above is the entire license notice
34
+ * for the JavaScript code in this file.
35
+ *
36
+ */
37
+ var _default = ({
38
+ treshold = 10
39
+ } = {}) => ({
40
+ name: 'titleVersionOriginal',
41
+ extract: ({
42
+ record
43
+ }) => {
44
+ const title = getTitle();
45
+ if (title) {
46
+ return [title.replace(/[^\p{Letter}\p{Number}]/gu, '').toLowerCase()];
47
+ }
48
+ return [];
49
+ function getTitle() {
50
+ const [field] = record.get(/^245$/u);
51
+ if (field) {
52
+ return field.subfields.filter(({
53
+ code
54
+ }) => ['a', 'b'].includes(code)).map(({
55
+ value
56
+ }) => value).join('');
57
+ }
58
+ }
59
+ },
60
+ compare: (a, b) => {
61
+ const debug = (0, _debug.default)('@natlibfi/melinda-record-matching:match-detection:features/bib/title-version-original');
62
+ const distance = (0, _natural.LevenshteinDistance)(a[0], b[0]);
63
+ if (distance === 0) {
64
+ return 0.5;
65
+ }
66
+ const maxLength = getMaxLength();
67
+ const percentage = distance / maxLength * 100;
68
+ debug(`'${a}' vs '${b}': Max length = ${maxLength}, distance = ${distance}, percentage = ${percentage}`);
69
+ if (percentage <= treshold) {
70
+ return 0.3;
71
+ }
72
+ return -0.5;
73
+ function getMaxLength() {
74
+ return a[0].length > b[0].length ? a[0].length : b[0].length;
75
+ }
76
+ }
77
+ });
78
+ exports.default = _default;
79
+ //# sourceMappingURL=title-version-original.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"title-version-original.js","names":["_debug","_interopRequireDefault","require","_natural","obj","__esModule","default","_default","treshold","name","extract","record","title","getTitle","replace","toLowerCase","field","get","subfields","filter","code","includes","map","value","join","compare","a","b","debug","createDebugLogger","distance","leven","maxLength","getMaxLength","percentage","length","exports"],"sources":["../../../../src/match-detection/features/bib/title-version-original.js"],"sourcesContent":["/**\n*\n* @licstart The following is the entire license notice for the JavaScript code in this file.\n*\n* Melinda record matching modules for Javascript\n*\n* Copyright (C) 2020 University Of Helsinki (The National Library Of Finland)\n*\n* This file is part of melinda-record-matching-js\n*\n* melinda-record-matching-js program is free software: you can redistribute it and/or modify\n* it under the terms of the GNU Lesser General Public License as\n* published by the Free Software Foundation, either version 3 of the\n* License, or (at your option) any later version.\n*\n* melinda-record-matching-js is distributed in the hope that it will be useful,\n* but WITHOUT ANY WARRANTY; without even the implied warranty of\n* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n* GNU Lesser General Public License for more details.\n*\n* You should have received a copy of the GNU Affero General Public License\n* along with this program. If not, see <http://www.gnu.org/licenses/>.\n*\n* @licend The above is the entire license notice\n* for the JavaScript code in this file.\n*\n*/\n\nimport createDebugLogger from 'debug';\nimport {LevenshteinDistance as leven} from 'natural';\n\nexport default ({treshold = 10} = {}) => ({\n name: 'titleVersionOriginal',\n extract: ({record}) => {\n const title = getTitle();\n\n if (title) {\n return [title.replace(/[^\\p{Letter}\\p{Number}]/gu, '').toLowerCase()];\n }\n\n return [];\n\n function getTitle() {\n const [field] = record.get(/^245$/u);\n\n if (field) {\n return field.subfields\n .filter(({code}) => ['a', 'b'].includes(code))\n .map(({value}) => value)\n .join('');\n }\n }\n },\n compare: (a, b) => {\n const debug = createDebugLogger('@natlibfi/melinda-record-matching:match-detection:features/bib/title-version-original');\n const distance = leven(a[0], b[0]);\n\n if (distance === 0) {\n return 0.5;\n }\n\n const maxLength = getMaxLength();\n const percentage = distance / maxLength * 100;\n\n debug(`'${a}' vs '${b}': Max length = ${maxLength}, distance = ${distance}, percentage = ${percentage}`);\n\n if (percentage <= treshold) {\n return 0.3;\n }\n\n return -0.5;\n\n function getMaxLength() {\n return a[0].length > b[0].length ? a[0].length : b[0].length;\n }\n\n }\n});\n"],"mappings":";;;;;;AA4BA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,QAAA,GAAAD,OAAA;AAAqD,SAAAD,uBAAAG,GAAA,WAAAA,GAAA,IAAAA,GAAA,CAAAC,UAAA,GAAAD,GAAA,KAAAE,OAAA,EAAAF,GAAA;AA7BrD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA1BA,IAAAG,QAAA,GA+BeA,CAAC;EAACC,QAAQ,GAAG;AAAE,CAAC,GAAG,CAAC,CAAC,MAAM;EACxCC,IAAI,EAAE,sBAAsB;EAC5BC,OAAO,EAAEA,CAAC;IAACC;EAAM,CAAC,KAAK;IACrB,MAAMC,KAAK,GAAGC,QAAQ,CAAC,CAAC;IAExB,IAAID,KAAK,EAAE;MACT,OAAO,CAACA,KAAK,CAACE,OAAO,CAAC,2BAA2B,EAAE,EAAE,CAAC,CAACC,WAAW,CAAC,CAAC,CAAC;IACvE;IAEA,OAAO,EAAE;IAET,SAASF,QAAQA,CAAA,EAAG;MAClB,MAAM,CAACG,KAAK,CAAC,GAAGL,MAAM,CAACM,GAAG,CAAC,QAAQ,CAAC;MAEpC,IAAID,KAAK,EAAE;QACT,OAAOA,KAAK,CAACE,SAAS,CACnBC,MAAM,CAAC,CAAC;UAACC;QAAI,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAACC,QAAQ,CAACD,IAAI,CAAC,CAAC,CAC7CE,GAAG,CAAC,CAAC;UAACC;QAAK,CAAC,KAAKA,KAAK,CAAC,CACvBC,IAAI,CAAC,EAAE,CAAC;MACb;IACF;EACF,CAAC;EACDC,OAAO,EAAEA,CAACC,CAAC,EAAEC,CAAC,KAAK;IACjB,MAAMC,KAAK,GAAG,IAAAC,cAAiB,EAAC,uFAAuF,CAAC;IACxH,MAAMC,QAAQ,GAAG,IAAAC,4BAAK,EAACL,CAAC,CAAC,CAAC,CAAC,EAAEC,CAAC,CAAC,CAAC,CAAC,CAAC;IAElC,IAAIG,QAAQ,KAAK,CAAC,EAAE;MAClB,OAAO,GAAG;IACZ;IAEA,MAAME,SAAS,GAAGC,YAAY,CAAC,CAAC;IAChC,MAAMC,UAAU,GAAGJ,QAAQ,GAAGE,SAAS,GAAG,GAAG;IAE7CJ,KAAK,CAAE,IAAGF,CAAE,SAAQC,CAAE,mBAAkBK,SAAU,gBAAeF,QAAS,kBAAiBI,UAAW,EAAC,CAAC;IAExG,IAAIA,UAAU,IAAI1B,QAAQ,EAAE;MAC1B,OAAO,GAAG;IACZ;IAEA,OAAO,CAAC,GAAG;IAEX,SAASyB,YAAYA,CAAA,EAAG;MACtB,OAAOP,CAAC,CAAC,CAAC,CAAC,CAACS,MAAM,GAAGR,CAAC,CAAC,CAAC,CAAC,CAACQ,MAAM,GAAGT,CAAC,CAAC,CAAC,CAAC,CAACS,MAAM,GAAGR,CAAC,CAAC,CAAC,CAAC,CAACQ,MAAM;IAC9D;EAEF;AACF,CAAC,CAAC;AAAAC,OAAA,CAAA9B,OAAA,GAAAC,QAAA"}