@natlibfi/marc-record-merge 6.0.0-beta.8 → 7.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 (63) hide show
  1. package/.github/CODEOWNERS +2 -9
  2. package/.github/dependabot.yml +2 -3
  3. package/.github/workflows/melinda-node-tests.yml +2 -2
  4. package/README.md +16 -0
  5. package/dist/index.js +49 -4
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.spec.js +59 -0
  8. package/dist/index.spec.js.map +1 -0
  9. package/dist/reducers/copy.js +59 -148
  10. package/dist/reducers/copy.js.map +1 -1
  11. package/dist/reducers/copy.spec.js +9 -12
  12. package/dist/reducers/copy.spec.js.map +1 -1
  13. package/dist/reducers/copy2.spec.js +66 -0
  14. package/dist/reducers/copy2.spec.js.map +1 -0
  15. package/dist/reducers/index.js +0 -6
  16. package/dist/reducers/index.js.map +1 -1
  17. package/dist/reducers/select.js +43 -40
  18. package/dist/reducers/select.js.map +1 -1
  19. package/dist/reducers/select.spec.js +4 -15
  20. package/dist/reducers/select.spec.js.map +1 -1
  21. package/dist/reducers/select2.spec.js +58 -0
  22. package/dist/reducers/select2.spec.js.map +1 -0
  23. package/package.json +18 -18
  24. package/src/index.js +51 -1
  25. package/src/index.spec.js +45 -0
  26. package/src/reducers/copy.js +42 -103
  27. package/src/reducers/copy.spec.js +4 -6
  28. package/src/reducers/copy2.spec.js +55 -0
  29. package/src/reducers/select.js +31 -10
  30. package/src/reducers/select2.spec.js +49 -0
  31. package/test-fixtures/index/01/base.json +24 -0
  32. package/test-fixtures/index/01/merged.json +24 -0
  33. package/test-fixtures/index/01/metadata.json +8 -0
  34. package/test-fixtures/index/01/source.json +40 -0
  35. package/test-fixtures/index/02/base.json +24 -0
  36. package/test-fixtures/index/02/merged.json +24 -0
  37. package/test-fixtures/index/02/metadata.json +7 -0
  38. package/test-fixtures/index/02/source.json +40 -0
  39. package/test-fixtures/reducers/copy/04 - compareWithoutIndicators/03/metadata.json +6 -0
  40. package/test-fixtures/reducers/copy/04 - compareWithoutIndicators/04/base.json +20 -0
  41. package/test-fixtures/reducers/copy/04 - compareWithoutIndicators/04/merged.json +31 -0
  42. package/test-fixtures/reducers/copy/04 - compareWithoutIndicators/04/metadata.json +5 -0
  43. package/test-fixtures/reducers/copy/04 - compareWithoutIndicators/04/source.json +20 -0
  44. package/test-fixtures/reducers/copy/11 - compareWithoutTag/01/base.json +28 -0
  45. package/test-fixtures/reducers/copy/11 - compareWithoutTag/01/merged.json +28 -0
  46. package/test-fixtures/reducers/copy/11 - compareWithoutTag/01/metadata.json +6 -0
  47. package/test-fixtures/reducers/copy/11 - compareWithoutTag/01/source.json +20 -0
  48. package/test-fixtures/reducers/copy/11 - compareWithoutTag/02/base.json +28 -0
  49. package/test-fixtures/reducers/copy/11 - compareWithoutTag/02/merged.json +39 -0
  50. package/test-fixtures/reducers/copy/11 - compareWithoutTag/02/metadata.json +6 -0
  51. package/test-fixtures/reducers/copy/11 - compareWithoutTag/02/source.json +31 -0
  52. package/test-fixtures/reducers/copy/11 - compareWithoutTag/03/base.json +28 -0
  53. package/test-fixtures/reducers/copy/11 - compareWithoutTag/03/merged.json +28 -0
  54. package/test-fixtures/reducers/copy/11 - compareWithoutTag/03/metadata.json +7 -0
  55. package/test-fixtures/reducers/copy/11 - compareWithoutTag/03/source.json +20 -0
  56. package/test-fixtures/reducers/copy/11 - compareWithoutTag/04/base.json +17 -0
  57. package/test-fixtures/reducers/copy/11 - compareWithoutTag/04/merged.json +28 -0
  58. package/test-fixtures/reducers/copy/11 - compareWithoutTag/04/metadata.json +7 -0
  59. package/test-fixtures/reducers/copy/11 - compareWithoutTag/04/source.json +31 -0
  60. package/test-fixtures/reducers/copy/11 - compareWithoutTag/05/base.json +28 -0
  61. package/test-fixtures/reducers/copy/11 - compareWithoutTag/05/merged.json +28 -0
  62. package/test-fixtures/reducers/copy/11 - compareWithoutTag/05/metadata.json +7 -0
  63. package/test-fixtures/reducers/copy/11 - compareWithoutTag/05/source.json +28 -0
@@ -1,9 +1,2 @@
1
- # With this line @NatLibFi/melinda-js-lead owns any files in the /.github/
2
- # directory at the root of the repository and any of its
3
- # subdirectories.
4
- /.github/ @NatLibFi/melinda-js-lead
5
-
6
- # With this line @NatLibFi/melinda-js-lead owns any files in the /src/
7
- # directory at the root of the repository and any of its
8
- # subdirectories.
9
- /src/ @NatLibFi/melinda-js-lead
1
+ # With this line @NatLibFi/melinda-js-lead owns any files in this repository
2
+ * @NatLibFi/melinda-js-lead
@@ -10,7 +10,7 @@ updates:
10
10
  interval: "daily"
11
11
  time: "06:30"
12
12
  timezone: "Europe/Helsinki"
13
-
13
+ target-branch: "dependencies"
14
14
 
15
15
  # Minor updates to npm production dependencies daily
16
16
  - package-ecosystem: "npm"
@@ -20,10 +20,9 @@ updates:
20
20
  time: "06:45"
21
21
  timezone: "Europe/Helsinki"
22
22
  versioning-strategy: lockfile-only
23
- labels:
24
- - "npm minor dependencies"
25
23
  allow:
26
24
  - dependency-type: "production"
25
+ target-branch: "dependencies"
27
26
 
28
27
  # Major updates to npm dependencies weekly @tuesday
29
28
  # Not possible yet https://github.com/dependabot/dependabot-core/issues/1778
@@ -11,7 +11,7 @@ jobs:
11
11
 
12
12
  strategy:
13
13
  matrix:
14
- node-version: [14.x, 16.x, 18.x]
14
+ node-version: [16.x, 18.x, 19.x]
15
15
  # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
16
16
 
17
17
  steps:
@@ -52,7 +52,7 @@ jobs:
52
52
  # Setup .npmrc file to publish to npm
53
53
  - uses: actions/setup-node@v3
54
54
  with:
55
- node-version: '14.x'
55
+ node-version: '18.x'
56
56
  registry-url: 'https://registry.npmjs.org'
57
57
  - run: npm ci
58
58
  - run: npm publish
package/README.md CHANGED
@@ -36,6 +36,14 @@ If base has field with that tag 011 source field is ignored
36
36
 
37
37
  When base and source fields are compared, indicator differences are ignored
38
38
 
39
+ ### compareWithoutTag (Defaults false)
40
+ ```
41
+ {tagPattern: /^(100|700)$/u, compareWithoutTag: false}
42
+ {tagPattern: /^(100|700)$/u, compareWithoutTag: false, swapTag: [{"from": "^100$", "to": "700"}]}
43
+ ```
44
+
45
+ When base and source fields are compared, tag differences are ignored
46
+
39
47
  ### subfieldsMustBeIdentical (Defaults true)
40
48
  ```
41
49
  {tagPattern: /010/u, subfieldsMustBeIdentical: true}
@@ -58,6 +66,14 @@ If source subfields are subset of base subfields this option says if it is copie
58
66
 
59
67
  When base and source fields are compared, excluded subfields are ignored
60
68
 
69
+ ### swapTag (Defaults [ ])
70
+ ```
71
+ {tagPattern: /^100$/u, swapTag: [{"from": "^100$", "to": "700"}]}
72
+ {tagPattern: /^(100|700)$/u, compareWithoutTag: false, swapTag: [{"from": "^100$", "to": "700"}]}
73
+ ```
74
+
75
+ When fields are copied, tags are swapped. From is Regexp filter and to is string value.
76
+
61
77
  ### swapSubfieldCode (Defaults [ ])
62
78
  ```
63
79
  {tagPattern: /010/u, swapSubfieldCode: [{"from": "a", "to": "b"}]}
package/dist/index.js CHANGED
@@ -10,16 +10,61 @@ Object.defineProperty(exports, "Reducers", {
10
10
  }
11
11
  });
12
12
  exports.default = void 0;
13
-
14
13
  var _reducers = _interopRequireDefault(require("./reducers"));
15
-
14
+ var _debug = _interopRequireDefault(require("debug"));
16
15
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
17
-
16
+ const debug = (0, _debug.default)('@natlibfi/melinda-marc-record-merge:index');
17
+ const debugData = debug.extend('data');
18
+ // export default ({base, source, reducers}) => reducers.reduce((base, reducer) => reducer(base, source), base);
19
+ // NV: Modified the reducer loop so, that not only base, but also is carried back.
20
+ // However, we try to be backward-compatible: normally after the reducers, only base is returned.
18
21
  var _default = ({
19
22
  base,
20
23
  source,
21
24
  reducers
22
- }) => reducers.reduce((base, reducer) => reducer(base, source), base);
25
+ }) => {
26
+ const combo = {
27
+ base,
28
+ source
29
+ };
30
+ const resultCombo = reducers.reduce((combo, reducer) => {
31
+ const returnCombo = singleRound(reducer, combo.base, combo.source);
32
+ //debugData(`returnCombo after current reducer: ${JSON.stringify(returnCombo)}`);
33
+ return returnCombo;
34
+ }, combo);
35
+ debugData(`ResultCombo after reducers: ${JSON.stringify(resultCombo)}`);
23
36
 
37
+ // Hack to make my melinda-marc-record-merge-reducers single tests that expect both
38
+ // base and source to return them both:
39
+ if (reducers.length === 1 && resultCombo.base && resultCombo.source) {
40
+ debug('Single reducer, returning resultCombo');
41
+ debugData(JSON.stringify(resultCombo));
42
+ return resultCombo;
43
+ }
44
+ // All other tests return just base... Backward (compability) it is!
45
+ debug('Multiple reducers, returning just base');
46
+ debugData(JSON.stringify(resultCombo.base));
47
+ return resultCombo.base;
48
+ function singleRound(reducer, base, source) {
49
+ //debug(`SINGLE ROUND INPUT (base, source)`);
50
+ //debugData(base);
51
+ //debugData(base);
52
+ const reducerResult = reducer(base, source);
53
+ //debug(`reducerResult:`);
54
+ //debugData(reducerResult);
55
+ if (reducerResult.base !== undefined && reducerResult.source !== undefined) {
56
+ debug('NEW STYLE REDUCER RESULT v2');
57
+ const combo = reducerResult;
58
+ //debugData(combo);
59
+ return combo;
60
+ }
61
+ debug('OLD SCHOOL REDUCER RESULT v2');
62
+ //debugData({base: reducerResult, source});
63
+ return {
64
+ base: reducerResult,
65
+ source
66
+ };
67
+ }
68
+ };
24
69
  exports.default = _default;
25
70
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["base","source","reducers","reduce","reducer"],"sources":["../src/index.js"],"sourcesContent":["import Reducers from './reducers';\n\nexport {Reducers};\nexport default ({base, source, reducers}) => reducers.reduce((base, reducer) => reducer(base, source), base);\n"],"mappings":";;;;;;;;;;;;;AAAA;;;;eAGe,CAAC;EAACA,IAAD;EAAOC,MAAP;EAAeC;AAAf,CAAD,KAA8BA,QAAQ,CAACC,MAAT,CAAgB,CAACH,IAAD,EAAOI,OAAP,KAAmBA,OAAO,CAACJ,IAAD,EAAOC,MAAP,CAA1C,EAA0DD,IAA1D,C"}
1
+ {"version":3,"file":"index.js","names":["_reducers","_interopRequireDefault","require","_debug","obj","__esModule","default","debug","createDebugLogger","debugData","extend","_default","base","source","reducers","combo","resultCombo","reduce","reducer","returnCombo","singleRound","JSON","stringify","length","reducerResult","undefined","exports"],"sources":["../src/index.js"],"sourcesContent":["import Reducers from './reducers';\nimport createDebugLogger from 'debug';\n\nconst debug = createDebugLogger('@natlibfi/melinda-marc-record-merge:index');\nconst debugData = debug.extend('data');\n\nexport {Reducers};\n// export default ({base, source, reducers}) => reducers.reduce((base, reducer) => reducer(base, source), base);\n\n// NV: Modified the reducer loop so, that not only base, but also is carried back.\n// However, we try to be backward-compatible: normally after the reducers, only base is returned.\n\nexport default ({base, source, reducers}) => {\n\n const combo = {base, source};\n const resultCombo = reducers.reduce((combo, reducer) => {\n const returnCombo = singleRound(reducer, combo.base, combo.source);\n //debugData(`returnCombo after current reducer: ${JSON.stringify(returnCombo)}`);\n return returnCombo;\n }, combo);\n\n debugData(`ResultCombo after reducers: ${JSON.stringify(resultCombo)}`);\n\n // Hack to make my melinda-marc-record-merge-reducers single tests that expect both\n // base and source to return them both:\n if (reducers.length === 1 && resultCombo.base && resultCombo.source) {\n debug('Single reducer, returning resultCombo');\n debugData(JSON.stringify(resultCombo));\n\n return resultCombo;\n }\n // All other tests return just base... Backward (compability) it is!\n debug('Multiple reducers, returning just base');\n debugData(JSON.stringify(resultCombo.base));\n return resultCombo.base;\n\n function singleRound(reducer, base, source) {\n //debug(`SINGLE ROUND INPUT (base, source)`);\n //debugData(base);\n //debugData(base);\n const reducerResult = reducer(base, source);\n //debug(`reducerResult:`);\n //debugData(reducerResult);\n if (reducerResult.base !== undefined && reducerResult.source !== undefined) {\n debug('NEW STYLE REDUCER RESULT v2');\n const combo = reducerResult;\n //debugData(combo);\n return combo;\n }\n debug('OLD SCHOOL REDUCER RESULT v2');\n //debugData({base: reducerResult, source});\n return {base: reducerResult, source};\n }\n};\n"],"mappings":";;;;;;;;;;;;AAAA,IAAAA,SAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,MAAA,GAAAF,sBAAA,CAAAC,OAAA;AAAsC,SAAAD,uBAAAG,GAAA,WAAAA,GAAA,IAAAA,GAAA,CAAAC,UAAA,GAAAD,GAAA,KAAAE,OAAA,EAAAF,GAAA;AAEtC,MAAMG,KAAK,GAAG,IAAAC,cAAiB,EAAC,2CAA2C,CAAC;AAC5E,MAAMC,SAAS,GAAGF,KAAK,CAACG,MAAM,CAAC,MAAM,CAAC;AAGtC;AAEA;AACA;AAAA,IAAAC,QAAA,GAEeA,CAAC;EAACC,IAAI;EAAEC,MAAM;EAAEC;AAAQ,CAAC,KAAK;EAE3C,MAAMC,KAAK,GAAG;IAACH,IAAI;IAAEC;EAAM,CAAC;EAC5B,MAAMG,WAAW,GAAGF,QAAQ,CAACG,MAAM,CAAC,CAACF,KAAK,EAAEG,OAAO,KAAK;IACtD,MAAMC,WAAW,GAAGC,WAAW,CAACF,OAAO,EAAEH,KAAK,CAACH,IAAI,EAAEG,KAAK,CAACF,MAAM,CAAC;IAClE;IACA,OAAOM,WAAW;EACpB,CAAC,EAAEJ,KAAK,CAAC;EAETN,SAAS,CAAE,+BAA8BY,IAAI,CAACC,SAAS,CAACN,WAAW,CAAE,EAAC,CAAC;;EAEvE;EACA;EACA,IAAIF,QAAQ,CAACS,MAAM,KAAK,CAAC,IAAIP,WAAW,CAACJ,IAAI,IAAII,WAAW,CAACH,MAAM,EAAE;IACnEN,KAAK,CAAC,uCAAuC,CAAC;IAC9CE,SAAS,CAACY,IAAI,CAACC,SAAS,CAACN,WAAW,CAAC,CAAC;IAEtC,OAAOA,WAAW;EACpB;EACA;EACAT,KAAK,CAAC,wCAAwC,CAAC;EAC/CE,SAAS,CAACY,IAAI,CAACC,SAAS,CAACN,WAAW,CAACJ,IAAI,CAAC,CAAC;EAC3C,OAAOI,WAAW,CAACJ,IAAI;EAEvB,SAASQ,WAAWA,CAACF,OAAO,EAAEN,IAAI,EAAEC,MAAM,EAAE;IAC1C;IACA;IACA;IACA,MAAMW,aAAa,GAAGN,OAAO,CAACN,IAAI,EAAEC,MAAM,CAAC;IAC3C;IACA;IACA,IAAIW,aAAa,CAACZ,IAAI,KAAKa,SAAS,IAAID,aAAa,CAACX,MAAM,KAAKY,SAAS,EAAE;MAC1ElB,KAAK,CAAC,6BAA6B,CAAC;MACpC,MAAMQ,KAAK,GAAGS,aAAa;MAC3B;MACA,OAAOT,KAAK;IACd;IACAR,KAAK,CAAC,8BAA8B,CAAC;IACrC;IACA,OAAO;MAACK,IAAI,EAAEY,aAAa;MAAEX;IAAM,CAAC;EACtC;AACF,CAAC;AAAAa,OAAA,CAAApB,OAAA,GAAAK,QAAA"}
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+
3
+ var _index = _interopRequireWildcard(require("./index"));
4
+ var _util = require("util");
5
+ var _debug = _interopRequireDefault(require("debug"));
6
+ var _chai = require("chai");
7
+ var _marcRecord = require("@natlibfi/marc-record");
8
+ var _fixura = require("@natlibfi/fixura");
9
+ var _fixugen = _interopRequireDefault(require("@natlibfi/fixugen"));
10
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
12
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
13
+ (0, _fixugen.default)({
14
+ callback,
15
+ path: [__dirname, '..', 'test-fixtures', 'index'],
16
+ recurse: false,
17
+ useMetadataFile: true,
18
+ fixura: {
19
+ failWhenNotFound: false,
20
+ reader: _fixura.READERS.JSON
21
+ }
22
+ });
23
+ function callback({
24
+ getFixture,
25
+ reducerConfigs = []
26
+ }) {
27
+ const base = new _marcRecord.MarcRecord(getFixture('base.json'), {
28
+ subfieldValues: false
29
+ });
30
+ const source = new _marcRecord.MarcRecord(getFixture('source.json'), {
31
+ subfieldValues: false
32
+ });
33
+ const expectedRecord = getFixture('merged.json');
34
+ const debug = (0, _debug.default)('@natlibfi/melinda-marc-record-merge-reducers:index:test');
35
+ const debugData = debug.extend('data');
36
+ const testReducerConfigs = reducerConfigs;
37
+ const reducers = [...testReducerConfigs.map(conf => _index.Reducers.copy(conf))];
38
+ debugData(`Reducers: ${(0, _util.inspect)(reducers, {
39
+ colors: true,
40
+ maxArrayLength: 10,
41
+ depth: 8
42
+ })})}`);
43
+ const result = (0, _index.default)({
44
+ base,
45
+ source,
46
+ reducers
47
+ });
48
+ debug(`Merge result is: ${result.constructor.name}`);
49
+ debugData(`${JSON.stringify(result)}`);
50
+
51
+ // Use either result.base or a plain result as resultRecord
52
+ // It can also be a MarcRecord or a plain object
53
+ const resultRecord = result.base || result;
54
+ const resultRecordToRecord = new _marcRecord.MarcRecord(resultRecord, {
55
+ subfieldValues: false
56
+ });
57
+ (0, _chai.expect)(resultRecordToRecord.toObject()).to.eql(expectedRecord);
58
+ }
59
+ //# sourceMappingURL=index.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.spec.js","names":["_index","_interopRequireWildcard","require","_util","_debug","_interopRequireDefault","_chai","_marcRecord","_fixura","_fixugen","obj","__esModule","default","_getRequireWildcardCache","nodeInterop","WeakMap","cacheBabelInterop","cacheNodeInterop","cache","has","get","newObj","hasPropertyDescriptor","Object","defineProperty","getOwnPropertyDescriptor","key","prototype","hasOwnProperty","call","desc","set","generateTests","callback","path","__dirname","recurse","useMetadataFile","fixura","failWhenNotFound","reader","READERS","JSON","getFixture","reducerConfigs","base","MarcRecord","subfieldValues","source","expectedRecord","debug","createDebugLogger","debugData","extend","testReducerConfigs","reducers","map","conf","Reducers","copy","inspect","colors","maxArrayLength","depth","result","merger","constructor","name","stringify","resultRecord","resultRecordToRecord","expect","toObject","to","eql"],"sources":["../src/index.spec.js"],"sourcesContent":["import merger, {Reducers} from './index';\nimport {inspect} from 'util';\nimport createDebugLogger from 'debug';\nimport {expect} from 'chai';\nimport {MarcRecord} from '@natlibfi/marc-record';\nimport {READERS} from '@natlibfi/fixura';\nimport generateTests from '@natlibfi/fixugen';\n\ngenerateTests({\n callback,\n path: [__dirname, '..', 'test-fixtures', 'index'],\n recurse: false,\n useMetadataFile: true,\n fixura: {\n failWhenNotFound: false,\n reader: READERS.JSON\n }\n});\n\nfunction callback({getFixture, reducerConfigs = []}) {\n const base = new MarcRecord(getFixture('base.json'), {subfieldValues: false});\n const source = new MarcRecord(getFixture('source.json'), {subfieldValues: false});\n const expectedRecord = getFixture('merged.json');\n\n const debug = createDebugLogger('@natlibfi/melinda-marc-record-merge-reducers:index:test');\n const debugData = debug.extend('data');\n\n const testReducerConfigs = reducerConfigs;\n const reducers = [...testReducerConfigs.map(conf => Reducers.copy(conf))];\n\n debugData(`Reducers: ${inspect(reducers, {colors: true, maxArrayLength: 10, depth: 8})})}`);\n\n const result = merger({base, source, reducers});\n\n debug(`Merge result is: ${result.constructor.name}`);\n debugData(`${JSON.stringify(result)}`);\n\n // Use either result.base or a plain result as resultRecord\n // It can also be a MarcRecord or a plain object\n const resultRecord = result.base || result;\n const resultRecordToRecord = new MarcRecord(resultRecord, {subfieldValues: false});\n expect(resultRecordToRecord.toObject()).to.eql(expectedRecord);\n\n\n}\n"],"mappings":"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"}
@@ -4,20 +4,18 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
-
8
7
  var _marcRecord = require("@natlibfi/marc-record");
9
-
10
8
  var _debug = _interopRequireDefault(require("debug"));
11
-
12
9
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
-
14
10
  /* eslint-disable max-statements */
15
-
16
11
  /* eslint-disable no-unused-vars */
17
12
  var _default = ({
18
13
  tagPattern,
19
14
  compareTagsOnly = false,
15
+ compareWithoutTag = false,
20
16
  compareWithoutIndicators = false,
17
+ compareWithoutIndicator1 = false,
18
+ compareWithoutIndicator2 = false,
21
19
  subfieldsMustBeIdentical = true,
22
20
  excludeSubfields = [],
23
21
  dropSubfields = [],
@@ -32,14 +30,40 @@ var _default = ({
32
30
  swapSubfieldCode = [],
33
31
  doNotCopyIfFieldPresent = false
34
32
  }) => (base, source) => {
35
- const baseRecord = new _marcRecord.MarcRecord(base, baseValidators);
36
- const sourceRecord = new _marcRecord.MarcRecord(source, sourceValidators);
37
- const debug = (0, _debug.default)('@natlibfi/marc-record-merge');
33
+ const debug = (0, _debug.default)('@natlibfi/marc-record-merge:copy');
34
+ const debugData = debug.extend('data');
38
35
  const debugOptions = (0, _debug.default)('@natlibfi/marc-record-merge:compare-options');
39
36
  const debugCompare = (0, _debug.default)('@natlibfi/marc-record-merge:compare');
37
+ debugData(`base: ${JSON.stringify(base)}`);
38
+ debugData(`source: ${JSON.stringify(source)}`);
39
+ const {
40
+ baseRecord,
41
+ sourceRecord
42
+ } = getRecordsFromParameters(base, source, baseValidators, sourceValidators);
43
+ function getRecordsFromParameters(base, source, baseValidators, sourceValidators) {
44
+ // records if we got an object ({base, source}) as a parameter
45
+ if (source === undefined && base.base !== undefined && base.source !== undefined) {
46
+ const baseRecord = new _marcRecord.MarcRecord(base.base, baseValidators);
47
+ const sourceRecord = new _marcRecord.MarcRecord(base.source, sourceValidators);
48
+ return {
49
+ baseRecord,
50
+ sourceRecord
51
+ };
52
+ }
53
+ // records if we got an non-object (base, source) as a parameter
54
+ const baseRecord = new _marcRecord.MarcRecord(base, baseValidators);
55
+ const sourceRecord = new _marcRecord.MarcRecord(source, sourceValidators);
56
+ return {
57
+ baseRecord,
58
+ sourceRecord
59
+ };
60
+ }
61
+ const ignoreInd1 = compareWithoutIndicators || compareWithoutIndicator1;
62
+ const ignoreInd2 = compareWithoutIndicators || compareWithoutIndicator2;
40
63
  debugOptions(`Tag Pattern: ${tagPattern}`);
41
64
  debugOptions(`Compare tags only: ${compareTagsOnly}`);
42
- debugOptions(`Compare without indicators ${compareWithoutIndicators}`);
65
+ debugOptions(`Omit indicator 1 from comparison: ${ignoreInd1}`);
66
+ debugOptions(`Omit indicator 2 from comparison: ${ignoreInd2}`);
43
67
  debugOptions(`Copy if identical: ${subfieldsMustBeIdentical}`);
44
68
  debugOptions(`Exclude subfields: [${excludeSubfields}]`);
45
69
  debugOptions(`Drop subfields [${dropSubfields}]`);
@@ -47,128 +71,117 @@ var _default = ({
47
71
  const baseFields = baseRecord.get(tagPattern);
48
72
  const sourceFields = sourceRecord.get(tagPattern);
49
73
  const doNotCopy = doNotCopyIfFieldPresent ? baseRecord.get(doNotCopyIfFieldPresent).length > 0 : false;
50
-
51
74
  if (doNotCopy) {
52
75
  return baseRecord.toObject();
53
76
  }
54
-
77
+ debug(`FFS: ${compareWithoutIndicator1}, ${compareWithoutIndicators}, ${ignoreInd1}`);
55
78
  debug(`Base fields: `, baseFields);
56
79
  debug(`Source fields: `, sourceFields);
80
+
81
+ // Logic steps
57
82
  const baseCompareFields = baseFields.map(baseField => createCompareField(baseField));
58
83
  const compareResultFields = compareFields(sourceFields, baseCompareFields);
59
84
  const droppedUnwantedSubfield = checkDropSubfields(compareResultFields);
60
85
  const droppedUnwantedFields = checkCopyUnlessFields(droppedUnwantedSubfield);
61
86
  const swappedSubfields = checkSwapSubfieldCodes(droppedUnwantedFields);
62
87
  const swappedTags = checkSwapTag(swappedSubfields);
88
+ const uniqueFields = [...new Set(swappedTags.map(field => JSON.stringify(field)))].map(field => JSON.parse(field));
63
89
  debug('Fields to be copied');
64
- debug(JSON.stringify(swappedTags)); // Add fields to base;
65
-
66
- swappedTags.forEach(field => baseRecord.insertField(field));
67
- return baseRecord.toObject(); //return copyFields(baseFields, sourceFields);
90
+ debug(JSON.stringify(uniqueFields));
68
91
 
92
+ // Add fields to base;
93
+ uniqueFields.forEach(field => baseRecord.insertField(field));
94
+ debugData(`baseRecord before return: ${JSON.stringify(baseRecord)}`);
95
+ //return baseRecord;
96
+ return baseRecord.toObject();
69
97
  function compareFields(sourceFields, baseCompareFields, uniqFields = []) {
70
98
  const [sourceField, ...rest] = sourceFields;
71
-
72
99
  if (sourceField === undefined) {
73
100
  return uniqFields;
74
101
  }
75
-
76
102
  if (baseCompareFields.length === 0) {
77
103
  return compareFields(rest, baseCompareFields, [...uniqFields, sourceField]);
78
- } // Source and base are also compared for identicalness
79
- // Non-identical fields are copied from source to base as duplicates
80
-
104
+ }
81
105
 
106
+ // Source and base are also compared for identicalness
107
+ // Non-identical fields are copied from source to base as duplicates
82
108
  const sourceCompareField = createCompareField(sourceField);
83
109
  const unique = checkCompareFields(baseCompareFields, sourceCompareField);
84
110
  debugCompare(`${JSON.stringify(sourceField)} ${unique ? 'is UNIQUE' : 'not UNIQUE'}`);
85
-
86
111
  if (unique) {
87
112
  return compareFields(rest, baseCompareFields, [...uniqFields, sourceField]);
88
113
  }
89
-
90
114
  return compareFields(rest, baseCompareFields, uniqFields);
91
-
92
115
  function checkCompareFields(baseCompareFields, sourceCompareField) {
93
116
  let unique = true; // eslint-disable-line functional/no-let
94
117
 
95
118
  baseCompareFields.forEach(baseCompareField => {
96
119
  debugCompare(`Comparing ${JSON.stringify(sourceCompareField)} to ${JSON.stringify(baseCompareField)}}`);
97
-
98
120
  if (sourceCompareField.value !== baseCompareField.value) {
99
121
  debugCompare(`Value is different ${sourceCompareField.value} !== ${baseCompareField.value}`);
100
122
  return;
101
123
  }
102
-
103
124
  if (sourceCompareField.ind1 !== baseCompareField.ind1) {
104
125
  debugCompare(`Ind1 is different ${sourceCompareField.ind1} !== ${baseCompareField.ind1}`);
105
126
  return;
106
127
  }
107
-
108
128
  if (sourceCompareField.ind2 !== baseCompareField.ind2) {
109
129
  debugCompare(`Ind2 is different ${sourceCompareField.ind2} !== ${baseCompareField.ind2}`);
110
130
  return;
111
131
  }
112
-
113
132
  if ('subfields' in sourceCompareField) {
114
133
  const allFound = checkSubfields(sourceCompareField.subfields, baseCompareField.subfields);
115
134
  debugCompare(`Subfields are different ${!allFound}`);
116
-
117
135
  if (!allFound) {
118
136
  return;
119
137
  }
120
-
121
138
  unique = false;
122
139
  return;
123
140
  }
124
-
125
141
  unique = false;
126
142
  return;
127
143
  });
128
144
  return unique;
129
145
  }
130
-
131
146
  function checkSubfields(sourceSubfields, baseSubfields) {
132
147
  const foundSubs = sourceSubfields.filter(sSub => baseSubfields.some(bSub => sSub.code === bSub.code && sSub.value === bSub.value));
133
-
134
148
  if (subfieldsMustBeIdentical) {
135
149
  return foundSubs.length === sourceSubfields.length && foundSubs.length === baseSubfields.length;
136
150
  }
137
-
138
151
  return foundSubs.length === sourceSubfields.length;
139
152
  }
140
153
  }
141
154
 
155
+ // compare objects have only fields that matter in comparison
142
156
  function createCompareField(field) {
143
157
  if (compareTagsOnly) {
144
158
  return {
145
159
  tag: field.tag
146
160
  };
147
161
  }
148
-
149
162
  if ('value' in field) {
150
163
  return {
151
164
  tag: field.tag,
152
165
  value: field.value
153
166
  };
154
167
  }
155
-
156
168
  const [filteredField] = checkDropSubfields([field]);
169
+ const [foundRule] = swapTag.filter(rule => new RegExp(rule.from, 'u').test(field.tag));
170
+ const replacementTag = foundRule ? foundRule.to : undefined;
157
171
  const params = [{
158
172
  name: 'tag',
159
- value: field.tag
173
+ value: compareWithoutTag ? replacementTag : field.tag
160
174
  }, {
161
175
  name: 'ind1',
162
- value: compareWithoutIndicators ? undefined : field.ind1
176
+ value: ignoreInd1 ? undefined : field.ind1
163
177
  }, {
164
178
  name: 'ind2',
165
- value: compareWithoutIndicators ? undefined : field.ind2
179
+ value: ignoreInd2 ? undefined : field.ind2
166
180
  }, {
167
181
  name: 'subfields',
168
182
  value: createCompareSubfields(filteredField.subfields)
169
183
  }].map(param => [param.name, param.value]);
170
184
  return Object.fromEntries(params);
171
-
172
185
  function createCompareSubfields(subfields) {
173
186
  const nonExcludedSubfields = subfields.filter(sub => !excludeSubfields.some(code => code === sub.code));
174
187
  const normalizedSubfields = nonExcludedSubfields.map(sub => ({
@@ -176,50 +189,41 @@ var _default = ({
176
189
  value: normalizeSubfieldValue(sub.value)
177
190
  }));
178
191
  return normalizedSubfields;
179
-
180
192
  function normalizeSubfieldValue(value) {
181
193
  return value.toLowerCase().replace(/\s+/ug, '');
182
194
  }
183
195
  }
184
196
  }
185
-
186
197
  function checkSwapTag(fields) {
187
198
  if (swapTag.length > 0) {
188
- return fields.map(field => ({ ...field,
199
+ return fields.map(field => ({
200
+ ...field,
189
201
  tag: swapTagsFunc(field.tag)
190
202
  }));
191
203
  }
192
-
193
204
  return fields;
194
-
195
205
  function swapTagsFunc(tag) {
196
206
  const [foundRule] = swapTag.filter(rule => new RegExp(rule.from, 'u').test(tag));
197
-
198
207
  if (foundRule === undefined) {
199
208
  return tag;
200
209
  }
201
-
202
210
  return foundRule.to;
203
211
  }
204
212
  }
205
-
206
213
  function checkSwapSubfieldCodes(fields) {
207
214
  if (swapSubfieldCode.length > 0) {
208
- return fields.map(field => ({ ...field,
215
+ return fields.map(field => ({
216
+ ...field,
209
217
  subfields: swapSubfieldCodesFunc(field.subfields)
210
218
  }));
211
219
  }
212
-
213
220
  return fields;
214
-
215
221
  function swapSubfieldCodesFunc(subfields) {
216
222
  return subfields.map(sub => {
217
223
  const [foundRule] = swapSubfieldCode.filter(rule => rule.from === sub.code);
218
-
219
224
  if (foundRule === undefined) {
220
225
  return sub;
221
226
  }
222
-
223
227
  return {
224
228
  code: foundRule.to,
225
229
  value: sub.value
@@ -227,16 +231,14 @@ var _default = ({
227
231
  });
228
232
  }
229
233
  }
230
-
231
234
  function checkDropSubfields(fields) {
232
235
  if (dropSubfields.length > 0) {
233
- return fields.map(field => ({ ...field,
236
+ return fields.map(field => ({
237
+ ...field,
234
238
  subfields: dropSubfieldsFunc(field.subfields)
235
239
  })).filter(field => field.subfields.length > 0);
236
240
  }
237
-
238
241
  return fields;
239
-
240
242
  function dropSubfieldsFunc(subfields) {
241
243
  return subfields.filter(sub => {
242
244
  // eslint-disable-line
@@ -248,116 +250,25 @@ var _default = ({
248
250
  if (code !== sub.code) {
249
251
  return false;
250
252
  }
251
-
252
253
  if (!condition && value) {
253
254
  return value === sub.value;
254
255
  }
255
-
256
256
  if (condition === 'unless' && value) {
257
257
  return !new RegExp(value, 'u').test(sub.value);
258
258
  }
259
-
260
259
  return true;
261
260
  });
262
261
  });
263
262
  }
264
263
  }
265
-
266
264
  function checkCopyUnlessFields(fields) {
267
265
  if (copyUnless.length > 0) {
268
266
  return fields.filter(({
269
267
  subfields
270
268
  }) => copyUnless.some(filter => !subfields.some(sub => sub.code === filter.code && new RegExp(filter.value, 'u').test(sub.value))));
271
269
  }
272
-
273
270
  return fields;
274
271
  }
275
- }; // function copyFields() { //eslint-disable-line no-unused-vars
276
- // const sourceTags = sourceFields.map(field => field.tag);
277
- // sourceTags.forEach(tag => debug(`Comparing field ${tag}`));
278
- // /*
279
- // if (combine.length > 0) {
280
- // debug(`*** NOW Copy options: ${tagPattern}, ${compareTagsOnly}, ${compareWithoutIndicators}, ${subfieldsMustBeIdentical}, [${combine}], [${excludeSubfields}], [${dropSubfields}]`);
281
- // combine.forEach(row => debug(` ### combine ${row} <- `));
282
- // return [];
283
- // }
284
- // */
285
- // // If compareTagsOnly = true, only this part is run
286
- // // The field is copied from source only if it is missing completely from base
287
- // if (compareTagsOnly && baseFields.length === 0) {
288
- // sourceTags.forEach(tag => debug(`Missing field ${tag} copied from source to base`));
289
- // sourceFields.forEach(f => base.insertField(f));
290
- // return true;
291
- // }
292
- // // If compareTagsOnly = false (default)
293
- // // Source and base are also compared for identicalness
294
- // // Non-identical fields are copied from source to base as duplicates
295
- // if (!compareTagsOnly) {
296
- // const filterMissing = function (sourceField) {
297
- // if ('value' in sourceField) {
298
- // debug(`Checking control field ${sourceField.tag} for identicalness`);
299
- // return baseFields.some(isIdenticalControlField) === false;
300
- // }
301
- // if ('subfields' in sourceField) {
302
- // debug(`Checking data field ${sourceField.tag} for identicalness`);
303
- // return baseFields.some(isIdenticalDataField) === false;
304
- // }
305
- // function normalizeControlField(field) {
306
- // return field.value.toLowerCase().replace(/\s+/u, '');
307
- // }
308
- // function isIdenticalControlField(baseField) {
309
- // const normalizedBaseField = normalizeControlField(baseField);
310
- // const normalizedSourceField = normalizeControlField(sourceField);
311
- // return normalizedSourceField === normalizedBaseField;
312
- // }
313
- // function isIdenticalDataField(baseField) {
314
- // // If excluded subfields have been defined for this field, they must be ignored first
315
- // // (i.e. source and base fields are considered identical if all non-excluded subfields are identical)
316
- // if (excludeSubfields.length > 0 &&
317
- // sourceField.tag === baseField.tag &&
318
- // sourceField.ind1 === baseField.ind1 &&
319
- // sourceField.ind2 === baseField.ind2) {
320
- // excludeSubfields.forEach(sub => debug(`Subfield ${sub} excluded from identicalness comparison`));
321
- // // Compare only those subfields that are not excluded
322
- // const baseSubsToCompare = baseField.subfields.filter(subfield => excludeSubfields.indexOf(subfield.code) === -1);
323
- // return baseSubsToCompare.every(isIdenticalSubfield);
324
- // }
325
- // // If there are no excluded subfields (default case)
326
- // if (sourceField.tag === baseField.tag &&
327
- // sourceField.ind1 === baseField.ind1 &&
328
- // sourceField.ind2 === baseField.ind2 &&
329
- // sourceField.subfields.length === baseField.subfields.length) {
330
- // return baseField.subfields.every(isIdenticalSubfield);
331
- // }
332
- // function normalizeSubfield(subfield) {
333
- // return subfield.value.toLowerCase().replace(/\s+/u, '');
334
- // }
335
- // function isIdenticalSubfield(baseSub) {
336
- // const normBaseSub = normalizeSubfield(baseSub);
337
- // return sourceField.subfields.some(sourceSub => {
338
- // const normSourceSub = normalizeSubfield(sourceSub);
339
- // return normSourceSub === normBaseSub;
340
- // });
341
- // }
342
- // }
343
- // };
344
- // // Search for fields missing from base
345
- // const missingFields = sourceFields.filter(filterMissing);
346
- // missingFields.forEach(f => base.insertField(f));
347
- // if (missingFields.length > 0) {
348
- // const missingTags = missingFields.map(field => field.tag);
349
- // missingTags.forEach(tag => debug(`Field ${tag} copied from source to base`));
350
- // return base;
351
- // }
352
- // if (missingFields.length === 0) {
353
- // debug(`No missing fields found`);
354
- // return base;
355
- // }
356
- // }
357
- // debug(`No missing fields found`);
358
- // return base;
359
- // }
360
-
361
-
272
+ };
362
273
  exports.default = _default;
363
274
  //# sourceMappingURL=copy.js.map