@natlibfi/marc-record-validators-melinda 10.7.0 → 10.8.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/mergeRelatorTermFields.js +140 -0
- package/dist/mergeRelatorTermFields.js.map +1 -0
- package/dist/mergeRelatorTermFields.spec.js +51 -0
- package/dist/mergeRelatorTermFields.spec.js.map +1 -0
- package/dist/sortRelatorTerms.js +3 -1
- package/dist/sortRelatorTerms.js.map +1 -1
- package/dist/update-field-540.js +7 -1
- package/dist/update-field-540.js.map +1 -1
- package/package.json +2 -2
- package/src/index.js +2 -0
- package/src/mergeRelatorTermFields.js +143 -0
- package/src/mergeRelatorTermFields.spec.js +52 -0
- package/src/sortRelatorTerms.js +4 -1
- package/src/update-field-540.js +2 -1
- package/test-fixtures/mergeRelatorTermFields/fixer/01/expectedResult.json +14 -0
- package/test-fixtures/mergeRelatorTermFields/fixer/01/metadata.json +6 -0
- package/test-fixtures/mergeRelatorTermFields/fixer/01/record.json +16 -0
- package/test-fixtures/mergeRelatorTermFields/fixer/02/expectedResult.json +17 -0
- package/test-fixtures/mergeRelatorTermFields/fixer/02/metadata.json +6 -0
- package/test-fixtures/mergeRelatorTermFields/fixer/02/record.json +23 -0
- package/test-fixtures/mergeRelatorTermFields/validator/01/expectedResult.json +6 -0
- package/test-fixtures/mergeRelatorTermFields/validator/01/metadata.json +6 -0
- package/test-fixtures/mergeRelatorTermFields/validator/01/record.json +16 -0
- package/test-fixtures/mergeRelatorTermFields/validator/02/expectedResult.json +4 -0
- package/test-fixtures/mergeRelatorTermFields/validator/02/metadata.json +6 -0
- package/test-fixtures/mergeRelatorTermFields/validator/02/record.json +16 -0
package/dist/index.js
CHANGED
|
@@ -141,6 +141,12 @@ Object.defineProperty(exports, "SubfieldExclusion", {
|
|
|
141
141
|
return _subfieldExclusion.default;
|
|
142
142
|
}
|
|
143
143
|
});
|
|
144
|
+
Object.defineProperty(exports, "TypeOfDateF008", {
|
|
145
|
+
enumerable: true,
|
|
146
|
+
get: function () {
|
|
147
|
+
return _typeOfDate.default;
|
|
148
|
+
}
|
|
149
|
+
});
|
|
144
150
|
Object.defineProperty(exports, "UnicodeDecomposition", {
|
|
145
151
|
enumerable: true,
|
|
146
152
|
get: function () {
|
|
@@ -183,6 +189,7 @@ var _updateField = _interopRequireDefault(require("./update-field-540"));
|
|
|
183
189
|
var _sortSubfields = _interopRequireDefault(require("./sortSubfields"));
|
|
184
190
|
var _sortTags = _interopRequireDefault(require("./sort-tags"));
|
|
185
191
|
var _subfieldExclusion = _interopRequireDefault(require("./subfield-exclusion"));
|
|
192
|
+
var _typeOfDate = _interopRequireDefault(require("./typeOfDate-008"));
|
|
186
193
|
var _unicodeDecomposition = _interopRequireDefault(require("./unicode-decomposition"));
|
|
187
194
|
var _urn = _interopRequireDefault(require("./urn"));
|
|
188
195
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
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","_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 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 UnicodeDecomposition,\n UpdateField540,\n Urn\n};\n"],"mappings":"
|
|
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"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = _default;
|
|
7
|
+
var _clone = _interopRequireDefault(require("clone"));
|
|
8
|
+
var _punctuation = require("./punctuation2");
|
|
9
|
+
var _utils = require("./utils");
|
|
10
|
+
var _sortSubfields = require("./sortSubfields");
|
|
11
|
+
var _sortRelatorTerms = require("./sortRelatorTerms");
|
|
12
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
13
|
+
// Merge author/agent fields
|
|
14
|
+
//
|
|
15
|
+
// Rationale: Same author can appear in one 1XX and multiple 7XX fields having only different $e subfields.
|
|
16
|
+
// These fields can be merged (and $e-subfields can then be sorted)...
|
|
17
|
+
//
|
|
18
|
+
// Author(s): Nicholas Volk
|
|
19
|
+
|
|
20
|
+
//import createDebugLogger from 'debug';
|
|
21
|
+
/*
|
|
22
|
+
//const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:mergeRelatorTermFields');
|
|
23
|
+
//const debugData = debug.extend('data');
|
|
24
|
+
*/
|
|
25
|
+
function _default() {
|
|
26
|
+
return {
|
|
27
|
+
description: 'Merge author fields that only differ in $e relator terms',
|
|
28
|
+
validate,
|
|
29
|
+
fix
|
|
30
|
+
};
|
|
31
|
+
function fix(record) {
|
|
32
|
+
const msg = mergeRelatorTermFields(record, true);
|
|
33
|
+
const res = {
|
|
34
|
+
message: msg,
|
|
35
|
+
fix: msg,
|
|
36
|
+
valid: true
|
|
37
|
+
};
|
|
38
|
+
return res;
|
|
39
|
+
}
|
|
40
|
+
function validate(record) {
|
|
41
|
+
const msg = mergeRelatorTermFields(record, false);
|
|
42
|
+
const res = {
|
|
43
|
+
message: msg
|
|
44
|
+
};
|
|
45
|
+
res.valid = !(res.message.length >= 1); // eslint-disable-line functional/immutable-data
|
|
46
|
+
return res;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function createNormalizedClone(field) {
|
|
50
|
+
const clonedField = (0, _clone.default)(field);
|
|
51
|
+
// Normalize
|
|
52
|
+
(0, _punctuation.fieldStripPunctuation)(clonedField);
|
|
53
|
+
return clonedField;
|
|
54
|
+
}
|
|
55
|
+
function createNormalizedCloneWithoutRelatorTerms(field) {
|
|
56
|
+
const clonedField = createNormalizedClone(field);
|
|
57
|
+
// Remove relator terms $e subfi:
|
|
58
|
+
clonedField.subfields = clonedField.subfields.filter(sf => sf.code !== 'e'); // eslint-disable-line functional/immutable-data
|
|
59
|
+
return clonedField;
|
|
60
|
+
}
|
|
61
|
+
function fieldToRelatorTermSubfieldCode(field) {
|
|
62
|
+
if (['100', '110', '700', '710', '720', '751', '752'].includes(field.tag)) {
|
|
63
|
+
return 'e';
|
|
64
|
+
}
|
|
65
|
+
if (field.tag === '111' || field.tag === '711') {
|
|
66
|
+
return 'j';
|
|
67
|
+
}
|
|
68
|
+
return '?'; // No need to complain. Nothing is found.
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function getRelatorTermStrings(relatorTermSubfieldCode, field) {
|
|
72
|
+
return field.subfields.filter(sf => sf.code === relatorTermSubfieldCode).map(sf => sf.value);
|
|
73
|
+
}
|
|
74
|
+
function extractAddableRelatorTerms(fromField, toField) {
|
|
75
|
+
const relatorTermSubfieldCode = fieldToRelatorTermSubfieldCode(fromField);
|
|
76
|
+
const normalizedFromFieldRelatorTerms = getRelatorTermStrings(relatorTermSubfieldCode, fromField);
|
|
77
|
+
if (normalizedFromFieldRelatorTerms.length === 0) {
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
// Remove values that already exist:
|
|
81
|
+
const normalizedToFieldRelatorTerms = getRelatorTermStrings(relatorTermSubfieldCode, toField);
|
|
82
|
+
return normalizedFromFieldRelatorTerms.filter(str => !normalizedToFieldRelatorTerms.includes(str));
|
|
83
|
+
}
|
|
84
|
+
function copyRelatorSubfields(fromField, toField) {
|
|
85
|
+
const relatorTermSubfieldCode = fieldToRelatorTermSubfieldCode(fromField);
|
|
86
|
+
const newRelatorTerms = extractAddableRelatorTerms(fromField, toField);
|
|
87
|
+
newRelatorTerms.forEach(term => toField.subfields.push({
|
|
88
|
+
code: relatorTermSubfieldCode,
|
|
89
|
+
value: term
|
|
90
|
+
})); // eslint-disable-line functional/immutable-data
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function mergeRelatorTermFields(record, fix = false) {
|
|
94
|
+
/* eslint-disable */
|
|
95
|
+
// NV: 111/711, 751 and 752 where so rare that I did not add them here
|
|
96
|
+
let fields = record.get('(?:[17][01]0|720)');
|
|
97
|
+
let result = [];
|
|
98
|
+
const comparisonFieldsAsString = fields.map(f => (0, _utils.fieldToString)(createNormalizedCloneWithoutRelatorTerms(f)));
|
|
99
|
+
(0, _utils.nvdebug)(`mergeRelatorTermFields(): ${fields.length} cand field(s) found`);
|
|
100
|
+
for (let i = 0; i < fields.length - 1; i++) {
|
|
101
|
+
let currField = fields[i];
|
|
102
|
+
if (currField.deleted) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
(0, _utils.nvdebug)(`RT: Trying to pair ${comparisonFieldsAsString[i]}/${i}`);
|
|
106
|
+
for (let j = i + 1; j < fields.length; j++) {
|
|
107
|
+
(0, _utils.nvdebug)(` Compare with ${comparisonFieldsAsString[j]}/${j}`);
|
|
108
|
+
let mergableField = fields[j];
|
|
109
|
+
// Skip 1/7 from 1XX/7XX for similarity check:
|
|
110
|
+
if (comparisonFieldsAsString[i].substring(1) !== comparisonFieldsAsString[j].substring(1)) {
|
|
111
|
+
(0, _utils.nvdebug)(" NOT PAIR");
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (mergableField.deleted) {
|
|
115
|
+
(0, _utils.nvdebug)(" DELETED");
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
const str = `MERGE RELATOR TERM FIELD: ${(0, _utils.fieldToString)(mergableField)}`;
|
|
119
|
+
(0, _utils.nvdebug)(str);
|
|
120
|
+
if (!result.includes(str)) {
|
|
121
|
+
result.push(str);
|
|
122
|
+
}
|
|
123
|
+
if (fix) {
|
|
124
|
+
mergableField.deleted = 1;
|
|
125
|
+
copyRelatorSubfields(mergableField, currField);
|
|
126
|
+
(0, _punctuation.fieldFixPunctuation)(currField);
|
|
127
|
+
(0, _sortSubfields.sortAdjacentSubfields)(currField); // Put the added $e subfield to proper places.
|
|
128
|
+
(0, _sortRelatorTerms.sortAdjacentESubfields)(currField); // Sort $e subfields with each other
|
|
129
|
+
(0, _punctuation.fieldFixPunctuation)(currField);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (!fix) {
|
|
134
|
+
fields.forEach(f => delete f.deleted);
|
|
135
|
+
}
|
|
136
|
+
record.fields = record.fields.filter(f => !f.deleted);
|
|
137
|
+
/* eslint-enable */
|
|
138
|
+
return result;
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=mergeRelatorTermFields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mergeRelatorTermFields.js","names":["_clone","_interopRequireDefault","require","_punctuation","_utils","_sortSubfields","_sortRelatorTerms","obj","__esModule","default","_default","description","validate","fix","record","msg","mergeRelatorTermFields","res","message","valid","length","createNormalizedClone","field","clonedField","clone","fieldStripPunctuation","createNormalizedCloneWithoutRelatorTerms","subfields","filter","sf","code","fieldToRelatorTermSubfieldCode","includes","tag","getRelatorTermStrings","relatorTermSubfieldCode","map","value","extractAddableRelatorTerms","fromField","toField","normalizedFromFieldRelatorTerms","normalizedToFieldRelatorTerms","str","copyRelatorSubfields","newRelatorTerms","forEach","term","push","fields","get","result","comparisonFieldsAsString","f","fieldToString","nvdebug","i","currField","deleted","j","mergableField","substring","fieldFixPunctuation","sortAdjacentSubfields","sortAdjacentESubfields"],"sources":["../src/mergeRelatorTermFields.js"],"sourcesContent":["// Merge author/agent fields\n//\n// Rationale: Same author can appear in one 1XX and multiple 7XX fields having only different $e subfields.\n// These fields can be merged (and $e-subfields can then be sorted)...\n//\n// Author(s): Nicholas Volk\n\n\nimport clone from 'clone';\nimport {fieldFixPunctuation, fieldStripPunctuation} from './punctuation2';\nimport {fieldToString, nvdebug} from './utils';\nimport {sortAdjacentSubfields} from './sortSubfields';\nimport {sortAdjacentESubfields} from './sortRelatorTerms';\n//import createDebugLogger from 'debug';\n/*\n//const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:mergeRelatorTermFields');\n//const debugData = debug.extend('data');\n*/\n\nexport default function () {\n\n return {\n description: 'Merge author fields that only differ in $e relator terms',\n validate, fix\n };\n\n function fix(record) {\n const msg = mergeRelatorTermFields(record, true);\n const res = {message: msg, fix: msg, valid: true};\n return res;\n }\n\n function validate(record) {\n const msg = mergeRelatorTermFields(record, false);\n const res = {message: msg};\n\n res.valid = !(res.message.length >= 1); // eslint-disable-line functional/immutable-data\n return res;\n }\n}\n\nfunction createNormalizedClone(field) {\n const clonedField = clone(field);\n // Normalize\n fieldStripPunctuation(clonedField);\n return clonedField;\n}\n\nfunction createNormalizedCloneWithoutRelatorTerms(field) {\n const clonedField = createNormalizedClone(field);\n // Remove relator terms $e subfi:\n clonedField.subfields = clonedField.subfields.filter(sf => sf.code !== 'e'); // eslint-disable-line functional/immutable-data\n return clonedField;\n}\n\nfunction fieldToRelatorTermSubfieldCode(field) {\n if (['100', '110', '700', '710', '720', '751', '752'].includes(field.tag)) {\n return 'e';\n }\n if (field.tag === '111' || field.tag === '711') {\n return 'j';\n }\n return '?'; // No need to complain. Nothing is found.\n}\n\nfunction getRelatorTermStrings(relatorTermSubfieldCode, field) {\n return field.subfields.filter(sf => sf.code === relatorTermSubfieldCode).map(sf => sf.value);\n\n}\n\nfunction extractAddableRelatorTerms(fromField, toField) {\n const relatorTermSubfieldCode = fieldToRelatorTermSubfieldCode(fromField);\n const normalizedFromFieldRelatorTerms = getRelatorTermStrings(relatorTermSubfieldCode, fromField);\n if (normalizedFromFieldRelatorTerms.length === 0) {\n return [];\n }\n // Remove values that already exist:\n const normalizedToFieldRelatorTerms = getRelatorTermStrings(relatorTermSubfieldCode, toField);\n return normalizedFromFieldRelatorTerms.filter(str => !normalizedToFieldRelatorTerms.includes(str));\n}\n\n\nfunction copyRelatorSubfields(fromField, toField) {\n const relatorTermSubfieldCode = fieldToRelatorTermSubfieldCode(fromField);\n const newRelatorTerms = extractAddableRelatorTerms(fromField, toField);\n\n newRelatorTerms.forEach(term => toField.subfields.push({code: relatorTermSubfieldCode, value: term})); // eslint-disable-line functional/immutable-data\n\n}\n\nfunction mergeRelatorTermFields(record, fix = false) {\n /* eslint-disable */\n // NV: 111/711, 751 and 752 where so rare that I did not add them here\n let fields = record.get('(?:[17][01]0|720)'); \n let result = [];\n const comparisonFieldsAsString = fields.map(f => fieldToString(createNormalizedCloneWithoutRelatorTerms(f)));\n\n nvdebug(`mergeRelatorTermFields(): ${fields.length} cand field(s) found`);\n for(let i=0; i < fields.length-1; i++) {\n let currField = fields[i];\n if (currField.deleted) {\n continue;\n }\n nvdebug(`RT: Trying to pair ${comparisonFieldsAsString[i]}/${i}`);\n for (let j=i+1; j < fields.length; j++) {\n nvdebug(` Compare with ${comparisonFieldsAsString[j]}/${j}`);\n let mergableField = fields[j];\n // Skip 1/7 from 1XX/7XX for similarity check:\n if ( comparisonFieldsAsString[i].substring(1) !== comparisonFieldsAsString[j].substring(1)) {\n nvdebug(\" NOT PAIR\");\n continue;\n }\n if (mergableField.deleted) {\n nvdebug(\" DELETED\");\n continue;\n }\n const str = `MERGE RELATOR TERM FIELD: ${fieldToString(mergableField)}`;\n nvdebug(str);\n\n if(!result.includes(str)) {\n result.push(str)\n }\n\n if (fix) {\n mergableField.deleted = 1;\n copyRelatorSubfields(mergableField, currField);\n fieldFixPunctuation(currField);\n sortAdjacentSubfields(currField); // Put the added $e subfield to proper places.\n sortAdjacentESubfields(currField); // Sort $e subfields with each other\n fieldFixPunctuation(currField);\n\n }\n }\n }\n\n if(!fix) {\n fields.forEach(f => delete f.deleted);\n }\n\n record.fields = record.fields.filter(f => !f.deleted);\n /* eslint-enable */\n return result;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _chai = require("chai");
|
|
4
|
+
var _marcRecord = require("@natlibfi/marc-record");
|
|
5
|
+
var _mergeRelatorTermFields = _interopRequireDefault(require("./mergeRelatorTermFields"));
|
|
6
|
+
var _fixura = require("@natlibfi/fixura");
|
|
7
|
+
var _fixugen = _interopRequireDefault(require("@natlibfi/fixugen"));
|
|
8
|
+
var _debug = _interopRequireDefault(require("debug"));
|
|
9
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
10
|
+
(0, _fixugen.default)({
|
|
11
|
+
callback,
|
|
12
|
+
path: [__dirname, '..', 'test-fixtures', 'mergeRelatorTermFields'],
|
|
13
|
+
useMetadataFile: true,
|
|
14
|
+
recurse: true,
|
|
15
|
+
fixura: {
|
|
16
|
+
reader: _fixura.READERS.JSON
|
|
17
|
+
},
|
|
18
|
+
mocha: {
|
|
19
|
+
before: () => testValidatorFactory()
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
const debug = (0, _debug.default)('@natlibfi/marc-record-validators-melinda/mergeRelatorTermFields:test');
|
|
23
|
+
async function testValidatorFactory() {
|
|
24
|
+
const validator = await (0, _mergeRelatorTermFields.default)();
|
|
25
|
+
(0, _chai.expect)(validator).to.be.an('object').that.has.any.keys('description', 'validate');
|
|
26
|
+
(0, _chai.expect)(validator.description).to.be.a('string');
|
|
27
|
+
(0, _chai.expect)(validator.validate).to.be.a('function');
|
|
28
|
+
}
|
|
29
|
+
async function callback({
|
|
30
|
+
getFixture,
|
|
31
|
+
enabled = true,
|
|
32
|
+
fix = false
|
|
33
|
+
}) {
|
|
34
|
+
if (enabled === false) {
|
|
35
|
+
debug('TEST SKIPPED!');
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const validator = await (0, _mergeRelatorTermFields.default)();
|
|
39
|
+
const record = new _marcRecord.MarcRecord(getFixture('record.json'));
|
|
40
|
+
const expectedResult = getFixture('expectedResult.json');
|
|
41
|
+
// console.log(expectedResult); // eslint-disable-line
|
|
42
|
+
|
|
43
|
+
if (!fix) {
|
|
44
|
+
const result = await validator.validate(record);
|
|
45
|
+
(0, _chai.expect)(result).to.eql(expectedResult);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
await validator.fix(record);
|
|
49
|
+
(0, _chai.expect)(record).to.eql(expectedResult);
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=mergeRelatorTermFields.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mergeRelatorTermFields.spec.js","names":["_chai","require","_marcRecord","_mergeRelatorTermFields","_interopRequireDefault","_fixura","_fixugen","_debug","obj","__esModule","default","generateTests","callback","path","__dirname","useMetadataFile","recurse","fixura","reader","READERS","JSON","mocha","before","testValidatorFactory","debug","createDebugLogger","validator","validatorFactory","expect","to","be","an","that","has","any","keys","description","a","validate","getFixture","enabled","fix","record","MarcRecord","expectedResult","result","eql"],"sources":["../src/mergeRelatorTermFields.spec.js"],"sourcesContent":["import {expect} from 'chai';\nimport {MarcRecord} from '@natlibfi/marc-record';\nimport validatorFactory from './mergeRelatorTermFields';\nimport {READERS} from '@natlibfi/fixura';\nimport generateTests from '@natlibfi/fixugen';\nimport createDebugLogger from 'debug';\n\ngenerateTests({\n callback,\n path: [__dirname, '..', 'test-fixtures', 'mergeRelatorTermFields'],\n useMetadataFile: true,\n recurse: true,\n fixura: {\n reader: READERS.JSON\n },\n mocha: {\n before: () => testValidatorFactory()\n }\n});\nconst debug = createDebugLogger('@natlibfi/marc-record-validators-melinda/mergeRelatorTermFields:test');\n\nasync function testValidatorFactory() {\n const validator = await validatorFactory();\n\n expect(validator)\n .to.be.an('object')\n .that.has.any.keys('description', 'validate');\n\n expect(validator.description).to.be.a('string');\n expect(validator.validate).to.be.a('function');\n}\n\nasync function callback({getFixture, enabled = true, fix = false}) {\n if (enabled === false) {\n debug('TEST SKIPPED!');\n return;\n }\n\n const validator = await validatorFactory();\n const record = new MarcRecord(getFixture('record.json'));\n const expectedResult = getFixture('expectedResult.json');\n // console.log(expectedResult); // eslint-disable-line\n\n if (!fix) {\n const result = await validator.validate(record);\n expect(result).to.eql(expectedResult);\n return;\n }\n\n await validator.fix(record);\n expect(record).to.eql(expectedResult);\n}\n"],"mappings":";;AAAA,IAAAA,KAAA,GAAAC,OAAA;AACA,IAAAC,WAAA,GAAAD,OAAA;AACA,IAAAE,uBAAA,GAAAC,sBAAA,CAAAH,OAAA;AACA,IAAAI,OAAA,GAAAJ,OAAA;AACA,IAAAK,QAAA,GAAAF,sBAAA,CAAAH,OAAA;AACA,IAAAM,MAAA,GAAAH,sBAAA,CAAAH,OAAA;AAAsC,SAAAG,uBAAAI,GAAA,WAAAA,GAAA,IAAAA,GAAA,CAAAC,UAAA,GAAAD,GAAA,KAAAE,OAAA,EAAAF,GAAA;AAEtC,IAAAG,gBAAa,EAAC;EACZC,QAAQ;EACRC,IAAI,EAAE,CAACC,SAAS,EAAE,IAAI,EAAE,eAAe,EAAE,wBAAwB,CAAC;EAClEC,eAAe,EAAE,IAAI;EACrBC,OAAO,EAAE,IAAI;EACbC,MAAM,EAAE;IACNC,MAAM,EAAEC,eAAO,CAACC;EAClB,CAAC;EACDC,KAAK,EAAE;IACLC,MAAM,EAAEA,CAAA,KAAMC,oBAAoB,CAAC;EACrC;AACF,CAAC,CAAC;AACF,MAAMC,KAAK,GAAG,IAAAC,cAAiB,EAAC,sEAAsE,CAAC;AAEvG,eAAeF,oBAAoBA,CAAA,EAAG;EACpC,MAAMG,SAAS,GAAG,MAAM,IAAAC,+BAAgB,EAAC,CAAC;EAE1C,IAAAC,YAAM,EAACF,SAAS,CAAC,CACdG,EAAE,CAACC,EAAE,CAACC,EAAE,CAAC,QAAQ,CAAC,CAClBC,IAAI,CAACC,GAAG,CAACC,GAAG,CAACC,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC;EAE/C,IAAAP,YAAM,EAACF,SAAS,CAACU,WAAW,CAAC,CAACP,EAAE,CAACC,EAAE,CAACO,CAAC,CAAC,QAAQ,CAAC;EAC/C,IAAAT,YAAM,EAACF,SAAS,CAACY,QAAQ,CAAC,CAACT,EAAE,CAACC,EAAE,CAACO,CAAC,CAAC,UAAU,CAAC;AAChD;AAEA,eAAezB,QAAQA,CAAC;EAAC2B,UAAU;EAAEC,OAAO,GAAG,IAAI;EAAEC,GAAG,GAAG;AAAK,CAAC,EAAE;EACjE,IAAID,OAAO,KAAK,KAAK,EAAE;IACrBhB,KAAK,CAAC,eAAe,CAAC;IACtB;EACF;EAEA,MAAME,SAAS,GAAG,MAAM,IAAAC,+BAAgB,EAAC,CAAC;EAC1C,MAAMe,MAAM,GAAG,IAAIC,sBAAU,CAACJ,UAAU,CAAC,aAAa,CAAC,CAAC;EACxD,MAAMK,cAAc,GAAGL,UAAU,CAAC,qBAAqB,CAAC;EACxD;;EAEA,IAAI,CAACE,GAAG,EAAE;IACR,MAAMI,MAAM,GAAG,MAAMnB,SAAS,CAACY,QAAQ,CAACI,MAAM,CAAC;IAC/C,IAAAd,YAAM,EAACiB,MAAM,CAAC,CAAChB,EAAE,CAACiB,GAAG,CAACF,cAAc,CAAC;IACrC;EACF;EAEA,MAAMlB,SAAS,CAACe,GAAG,CAACC,MAAM,CAAC;EAC3B,IAAAd,YAAM,EAACc,MAAM,CAAC,CAACb,EAAE,CAACiB,GAAG,CAACF,cAAc,CAAC;AACvC"}
|
package/dist/sortRelatorTerms.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sortRelatorTerms.js","names":["_clone","_interopRequireDefault","require","_utils","_punctuation","obj","__esModule","default","WORST_WORK","relatorTermValues","scoreRelatorTerm","term","normalizedTerm","normalizeValue","_default","description","validate","fix","record","res","message","valid","fields","forEach","field","sortAdjacentESubfields","clonedField","clone","clonedFieldAsString","fieldToString","fieldAsString","push","length","value","replace","swapESubfields","subfields","loopAgain","some","sf","index","code","currScore","prevSubfield","prevScore","tmp","fieldFixPunctuation"],"sources":["../src/sortRelatorTerms.js"],"sourcesContent":["// Validator/fixer for sorting $e relator term subfields\n//\n// Author(s): Nicholas Volk\n\nimport clone from 'clone';\n//import createDebugLogger from 'debug';\nimport {fieldToString} from './utils';\nimport {fieldFixPunctuation} from './punctuation2';\n//const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:sortRelatorTerms');\n//const debugData = debug.extend('data');\n\nconst WORST_WORK = 98;\n\nconst relatorTermValues = { // The higher, the better\n // More abstract, the earlier it appears.\n // Note that terms with same abstraction level might also have order preferences\n // work/teos > expression/ekspressio > manifestation/manifestaatio\n 'säveltäjä': 100,\n 'kirjoittaja': 99, // Viola wants composer/säveltäjä on top (highly unlikely to ever appear together, but...)\n 'taiteilija': 98,\n 'sanoittaja': 90,\n // ekspressio\n 'sovittaja': 80,\n 'toimittaja': 80,\n 'kuvittaja': 75,\n 'editointi': 71,\n 'kääntäjä': 70,\n 'lukija': 61,\n // manifestaatio\n 'esittäjä': 60,\n 'johtaja': 50\n};\n\nfunction scoreRelatorTerm(term) {\n const normalizedTerm = normalizeValue(term);\n if (normalizedTerm in relatorTermValues) {\n return relatorTermValues[normalizedTerm];\n }\n return 0;\n}\n\nexport default function () {\n\n return {\n description: 'Sort adjacent $e subfields in field [1678][01]0',\n validate, fix\n };\n\n function fix(record) {\n const res = {message: [], fix: [], valid: true};\n\n record.fields.forEach(field => {\n sortAdjacentESubfields(field);\n });\n\n return res;\n }\n\n function validate(record) {\n const res = {message: []};\n\n record.fields.forEach(field => {\n const clonedField = clone(field);\n sortAdjacentESubfields(clonedField);\n const clonedFieldAsString = fieldToString(clonedField);\n const fieldAsString = fieldToString(field);\n if (fieldAsString !== clonedFieldAsString) { // eslint-disable-line functional/no-conditional-statements\n res.message.push(`${fieldAsString} => ${clonedFieldAsString}`); // eslint-disable-line functional/immutable-data\n }\n });\n\n res.valid = !(res.message.length >= 1); // eslint-disable-line functional/immutable-data\n return res;\n }\n}\n\n\nfunction normalizeValue(value) {\n // Removing last punc char is good enough for our purposes.\n // We don't handle abbreviations here etc.\n // Brackets should not happen either, should they?\n return value.replace(/[.,]$/u, '');\n}\n\n\nfunction swapESubfields(field) {\n if (!field.subfields) {\n return;\n }\n\n const loopAgain = field.subfields.some((sf, index) => {\n if (index === 0 || sf.code !== 'e') {\n return false;\n }\n const currScore = scoreRelatorTerm(sf.value);\n\n const prevSubfield = field.subfields[index - 1];\n if (currScore === 0 || prevSubfield.code !== 'e') {\n return false;\n }\n const prevScore = scoreRelatorTerm(prevSubfield.value);\n\n\n // If this subfield maps to a Work, then subfields can be swapped, even if we don't have a score for the prev subfield!\n if (prevScore === 0 && currScore < WORST_WORK) {\n return false;\n }\n\n if (currScore > prevScore) {\n // Swap:\n const tmp = field.subfields[index - 1];\n field.subfields[index - 1] = sf; // eslint-disable-line functional/immutable-data\n field.subfields[index] = tmp; // eslint-disable-line functional/immutable-data\n fieldFixPunctuation(field);\n return true;\n }\n\n return false;\n\n });\n\n if (loopAgain) {\n swapESubfields(field); // uh, evil recursion...\n return;\n }\n\n return;\n\n}\n\nexport function sortAdjacentESubfields(field) {\n if (!field.subfields) {\n return field;\n }\n swapESubfields(field);\n\n return field;\n}\n\n"],"mappings":";;;;;;;AAIA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AAEA,IAAAC,MAAA,GAAAD,OAAA;AACA,IAAAE,YAAA,GAAAF,OAAA;AAAmD,SAAAD,uBAAAI,GAAA,WAAAA,GAAA,IAAAA,GAAA,CAAAC,UAAA,GAAAD,GAAA,KAAAE,OAAA,EAAAF,GAAA;AAPnD;AACA;AACA;;AAGA;;AAGA;AACA;AAEA,MAAMG,UAAU,GAAG,EAAE;AAErB,MAAMC,iBAAiB,GAAG;EAAE;EAC1B;EACA;EACA;EACA,WAAW,EAAE,GAAG;EAChB,aAAa,EAAE,EAAE;EAAE;EACnB,YAAY,EAAE,EAAE;EAChB,YAAY,EAAE,EAAE;EAChB;EACA,WAAW,EAAE,EAAE;EACf,YAAY,EAAE,EAAE;EAChB,WAAW,EAAE,EAAE;EACf,WAAW,EAAE,EAAE;EACf,UAAU,EAAE,EAAE;EACd,QAAQ,EAAE,EAAE;EACZ;EACA,UAAU,EAAE,EAAE;EACd,SAAS,EAAE;
|
|
1
|
+
{"version":3,"file":"sortRelatorTerms.js","names":["_clone","_interopRequireDefault","require","_utils","_punctuation","obj","__esModule","default","WORST_WORK","relatorTermValues","scoreRelatorTerm","term","normalizedTerm","normalizeValue","_default","description","validate","fix","record","res","message","valid","fields","forEach","field","sortAdjacentESubfields","clonedField","clone","clonedFieldAsString","fieldToString","fieldAsString","push","length","value","replace","swapESubfields","subfields","loopAgain","some","sf","index","code","currScore","prevSubfield","prevScore","tmp","fieldFixPunctuation"],"sources":["../src/sortRelatorTerms.js"],"sourcesContent":["// Validator/fixer for sorting $e relator term subfields\n//\n// Author(s): Nicholas Volk\n\nimport clone from 'clone';\n//import createDebugLogger from 'debug';\nimport {fieldToString} from './utils';\nimport {fieldFixPunctuation} from './punctuation2';\n//const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:sortRelatorTerms');\n//const debugData = debug.extend('data');\n\nconst WORST_WORK = 98;\n\nconst relatorTermValues = { // The higher, the better\n // More abstract, the earlier it appears.\n // Note that terms with same abstraction level might also have order preferences\n // work/teos > expression/ekspressio > manifestation/manifestaatio\n 'säveltäjä': 100,\n 'kirjoittaja': 99, // Viola wants composer/säveltäjä on top (highly unlikely to ever appear together, but...)\n 'taiteilija': 98,\n 'sanoittaja': 90,\n // ekspressio\n 'sovittaja': 80,\n 'toimittaja': 80,\n 'kuvittaja': 75,\n 'editointi': 71,\n 'kääntäjä': 70,\n 'lukija': 61,\n // manifestaatio\n 'esittäjä': 60,\n 'johtaja': 50,\n 'kustantaja': 41,\n 'julkaisija': 40\n\n};\n\nfunction scoreRelatorTerm(term) {\n const normalizedTerm = normalizeValue(term);\n if (normalizedTerm in relatorTermValues) {\n return relatorTermValues[normalizedTerm];\n }\n return 0;\n}\n\nexport default function () {\n\n return {\n description: 'Sort adjacent $e subfields in field [1678][01]0',\n validate, fix\n };\n\n function fix(record) {\n const res = {message: [], fix: [], valid: true};\n\n record.fields.forEach(field => {\n sortAdjacentESubfields(field);\n });\n\n return res;\n }\n\n function validate(record) {\n const res = {message: []};\n\n record.fields.forEach(field => {\n const clonedField = clone(field);\n sortAdjacentESubfields(clonedField);\n const clonedFieldAsString = fieldToString(clonedField);\n const fieldAsString = fieldToString(field);\n if (fieldAsString !== clonedFieldAsString) { // eslint-disable-line functional/no-conditional-statements\n res.message.push(`${fieldAsString} => ${clonedFieldAsString}`); // eslint-disable-line functional/immutable-data\n }\n });\n\n res.valid = !(res.message.length >= 1); // eslint-disable-line functional/immutable-data\n return res;\n }\n}\n\n\nfunction normalizeValue(value) {\n // Removing last punc char is good enough for our purposes.\n // We don't handle abbreviations here etc.\n // Brackets should not happen either, should they?\n return value.replace(/[.,]$/u, '');\n}\n\n\nfunction swapESubfields(field) {\n if (!field.subfields) {\n return;\n }\n\n const loopAgain = field.subfields.some((sf, index) => {\n if (index === 0 || sf.code !== 'e') {\n return false;\n }\n const currScore = scoreRelatorTerm(sf.value);\n\n const prevSubfield = field.subfields[index - 1];\n if (currScore === 0 || prevSubfield.code !== 'e') {\n return false;\n }\n const prevScore = scoreRelatorTerm(prevSubfield.value);\n\n\n // If this subfield maps to a Work, then subfields can be swapped, even if we don't have a score for the prev subfield!\n if (prevScore === 0 && currScore < WORST_WORK) {\n return false;\n }\n\n if (currScore > prevScore) {\n // Swap:\n const tmp = field.subfields[index - 1];\n field.subfields[index - 1] = sf; // eslint-disable-line functional/immutable-data\n field.subfields[index] = tmp; // eslint-disable-line functional/immutable-data\n fieldFixPunctuation(field);\n return true;\n }\n\n return false;\n\n });\n\n if (loopAgain) {\n swapESubfields(field); // uh, evil recursion...\n return;\n }\n\n return;\n\n}\n\nexport function sortAdjacentESubfields(field) {\n if (!field.subfields) {\n return field;\n }\n swapESubfields(field);\n\n return field;\n}\n\n"],"mappings":"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"}
|
package/dist/update-field-540.js
CHANGED
|
@@ -54,8 +54,14 @@ const licences = [{
|
|
|
54
54
|
}, {
|
|
55
55
|
'license': 'CC BY-ND 4.0',
|
|
56
56
|
'url': 'https://creativecommons.org/licenses/by-nd/4.0/deed.fi'
|
|
57
|
+
}, {
|
|
58
|
+
'license': 'CC BY-SA 4.0',
|
|
59
|
+
'url': 'https://creativecommons.org/licenses/by-sa/4.0/deed.fi'
|
|
60
|
+
}, {
|
|
61
|
+
'license': 'CC0 1.0',
|
|
62
|
+
'url': 'https://creativecommons.org/publicdomain/zero/1.0/deed.fi'
|
|
57
63
|
},
|
|
58
|
-
//
|
|
64
|
+
// not seen/unused
|
|
59
65
|
{
|
|
60
66
|
'license': 'Public domain',
|
|
61
67
|
'url': 'https://creativecommons.org/publicdomain/mark/1.0/deed.fi'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update-field-540.js","names":["_utils","require","_default","description","validate","fix","record","fixedFields","getFieldsThatUseOldFormat","fixedFieldsAsStrings","map","f","fieldToString","message","valid","yeOldeFields","length","messages","licences","findSubfieldIndex","field","subfield","nvtmp","index","subfields","findIndex","sf","validLicenseInSubfieldC","subfieldC","license","code","value","validUrlInSubfieldU","subfieldU","url","fixC","splice","fieldHasOldCcLicense","tag","validLicense","find","some","subfieldsC","filter","forEach","c","fields"],"sources":["../src/update-field-540.js"],"sourcesContent":["//import createDebugLogger from 'debug';\nimport {fieldToString} from './utils';\n\n//const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda/update-field-540');\n\n// Author(s): Nicholas Volk\nexport default function () {\n\n return {\n description: 'Validator for field 540 (modernization as per MELKEHITYS-2431)',\n validate, fix\n };\n\n function fix(record) {\n const fixedFields = getFieldsThatUseOldFormat(record, true);\n\n const fixedFieldsAsStrings = fixedFields.map(f => fieldToString(f));\n\n return {message: [], fix: fixedFieldsAsStrings, valid: true};\n }\n\n function validate(record) {\n const yeOldeFields = getFieldsThatUseOldFormat(record, false);\n if (yeOldeFields.length === 0) {\n return {'message': [], 'valid': true};\n }\n const messages = yeOldeFields.map(f => fieldToString(f));\n\n return {'message': messages, 'valid': false};\n }\n\n}\n\n\nconst licences = [\n {'license': 'CC BY 4.0', 'url': 'https://creativecommons.org/licenses/by/4.0/deed.fi'},\n {'license': 'CC BY-NC 4.0', 'url': 'https://creativecommons.org/licenses/by-nc/4.0/deed.fi'},\n {'license': 'CC BY-NC-ND 4.0', 'url': 'https://creativecommons.org/licenses/by-nc-nd/4.0/deed.fi'},\n {'license': 'CC BY-NC-SA 4.0', 'url': 'https://creativecommons.org/licenses/by-nc-sa/4.0/deed.fi'},\n {'license': 'CC BY-ND 4.0', 'url': 'https://creativecommons.org/licenses/by-nd/4.0/deed.fi'},\n
|
|
1
|
+
{"version":3,"file":"update-field-540.js","names":["_utils","require","_default","description","validate","fix","record","fixedFields","getFieldsThatUseOldFormat","fixedFieldsAsStrings","map","f","fieldToString","message","valid","yeOldeFields","length","messages","licences","findSubfieldIndex","field","subfield","nvtmp","index","subfields","findIndex","sf","validLicenseInSubfieldC","subfieldC","license","code","value","validUrlInSubfieldU","subfieldU","url","fixC","splice","fieldHasOldCcLicense","tag","validLicense","find","some","subfieldsC","filter","forEach","c","fields"],"sources":["../src/update-field-540.js"],"sourcesContent":["//import createDebugLogger from 'debug';\nimport {fieldToString} from './utils';\n\n//const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda/update-field-540');\n\n// Author(s): Nicholas Volk\nexport default function () {\n\n return {\n description: 'Validator for field 540 (modernization as per MELKEHITYS-2431)',\n validate, fix\n };\n\n function fix(record) {\n const fixedFields = getFieldsThatUseOldFormat(record, true);\n\n const fixedFieldsAsStrings = fixedFields.map(f => fieldToString(f));\n\n return {message: [], fix: fixedFieldsAsStrings, valid: true};\n }\n\n function validate(record) {\n const yeOldeFields = getFieldsThatUseOldFormat(record, false);\n if (yeOldeFields.length === 0) {\n return {'message': [], 'valid': true};\n }\n const messages = yeOldeFields.map(f => fieldToString(f));\n\n return {'message': messages, 'valid': false};\n }\n\n}\n\n\nconst licences = [\n {'license': 'CC BY 4.0', 'url': 'https://creativecommons.org/licenses/by/4.0/deed.fi'},\n {'license': 'CC BY-NC 4.0', 'url': 'https://creativecommons.org/licenses/by-nc/4.0/deed.fi'},\n {'license': 'CC BY-NC-ND 4.0', 'url': 'https://creativecommons.org/licenses/by-nc-nd/4.0/deed.fi'},\n {'license': 'CC BY-NC-SA 4.0', 'url': 'https://creativecommons.org/licenses/by-nc-sa/4.0/deed.fi'},\n {'license': 'CC BY-ND 4.0', 'url': 'https://creativecommons.org/licenses/by-nd/4.0/deed.fi'},\n {'license': 'CC BY-SA 4.0', 'url': 'https://creativecommons.org/licenses/by-sa/4.0/deed.fi'},\n {'license': 'CC0 1.0', 'url': 'https://creativecommons.org/publicdomain/zero/1.0/deed.fi'}, // not seen/unused\n {'license': 'Public domain', 'url': 'https://creativecommons.org/publicdomain/mark/1.0/deed.fi'}\n];\n\nfunction findSubfieldIndex(field, subfield) {\n subfield.nvtmp = 1; // eslint-disable-line functional/immutable-data\n const index = field.subfields.findIndex(sf => sf.nvtmp === 1);\n delete subfield.nvtmp; // eslint-disable-line functional/immutable-data\n return index;\n}\n\nfunction validLicenseInSubfieldC(subfieldC, license) {\n if (subfieldC.code !== 'c') {\n return false;\n }\n //nvdebug(`Compare ${subfieldC.value} vs ${license.license}`);\n return license.license === subfieldC.value;\n}\n\nfunction validUrlInSubfieldU(subfieldU, license) {\n if (subfieldU.code !== 'u') {\n return false;\n }\n //nvdebug(`Compare ${subfieldU.value} vs ${license.url}`);\n return license.url === subfieldU.value;\n}\n\n\nfunction fixC(field, subfieldC) {\n // MELINDA-2431_\n subfieldC.code = 'f'; // eslint-disable-line functional/immutable-data\n const index = findSubfieldIndex(field, subfieldC);\n field.subfields.splice(index + 1, 0, {'code': '2', 'value': 'cc'}); // eslint-disable-line functional/immutable-data\n}\n\nfunction fieldHasOldCcLicense(field, fix) {\n if (field.tag !== '540') {\n return false;\n }\n //nvdebug(`NORM 540: ${fieldToString(field)}`);\n const validLicense = licences.find(license => field.subfields.some(sf => validLicenseInSubfieldC(sf, license)) && field.subfields.some(sf => validUrlInSubfieldU(sf, license)));\n if (!validLicense) {\n return false;\n }\n //nvdebug(` Found valid license`);\n if (fix) { // eslint-disable-line functional/no-conditional-statements\n const subfieldsC = field.subfields.filter(sf => validLicenseInSubfieldC(sf, validLicense));\n subfieldsC.forEach(c => fixC(field, c));\n }\n\n return true;\n}\n\n\nfunction getFieldsThatUseOldFormat(record, fix) {\n return record.fields.filter(f => fieldHasOldCcLicense(f, fix));\n}\n\n"],"mappings":"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"}
|
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.
|
|
17
|
+
"version": "10.8.0-alpha.1",
|
|
18
18
|
"main": "./dist/index.js",
|
|
19
19
|
"publishConfig": {
|
|
20
20
|
"access": "public"
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"chai": "^4.3.7",
|
|
64
64
|
"chai-as-promised": "^7.1.1",
|
|
65
65
|
"cross-env": "^7.0.3",
|
|
66
|
-
"eslint": "^8.
|
|
66
|
+
"eslint": "^8.41.0",
|
|
67
67
|
"fetch-mock": "^9.11.0",
|
|
68
68
|
"mocha": "^10.2.0",
|
|
69
69
|
"nyc": "^15.1.0"
|
package/src/index.js
CHANGED
|
@@ -22,6 +22,7 @@ import UpdateField540 from './update-field-540';
|
|
|
22
22
|
import SortSubfields from './sortSubfields';
|
|
23
23
|
import SortTags from './sort-tags';
|
|
24
24
|
import SubfieldExclusion from './subfield-exclusion';
|
|
25
|
+
import TypeOfDateF008 from './typeOfDate-008';
|
|
25
26
|
import UnicodeDecomposition from './unicode-decomposition';
|
|
26
27
|
import Urn from './urn';
|
|
27
28
|
|
|
@@ -49,6 +50,7 @@ export {
|
|
|
49
50
|
SortSubfields,
|
|
50
51
|
SortTags,
|
|
51
52
|
SubfieldExclusion,
|
|
53
|
+
TypeOfDateF008,
|
|
52
54
|
UnicodeDecomposition,
|
|
53
55
|
UpdateField540,
|
|
54
56
|
Urn
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
// Merge author/agent fields
|
|
2
|
+
//
|
|
3
|
+
// Rationale: Same author can appear in one 1XX and multiple 7XX fields having only different $e subfields.
|
|
4
|
+
// These fields can be merged (and $e-subfields can then be sorted)...
|
|
5
|
+
//
|
|
6
|
+
// Author(s): Nicholas Volk
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
import clone from 'clone';
|
|
10
|
+
import {fieldFixPunctuation, fieldStripPunctuation} from './punctuation2';
|
|
11
|
+
import {fieldToString, nvdebug} from './utils';
|
|
12
|
+
import {sortAdjacentSubfields} from './sortSubfields';
|
|
13
|
+
import {sortAdjacentESubfields} from './sortRelatorTerms';
|
|
14
|
+
//import createDebugLogger from 'debug';
|
|
15
|
+
/*
|
|
16
|
+
//const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:mergeRelatorTermFields');
|
|
17
|
+
//const debugData = debug.extend('data');
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
export default function () {
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
description: 'Merge author fields that only differ in $e relator terms',
|
|
24
|
+
validate, fix
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
function fix(record) {
|
|
28
|
+
const msg = mergeRelatorTermFields(record, true);
|
|
29
|
+
const res = {message: msg, fix: msg, valid: true};
|
|
30
|
+
return res;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function validate(record) {
|
|
34
|
+
const msg = mergeRelatorTermFields(record, false);
|
|
35
|
+
const res = {message: msg};
|
|
36
|
+
|
|
37
|
+
res.valid = !(res.message.length >= 1); // eslint-disable-line functional/immutable-data
|
|
38
|
+
return res;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function createNormalizedClone(field) {
|
|
43
|
+
const clonedField = clone(field);
|
|
44
|
+
// Normalize
|
|
45
|
+
fieldStripPunctuation(clonedField);
|
|
46
|
+
return clonedField;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function createNormalizedCloneWithoutRelatorTerms(field) {
|
|
50
|
+
const clonedField = createNormalizedClone(field);
|
|
51
|
+
// Remove relator terms $e subfi:
|
|
52
|
+
clonedField.subfields = clonedField.subfields.filter(sf => sf.code !== 'e'); // eslint-disable-line functional/immutable-data
|
|
53
|
+
return clonedField;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function fieldToRelatorTermSubfieldCode(field) {
|
|
57
|
+
if (['100', '110', '700', '710', '720', '751', '752'].includes(field.tag)) {
|
|
58
|
+
return 'e';
|
|
59
|
+
}
|
|
60
|
+
if (field.tag === '111' || field.tag === '711') {
|
|
61
|
+
return 'j';
|
|
62
|
+
}
|
|
63
|
+
return '?'; // No need to complain. Nothing is found.
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function getRelatorTermStrings(relatorTermSubfieldCode, field) {
|
|
67
|
+
return field.subfields.filter(sf => sf.code === relatorTermSubfieldCode).map(sf => sf.value);
|
|
68
|
+
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function extractAddableRelatorTerms(fromField, toField) {
|
|
72
|
+
const relatorTermSubfieldCode = fieldToRelatorTermSubfieldCode(fromField);
|
|
73
|
+
const normalizedFromFieldRelatorTerms = getRelatorTermStrings(relatorTermSubfieldCode, fromField);
|
|
74
|
+
if (normalizedFromFieldRelatorTerms.length === 0) {
|
|
75
|
+
return [];
|
|
76
|
+
}
|
|
77
|
+
// Remove values that already exist:
|
|
78
|
+
const normalizedToFieldRelatorTerms = getRelatorTermStrings(relatorTermSubfieldCode, toField);
|
|
79
|
+
return normalizedFromFieldRelatorTerms.filter(str => !normalizedToFieldRelatorTerms.includes(str));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
function copyRelatorSubfields(fromField, toField) {
|
|
84
|
+
const relatorTermSubfieldCode = fieldToRelatorTermSubfieldCode(fromField);
|
|
85
|
+
const newRelatorTerms = extractAddableRelatorTerms(fromField, toField);
|
|
86
|
+
|
|
87
|
+
newRelatorTerms.forEach(term => toField.subfields.push({code: relatorTermSubfieldCode, value: term})); // eslint-disable-line functional/immutable-data
|
|
88
|
+
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function mergeRelatorTermFields(record, fix = false) {
|
|
92
|
+
/* eslint-disable */
|
|
93
|
+
// NV: 111/711, 751 and 752 where so rare that I did not add them here
|
|
94
|
+
let fields = record.get('(?:[17][01]0|720)');
|
|
95
|
+
let result = [];
|
|
96
|
+
const comparisonFieldsAsString = fields.map(f => fieldToString(createNormalizedCloneWithoutRelatorTerms(f)));
|
|
97
|
+
|
|
98
|
+
nvdebug(`mergeRelatorTermFields(): ${fields.length} cand field(s) found`);
|
|
99
|
+
for(let i=0; i < fields.length-1; i++) {
|
|
100
|
+
let currField = fields[i];
|
|
101
|
+
if (currField.deleted) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
nvdebug(`RT: Trying to pair ${comparisonFieldsAsString[i]}/${i}`);
|
|
105
|
+
for (let j=i+1; j < fields.length; j++) {
|
|
106
|
+
nvdebug(` Compare with ${comparisonFieldsAsString[j]}/${j}`);
|
|
107
|
+
let mergableField = fields[j];
|
|
108
|
+
// Skip 1/7 from 1XX/7XX for similarity check:
|
|
109
|
+
if ( comparisonFieldsAsString[i].substring(1) !== comparisonFieldsAsString[j].substring(1)) {
|
|
110
|
+
nvdebug(" NOT PAIR");
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (mergableField.deleted) {
|
|
114
|
+
nvdebug(" DELETED");
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
const str = `MERGE RELATOR TERM FIELD: ${fieldToString(mergableField)}`;
|
|
118
|
+
nvdebug(str);
|
|
119
|
+
|
|
120
|
+
if(!result.includes(str)) {
|
|
121
|
+
result.push(str)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (fix) {
|
|
125
|
+
mergableField.deleted = 1;
|
|
126
|
+
copyRelatorSubfields(mergableField, currField);
|
|
127
|
+
fieldFixPunctuation(currField);
|
|
128
|
+
sortAdjacentSubfields(currField); // Put the added $e subfield to proper places.
|
|
129
|
+
sortAdjacentESubfields(currField); // Sort $e subfields with each other
|
|
130
|
+
fieldFixPunctuation(currField);
|
|
131
|
+
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if(!fix) {
|
|
137
|
+
fields.forEach(f => delete f.deleted);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
record.fields = record.fields.filter(f => !f.deleted);
|
|
141
|
+
/* eslint-enable */
|
|
142
|
+
return result;
|
|
143
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import {expect} from 'chai';
|
|
2
|
+
import {MarcRecord} from '@natlibfi/marc-record';
|
|
3
|
+
import validatorFactory from './mergeRelatorTermFields';
|
|
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', 'mergeRelatorTermFields'],
|
|
11
|
+
useMetadataFile: true,
|
|
12
|
+
recurse: true,
|
|
13
|
+
fixura: {
|
|
14
|
+
reader: READERS.JSON
|
|
15
|
+
},
|
|
16
|
+
mocha: {
|
|
17
|
+
before: () => testValidatorFactory()
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda/mergeRelatorTermFields: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/sortRelatorTerms.js
CHANGED
package/src/update-field-540.js
CHANGED
|
@@ -38,7 +38,8 @@ const licences = [
|
|
|
38
38
|
{'license': 'CC BY-NC-ND 4.0', 'url': 'https://creativecommons.org/licenses/by-nc-nd/4.0/deed.fi'},
|
|
39
39
|
{'license': 'CC BY-NC-SA 4.0', 'url': 'https://creativecommons.org/licenses/by-nc-sa/4.0/deed.fi'},
|
|
40
40
|
{'license': 'CC BY-ND 4.0', 'url': 'https://creativecommons.org/licenses/by-nd/4.0/deed.fi'},
|
|
41
|
-
|
|
41
|
+
{'license': 'CC BY-SA 4.0', 'url': 'https://creativecommons.org/licenses/by-sa/4.0/deed.fi'},
|
|
42
|
+
{'license': 'CC0 1.0', 'url': 'https://creativecommons.org/publicdomain/zero/1.0/deed.fi'}, // not seen/unused
|
|
42
43
|
{'license': 'Public domain', 'url': 'https://creativecommons.org/publicdomain/mark/1.0/deed.fi'}
|
|
43
44
|
];
|
|
44
45
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_validationOptions": {},
|
|
3
|
+
"fields": [
|
|
4
|
+
{ "tag": "005", "value": "20220202020202.0" },
|
|
5
|
+
{ "tag": "100", "ind1": "1", "ind2": " ", "subfields": [
|
|
6
|
+
{ "code": "a", "value": "Sukunimi, Etunimi," },
|
|
7
|
+
{ "code": "e", "value": "kirjoittaja," },
|
|
8
|
+
{ "code": "e", "value": "kuvittaja," },
|
|
9
|
+
{ "code": "e", "value": "valokuvaaja." }
|
|
10
|
+
|
|
11
|
+
]}
|
|
12
|
+
],
|
|
13
|
+
"leader": ""
|
|
14
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"fields": [
|
|
3
|
+
{ "tag": "005", "value": "20220202020202.0" },
|
|
4
|
+
{ "tag": "100", "ind1": "1", "ind2": " ", "subfields": [
|
|
5
|
+
{ "code": "a", "value": "Sukunimi, Etunimi," },
|
|
6
|
+
{ "code": "e", "value": "kuvittaja." }
|
|
7
|
+
]},
|
|
8
|
+
{ "tag": "700", "ind1": "1", "ind2": " ", "subfields": [
|
|
9
|
+
{ "code": "a", "value": "Sukunimi, Etunimi," },
|
|
10
|
+
{ "code": "e", "value": "kirjoittaja," },
|
|
11
|
+
{ "code": "e", "value": "valokuvaaja." }
|
|
12
|
+
]}
|
|
13
|
+
],
|
|
14
|
+
|
|
15
|
+
"leader": ""
|
|
16
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_validationOptions": {},
|
|
3
|
+
"fields": [
|
|
4
|
+
{ "tag": "005", "value": "20220202020202.0" },
|
|
5
|
+
{ "tag": "700", "ind1": "1", "ind2": " ", "subfields": [
|
|
6
|
+
{ "code": "a", "value": "Sukunimi, Etunimi," },
|
|
7
|
+
{ "code": "e", "value": "kirjoittaja," },
|
|
8
|
+
{ "code": "e", "value": "kuvittaja." }
|
|
9
|
+
]},
|
|
10
|
+
{ "tag": "700", "ind1": "1", "ind2": " ", "subfields": [
|
|
11
|
+
{ "code": "a", "value": "Sukunimi2, Etunimi," },
|
|
12
|
+
{ "code": "e", "value": "kirjoittaja," },
|
|
13
|
+
{ "code": "e", "value": "kuvittaja." }
|
|
14
|
+
]}
|
|
15
|
+
],
|
|
16
|
+
"leader": ""
|
|
17
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"fields": [
|
|
3
|
+
{ "tag": "005", "value": "20220202020202.0" },
|
|
4
|
+
{ "tag": "700", "ind1": "1", "ind2": " ", "subfields": [
|
|
5
|
+
{ "code": "a", "value": "Sukunimi, Etunimi." }
|
|
6
|
+
]},
|
|
7
|
+
{ "tag": "700", "ind1": "1", "ind2": " ", "subfields": [
|
|
8
|
+
{ "code": "a", "value": "Sukunimi, Etunimi," },
|
|
9
|
+
{ "code": "e", "value": "kuvittaja," },
|
|
10
|
+
{ "code": "e", "value": "kirjoittaja." }
|
|
11
|
+
]},
|
|
12
|
+
{ "tag": "700", "ind1": "1", "ind2": " ", "subfields": [
|
|
13
|
+
{ "code": "a", "value": "Sukunimi2, Etunimi," },
|
|
14
|
+
{ "code": "e", "value": "kuvittaja," },
|
|
15
|
+
{ "code": "e", "value": "kirjoittaja." }
|
|
16
|
+
]},
|
|
17
|
+
{ "tag": "700", "ind1": "1", "ind2": " ", "subfields": [
|
|
18
|
+
{ "code": "a", "value": "Sukunimi2, Etunimi." }
|
|
19
|
+
]}
|
|
20
|
+
],
|
|
21
|
+
|
|
22
|
+
"leader": ""
|
|
23
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"fields": [
|
|
3
|
+
{ "tag": "005", "value": "20220202020202.0" },
|
|
4
|
+
{ "tag": "100", "ind1": "1", "ind2": " ", "subfields": [
|
|
5
|
+
{ "code": "a", "value": "Sukunimi, Etunimi," },
|
|
6
|
+
{ "code": "e", "value": "kuvittaja." }
|
|
7
|
+
]},
|
|
8
|
+
{ "tag": "700", "ind1": "1", "ind2": " ", "subfields": [
|
|
9
|
+
{ "code": "a", "value": "Sukunimi, Etunimi," },
|
|
10
|
+
{ "code": "e", "value": "kirjoittaja," },
|
|
11
|
+
{ "code": "e", "value": "valokuvaaja." }
|
|
12
|
+
]}
|
|
13
|
+
],
|
|
14
|
+
|
|
15
|
+
"leader": ""
|
|
16
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"fields": [
|
|
3
|
+
{ "tag": "005", "value": "20220202020202.0" },
|
|
4
|
+
{ "tag": "100", "ind1": "1", "ind2": " ", "subfields": [
|
|
5
|
+
{ "code": "a", "value": "Sukunimi, Etunimi," },
|
|
6
|
+
{ "code": "e", "value": "kuvittaja." }
|
|
7
|
+
]},
|
|
8
|
+
{ "tag": "700", "ind1": "1", "ind2": " ", "subfields": [
|
|
9
|
+
{ "code": "a", "value": "Eri-Sukunimi, Etunimi," },
|
|
10
|
+
{ "code": "e", "value": "kirjoittaja," },
|
|
11
|
+
{ "code": "e", "value": "valokuvaaja." }
|
|
12
|
+
]}
|
|
13
|
+
],
|
|
14
|
+
|
|
15
|
+
"leader": ""
|
|
16
|
+
}
|