@natlibfi/marc-record-validators-melinda 10.8.0 → 10.8.1-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 (46) hide show
  1. package/dist/mergeRelatorTermFields.js +140 -0
  2. package/dist/mergeRelatorTermFields.js.map +1 -0
  3. package/dist/mergeRelatorTermFields.spec.js +51 -0
  4. package/dist/mergeRelatorTermFields.spec.js.map +1 -0
  5. package/dist/punctuation2.js +53 -22
  6. package/dist/punctuation2.js.map +1 -1
  7. package/dist/removeInferiorDataFields.js +14 -0
  8. package/dist/removeInferiorDataFields.js.map +1 -1
  9. package/dist/sortRelatorTerms.js +3 -1
  10. package/dist/sortRelatorTerms.js.map +1 -1
  11. package/dist/sortSubfields.js +5 -4
  12. package/dist/sortSubfields.js.map +1 -1
  13. package/dist/update-field-540.js +7 -1
  14. package/dist/update-field-540.js.map +1 -1
  15. package/package.json +4 -4
  16. package/src/mergeRelatorTermFields.js +143 -0
  17. package/src/mergeRelatorTermFields.spec.js +52 -0
  18. package/src/punctuation2.js +54 -23
  19. package/src/removeInferiorDataFields.js +14 -0
  20. package/src/sortRelatorTerms.js +4 -1
  21. package/src/sortSubfields.js +5 -4
  22. package/src/update-field-540.js +2 -1
  23. package/test-fixtures/mergeRelatorTermFields/fixer/01/expectedResult.json +14 -0
  24. package/test-fixtures/mergeRelatorTermFields/fixer/01/metadata.json +6 -0
  25. package/test-fixtures/mergeRelatorTermFields/fixer/01/record.json +16 -0
  26. package/test-fixtures/mergeRelatorTermFields/fixer/02/expectedResult.json +17 -0
  27. package/test-fixtures/mergeRelatorTermFields/fixer/02/metadata.json +6 -0
  28. package/test-fixtures/mergeRelatorTermFields/fixer/02/record.json +23 -0
  29. package/test-fixtures/mergeRelatorTermFields/validator/01/expectedResult.json +6 -0
  30. package/test-fixtures/mergeRelatorTermFields/validator/01/metadata.json +6 -0
  31. package/test-fixtures/mergeRelatorTermFields/validator/01/record.json +16 -0
  32. package/test-fixtures/mergeRelatorTermFields/validator/02/expectedResult.json +4 -0
  33. package/test-fixtures/mergeRelatorTermFields/validator/02/metadata.json +6 -0
  34. package/test-fixtures/mergeRelatorTermFields/validator/02/record.json +16 -0
  35. package/test-fixtures/punctuation2/98/expectedResult.json +6 -0
  36. package/test-fixtures/punctuation2/98/metadata.json +1 -1
  37. package/test-fixtures/punctuation2/98/record.json +6 -0
  38. package/test-fixtures/remove-inferior-datafields/f05/expectedResult.json +18 -1
  39. package/test-fixtures/remove-inferior-datafields/f05/metadata.json +1 -2
  40. package/test-fixtures/remove-inferior-datafields/f05/record.json +16 -0
  41. package/test-fixtures/remove-inferior-datafields/f06/expectedResult.json +16 -0
  42. package/test-fixtures/remove-inferior-datafields/f06/metadata.json +6 -0
  43. package/test-fixtures/remove-inferior-datafields/f06/record.json +20 -0
  44. package/test-fixtures/sort-subfields/f01/expectedResult.json +8 -0
  45. package/test-fixtures/sort-subfields/f01/metadata.json +1 -1
  46. package/test-fixtures/sort-subfields/f01/record.json +6 -0
@@ -0,0 +1,140 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = _default;
7
+ var _clone = _interopRequireDefault(require("clone"));
8
+ var _punctuation = require("./punctuation2");
9
+ var _utils = require("./utils");
10
+ var _sortSubfields = require("./sortSubfields");
11
+ var _sortRelatorTerms = require("./sortRelatorTerms");
12
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
+ // Merge author/agent fields
14
+ //
15
+ // Rationale: Same author can appear in one 1XX and multiple 7XX fields having only different $e subfields.
16
+ // These fields can be merged (and $e-subfields can then be sorted)...
17
+ //
18
+ // Author(s): Nicholas Volk
19
+
20
+ //import createDebugLogger from 'debug';
21
+ /*
22
+ //const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:mergeRelatorTermFields');
23
+ //const debugData = debug.extend('data');
24
+ */
25
+ function _default() {
26
+ return {
27
+ description: 'Merge author fields that only differ in $e relator terms',
28
+ validate,
29
+ fix
30
+ };
31
+ function fix(record) {
32
+ const msg = mergeRelatorTermFields(record, true);
33
+ const res = {
34
+ message: msg,
35
+ fix: msg,
36
+ valid: true
37
+ };
38
+ return res;
39
+ }
40
+ function validate(record) {
41
+ const msg = mergeRelatorTermFields(record, false);
42
+ const res = {
43
+ message: msg
44
+ };
45
+ res.valid = !(res.message.length >= 1); // eslint-disable-line functional/immutable-data
46
+ return res;
47
+ }
48
+ }
49
+ function createNormalizedClone(field) {
50
+ const clonedField = (0, _clone.default)(field);
51
+ // Normalize
52
+ (0, _punctuation.fieldStripPunctuation)(clonedField);
53
+ return clonedField;
54
+ }
55
+ function createNormalizedCloneWithoutRelatorTerms(field) {
56
+ const clonedField = createNormalizedClone(field);
57
+ // Remove relator terms $e subfi:
58
+ clonedField.subfields = clonedField.subfields.filter(sf => sf.code !== 'e'); // eslint-disable-line functional/immutable-data
59
+ return clonedField;
60
+ }
61
+ function fieldToRelatorTermSubfieldCode(field) {
62
+ if (['100', '110', '700', '710', '720', '751', '752'].includes(field.tag)) {
63
+ return 'e';
64
+ }
65
+ if (field.tag === '111' || field.tag === '711') {
66
+ return 'j';
67
+ }
68
+ return '?'; // No need to complain. Nothing is found.
69
+ }
70
+
71
+ function getRelatorTermStrings(relatorTermSubfieldCode, field) {
72
+ return field.subfields.filter(sf => sf.code === relatorTermSubfieldCode).map(sf => sf.value);
73
+ }
74
+ function extractAddableRelatorTerms(fromField, toField) {
75
+ const relatorTermSubfieldCode = fieldToRelatorTermSubfieldCode(fromField);
76
+ const normalizedFromFieldRelatorTerms = getRelatorTermStrings(relatorTermSubfieldCode, fromField);
77
+ if (normalizedFromFieldRelatorTerms.length === 0) {
78
+ return [];
79
+ }
80
+ // Remove values that already exist:
81
+ const normalizedToFieldRelatorTerms = getRelatorTermStrings(relatorTermSubfieldCode, toField);
82
+ return normalizedFromFieldRelatorTerms.filter(str => !normalizedToFieldRelatorTerms.includes(str));
83
+ }
84
+ function copyRelatorSubfields(fromField, toField) {
85
+ const relatorTermSubfieldCode = fieldToRelatorTermSubfieldCode(fromField);
86
+ const newRelatorTerms = extractAddableRelatorTerms(fromField, toField);
87
+ newRelatorTerms.forEach(term => toField.subfields.push({
88
+ code: relatorTermSubfieldCode,
89
+ value: term
90
+ })); // eslint-disable-line functional/immutable-data
91
+ }
92
+
93
+ function mergeRelatorTermFields(record, fix = false) {
94
+ /* eslint-disable */
95
+ // NV: 111/711, 751 and 752 where so rare that I did not add them here
96
+ let fields = record.get('(?:[17][01]0|720)');
97
+ let result = [];
98
+ const comparisonFieldsAsString = fields.map(f => (0, _utils.fieldToString)(createNormalizedCloneWithoutRelatorTerms(f)));
99
+ (0, _utils.nvdebug)(`mergeRelatorTermFields(): ${fields.length} cand field(s) found`);
100
+ for (let i = 0; i < fields.length - 1; i++) {
101
+ let currField = fields[i];
102
+ if (currField.deleted) {
103
+ continue;
104
+ }
105
+ (0, _utils.nvdebug)(`RT: Trying to pair ${comparisonFieldsAsString[i]}/${i}`);
106
+ for (let j = i + 1; j < fields.length; j++) {
107
+ (0, _utils.nvdebug)(` Compare with ${comparisonFieldsAsString[j]}/${j}`);
108
+ let mergableField = fields[j];
109
+ // Skip 1/7 from 1XX/7XX for similarity check:
110
+ if (comparisonFieldsAsString[i].substring(1) !== comparisonFieldsAsString[j].substring(1)) {
111
+ (0, _utils.nvdebug)(" NOT PAIR");
112
+ continue;
113
+ }
114
+ if (mergableField.deleted) {
115
+ (0, _utils.nvdebug)(" DELETED");
116
+ continue;
117
+ }
118
+ const str = `MERGE RELATOR TERM FIELD: ${(0, _utils.fieldToString)(mergableField)}`;
119
+ (0, _utils.nvdebug)(str);
120
+ if (!result.includes(str)) {
121
+ result.push(str);
122
+ }
123
+ if (fix) {
124
+ mergableField.deleted = 1;
125
+ copyRelatorSubfields(mergableField, currField);
126
+ (0, _punctuation.fieldFixPunctuation)(currField);
127
+ (0, _sortSubfields.sortAdjacentSubfields)(currField); // Put the added $e subfield to proper places.
128
+ (0, _sortRelatorTerms.sortAdjacentESubfields)(currField); // Sort $e subfields with each other
129
+ (0, _punctuation.fieldFixPunctuation)(currField);
130
+ }
131
+ }
132
+ }
133
+ if (!fix) {
134
+ fields.forEach(f => delete f.deleted);
135
+ }
136
+ record.fields = record.fields.filter(f => !f.deleted);
137
+ /* eslint-enable */
138
+ return result;
139
+ }
140
+ //# sourceMappingURL=mergeRelatorTermFields.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mergeRelatorTermFields.js","names":["_clone","_interopRequireDefault","require","_punctuation","_utils","_sortSubfields","_sortRelatorTerms","obj","__esModule","default","_default","description","validate","fix","record","msg","mergeRelatorTermFields","res","message","valid","length","createNormalizedClone","field","clonedField","clone","fieldStripPunctuation","createNormalizedCloneWithoutRelatorTerms","subfields","filter","sf","code","fieldToRelatorTermSubfieldCode","includes","tag","getRelatorTermStrings","relatorTermSubfieldCode","map","value","extractAddableRelatorTerms","fromField","toField","normalizedFromFieldRelatorTerms","normalizedToFieldRelatorTerms","str","copyRelatorSubfields","newRelatorTerms","forEach","term","push","fields","get","result","comparisonFieldsAsString","f","fieldToString","nvdebug","i","currField","deleted","j","mergableField","substring","fieldFixPunctuation","sortAdjacentSubfields","sortAdjacentESubfields"],"sources":["../src/mergeRelatorTermFields.js"],"sourcesContent":["// Merge author/agent fields\n//\n// Rationale: Same author can appear in one 1XX and multiple 7XX fields having only different $e subfields.\n// These fields can be merged (and $e-subfields can then be sorted)...\n//\n// Author(s): Nicholas Volk\n\n\nimport clone from 'clone';\nimport {fieldFixPunctuation, fieldStripPunctuation} from './punctuation2';\nimport {fieldToString, nvdebug} from './utils';\nimport {sortAdjacentSubfields} from './sortSubfields';\nimport {sortAdjacentESubfields} from './sortRelatorTerms';\n//import createDebugLogger from 'debug';\n/*\n//const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:mergeRelatorTermFields');\n//const debugData = debug.extend('data');\n*/\n\nexport default function () {\n\n return {\n description: 'Merge author fields that only differ in $e relator terms',\n validate, fix\n };\n\n function fix(record) {\n const msg = mergeRelatorTermFields(record, true);\n const res = {message: msg, fix: msg, valid: true};\n return res;\n }\n\n function validate(record) {\n const msg = mergeRelatorTermFields(record, false);\n const res = {message: msg};\n\n res.valid = !(res.message.length >= 1); // eslint-disable-line functional/immutable-data\n return res;\n }\n}\n\nfunction createNormalizedClone(field) {\n const clonedField = clone(field);\n // Normalize\n fieldStripPunctuation(clonedField);\n return clonedField;\n}\n\nfunction createNormalizedCloneWithoutRelatorTerms(field) {\n const clonedField = createNormalizedClone(field);\n // Remove relator terms $e subfi:\n clonedField.subfields = clonedField.subfields.filter(sf => sf.code !== 'e'); // eslint-disable-line functional/immutable-data\n return clonedField;\n}\n\nfunction fieldToRelatorTermSubfieldCode(field) {\n if (['100', '110', '700', '710', '720', '751', '752'].includes(field.tag)) {\n return 'e';\n }\n if (field.tag === '111' || field.tag === '711') {\n return 'j';\n }\n return '?'; // No need to complain. Nothing is found.\n}\n\nfunction getRelatorTermStrings(relatorTermSubfieldCode, field) {\n return field.subfields.filter(sf => sf.code === relatorTermSubfieldCode).map(sf => sf.value);\n\n}\n\nfunction extractAddableRelatorTerms(fromField, toField) {\n const relatorTermSubfieldCode = fieldToRelatorTermSubfieldCode(fromField);\n const normalizedFromFieldRelatorTerms = getRelatorTermStrings(relatorTermSubfieldCode, fromField);\n if (normalizedFromFieldRelatorTerms.length === 0) {\n return [];\n }\n // Remove values that already exist:\n const normalizedToFieldRelatorTerms = getRelatorTermStrings(relatorTermSubfieldCode, toField);\n return normalizedFromFieldRelatorTerms.filter(str => !normalizedToFieldRelatorTerms.includes(str));\n}\n\n\nfunction copyRelatorSubfields(fromField, toField) {\n const relatorTermSubfieldCode = fieldToRelatorTermSubfieldCode(fromField);\n const newRelatorTerms = extractAddableRelatorTerms(fromField, toField);\n\n newRelatorTerms.forEach(term => toField.subfields.push({code: relatorTermSubfieldCode, value: term})); // eslint-disable-line functional/immutable-data\n\n}\n\nfunction mergeRelatorTermFields(record, fix = false) {\n /* eslint-disable */\n // NV: 111/711, 751 and 752 where so rare that I did not add them here\n let fields = record.get('(?:[17][01]0|720)'); \n let result = [];\n const comparisonFieldsAsString = fields.map(f => fieldToString(createNormalizedCloneWithoutRelatorTerms(f)));\n\n nvdebug(`mergeRelatorTermFields(): ${fields.length} cand field(s) found`);\n for(let i=0; i < fields.length-1; i++) {\n let currField = fields[i];\n if (currField.deleted) {\n continue;\n }\n nvdebug(`RT: Trying to pair ${comparisonFieldsAsString[i]}/${i}`);\n for (let j=i+1; j < fields.length; j++) {\n nvdebug(` Compare with ${comparisonFieldsAsString[j]}/${j}`);\n let mergableField = fields[j];\n // Skip 1/7 from 1XX/7XX for similarity check:\n if ( comparisonFieldsAsString[i].substring(1) !== comparisonFieldsAsString[j].substring(1)) {\n nvdebug(\" NOT PAIR\");\n continue;\n }\n if (mergableField.deleted) {\n nvdebug(\" DELETED\");\n continue;\n }\n const str = `MERGE RELATOR TERM FIELD: ${fieldToString(mergableField)}`;\n nvdebug(str);\n\n if(!result.includes(str)) {\n result.push(str)\n }\n\n if (fix) {\n mergableField.deleted = 1;\n copyRelatorSubfields(mergableField, currField);\n fieldFixPunctuation(currField);\n sortAdjacentSubfields(currField); // Put the added $e subfield to proper places.\n sortAdjacentESubfields(currField); // Sort $e subfields with each other\n fieldFixPunctuation(currField);\n\n }\n }\n }\n\n if(!fix) {\n fields.forEach(f => delete f.deleted);\n }\n\n record.fields = record.fields.filter(f => !f.deleted);\n /* eslint-enable */\n return result;\n}\n"],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+
3
+ var _chai = require("chai");
4
+ var _marcRecord = require("@natlibfi/marc-record");
5
+ var _mergeRelatorTermFields = _interopRequireDefault(require("./mergeRelatorTermFields"));
6
+ var _fixura = require("@natlibfi/fixura");
7
+ var _fixugen = _interopRequireDefault(require("@natlibfi/fixugen"));
8
+ var _debug = _interopRequireDefault(require("debug"));
9
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10
+ (0, _fixugen.default)({
11
+ callback,
12
+ path: [__dirname, '..', 'test-fixtures', 'mergeRelatorTermFields'],
13
+ useMetadataFile: true,
14
+ recurse: true,
15
+ fixura: {
16
+ reader: _fixura.READERS.JSON
17
+ },
18
+ mocha: {
19
+ before: () => testValidatorFactory()
20
+ }
21
+ });
22
+ const debug = (0, _debug.default)('@natlibfi/marc-record-validators-melinda/mergeRelatorTermFields:test');
23
+ async function testValidatorFactory() {
24
+ const validator = await (0, _mergeRelatorTermFields.default)();
25
+ (0, _chai.expect)(validator).to.be.an('object').that.has.any.keys('description', 'validate');
26
+ (0, _chai.expect)(validator.description).to.be.a('string');
27
+ (0, _chai.expect)(validator.validate).to.be.a('function');
28
+ }
29
+ async function callback({
30
+ getFixture,
31
+ enabled = true,
32
+ fix = false
33
+ }) {
34
+ if (enabled === false) {
35
+ debug('TEST SKIPPED!');
36
+ return;
37
+ }
38
+ const validator = await (0, _mergeRelatorTermFields.default)();
39
+ const record = new _marcRecord.MarcRecord(getFixture('record.json'));
40
+ const expectedResult = getFixture('expectedResult.json');
41
+ // console.log(expectedResult); // eslint-disable-line
42
+
43
+ if (!fix) {
44
+ const result = await validator.validate(record);
45
+ (0, _chai.expect)(result).to.eql(expectedResult);
46
+ return;
47
+ }
48
+ await validator.fix(record);
49
+ (0, _chai.expect)(record).to.eql(expectedResult);
50
+ }
51
+ //# sourceMappingURL=mergeRelatorTermFields.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mergeRelatorTermFields.spec.js","names":["_chai","require","_marcRecord","_mergeRelatorTermFields","_interopRequireDefault","_fixura","_fixugen","_debug","obj","__esModule","default","generateTests","callback","path","__dirname","useMetadataFile","recurse","fixura","reader","READERS","JSON","mocha","before","testValidatorFactory","debug","createDebugLogger","validator","validatorFactory","expect","to","be","an","that","has","any","keys","description","a","validate","getFixture","enabled","fix","record","MarcRecord","expectedResult","result","eql"],"sources":["../src/mergeRelatorTermFields.spec.js"],"sourcesContent":["import {expect} from 'chai';\nimport {MarcRecord} from '@natlibfi/marc-record';\nimport validatorFactory from './mergeRelatorTermFields';\nimport {READERS} from '@natlibfi/fixura';\nimport generateTests from '@natlibfi/fixugen';\nimport createDebugLogger from 'debug';\n\ngenerateTests({\n callback,\n path: [__dirname, '..', 'test-fixtures', 'mergeRelatorTermFields'],\n useMetadataFile: true,\n recurse: true,\n fixura: {\n reader: READERS.JSON\n },\n mocha: {\n before: () => testValidatorFactory()\n }\n});\nconst debug = createDebugLogger('@natlibfi/marc-record-validators-melinda/mergeRelatorTermFields:test');\n\nasync function testValidatorFactory() {\n const validator = await validatorFactory();\n\n expect(validator)\n .to.be.an('object')\n .that.has.any.keys('description', 'validate');\n\n expect(validator.description).to.be.a('string');\n expect(validator.validate).to.be.a('function');\n}\n\nasync function callback({getFixture, enabled = true, fix = false}) {\n if (enabled === false) {\n debug('TEST SKIPPED!');\n return;\n }\n\n const validator = await validatorFactory();\n const record = new MarcRecord(getFixture('record.json'));\n const expectedResult = getFixture('expectedResult.json');\n // console.log(expectedResult); // eslint-disable-line\n\n if (!fix) {\n const result = await validator.validate(record);\n expect(result).to.eql(expectedResult);\n return;\n }\n\n await validator.fix(record);\n expect(record).to.eql(expectedResult);\n}\n"],"mappings":";;AAAA,IAAAA,KAAA,GAAAC,OAAA;AACA,IAAAC,WAAA,GAAAD,OAAA;AACA,IAAAE,uBAAA,GAAAC,sBAAA,CAAAH,OAAA;AACA,IAAAI,OAAA,GAAAJ,OAAA;AACA,IAAAK,QAAA,GAAAF,sBAAA,CAAAH,OAAA;AACA,IAAAM,MAAA,GAAAH,sBAAA,CAAAH,OAAA;AAAsC,SAAAG,uBAAAI,GAAA,WAAAA,GAAA,IAAAA,GAAA,CAAAC,UAAA,GAAAD,GAAA,KAAAE,OAAA,EAAAF,GAAA;AAEtC,IAAAG,gBAAa,EAAC;EACZC,QAAQ;EACRC,IAAI,EAAE,CAACC,SAAS,EAAE,IAAI,EAAE,eAAe,EAAE,wBAAwB,CAAC;EAClEC,eAAe,EAAE,IAAI;EACrBC,OAAO,EAAE,IAAI;EACbC,MAAM,EAAE;IACNC,MAAM,EAAEC,eAAO,CAACC;EAClB,CAAC;EACDC,KAAK,EAAE;IACLC,MAAM,EAAEA,CAAA,KAAMC,oBAAoB,CAAC;EACrC;AACF,CAAC,CAAC;AACF,MAAMC,KAAK,GAAG,IAAAC,cAAiB,EAAC,sEAAsE,CAAC;AAEvG,eAAeF,oBAAoBA,CAAA,EAAG;EACpC,MAAMG,SAAS,GAAG,MAAM,IAAAC,+BAAgB,EAAC,CAAC;EAE1C,IAAAC,YAAM,EAACF,SAAS,CAAC,CACdG,EAAE,CAACC,EAAE,CAACC,EAAE,CAAC,QAAQ,CAAC,CAClBC,IAAI,CAACC,GAAG,CAACC,GAAG,CAACC,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC;EAE/C,IAAAP,YAAM,EAACF,SAAS,CAACU,WAAW,CAAC,CAACP,EAAE,CAACC,EAAE,CAACO,CAAC,CAAC,QAAQ,CAAC;EAC/C,IAAAT,YAAM,EAACF,SAAS,CAACY,QAAQ,CAAC,CAACT,EAAE,CAACC,EAAE,CAACO,CAAC,CAAC,UAAU,CAAC;AAChD;AAEA,eAAezB,QAAQA,CAAC;EAAC2B,UAAU;EAAEC,OAAO,GAAG,IAAI;EAAEC,GAAG,GAAG;AAAK,CAAC,EAAE;EACjE,IAAID,OAAO,KAAK,KAAK,EAAE;IACrBhB,KAAK,CAAC,eAAe,CAAC;IACtB;EACF;EAEA,MAAME,SAAS,GAAG,MAAM,IAAAC,+BAAgB,EAAC,CAAC;EAC1C,MAAMe,MAAM,GAAG,IAAIC,sBAAU,CAACJ,UAAU,CAAC,aAAa,CAAC,CAAC;EACxD,MAAMK,cAAc,GAAGL,UAAU,CAAC,qBAAqB,CAAC;EACxD;;EAEA,IAAI,CAACE,GAAG,EAAE;IACR,MAAMI,MAAM,GAAG,MAAMnB,SAAS,CAACY,QAAQ,CAACI,MAAM,CAAC;IAC/C,IAAAd,YAAM,EAACiB,MAAM,CAAC,CAAChB,EAAE,CAACiB,GAAG,CAACF,cAAc,CAAC;IACrC;EACF;EAEA,MAAMlB,SAAS,CAACe,GAAG,CAACC,MAAM,CAAC;EAC3B,IAAAd,YAAM,EAACc,MAAM,CAAC,CAACb,EAAE,CAACiB,GAAG,CAACF,cAAc,CAAC;AACvC"}
@@ -17,6 +17,8 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
17
17
  *
18
18
  * NOTE #1: https://www.kiwi.fi/display/kumea/Loppupisteohje is implemented via another validator/fixer.(ending-punctuation)
19
19
  * NOTE #2: Validator/fixer punctuation does similar stuff, but focuses on X00 fields.
20
+ * NOTE #3: As of 2023-06-05 control subfields ($0...$9) are obsolete. Don't use them in rules.
21
+ * (They are jumped over when looking for next (non-controlfield subfield)
20
22
  */
21
23
 
22
24
  // import createDebugLogger from 'debug';
@@ -52,12 +54,18 @@ function _default() {
52
54
  return res;
53
55
  }
54
56
  }
57
+ function isControlSubfield(subfield) {
58
+ return ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'].includes(subfield.code);
59
+ }
60
+ function getNextRelevantSubfield(field, currSubfieldIndex) {
61
+ return field.subfields.find((subfield, index) => index > currSubfieldIndex && !isControlSubfield(subfield));
62
+ }
55
63
  function fieldGetFixedString(field) {
56
64
  const cloneField = (0, _clone.default)(field);
57
65
  cloneField.subfields.forEach((sf, i) => {
58
66
  // NB! instead of next subfield, we should actually get next *non-control-subfield*!!!
59
67
  // (In plain English: We should skip $0 - $9 at least, maybe $w as well...)
60
- subfieldFixPunctuation(cloneField.tag, sf, i + 1 < cloneField.subfields.length ? cloneField.subfields[i + 1] : null);
68
+ subfieldFixPunctuation(cloneField, sf, getNextRelevantSubfield(cloneField, i));
61
69
  });
62
70
  return (0, _utils.fieldToString)(cloneField);
63
71
  }
@@ -92,7 +100,7 @@ const removeColons = {
92
100
  };
93
101
  const removeX00Comma = {
94
102
  'code': 'abcqde',
95
- 'followedBy': 'abcqde#01459',
103
+ 'followedBy': 'abcqde#',
96
104
  'context': /.,$/u,
97
105
  'remove': /,$/u
98
106
  };
@@ -105,7 +113,7 @@ const cleanRHS = {
105
113
  };
106
114
  const cleanX00dCommaOrDot = {
107
115
  'code': 'd',
108
- 'followedBy': 'et#01459',
116
+ 'followedBy': 'et#',
109
117
  'context': /[0-9]-[,.]$/u,
110
118
  'remove': /[,.]$/u
111
119
  };
@@ -122,7 +130,7 @@ const cleanCorruption = {
122
130
  // These $e dot removals are tricky: before removing the comma, we should know that it ain't an abbreviation such as "esitt."...
123
131
  const cleanX00eDot = {
124
132
  'code': 'e',
125
- 'followedBy': 'egj#059',
133
+ 'followedBy': 'egj#',
126
134
  'context': /(?:[ai]ja|jä)[.,]$/u,
127
135
  'remove': /\.$/u
128
136
  };
@@ -155,7 +163,7 @@ const addX00aComma2 = {
155
163
  const addX00aDot = {
156
164
  'add': '.',
157
165
  'code': 'abcde',
158
- 'followedBy': '#tu0159',
166
+ 'followedBy': '#tu',
159
167
  'context': defaultNeedsPuncAfter
160
168
  };
161
169
  const addX10bDot = {
@@ -175,7 +183,7 @@ const addX10Dot = {
175
183
  'name': 'Add X10 final dot',
176
184
  'add': '.',
177
185
  'code': 'abe',
178
- 'followedBy': '#0159',
186
+ 'followedBy': '#',
179
187
  'context': defaultNeedsPuncAfter
180
188
  };
181
189
  const addLanguageComma = {
@@ -272,13 +280,13 @@ const cleanLegalX00Comma = {
272
280
  // Accept upper case letters in X00$b, since they are probably Roman numerals.
273
281
  const cleanLegalX00bDot = {
274
282
  'code': 'b',
275
- 'followedBy': 't#01459',
283
+ 'followedBy': 't#',
276
284
  context: /^[IVXLCDM]+\.$/u,
277
285
  'remove': /\.$/u
278
286
  };
279
287
  const cleanLegalX00Dot = {
280
288
  'code': 'abcdetvl',
281
- 'followedBy': 'tu#01459',
289
+ 'followedBy': 'tu#',
282
290
  'context': /(?:[a-z0-9)]|å|ä|ö)\.$/u,
283
291
  'remove': /\.$/u
284
292
  };
@@ -300,7 +308,7 @@ const cleanLegalX10Comma = {
300
308
  const cleanLegalX10Dot = {
301
309
  'name': 'X10dot',
302
310
  'code': 'ab',
303
- 'followedBy': 'b#059',
311
+ 'followedBy': 'b#',
304
312
  'context': /.\.$/u,
305
313
  'remove': /\.$/u
306
314
  };
@@ -418,6 +426,13 @@ const cleanValidPunctuationRules = {
418
426
  'code': 'p',
419
427
  'followedBy': 'c',
420
428
  'remove': /:$/u
429
+ }],
430
+ // Experimental, MET366-ish (end punc in internationally valid, but we don't use it here in Finland):
431
+ '648': [{
432
+ 'code': 'a',
433
+ 'content': /^[0-9]+\.$/u,
434
+ 'ind2': ['4'],
435
+ 'remove': /\.$/u
421
436
  }]
422
437
  };
423
438
 
@@ -550,6 +565,18 @@ function ruleAppliesToSubfieldCode(targetSubfieldCodes, currSubfieldCode) {
550
565
  }
551
566
  return targetSubfieldCodes.includes(currSubfieldCode);
552
567
  }
568
+ function ruleAppliesToField(rule, field) {
569
+ if ('ind1' in rule && field.ind1.includes(rule.ind1)) {
570
+ return false;
571
+ }
572
+ if ('ind2' in rule && field.ind2.includes(rule.ind2)) {
573
+ return false;
574
+ }
575
+
576
+ // If we want to check, say, $2, it should be implemented here!
577
+
578
+ return true;
579
+ }
553
580
  function ruleAppliesToCurrentSubfield(rule, subfield) {
554
581
  if (!ruleAppliesToSubfieldCode(rule.code, subfield.code)) {
555
582
  return false;
@@ -566,7 +593,7 @@ function ruleAppliesToNextSubfield(rule, nextSubfield) {
566
593
  return true;
567
594
  }
568
595
  // The '#' existence check applies only to the RHS field. LHS always exists.
569
- if (nextSubfield === null) {
596
+ if (!nextSubfield) {
570
597
  const negation = rule.followedBy.includes('!');
571
598
  if (negation) {
572
599
  return !rule.followedBy.includes('#');
@@ -582,16 +609,20 @@ function ruleAppliesToNextSubfield(rule, nextSubfield) {
582
609
  }
583
610
  return true;
584
611
  }
585
- function checkRule(rule, subfield1, subfield2) {
612
+ function checkRule(rule, field, subfield1, subfield2) {
613
+ if (!ruleAppliesToField(rule, field)) {
614
+ (0, _utils.nvdebug)(`FAIL ON WHOLE FIELD: '${(0, _utils.fieldToString)(field)}`);
615
+ return false;
616
+ }
586
617
  //const name = rule.name || 'UNNAMED';
587
618
  if (!ruleAppliesToCurrentSubfield(rule, subfield1)) {
588
- //nvdebug(`${name}: FAIL ON LHS FIELD: '$${subfield1.code} ${subfield1.value}', SF=${rule.code}`, debug);
619
+ //nvdebug(`${name}: FAIL ON LHS SUBFIELD: '$${subfield1.code} ${subfield1.value}', SF=${rule.code}`, debug);
589
620
  return false;
590
621
  }
591
622
 
592
623
  // NB! This is not a perfect solution. We might have $e$0$e where $e$0 punctuation should actually be based on $e$e rules
593
624
  if (!ruleAppliesToNextSubfield(rule, subfield2)) {
594
- //const msg = subfield2 ? `${name}: FAIL ON RHS FIELD '${subfield2.code}' not in [${rule.followedBy}]` : `${name}: FAIL ON RHS FIELD`;
625
+ //const msg = subfield2 ? `${name}: FAIL ON RHS SUBFIELD '${subfield2.code}' not in [${rule.followedBy}]` : `${name}: FAIL ON RHS FIELD`;
595
626
  //nvdebug(msg, debug);
596
627
  return false;
597
628
  }
@@ -599,14 +630,14 @@ function checkRule(rule, subfield1, subfield2) {
599
630
  //nvdebug(`${name}: ACCEPT ${rule.code}/${subfield1.code}, SF2=${rule.followedBy}/${subfield2 ? subfield2.code : '#'}`, debug);
600
631
  return true;
601
632
  }
602
- function applyPunctuationRules(tag, subfield1, subfield2, ruleArray = null, operation = NONE) {
633
+ function applyPunctuationRules(field, subfield1, subfield2, ruleArray = null, operation = NONE) {
603
634
  /*
604
635
  if (ruleArray === null || operation === NONE) {
605
636
  debug(`applyPunctuation(): No rules to apply!`);
606
637
  return;
607
638
  }
608
639
  */
609
- if (!(`${tag}` in ruleArray) || ruleArray === null || operation === NONE) {
640
+ if (!(`${field.tag}` in ruleArray) || ruleArray === null || operation === NONE) {
610
641
  /*
611
642
  if (!['020', '650'].includes(tag) || !isControlSubfieldCode(subfield1.code)) { // eslint-disable-line functional/no-conditional-statements
612
643
  nvdebug(`No punctuation rules found for ${tag} (looking for: ‡${subfield1.code})`, debug);
@@ -616,7 +647,7 @@ function applyPunctuationRules(tag, subfield1, subfield2, ruleArray = null, oper
616
647
  }
617
648
 
618
649
  //nvdebug(`OP=${operation} ${tag}: '${subfield1.code}: ${subfield1.value}' ??? '${subfield2 ? subfield2.code : '#'}'`, debug);
619
- const activeRules = ruleArray[tag].filter(rule => checkRule(rule, subfield1, subfield2));
650
+ const activeRules = ruleArray[field.tag].filter(rule => checkRule(rule, field, subfield1, subfield2));
620
651
  activeRules.forEach(rule => {
621
652
  const originalValue = subfield1.value;
622
653
  if (rule.remove && [REMOVE, REMOVE_AND_ADD].includes(operation) && subfield1.value.match(rule.remove)) {
@@ -637,9 +668,9 @@ function applyPunctuationRules(tag, subfield1, subfield2, ruleArray = null, oper
637
668
  }
638
669
  });
639
670
  }
640
- function subfieldFixPunctuation(tag, subfield1, subfield2) {
641
- applyPunctuationRules(tag, subfield1, subfield2, cleanCrappyPunctuationRules, REMOVE);
642
- applyPunctuationRules(tag, subfield1, subfield2, addPairedPunctuationRules, ADD);
671
+ function subfieldFixPunctuation(field, subfield1, subfield2) {
672
+ applyPunctuationRules(field, subfield1, subfield2, cleanCrappyPunctuationRules, REMOVE);
673
+ applyPunctuationRules(field, subfield1, subfield2, addPairedPunctuationRules, ADD);
643
674
  }
644
675
  function fieldStripPunctuation(field) {
645
676
  if (!field.subfields) {
@@ -647,9 +678,9 @@ function fieldStripPunctuation(field) {
647
678
  }
648
679
  field.subfields.forEach((sf, i) => {
649
680
  (0, _utils.nvdebug)(`FSP1: '${sf.value}'`);
650
- applyPunctuationRules(field.tag, sf, i + 1 < field.subfields.length ? field.subfields[i + 1] : null, cleanValidPunctuationRules, REMOVE);
681
+ applyPunctuationRules(field, sf, i + 1 < field.subfields.length ? field.subfields[i + 1] : null, cleanValidPunctuationRules, REMOVE);
651
682
  (0, _utils.nvdebug)(`FSP2: '${sf.value}'`);
652
- applyPunctuationRules(field.tag, sf, i + 1 < field.subfields.length ? field.subfields[i + 1] : null, cleanCrappyPunctuationRules, REMOVE);
683
+ applyPunctuationRules(field, sf, i + 1 < field.subfields.length ? field.subfields[i + 1] : null, cleanCrappyPunctuationRules, REMOVE);
653
684
  (0, _utils.nvdebug)(`FSP3: '${sf.value}'`);
654
685
  });
655
686
  return field;
@@ -662,7 +693,7 @@ function fieldFixPunctuation(field) {
662
693
  field.subfields.forEach((sf, i) => {
663
694
  // NB! instead of next subfield, we should actually get next *non-control-subfield*!!!
664
695
  // (In plain English: We should skip $0 - $9 at least, maybe $w as well...)
665
- subfieldFixPunctuation(field.tag, sf, i + 1 < field.subfields.length ? field.subfields[i + 1] : null);
696
+ subfieldFixPunctuation(field, sf, getNextRelevantSubfield(field, i));
666
697
  });
667
698
 
668
699
  // Use shared code for final punctuation (sadly this does not fix intermediate punc):