@natlibfi/marc-record-validators-melinda 12.0.2 → 12.0.3-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/fix-sami-041.js +61 -40
- package/dist/fix-sami-041.js.map +2 -2
- package/package.json +3 -3
- package/src/fix-sami-041.js +75 -43
- package/test-fixtures/fix-sami-041/01/record.json +1 -0
- package/test-fixtures/fix-sami-041/03/record.json +1 -1
- package/test-fixtures/fix-sami-041/06/expectedResult.json +10 -0
- package/test-fixtures/fix-sami-041/06/metadata.json +4 -0
- package/test-fixtures/fix-sami-041/06/record.json +9 -0
package/dist/fix-sami-041.js
CHANGED
|
@@ -1,23 +1,39 @@
|
|
|
1
|
+
import createDebugLogger from "debug";
|
|
1
2
|
import clone from "clone";
|
|
2
3
|
import { fieldToString } from "./utils.js";
|
|
4
|
+
const debug = createDebugLogger("@natlibfi/marc-record-validators-melinda:fix-sami-041");
|
|
3
5
|
export default function() {
|
|
4
6
|
const samiLanguages = ["sma", "sme", "smj", "smn", "sms"];
|
|
5
|
-
const
|
|
7
|
+
const subfieldCodesUsingSmi = ["a", "d"];
|
|
6
8
|
return {
|
|
7
|
-
description: "Add
|
|
9
|
+
description: "Add corresponding 'smi' subfield before a specific sami language subfields and update 008/35-37, if needed",
|
|
8
10
|
validate,
|
|
9
11
|
fix
|
|
10
12
|
};
|
|
13
|
+
function getRelevantSubfieldCodes(record) {
|
|
14
|
+
if (record && record.leader && record.leader[6]) {
|
|
15
|
+
debug(` LDR/06 is '${record.leader[6]}'`);
|
|
16
|
+
if (["i", "j"].includes(record.leader[6])) {
|
|
17
|
+
return ["d"];
|
|
18
|
+
}
|
|
19
|
+
return ["a"];
|
|
20
|
+
}
|
|
21
|
+
return ["a", "d"];
|
|
22
|
+
}
|
|
11
23
|
function fix(record, validateMode = false) {
|
|
12
|
-
|
|
24
|
+
debug(`Start ${validateMode ? "validator" : "fixer"}`);
|
|
25
|
+
const relevantSubfieldCodes = getRelevantSubfieldCodes(record);
|
|
26
|
+
debug(` Relevant subfield codes are '${relevantSubfieldCodes.join("', '")}'`);
|
|
27
|
+
const relevantFields = record.fields.filter((f) => isRelevantField(f, relevantSubfieldCodes)).map((f) => validateMode ? clone(f) : f);
|
|
13
28
|
if (relevantFields.length === 0) {
|
|
29
|
+
debug(` No relevant f041 fields found`);
|
|
14
30
|
if (validateMode) {
|
|
15
31
|
return { message: [], valid: true };
|
|
16
32
|
}
|
|
17
33
|
return { message: [], fix: [], valid: true };
|
|
18
34
|
}
|
|
19
35
|
const relevantFieldsAsStrings = relevantFields.map((f) => fieldToString(f));
|
|
20
|
-
relevantFields.forEach((f) => processField(f));
|
|
36
|
+
relevantFields.forEach((f) => processField(f, relevantSubfieldCodes));
|
|
21
37
|
const modFieldsAsStrings = relevantFields.map((f) => fieldToString(f));
|
|
22
38
|
const report = [...updateAndReport008(), ...createReport(relevantFieldsAsStrings, modFieldsAsStrings)];
|
|
23
39
|
if (validateMode) {
|
|
@@ -27,19 +43,57 @@ export default function() {
|
|
|
27
43
|
function updateAndReport008() {
|
|
28
44
|
const [f008] = record.get("008").map((f) => validateMode ? clone(f) : f);
|
|
29
45
|
if (!f008) {
|
|
46
|
+
debug(" WARNING: no f008 found");
|
|
30
47
|
return [];
|
|
31
48
|
}
|
|
32
49
|
const currLang = f008.value.substr(35, 3);
|
|
33
50
|
if (!samiLanguages.includes(currLang)) {
|
|
51
|
+
debug(` Existing 008/35-37 '${currLang}' is not a sami language. No need to update 008/35-37`);
|
|
34
52
|
return [];
|
|
35
53
|
}
|
|
36
54
|
const origValue = f008.value;
|
|
37
|
-
const firstRelevantSubfield = relevantFields[0].subfields.find((sf) =>
|
|
38
|
-
if (firstRelevantSubfield.value
|
|
39
|
-
|
|
55
|
+
const firstRelevantSubfield = relevantFields[0].subfields.find((sf) => relevantSubfieldCodes.includes(sf.code));
|
|
56
|
+
if (firstRelevantSubfield.value !== "smi") {
|
|
57
|
+
debug(` First relevant subfield is '$${firstRelevantSubfield.code} ${firstRelevantSubfield.value}'. No need to update 008/35-37`);
|
|
58
|
+
return [];
|
|
40
59
|
}
|
|
60
|
+
f008.value = `${f008.value.substr(0, 35)}smi${f008.value.substr(38)}`;
|
|
61
|
+
debug(` Update 008/35-37: '${currLang}' => 'smi'`);
|
|
41
62
|
return createReport([origValue], [f008.value]);
|
|
42
63
|
}
|
|
64
|
+
function processField(f) {
|
|
65
|
+
f.subfields = processSubfields(f.subfields, []);
|
|
66
|
+
}
|
|
67
|
+
function processSubfields(incomingSubfields, outgoingSubfields = []) {
|
|
68
|
+
const [currSubfield, ...otherSubfields] = incomingSubfields;
|
|
69
|
+
if (!currSubfield) {
|
|
70
|
+
return outgoingSubfields;
|
|
71
|
+
}
|
|
72
|
+
if (!isRelevantSamiSubfield(currSubfield, [...outgoingSubfields, ...otherSubfields])) {
|
|
73
|
+
return processSubfields(otherSubfields, [...outgoingSubfields, currSubfield]);
|
|
74
|
+
}
|
|
75
|
+
const smiSubfield = {
|
|
76
|
+
code: currSubfield.code,
|
|
77
|
+
value: "smi"
|
|
78
|
+
};
|
|
79
|
+
debug(` f041: Add '$${currSubfield.code} smi' before '${currSubfield.value}'`);
|
|
80
|
+
return processSubfields(otherSubfields, [...outgoingSubfields, smiSubfield, currSubfield]);
|
|
81
|
+
}
|
|
82
|
+
function isRelevantField(f) {
|
|
83
|
+
if (f.tag !== "041" || !f.subfields || f.subfields.some((sf) => sf.code === "2")) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
return f.subfields.some((sf) => isRelevantSamiSubfield(sf, f.subfields));
|
|
87
|
+
}
|
|
88
|
+
function isRelevantSamiSubfield(sf, otherSubfields) {
|
|
89
|
+
if (!subfieldCodesUsingSmi.includes(sf.code) || !samiLanguages.includes(sf.value)) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
if (otherSubfields.some((sf2) => sf2.code === sf.code && sf2.value === "smi")) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
43
97
|
}
|
|
44
98
|
function createReport(origArray, modArray) {
|
|
45
99
|
return origArray.map((entry, index) => createEntry(entry, index));
|
|
@@ -50,38 +104,5 @@ export default function() {
|
|
|
50
104
|
function validate(record) {
|
|
51
105
|
return fix(record, true);
|
|
52
106
|
}
|
|
53
|
-
function processField(f) {
|
|
54
|
-
f.subfields = prosessSubfields(f.subfields);
|
|
55
|
-
return f;
|
|
56
|
-
}
|
|
57
|
-
function prosessSubfields(incomingSubfields, outgoingSubfields = []) {
|
|
58
|
-
const [currSubfield, ...otherSubfields] = incomingSubfields;
|
|
59
|
-
if (!currSubfield) {
|
|
60
|
-
return outgoingSubfields;
|
|
61
|
-
}
|
|
62
|
-
if (!isRelevantSamiSubfield(currSubfield, [...outgoingSubfields, ...otherSubfields])) {
|
|
63
|
-
return prosessSubfields(otherSubfields, [...outgoingSubfields, currSubfield]);
|
|
64
|
-
}
|
|
65
|
-
const smiSubfield = {
|
|
66
|
-
code: currSubfield.code,
|
|
67
|
-
value: "smi"
|
|
68
|
-
};
|
|
69
|
-
return prosessSubfields(otherSubfields, [...outgoingSubfields, smiSubfield, currSubfield]);
|
|
70
|
-
}
|
|
71
|
-
function isRelevantField(f) {
|
|
72
|
-
if (f.tag !== "041" || !f.subfields || f.subfields.some((sf) => sf.code === "2")) {
|
|
73
|
-
return false;
|
|
74
|
-
}
|
|
75
|
-
return f.subfields.some((sf) => isRelevantSamiSubfield(sf, f.subfields));
|
|
76
|
-
}
|
|
77
|
-
function isRelevantSamiSubfield(sf, otherSubfields) {
|
|
78
|
-
if (!relevantSubfieldCodes.includes(sf.code) || !samiLanguages.includes(sf.value)) {
|
|
79
|
-
return false;
|
|
80
|
-
}
|
|
81
|
-
if (otherSubfields.some((sf2) => sf2.code === sf.code && sf2.value === "smi")) {
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
return true;
|
|
85
|
-
}
|
|
86
107
|
}
|
|
87
108
|
//# sourceMappingURL=fix-sami-041.js.map
|
package/dist/fix-sami-041.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/fix-sami-041.js"],
|
|
4
|
-
"sourcesContent": ["// Author(s): Nicholas Volk\n\
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["// Author(s): Nicholas Volk\n\nimport createDebugLogger from 'debug';\nimport clone from 'clone';\n\nimport {fieldToString} from './utils.js';\n\nconst debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:fix-sami-041');\n\n\n\nexport default function () {\n /* 'sma': etel\u00E4saame, 'sme': pohjoissaame, 'smj': luulajansaame, 'smn': inarinsaame, 'sms': koltansaame */\n const samiLanguages = ['sma', 'sme', 'smj', 'smn', 'sms'];\n const subfieldCodesUsingSmi = ['a', 'd'];\n\n return {\n description: 'Add corresponding \\'smi\\' subfield before a specific sami language subfields and update 008/35-37, if needed',\n validate, fix\n };\n\n function getRelevantSubfieldCodes(record) { // Maybe this should be an exportable utility function...\n if (record && record.leader && record.leader[6]) {\n debug(` LDR/06 is '${record.leader[6]}'`);\n // We should test this properly...\n if (['i', 'j'].includes(record.leader[6])) { // Check type of record: sound recordings use 'd'\n return ['d'];\n }\n return ['a'];\n }\n\n return ['a', 'd']; // B\u00E5de-och\n }\n\n\n function fix(record, validateMode = false) {\n debug(`Start ${validateMode ? 'validator' : 'fixer'}`);\n const relevantSubfieldCodes = getRelevantSubfieldCodes(record);\n debug(` Relevant subfield codes are '${relevantSubfieldCodes.join(\"', '\")}'`);\n const relevantFields = record.fields.filter(f => isRelevantField(f, relevantSubfieldCodes)).map(f => validateMode ? clone(f) : f); // NV! relevant fields are cloned in validation mode!\n // Nothing to do:\n if (relevantFields.length === 0) {\n debug(` No relevant f041 fields found`);\n if (validateMode) {\n return {message: [], valid: true};\n }\n return {message: [], fix: [], valid: true};\n }\n\n const relevantFieldsAsStrings = relevantFields.map(f => fieldToString(f)); // get original values\n\n relevantFields.forEach(f => processField(f, relevantSubfieldCodes));\n const modFieldsAsStrings = relevantFields.map(f => fieldToString(f));\n const report = [...updateAndReport008(), ...createReport(relevantFieldsAsStrings, modFieldsAsStrings)];\n\n if (validateMode) {\n return {'message': report, 'valid': false};\n }\n\n return {message: [], fix: report, valid: true};\n\n function updateAndReport008() { // Update 008/35-37 if necessary + report it\n const [f008] = record.get('008').map(f => validateMode ? clone(f) : f);\n\n if (!f008) {\n debug(' WARNING: no f008 found');\n return [];\n }\n const currLang = f008.value.substr(35, 3);\n if (!samiLanguages.includes(currLang)) { // NB! If original 008/35-37 was not a sami language, we don't change anything!\n debug(` Existing 008/35-37 '${currLang}' is not a sami language. No need to update 008/35-37`);\n return [];\n }\n const origValue = f008.value;\n const firstRelevantSubfield = relevantFields[0].subfields.find(sf => relevantSubfieldCodes.includes(sf.code));\n if (firstRelevantSubfield.value !== 'smi') {\n debug(` First relevant subfield is '\\$${firstRelevantSubfield.code} ${firstRelevantSubfield.value}'. No need to update 008/35-37`);\n return [];\n }\n f008.value = `${f008.value.substr(0, 35)}smi${f008.value.substr(38)}`;\n debug(` Update 008/35-37: '${currLang}' => 'smi'`);\n return createReport([origValue], [f008.value]);\n }\n\n function processField(f) {\n f.subfields = processSubfields(f.subfields, []);\n }\n\n function processSubfields(incomingSubfields, outgoingSubfields = []) {\n const [currSubfield, ...otherSubfields] = incomingSubfields;\n if (!currSubfield) {\n return outgoingSubfields;\n }\n if (!isRelevantSamiSubfield(currSubfield, [...outgoingSubfields, ...otherSubfields])) {\n return processSubfields(otherSubfields, [...outgoingSubfields, currSubfield]);\n }\n\n const smiSubfield = {\n code: currSubfield.code,\n value: 'smi'\n };\n debug(` f041: Add '\\$${currSubfield.code} smi' before '${currSubfield.value}'`);\n\n return processSubfields(otherSubfields, [...outgoingSubfields, smiSubfield, currSubfield]);\n }\n\n function isRelevantField(f) {\n if (f.tag !== '041' || !f.subfields || f.subfields.some(sf => sf.code === '2')) {\n return false;\n }\n return f.subfields.some(sf => isRelevantSamiSubfield(sf, f.subfields)); // it's ok to pass sf in f.subfields also\n }\n\n function isRelevantSamiSubfield(sf, otherSubfields) {\n // NB! preceding 'smi' is added to all $a and $d fields, regardless of the LDR/06 value! (However, copying 041$a/d -> 008/35-37 depends on LDR/06)\n if (!subfieldCodesUsingSmi.includes(sf.code) || !samiLanguages.includes(sf.value)) {\n return false;\n }\n if (otherSubfields.some(sf2 => sf2.code === sf.code && sf2.value === 'smi')) { // fail if 'smi' already exists\n return false;\n }\n //debug(` '\\${sf.code} ${sf.value}' requires preceding 'smi'`);\n return true;\n }\n }\n\n function createReport(origArray, modArray) {\n return origArray.map((entry, index) => createEntry(entry, index));\n\n function createEntry(item, index) {\n return `'${item}' => '${modArray[index]}'`;\n }\n }\n\n function validate(record) {\n return fix(record, true);\n }\n\n\n\n\n\n\n}\n\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"url": "https://github.com/NatLibFi/marc-record-validators-melinda"
|
|
15
15
|
},
|
|
16
16
|
"license": "MIT",
|
|
17
|
-
"version": "12.0.
|
|
17
|
+
"version": "12.0.3-alpha.1",
|
|
18
18
|
"main": "./dist/index.js",
|
|
19
19
|
"publishConfig": {
|
|
20
20
|
"access": "public"
|
|
@@ -59,8 +59,8 @@
|
|
|
59
59
|
"@natlibfi/fixugen": "^3.0.0",
|
|
60
60
|
"@natlibfi/fixura": "^4.0.0",
|
|
61
61
|
"cross-env": "^10.1.0",
|
|
62
|
-
"esbuild": "^0.27.
|
|
63
|
-
"eslint": "^9.39.
|
|
62
|
+
"esbuild": "^0.27.2",
|
|
63
|
+
"eslint": "^9.39.2",
|
|
64
64
|
"fetch-mock": "^12.6.0"
|
|
65
65
|
},
|
|
66
66
|
"overrides": {
|
package/src/fix-sami-041.js
CHANGED
|
@@ -1,28 +1,46 @@
|
|
|
1
1
|
// Author(s): Nicholas Volk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import createDebugLogger from 'debug';
|
|
4
4
|
import clone from 'clone';
|
|
5
5
|
|
|
6
6
|
import {fieldToString} from './utils.js';
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:fix-sami-041');
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
export default function () {
|
|
13
13
|
/* 'sma': eteläsaame, 'sme': pohjoissaame, 'smj': luulajansaame, 'smn': inarinsaame, 'sms': koltansaame */
|
|
14
14
|
const samiLanguages = ['sma', 'sme', 'smj', 'smn', 'sms'];
|
|
15
|
-
const
|
|
15
|
+
const subfieldCodesUsingSmi = ['a', 'd'];
|
|
16
16
|
|
|
17
17
|
return {
|
|
18
|
-
description: 'Add
|
|
18
|
+
description: 'Add corresponding \'smi\' subfield before a specific sami language subfields and update 008/35-37, if needed',
|
|
19
19
|
validate, fix
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
+
function getRelevantSubfieldCodes(record) { // Maybe this should be an exportable utility function...
|
|
23
|
+
if (record && record.leader && record.leader[6]) {
|
|
24
|
+
debug(` LDR/06 is '${record.leader[6]}'`);
|
|
25
|
+
// We should test this properly...
|
|
26
|
+
if (['i', 'j'].includes(record.leader[6])) { // Check type of record: sound recordings use 'd'
|
|
27
|
+
return ['d'];
|
|
28
|
+
}
|
|
29
|
+
return ['a'];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return ['a', 'd']; // Både-och
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
22
36
|
function fix(record, validateMode = false) {
|
|
23
|
-
|
|
37
|
+
debug(`Start ${validateMode ? 'validator' : 'fixer'}`);
|
|
38
|
+
const relevantSubfieldCodes = getRelevantSubfieldCodes(record);
|
|
39
|
+
debug(` Relevant subfield codes are '${relevantSubfieldCodes.join("', '")}'`);
|
|
40
|
+
const relevantFields = record.fields.filter(f => isRelevantField(f, relevantSubfieldCodes)).map(f => validateMode ? clone(f) : f); // NV! relevant fields are cloned in validation mode!
|
|
24
41
|
// Nothing to do:
|
|
25
42
|
if (relevantFields.length === 0) {
|
|
43
|
+
debug(` No relevant f041 fields found`);
|
|
26
44
|
if (validateMode) {
|
|
27
45
|
return {message: [], valid: true};
|
|
28
46
|
}
|
|
@@ -31,7 +49,7 @@ export default function () {
|
|
|
31
49
|
|
|
32
50
|
const relevantFieldsAsStrings = relevantFields.map(f => fieldToString(f)); // get original values
|
|
33
51
|
|
|
34
|
-
relevantFields.forEach(f => processField(f));
|
|
52
|
+
relevantFields.forEach(f => processField(f, relevantSubfieldCodes));
|
|
35
53
|
const modFieldsAsStrings = relevantFields.map(f => fieldToString(f));
|
|
36
54
|
const report = [...updateAndReport008(), ...createReport(relevantFieldsAsStrings, modFieldsAsStrings)];
|
|
37
55
|
|
|
@@ -41,23 +59,69 @@ export default function () {
|
|
|
41
59
|
|
|
42
60
|
return {message: [], fix: report, valid: true};
|
|
43
61
|
|
|
44
|
-
function updateAndReport008() {
|
|
62
|
+
function updateAndReport008() { // Update 008/35-37 if necessary + report it
|
|
45
63
|
const [f008] = record.get('008').map(f => validateMode ? clone(f) : f);
|
|
46
64
|
|
|
47
65
|
if (!f008) {
|
|
66
|
+
debug(' WARNING: no f008 found');
|
|
48
67
|
return [];
|
|
49
68
|
}
|
|
50
69
|
const currLang = f008.value.substr(35, 3);
|
|
51
70
|
if (!samiLanguages.includes(currLang)) { // NB! If original 008/35-37 was not a sami language, we don't change anything!
|
|
71
|
+
debug(` Existing 008/35-37 '${currLang}' is not a sami language. No need to update 008/35-37`);
|
|
52
72
|
return [];
|
|
53
73
|
}
|
|
54
74
|
const origValue = f008.value;
|
|
55
|
-
const firstRelevantSubfield = relevantFields[0].subfields.find(sf =>
|
|
56
|
-
if (firstRelevantSubfield.value
|
|
57
|
-
|
|
75
|
+
const firstRelevantSubfield = relevantFields[0].subfields.find(sf => relevantSubfieldCodes.includes(sf.code));
|
|
76
|
+
if (firstRelevantSubfield.value !== 'smi') {
|
|
77
|
+
debug(` First relevant subfield is '\$${firstRelevantSubfield.code} ${firstRelevantSubfield.value}'. No need to update 008/35-37`);
|
|
78
|
+
return [];
|
|
58
79
|
}
|
|
80
|
+
f008.value = `${f008.value.substr(0, 35)}smi${f008.value.substr(38)}`;
|
|
81
|
+
debug(` Update 008/35-37: '${currLang}' => 'smi'`);
|
|
59
82
|
return createReport([origValue], [f008.value]);
|
|
60
83
|
}
|
|
84
|
+
|
|
85
|
+
function processField(f) {
|
|
86
|
+
f.subfields = processSubfields(f.subfields, []);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function processSubfields(incomingSubfields, outgoingSubfields = []) {
|
|
90
|
+
const [currSubfield, ...otherSubfields] = incomingSubfields;
|
|
91
|
+
if (!currSubfield) {
|
|
92
|
+
return outgoingSubfields;
|
|
93
|
+
}
|
|
94
|
+
if (!isRelevantSamiSubfield(currSubfield, [...outgoingSubfields, ...otherSubfields])) {
|
|
95
|
+
return processSubfields(otherSubfields, [...outgoingSubfields, currSubfield]);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const smiSubfield = {
|
|
99
|
+
code: currSubfield.code,
|
|
100
|
+
value: 'smi'
|
|
101
|
+
};
|
|
102
|
+
debug(` f041: Add '\$${currSubfield.code} smi' before '${currSubfield.value}'`);
|
|
103
|
+
|
|
104
|
+
return processSubfields(otherSubfields, [...outgoingSubfields, smiSubfield, currSubfield]);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function isRelevantField(f) {
|
|
108
|
+
if (f.tag !== '041' || !f.subfields || f.subfields.some(sf => sf.code === '2')) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
return f.subfields.some(sf => isRelevantSamiSubfield(sf, f.subfields)); // it's ok to pass sf in f.subfields also
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function isRelevantSamiSubfield(sf, otherSubfields) {
|
|
115
|
+
// NB! preceding 'smi' is added to all $a and $d fields, regardless of the LDR/06 value! (However, copying 041$a/d -> 008/35-37 depends on LDR/06)
|
|
116
|
+
if (!subfieldCodesUsingSmi.includes(sf.code) || !samiLanguages.includes(sf.value)) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
if (otherSubfields.some(sf2 => sf2.code === sf.code && sf2.value === 'smi')) { // fail if 'smi' already exists
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
//debug(` '\${sf.code} ${sf.value}' requires preceding 'smi'`);
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
61
125
|
}
|
|
62
126
|
|
|
63
127
|
function createReport(origArray, modArray) {
|
|
@@ -72,42 +136,10 @@ export default function () {
|
|
|
72
136
|
return fix(record, true);
|
|
73
137
|
}
|
|
74
138
|
|
|
75
|
-
function processField(f) {
|
|
76
|
-
f.subfields = prosessSubfields(f.subfields);
|
|
77
|
-
return f;
|
|
78
|
-
}
|
|
79
139
|
|
|
80
|
-
function prosessSubfields(incomingSubfields, outgoingSubfields = []) {
|
|
81
|
-
const [currSubfield, ...otherSubfields] = incomingSubfields;
|
|
82
|
-
if (!currSubfield) {
|
|
83
|
-
return outgoingSubfields;
|
|
84
|
-
}
|
|
85
|
-
if (!isRelevantSamiSubfield(currSubfield, [...outgoingSubfields, ...otherSubfields])) {
|
|
86
|
-
return prosessSubfields(otherSubfields, [...outgoingSubfields, currSubfield]);
|
|
87
|
-
}
|
|
88
140
|
|
|
89
|
-
const smiSubfield = {
|
|
90
|
-
code: currSubfield.code,
|
|
91
|
-
value: 'smi'
|
|
92
|
-
};
|
|
93
|
-
return prosessSubfields(otherSubfields, [...outgoingSubfields, smiSubfield, currSubfield]);
|
|
94
|
-
}
|
|
95
141
|
|
|
96
|
-
function isRelevantField(f) {
|
|
97
|
-
if (f.tag !== '041' || !f.subfields || f.subfields.some(sf => sf.code === '2')) {
|
|
98
|
-
return false;
|
|
99
|
-
}
|
|
100
|
-
return f.subfields.some(sf => isRelevantSamiSubfield(sf, f.subfields)); // it's ok to pass sf in f.subfields also
|
|
101
|
-
}
|
|
102
142
|
|
|
103
|
-
|
|
104
|
-
if (!relevantSubfieldCodes.includes(sf.code) || !samiLanguages.includes(sf.value)) {
|
|
105
|
-
return false;
|
|
106
|
-
}
|
|
107
|
-
if (otherSubfields.some(sf2 => sf2.code === sf.code && sf2.value === 'smi')) {
|
|
108
|
-
return false;
|
|
109
|
-
}
|
|
110
|
-
return true;
|
|
111
|
-
}
|
|
143
|
+
|
|
112
144
|
}
|
|
113
145
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_validationOptions": {},
|
|
3
|
-
"leader": "",
|
|
3
|
+
"leader": "012345j78901234567894500",
|
|
4
4
|
"fields": [
|
|
5
5
|
{ "tag": "041", "ind1": " ", "ind2": " ", "subfields": [ { "code": "a", "value": "eng" } ]},
|
|
6
6
|
{ "tag": "041", "ind1": "1", "ind2": "7", "subfields": [ { "code": "a", "value": "smi" }, {"code": "2", "value": "iso-639-3"} ]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_validationOptions": {},
|
|
3
|
+
"leader": "01234ci789012345678 2500",
|
|
4
|
+
"fields": [
|
|
5
|
+
{ "tag": "008", "value": "01234567890123456789012345678901234|||89" },
|
|
6
|
+
{ "tag": "041", "ind1": " ", "ind2": " ",
|
|
7
|
+
"subfields": [ { "code": "a", "value": "smi" }, { "code": "a", "value": "sme" } ]
|
|
8
|
+
}
|
|
9
|
+
]
|
|
10
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"leader": "01234ci789012345678 2500",
|
|
3
|
+
"fields": [
|
|
4
|
+
{ "tag": "008", "value": "01234567890123456789012345678901234|||89" },
|
|
5
|
+
{ "tag": "041", "ind1": " ", "ind2": " ",
|
|
6
|
+
"subfields": [ { "code": "a", "value": "smi" }, { "code": "a", "value": "sme" } ]
|
|
7
|
+
}
|
|
8
|
+
]
|
|
9
|
+
}
|