@natlibfi/marc-record-validators-melinda 10.9.0 → 10.9.2

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 (49) hide show
  1. package/dist/field-521-fix.js +96 -0
  2. package/dist/field-521-fix.js.map +1 -0
  3. package/dist/field-521-fix.spec.js +51 -0
  4. package/dist/field-521-fix.spec.js.map +1 -0
  5. package/dist/index.js +7 -0
  6. package/dist/index.js.map +1 -1
  7. package/dist/indicator-fixes.js +2 -11
  8. package/dist/indicator-fixes.js.map +1 -1
  9. package/dist/normalize-identifiers.js +3 -12
  10. package/dist/normalize-identifiers.js.map +1 -1
  11. package/dist/normalize-utf8-diacritics.js +3 -9
  12. package/dist/normalize-utf8-diacritics.js.map +1 -1
  13. package/dist/utils.js +7 -1
  14. package/dist/utils.js.map +1 -1
  15. package/package.json +2 -2
  16. package/src/field-521-fix.js +92 -0
  17. package/src/field-521-fix.spec.js +52 -0
  18. package/src/index.js +2 -0
  19. package/src/indicator-fixes.js +1 -12
  20. package/src/normalize-identifiers.js +1 -10
  21. package/src/normalize-utf8-diacritics.js +1 -9
  22. package/src/utils.js +8 -1
  23. package/test-fixtures/fix521/01/expectedResult.json +6 -0
  24. package/test-fixtures/fix521/01/metadata.json +5 -0
  25. package/test-fixtures/fix521/01/record.json +13 -0
  26. package/test-fixtures/fix521/02/expectedResult.json +15 -0
  27. package/test-fixtures/fix521/02/metadata.json +5 -0
  28. package/test-fixtures/fix521/02/record.json +13 -0
  29. package/test-fixtures/fix521/03/expectedResult.json +5 -0
  30. package/test-fixtures/fix521/03/metadata.json +5 -0
  31. package/test-fixtures/fix521/03/record.json +13 -0
  32. package/test-fixtures/indicator-fixes/01/expectedResult.json +4 -4
  33. package/test-fixtures/mergeRelatorTermFields/validator/01/expectedResult.json +1 -1
  34. package/test-fixtures/normalize-identifiers/01/expectedResult.json +3 -3
  35. package/test-fixtures/normalize-utf8-diacritics/01/expectedResult.json +2 -2
  36. package/test-fixtures/punctuation2/01/expectedResult.json +6 -6
  37. package/test-fixtures/punctuation2/05/expectedResult.json +1 -1
  38. package/test-fixtures/remove-duplicate-datafields/v02/expectedResult.json +5 -5
  39. package/test-fixtures/remove-duplicate-datafields/v03/expectedResult.json +1 -1
  40. package/test-fixtures/remove-duplicate-datafields/v04/expectedResult.json +3 -3
  41. package/test-fixtures/remove-inferior-datafields/v02/expectedResult.json +1 -1
  42. package/test-fixtures/sanitize-vocabulary-source-codes/v01/expectedResult.json +7 -7
  43. package/test-fixtures/sort-relator-terms/v02/expectedResult.json +1 -1
  44. package/test-fixtures/sort-subfields/v02/expectedResult.json +1 -1
  45. package/test-fixtures/strip-punctuation/01/expectedResult.json +6 -6
  46. package/test-fixtures/strip-punctuation/05/expectedResult.json +1 -1
  47. package/test-fixtures/subfield0/v02/expectedResult.json +4 -4
  48. package/test-fixtures/update-field-540/v01/expectedResult.json +2 -2
  49. package/test-fixtures/normalize-utf8-diacritics/05/tmp.json +0 -41
@@ -0,0 +1,96 @@
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 _utils = require("./utils");
9
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10
+ //import createDebugLogger from 'debug';
11
+
12
+ // Author(s): Nicholas Volk
13
+ function _default() {
14
+ return {
15
+ description: 'Various fixes for field 521',
16
+ validate,
17
+ fix
18
+ };
19
+ function fix(record) {
20
+ record.fields.forEach(field => {
21
+ fix521(field);
22
+ });
23
+ // Fix always succeeds (even when it really does not):
24
+ const res = {
25
+ message: [],
26
+ fix: [],
27
+ valid: true
28
+ };
29
+ return res;
30
+ }
31
+ function validate(record) {
32
+ const res = {
33
+ message: []
34
+ };
35
+
36
+ // Actual parsing of all fields
37
+ /*
38
+ if (!record.fields) {
39
+ return false;
40
+ }
41
+ */
42
+
43
+ record.fields?.forEach(field => {
44
+ validateField(field, res);
45
+ });
46
+ res.valid = !(res.message.length >= 1); // eslint-disable-line functional/immutable-data
47
+ return res;
48
+ }
49
+ function validateField(field, res) {
50
+ const orig = (0, _utils.fieldToString)(field);
51
+ const normalizedField = fix521((0, _clone.default)(field));
52
+ const mod = (0, _utils.fieldToString)(normalizedField);
53
+ if (orig !== mod) {
54
+ // Fail as the input is "broken"/"crap"/sumthing
55
+ res.message.push(`'TODO: ${orig}' => '${mod}'`); // eslint-disable-line functional/immutable-data
56
+ return;
57
+ }
58
+ return;
59
+ }
60
+ }
61
+ function fixSubfieldA(a) {
62
+ a.value = a.value.
63
+ // eslint-disable-line functional/immutable-data
64
+ // MET-332:
65
+ replace(/^(Ikäsuositus) ([0-9])/u, '$1: $2'); // eslint-disable-line prefer-named-capture-group, functional/immutable-data
66
+ }
67
+
68
+ function fixSubfieldAInternalPunctuation(field) {
69
+ const a = field.subfields.filter(sf => sf.code === 'a');
70
+ a.forEach(sf => fixSubfieldA(sf));
71
+ }
72
+ function getIndicator1(field) {
73
+ const [a] = field.subfields.filter(sf => sf.code === 'a');
74
+ if (a) {
75
+ if (a.value.match(/^Ikäsuositus/u)) {
76
+ return '1';
77
+ }
78
+ }
79
+ return undefined;
80
+ }
81
+ function fixIndicator1(field) {
82
+ const value = getIndicator1(field);
83
+ if (value) {
84
+ field.ind1 = value; // eslint-disable-line functional/immutable-data
85
+ return;
86
+ }
87
+ }
88
+ function fix521(field) {
89
+ if (field.tag !== '521' || !field.subfields) {
90
+ return field;
91
+ }
92
+ fixIndicator1(field);
93
+ fixSubfieldAInternalPunctuation(field);
94
+ return field;
95
+ }
96
+ //# sourceMappingURL=field-521-fix.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-521-fix.js","names":["_clone","_interopRequireDefault","require","_utils","obj","__esModule","default","_default","description","validate","fix","record","fields","forEach","field","fix521","res","message","valid","validateField","length","orig","fieldToString","normalizedField","clone","mod","push","fixSubfieldA","a","value","replace","fixSubfieldAInternalPunctuation","subfields","filter","sf","code","getIndicator1","match","undefined","fixIndicator1","ind1","tag"],"sources":["../src/field-521-fix.js"],"sourcesContent":["//import createDebugLogger from 'debug';\nimport clone from 'clone';\nimport {fieldToString} from './utils';\n\n// Author(s): Nicholas Volk\nexport default function () {\n\n return {\n description: 'Various fixes for field 521',\n validate, fix\n };\n\n function fix(record) {\n record.fields.forEach(field => {\n fix521(field);\n });\n // Fix always succeeds (even when it really does not):\n const res = {message: [], fix: [], valid: true};\n return res;\n }\n\n function validate(record) {\n const res = {message: []};\n\n // Actual parsing of all fields\n /*\n if (!record.fields) {\n return false;\n }\n */\n\n record.fields?.forEach(field => {\n validateField(field, res);\n });\n\n res.valid = !(res.message.length >= 1); // eslint-disable-line functional/immutable-data\n return res;\n }\n\n function validateField(field, res) {\n const orig = fieldToString(field);\n\n const normalizedField = fix521(clone(field));\n const mod = fieldToString(normalizedField);\n if (orig !== mod) { // Fail as the input is \"broken\"/\"crap\"/sumthing\n res.message.push(`'TODO: ${orig}' => '${mod}'`); // eslint-disable-line functional/immutable-data\n return;\n }\n return;\n }\n}\n\nfunction fixSubfieldA(a) {\n a.value = a.value. // eslint-disable-line functional/immutable-data\n // MET-332:\n replace(/^(Ikäsuositus) ([0-9])/u, '$1: $2'); // eslint-disable-line prefer-named-capture-group, functional/immutable-data\n}\n\nfunction fixSubfieldAInternalPunctuation(field) {\n const a = field.subfields.filter(sf => sf.code === 'a');\n\n a.forEach(sf => fixSubfieldA(sf));\n}\n\nfunction getIndicator1(field) {\n const [a] = field.subfields.filter(sf => sf.code === 'a');\n if (a) {\n if (a.value.match(/^Ikäsuositus/u)) {\n return '1';\n }\n }\n return undefined;\n}\n\nfunction fixIndicator1(field) {\n const value = getIndicator1(field);\n if (value) {\n field.ind1 = value; // eslint-disable-line functional/immutable-data\n return;\n }\n\n}\n\nfunction fix521(field) {\n if (field.tag !== '521' || !field.subfields) {\n return field;\n }\n fixIndicator1(field);\n fixSubfieldAInternalPunctuation(field);\n return field;\n}\n\n"],"mappings":";;;;;;AACA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,MAAA,GAAAD,OAAA;AAAsC,SAAAD,uBAAAG,GAAA,WAAAA,GAAA,IAAAA,GAAA,CAAAC,UAAA,GAAAD,GAAA,KAAAE,OAAA,EAAAF,GAAA;AAFtC;;AAIA;AACe,SAAAG,SAAA,EAAY;EAEzB,OAAO;IACLC,WAAW,EAAE,6BAA6B;IAC1CC,QAAQ;IAAEC;EACZ,CAAC;EAED,SAASA,GAAGA,CAACC,MAAM,EAAE;IACnBA,MAAM,CAACC,MAAM,CAACC,OAAO,CAACC,KAAK,IAAI;MAC7BC,MAAM,CAACD,KAAK,CAAC;IACf,CAAC,CAAC;IACF;IACA,MAAME,GAAG,GAAG;MAACC,OAAO,EAAE,EAAE;MAAEP,GAAG,EAAE,EAAE;MAAEQ,KAAK,EAAE;IAAI,CAAC;IAC/C,OAAOF,GAAG;EACZ;EAEA,SAASP,QAAQA,CAACE,MAAM,EAAE;IACxB,MAAMK,GAAG,GAAG;MAACC,OAAO,EAAE;IAAE,CAAC;;IAEzB;IACA;AACJ;AACA;AACA;AACA;;IAEIN,MAAM,CAACC,MAAM,EAAEC,OAAO,CAACC,KAAK,IAAI;MAC9BK,aAAa,CAACL,KAAK,EAAEE,GAAG,CAAC;IAC3B,CAAC,CAAC;IAEFA,GAAG,CAACE,KAAK,GAAG,EAAEF,GAAG,CAACC,OAAO,CAACG,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC;IACxC,OAAOJ,GAAG;EACZ;EAEA,SAASG,aAAaA,CAACL,KAAK,EAAEE,GAAG,EAAE;IACjC,MAAMK,IAAI,GAAG,IAAAC,oBAAa,EAACR,KAAK,CAAC;IAEjC,MAAMS,eAAe,GAAGR,MAAM,CAAC,IAAAS,cAAK,EAACV,KAAK,CAAC,CAAC;IAC5C,MAAMW,GAAG,GAAG,IAAAH,oBAAa,EAACC,eAAe,CAAC;IAC1C,IAAIF,IAAI,KAAKI,GAAG,EAAE;MAAE;MAClBT,GAAG,CAACC,OAAO,CAACS,IAAI,CAAE,UAASL,IAAK,SAAQI,GAAI,GAAE,CAAC,CAAC,CAAC;MACjD;IACF;IACA;EACF;AACF;AAEA,SAASE,YAAYA,CAACC,CAAC,EAAE;EACvBA,CAAC,CAACC,KAAK,GAAGD,CAAC,CAACC,KAAK;EAAE;EACjB;EACAC,OAAO,CAAC,yBAAyB,EAAE,QAAQ,CAAC,CAAC,CAAC;AAClD;;AAEA,SAASC,+BAA+BA,CAACjB,KAAK,EAAE;EAC9C,MAAMc,CAAC,GAAGd,KAAK,CAACkB,SAAS,CAACC,MAAM,CAACC,EAAE,IAAIA,EAAE,CAACC,IAAI,KAAK,GAAG,CAAC;EAEvDP,CAAC,CAACf,OAAO,CAACqB,EAAE,IAAIP,YAAY,CAACO,EAAE,CAAC,CAAC;AACnC;AAEA,SAASE,aAAaA,CAACtB,KAAK,EAAE;EAC5B,MAAM,CAACc,CAAC,CAAC,GAAGd,KAAK,CAACkB,SAAS,CAACC,MAAM,CAACC,EAAE,IAAIA,EAAE,CAACC,IAAI,KAAK,GAAG,CAAC;EACzD,IAAIP,CAAC,EAAE;IACL,IAAIA,CAAC,CAACC,KAAK,CAACQ,KAAK,CAAC,eAAe,CAAC,EAAE;MAClC,OAAO,GAAG;IACZ;EACF;EACA,OAAOC,SAAS;AAClB;AAEA,SAASC,aAAaA,CAACzB,KAAK,EAAE;EAC5B,MAAMe,KAAK,GAAGO,aAAa,CAACtB,KAAK,CAAC;EAClC,IAAIe,KAAK,EAAE;IACTf,KAAK,CAAC0B,IAAI,GAAGX,KAAK,CAAC,CAAC;IACpB;EACF;AAEF;AAEA,SAASd,MAAMA,CAACD,KAAK,EAAE;EACrB,IAAIA,KAAK,CAAC2B,GAAG,KAAK,KAAK,IAAI,CAAC3B,KAAK,CAACkB,SAAS,EAAE;IAC3C,OAAOlB,KAAK;EACd;EACAyB,aAAa,CAACzB,KAAK,CAAC;EACpBiB,+BAA+B,CAACjB,KAAK,CAAC;EACtC,OAAOA,KAAK;AACd"}
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+
3
+ var _chai = require("chai");
4
+ var _marcRecord = require("@natlibfi/marc-record");
5
+ var _field521Fix = _interopRequireDefault(require("./field-521-fix"));
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', 'fix521'],
13
+ useMetadataFile: true,
14
+ recurse: false,
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/fix521:test');
23
+ async function testValidatorFactory() {
24
+ const validator = await (0, _field521Fix.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, _field521Fix.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=field-521-fix.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-521-fix.spec.js","names":["_chai","require","_marcRecord","_field521Fix","_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/field-521-fix.spec.js"],"sourcesContent":["import {expect} from 'chai';\nimport {MarcRecord} from '@natlibfi/marc-record';\nimport validatorFactory from './field-521-fix';\nimport {READERS} from '@natlibfi/fixura';\nimport generateTests from '@natlibfi/fixugen';\nimport createDebugLogger from 'debug';\n\ngenerateTests({\n callback,\n path: [__dirname, '..', 'test-fixtures', 'fix521'],\n useMetadataFile: true,\n recurse: false,\n fixura: {\n reader: READERS.JSON\n },\n mocha: {\n before: () => testValidatorFactory()\n }\n});\nconst debug = createDebugLogger('@natlibfi/marc-record-validators-melinda/fix521: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,YAAA,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,QAAQ,CAAC;EAClDC,eAAe,EAAE,IAAI;EACrBC,OAAO,EAAE,KAAK;EACdC,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,sDAAsD,CAAC;AAEvF,eAAeF,oBAAoBA,CAAA,EAAG;EACpC,MAAMG,SAAS,GAAG,MAAM,IAAAC,oBAAgB,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,oBAAgB,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"}
package/dist/index.js CHANGED
@@ -39,6 +39,12 @@ Object.defineProperty(exports, "EndingWhitespace", {
39
39
  return _endingWhitespace.default;
40
40
  }
41
41
  });
42
+ Object.defineProperty(exports, "Field521Fix", {
43
+ enumerable: true,
44
+ get: function () {
45
+ return _field521Fix.default;
46
+ }
47
+ });
42
48
  Object.defineProperty(exports, "FieldExclusion", {
43
49
  enumerable: true,
44
50
  get: function () {
@@ -171,6 +177,7 @@ var _duplicatesInd = _interopRequireDefault(require("./duplicates-ind1"));
171
177
  var _emptyFields = _interopRequireDefault(require("./empty-fields"));
172
178
  var _endingPunctuation = _interopRequireDefault(require("./ending-punctuation"));
173
179
  var _endingWhitespace = _interopRequireDefault(require("./ending-whitespace"));
180
+ var _field521Fix = _interopRequireDefault(require("./field-521-fix"));
174
181
  var _fieldsPresent = _interopRequireDefault(require("./fields-present"));
175
182
  var _fieldStructure = _interopRequireDefault(require("./field-structure"));
176
183
  var _fixedFields = _interopRequireDefault(require("./fixed-fields"));
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["_accessRights","_interopRequireDefault","require","_doubleCommas","_duplicatesInd","_emptyFields","_endingPunctuation","_endingWhitespace","_fieldsPresent","_fieldStructure","_fixedFields","_fieldExclusion","_identicalFields","_isbnIssn","_itemLanguage","_nonBreakingSpace","_normalizeUtf8Diacritics","_punctuation","_resolveOrphanedSubfield6s","_reindexSubfield6OccurenceNumbers","_resolvableExtReferencesMelinda","_sanitizeVocabularySourceCodes","_updateField","_sortSubfields","_sortTags","_subfieldExclusion","_typeOfDate","_unicodeDecomposition","_urn","obj","__esModule","default"],"sources":["../src/index.js"],"sourcesContent":["import AccessRights from './access-rights';\nimport DoubleCommas from './double-commas';\nimport DuplicatesInd1 from './duplicates-ind1';\nimport EmptyFields from './empty-fields';\nimport EndingPunctuation from './ending-punctuation';\nimport EndingWhitespace from './ending-whitespace';\nimport FieldsPresent from './fields-present';\nimport FieldStructure from './field-structure';\nimport FixedFields from './fixed-fields';\nimport FieldExclusion from './field-exclusion';\nimport IdenticalFields from './identical-fields';\nimport IsbnIssn from './isbn-issn';\nimport ItemLanguage from './item-language';\nimport NonBreakingSpace from './non-breaking-space';\nimport NormalizeUTF8Diacritics from './normalize-utf8-diacritics';\nimport Punctuation from './punctuation/';\nimport ResolveOrphanedSubfield6s from './resolveOrphanedSubfield6s'; // Do this before reindexing!\nimport ReindexSubfield6OccurenceNumbers from './reindexSubfield6OccurenceNumbers';\nimport ResolvableExtReferences from './resolvable-ext-references-melinda';\nimport SanitizeVocabularySourceCodes from './sanitize-vocabulary-source-codes';\nimport UpdateField540 from './update-field-540';\nimport SortSubfields from './sortSubfields';\nimport SortTags from './sort-tags';\nimport SubfieldExclusion from './subfield-exclusion';\nimport TypeOfDateF008 from './typeOfDate-008';\nimport UnicodeDecomposition from './unicode-decomposition';\nimport Urn from './urn';\n\nexport {\n AccessRights,\n DoubleCommas,\n DuplicatesInd1,\n EmptyFields,\n EndingPunctuation,\n EndingWhitespace,\n FieldExclusion,\n FieldsPresent,\n FieldStructure,\n FixedFields,\n IdenticalFields,\n IsbnIssn,\n ItemLanguage,\n NonBreakingSpace,\n NormalizeUTF8Diacritics,\n Punctuation,\n ResolveOrphanedSubfield6s,\n ReindexSubfield6OccurenceNumbers,\n ResolvableExtReferences,\n SanitizeVocabularySourceCodes,\n SortSubfields,\n SortTags,\n SubfieldExclusion,\n TypeOfDateF008,\n UnicodeDecomposition,\n UpdateField540,\n Urn\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,aAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,aAAA,GAAAF,sBAAA,CAAAC,OAAA;AACA,IAAAE,cAAA,GAAAH,sBAAA,CAAAC,OAAA;AACA,IAAAG,YAAA,GAAAJ,sBAAA,CAAAC,OAAA;AACA,IAAAI,kBAAA,GAAAL,sBAAA,CAAAC,OAAA;AACA,IAAAK,iBAAA,GAAAN,sBAAA,CAAAC,OAAA;AACA,IAAAM,cAAA,GAAAP,sBAAA,CAAAC,OAAA;AACA,IAAAO,eAAA,GAAAR,sBAAA,CAAAC,OAAA;AACA,IAAAQ,YAAA,GAAAT,sBAAA,CAAAC,OAAA;AACA,IAAAS,eAAA,GAAAV,sBAAA,CAAAC,OAAA;AACA,IAAAU,gBAAA,GAAAX,sBAAA,CAAAC,OAAA;AACA,IAAAW,SAAA,GAAAZ,sBAAA,CAAAC,OAAA;AACA,IAAAY,aAAA,GAAAb,sBAAA,CAAAC,OAAA;AACA,IAAAa,iBAAA,GAAAd,sBAAA,CAAAC,OAAA;AACA,IAAAc,wBAAA,GAAAf,sBAAA,CAAAC,OAAA;AACA,IAAAe,YAAA,GAAAhB,sBAAA,CAAAC,OAAA;AACA,IAAAgB,0BAAA,GAAAjB,sBAAA,CAAAC,OAAA;AACA,IAAAiB,iCAAA,GAAAlB,sBAAA,CAAAC,OAAA;AACA,IAAAkB,+BAAA,GAAAnB,sBAAA,CAAAC,OAAA;AACA,IAAAmB,8BAAA,GAAApB,sBAAA,CAAAC,OAAA;AACA,IAAAoB,YAAA,GAAArB,sBAAA,CAAAC,OAAA;AACA,IAAAqB,cAAA,GAAAtB,sBAAA,CAAAC,OAAA;AACA,IAAAsB,SAAA,GAAAvB,sBAAA,CAAAC,OAAA;AACA,IAAAuB,kBAAA,GAAAxB,sBAAA,CAAAC,OAAA;AACA,IAAAwB,WAAA,GAAAzB,sBAAA,CAAAC,OAAA;AACA,IAAAyB,qBAAA,GAAA1B,sBAAA,CAAAC,OAAA;AACA,IAAA0B,IAAA,GAAA3B,sBAAA,CAAAC,OAAA;AAAwB,SAAAD,uBAAA4B,GAAA,WAAAA,GAAA,IAAAA,GAAA,CAAAC,UAAA,GAAAD,GAAA,KAAAE,OAAA,EAAAF,GAAA"}
1
+ {"version":3,"file":"index.js","names":["_accessRights","_interopRequireDefault","require","_doubleCommas","_duplicatesInd","_emptyFields","_endingPunctuation","_endingWhitespace","_field521Fix","_fieldsPresent","_fieldStructure","_fixedFields","_fieldExclusion","_identicalFields","_isbnIssn","_itemLanguage","_nonBreakingSpace","_normalizeUtf8Diacritics","_punctuation","_resolveOrphanedSubfield6s","_reindexSubfield6OccurenceNumbers","_resolvableExtReferencesMelinda","_sanitizeVocabularySourceCodes","_updateField","_sortSubfields","_sortTags","_subfieldExclusion","_typeOfDate","_unicodeDecomposition","_urn","obj","__esModule","default"],"sources":["../src/index.js"],"sourcesContent":["import AccessRights from './access-rights';\nimport DoubleCommas from './double-commas';\nimport DuplicatesInd1 from './duplicates-ind1';\nimport EmptyFields from './empty-fields';\nimport EndingPunctuation from './ending-punctuation';\nimport EndingWhitespace from './ending-whitespace';\nimport Field521Fix from './field-521-fix';\nimport FieldsPresent from './fields-present';\nimport FieldStructure from './field-structure';\nimport FixedFields from './fixed-fields';\nimport FieldExclusion from './field-exclusion';\nimport IdenticalFields from './identical-fields';\nimport IsbnIssn from './isbn-issn';\nimport ItemLanguage from './item-language';\nimport NonBreakingSpace from './non-breaking-space';\nimport NormalizeUTF8Diacritics from './normalize-utf8-diacritics';\nimport Punctuation from './punctuation/';\nimport ResolveOrphanedSubfield6s from './resolveOrphanedSubfield6s'; // Do this before reindexing!\nimport ReindexSubfield6OccurenceNumbers from './reindexSubfield6OccurenceNumbers';\nimport ResolvableExtReferences from './resolvable-ext-references-melinda';\nimport SanitizeVocabularySourceCodes from './sanitize-vocabulary-source-codes';\nimport UpdateField540 from './update-field-540';\nimport SortSubfields from './sortSubfields';\nimport SortTags from './sort-tags';\nimport SubfieldExclusion from './subfield-exclusion';\nimport TypeOfDateF008 from './typeOfDate-008';\nimport UnicodeDecomposition from './unicode-decomposition';\nimport Urn from './urn';\n\nexport {\n AccessRights,\n DoubleCommas,\n DuplicatesInd1,\n EmptyFields,\n EndingPunctuation,\n EndingWhitespace,\n Field521Fix,\n FieldExclusion,\n FieldsPresent,\n FieldStructure,\n FixedFields,\n IdenticalFields,\n IsbnIssn,\n ItemLanguage,\n NonBreakingSpace,\n NormalizeUTF8Diacritics,\n Punctuation,\n ResolveOrphanedSubfield6s,\n ReindexSubfield6OccurenceNumbers,\n ResolvableExtReferences,\n SanitizeVocabularySourceCodes,\n SortSubfields,\n SortTags,\n SubfieldExclusion,\n TypeOfDateF008,\n UnicodeDecomposition,\n UpdateField540,\n Urn\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,aAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,aAAA,GAAAF,sBAAA,CAAAC,OAAA;AACA,IAAAE,cAAA,GAAAH,sBAAA,CAAAC,OAAA;AACA,IAAAG,YAAA,GAAAJ,sBAAA,CAAAC,OAAA;AACA,IAAAI,kBAAA,GAAAL,sBAAA,CAAAC,OAAA;AACA,IAAAK,iBAAA,GAAAN,sBAAA,CAAAC,OAAA;AACA,IAAAM,YAAA,GAAAP,sBAAA,CAAAC,OAAA;AACA,IAAAO,cAAA,GAAAR,sBAAA,CAAAC,OAAA;AACA,IAAAQ,eAAA,GAAAT,sBAAA,CAAAC,OAAA;AACA,IAAAS,YAAA,GAAAV,sBAAA,CAAAC,OAAA;AACA,IAAAU,eAAA,GAAAX,sBAAA,CAAAC,OAAA;AACA,IAAAW,gBAAA,GAAAZ,sBAAA,CAAAC,OAAA;AACA,IAAAY,SAAA,GAAAb,sBAAA,CAAAC,OAAA;AACA,IAAAa,aAAA,GAAAd,sBAAA,CAAAC,OAAA;AACA,IAAAc,iBAAA,GAAAf,sBAAA,CAAAC,OAAA;AACA,IAAAe,wBAAA,GAAAhB,sBAAA,CAAAC,OAAA;AACA,IAAAgB,YAAA,GAAAjB,sBAAA,CAAAC,OAAA;AACA,IAAAiB,0BAAA,GAAAlB,sBAAA,CAAAC,OAAA;AACA,IAAAkB,iCAAA,GAAAnB,sBAAA,CAAAC,OAAA;AACA,IAAAmB,+BAAA,GAAApB,sBAAA,CAAAC,OAAA;AACA,IAAAoB,8BAAA,GAAArB,sBAAA,CAAAC,OAAA;AACA,IAAAqB,YAAA,GAAAtB,sBAAA,CAAAC,OAAA;AACA,IAAAsB,cAAA,GAAAvB,sBAAA,CAAAC,OAAA;AACA,IAAAuB,SAAA,GAAAxB,sBAAA,CAAAC,OAAA;AACA,IAAAwB,kBAAA,GAAAzB,sBAAA,CAAAC,OAAA;AACA,IAAAyB,WAAA,GAAA1B,sBAAA,CAAAC,OAAA;AACA,IAAA0B,qBAAA,GAAA3B,sBAAA,CAAAC,OAAA;AACA,IAAA2B,IAAA,GAAA5B,sBAAA,CAAAC,OAAA;AAAwB,SAAAD,uBAAA6B,GAAA,WAAAA,GAAA,IAAAA,GAAA,CAAAC,UAAA,GAAAD,GAAA,KAAAE,OAAA,EAAAF,GAAA"}
@@ -5,20 +5,11 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = _default;
7
7
  exports.recordNormalizeIndicators = recordNormalizeIndicators;
8
+ var _utils = require("./utils");
8
9
  // Relocated from melinda-marc-record-merge-reducers (and renamed)
9
10
  //import createDebugLogger from 'debug';
10
11
  //const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:normalizeIdentifiers');
11
12
 
12
- function fieldToString(f) {
13
- if (!f.subfields) {
14
- return `${f.tag} ${f.value}`;
15
- }
16
- return `${f.tag} ${f.ind1}${f.ind2} ‡${formatSubfields(f)}`;
17
- function formatSubfields(field) {
18
- //return field.subfields.map(sf => `${sf.code}${sf.value || ''}`).join('‡');
19
- return field.subfields.map(sf => `${sf.code}${sf.value}`).join(' ‡');
20
- }
21
- }
22
13
  function _default() {
23
14
  return {
24
15
  description: 'Normalizes indicator values',
@@ -48,7 +39,7 @@ function _default() {
48
39
  recordNormalizeIndicators(record);
49
40
  record.fields.forEach((field, index) => compareFields(field, index));
50
41
  function compareFields(field, index) {
51
- const origFieldAsString = fieldToString(clonedFields[index]);
42
+ const origFieldAsString = (0, _utils.fieldToString)(clonedFields[index]);
52
43
  //const clonedFieldAsString = fieldToString(field);
53
44
  if (clonedFields[index].ind1 !== field.ind1) {
54
45
  // eslint-disable-line functional/no-conditional-statements
@@ -1 +1 @@
1
- {"version":3,"file":"indicator-fixes.js","names":["fieldToString","f","subfields","tag","value","ind1","ind2","formatSubfields","field","map","sf","code","join","_default","description","validate","fix","record","res","message","valid","recordNormalizeIndicators","validateRecord","length","clonedFields","JSON","parse","stringify","fields","forEach","index","compareFields","origFieldAsString","push","ind1NonFilingChars","ind2NonFilingChars","hasNonFilingIndicator1","includes","modifiableIndicatorValue","hasNonFilingIndicator2","valueBeginsWithDeterminer","cands","find","cand","substring","determineNonFilingIndicatorValue","languages","undefined","subfieldA","name","toLowerCase","match","normalizeNonFilingIndicator1","normalizeNonFilingIndicator2","normalize245Indicator1","field1XX","get","recordNormalize490","fields490","fields8XX","getLanguages","langFields","filter","isRelevantSubfield","subfield","fieldNormalizeIndicators"],"sources":["../src/indicator-fixes.js"],"sourcesContent":["// Relocated from melinda-marc-record-merge-reducers (and renamed)\n//import createDebugLogger from 'debug';\n//const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:normalizeIdentifiers');\n\n\nfunction fieldToString(f) {\n if (!f.subfields) {\n return `${f.tag} ${f.value}`;\n }\n return `${f.tag} ${f.ind1}${f.ind2} ‡${formatSubfields(f)}`;\n\n function formatSubfields(field) {\n //return field.subfields.map(sf => `${sf.code}${sf.value || ''}`).join('‡');\n return field.subfields.map(sf => `${sf.code}${sf.value}`).join(' ‡');\n }\n}\n\n\nexport default function () {\n\n return {\n description: 'Normalizes indicator values',\n validate, fix\n };\n\n function fix(record) {\n const res = {message: [], fix: [], valid: true};\n\n recordNormalizeIndicators(record);\n\n return res;\n }\n\n function validate(record) {\n const res = {message: []};\n\n validateRecord(record, res);\n\n res.valid = res.message.length < 1; // eslint-disable-line functional/immutable-data\n return res;\n }\n\n\n function validateRecord(record, res) {\n //nvdebug(record);\n const clonedFields = JSON.parse(JSON.stringify(record.fields));\n recordNormalizeIndicators(record);\n\n record.fields.forEach((field, index) => compareFields(field, index));\n\n function compareFields(field, index) {\n const origFieldAsString = fieldToString(clonedFields[index]);\n //const clonedFieldAsString = fieldToString(field);\n if (clonedFields[index].ind1 !== field.ind1) { // eslint-disable-line functional/no-conditional-statements\n //nvdebug(`FIX IND1: '${clonedFields[index].ind1}' => '${field.ind1}': ${clonedFieldAsString}`);\n res.message.push(`Expected IND1 for '${origFieldAsString}' is '${field.ind1}'`); // eslint-disable-line functional/immutable-data\n }\n if (clonedFields[index].ind2 !== field.ind2) { // eslint-disable-line functional/no-conditional-statements\n //nvdebug(`FIX IND2: '${clonedFields[index].ind2}' => '${field.ind2}': ${clonedFieldAsString}`);\n res.message.push(`Expected IND2 for '${origFieldAsString}' is '${field.ind2}'`); // eslint-disable-line functional/immutable-data\n }\n }\n // Validator should not change the original record:\n record.fields = clonedFields; // eslint-disable-line functional/immutable-data\n return;\n }\n}\n\n\nconst ind1NonFilingChars = ['130', '630', '730', '740'];\nconst ind2NonFilingChars = ['222', '240', '242', '243', '245', '830'];\n\nfunction hasNonFilingIndicator1(field) {\n return ind1NonFilingChars.includes(field.tag);\n}\n\nfunction modifiableIndicatorValue(value) {\n // If field contains a legit-looking value, don't try to modify it here...\n return !['9', '8', '7', '6', '5', '4', '3', '2', '1'].includes(value);\n}\n\nfunction hasNonFilingIndicator2(field) {\n return ind2NonFilingChars.includes(field.tag);\n}\n\nfunction valueBeginsWithDeterminer(value, cands) {\n return cands.find(cand => value.substring(0, cand.length) === cand);\n}\n\nfunction determineNonFilingIndicatorValue(field, languages = undefined) {\n const subfieldA = field.subfields.find(sf => sf.code === 'a');\n if (!subfieldA) {\n // nvdebug(' Subfield $a miss!');\n return;\n }\n\n const name = subfieldA.value.toLowerCase();\n\n if (languages.includes('eng')) {\n const match = valueBeginsWithDeterminer(name, ['a ', 'an ', 'the ']);\n if (match) {\n return `${match.length}`;\n }\n }\n\n if (languages.includes('fre')) {\n const match = valueBeginsWithDeterminer(name, ['l\\'', 'le ']);\n if (match) {\n return `${match.length}`;\n }\n }\n\n if (languages.includes('ger')) {\n const match = valueBeginsWithDeterminer(name, ['das ', 'der ', 'die ']);\n if (match) {\n return `${match.length}`;\n }\n }\n\n if (languages.includes('swe')) {\n const match = valueBeginsWithDeterminer(name, ['en ', 'ett ']);\n if (match) {\n return `${match.length}`;\n }\n }\n\n // Fallback-ish: try to guess even without languages:\n const match = valueBeginsWithDeterminer(name, ['the ']);\n if (match) {\n return `${match.length}`;\n }\n\n return '0';\n}\n\nfunction normalizeNonFilingIndicator1(field, languages = []) {\n if (!hasNonFilingIndicator1(field) || !modifiableIndicatorValue(field.ind1)) {\n return;\n }\n\n field.ind1 = determineNonFilingIndicatorValue(field, languages); // eslint-disable-line functional/immutable-data\n}\n\nfunction normalizeNonFilingIndicator2(field, languages = []) {\n if (!hasNonFilingIndicator2(field) || !modifiableIndicatorValue(field.ind2)) {\n return;\n }\n\n field.ind2 = determineNonFilingIndicatorValue(field, languages); // eslint-disable-line functional/immutable-data\n}\n\n\nfunction normalize245Indicator1(field, record) {\n if (field.tag !== '245') {\n return;\n }\n const field1XX = record.get('^1..$');\n field.ind1 = field1XX.length === 0 ? '0' : '1'; // eslint-disable-line functional/immutable-data\n}\n\n\nfunction recordNormalize490(record) {\n const fields490 = record.get('^490$');\n const fields8XX = record.get('^(?:800|810|811|830)$');\n\n if (fields490.length === 0) {\n return;\n }\n if (fields490.length <= fields8XX.length) {\n // Trace found for each field 490:\n fields490.forEach(f => {\n f.ind1 = '1'; // eslint-disable-line functional/immutable-data\n });\n return;\n }\n if (fields8XX.length === 0) { // Fields 490 are always untraced (no traces found)\n fields490.forEach(f => {\n f.ind1 = '0'; // eslint-disable-line functional/immutable-data\n });\n return;\n }\n // For other combinations we just can't be sure, so leave them as they are.\n}\n\n\nfunction getLanguages(record) {\n const langFields = record.get('^041$');\n\n if (langFields.length === 0) {\n return [];\n }\n\n return langFields[0].subfields.filter(sf => isRelevantSubfield(sf)).map(subfield => subfield.value);\n\n function isRelevantSubfield(subfield) {\n if (subfield.code !== 'a' && subfield.code !== 'd') {\n return false;\n }\n if (subfield.value.length !== 3) {\n return false;\n }\n // We could require /^[a-z][a-z][a-z]$/ etc as well, but it's not really that relevant.\n return true;\n }\n\n}\n\nexport function recordNormalizeIndicators(record) {\n recordNormalize490(record);\n\n // Language is used to handle non-filing indicators\n const languages = getLanguages(record);\n\n record.fields.forEach(field => fieldNormalizeIndicators(field, record, languages));\n\n}\n\nfunction fieldNormalizeIndicators(field, record, languages) {\n normalize245Indicator1(field, record);\n normalizeNonFilingIndicator1(field, languages);\n normalizeNonFilingIndicator2(field, languages);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"indicator-fixes.js","names":["_utils","require","_default","description","validate","fix","record","res","message","valid","recordNormalizeIndicators","validateRecord","length","clonedFields","JSON","parse","stringify","fields","forEach","field","index","compareFields","origFieldAsString","fieldToString","ind1","push","ind2","ind1NonFilingChars","ind2NonFilingChars","hasNonFilingIndicator1","includes","tag","modifiableIndicatorValue","value","hasNonFilingIndicator2","valueBeginsWithDeterminer","cands","find","cand","substring","determineNonFilingIndicatorValue","languages","undefined","subfieldA","subfields","sf","code","name","toLowerCase","match","normalizeNonFilingIndicator1","normalizeNonFilingIndicator2","normalize245Indicator1","field1XX","get","recordNormalize490","fields490","fields8XX","f","getLanguages","langFields","filter","isRelevantSubfield","map","subfield","fieldNormalizeIndicators"],"sources":["../src/indicator-fixes.js"],"sourcesContent":["// Relocated from melinda-marc-record-merge-reducers (and renamed)\n//import createDebugLogger from 'debug';\n//const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:normalizeIdentifiers');\n\nimport {fieldToString} from './utils';\n\n\nexport default function () {\n\n return {\n description: 'Normalizes indicator values',\n validate, fix\n };\n\n function fix(record) {\n const res = {message: [], fix: [], valid: true};\n\n recordNormalizeIndicators(record);\n\n return res;\n }\n\n function validate(record) {\n const res = {message: []};\n\n validateRecord(record, res);\n\n res.valid = res.message.length < 1; // eslint-disable-line functional/immutable-data\n return res;\n }\n\n\n function validateRecord(record, res) {\n //nvdebug(record);\n const clonedFields = JSON.parse(JSON.stringify(record.fields));\n recordNormalizeIndicators(record);\n\n record.fields.forEach((field, index) => compareFields(field, index));\n\n function compareFields(field, index) {\n const origFieldAsString = fieldToString(clonedFields[index]);\n //const clonedFieldAsString = fieldToString(field);\n if (clonedFields[index].ind1 !== field.ind1) { // eslint-disable-line functional/no-conditional-statements\n //nvdebug(`FIX IND1: '${clonedFields[index].ind1}' => '${field.ind1}': ${clonedFieldAsString}`);\n res.message.push(`Expected IND1 for '${origFieldAsString}' is '${field.ind1}'`); // eslint-disable-line functional/immutable-data\n }\n if (clonedFields[index].ind2 !== field.ind2) { // eslint-disable-line functional/no-conditional-statements\n //nvdebug(`FIX IND2: '${clonedFields[index].ind2}' => '${field.ind2}': ${clonedFieldAsString}`);\n res.message.push(`Expected IND2 for '${origFieldAsString}' is '${field.ind2}'`); // eslint-disable-line functional/immutable-data\n }\n }\n // Validator should not change the original record:\n record.fields = clonedFields; // eslint-disable-line functional/immutable-data\n return;\n }\n}\n\n\nconst ind1NonFilingChars = ['130', '630', '730', '740'];\nconst ind2NonFilingChars = ['222', '240', '242', '243', '245', '830'];\n\nfunction hasNonFilingIndicator1(field) {\n return ind1NonFilingChars.includes(field.tag);\n}\n\nfunction modifiableIndicatorValue(value) {\n // If field contains a legit-looking value, don't try to modify it here...\n return !['9', '8', '7', '6', '5', '4', '3', '2', '1'].includes(value);\n}\n\nfunction hasNonFilingIndicator2(field) {\n return ind2NonFilingChars.includes(field.tag);\n}\n\nfunction valueBeginsWithDeterminer(value, cands) {\n return cands.find(cand => value.substring(0, cand.length) === cand);\n}\n\nfunction determineNonFilingIndicatorValue(field, languages = undefined) {\n const subfieldA = field.subfields.find(sf => sf.code === 'a');\n if (!subfieldA) {\n // nvdebug(' Subfield $a miss!');\n return;\n }\n\n const name = subfieldA.value.toLowerCase();\n\n if (languages.includes('eng')) {\n const match = valueBeginsWithDeterminer(name, ['a ', 'an ', 'the ']);\n if (match) {\n return `${match.length}`;\n }\n }\n\n if (languages.includes('fre')) {\n const match = valueBeginsWithDeterminer(name, ['l\\'', 'le ']);\n if (match) {\n return `${match.length}`;\n }\n }\n\n if (languages.includes('ger')) {\n const match = valueBeginsWithDeterminer(name, ['das ', 'der ', 'die ']);\n if (match) {\n return `${match.length}`;\n }\n }\n\n if (languages.includes('swe')) {\n const match = valueBeginsWithDeterminer(name, ['en ', 'ett ']);\n if (match) {\n return `${match.length}`;\n }\n }\n\n // Fallback-ish: try to guess even without languages:\n const match = valueBeginsWithDeterminer(name, ['the ']);\n if (match) {\n return `${match.length}`;\n }\n\n return '0';\n}\n\nfunction normalizeNonFilingIndicator1(field, languages = []) {\n if (!hasNonFilingIndicator1(field) || !modifiableIndicatorValue(field.ind1)) {\n return;\n }\n\n field.ind1 = determineNonFilingIndicatorValue(field, languages); // eslint-disable-line functional/immutable-data\n}\n\nfunction normalizeNonFilingIndicator2(field, languages = []) {\n if (!hasNonFilingIndicator2(field) || !modifiableIndicatorValue(field.ind2)) {\n return;\n }\n\n field.ind2 = determineNonFilingIndicatorValue(field, languages); // eslint-disable-line functional/immutable-data\n}\n\n\nfunction normalize245Indicator1(field, record) {\n if (field.tag !== '245') {\n return;\n }\n const field1XX = record.get('^1..$');\n field.ind1 = field1XX.length === 0 ? '0' : '1'; // eslint-disable-line functional/immutable-data\n}\n\n\nfunction recordNormalize490(record) {\n const fields490 = record.get('^490$');\n const fields8XX = record.get('^(?:800|810|811|830)$');\n\n if (fields490.length === 0) {\n return;\n }\n if (fields490.length <= fields8XX.length) {\n // Trace found for each field 490:\n fields490.forEach(f => {\n f.ind1 = '1'; // eslint-disable-line functional/immutable-data\n });\n return;\n }\n if (fields8XX.length === 0) { // Fields 490 are always untraced (no traces found)\n fields490.forEach(f => {\n f.ind1 = '0'; // eslint-disable-line functional/immutable-data\n });\n return;\n }\n // For other combinations we just can't be sure, so leave them as they are.\n}\n\n\nfunction getLanguages(record) {\n const langFields = record.get('^041$');\n\n if (langFields.length === 0) {\n return [];\n }\n\n return langFields[0].subfields.filter(sf => isRelevantSubfield(sf)).map(subfield => subfield.value);\n\n function isRelevantSubfield(subfield) {\n if (subfield.code !== 'a' && subfield.code !== 'd') {\n return false;\n }\n if (subfield.value.length !== 3) {\n return false;\n }\n // We could require /^[a-z][a-z][a-z]$/ etc as well, but it's not really that relevant.\n return true;\n }\n\n}\n\nexport function recordNormalizeIndicators(record) {\n recordNormalize490(record);\n\n // Language is used to handle non-filing indicators\n const languages = getLanguages(record);\n\n record.fields.forEach(field => fieldNormalizeIndicators(field, record, languages));\n\n}\n\nfunction fieldNormalizeIndicators(field, record, languages) {\n normalize245Indicator1(field, record);\n normalizeNonFilingIndicator1(field, languages);\n normalizeNonFilingIndicator2(field, languages);\n}\n"],"mappings":";;;;;;;AAIA,IAAAA,MAAA,GAAAC,OAAA;AAJA;AACA;AACA;;AAKe,SAAAC,SAAA,EAAY;EAEzB,OAAO;IACLC,WAAW,EAAE,6BAA6B;IAC1CC,QAAQ;IAAEC;EACZ,CAAC;EAED,SAASA,GAAGA,CAACC,MAAM,EAAE;IACnB,MAAMC,GAAG,GAAG;MAACC,OAAO,EAAE,EAAE;MAAEH,GAAG,EAAE,EAAE;MAAEI,KAAK,EAAE;IAAI,CAAC;IAE/CC,yBAAyB,CAACJ,MAAM,CAAC;IAEjC,OAAOC,GAAG;EACZ;EAEA,SAASH,QAAQA,CAACE,MAAM,EAAE;IACxB,MAAMC,GAAG,GAAG;MAACC,OAAO,EAAE;IAAE,CAAC;IAEzBG,cAAc,CAACL,MAAM,EAAEC,GAAG,CAAC;IAE3BA,GAAG,CAACE,KAAK,GAAGF,GAAG,CAACC,OAAO,CAACI,MAAM,GAAG,CAAC,CAAC,CAAC;IACpC,OAAOL,GAAG;EACZ;EAGA,SAASI,cAAcA,CAACL,MAAM,EAAEC,GAAG,EAAE;IACnC;IACA,MAAMM,YAAY,GAAGC,IAAI,CAACC,KAAK,CAACD,IAAI,CAACE,SAAS,CAACV,MAAM,CAACW,MAAM,CAAC,CAAC;IAC9DP,yBAAyB,CAACJ,MAAM,CAAC;IAEjCA,MAAM,CAACW,MAAM,CAACC,OAAO,CAAC,CAACC,KAAK,EAAEC,KAAK,KAAKC,aAAa,CAACF,KAAK,EAAEC,KAAK,CAAC,CAAC;IAEpE,SAASC,aAAaA,CAACF,KAAK,EAAEC,KAAK,EAAE;MACnC,MAAME,iBAAiB,GAAG,IAAAC,oBAAa,EAACV,YAAY,CAACO,KAAK,CAAC,CAAC;MAC5D;MACA,IAAIP,YAAY,CAACO,KAAK,CAAC,CAACI,IAAI,KAAKL,KAAK,CAACK,IAAI,EAAE;QAAE;QAC7C;QACAjB,GAAG,CAACC,OAAO,CAACiB,IAAI,CAAE,sBAAqBH,iBAAkB,SAAQH,KAAK,CAACK,IAAK,GAAE,CAAC,CAAC,CAAC;MACnF;;MACA,IAAIX,YAAY,CAACO,KAAK,CAAC,CAACM,IAAI,KAAKP,KAAK,CAACO,IAAI,EAAE;QAAE;QAC7C;QACAnB,GAAG,CAACC,OAAO,CAACiB,IAAI,CAAE,sBAAqBH,iBAAkB,SAAQH,KAAK,CAACO,IAAK,GAAE,CAAC,CAAC,CAAC;MACnF;IACF;IACA;IACApB,MAAM,CAACW,MAAM,GAAGJ,YAAY,CAAC,CAAC;IAC9B;EACF;AACF;AAGA,MAAMc,kBAAkB,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;AACvD,MAAMC,kBAAkB,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;AAErE,SAASC,sBAAsBA,CAACV,KAAK,EAAE;EACrC,OAAOQ,kBAAkB,CAACG,QAAQ,CAACX,KAAK,CAACY,GAAG,CAAC;AAC/C;AAEA,SAASC,wBAAwBA,CAACC,KAAK,EAAE;EACvC;EACA,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAACH,QAAQ,CAACG,KAAK,CAAC;AACvE;AAEA,SAASC,sBAAsBA,CAACf,KAAK,EAAE;EACrC,OAAOS,kBAAkB,CAACE,QAAQ,CAACX,KAAK,CAACY,GAAG,CAAC;AAC/C;AAEA,SAASI,yBAAyBA,CAACF,KAAK,EAAEG,KAAK,EAAE;EAC/C,OAAOA,KAAK,CAACC,IAAI,CAACC,IAAI,IAAIL,KAAK,CAACM,SAAS,CAAC,CAAC,EAAED,IAAI,CAAC1B,MAAM,CAAC,KAAK0B,IAAI,CAAC;AACrE;AAEA,SAASE,gCAAgCA,CAACrB,KAAK,EAAEsB,SAAS,GAAGC,SAAS,EAAE;EACtE,MAAMC,SAAS,GAAGxB,KAAK,CAACyB,SAAS,CAACP,IAAI,CAACQ,EAAE,IAAIA,EAAE,CAACC,IAAI,KAAK,GAAG,CAAC;EAC7D,IAAI,CAACH,SAAS,EAAE;IACd;IACA;EACF;EAEA,MAAMI,IAAI,GAAGJ,SAAS,CAACV,KAAK,CAACe,WAAW,CAAC,CAAC;EAE1C,IAAIP,SAAS,CAACX,QAAQ,CAAC,KAAK,CAAC,EAAE;IAC7B,MAAMmB,KAAK,GAAGd,yBAAyB,CAACY,IAAI,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IACpE,IAAIE,KAAK,EAAE;MACT,OAAQ,GAAEA,KAAK,CAACrC,MAAO,EAAC;IAC1B;EACF;EAEA,IAAI6B,SAAS,CAACX,QAAQ,CAAC,KAAK,CAAC,EAAE;IAC7B,MAAMmB,KAAK,GAAGd,yBAAyB,CAACY,IAAI,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC7D,IAAIE,KAAK,EAAE;MACT,OAAQ,GAAEA,KAAK,CAACrC,MAAO,EAAC;IAC1B;EACF;EAEA,IAAI6B,SAAS,CAACX,QAAQ,CAAC,KAAK,CAAC,EAAE;IAC7B,MAAMmB,KAAK,GAAGd,yBAAyB,CAACY,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACvE,IAAIE,KAAK,EAAE;MACT,OAAQ,GAAEA,KAAK,CAACrC,MAAO,EAAC;IAC1B;EACF;EAEA,IAAI6B,SAAS,CAACX,QAAQ,CAAC,KAAK,CAAC,EAAE;IAC7B,MAAMmB,KAAK,GAAGd,yBAAyB,CAACY,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC9D,IAAIE,KAAK,EAAE;MACT,OAAQ,GAAEA,KAAK,CAACrC,MAAO,EAAC;IAC1B;EACF;;EAEA;EACA,MAAMqC,KAAK,GAAGd,yBAAyB,CAACY,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC;EACvD,IAAIE,KAAK,EAAE;IACT,OAAQ,GAAEA,KAAK,CAACrC,MAAO,EAAC;EAC1B;EAEA,OAAO,GAAG;AACZ;AAEA,SAASsC,4BAA4BA,CAAC/B,KAAK,EAAEsB,SAAS,GAAG,EAAE,EAAE;EAC3D,IAAI,CAACZ,sBAAsB,CAACV,KAAK,CAAC,IAAI,CAACa,wBAAwB,CAACb,KAAK,CAACK,IAAI,CAAC,EAAE;IAC3E;EACF;EAEAL,KAAK,CAACK,IAAI,GAAGgB,gCAAgC,CAACrB,KAAK,EAAEsB,SAAS,CAAC,CAAC,CAAC;AACnE;;AAEA,SAASU,4BAA4BA,CAAChC,KAAK,EAAEsB,SAAS,GAAG,EAAE,EAAE;EAC3D,IAAI,CAACP,sBAAsB,CAACf,KAAK,CAAC,IAAI,CAACa,wBAAwB,CAACb,KAAK,CAACO,IAAI,CAAC,EAAE;IAC3E;EACF;EAEAP,KAAK,CAACO,IAAI,GAAGc,gCAAgC,CAACrB,KAAK,EAAEsB,SAAS,CAAC,CAAC,CAAC;AACnE;;AAGA,SAASW,sBAAsBA,CAACjC,KAAK,EAAEb,MAAM,EAAE;EAC7C,IAAIa,KAAK,CAACY,GAAG,KAAK,KAAK,EAAE;IACvB;EACF;EACA,MAAMsB,QAAQ,GAAG/C,MAAM,CAACgD,GAAG,CAAC,OAAO,CAAC;EACpCnC,KAAK,CAACK,IAAI,GAAG6B,QAAQ,CAACzC,MAAM,KAAK,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;AAClD;;AAGA,SAAS2C,kBAAkBA,CAACjD,MAAM,EAAE;EAClC,MAAMkD,SAAS,GAAGlD,MAAM,CAACgD,GAAG,CAAC,OAAO,CAAC;EACrC,MAAMG,SAAS,GAAGnD,MAAM,CAACgD,GAAG,CAAC,uBAAuB,CAAC;EAErD,IAAIE,SAAS,CAAC5C,MAAM,KAAK,CAAC,EAAE;IAC1B;EACF;EACA,IAAI4C,SAAS,CAAC5C,MAAM,IAAI6C,SAAS,CAAC7C,MAAM,EAAE;IACxC;IACA4C,SAAS,CAACtC,OAAO,CAACwC,CAAC,IAAI;MACrBA,CAAC,CAAClC,IAAI,GAAG,GAAG,CAAC,CAAC;IAChB,CAAC,CAAC;;IACF;EACF;EACA,IAAIiC,SAAS,CAAC7C,MAAM,KAAK,CAAC,EAAE;IAAE;IAC5B4C,SAAS,CAACtC,OAAO,CAACwC,CAAC,IAAI;MACrBA,CAAC,CAAClC,IAAI,GAAG,GAAG,CAAC,CAAC;IAChB,CAAC,CAAC;;IACF;EACF;EACA;AACF;;AAGA,SAASmC,YAAYA,CAACrD,MAAM,EAAE;EAC5B,MAAMsD,UAAU,GAAGtD,MAAM,CAACgD,GAAG,CAAC,OAAO,CAAC;EAEtC,IAAIM,UAAU,CAAChD,MAAM,KAAK,CAAC,EAAE;IAC3B,OAAO,EAAE;EACX;EAEA,OAAOgD,UAAU,CAAC,CAAC,CAAC,CAAChB,SAAS,CAACiB,MAAM,CAAChB,EAAE,IAAIiB,kBAAkB,CAACjB,EAAE,CAAC,CAAC,CAACkB,GAAG,CAACC,QAAQ,IAAIA,QAAQ,CAAC/B,KAAK,CAAC;EAEnG,SAAS6B,kBAAkBA,CAACE,QAAQ,EAAE;IACpC,IAAIA,QAAQ,CAAClB,IAAI,KAAK,GAAG,IAAIkB,QAAQ,CAAClB,IAAI,KAAK,GAAG,EAAE;MAClD,OAAO,KAAK;IACd;IACA,IAAIkB,QAAQ,CAAC/B,KAAK,CAACrB,MAAM,KAAK,CAAC,EAAE;MAC/B,OAAO,KAAK;IACd;IACA;IACA,OAAO,IAAI;EACb;AAEF;AAEO,SAASF,yBAAyBA,CAACJ,MAAM,EAAE;EAChDiD,kBAAkB,CAACjD,MAAM,CAAC;;EAE1B;EACA,MAAMmC,SAAS,GAAGkB,YAAY,CAACrD,MAAM,CAAC;EAEtCA,MAAM,CAACW,MAAM,CAACC,OAAO,CAACC,KAAK,IAAI8C,wBAAwB,CAAC9C,KAAK,EAAEb,MAAM,EAAEmC,SAAS,CAAC,CAAC;AAEpF;AAEA,SAASwB,wBAAwBA,CAAC9C,KAAK,EAAEb,MAAM,EAAEmC,SAAS,EAAE;EAC1DW,sBAAsB,CAACjC,KAAK,EAAEb,MAAM,CAAC;EACrC4C,4BAA4B,CAAC/B,KAAK,EAAEsB,SAAS,CAAC;EAC9CU,4BAA4B,CAAChC,KAAK,EAAEsB,SAAS,CAAC;AAChD"}
@@ -10,20 +10,12 @@ exports.normalizeAs = normalizeAs;
10
10
  exports.normalizeControlSubfieldValue = normalizeControlSubfieldValue;
11
11
  exports.normalizeIsni = normalizeIsni;
12
12
  var _clone = _interopRequireDefault(require("clone"));
13
+ var _utils = require("./utils");
13
14
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
14
15
  // Relocated from melinda-marc-record-merge-reducers (and renamed)
15
16
  //import createDebugLogger from 'debug';
16
17
 
17
18
  //const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:normalizeIdentifiers');
18
-
19
- function fieldToString(f) {
20
- return `${f.tag} ${f.ind1}${f.ind2} ‡${formatSubfields(f)}`;
21
- function formatSubfields(field) {
22
- //return field.subfields.map(sf => `${sf.code}${sf.value || ''}`).join('‡');
23
- return field.subfields.map(sf => `${sf.code}${sf.value}`).join(' ‡');
24
- }
25
- }
26
-
27
19
  /*
28
20
  function nvdebug(message, func) {
29
21
  if (func) { // eslint-disable-line functional/no-conditional-statements
@@ -32,7 +24,6 @@ function nvdebug(message, func) {
32
24
  console.info(message); // eslint-disable-line no-console
33
25
  }
34
26
  */
35
-
36
27
  function _default() {
37
28
  // NB! We should and could handle ISNIs here as well.
38
29
  return {
@@ -91,8 +82,8 @@ function _default() {
91
82
  }
92
83
  const normalizedField = (0, _clone.default)(field);
93
84
  fieldNormalizeControlNumbers(normalizedField);
94
- const orig = fieldToString(field);
95
- const mod = fieldToString(normalizedField);
85
+ const orig = (0, _utils.fieldToString)(field);
86
+ const mod = (0, _utils.fieldToString)(normalizedField);
96
87
  if (orig !== mod) {
97
88
  // Fail as the input is "broken"/"crap"/sumthing
98
89
  res.message.push(`'${orig}' could do with control number identifier normalization`); // eslint-disable-line functional/immutable-data
@@ -1 +1 @@
1
- {"version":3,"file":"normalize-identifiers.js","names":["_clone","_interopRequireDefault","require","obj","__esModule","default","fieldToString","f","tag","ind1","ind2","formatSubfields","field","subfields","map","sf","code","value","join","_default","description","validate","fix","record","res","message","valid","fields","forEach","fieldNormalizeControlNumbers","validateField","length","normalizedField","clone","orig","mod","push","alephInternal01","alephInternal10","alephInternal11","alephInternal12","alephInternal13","standard01","standard10","standard11","standard12","standard13","both01","ALEPH_INTERNAL","STANDARD","both10","both11","both12","both13","mappings","normalizeNineDigitIDs","targetFormat","nineDigitTail","slice","test","currPrefix","isIsni","normalizeIsni","replace","normalizeControlSubfieldValue","normalizedValue","normalizeAs","subfieldCode","includes","undefined"],"sources":["../src/normalize-identifiers.js"],"sourcesContent":["// Relocated from melinda-marc-record-merge-reducers (and renamed)\n//import createDebugLogger from 'debug';\nimport clone from 'clone';\n//const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:normalizeIdentifiers');\n\n\nfunction fieldToString(f) {\n return `${f.tag} ${f.ind1}${f.ind2} ‡${formatSubfields(f)}`;\n\n function formatSubfields(field) {\n //return field.subfields.map(sf => `${sf.code}${sf.value || ''}`).join('‡');\n return field.subfields.map(sf => `${sf.code}${sf.value}`).join(' ‡');\n }\n}\n\n/*\nfunction nvdebug(message, func) {\n if (func) { // eslint-disable-line functional/no-conditional-statements\n func(message);\n }\n console.info(message); // eslint-disable-line no-console\n}\n*/\n\nexport default function () {\n\n // NB! We should and could handle ISNIs here as well.\n return {\n description: 'Normalizes identifiers such as subfield $0 values',\n validate, fix\n };\n\n function fix(record) {\n const res = {message: [], fix: [], valid: true};\n //message.fix = []; // eslint-disable-line functional/immutable-data\n\n // Actual parsing of all fields\n /*\n if (!record.fields) {\n return false;\n }\n */\n\n //nvdebug(`NORMALIZE CONTROL NUMBER FIX`, debug);\n record.fields.forEach(field => {\n //nvdebug(` NORMALIZE CONTROL NUMBER FIX ${fieldToString(field)}`, debug);\n\n fieldNormalizeControlNumbers(field);\n //validateField(field, true, message);\n });\n\n // message.valid = !(message.message.length >= 1); // eslint-disable-line functional/immutable-data\n return res;\n }\n\n function validate(record) {\n const res = {message: []};\n //nvdebug(`NORMALIZE CONTROL NUMBER VALIDATE`, debug);\n // Actual parsing of all fields\n /*\n if (!record.fields) {\n return false;\n }\n */\n\n record.fields.forEach(field => {\n //nvdebug(` NORMALIZE CONTROL NUMBER VALIDATE ${fieldToString(field)}`, debug);\n validateField(field, res);\n });\n\n res.valid = !(res.message.length >= 1); // eslint-disable-line functional/immutable-data\n return res;\n }\n\n function validateField(field, res) {\n if (!field.subfields) {\n return;\n }\n\n const normalizedField = clone(field);\n fieldNormalizeControlNumbers(normalizedField);\n\n const orig = fieldToString(field);\n const mod = fieldToString(normalizedField);\n if (orig !== mod) { // Fail as the input is \"broken\"/\"crap\"/sumthing\n res.message.push(`'${orig}' could do with control number identifier normalization`); // eslint-disable-line functional/immutable-data\n return;\n }\n\n return;\n }\n}\n\nconst alephInternal01 = '(FIN01)';\nconst alephInternal10 = '(FIN10)';\nconst alephInternal11 = '(FIN11)';\nconst alephInternal12 = '(FIN12)';\nconst alephInternal13 = '(FIN13)';\n\nconst standard01 = '(FI-MELINDA)';\nconst standard10 = '(FI-ASTERI-S)';\nconst standard11 = '(FI-ASTERI-N)';\nconst standard12 = '(FI-ASTERI-A)';\nconst standard13 = '(FI-ASTERI-W)';\n\nconst both01 = {ALEPH_INTERNAL: alephInternal01, STANDARD: standard01};\nconst both10 = {ALEPH_INTERNAL: alephInternal10, STANDARD: standard10};\nconst both11 = {ALEPH_INTERNAL: alephInternal11, STANDARD: standard11};\nconst both12 = {ALEPH_INTERNAL: alephInternal12, STANDARD: standard12};\nconst both13 = {ALEPH_INTERNAL: alephInternal13, STANDARD: standard13};\n\nconst mappings = {\n 'FCC': both01,\n '(FI-ASTERI-A)': both12,\n '(FI-ASTERI-N)': both11,\n '(FI-ASTERI-S)': both10,\n '(FI-ASTERI-W)': both13,\n '(FI-MELINDA)': both01,\n '(FIN01)': both01,\n '(FIN10)': both10,\n '(FIN11)': both11,\n '(FIN12)': both12,\n '(FIN13)': both13,\n 'http://urn.fi/URN:NBN:fi:au:finaf:': both11,\n 'https://urn.fi/URN:NBN:fi:au:finaf:': both11\n};\n\nfunction normalizeNineDigitIDs(value, targetFormat = 'ALEPH_INTERNAL') {\n // $value should be prefix + nine-digits. Do nothing if nine-digit tail condition is not met:\n const nineDigitTail = value.slice(-9);\n if (!(/^[0-9]{9}$/u).test(nineDigitTail)) {\n return value;\n }\n // Normalize prefix:\n const currPrefix = value.slice(0, -9);\n\n if (currPrefix in mappings) {\n //nvdebug(`${currPrefix}, TF:${targetFormat}...`);\n //nvdebug(`${JSON.stringify(mappings[currPrefix])}`);\n return `${mappings[currPrefix][targetFormat]}${nineDigitTail}`;\n }\n return value;\n}\n\nexport function isIsni(value) {\n if ((/^\\(isni\\)(?: ?[0-9]{4}){4}$/u).test(value)) {\n return true;\n }\n if ((/^https:\\/\\/isni.org\\/isni\\/[0-9]{16}$/u).test(value)) {\n return true;\n }\n return false;\n}\n\nexport function normalizeIsni(value) {\n if (isIsni(value)) {\n return `https://isni.org/isni/${value.replace(/[^0-9]/gu, '')}`;\n }\n return value;\n}\n\n\nexport function normalizeControlSubfieldValue(value = '', targetFormat = 'ALEPH_INTERNAL') {\n if (isIsni(value)) {\n return normalizeIsni(value);\n }\n\n const normalizedValue = normalizeNineDigitIDs(value, targetFormat);\n if (normalizedValue !== value) {\n return normalizedValue;\n }\n\n // Something for isni IDs?\n return value;\n}\n\n//export function normalizableSubfieldPrefix(tag, sf) {\nexport function normalizeAs(tag, subfieldCode) {\n //nvdebug(`nAs ${tag}, ${subfieldCode}`);\n if (subfieldCode === '0' || subfieldCode === '1' || subfieldCode === 'w') {\n return 'ALEPH_INTERNAL';\n }\n\n if (tag === '035' && ['a', 'z'].includes(subfieldCode)) {\n return 'STANDARD';\n }\n return undefined;\n}\n\nexport function fieldNormalizeControlNumbers(field) {\n // Rename \"Prefixes\" as \"ControlNumberIdentifiers\"?\n // No, since isni etc... however, just \"ControlNumber\" would do...\n // \"identifiers\" ?\n if (!field.subfields) {\n return;\n }\n\n field.subfields.forEach(sf => {\n const targetFormat = normalizeAs(field.tag, sf.code);\n if (targetFormat !== undefined) {\n //nvdebug(`NORMALIZE SUBFIELD $${sf.code} IN FIELD: '${fieldToString(field)}' TO ${targetFormat}`);\n sf.value = normalizeControlSubfieldValue(sf.value, targetFormat); // eslint-disable-line functional/immutable-data\n return;\n }\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"normalize-identifiers.js","names":["_clone","_interopRequireDefault","require","_utils","obj","__esModule","default","_default","description","validate","fix","record","res","message","valid","fields","forEach","field","fieldNormalizeControlNumbers","validateField","length","subfields","normalizedField","clone","orig","fieldToString","mod","push","alephInternal01","alephInternal10","alephInternal11","alephInternal12","alephInternal13","standard01","standard10","standard11","standard12","standard13","both01","ALEPH_INTERNAL","STANDARD","both10","both11","both12","both13","mappings","normalizeNineDigitIDs","value","targetFormat","nineDigitTail","slice","test","currPrefix","isIsni","normalizeIsni","replace","normalizeControlSubfieldValue","normalizedValue","normalizeAs","tag","subfieldCode","includes","undefined","sf","code"],"sources":["../src/normalize-identifiers.js"],"sourcesContent":["// Relocated from melinda-marc-record-merge-reducers (and renamed)\n//import createDebugLogger from 'debug';\nimport clone from 'clone';\nimport {fieldToString} from './utils';\n//const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:normalizeIdentifiers');\n\n/*\nfunction nvdebug(message, func) {\n if (func) { // eslint-disable-line functional/no-conditional-statements\n func(message);\n }\n console.info(message); // eslint-disable-line no-console\n}\n*/\n\nexport default function () {\n\n // NB! We should and could handle ISNIs here as well.\n return {\n description: 'Normalizes identifiers such as subfield $0 values',\n validate, fix\n };\n\n function fix(record) {\n const res = {message: [], fix: [], valid: true};\n //message.fix = []; // eslint-disable-line functional/immutable-data\n\n // Actual parsing of all fields\n /*\n if (!record.fields) {\n return false;\n }\n */\n\n //nvdebug(`NORMALIZE CONTROL NUMBER FIX`, debug);\n record.fields.forEach(field => {\n //nvdebug(` NORMALIZE CONTROL NUMBER FIX ${fieldToString(field)}`, debug);\n\n fieldNormalizeControlNumbers(field);\n //validateField(field, true, message);\n });\n\n // message.valid = !(message.message.length >= 1); // eslint-disable-line functional/immutable-data\n return res;\n }\n\n function validate(record) {\n const res = {message: []};\n //nvdebug(`NORMALIZE CONTROL NUMBER VALIDATE`, debug);\n // Actual parsing of all fields\n /*\n if (!record.fields) {\n return false;\n }\n */\n\n record.fields.forEach(field => {\n //nvdebug(` NORMALIZE CONTROL NUMBER VALIDATE ${fieldToString(field)}`, debug);\n validateField(field, res);\n });\n\n res.valid = !(res.message.length >= 1); // eslint-disable-line functional/immutable-data\n return res;\n }\n\n function validateField(field, res) {\n if (!field.subfields) {\n return;\n }\n\n const normalizedField = clone(field);\n fieldNormalizeControlNumbers(normalizedField);\n\n const orig = fieldToString(field);\n const mod = fieldToString(normalizedField);\n if (orig !== mod) { // Fail as the input is \"broken\"/\"crap\"/sumthing\n res.message.push(`'${orig}' could do with control number identifier normalization`); // eslint-disable-line functional/immutable-data\n return;\n }\n\n return;\n }\n}\n\nconst alephInternal01 = '(FIN01)';\nconst alephInternal10 = '(FIN10)';\nconst alephInternal11 = '(FIN11)';\nconst alephInternal12 = '(FIN12)';\nconst alephInternal13 = '(FIN13)';\n\nconst standard01 = '(FI-MELINDA)';\nconst standard10 = '(FI-ASTERI-S)';\nconst standard11 = '(FI-ASTERI-N)';\nconst standard12 = '(FI-ASTERI-A)';\nconst standard13 = '(FI-ASTERI-W)';\n\nconst both01 = {ALEPH_INTERNAL: alephInternal01, STANDARD: standard01};\nconst both10 = {ALEPH_INTERNAL: alephInternal10, STANDARD: standard10};\nconst both11 = {ALEPH_INTERNAL: alephInternal11, STANDARD: standard11};\nconst both12 = {ALEPH_INTERNAL: alephInternal12, STANDARD: standard12};\nconst both13 = {ALEPH_INTERNAL: alephInternal13, STANDARD: standard13};\n\nconst mappings = {\n 'FCC': both01,\n '(FI-ASTERI-A)': both12,\n '(FI-ASTERI-N)': both11,\n '(FI-ASTERI-S)': both10,\n '(FI-ASTERI-W)': both13,\n '(FI-MELINDA)': both01,\n '(FIN01)': both01,\n '(FIN10)': both10,\n '(FIN11)': both11,\n '(FIN12)': both12,\n '(FIN13)': both13,\n 'http://urn.fi/URN:NBN:fi:au:finaf:': both11,\n 'https://urn.fi/URN:NBN:fi:au:finaf:': both11\n};\n\nfunction normalizeNineDigitIDs(value, targetFormat = 'ALEPH_INTERNAL') {\n // $value should be prefix + nine-digits. Do nothing if nine-digit tail condition is not met:\n const nineDigitTail = value.slice(-9);\n if (!(/^[0-9]{9}$/u).test(nineDigitTail)) {\n return value;\n }\n // Normalize prefix:\n const currPrefix = value.slice(0, -9);\n\n if (currPrefix in mappings) {\n //nvdebug(`${currPrefix}, TF:${targetFormat}...`);\n //nvdebug(`${JSON.stringify(mappings[currPrefix])}`);\n return `${mappings[currPrefix][targetFormat]}${nineDigitTail}`;\n }\n return value;\n}\n\nexport function isIsni(value) {\n if ((/^\\(isni\\)(?: ?[0-9]{4}){4}$/u).test(value)) {\n return true;\n }\n if ((/^https:\\/\\/isni.org\\/isni\\/[0-9]{16}$/u).test(value)) {\n return true;\n }\n return false;\n}\n\nexport function normalizeIsni(value) {\n if (isIsni(value)) {\n return `https://isni.org/isni/${value.replace(/[^0-9]/gu, '')}`;\n }\n return value;\n}\n\n\nexport function normalizeControlSubfieldValue(value = '', targetFormat = 'ALEPH_INTERNAL') {\n if (isIsni(value)) {\n return normalizeIsni(value);\n }\n\n const normalizedValue = normalizeNineDigitIDs(value, targetFormat);\n if (normalizedValue !== value) {\n return normalizedValue;\n }\n\n // Something for isni IDs?\n return value;\n}\n\n//export function normalizableSubfieldPrefix(tag, sf) {\nexport function normalizeAs(tag, subfieldCode) {\n //nvdebug(`nAs ${tag}, ${subfieldCode}`);\n if (subfieldCode === '0' || subfieldCode === '1' || subfieldCode === 'w') {\n return 'ALEPH_INTERNAL';\n }\n\n if (tag === '035' && ['a', 'z'].includes(subfieldCode)) {\n return 'STANDARD';\n }\n return undefined;\n}\n\nexport function fieldNormalizeControlNumbers(field) {\n // Rename \"Prefixes\" as \"ControlNumberIdentifiers\"?\n // No, since isni etc... however, just \"ControlNumber\" would do...\n // \"identifiers\" ?\n if (!field.subfields) {\n return;\n }\n\n field.subfields.forEach(sf => {\n const targetFormat = normalizeAs(field.tag, sf.code);\n if (targetFormat !== undefined) {\n //nvdebug(`NORMALIZE SUBFIELD $${sf.code} IN FIELD: '${fieldToString(field)}' TO ${targetFormat}`);\n sf.value = normalizeControlSubfieldValue(sf.value, targetFormat); // eslint-disable-line functional/immutable-data\n return;\n }\n });\n}\n"],"mappings":"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"}
@@ -7,6 +7,7 @@ exports.default = _default;
7
7
  exports.fieldFixComposition = fieldFixComposition;
8
8
  var _clone = _interopRequireDefault(require("clone"));
9
9
  var _unicodeDecomposition = require("./unicode-decomposition");
10
+ var _utils = require("./utils");
10
11
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
12
  //import createDebugLogger from 'debug';
12
13
 
@@ -71,9 +72,9 @@ function _default() {
71
72
  if (!field.subfields) {
72
73
  return;
73
74
  }
74
- const orig = fieldToString(field);
75
+ const orig = (0, _utils.fieldToString)(field);
75
76
  const normalizedField = fieldFixComposition((0, _clone.default)(field));
76
- const mod = fieldToString(normalizedField);
77
+ const mod = (0, _utils.fieldToString)(normalizedField);
77
78
  if (orig !== mod) {
78
79
  // Fail as the input is "broken"/"crap"/sumthing
79
80
  res.message.push(`'${orig}' requires normalization`); // eslint-disable-line functional/immutable-data
@@ -81,13 +82,6 @@ function _default() {
81
82
  }
82
83
  return;
83
84
  }
84
- function fieldToString(f) {
85
- return `${f.tag} ${f.ind1}${f.ind2} ‡${formatSubfields(f)}`;
86
- function formatSubfields(field) {
87
- //return field.subfields.map(sf => `${sf.code}${sf.value || ''}`).join('‡');
88
- return field.subfields.map(sf => `${sf.code}${sf.value}`).join('‡');
89
- }
90
- }
91
85
  }
92
86
 
93
87
  // Traditionally these six are precomposed and all the rest decomposed
@@ -1 +1 @@
1
- {"version":3,"file":"normalize-utf8-diacritics.js","names":["_clone","_interopRequireDefault","require","_unicodeDecomposition","obj","__esModule","default","_default","description","validate","fix","record","res","message","valid","fields","forEach","field","fieldFixComposition","validateField","length","subfields","orig","fieldToString","normalizedField","clone","mod","push","f","tag","ind1","ind2","formatSubfields","map","sf","code","value","join","precomposeFinnishLetters","replace","fixComposition","match","nongenericNormalization","String","normalize","subfield","index"],"sources":["../src/normalize-utf8-diacritics.js"],"sourcesContent":["//import createDebugLogger from 'debug';\nimport clone from 'clone';\nimport {convert as nongenericNormalization} from './unicode-decomposition';\n\n// Note that https://github.com/NatLibFi/marc-record-validators-melinda/blob/master/src/unicode-decomposition.js contains\n// similar functionalities. It's less generic and lacks diacritic removal but has it advantages as well.\n\n//const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda/normalize-utf-diacritics');\n\n// See also https://github.com/NatLibFi/marc-record-validators-melinda/blob/master/src/unicode-decomposition.js .\n// It uses a list of convertable characters whilst this uses a generic stuff as well.\n// It handles various '.' and '©' type normalizations as well.\n// NB! This version has minor bug/feature issue regarding fixComposition()\n\n// Author(s): Nicholas Volk\nexport default function () {\n\n return {\n description: 'Generic normalization of latin UTF-8 diacritics. Precompose Finnish å, ä and ö. Decompose others.',\n validate, fix\n };\n\n function fix(record) {\n const res = {message: [], fix: [], valid: true};\n //message.fix = []; // eslint-disable-line functional/immutable-data\n\n // Actual parsing of all fields\n /*\n if (!record.fields) {\n return false;\n }\n */\n\n record.fields.forEach(field => {\n fieldFixComposition(field);\n //validateField(field, true, message);\n });\n\n // message.valid = !(message.message.length >= 1); // eslint-disable-line functional/immutable-data\n return res;\n }\n\n function validate(record) {\n const res = {message: []};\n\n // Actual parsing of all fields\n /*\n if (!record.fields) {\n return false;\n }\n */\n\n record.fields.forEach(field => {\n validateField(field, res);\n });\n\n res.valid = !(res.message.length >= 1); // eslint-disable-line functional/immutable-data\n return res;\n }\n\n function validateField(field, res) {\n if (!field.subfields) {\n return;\n }\n const orig = fieldToString(field);\n\n const normalizedField = fieldFixComposition(clone(field));\n const mod = fieldToString(normalizedField);\n if (orig !== mod) { // Fail as the input is \"broken\"/\"crap\"/sumthing\n res.message.push(`'${orig}' requires normalization`); // eslint-disable-line functional/immutable-data\n return;\n }\n return;\n }\n\n function fieldToString(f) {\n return `${f.tag} ${f.ind1}${f.ind2} ‡${formatSubfields(f)}`;\n\n function formatSubfields(field) {\n //return field.subfields.map(sf => `${sf.code}${sf.value || ''}`).join('‡');\n return field.subfields.map(sf => `${sf.code}${sf.value}`).join('‡');\n }\n }\n}\n\n\n// Traditionally these six are precomposed and all the rest decomposed\nfunction precomposeFinnishLetters(value = '') {\n return value.\n replace(/å/gu, 'å').\n replace(/ä/gu, 'ä').\n replace(/ö/gu, 'ö').\n replace(/Å/gu, 'Å').\n replace(/Ä/gu, 'Ä').\n replace(/Ö/gu, 'Ö');\n}\n\nfunction fixComposition(value = '') {\n // Target: Diacritics use Melinda internal notation.\n // General solution: Decompose everything and then compose 'å', 'ä', 'ö', 'Å', 'Ä' and 'Ö'.\n // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize\n // Bug/Feature: the generic normalize() function also normalizes non-latin encodings as well, is this ok?\n // Exception: Input contains non-Latin script letters: don't decompose (see field 880 tests):\n if (value.match(/[^\\p{Script=Latin}\\p{Script=Common}\\p{Script=Inherited}]/u)) {\n // Problem with this approach: mixed language content (eg. cyrillic + latin) won't get normalized.\n // Hack/Damage control: we might add decomposition rules for most common diacritis here (eg. ü, é...).\n // OR we could split input to words and handle them separately?\n // NB! Hack not implemented yet. The main source of problematic case would probably be greek characters\n // within texts, that are written with latin alphabet.\n //return precomposeFinnishLetters(value);\n return nongenericNormalization(value);\n }\n return precomposeFinnishLetters(String(value).normalize('NFD'));\n}\n\n\nexport function fieldFixComposition(field) {\n if (!field.subfields) {\n return field;\n }\n //const originalValue = fieldToString(field);\n //nvdebug(`fFC: '${originalValue}'`, debug);\n field.subfields.forEach((subfield, index) => {\n field.subfields[index].value = fixComposition(subfield.value); // eslint-disable-line functional/immutable-data\n });\n //const newValue = fieldToString(field);\n //if (originalValue !== newValue) { // eslint-disable-line functional/no-conditional-statements\n // debug(`FIXCOMP: '${originalValue}' => '${newValue}'`);\n //}\n return field;\n}\n\n/*\nexport function fieldRemoveDecomposedDiacritics(field) {\n // Raison d'être/motivation: \"Sirén\" and diacriticless \"Siren\" might refer to a same surname, so this normalization\n // allows us to compare authors and avoid duplicate fields.\n field.subfields.forEach((sf) => {\n sf.value = removeDecomposedDiacritics(sf.value); // eslint-disable-line functional/immutable-data\n });\n\n function removeDecomposedDiacritics(value = '') {\n // NB #1: Does nothing to precomposed letters. String.normalize('NFD') can handle them.\n // NB #2: Finnish letters 'å', 'ä', 'ö', 'Å', Ä', and 'Ö' should be handled (=precomposed) before calling this.\n // NB #3: Calling our very own fixComposition() before this function handles both #1 and #2.\n return String(value).replace(/\\p{Diacritic}/gu, '');\n }\n}\n*/\n\n"],"mappings":";;;;;;;AACA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,qBAAA,GAAAD,OAAA;AAA2E,SAAAD,uBAAAG,GAAA,WAAAA,GAAA,IAAAA,GAAA,CAAAC,UAAA,GAAAD,GAAA,KAAAE,OAAA,EAAAF,GAAA;AAF3E;;AAIA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AAEA;AACe,SAAAG,SAAA,EAAY;EAEzB,OAAO;IACLC,WAAW,EAAE,mGAAmG;IAChHC,QAAQ;IAAEC;EACZ,CAAC;EAED,SAASA,GAAGA,CAACC,MAAM,EAAE;IACnB,MAAMC,GAAG,GAAG;MAACC,OAAO,EAAE,EAAE;MAAEH,GAAG,EAAE,EAAE;MAAEI,KAAK,EAAE;IAAI,CAAC;IAC/C;;IAEA;IACA;AACJ;AACA;AACA;AACA;;IAEIH,MAAM,CAACI,MAAM,CAACC,OAAO,CAACC,KAAK,IAAI;MAC7BC,mBAAmB,CAACD,KAAK,CAAC;MAC1B;IACF,CAAC,CAAC;;IAEF;IACA,OAAOL,GAAG;EACZ;EAEA,SAASH,QAAQA,CAACE,MAAM,EAAE;IACxB,MAAMC,GAAG,GAAG;MAACC,OAAO,EAAE;IAAE,CAAC;;IAEzB;IACA;AACJ;AACA;AACA;AACA;;IAEIF,MAAM,CAACI,MAAM,CAACC,OAAO,CAACC,KAAK,IAAI;MAC7BE,aAAa,CAACF,KAAK,EAAEL,GAAG,CAAC;IAC3B,CAAC,CAAC;IAEFA,GAAG,CAACE,KAAK,GAAG,EAAEF,GAAG,CAACC,OAAO,CAACO,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC;IACxC,OAAOR,GAAG;EACZ;EAEA,SAASO,aAAaA,CAACF,KAAK,EAAEL,GAAG,EAAE;IACjC,IAAI,CAACK,KAAK,CAACI,SAAS,EAAE;MACpB;IACF;IACA,MAAMC,IAAI,GAAGC,aAAa,CAACN,KAAK,CAAC;IAEjC,MAAMO,eAAe,GAAGN,mBAAmB,CAAC,IAAAO,cAAK,EAACR,KAAK,CAAC,CAAC;IACzD,MAAMS,GAAG,GAAGH,aAAa,CAACC,eAAe,CAAC;IAC1C,IAAIF,IAAI,KAAKI,GAAG,EAAE;MAAE;MAClBd,GAAG,CAACC,OAAO,CAACc,IAAI,CAAE,IAAGL,IAAK,0BAAyB,CAAC,CAAC,CAAC;MACtD;IACF;IACA;EACF;EAEA,SAASC,aAAaA,CAACK,CAAC,EAAE;IACxB,OAAQ,GAAEA,CAAC,CAACC,GAAI,IAAGD,CAAC,CAACE,IAAK,GAAEF,CAAC,CAACG,IAAK,KAAIC,eAAe,CAACJ,CAAC,CAAE,EAAC;IAE3D,SAASI,eAAeA,CAACf,KAAK,EAAE;MAC9B;MACA,OAAOA,KAAK,CAACI,SAAS,CAACY,GAAG,CAACC,EAAE,IAAK,GAAEA,EAAE,CAACC,IAAK,GAAED,EAAE,CAACE,KAAM,EAAC,CAAC,CAACC,IAAI,CAAC,GAAG,CAAC;IACrE;EACF;AACF;;AAGA;AACA,SAASC,wBAAwBA,CAACF,KAAK,GAAG,EAAE,EAAE;EAC5C,OAAOA,KAAK,CACVG,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CACpBA,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CACpBA,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CACpBA,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CACpBA,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CACpBA,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;AACxB;AAEA,SAASC,cAAcA,CAACJ,KAAK,GAAG,EAAE,EAAE;EAClC;EACA;EACA;EACA;EACA;EACA,IAAIA,KAAK,CAACK,KAAK,CAAC,2DAA2D,CAAC,EAAE;IAC5E;IACA;IACA;IACA;IACA;IACA;IACA,OAAO,IAAAC,6BAAuB,EAACN,KAAK,CAAC;EACvC;EACA,OAAOE,wBAAwB,CAACK,MAAM,CAACP,KAAK,CAAC,CAACQ,SAAS,CAAC,KAAK,CAAC,CAAC;AACjE;AAGO,SAAS1B,mBAAmBA,CAACD,KAAK,EAAE;EACzC,IAAI,CAACA,KAAK,CAACI,SAAS,EAAE;IACpB,OAAOJ,KAAK;EACd;EACA;EACA;EACAA,KAAK,CAACI,SAAS,CAACL,OAAO,CAAC,CAAC6B,QAAQ,EAAEC,KAAK,KAAK;IAC3C7B,KAAK,CAACI,SAAS,CAACyB,KAAK,CAAC,CAACV,KAAK,GAAGI,cAAc,CAACK,QAAQ,CAACT,KAAK,CAAC,CAAC,CAAC;EACjE,CAAC,CAAC;EACF;EACA;EACA;EACA;EACA,OAAOnB,KAAK;AACd;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
1
+ {"version":3,"file":"normalize-utf8-diacritics.js","names":["_clone","_interopRequireDefault","require","_unicodeDecomposition","_utils","obj","__esModule","default","_default","description","validate","fix","record","res","message","valid","fields","forEach","field","fieldFixComposition","validateField","length","subfields","orig","fieldToString","normalizedField","clone","mod","push","precomposeFinnishLetters","value","replace","fixComposition","match","nongenericNormalization","String","normalize","subfield","index"],"sources":["../src/normalize-utf8-diacritics.js"],"sourcesContent":["//import createDebugLogger from 'debug';\nimport clone from 'clone';\nimport {convert as nongenericNormalization} from './unicode-decomposition';\nimport {fieldToString} from './utils';\n\n// Note that https://github.com/NatLibFi/marc-record-validators-melinda/blob/master/src/unicode-decomposition.js contains\n// similar functionalities. It's less generic and lacks diacritic removal but has it advantages as well.\n\n//const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda/normalize-utf-diacritics');\n\n// See also https://github.com/NatLibFi/marc-record-validators-melinda/blob/master/src/unicode-decomposition.js .\n// It uses a list of convertable characters whilst this uses a generic stuff as well.\n// It handles various '.' and '©' type normalizations as well.\n// NB! This version has minor bug/feature issue regarding fixComposition()\n\n// Author(s): Nicholas Volk\nexport default function () {\n\n return {\n description: 'Generic normalization of latin UTF-8 diacritics. Precompose Finnish å, ä and ö. Decompose others.',\n validate, fix\n };\n\n function fix(record) {\n const res = {message: [], fix: [], valid: true};\n //message.fix = []; // eslint-disable-line functional/immutable-data\n\n // Actual parsing of all fields\n /*\n if (!record.fields) {\n return false;\n }\n */\n\n record.fields.forEach(field => {\n fieldFixComposition(field);\n //validateField(field, true, message);\n });\n\n // message.valid = !(message.message.length >= 1); // eslint-disable-line functional/immutable-data\n return res;\n }\n\n function validate(record) {\n const res = {message: []};\n\n // Actual parsing of all fields\n /*\n if (!record.fields) {\n return false;\n }\n */\n\n record.fields.forEach(field => {\n validateField(field, res);\n });\n\n res.valid = !(res.message.length >= 1); // eslint-disable-line functional/immutable-data\n return res;\n }\n\n function validateField(field, res) {\n if (!field.subfields) {\n return;\n }\n const orig = fieldToString(field);\n\n const normalizedField = fieldFixComposition(clone(field));\n const mod = fieldToString(normalizedField);\n if (orig !== mod) { // Fail as the input is \"broken\"/\"crap\"/sumthing\n res.message.push(`'${orig}' requires normalization`); // eslint-disable-line functional/immutable-data\n return;\n }\n return;\n }\n}\n\n\n// Traditionally these six are precomposed and all the rest decomposed\nfunction precomposeFinnishLetters(value = '') {\n return value.\n replace(/å/gu, 'å').\n replace(/ä/gu, 'ä').\n replace(/ö/gu, 'ö').\n replace(/Å/gu, 'Å').\n replace(/Ä/gu, 'Ä').\n replace(/Ö/gu, 'Ö');\n}\n\nfunction fixComposition(value = '') {\n // Target: Diacritics use Melinda internal notation.\n // General solution: Decompose everything and then compose 'å', 'ä', 'ö', 'Å', 'Ä' and 'Ö'.\n // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize\n // Bug/Feature: the generic normalize() function also normalizes non-latin encodings as well, is this ok?\n // Exception: Input contains non-Latin script letters: don't decompose (see field 880 tests):\n if (value.match(/[^\\p{Script=Latin}\\p{Script=Common}\\p{Script=Inherited}]/u)) {\n // Problem with this approach: mixed language content (eg. cyrillic + latin) won't get normalized.\n // Hack/Damage control: we might add decomposition rules for most common diacritis here (eg. ü, é...).\n // OR we could split input to words and handle them separately?\n // NB! Hack not implemented yet. The main source of problematic case would probably be greek characters\n // within texts, that are written with latin alphabet.\n //return precomposeFinnishLetters(value);\n return nongenericNormalization(value);\n }\n return precomposeFinnishLetters(String(value).normalize('NFD'));\n}\n\n\nexport function fieldFixComposition(field) {\n if (!field.subfields) {\n return field;\n }\n //const originalValue = fieldToString(field);\n //nvdebug(`fFC: '${originalValue}'`, debug);\n field.subfields.forEach((subfield, index) => {\n field.subfields[index].value = fixComposition(subfield.value); // eslint-disable-line functional/immutable-data\n });\n //const newValue = fieldToString(field);\n //if (originalValue !== newValue) { // eslint-disable-line functional/no-conditional-statements\n // debug(`FIXCOMP: '${originalValue}' => '${newValue}'`);\n //}\n return field;\n}\n\n/*\nexport function fieldRemoveDecomposedDiacritics(field) {\n // Raison d'être/motivation: \"Sirén\" and diacriticless \"Siren\" might refer to a same surname, so this normalization\n // allows us to compare authors and avoid duplicate fields.\n field.subfields.forEach((sf) => {\n sf.value = removeDecomposedDiacritics(sf.value); // eslint-disable-line functional/immutable-data\n });\n\n function removeDecomposedDiacritics(value = '') {\n // NB #1: Does nothing to precomposed letters. String.normalize('NFD') can handle them.\n // NB #2: Finnish letters 'å', 'ä', 'ö', 'Å', Ä', and 'Ö' should be handled (=precomposed) before calling this.\n // NB #3: Calling our very own fixComposition() before this function handles both #1 and #2.\n return String(value).replace(/\\p{Diacritic}/gu, '');\n }\n}\n*/\n\n"],"mappings":"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"}
package/dist/utils.js CHANGED
@@ -37,9 +37,15 @@ function fieldHasSubfield(field, subfieldCode, subfieldValue = null) {
37
37
  function subfieldToString(sf) {
38
38
  return `‡${sf.code} ${sf.value}`;
39
39
  }
40
+ function normalizeIndicatorValue(val) {
41
+ if (val === ' ') {
42
+ return '#';
43
+ }
44
+ return val;
45
+ }
40
46
  function fieldToString(f) {
41
47
  if ('subfields' in f) {
42
- return `${f.tag} ${f.ind1}${f.ind2}${formatSubfields(f)}`;
48
+ return `${f.tag} ${normalizeIndicatorValue(f.ind1)}${normalizeIndicatorValue(f.ind2)}${formatSubfields(f)}`;
43
49
  }
44
50
  return `${f.tag} ${f.value}`;
45
51
  function formatSubfields(field) {
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","names":["isElectronicMaterial","record","f337s","get","some","field","mediaTypeIsC","subfields","sub","code","value","sourceIsRdamedia","nvdebug","message","func","undefined","fieldHasSubfield","subfieldCode","subfieldValue","sf","subfieldToString","fieldToString","f","tag","ind1","ind2","formatSubfields","map","join","fieldsToString","fields"],"sources":["../src/utils.js"],"sourcesContent":["export function isElectronicMaterial(record) {\n const f337s = record.get('337');\n\n return f337s.some(field => {\n const mediaTypeIsC = field.subfields.some(sub => sub.code === 'b' && sub.value === 'c');\n const sourceIsRdamedia = field.subfields.some(sub => sub.code === '2' && sub.value === 'rdamedia');\n return mediaTypeIsC && sourceIsRdamedia;\n });\n}\n\nexport function nvdebug(message, func = undefined) {\n if (func) { // eslint-disable-line functional/no-conditional-statements\n func(message);\n }\n //console.info(message); // eslint-disable-line no-console\n}\n\nexport function fieldHasSubfield(field, subfieldCode, subfieldValue = null) {\n if (!field.subfields) {\n return false;\n }\n if (subfieldValue === null) {\n return field.subfields.some(sf => sf.code === subfieldCode);\n }\n return field.subfields.some(sf => sf.code === subfieldCode && subfieldValue === sf.value);\n}\n\nexport function subfieldToString(sf) {\n return `‡${sf.code} ${sf.value}`;\n}\n\nexport function fieldToString(f) {\n if ('subfields' in f) {\n return `${f.tag} ${f.ind1}${f.ind2}${formatSubfields(f)}`;\n }\n return `${f.tag} ${f.value}`;\n\n function formatSubfields(field) {\n return field.subfields.map(sf => ` ${subfieldToString(sf)}`).join('');\n }\n}\n\nexport function fieldsToString(fields) {\n return fields.map(f => fieldToString(f)).join('\\t__SEPARATOR__\\t');\n}\n"],"mappings":";;;;;;;;;;;AAAO,SAASA,oBAAoBA,CAACC,MAAM,EAAE;EAC3C,MAAMC,KAAK,GAAGD,MAAM,CAACE,GAAG,CAAC,KAAK,CAAC;EAE/B,OAAOD,KAAK,CAACE,IAAI,CAACC,KAAK,IAAI;IACzB,MAAMC,YAAY,GAAGD,KAAK,CAACE,SAAS,CAACH,IAAI,CAACI,GAAG,IAAIA,GAAG,CAACC,IAAI,KAAK,GAAG,IAAID,GAAG,CAACE,KAAK,KAAK,GAAG,CAAC;IACvF,MAAMC,gBAAgB,GAAGN,KAAK,CAACE,SAAS,CAACH,IAAI,CAACI,GAAG,IAAIA,GAAG,CAACC,IAAI,KAAK,GAAG,IAAID,GAAG,CAACE,KAAK,KAAK,UAAU,CAAC;IAClG,OAAOJ,YAAY,IAAIK,gBAAgB;EACzC,CAAC,CAAC;AACJ;AAEO,SAASC,OAAOA,CAACC,OAAO,EAAEC,IAAI,GAAGC,SAAS,EAAE;EACjD,IAAID,IAAI,EAAE;IAAE;IACVA,IAAI,CAACD,OAAO,CAAC;EACf;EACA;AACF;;AAEO,SAASG,gBAAgBA,CAACX,KAAK,EAAEY,YAAY,EAAEC,aAAa,GAAG,IAAI,EAAE;EAC1E,IAAI,CAACb,KAAK,CAACE,SAAS,EAAE;IACpB,OAAO,KAAK;EACd;EACA,IAAIW,aAAa,KAAK,IAAI,EAAE;IAC1B,OAAOb,KAAK,CAACE,SAAS,CAACH,IAAI,CAACe,EAAE,IAAIA,EAAE,CAACV,IAAI,KAAKQ,YAAY,CAAC;EAC7D;EACA,OAAOZ,KAAK,CAACE,SAAS,CAACH,IAAI,CAACe,EAAE,IAAIA,EAAE,CAACV,IAAI,KAAKQ,YAAY,IAAIC,aAAa,KAAKC,EAAE,CAACT,KAAK,CAAC;AAC3F;AAEO,SAASU,gBAAgBA,CAACD,EAAE,EAAE;EACnC,OAAQ,IAAGA,EAAE,CAACV,IAAK,IAAGU,EAAE,CAACT,KAAM,EAAC;AAClC;AAEO,SAASW,aAAaA,CAACC,CAAC,EAAE;EAC/B,IAAI,WAAW,IAAIA,CAAC,EAAE;IACpB,OAAQ,GAAEA,CAAC,CAACC,GAAI,IAAGD,CAAC,CAACE,IAAK,GAAEF,CAAC,CAACG,IAAK,GAAEC,eAAe,CAACJ,CAAC,CAAE,EAAC;EAC3D;EACA,OAAQ,GAAEA,CAAC,CAACC,GAAI,OAAMD,CAAC,CAACZ,KAAM,EAAC;EAE/B,SAASgB,eAAeA,CAACrB,KAAK,EAAE;IAC9B,OAAOA,KAAK,CAACE,SAAS,CAACoB,GAAG,CAACR,EAAE,IAAK,IAAGC,gBAAgB,CAACD,EAAE,CAAE,EAAC,CAAC,CAACS,IAAI,CAAC,EAAE,CAAC;EACvE;AACF;AAEO,SAASC,cAAcA,CAACC,MAAM,EAAE;EACrC,OAAOA,MAAM,CAACH,GAAG,CAACL,CAAC,IAAID,aAAa,CAACC,CAAC,CAAC,CAAC,CAACM,IAAI,CAAC,mBAAmB,CAAC;AACpE"}
1
+ {"version":3,"file":"utils.js","names":["isElectronicMaterial","record","f337s","get","some","field","mediaTypeIsC","subfields","sub","code","value","sourceIsRdamedia","nvdebug","message","func","undefined","fieldHasSubfield","subfieldCode","subfieldValue","sf","subfieldToString","normalizeIndicatorValue","val","fieldToString","f","tag","ind1","ind2","formatSubfields","map","join","fieldsToString","fields"],"sources":["../src/utils.js"],"sourcesContent":["export function isElectronicMaterial(record) {\n const f337s = record.get('337');\n\n return f337s.some(field => {\n const mediaTypeIsC = field.subfields.some(sub => sub.code === 'b' && sub.value === 'c');\n const sourceIsRdamedia = field.subfields.some(sub => sub.code === '2' && sub.value === 'rdamedia');\n return mediaTypeIsC && sourceIsRdamedia;\n });\n}\n\nexport function nvdebug(message, func = undefined) {\n if (func) { // eslint-disable-line functional/no-conditional-statements\n func(message);\n }\n //console.info(message); // eslint-disable-line no-console\n}\n\nexport function fieldHasSubfield(field, subfieldCode, subfieldValue = null) {\n if (!field.subfields) {\n return false;\n }\n if (subfieldValue === null) {\n return field.subfields.some(sf => sf.code === subfieldCode);\n }\n return field.subfields.some(sf => sf.code === subfieldCode && subfieldValue === sf.value);\n}\n\nexport function subfieldToString(sf) {\n return `‡${sf.code} ${sf.value}`;\n}\n\nfunction normalizeIndicatorValue(val) {\n if (val === ' ') {\n return '#';\n }\n return val;\n}\n\nexport function fieldToString(f) {\n if ('subfields' in f) {\n return `${f.tag} ${normalizeIndicatorValue(f.ind1)}${normalizeIndicatorValue(f.ind2)}${formatSubfields(f)}`;\n }\n return `${f.tag} ${f.value}`;\n\n function formatSubfields(field) {\n return field.subfields.map(sf => ` ${subfieldToString(sf)}`).join('');\n }\n}\n\nexport function fieldsToString(fields) {\n return fields.map(f => fieldToString(f)).join('\\t__SEPARATOR__\\t');\n}\n"],"mappings":";;;;;;;;;;;AAAO,SAASA,oBAAoBA,CAACC,MAAM,EAAE;EAC3C,MAAMC,KAAK,GAAGD,MAAM,CAACE,GAAG,CAAC,KAAK,CAAC;EAE/B,OAAOD,KAAK,CAACE,IAAI,CAACC,KAAK,IAAI;IACzB,MAAMC,YAAY,GAAGD,KAAK,CAACE,SAAS,CAACH,IAAI,CAACI,GAAG,IAAIA,GAAG,CAACC,IAAI,KAAK,GAAG,IAAID,GAAG,CAACE,KAAK,KAAK,GAAG,CAAC;IACvF,MAAMC,gBAAgB,GAAGN,KAAK,CAACE,SAAS,CAACH,IAAI,CAACI,GAAG,IAAIA,GAAG,CAACC,IAAI,KAAK,GAAG,IAAID,GAAG,CAACE,KAAK,KAAK,UAAU,CAAC;IAClG,OAAOJ,YAAY,IAAIK,gBAAgB;EACzC,CAAC,CAAC;AACJ;AAEO,SAASC,OAAOA,CAACC,OAAO,EAAEC,IAAI,GAAGC,SAAS,EAAE;EACjD,IAAID,IAAI,EAAE;IAAE;IACVA,IAAI,CAACD,OAAO,CAAC;EACf;EACA;AACF;;AAEO,SAASG,gBAAgBA,CAACX,KAAK,EAAEY,YAAY,EAAEC,aAAa,GAAG,IAAI,EAAE;EAC1E,IAAI,CAACb,KAAK,CAACE,SAAS,EAAE;IACpB,OAAO,KAAK;EACd;EACA,IAAIW,aAAa,KAAK,IAAI,EAAE;IAC1B,OAAOb,KAAK,CAACE,SAAS,CAACH,IAAI,CAACe,EAAE,IAAIA,EAAE,CAACV,IAAI,KAAKQ,YAAY,CAAC;EAC7D;EACA,OAAOZ,KAAK,CAACE,SAAS,CAACH,IAAI,CAACe,EAAE,IAAIA,EAAE,CAACV,IAAI,KAAKQ,YAAY,IAAIC,aAAa,KAAKC,EAAE,CAACT,KAAK,CAAC;AAC3F;AAEO,SAASU,gBAAgBA,CAACD,EAAE,EAAE;EACnC,OAAQ,IAAGA,EAAE,CAACV,IAAK,IAAGU,EAAE,CAACT,KAAM,EAAC;AAClC;AAEA,SAASW,uBAAuBA,CAACC,GAAG,EAAE;EACpC,IAAIA,GAAG,KAAK,GAAG,EAAE;IACf,OAAO,GAAG;EACZ;EACA,OAAOA,GAAG;AACZ;AAEO,SAASC,aAAaA,CAACC,CAAC,EAAE;EAC/B,IAAI,WAAW,IAAIA,CAAC,EAAE;IACpB,OAAQ,GAAEA,CAAC,CAACC,GAAI,IAAGJ,uBAAuB,CAACG,CAAC,CAACE,IAAI,CAAE,GAAEL,uBAAuB,CAACG,CAAC,CAACG,IAAI,CAAE,GAAEC,eAAe,CAACJ,CAAC,CAAE,EAAC;EAC7G;EACA,OAAQ,GAAEA,CAAC,CAACC,GAAI,OAAMD,CAAC,CAACd,KAAM,EAAC;EAE/B,SAASkB,eAAeA,CAACvB,KAAK,EAAE;IAC9B,OAAOA,KAAK,CAACE,SAAS,CAACsB,GAAG,CAACV,EAAE,IAAK,IAAGC,gBAAgB,CAACD,EAAE,CAAE,EAAC,CAAC,CAACW,IAAI,CAAC,EAAE,CAAC;EACvE;AACF;AAEO,SAASC,cAAcA,CAACC,MAAM,EAAE;EACrC,OAAOA,MAAM,CAACH,GAAG,CAACL,CAAC,IAAID,aAAa,CAACC,CAAC,CAAC,CAAC,CAACM,IAAI,CAAC,mBAAmB,CAAC;AACpE"}
package/package.json CHANGED
@@ -14,7 +14,7 @@
14
14
  "url": "git@github.com:natlibfi/marc-record-validators-melinda.git"
15
15
  },
16
16
  "license": "MIT",
17
- "version": "10.9.0",
17
+ "version": "10.9.2",
18
18
  "main": "./dist/index.js",
19
19
  "publishConfig": {
20
20
  "access": "public"
@@ -41,7 +41,7 @@
41
41
  "@natlibfi/marc-record-validate": "^8.0.0",
42
42
  "cld3-asm": "^3.1.1",
43
43
  "debug": "^4.3.4",
44
- "isbn3": "^1.1.37",
44
+ "isbn3": "^1.1.39",
45
45
  "langs": "^2.0.0",
46
46
  "node-fetch": "^2.6.9",
47
47
  "xml2js": ">=0.6.0 <1.0.0",
@@ -0,0 +1,92 @@
1
+ //import createDebugLogger from 'debug';
2
+ import clone from 'clone';
3
+ import {fieldToString} from './utils';
4
+
5
+ // Author(s): Nicholas Volk
6
+ export default function () {
7
+
8
+ return {
9
+ description: 'Various fixes for field 521',
10
+ validate, fix
11
+ };
12
+
13
+ function fix(record) {
14
+ record.fields.forEach(field => {
15
+ fix521(field);
16
+ });
17
+ // Fix always succeeds (even when it really does not):
18
+ const res = {message: [], fix: [], valid: true};
19
+ return res;
20
+ }
21
+
22
+ function validate(record) {
23
+ const res = {message: []};
24
+
25
+ // Actual parsing of all fields
26
+ /*
27
+ if (!record.fields) {
28
+ return false;
29
+ }
30
+ */
31
+
32
+ record.fields?.forEach(field => {
33
+ validateField(field, res);
34
+ });
35
+
36
+ res.valid = !(res.message.length >= 1); // eslint-disable-line functional/immutable-data
37
+ return res;
38
+ }
39
+
40
+ function validateField(field, res) {
41
+ const orig = fieldToString(field);
42
+
43
+ const normalizedField = fix521(clone(field));
44
+ const mod = fieldToString(normalizedField);
45
+ if (orig !== mod) { // Fail as the input is "broken"/"crap"/sumthing
46
+ res.message.push(`'TODO: ${orig}' => '${mod}'`); // eslint-disable-line functional/immutable-data
47
+ return;
48
+ }
49
+ return;
50
+ }
51
+ }
52
+
53
+ function fixSubfieldA(a) {
54
+ a.value = a.value. // eslint-disable-line functional/immutable-data
55
+ // MET-332:
56
+ replace(/^(Ikäsuositus) ([0-9])/u, '$1: $2'); // eslint-disable-line prefer-named-capture-group, functional/immutable-data
57
+ }
58
+
59
+ function fixSubfieldAInternalPunctuation(field) {
60
+ const a = field.subfields.filter(sf => sf.code === 'a');
61
+
62
+ a.forEach(sf => fixSubfieldA(sf));
63
+ }
64
+
65
+ function getIndicator1(field) {
66
+ const [a] = field.subfields.filter(sf => sf.code === 'a');
67
+ if (a) {
68
+ if (a.value.match(/^Ikäsuositus/u)) {
69
+ return '1';
70
+ }
71
+ }
72
+ return undefined;
73
+ }
74
+
75
+ function fixIndicator1(field) {
76
+ const value = getIndicator1(field);
77
+ if (value) {
78
+ field.ind1 = value; // eslint-disable-line functional/immutable-data
79
+ return;
80
+ }
81
+
82
+ }
83
+
84
+ function fix521(field) {
85
+ if (field.tag !== '521' || !field.subfields) {
86
+ return field;
87
+ }
88
+ fixIndicator1(field);
89
+ fixSubfieldAInternalPunctuation(field);
90
+ return field;
91
+ }
92
+
@@ -0,0 +1,52 @@
1
+ import {expect} from 'chai';
2
+ import {MarcRecord} from '@natlibfi/marc-record';
3
+ import validatorFactory from './field-521-fix';
4
+ import {READERS} from '@natlibfi/fixura';
5
+ import generateTests from '@natlibfi/fixugen';
6
+ import createDebugLogger from 'debug';
7
+
8
+ generateTests({
9
+ callback,
10
+ path: [__dirname, '..', 'test-fixtures', 'fix521'],
11
+ useMetadataFile: true,
12
+ recurse: false,
13
+ fixura: {
14
+ reader: READERS.JSON
15
+ },
16
+ mocha: {
17
+ before: () => testValidatorFactory()
18
+ }
19
+ });
20
+ const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda/fix521:test');
21
+
22
+ async function testValidatorFactory() {
23
+ const validator = await validatorFactory();
24
+
25
+ expect(validator)
26
+ .to.be.an('object')
27
+ .that.has.any.keys('description', 'validate');
28
+
29
+ expect(validator.description).to.be.a('string');
30
+ expect(validator.validate).to.be.a('function');
31
+ }
32
+
33
+ async function callback({getFixture, enabled = true, fix = false}) {
34
+ if (enabled === false) {
35
+ debug('TEST SKIPPED!');
36
+ return;
37
+ }
38
+
39
+ const validator = await validatorFactory();
40
+ const record = new MarcRecord(getFixture('record.json'));
41
+ const expectedResult = getFixture('expectedResult.json');
42
+ // console.log(expectedResult); // eslint-disable-line
43
+
44
+ if (!fix) {
45
+ const result = await validator.validate(record);
46
+ expect(result).to.eql(expectedResult);
47
+ return;
48
+ }
49
+
50
+ await validator.fix(record);
51
+ expect(record).to.eql(expectedResult);
52
+ }
package/src/index.js CHANGED
@@ -4,6 +4,7 @@ import DuplicatesInd1 from './duplicates-ind1';
4
4
  import EmptyFields from './empty-fields';
5
5
  import EndingPunctuation from './ending-punctuation';
6
6
  import EndingWhitespace from './ending-whitespace';
7
+ import Field521Fix from './field-521-fix';
7
8
  import FieldsPresent from './fields-present';
8
9
  import FieldStructure from './field-structure';
9
10
  import FixedFields from './fixed-fields';
@@ -33,6 +34,7 @@ export {
33
34
  EmptyFields,
34
35
  EndingPunctuation,
35
36
  EndingWhitespace,
37
+ Field521Fix,
36
38
  FieldExclusion,
37
39
  FieldsPresent,
38
40
  FieldStructure,
@@ -2,18 +2,7 @@
2
2
  //import createDebugLogger from 'debug';
3
3
  //const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:normalizeIdentifiers');
4
4
 
5
-
6
- function fieldToString(f) {
7
- if (!f.subfields) {
8
- return `${f.tag} ${f.value}`;
9
- }
10
- return `${f.tag} ${f.ind1}${f.ind2} ‡${formatSubfields(f)}`;
11
-
12
- function formatSubfields(field) {
13
- //return field.subfields.map(sf => `${sf.code}${sf.value || ''}`).join('‡');
14
- return field.subfields.map(sf => `${sf.code}${sf.value}`).join(' ‡');
15
- }
16
- }
5
+ import {fieldToString} from './utils';
17
6
 
18
7
 
19
8
  export default function () {
@@ -1,18 +1,9 @@
1
1
  // Relocated from melinda-marc-record-merge-reducers (and renamed)
2
2
  //import createDebugLogger from 'debug';
3
3
  import clone from 'clone';
4
+ import {fieldToString} from './utils';
4
5
  //const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:normalizeIdentifiers');
5
6
 
6
-
7
- function fieldToString(f) {
8
- return `${f.tag} ${f.ind1}${f.ind2} ‡${formatSubfields(f)}`;
9
-
10
- function formatSubfields(field) {
11
- //return field.subfields.map(sf => `${sf.code}${sf.value || ''}`).join('‡');
12
- return field.subfields.map(sf => `${sf.code}${sf.value}`).join(' ‡');
13
- }
14
- }
15
-
16
7
  /*
17
8
  function nvdebug(message, func) {
18
9
  if (func) { // eslint-disable-line functional/no-conditional-statements
@@ -1,6 +1,7 @@
1
1
  //import createDebugLogger from 'debug';
2
2
  import clone from 'clone';
3
3
  import {convert as nongenericNormalization} from './unicode-decomposition';
4
+ import {fieldToString} from './utils';
4
5
 
5
6
  // Note that https://github.com/NatLibFi/marc-record-validators-melinda/blob/master/src/unicode-decomposition.js contains
6
7
  // similar functionalities. It's less generic and lacks diacritic removal but has it advantages as well.
@@ -72,15 +73,6 @@ export default function () {
72
73
  }
73
74
  return;
74
75
  }
75
-
76
- function fieldToString(f) {
77
- return `${f.tag} ${f.ind1}${f.ind2} ‡${formatSubfields(f)}`;
78
-
79
- function formatSubfields(field) {
80
- //return field.subfields.map(sf => `${sf.code}${sf.value || ''}`).join('‡');
81
- return field.subfields.map(sf => `${sf.code}${sf.value}`).join('‡');
82
- }
83
- }
84
76
  }
85
77
 
86
78
 
package/src/utils.js CHANGED
@@ -29,9 +29,16 @@ export function subfieldToString(sf) {
29
29
  return `‡${sf.code} ${sf.value}`;
30
30
  }
31
31
 
32
+ function normalizeIndicatorValue(val) {
33
+ if (val === ' ') {
34
+ return '#';
35
+ }
36
+ return val;
37
+ }
38
+
32
39
  export function fieldToString(f) {
33
40
  if ('subfields' in f) {
34
- return `${f.tag} ${f.ind1}${f.ind2}${formatSubfields(f)}`;
41
+ return `${f.tag} ${normalizeIndicatorValue(f.ind1)}${normalizeIndicatorValue(f.ind2)}${formatSubfields(f)}`;
35
42
  }
36
43
  return `${f.tag} ${f.value}`;
37
44
 
@@ -0,0 +1,6 @@
1
+ {
2
+ "message": [
3
+ "'TODO: 521 ## ‡a Ikäsuositus 50v.' => '521 1# ‡a Ikäsuositus: 50v.'"
4
+ ],
5
+ "valid": false
6
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "description": "Validate diacritics: fail, since both 506 ind1 and $a both should change",
3
+ "enabled": true,
4
+ "fix": false
5
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "fields": [
3
+ {
4
+ "tag": "005",
5
+ "value": "20220202020202.0"
6
+ },
7
+ { "tag": "521", "ind1": " ", "ind2": " ",
8
+ "subfields": [
9
+ { "code": "a", "value": "Ikäsuositus 50v." }
10
+ ]
11
+ }
12
+ ]
13
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "_validationOptions": {},
3
+ "leader": "",
4
+ "fields": [
5
+ {
6
+ "tag": "005",
7
+ "value": "20220202020202.0"
8
+ },
9
+ { "tag": "521", "ind1": "1", "ind2": " ",
10
+ "subfields": [
11
+ { "code": "a", "value": "Ikäsuositus: 50v." }
12
+ ]
13
+ }
14
+ ]
15
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "description": "Fix field 521 ind1 and $a value",
3
+ "enabled": true,
4
+ "fix": true
5
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "fields": [
3
+ {
4
+ "tag": "005",
5
+ "value": "20220202020202.0"
6
+ },
7
+ { "tag": "521", "ind1": " ", "ind2": " ",
8
+ "subfields": [
9
+ { "code": "a", "value": "Ikäsuositus 50v." }
10
+ ]
11
+ }
12
+ ]
13
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "message": [],
3
+ "valid": true
4
+ }
5
+
@@ -0,0 +1,5 @@
1
+ {
2
+ "description": "Validate diacritics: success, since nothing to do",
3
+ "enabled": true,
4
+ "fix": false
5
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "_validationOptions": {},
3
+ "leader": "",
4
+ "fields": [
5
+ { "tag": "521", "ind1": "1", "ind2": " ",
6
+ "subfields": [
7
+ { "code": "a", "value": "Ikäsuositus: 50v." }
8
+ ]
9
+ }
10
+
11
+
12
+ ]
13
+ }
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "message": [
3
- "Expected IND1 for '130 0 aThe Title.' is '4'",
4
- "Expected IND1 for '245 aAn Example' is '1'",
5
- "Expected IND2 for '245 aAn Example' is '3'",
6
- "Expected IND1 for '730 aA Tale of Two Cities' is '2'"
3
+ "Expected IND1 for '130 0# a The Title.' is '4'",
4
+ "Expected IND1 for '245 ## a An Example' is '1'",
5
+ "Expected IND2 for '245 ## a An Example' is '3'",
6
+ "Expected IND1 for '730 ## a A Tale of Two Cities' is '2'"
7
7
  ],
8
8
  "valid": false
9
9
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "message": [
3
- "MERGE RELATOR TERM FIELD: 700 1 ‡a Sukunimi, Etunimi, ‡e kirjoittaja, ‡e valokuvaaja."
3
+ "MERGE RELATOR TERM FIELD: 700 1# ‡a Sukunimi, Etunimi, ‡e kirjoittaja, ‡e valokuvaaja."
4
4
  ],
5
5
  "valid": false
6
6
  }
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "message": [
3
- "'100 aSirén, Matti ‡ekirjoittaja. ‡0(FI-ASTERI-N)000654321' could do with control number identifier normalization",
4
- "'773 wFCC000123456twhatever' could do with control number identifier normalization",
5
- "'773 ‡w(FI-MELINDA)000666666 ‡twhatever 2' could do with control number identifier normalization"
3
+ "'100 ## a Sirén, Matti ‡e kirjoittaja. ‡0 (FI-ASTERI-N)000654321' could do with control number identifier normalization",
4
+ "'773 ## w FCC000123456 t whatever' could do with control number identifier normalization",
5
+ "'773 ## ‡w (FI-MELINDA)000666666 ‡t whatever 2' could do with control number identifier normalization"
6
6
  ],
7
7
  "valid": false
8
8
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "message": [
3
- "'100 aSirén, Matti‡ekirjoittaja.' requires normalization",
4
- "'245 aÁÈÏÔŨ áèïôũ‡cMatti Sirén.' requires normalization"
3
+ "'100 ## a Sirén, Matti e kirjoittaja.' requires normalization",
4
+ "'245 ## a ÁÈÏÔŨ áèïôũ ‡c Matti Sirén.' requires normalization"
5
5
  ],
6
6
  "valid": false
7
7
  }
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "message": [
3
- "'100 1 ‡a Tuisku, Sara ‡e turkulainen ‡e testaaja' => '100 1 ‡a Tuisku, Sara, ‡e turkulainen, ‡e testaaja.'",
4
- "'700 1 ‡a Reipas, R. ‡d 2000- ‡e esittäjä' => '700 1 ‡a Reipas, R., ‡d 2000- ‡e esittäjä.'",
5
- "'700 1 ‡a Reippaahko, R. ‡d 2000-' => '700 1 ‡a Reippaahko, R., ‡d 2000-'",
6
- "'700 1 ‡a Reippaampi, R. ‡d 2000-2050 ‡e esittäjä' => '700 1 ‡a Reippaampi, R., ‡d 2000-2050, ‡e esittäjä.'",
7
- "'700 1 ‡a Reippain, R. ‡d 2000-2050' => '700 1 ‡a Reippain, R., ‡d 2000-2050.'",
8
- "'700 1 ‡a Nalle, P. ‡d 1926- ‡0 (FIN11)000000000' => '700 1 ‡a Nalle, P., ‡d 1926- ‡0 (FIN11)000000000'"
3
+ "'100 1# ‡a Tuisku, Sara ‡e turkulainen ‡e testaaja' => '100 1# ‡a Tuisku, Sara, ‡e turkulainen, ‡e testaaja.'",
4
+ "'700 1# ‡a Reipas, R. ‡d 2000- ‡e esittäjä' => '700 1# ‡a Reipas, R., ‡d 2000- ‡e esittäjä.'",
5
+ "'700 1# ‡a Reippaahko, R. ‡d 2000-' => '700 1# ‡a Reippaahko, R., ‡d 2000-'",
6
+ "'700 1# ‡a Reippaampi, R. ‡d 2000-2050 ‡e esittäjä' => '700 1# ‡a Reippaampi, R., ‡d 2000-2050, ‡e esittäjä.'",
7
+ "'700 1# ‡a Reippain, R. ‡d 2000-2050' => '700 1# ‡a Reippain, R., ‡d 2000-2050.'",
8
+ "'700 1# ‡a Nalle, P. ‡d 1926- ‡0 (FIN11)000000000' => '700 1# ‡a Nalle, P., ‡d 1926- ‡0 (FIN11)000000000'"
9
9
  ],
10
10
  "valid": false
11
11
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "message": [
3
- "'300 1 ‡a 740 sivua ‡b kuvitettu ‡c 25 cm ‡e 1 CD-levy' => '300 1 ‡a 740 sivua : ‡b kuvitettu ; ‡c 25 cm + ‡e 1 CD-levy'"
3
+ "'300 1# ‡a 740 sivua ‡b kuvitettu ‡c 25 cm ‡e 1 CD-levy' => '300 1# ‡a 740 sivua : ‡b kuvitettu ; ‡c 25 cm + ‡e 1 CD-levy'"
4
4
  ],
5
5
  "valid": false
6
6
  }
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "message": [
3
- "DEL: 500 ‡a Whatever.",
4
- "DEL: 700 1 ‡a A., A., ‡e kirjoittaja, ‡e taiteilija.",
5
- "DEL: 700 1 ‡a B., B., ‡e kirjoittaja.",
6
- "DEL: 700 1 ‡6 880-01 ‡a C., C., ‡e kirjoittaja.",
7
- "DEL: 880 1 ‡6 700-02 ‡a D., D., ‡e kirjoittaja."
3
+ "DEL: 500 ## ‡a Whatever.",
4
+ "DEL: 700 1# ‡a A., A., ‡e kirjoittaja, ‡e taiteilija.",
5
+ "DEL: 700 1# ‡a B., B., ‡e kirjoittaja.",
6
+ "DEL: 700 1# ‡6 880-01 ‡a C., C., ‡e kirjoittaja.",
7
+ "DEL: 880 1# ‡6 700-02 ‡a D., D., ‡e kirjoittaja."
8
8
  ],
9
9
  "valid": false
10
10
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "message": [
3
- "DEL: 100 1 ‡6 880-01 ‡a Zabara, Olena, ‡e kirjoittaja, ‡e taiteilija."
3
+ "DEL: 100 1# ‡6 880-01 ‡a Zabara, Olena, ‡e kirjoittaja, ‡e taiteilija."
4
4
  ],
5
5
  "valid": false
6
6
  }
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "message": [
3
- "DEL: 520 3 ‡8 2.1\\x ‡a eka",
4
- "DEL: 520 3 ‡8 2.2\\x ‡a toka",
5
- "DEL: 520 3 ‡8 2.3\\x ‡a kolmas"
3
+ "DEL: 520 3# ‡8 2.1\\x ‡a eka",
4
+ "DEL: 520 3# ‡8 2.2\\x ‡a toka",
5
+ "DEL: 520 3# ‡8 2.3\\x ‡a kolmas"
6
6
  ],
7
7
  "valid": false
8
8
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "message": [
3
- "DEL: '520 8 ‡6 880-05 ‡a Tiivistelmä venäjäksi,\t__SEPARATOR__\t880 8 ‡6 520-05 ‡a Образы составляют нашу жизнь. Реальные, воображаемые, мимолетные, те, что навсегда запечатлеваются в памяти. И пока живы образы, жива история, живы люди, жив каждый отельный человек.Роман \"Годы\" - словно фотоальбом, галерея воспоминаний, ворох образов, слов, вопросов, мыслей. Анни Эрно сумела воплотить не только память личности, но и коллективную память целой эпохи в своей беспрецедентной по форме и стилю прозе. И страницы, пропитанные нежным чувством ностальгии, смогут всколыхнуть эти образы в вашем сознании, увековечив воспоминания навсегда.' REASON: '520 8 ‡6 880-04 ‡a Tiivistelmä venäjäksi,\t__SEPARATOR__\t880 8 ‡6 520-04/(N ‡a Образы составляют нашу жизнь. Реальные, воображаемые, мимолетные, те, что навсегда запечатлеваются в памяти. И пока живы образы, жива история, живы люди, жив каждый отельный человек.Роман \"Годы\" - словно фотоальбом, галерея воспоминаний, ворох образов, слов, вопросов, мыслей. Анни Эрно сумела воплотить не только память личности, но и коллективную память целой эпохи в своей беспрецедентной по форме и стилю прозе. И страницы, пропитанные нежным чувством ностальгии, смогут всколыхнуть эти образы в вашем сознании, увековечив воспоминания навсегда.'"
3
+ "DEL: '520 8# ‡6 880-05 ‡a Tiivistelmä venäjäksi,\t__SEPARATOR__\t880 8# ‡6 520-05 ‡a Образы составляют нашу жизнь. Реальные, воображаемые, мимолетные, те, что навсегда запечатлеваются в памяти. И пока живы образы, жива история, живы люди, жив каждый отельный человек.Роман \"Годы\" - словно фотоальбом, галерея воспоминаний, ворох образов, слов, вопросов, мыслей. Анни Эрно сумела воплотить не только память личности, но и коллективную память целой эпохи в своей беспрецедентной по форме и стилю прозе. И страницы, пропитанные нежным чувством ностальгии, смогут всколыхнуть эти образы в вашем сознании, увековечив воспоминания навсегда.' REASON: '520 8# ‡6 880-04 ‡a Tiivistelmä venäjäksi,\t__SEPARATOR__\t880 8# ‡6 520-04/(N ‡a Образы составляют нашу жизнь. Реальные, воображаемые, мимолетные, те, что навсегда запечатлеваются в памяти. И пока живы образы, жива история, живы люди, жив каждый отельный человек.Роман \"Годы\" - словно фотоальбом, галерея воспоминаний, ворох образов, слов, вопросов, мыслей. Анни Эрно сумела воплотить не только память личности, но и коллективную память целой эпохи в своей беспрецедентной по форме и стилю прозе. И страницы, пропитанные нежным чувством ностальгии, смогут всколыхнуть эти образы в вашем сознании, увековечив воспоминания навсегда.'"
4
4
  ],
5
5
  "valid": false
6
6
  }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "message": [
3
- "650 7 ‡a bad3 ‡2 ysa.",
4
- "650 7 ‡a bad4 ‡2 mts/",
5
- "650 7 ‡a bad6 ‡2 mts/fin ",
6
- "650 7 ‡a bad7 ‡2 yso/foobar",
7
- "655 7 ‡a bad1 ‡2 slm//fin",
8
- "655 7 ‡a bad2 ‡2 slm/fin/",
9
- "655 7 ‡a bad5 ‡2 slm /fin"
3
+ "650 #7 ‡a bad3 ‡2 ysa.",
4
+ "650 #7 ‡a bad4 ‡2 mts/",
5
+ "650 #7 ‡a bad6 ‡2 mts/fin ",
6
+ "650 #7 ‡a bad7 ‡2 yso/foobar",
7
+ "655 #7 ‡a bad1 ‡2 slm//fin",
8
+ "655 #7 ‡a bad2 ‡2 slm/fin/",
9
+ "655 #7 ‡a bad5 ‡2 slm /fin"
10
10
  ],
11
11
  "valid": false
12
12
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "message": [
3
- "700 ‡a Nimi1, ‡d 1900-2000, ‡e esittäjä ‡e sovittaja, ‡e säveltäjä. ‡0 (isni)1234567890123456 => 700 ‡a Nimi1, ‡d 1900-2000, ‡e säveltäjä, ‡e sovittaja, ‡e esittäjä. ‡0 (isni)1234567890123456"
3
+ "700 ## ‡a Nimi1, ‡d 1900-2000, ‡e esittäjä ‡e sovittaja, ‡e säveltäjä. ‡0 (isni)1234567890123456 => 700 ## ‡a Nimi1, ‡d 1900-2000, ‡e säveltäjä, ‡e sovittaja, ‡e esittäjä. ‡0 (isni)1234567890123456"
4
4
  ],
5
5
  "valid": false
6
6
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "message": [
3
- "028 ‡b Bar Records ‡a BARCD-2"
3
+ "028 ## ‡b Bar Records ‡a BARCD-2"
4
4
  ],
5
5
  "valid": false
6
6
  }
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "message": [
3
- "'100 1 ‡a Tuisku, Sara, ‡e turkulainen, ‡e testaaja.' => '100 1 ‡a Tuisku, Sara ‡e turkulainen ‡e testaaja'",
4
- "'700 1 ‡a Reipas, R., ‡d 2000- ‡e esittäjä.' => '700 1 ‡a Reipas, R. ‡d 2000- ‡e esittäjä'",
5
- "'700 1 ‡a Reippaahko, R., ‡d 2000-' => '700 1 ‡a Reippaahko, R. ‡d 2000-'",
6
- "'700 1 ‡a Reippaampi, R., ‡d 2000-2050, ‡e esittäjä.' => '700 1 ‡a Reippaampi, R. ‡d 2000-2050 ‡e esittäjä'",
7
- "'700 1 ‡a Reippain, R., ‡d 2000-2050.' => '700 1 ‡a Reippain, R. ‡d 2000-2050'",
8
- "'700 1 ‡a Nalle, P., ‡d 1926- ‡0 (FIN11)000000000' => '700 1 ‡a Nalle, P. ‡d 1926- ‡0 (FIN11)000000000'"
3
+ "'100 1# ‡a Tuisku, Sara, ‡e turkulainen, ‡e testaaja.' => '100 1# ‡a Tuisku, Sara ‡e turkulainen ‡e testaaja'",
4
+ "'700 1# ‡a Reipas, R., ‡d 2000- ‡e esittäjä.' => '700 1# ‡a Reipas, R. ‡d 2000- ‡e esittäjä'",
5
+ "'700 1# ‡a Reippaahko, R., ‡d 2000-' => '700 1# ‡a Reippaahko, R. ‡d 2000-'",
6
+ "'700 1# ‡a Reippaampi, R., ‡d 2000-2050, ‡e esittäjä.' => '700 1# ‡a Reippaampi, R. ‡d 2000-2050 ‡e esittäjä'",
7
+ "'700 1# ‡a Reippain, R., ‡d 2000-2050.' => '700 1# ‡a Reippain, R. ‡d 2000-2050'",
8
+ "'700 1# ‡a Nalle, P., ‡d 1926- ‡0 (FIN11)000000000' => '700 1# ‡a Nalle, P. ‡d 1926- ‡0 (FIN11)000000000'"
9
9
  ],
10
10
  "valid": false
11
11
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "message": [
3
- "'300 1 ‡a 740 sivua : ‡b kuvitettu ; ‡c 25 cm + ‡e 1 CD-levy' => '300 1 ‡a 740 sivua ‡b kuvitettu ‡c 25 cm ‡e 1 CD-levy'"
3
+ "'300 1# ‡a 740 sivua : ‡b kuvitettu ; ‡c 25 cm + ‡e 1 CD-levy' => '300 1# ‡a 740 sivua ‡b kuvitettu ‡c 25 cm ‡e 1 CD-levy'"
4
4
  ],
5
5
  "valid": false
6
6
  }
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "message": [
3
- "Field '700 ‡a Nimi1 ‡0 (FI-ASTERI-N)000654321 ‡0 (orcid)0000-0002-1355-5633' contains deletable $0 subfield(s): (orcid)0000-0002-1355-5633",
4
- "Field '700 ‡a Nimi2 ‡0 https://isni.org/isni/0000000110485855 ‡0 (FI-ASTERI-N)000654322' contains deletable $0 subfield(s): https://isni.org/isni/0000000110485855",
5
- "Field '700 ‡a Nimi3 ‡0 (FI-ASTERI-N)000654323 ‡0 https://isni.org/isni/0000000110485853 ‡0 (keep-only-if-title-part-present)666 ‡0 (orcid)0000-0002-1355-5633' contains deletable $0 subfield(s): https://isni.org/isni/0000000110485853, (keep-only-if-title-part-present)666, (orcid)0000-0002-1355-5633",
6
- "Field '700 ‡a Nimi3 ‡0 (FI-ASTERI-N)000654323 ‡t Titlepart prevents unknown $0 identifiers from being removed ‡0 https://isni.org/isni/0000000110485853 ‡0 (keep-only-if-title-part-present)666 ‡0 (orcid)0000-0002-1355-5633' contains deletable $0 subfield(s): https://isni.org/isni/0000000110485853, (orcid)0000-0002-1355-5633"
3
+ "Field '700 ## ‡a Nimi1 ‡0 (FI-ASTERI-N)000654321 ‡0 (orcid)0000-0002-1355-5633' contains deletable $0 subfield(s): (orcid)0000-0002-1355-5633",
4
+ "Field '700 ## ‡a Nimi2 ‡0 https://isni.org/isni/0000000110485855 ‡0 (FI-ASTERI-N)000654322' contains deletable $0 subfield(s): https://isni.org/isni/0000000110485855",
5
+ "Field '700 ## ‡a Nimi3 ‡0 (FI-ASTERI-N)000654323 ‡0 https://isni.org/isni/0000000110485853 ‡0 (keep-only-if-title-part-present)666 ‡0 (orcid)0000-0002-1355-5633' contains deletable $0 subfield(s): https://isni.org/isni/0000000110485853, (keep-only-if-title-part-present)666, (orcid)0000-0002-1355-5633",
6
+ "Field '700 ## ‡a Nimi3 ‡0 (FI-ASTERI-N)000654323 ‡t Titlepart prevents unknown $0 identifiers from being removed ‡0 https://isni.org/isni/0000000110485853 ‡0 (keep-only-if-title-part-present)666 ‡0 (orcid)0000-0002-1355-5633' contains deletable $0 subfield(s): https://isni.org/isni/0000000110485853, (orcid)0000-0002-1355-5633"
7
7
  ],
8
8
  "valid": false
9
9
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "message": [
3
- "540 ‡c CC BY 4.0 ‡u https://creativecommons.org/licenses/by/4.0/deed.fi",
4
- "540 ‡a Whatever ‡c CC BY-NC 4.0 ‡u https://creativecommons.org/licenses/by-nc/4.0/deed.fi"
3
+ "540 ## ‡c CC BY 4.0 ‡u https://creativecommons.org/licenses/by/4.0/deed.fi",
4
+ "540 ## ‡a Whatever ‡c CC BY-NC 4.0 ‡u https://creativecommons.org/licenses/by-nc/4.0/deed.fi"
5
5
  ],
6
6
  "valid": false
7
7
  }
@@ -1,41 +0,0 @@
1
- {
2
- "_validationOptions": {},
3
- "leader": "",
4
- "fields": [
5
- {
6
- "tag": "005",
7
- "value": "20220202020202.0"
8
- },
9
- {
10
- "tag": "100",
11
- "ind1": " ",
12
- "ind2": " ",
13
- "subfields": [
14
- {
15
- "code": "a",
16
- "value": "Ålander, Väinö"
17
- },
18
- {
19
- "code": "e",
20
- "value": "kirjoittaja."
21
- }
22
- ]
23
- },
24
- {
25
- "tag": "245",
26
- "ind1": " ",
27
- "ind2": " ",
28
- "subfields": [
29
- {
30
- "code": "a",
31
- "value": "Örkkejä /"
32
- },
33
- {
34
- "code": "c",
35
- "value": "Väinö Ålander."
36
- }
37
- ]
38
- }
39
-
40
- ]
41
- }