@natlibfi/melinda-record-matching 4.3.5 → 5.0.0-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 (101) hide show
  1. package/.github/workflows/melinda-node-tests.yml +11 -7
  2. package/eslint.config.js +52 -0
  3. package/example.env +4 -0
  4. package/package.json +22 -90
  5. package/src/candidate-search/choose-queries.js +1 -3
  6. package/src/candidate-search/index.js +63 -89
  7. package/src/candidate-search/{index.spec.js → index.test.js} +19 -18
  8. package/src/candidate-search/query-list/bib.js +10 -4
  9. package/src/candidate-search/query-list/{bib.spec.js → bib.test.js} +8 -7
  10. package/src/candidate-search/query-list/component.js +127 -0
  11. package/src/candidate-search/query-list/index.js +23 -9
  12. package/src/cli.js +177 -0
  13. package/src/index.js +22 -37
  14. package/src/{index.spec.js → index.test.js} +11 -14
  15. package/src/match-detection/features/bib/all-source-ids.js +2 -2
  16. package/src/match-detection/features/bib/authors.js +3 -2
  17. package/src/match-detection/features/bib/index.js +16 -16
  18. package/src/match-detection/features/bib/{index.spec.js → index.test.js} +7 -6
  19. package/src/match-detection/features/bib/isbn.js +2 -2
  20. package/src/match-detection/features/bib/issn.js +1 -1
  21. package/src/match-detection/features/bib/language.js +5 -5
  22. package/src/match-detection/features/bib/media-type.js +1 -1
  23. package/src/match-detection/features/bib/melinda-id.js +1 -1
  24. package/src/match-detection/features/bib/melinda-identifier-factory.js +5 -5
  25. package/src/match-detection/features/bib/other-standard-identifier.js +1 -1
  26. package/src/match-detection/features/bib/publication-time-allow-cons-years-multi.js +6 -6
  27. package/src/match-detection/features/bib/publication-time-allow-cons-years.js +1 -1
  28. package/src/match-detection/features/bib/publication-time.js +1 -1
  29. package/src/match-detection/features/bib/standard-identifier-factory.js +1 -2
  30. package/src/match-detection/features/bib/title-version-original.js +2 -1
  31. package/src/match-detection/features/bib/title.js +6 -5
  32. package/src/match-detection/features/index.js +1 -1
  33. package/src/match-detection/index.js +1 -1
  34. package/src/match-detection/{index.spec.js → index.test.js} +9 -8
  35. package/src/matching-utils.js +8 -9
  36. package/dist/candidate-search/candidate-search-utils.js +0 -29
  37. package/dist/candidate-search/candidate-search-utils.js.map +0 -1
  38. package/dist/candidate-search/choose-queries.js +0 -122
  39. package/dist/candidate-search/choose-queries.js.map +0 -1
  40. package/dist/candidate-search/index.js +0 -260
  41. package/dist/candidate-search/index.js.map +0 -1
  42. package/dist/candidate-search/index.spec.js +0 -133
  43. package/dist/candidate-search/index.spec.js.map +0 -1
  44. package/dist/candidate-search/query-list/bib.js +0 -458
  45. package/dist/candidate-search/query-list/bib.js.map +0 -1
  46. package/dist/candidate-search/query-list/bib.spec.js +0 -46
  47. package/dist/candidate-search/query-list/bib.spec.js.map +0 -1
  48. package/dist/candidate-search/query-list/index.js +0 -47
  49. package/dist/candidate-search/query-list/index.js.map +0 -1
  50. package/dist/index.js +0 -555
  51. package/dist/index.js.map +0 -1
  52. package/dist/index.spec.js +0 -99
  53. package/dist/index.spec.js.map +0 -1
  54. package/dist/match-detection/features/bib/all-source-ids.js +0 -91
  55. package/dist/match-detection/features/bib/all-source-ids.js.map +0 -1
  56. package/dist/match-detection/features/bib/authors.js +0 -86
  57. package/dist/match-detection/features/bib/authors.js.map +0 -1
  58. package/dist/match-detection/features/bib/bibliographic-level.js +0 -15
  59. package/dist/match-detection/features/bib/bibliographic-level.js.map +0 -1
  60. package/dist/match-detection/features/bib/host-component.js +0 -15
  61. package/dist/match-detection/features/bib/host-component.js.map +0 -1
  62. package/dist/match-detection/features/bib/index.js +0 -119
  63. package/dist/match-detection/features/bib/index.js.map +0 -1
  64. package/dist/match-detection/features/bib/index.spec.js +0 -65
  65. package/dist/match-detection/features/bib/index.spec.js.map +0 -1
  66. package/dist/match-detection/features/bib/isbn.js +0 -49
  67. package/dist/match-detection/features/bib/isbn.js.map +0 -1
  68. package/dist/match-detection/features/bib/issn.js +0 -24
  69. package/dist/match-detection/features/bib/issn.js.map +0 -1
  70. package/dist/match-detection/features/bib/language.js +0 -113
  71. package/dist/match-detection/features/bib/language.js.map +0 -1
  72. package/dist/match-detection/features/bib/media-type.js +0 -56
  73. package/dist/match-detection/features/bib/media-type.js.map +0 -1
  74. package/dist/match-detection/features/bib/melinda-id.js +0 -21
  75. package/dist/match-detection/features/bib/melinda-id.js.map +0 -1
  76. package/dist/match-detection/features/bib/melinda-identifier-factory.js +0 -62
  77. package/dist/match-detection/features/bib/melinda-identifier-factory.js.map +0 -1
  78. package/dist/match-detection/features/bib/other-standard-identifier.js +0 -25
  79. package/dist/match-detection/features/bib/other-standard-identifier.js.map +0 -1
  80. package/dist/match-detection/features/bib/publication-time-allow-cons-years-multi.js +0 -229
  81. package/dist/match-detection/features/bib/publication-time-allow-cons-years-multi.js.map +0 -1
  82. package/dist/match-detection/features/bib/publication-time-allow-cons-years.js +0 -44
  83. package/dist/match-detection/features/bib/publication-time-allow-cons-years.js.map +0 -1
  84. package/dist/match-detection/features/bib/publication-time.js +0 -21
  85. package/dist/match-detection/features/bib/publication-time.js.map +0 -1
  86. package/dist/match-detection/features/bib/record-type.js +0 -18
  87. package/dist/match-detection/features/bib/record-type.js.map +0 -1
  88. package/dist/match-detection/features/bib/standard-identifier-factory.js +0 -188
  89. package/dist/match-detection/features/bib/standard-identifier-factory.js.map +0 -1
  90. package/dist/match-detection/features/bib/title-version-original.js +0 -52
  91. package/dist/match-detection/features/bib/title-version-original.js.map +0 -1
  92. package/dist/match-detection/features/bib/title.js +0 -70
  93. package/dist/match-detection/features/bib/title.js.map +0 -1
  94. package/dist/match-detection/features/index.js +0 -11
  95. package/dist/match-detection/features/index.js.map +0 -1
  96. package/dist/match-detection/index.js +0 -174
  97. package/dist/match-detection/index.js.map +0 -1
  98. package/dist/match-detection/index.spec.js +0 -63
  99. package/dist/match-detection/index.spec.js.map +0 -1
  100. package/dist/matching-utils.js +0 -115
  101. package/dist/matching-utils.js.map +0 -1
@@ -1,44 +0,0 @@
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(e) { return e && e.__esModule ? e : { default: e }; }
10
- // We should also get copyright time and copyright/publication times from 26x
11
- var _default = () => ({
12
- name: 'Publication time, allow consequent years',
13
- extract: ({
14
- record
15
- }) => {
16
- const value = record.get(/^008$/u)?.[0]?.value || undefined;
17
- return (0, _matchingUtils.testStringOrNumber)(value) ? [String(value).slice(7, 11)] : [];
18
- },
19
- compare: (a, b) => {
20
- const debug = (0, _debug.default)('@natlibfi/melinda-record-matching:match-detection:features/bib/publication-time-allow-cons-years');
21
- debug(`Comparing ${a[0]} to ${b[0]}`);
22
- const [firstA] = a;
23
- const [firstB] = b;
24
- if (firstA === firstB) {
25
- return 0.1;
26
- }
27
-
28
- // If either of years is a non string/number, values are not comparable
29
- if (!(0, _matchingUtils.testStringOrNumber)(firstA) || !(0, _matchingUtils.testStringOrNumber)(firstB)) {
30
- return 0;
31
- }
32
- const firstANumber = parseInt(firstA, 10);
33
- const firstBNumber = parseInt(firstB, 10);
34
- if (isNaN(firstANumber) || isNaN(firstBNumber)) {
35
- return -1;
36
- }
37
-
38
- // Handle consequent years as a match
39
- // see publication-time for a version that does not handle consequent years as a match
40
- return firstANumber + 1 === firstBNumber || firstANumber - 1 === firstBNumber ? 0.1 : -1;
41
- }
42
- });
43
- exports.default = _default;
44
- //# sourceMappingURL=publication-time-allow-cons-years.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"publication-time-allow-cons-years.js","names":["_matchingUtils","require","_debug","_interopRequireDefault","e","__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":["\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":";;;;;;AACA,IAAAA,cAAA,GAAAC,OAAA;AACA,IAAAC,MAAA,GAAAC,sBAAA,CAAAF,OAAA;AAAsC,SAAAE,uBAAAC,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAEtC;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,CAAC,aAAaF,CAAC,CAAC,CAAC,CAAC,OAAOC,CAAC,CAAC,CAAC,CAAC,EAAE,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","ignoreList":[]}
@@ -1,21 +0,0 @@
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
- // We should also get copyright time and copyright/publication times from 26x
9
- // see publication-time-allow-cons-years for a version allowing consequent years to match
10
- var _default = () => ({
11
- name: 'Publication time',
12
- extract: ({
13
- record
14
- }) => {
15
- const value = record.get(/^008$/u)?.[0]?.value || undefined;
16
- return (0, _matchingUtils.testStringOrNumber)(value) ? [String(value).slice(7, 11)] : [];
17
- },
18
- compare: (a, b) => a[0] === b[0] ? 0.1 : -1.0
19
- });
20
- exports.default = _default;
21
- //# sourceMappingURL=publication-time.js.map
@@ -1 +0,0 @@
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\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":";;;;;;AAEA,IAAAA,cAAA,GAAAC,OAAA;AAEA;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","ignoreList":[]}
@@ -1,18 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
- // we could handle the case of books/notes
8
- // Recordtype: LDR/06 - Type of Record
9
- // Note: currently matchValidator fails all mismatching recordTypes, so this won't actually do much
10
- var _default = () => ({
11
- name: 'Record type',
12
- extract: ({
13
- record
14
- }) => record.leader[6] ? [record.leader[6]] : [],
15
- compare: (a, b) => a[0] === b[0] ? 0.1 : -0.5
16
- });
17
- exports.default = _default;
18
- //# sourceMappingURL=record-type.js.map
@@ -1 +0,0 @@
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// 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":";;;;;;AACA;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","ignoreList":[]}
@@ -1,188 +0,0 @@
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 _matchingUtils = require("../../../matching-utils");
9
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
- /* eslint-disable max-statements */
11
- // Note about validity of standardIdentifiers:
12
- // We have three types of invalid standardIdentifiers:
13
- // 1. Formally invalid standardIdentifiers (ie. typos either in the resource or the record)
14
- // 2. Formally valid standardIdentifiers that are used in a wrong resource
15
- // 3. Canceled standardIdentifiers
16
- // 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
17
- // 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
18
- // We could also do a separate handling for formally valid an formally invalid standardIdentifiers
19
- var _default = ({
20
- pattern,
21
- subfieldCodes,
22
- identifier,
23
- validIdentifierSubfieldCodes = ['a'],
24
- invalidIdentifierSubfieldCodes = ['z'],
25
- validatorAndNormalizer = undefined
26
- }) => {
27
- const debug = (0, _debug.default)(`@natlibfi/melinda-record-matching:match-detection:features:standard-identifiers:${identifier}`);
28
- const debugData = debug.extend('data');
29
- return {
30
- extract,
31
- compare
32
- };
33
- function extract({
34
- record,
35
- recordExternal
36
- }) {
37
- const label = recordExternal && recordExternal.label ? recordExternal.label : 'record';
38
- const fields = record.get(pattern);
39
- debugData(`${label}: ${fields.length} ${identifier}-fields `);
40
-
41
- // extractIdentifierSubfield normalizes hyphens away from the subfield values
42
- const identifiersFromFields = fields.map(field => (0, _matchingUtils.extractSubfieldsFromField)(field, subfieldCodes));
43
- debugData(`${label}: IDs from fields (${identifiersFromFields.length}): ${JSON.stringify(identifiersFromFields)}`);
44
- const allIdentifiers = identifiersFromFields.flat();
45
- debugData(`${label}: Flat IDs from fields (${allIdentifiers.length}): ${JSON.stringify(allIdentifiers)}`);
46
- const validatedAndNormalizedIdentifiers = validateAndNormalizeIdentifiers({
47
- identifierSubs: allIdentifiers,
48
- validatorAndNormalizer,
49
- validIdentifierSubfieldCodes,
50
- invalidIdentifierSubfieldCodes
51
- });
52
- const identifiers = (0, _matchingUtils.uniqueSubfields)(validatedAndNormalizedIdentifiers);
53
- debugData(`${label}: Unique IDs from fields (${identifiers.length}): ${JSON.stringify(identifiers)}`);
54
- return identifiers;
55
- function validateAndNormalizeIdentifiers({
56
- identifierSubs,
57
- validatorAndNormalizer,
58
- validIdentifierSubfieldCodes,
59
- invalidIdentifierSubfieldCodes
60
- }) {
61
- if (validatorAndNormalizer) {
62
- return identifierSubs.map(idSub => validateAndNormalizeIdentifier({
63
- idSub,
64
- validatorAndNormalizer,
65
- validIdentifierSubfieldCodes,
66
- invalidIdentifierSubfieldCodes
67
- }));
68
- }
69
- return identifierSubs.map(idSub => normalizeHyphens(idSub));
70
- }
71
- function validateAndNormalizeIdentifier({
72
- idSub,
73
- validatorAndNormalizer,
74
- validIdentifierSubfieldCodes,
75
- invalidIdentifierSubfieldCodes
76
- }) {
77
- const {
78
- valid,
79
- value
80
- } = validatorAndNormalizer(idSub.value);
81
- if (validIdentifierSubfieldCodes.includes(idSub.code) && valid === false) {
82
- const [code] = invalidIdentifierSubfieldCodes;
83
- return {
84
- code,
85
- value
86
- };
87
- }
88
- return {
89
- code: idSub.code,
90
- value
91
- };
92
- }
93
- function normalizeHyphens(idSub) {
94
- return {
95
- code: idSub.code,
96
- value: idSub.value.replace(/-/ug, '')
97
- };
98
- }
99
- }
100
- function compare(a, b) {
101
- debug(`Comparing A and B`);
102
- if (a.length === 0 || b.length === 0) {
103
- debugData(`No standardidentifiers (${identifier}) to compare`);
104
- return 0;
105
- }
106
- debugData(`A: ${JSON.stringify(a)}`);
107
- debugData(`B: ${JSON.stringify(b)}`);
108
- if (bothHaveValidIdentifiers()) {
109
- // Compare only valid identifiers, if both have valid idenfiers
110
- const {
111
- maxValues,
112
- possibleMatchValues,
113
- matchingValues
114
- } = getValueCount(true);
115
- if (matchingValues < 1) {
116
- debug(`Both have valid standardidentifiers (${identifier}), but none of these match.`);
117
- return -0.75;
118
- }
119
- debug(`Both have valid standardidentifiers (${identifier}), ${matchingValues}/${possibleMatchValues} valid identifiers match.`);
120
- // ignore non-matches if there is mismatching amount of values
121
- debug(`Possible matches: ${possibleMatchValues}/${maxValues}`);
122
- //we give some kind of penalty for mismatching amount of values instead of simple divide?
123
- const penaltyForMissing = 0.1 * (maxValues - possibleMatchValues);
124
- const penaltyForMisMatch = 0.2 * (possibleMatchValues - matchingValues);
125
- debug(`\t points: penaltyForMissing: ${penaltyForMissing}`);
126
- debug(`\t points: penaltyForMisMatch: ${penaltyForMisMatch}`);
127
- return 0.75 - penaltyForMisMatch - penaltyForMissing;
128
- //return matchingValues / possibleMatchValues * 0.75;
129
- }
130
- // If both do not have valid identifiers, compare all identifiers
131
- const {
132
- maxValues,
133
- matchingValues
134
- } = getValueCount();
135
- debug(`Both do NOT have valid standardidentifiers (${identifier}), ${matchingValues}/${maxValues} valid/invalid identifiers match.`);
136
- return matchingValues / maxValues * 0.2;
137
- function bothHaveValidIdentifiers() {
138
- const aValues = a.filter(({
139
- code
140
- }) => validIdentifierSubfieldCodes.includes(code));
141
- const bValues = a.filter(({
142
- code
143
- }) => validIdentifierSubfieldCodes.includes(code));
144
- debug(`A: ${aValues.length} valid ${identifier} identifiers`);
145
- debug(`B: ${bValues.length} valid ${identifier} identifiers`);
146
- return aValues.length > 0 && bValues.length > 0;
147
- }
148
- function getValueCount(validOnly = false) {
149
- const aValues = getIdentifiers(a, validOnly);
150
- const bValues = getIdentifiers(b, validOnly);
151
- const matchingValues = getMatchingValuesAmount(aValues, bValues);
152
- return {
153
- maxValues: aValues.length > bValues.length ? aValues.length : bValues.length,
154
- // possibleMatchingValues: amount of identifiers in set of less identifiers (we cannot more values than these)
155
- possibleMatchValues: aValues.length > bValues.length ? bValues.length : aValues.length,
156
- matchingValues
157
- };
158
- function getMatchingValuesAmount(aValues, bValues) {
159
- if (bValues.length > aValues.length) {
160
- return aValues.filter(aValue => bValues.some(bValue => aValue === bValue)).length;
161
- }
162
- if (aValues.length > bValues.length) {
163
- return bValues.filter(bValue => aValues.some(aValue => bValue === aValue)).length;
164
- }
165
-
166
- // If we have same amount of values, we'll check matches both ways, to avoid mixups in cases
167
- // there would be duplicate values
168
- const aToB = aValues.filter(aValue => bValues.some(bValue => aValue === bValue)).length;
169
- const bToA = bValues.filter(bValue => aValues.some(aValue => bValue === aValue)).length;
170
- return aToB < bToA ? aToB : bToA;
171
- }
172
- function getIdentifiers(values, validOnly) {
173
- if (validOnly) {
174
- return values.filter(({
175
- code
176
- }) => validIdentifierSubfieldCodes.includes(code)).map(({
177
- value
178
- }) => value);
179
- }
180
- return values.map(({
181
- value
182
- }) => value);
183
- }
184
- }
185
- }
186
- };
187
- exports.default = _default;
188
- //# sourceMappingURL=standard-identifier-factory.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"standard-identifier-factory.js","names":["_debug","_interopRequireDefault","require","_matchingUtils","e","__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\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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","ignoreList":[]}
@@ -1,52 +0,0 @@
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(e) { return e && e.__esModule ? e : { default: e }; }
10
- var _default = ({
11
- treshold = 10
12
- } = {}) => ({
13
- name: 'titleVersionOriginal',
14
- extract: ({
15
- record
16
- }) => {
17
- const title = getTitle();
18
- if (title) {
19
- return [title.replace(/[^\p{Letter}\p{Number}]/gu, '').toLowerCase()];
20
- }
21
- return [];
22
- function getTitle() {
23
- const [field] = record.get(/^245$/u);
24
- if (field) {
25
- return field.subfields.filter(({
26
- code
27
- }) => ['a', 'b'].includes(code)).map(({
28
- value
29
- }) => value).join('');
30
- }
31
- }
32
- },
33
- compare: (a, b) => {
34
- const debug = (0, _debug.default)('@natlibfi/melinda-record-matching:match-detection:features/bib/title-version-original');
35
- const distance = (0, _natural.LevenshteinDistance)(a[0], b[0]);
36
- if (distance === 0) {
37
- return 0.5;
38
- }
39
- const maxLength = getMaxLength();
40
- const percentage = distance / maxLength * 100;
41
- debug(`'${a}' vs '${b}': Max length = ${maxLength}, distance = ${distance}, percentage = ${percentage}`);
42
- if (percentage <= treshold) {
43
- return 0.3;
44
- }
45
- return -0.5;
46
- function getMaxLength() {
47
- return a[0].length > b[0].length ? a[0].length : b[0].length;
48
- }
49
- }
50
- });
51
- exports.default = _default;
52
- //# sourceMappingURL=title-version-original.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"title-version-original.js","names":["_debug","_interopRequireDefault","require","_natural","e","__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":["\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":";;;;;;AACA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,QAAA,GAAAD,OAAA;AAAqD,SAAAD,uBAAAG,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAAA,IAAAG,QAAA,GAEtCA,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,CAAC,IAAIF,CAAC,SAASC,CAAC,mBAAmBK,SAAS,gBAAgBF,QAAQ,kBAAkBI,UAAU,EAAE,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","ignoreList":[]}
@@ -1,70 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
- var _natural = require("natural");
8
- var _matchingUtils = require("../../../matching-utils");
9
- var _debug = _interopRequireDefault(require("debug"));
10
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
- const debug = (0, _debug.default)('@natlibfi/melinda-record-matching:match-detection:features:title');
12
- const debugData = debug.extend('data');
13
- var _default = ({
14
- treshold = 10
15
- } = {}) => ({
16
- name: 'Title',
17
- extract: ({
18
- record,
19
- recordExternal
20
- }) => {
21
- const label = recordExternal && recordExternal.label ? recordExternal.label : 'record';
22
- const title = getTitle();
23
- debug(`${label} title: ${title}`);
24
- if ((0, _matchingUtils.testStringOrNumber)(title)) {
25
- const titleAsNormalizedString = String(title)
26
- // decompose unicode diacritics
27
- .normalize('NFD')
28
- // strip non-letters/numbers
29
- // - note: combined with decomposing unicode diactics this normalizes both 'saa' and 'sää' as 'saa'
30
- // - we could precompose the finnish letters back to avoid this
31
- .replace(/[^\p{Letter}\p{Number}]/gu, '').toLowerCase();
32
- debug(`${label} titleString: ${titleAsNormalizedString}`);
33
- return [titleAsNormalizedString];
34
- }
35
- return [];
36
- function getTitle() {
37
- const [field] = record.get(/^245$/u);
38
- debugData(`${label} titleField: ${JSON.stringify(field)}`);
39
- if (field) {
40
- return field.subfields
41
- // get also $n:s and $p:s here
42
- .filter(({
43
- code
44
- }) => ['a', 'b', 'n', 'p'].includes(code)).map(({
45
- value
46
- }) => (0, _matchingUtils.testStringOrNumber)(value) ? String(value) : '').join('');
47
- }
48
- return false;
49
- }
50
- },
51
- compare: (a, b) => {
52
- const debug = (0, _debug.default)('@natlibfi/melinda-record-matching:match-detection:features/bib/title');
53
- const distance = (0, _natural.LevenshteinDistance)(a[0], b[0]);
54
- if (distance === 0) {
55
- return 0.5;
56
- }
57
- const maxLength = getMaxLength();
58
- const percentage = distance / maxLength * 100;
59
- debug(`'${a}' vs '${b}': Max length = ${maxLength}, distance = ${distance}, percentage = ${percentage}`);
60
- if (percentage <= treshold) {
61
- return 0.3;
62
- }
63
- return -0.5;
64
- function getMaxLength() {
65
- return a[0].length > b[0].length ? a[0].length : b[0].length;
66
- }
67
- }
68
- });
69
- exports.default = _default;
70
- //# sourceMappingURL=title.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"title.js","names":["_natural","require","_matchingUtils","_debug","_interopRequireDefault","e","__esModule","default","debug","createDebugLogger","debugData","extend","_default","treshold","name","extract","record","recordExternal","label","title","getTitle","testStringOrNumber","titleAsNormalizedString","String","normalize","replace","toLowerCase","field","get","JSON","stringify","subfields","filter","code","includes","map","value","join","compare","a","b","distance","leven","maxLength","getMaxLength","percentage","length","exports"],"sources":["../../../../src/match-detection/features/bib/title.js"],"sourcesContent":["import {LevenshteinDistance as leven} from 'natural';\nimport {testStringOrNumber} from '../../../matching-utils';\nimport createDebugLogger from 'debug';\n\nconst debug = createDebugLogger('@natlibfi/melinda-record-matching:match-detection:features:title');\nconst debugData = debug.extend('data');\n\n\nexport default ({treshold = 10} = {}) => ({\n name: 'Title',\n extract: ({record, recordExternal}) => {\n const label = recordExternal && recordExternal.label ? recordExternal.label : 'record';\n const title = getTitle();\n debug(`${label} title: ${title}`);\n\n if (testStringOrNumber(title)) {\n const titleAsNormalizedString = String(title)\n // decompose unicode diacritics\n .normalize('NFD')\n // strip non-letters/numbers\n // - note: combined with decomposing unicode diactics this normalizes both 'saa' and 'sää' as 'saa'\n // - we could precompose the finnish letters back to avoid this\n .replace(/[^\\p{Letter}\\p{Number}]/gu, '')\n .toLowerCase();\n debug(`${label} titleString: ${titleAsNormalizedString}`);\n return [titleAsNormalizedString];\n }\n\n return [];\n\n function getTitle() {\n const [field] = record.get(/^245$/u);\n debugData(`${label} titleField: ${JSON.stringify(field)}`);\n\n if (field) {\n return field.subfields\n // get also $n:s and $p:s here\n .filter(({code}) => ['a', 'b', 'n', 'p'].includes(code))\n .map(({value}) => testStringOrNumber(value) ? String(value) : '')\n .join('');\n }\n return false;\n }\n },\n compare: (a, b) => {\n const debug = createDebugLogger('@natlibfi/melinda-record-matching:match-detection:features/bib/title');\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":"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","ignoreList":[]}
@@ -1,11 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.bib = void 0;
7
- var bib = _interopRequireWildcard(require("./bib"));
8
- exports.bib = bib;
9
- function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
10
- function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
11
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":["bib","_interopRequireWildcard","require","exports","_getRequireWildcardCache","e","WeakMap","r","t","__esModule","default","has","get","n","__proto__","a","Object","defineProperty","getOwnPropertyDescriptor","u","hasOwnProperty","call","i","set"],"sources":["../../../src/match-detection/features/index.js"],"sourcesContent":["\nimport * as bib from './bib';\nexport {bib};\n"],"mappings":";;;;;;AACA,IAAAA,GAAA,GAAAC,uBAAA,CAAAC,OAAA;AAA6BC,OAAA,CAAAH,GAAA,GAAAA,GAAA;AAAA,SAAAI,yBAAAC,CAAA,6BAAAC,OAAA,mBAAAC,CAAA,OAAAD,OAAA,IAAAE,CAAA,OAAAF,OAAA,YAAAF,wBAAA,YAAAA,CAAAC,CAAA,WAAAA,CAAA,GAAAG,CAAA,GAAAD,CAAA,KAAAF,CAAA;AAAA,SAAAJ,wBAAAI,CAAA,EAAAE,CAAA,SAAAA,CAAA,IAAAF,CAAA,IAAAA,CAAA,CAAAI,UAAA,SAAAJ,CAAA,eAAAA,CAAA,uBAAAA,CAAA,yBAAAA,CAAA,WAAAK,OAAA,EAAAL,CAAA,QAAAG,CAAA,GAAAJ,wBAAA,CAAAG,CAAA,OAAAC,CAAA,IAAAA,CAAA,CAAAG,GAAA,CAAAN,CAAA,UAAAG,CAAA,CAAAI,GAAA,CAAAP,CAAA,OAAAQ,CAAA,KAAAC,SAAA,UAAAC,CAAA,GAAAC,MAAA,CAAAC,cAAA,IAAAD,MAAA,CAAAE,wBAAA,WAAAC,CAAA,IAAAd,CAAA,oBAAAc,CAAA,OAAAC,cAAA,CAAAC,IAAA,CAAAhB,CAAA,EAAAc,CAAA,SAAAG,CAAA,GAAAP,CAAA,GAAAC,MAAA,CAAAE,wBAAA,CAAAb,CAAA,EAAAc,CAAA,UAAAG,CAAA,KAAAA,CAAA,CAAAV,GAAA,IAAAU,CAAA,CAAAC,GAAA,IAAAP,MAAA,CAAAC,cAAA,CAAAJ,CAAA,EAAAM,CAAA,EAAAG,CAAA,IAAAT,CAAA,CAAAM,CAAA,IAAAd,CAAA,CAAAc,CAAA,YAAAN,CAAA,CAAAH,OAAA,GAAAL,CAAA,EAAAG,CAAA,IAAAA,CAAA,CAAAe,GAAA,CAAAlB,CAAA,EAAAQ,CAAA,GAAAA,CAAA","ignoreList":[]}