@natlibfi/melinda-merge-ui-commons
Version:
Common modules for Melinda Merge UI application
524 lines (406 loc) • 35.3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); /**
*
* @licstart The following is the entire license notice for the JavaScript code in this file.
*
* Common modules for Melinda UI applications
*
* Copyright (C) 2015-2019 University Of Helsinki (The National Library Of Finland)
*
* This file is part of melinda-ui-commons
*
* melinda-ui-commons program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* melinda-ui-commons is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @licend The above is the entire license notice
* for the JavaScript code in this file.
*
*/
exports.transliterate = transliterate;
var _lodash = require('lodash');
var _lodash2 = _interopRequireDefault(_lodash);
var _sfs = require('sfs4900');
var sfs4900 = _interopRequireWildcard(_sfs);
var _iso9_ = require('iso9_1995');
var iso9 = _interopRequireWildcard(_iso9_);
var _nodeUuid = require('node-uuid');
var _nodeUuid2 = _interopRequireDefault(_nodeUuid);
var _recordUtils = require('../record-utils');
var _marcRecordJs = require('marc-record-js');
var _marcRecordJs2 = _interopRequireDefault(_marcRecordJs);
var _xregexp = require('xregexp');
var _xregexp2 = _interopRequireDefault(_xregexp);
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var defaultOptions = {
doSFS4900RusTransliteration: true
};
function transliterate(record, options) {
options = _lodash2.default.assign({}, defaultOptions, options);
record.fields.forEach(function (field) {
if (field.uuid === undefined) {
field.uuid = _nodeUuid2.default.v4();
}
});
return new Promise(function (resolve) {
var originalRecord = new _marcRecordJs2.default(record);
var fields = record.fields;
record.fields = transformFields(options, fields);
var warnings = checkForWarnings(originalRecord, record);
record.fields = removeFailedTransliterations(record.fields);
resolve({ record: record, warnings: warnings });
});
}
function transformFields(options, fields) {
var transliterate880Fields = _lodash2.default.partial(createTransliteratedFieldsFrom880, options);
var transformComposition = _lodash2.default.flow(function (fields) {
return fields.map(normalizeField);
}, // normalize link subfields etc.
moveCyrillicFieldsTo880, // move fields with cyrillic content to 880
transliterate880Fields, // create transliterated fields for every cyrillic 880
sortNumericFields // new fields were added, so they need to be sorted
);
return transformComposition(fields);
}
function shouldCreateTransliteratedFields(field) {
return field.tag === '880' && fieldContainsCyrillicCharacters(field);
}
function removeFailedTransliterations(fieldList) {
var isSFSTransliteratedField = hasSubfieldValue(9, 'SFS4900 <TRANS>');
return fieldList.filter(function (field) {
var failedSFS4900Transliteration = isSFSTransliteratedField(field) && fieldContainsCyrillicCharacters(field);
return !failedSFS4900Transliteration;
});
}
function hasSubfieldValue(expectedCode, expectedValue) {
var expectedSubfieldCodeStr = expectedCode.toString();
return function (field) {
return field.subfields && field.subfields.some(function (subfield) {
return subfield.code === expectedSubfieldCodeStr && subfield.value === expectedValue;
});
};
}
function checkForWarnings(originalRecord, transformedRecord) {
// check for mixed alphabets
var mixedAlphabetsWarnings = transformedRecord.fields.reduce(function (acc, field) {
if (field.subfields) {
var warnings = field.subfields.filter(function (subfield) {
return isMixedAlphabet(subfield.value);
}).map(function (subfield) {
var link = getLink(field).join('-');
return 'Kent\xE4ss\xE4 ' + field.tag + subfield.code + ' (' + link + ') on sek\xE4 kyrillisi\xE4 ett\xE4 latinalaisia merkkej\xE4.';
});
return _lodash2.default.concat(acc, warnings);
} else {
if (isMixedAlphabet(field.value)) {
var link = getLink(field).join('-');
var warning = 'Kent\xE4ss\xE4 ' + field.tag + ' ' + link + ' on sek\xE4 kyrillisi\xE4 ett\xE4 latinalaisia merkkej\xE4.';
return _lodash2.default.concat(acc, warning);
}
}
return acc;
}, []);
var brokenLinkWarnings = transformedRecord.fields.filter(containsLinkSubfield).filter(function (field) {
var linkedField = transformedRecord.fields.find(isLinkedFieldOf(field));
return linkedField === undefined;
}).map(function (field) {
var link = getLink(field).join('-');
return 'Kentt\xE4 ' + field.tag + ' (' + link + ') linkitt\xE4\xE4 kentt\xE4\xE4n jota ei ole olemassa.';
});
var subfieldCountMismatchWarnings = _lodash2.default.chain(originalRecord.fields).filter(containsLinkSubfield).filter(function (field) {
return field.tag !== '880';
}).flatMap(function (field) {
var linkedFields = transformedRecord.fields.filter(isLinkedFieldOf(field));
if (linkedFields === undefined) return [];
return linkedFields.map(function (linked) {
return [field, linked];
});
}).filter(function (_ref) {
var _ref2 = _slicedToArray(_ref, 2),
field = _ref2[0],
linkedField = _ref2[1];
return _lodash2.default.difference(_lodash2.default.map(field.subfields, 'code'), _lodash2.default.map(linkedField.subfields, 'code')).length !== 0;
}).map(function (offendingFieldPairs) {
var field = offendingFieldPairs[0];
return 'Alkuper\xE4isen tietueen kent\xE4ss\xE4 ' + field.tag + ' ja sen linkitt\xE4m\xE4ss\xE4 kent\xE4ss\xE4 on eri m\xE4\xE4r\xE4 osakentti\xE4. Osakenttien sis\xE4lt\xF6 h\xE4vi\xE4\xE4.';
}).uniq().value();
var isSFSTransliteratedField = hasSubfieldValue(9, 'SFS4900 <TRANS>');
var failedSFS4900TransliterationWarnings = transformedRecord.fields.filter(function (field) {
return isSFSTransliteratedField(field) && fieldContainsCyrillicCharacters(field);
}).map(function (failedField) {
var originalTag = _lodash2.default.head(getLink(failedField));
return 'Alkuper\xE4isen tietueen kent\xE4ss\xE4 ' + originalTag + ' on merkkej\xE4, joita ei ole m\xE4\xE4ritelty SFS4900-ven\xE4j\xE4 translitteroinnissa. SFS4900 kentt\xE4\xE4 ei luotu.';
});
return _lodash2.default.concat(mixedAlphabetsWarnings, brokenLinkWarnings, subfieldCountMismatchWarnings, failedSFS4900TransliterationWarnings);
}
function containsLinkSubfield(field) {
return field.subfields && field.subfields.some(function (sub) {
return sub.code === '6';
});
}
function isLinkedFieldOf(queryField) {
var _getLink = getLink(queryField),
_getLink2 = _slicedToArray(_getLink, 2),
queryTag = _getLink2[0],
queryLinkNumber = _getLink2[1];
return function (field) {
var linkInLinkedField = getLink(field);
var _linkInLinkedField = _slicedToArray(linkInLinkedField, 2),
linkTag = _linkInLinkedField[0],
linkNumber = _linkInLinkedField[1];
var fieldMatchesQueryLinkTag = field.tag === queryTag;
var linkNumberMatchesQueryLinkNumber = linkNumber === queryLinkNumber;
var linkTagLinksBackToQueryField = linkTag === queryField.tag;
return fieldMatchesQueryLinkTag && linkNumberMatchesQueryLinkNumber && linkTagLinksBackToQueryField;
};
}
function isMixedAlphabet(str) {
var hasCyrillic = str.split('').filter(isCharacter).some(isCyrillicCharacter);
var hasOnlyCyrillic = str.split('').filter(isCharacter).every(isCyrillicCharacter);
return hasCyrillic && !hasOnlyCyrillic;
}
function isCharacter(char) {
return (0, _xregexp2.default)('[\\p{Cyrillic}|\\w]').test(char) && !/[0-9_]/.test(char);
}
function normalizeField(field) {
return (0, _recordUtils.isDataField)(field) ? normalize(field) : field;
function normalize(field) {
return _lodash2.default.assign({}, field, {
subfields: field.subfields.map(normalizeSub_6)
});
}
function normalizeSub_6(subfield) {
var code = subfield.code,
value = subfield.value;
if (subfield.code === '6') {
value = _lodash2.default.head(value.split('/'));
}
return { code: code, value: value };
}
}
function moveCyrillicFieldsTo880(fieldList) {
return fieldList.reduce(function (fields, field) {
if (shouldTransliterateField(field)) {
var tagForLinking = field.tag;
var linkNumber = getNextAvailableLinkNumber(_lodash2.default.concat(fieldList, fields));
var movedField = changeFieldTag(field, tagForLinking, linkNumber);
if (containsField(fieldList, movedField)) {
fields.push(field);
} else {
fields.push(movedField);
}
} else {
fields.push(field);
}
return fields;
}, []);
function changeFieldTag(field, tagForLinking, linkNumber) {
var newField = _lodash2.default.assign({}, field, {
tag: '880'
});
newField.subfields.unshift({ code: '6', value: tagForLinking + '-' + linkNumber });
return newField;
}
}
function containsField(fieldList, field) {
var isEqualField = _lodash2.default.partial(fieldIsLessOrEqual, field);
return fieldList.some(isEqualField);
}
function shouldTransliterateField(field) {
return field.tag !== '880' && fieldContainsCyrillicCharacters(field);
}
function fieldContainsCyrillicCharacters(field) {
return field.subfields && field.subfields.map(function (sub) {
return sub.value;
}).some(containsCyrillicCharacters);
}
function containsCyrillicCharacters(str) {
return str.split('').some(isCyrillicCharacter);
}
function isCyrillicCharacter(char) {
return (0, _xregexp2.default)('[\\p{Cyrillic}]').test(char);
}
function createTransliteratedFieldsFrom880(options, fieldList) {
var fieldsForRemoval = [];
var transliteratedFieldList = fieldList.reduce(function (fields, field) {
if (shouldCreateTransliteratedFields(field)) {
var link = getLinkSubfield(field).value;
var _link$split = link.split('-'),
_link$split2 = _slicedToArray(_link$split, 2),
linkedTag = _link$split2[0],
linkNumber = _link$split2[1];
if (options.doSFS4900RusTransliteration) {
var sfs4900Transliterated = createSFS4900TransliteratedField(field, linkedTag, linkNumber);
if (!containsField(fieldList, sfs4900Transliterated)) {
fields.push(sfs4900Transliterated);
}
}
var iso9Transliterated = createISO9TransliteratedField(field, linkedTag, linkNumber);
if (!containsField(fieldList, iso9Transliterated)) {
fields.push(iso9Transliterated);
// We added new "main" field (non-880) with iso9 transliteration. We cleanup the corresponding,
// already transliterated field (if any), from the record
var iso9link = getLinkSubfield(iso9Transliterated);
fieldList.filter(function (field) {
return field.tag === iso9Transliterated.tag;
}).filter(function (field) {
return field.subfields.some(function (sub) {
return _lodash2.default.isEqual(sub, iso9link);
});
}).forEach(function (field) {
iso9Transliterated.uuid = field.uuid;
fieldsForRemoval.push(field);
});
}
// Mark the original field contents as being cyrillic
var cyrillicNoteSubField = { code: '9', value: 'CYRILLIC <TRANS>' };
if (!field.subfields.some(function (sub) {
return _lodash2.default.isEqual(sub, cyrillicNoteSubField);
})) {
field.subfields.push(cyrillicNoteSubField);
}
}
fields.push(field);
return fields;
}, []);
return _lodash2.default.difference(transliteratedFieldList, fieldsForRemoval);
function createSFS4900TransliteratedField(field, linkedTag, linkNumber) {
var sfs4900Transliterated = _lodash2.default.assign({}, field, {
tag: '880',
uuid: _nodeUuid2.default.v4(),
subfields: field.subfields.filter(function (sub) {
return !isTransliterationSubfield(sub);
}).map(transliterateSubfield('sfs4900'))
});
sfs4900Transliterated.subfields.unshift({ code: '6', value: linkedTag + '-' + linkNumber });
sfs4900Transliterated.subfields.push({ code: '9', value: 'SFS4900 <TRANS>' });
return sfs4900Transliterated;
}
function createISO9TransliteratedField(field, linkedTag, linkNumber) {
var iso9Transliterated = {
tag: linkedTag,
uuid: _nodeUuid2.default.v4(),
ind1: field.ind1,
ind2: field.ind2,
subfields: field.subfields.filter(function (sub) {
return !isTransliterationSubfield(sub);
}).map(transliterateSubfield('iso9'))
};
var iso9TransliteratedLinkSubField = { code: '6', value: '880-' + linkNumber };
iso9Transliterated.subfields.unshift(iso9TransliteratedLinkSubField);
iso9Transliterated.subfields.push({ code: '9', value: 'ISO9 <TRANS>' });
return iso9Transliterated;
}
function isTransliterationSubfield(subfield) {
return subfield.code === '6' || subfield.code === '9' && subfield.value.indexOf('<TRANS>') !== -1;
}
}
function getLinkSubfield(field) {
return field.subfields.find(function (sub) {
return sub.code === '6';
});
}
function fieldIsLessOrEqual(fieldA, fieldB) {
if (fieldA.tag !== fieldB.tag) return false;
if (fieldA.ind1 !== fieldB.ind1) return false;
if (fieldA.ind2 !== fieldB.ind2) return false;
if (_typeof(fieldA.subfields) !== _typeof(fieldB.subfields)) return false;
if (fieldA.subfields) {
if (_lodash2.default.differenceWith(fieldA.subfields, fieldB.subfields, _lodash2.default.isEqual).length !== 0) return false;
} else {
if (fieldA.value !== fieldB.value) return false;
}
return true;
}
function sortNumericFields(fields) {
var nonNumericFields = fields.reduce(function (acc, field, i) {
if (isNaN(field.tag)) {
acc.push({
field: field,
index: i
});
}
return acc;
}, []);
var numericFields = _lodash2.default.difference(fields, nonNumericFields.map(function (item) {
return item.field;
}));
numericFields.sort(function (a, b) {
var byTag = parseInt(a.tag) - parseInt(b.tag);
if (byTag !== 0) return byTag;
var _getLink3 = getLink(a),
_getLink4 = _slicedToArray(_getLink3, 1),
aLinkedTag = _getLink4[0];
var _getLink5 = getLink(b),
_getLink6 = _slicedToArray(_getLink5, 1),
bLinkedTag = _getLink6[0];
var byLinkedFieldTag = parseInt(aLinkedTag) - parseInt(bLinkedTag);
if (byLinkedFieldTag !== 0) return byLinkedFieldTag;
var cyrillicFirst = fieldContainsCyrillicCharacters(b) ? 1 : -1;
return cyrillicFirst;
});
nonNumericFields.forEach(function (item) {
numericFields.splice(item.index, 0, item.field);
});
return numericFields;
}
function getNextAvailableLinkNumber(fields) {
var currentLinkNumbers = (0, _lodash2.default)(fields).flatMap(function (field) {
return field.subfields;
}).filter(_lodash2.default.isObject).filter(function (sub) {
return sub.code === '6';
}).map(function (sub) {
return sub.value;
}).map(function (link) {
return _lodash2.default.last(link.split('-'));
}).value();
var isTaken = function isTaken(linkNumberPart) {
return currentLinkNumbers.some(function (used) {
return used === linkNumberPart;
});
};
return _lodash2.default.range(1, 100).map(function (num) {
return _lodash2.default.padStart(num, 2, '0');
}).find(function (linkNumberPart) {
return !isTaken(linkNumberPart);
});
}
function getLink(field) {
var links = _lodash2.default.get(field, 'subfields', []).filter(function (sub) {
return sub.code === '6';
}).map(function (sub) {
return sub.value;
}).map(function (link) {
return link.split('-');
});
return _lodash2.default.head(links) || [];
}
function transliterateSubfield(type) {
return function (subfield) {
var converted = type === 'sfs4900' ? sfs4900Convert(subfield.value) : iso9Convert(subfield.value);
return _lodash2.default.assign({}, subfield, { value: converted.result });
};
}
function sfs4900Convert(str) {
return sfs4900.convertToLatin(str);
}
function iso9Convert(str) {
return {
result: iso9.convertToLatin(str)
};
}
//# sourceMappingURL=transliterate.js.map