@natlibfi/marc-record-validators-melinda 12.0.0-alpha.8 → 12.0.0-alpha.9

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/isbn-issn.js CHANGED
@@ -23,8 +23,12 @@ export default ({ hyphenateISBN = false, handleInvalid = false } = {}) => {
23
23
  }
24
24
  function invalidISBN(isbn) {
25
25
  const isbnOnly = getFirstWord(isbn);
26
- const auditedIsbn = ISBN.audit(isbnOnly);
27
- return !auditedIsbn.validIsbn;
26
+ try {
27
+ const auditedIsbn = ISBN.audit(isbnOnly);
28
+ return !auditedIsbn.validIsbn;
29
+ } catch {
30
+ return true;
31
+ }
28
32
  }
29
33
  function invalidSubfield(subfield) {
30
34
  if (subfield.code !== "a") {
@@ -184,8 +188,7 @@ export default ({ hyphenateISBN = false, handleInvalid = false } = {}) => {
184
188
  }
185
189
  function normalizeIsbnValue(value) {
186
190
  const trimmedValue = getFirstWord(value);
187
- const auditResult = ISBN.audit(trimmedValue);
188
- if (!auditResult.validIsbn) {
191
+ if (invalidISBN(trimmedValue)) {
189
192
  return void 0;
190
193
  }
191
194
  const numbersOnly = trimmedValue.replace(/[^0-9Xx]+/ug, "");
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/isbn-issn.js"],
4
- "sourcesContent": ["import ISBN from 'isbn3';\nimport validateISSN from '@natlibfi/issn-verify';\n\n// handleInvalid: move invalid 020$a to 020$z, and invalid 022$a to 022$y\nexport default ({hyphenateISBN = false, handleInvalid = false} = {}) => {\n return {\n validate, fix,\n description: 'Validates ISBN and ISSN values'\n };\n\n function stringHasSpace(str) {\n return str.indexOf(' ') > -1;\n }\n\n function trimSpaces(value) {\n return value.replace(/^\\s+/u, '').replace(/\\s+$/u, '').replace(/\\s+/gu, ' ');\n }\n\n function isMultiWord(inputString) {\n const trimmedString = trimSpaces(inputString);\n return stringHasSpace(trimmedString);\n }\n\n function getFirstWord(inputString) {\n const trimmedString = trimSpaces(inputString);\n const arr = trimmedString.split(' ');\n return arr[0];\n }\n\n function invalidISBN(isbn) {\n const isbnOnly = getFirstWord(isbn);\n const auditedIsbn = ISBN.audit(isbnOnly);\n return !auditedIsbn.validIsbn;\n }\n\n function invalidSubfield(subfield) {\n if (subfield.code !== 'a') {\n return false;\n }\n return invalidISBN(subfield.value) || isMultiWord(subfield.value);\n }\n\n\n function invalidField020(field) {\n if (field.subfields && field.subfields.some(sf => invalidSubfield(sf))) {\n return true;\n }\n return false;\n }\n\n function subfieldsIsbnRequiresHyphenation(subfield) {\n if (!hyphenateISBN || !['a', 'z'].includes(subfield.code)) {\n return false;\n }\n\n const isbn = getFirstWord(subfield.value);\n if (subfield.code === 'a') {\n return requiresHyphenation(isbn);\n }\n\n // $z is a bit hacky: hyphenation is required only iff valid and no '-' chars\n if (isbn.indexOf('-') > -1) {\n return false;\n }\n return !invalidISBN(isbn);\n\n function requiresHyphenation(isbn) {\n if (!hyphenateISBN) {\n return false;\n }\n // Handle old notation such as \"978-952-396-001-5 (nid.)\"\n const isbn2 = getFirstWord(isbn);\n\n if (invalidISBN(isbn2)) {\n return false;\n }\n\n const parsedIsbn = ISBN.parse(isbn2);\n // Return true only if existing ISBN is a valid and hyphenated 10 or 13 digit ISBN:\n return !(isbn2 === parsedIsbn.isbn10h || isbn2 === parsedIsbn.isbn13h);\n }\n }\n\n function getRelevantFields(record) {\n //return record.get(/^(?:020|022)$/u).filter(field => {\n return record.fields.filter(field => {\n if (!field.subfields) {\n return false;\n }\n // Check ISBN:\n if (field.tag === '020') {\n if (invalidField020(field)) { // checks multiwordness\n return true;\n }\n return fieldsIsbnRequiresHyphenation(field);\n }\n\n // Check ISSN:\n if (field.tag === '022') {\n if (invalidField022(field)) {\n return true;\n }\n\n const subfield = field.subfields.find(sf => sf.code === 'a' || sf.code === 'l');\n\n return !validateISSN(subfield.value);\n }\n return false;\n });\n\n function fieldsIsbnRequiresHyphenation(field) {\n return field.subfields && field.subfields.some(sf => subfieldsIsbnRequiresHyphenation(sf));\n }\n\n function invalidField022(field) {\n const subfieldAorL = field.subfields.find(sf => sf.code === 'a' || sf.code === 'l');\n\n if (subfieldAorL === undefined) {\n const subfieldY = field.subfields.find(sf => sf.code === 'y');\n if (subfieldY) {\n return false;\n }\n\n return true;\n }\n return false;\n }\n }\n\n function validate(record) {\n const fields = getRelevantFields(record);\n\n if (fields.length === 0) {\n return {valid: true};\n }\n\n return fields\n .map(field => {\n if (field.tag === '020') {\n const subfieldA = field.subfields.find(sf => sf.code === 'a');\n if (subfieldA) {\n return {name: 'ISBN', value: subfieldA.value};\n }\n const subfieldZ = field.subfields.find(sf => sf.code === 'z');\n if (subfieldZ) {\n return {name: 'ISBN (subfield Z)', value: subfieldZ.value};\n }\n\n return {name: 'ISBN', value: undefined};\n }\n\n return {name: 'ISSN', value: getISSN()};\n\n function getISSN() {\n const subfieldAorL = field.subfields.find(sf => sf.code === 'a' || sf.code === 'l');\n\n if (subfieldAorL) {\n return subfieldAorL.value;\n }\n\n return undefined;\n }\n })\n .reduce((acc, obj) => {\n const {name, value} = obj;\n const msg = `${name} (${value}) is not valid`;\n\n return {...acc, messages: acc.messages.concat(msg)};\n }, {valid: false, messages: []});\n }\n\n\n function fix(record) {\n getRelevantFields(record).forEach(field => {\n if (field.tag === '020') {\n field.subfields.forEach(subfield => fixField020Subfield(field, subfield));\n return;\n }\n // 022 ISSN:\n const subfield = field.subfields.find(sf => sf.code === 'a' || sf.code === 'l');\n if (subfield && handleInvalid) {\n // $a/$l => $y (bit overkill to add $z and remove $a/$l instead of just renaming)\n field.subfields.push({code: 'y', value: subfield.value});\n record.removeSubfield(subfield, field);\n }\n });\n\n\n function fixField020Subfield(field, subfield) {\n split020A(); // subfield and field are in the scope\n addHyphens(subfield);\n handleInvalidIsbn(field, subfield); // remove 020$a, add 020$z, Do this last, as it uses deletion\n return;\n\n function addHyphens(subfield) {\n if (!subfieldsIsbnRequiresHyphenation(subfield)) {\n return;\n }\n // ISBN is valid but is missing hyphens\n const normalizedValue = normalizeIsbnValue(subfield.value);\n if (normalizedValue !== undefined) {\n subfield.value = normalizedValue;\n }\n }\n\n function handleInvalidIsbn(field, subfield) {\n if (subfield.code !== 'a' || !handleInvalid) {\n return;\n }\n const head = getFirstWord(subfield.value);\n if (!invalidISBN(head)) {\n return;\n }\n // $a => $z (bit overkill to add $z and remove $a instead of just renaming, but too lazy to fix/test thorougly)\n field.subfields.push({code: 'z', value: subfield.value});\n record.removeSubfield(subfield, field);\n }\n\n function split020A() {\n // Move non-initial words from $a to $q:\n if (subfield.code !== 'a') {\n return;\n }\n const value = trimSpaces(subfield.value);\n const position = value.indexOf(' ');\n if (position === -1) {\n return;\n }\n const head = getFirstWord(value);\n if (invalidISBN(head)) { // Don't split, if first word ain't ISBN\n return;\n }\n const tail = value.substring(position + 1);\n subfield.value = head;\n field.subfields.push({code: 'q', value: tail});\n }\n\n function normalizeIsbnValue(value) {\n const trimmedValue = getFirstWord(value);\n //const trimmedValue = trimISBN(value); // NB! This might lose information that should be stored in $q...\n const auditResult = ISBN.audit(trimmedValue);\n if (!auditResult.validIsbn) {\n return undefined;\n }\n const numbersOnly = trimmedValue.replace(/[^0-9Xx]+/ug, '');\n const parsedIsbn = ISBN.parse(trimmedValue);\n if (hyphenateISBN) {\n return numbersOnly.length === 10 ? parsedIsbn.isbn10h : parsedIsbn.isbn13h;\n }\n return numbersOnly.length === 10 ? parsedIsbn.isbn10 : parsedIsbn.isbn13;\n }\n }\n }\n};\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import ISBN from 'isbn3';\nimport validateISSN from '@natlibfi/issn-verify';\n\n// handleInvalid: move invalid 020$a to 020$z, and invalid 022$a to 022$y\nexport default ({hyphenateISBN = false, handleInvalid = false} = {}) => {\n return {\n validate, fix,\n description: 'Validates ISBN and ISSN values'\n };\n\n function stringHasSpace(str) {\n return str.indexOf(' ') > -1;\n }\n\n function trimSpaces(value) {\n return value.replace(/^\\s+/u, '').replace(/\\s+$/u, '').replace(/\\s+/gu, ' ');\n }\n\n function isMultiWord(inputString) {\n const trimmedString = trimSpaces(inputString);\n return stringHasSpace(trimmedString);\n }\n\n function getFirstWord(inputString) {\n const trimmedString = trimSpaces(inputString);\n const arr = trimmedString.split(' ');\n return arr[0];\n }\n\n function invalidISBN(isbn) {\n const isbnOnly = getFirstWord(isbn);\n try {\n const auditedIsbn = ISBN.audit(isbnOnly);\n return !auditedIsbn.validIsbn;\n }\n catch {\n return true;\n }\n\n }\n\n function invalidSubfield(subfield) {\n if (subfield.code !== 'a') {\n return false;\n }\n return invalidISBN(subfield.value) || isMultiWord(subfield.value);\n }\n\n\n function invalidField020(field) {\n if (field.subfields && field.subfields.some(sf => invalidSubfield(sf))) {\n return true;\n }\n return false;\n }\n\n function subfieldsIsbnRequiresHyphenation(subfield) {\n if (!hyphenateISBN || !['a', 'z'].includes(subfield.code)) {\n return false;\n }\n\n const isbn = getFirstWord(subfield.value);\n if (subfield.code === 'a') {\n return requiresHyphenation(isbn);\n }\n\n // $z is a bit hacky: hyphenation is required only iff valid and no '-' chars\n if (isbn.indexOf('-') > -1) {\n return false;\n }\n return !invalidISBN(isbn);\n\n function requiresHyphenation(isbn) {\n if (!hyphenateISBN) {\n return false;\n }\n // Handle old notation such as \"978-952-396-001-5 (nid.)\"\n const isbn2 = getFirstWord(isbn);\n\n if (invalidISBN(isbn2)) {\n return false;\n }\n\n const parsedIsbn = ISBN.parse(isbn2);\n // Return true only if existing ISBN is a valid and hyphenated 10 or 13 digit ISBN:\n return !(isbn2 === parsedIsbn.isbn10h || isbn2 === parsedIsbn.isbn13h);\n }\n }\n\n function getRelevantFields(record) {\n //return record.get(/^(?:020|022)$/u).filter(field => {\n return record.fields.filter(field => {\n if (!field.subfields) {\n return false;\n }\n // Check ISBN:\n if (field.tag === '020') {\n if (invalidField020(field)) { // checks multiwordness\n return true;\n }\n return fieldsIsbnRequiresHyphenation(field);\n }\n\n // Check ISSN:\n if (field.tag === '022') {\n if (invalidField022(field)) {\n return true;\n }\n\n const subfield = field.subfields.find(sf => sf.code === 'a' || sf.code === 'l');\n\n return !validateISSN(subfield.value);\n }\n return false;\n });\n\n function fieldsIsbnRequiresHyphenation(field) {\n return field.subfields && field.subfields.some(sf => subfieldsIsbnRequiresHyphenation(sf));\n }\n\n function invalidField022(field) {\n const subfieldAorL = field.subfields.find(sf => sf.code === 'a' || sf.code === 'l');\n\n if (subfieldAorL === undefined) {\n const subfieldY = field.subfields.find(sf => sf.code === 'y');\n if (subfieldY) {\n return false;\n }\n\n return true;\n }\n return false;\n }\n }\n\n function validate(record) {\n const fields = getRelevantFields(record);\n\n if (fields.length === 0) {\n return {valid: true};\n }\n\n return fields\n .map(field => {\n if (field.tag === '020') {\n const subfieldA = field.subfields.find(sf => sf.code === 'a');\n if (subfieldA) {\n return {name: 'ISBN', value: subfieldA.value};\n }\n const subfieldZ = field.subfields.find(sf => sf.code === 'z');\n if (subfieldZ) {\n return {name: 'ISBN (subfield Z)', value: subfieldZ.value};\n }\n\n return {name: 'ISBN', value: undefined};\n }\n\n return {name: 'ISSN', value: getISSN()};\n\n function getISSN() {\n const subfieldAorL = field.subfields.find(sf => sf.code === 'a' || sf.code === 'l');\n\n if (subfieldAorL) {\n return subfieldAorL.value;\n }\n\n return undefined;\n }\n })\n .reduce((acc, obj) => {\n const {name, value} = obj;\n const msg = `${name} (${value}) is not valid`;\n\n return {...acc, messages: acc.messages.concat(msg)};\n }, {valid: false, messages: []});\n }\n\n\n function fix(record) {\n getRelevantFields(record).forEach(field => {\n if (field.tag === '020') {\n field.subfields.forEach(subfield => fixField020Subfield(field, subfield));\n return;\n }\n // 022 ISSN:\n const subfield = field.subfields.find(sf => sf.code === 'a' || sf.code === 'l');\n if (subfield && handleInvalid) {\n // $a/$l => $y (bit overkill to add $z and remove $a/$l instead of just renaming)\n field.subfields.push({code: 'y', value: subfield.value});\n record.removeSubfield(subfield, field);\n }\n });\n\n\n function fixField020Subfield(field, subfield) {\n split020A(); // subfield and field are in the scope\n addHyphens(subfield);\n handleInvalidIsbn(field, subfield); // remove 020$a, add 020$z, Do this last, as it uses deletion\n return;\n\n function addHyphens(subfield) {\n if (!subfieldsIsbnRequiresHyphenation(subfield)) {\n return;\n }\n // ISBN is valid but is missing hyphens\n const normalizedValue = normalizeIsbnValue(subfield.value);\n if (normalizedValue !== undefined) {\n subfield.value = normalizedValue;\n }\n }\n\n function handleInvalidIsbn(field, subfield) {\n if (subfield.code !== 'a' || !handleInvalid) {\n return;\n }\n const head = getFirstWord(subfield.value);\n if (!invalidISBN(head)) {\n return;\n }\n // $a => $z (bit overkill to add $z and remove $a instead of just renaming, but too lazy to fix/test thorougly)\n field.subfields.push({code: 'z', value: subfield.value});\n record.removeSubfield(subfield, field);\n }\n\n function split020A() {\n // Move non-initial words from $a to $q:\n if (subfield.code !== 'a') {\n return;\n }\n const value = trimSpaces(subfield.value);\n const position = value.indexOf(' ');\n if (position === -1) {\n return;\n }\n const head = getFirstWord(value);\n if (invalidISBN(head)) { // Don't split, if first word ain't ISBN\n return;\n }\n const tail = value.substring(position + 1);\n subfield.value = head;\n field.subfields.push({code: 'q', value: tail});\n }\n\n function normalizeIsbnValue(value) {\n const trimmedValue = getFirstWord(value);\n //const trimmedValue = trimISBN(value); // NB! This might lose information that should be stored in $q...\n if (invalidISBN(trimmedValue)) {\n return undefined; // should this return value (= nothing normalized), not undefined?\n }\n const numbersOnly = trimmedValue.replace(/[^0-9Xx]+/ug, '');\n const parsedIsbn = ISBN.parse(trimmedValue);\n if (hyphenateISBN) {\n return numbersOnly.length === 10 ? parsedIsbn.isbn10h : parsedIsbn.isbn13h;\n }\n return numbersOnly.length === 10 ? parsedIsbn.isbn10 : parsedIsbn.isbn13;\n }\n }\n }\n};\n"],
5
+ "mappings": "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",
6
6
  "names": ["isbn", "isbn2", "subfield", "field"]
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.0-alpha.8",
17
+ "version": "12.0.0-alpha.9",
18
18
  "main": "./dist/index.js",
19
19
  "publishConfig": {
20
20
  "access": "public"
@@ -44,7 +44,7 @@
44
44
  "cld3-asm": "^4.0.0",
45
45
  "clone": "^2.1.2",
46
46
  "debug": "^4.4.3",
47
- "isbn3": "1.2.15",
47
+ "isbn3": "^2.0.0",
48
48
  "langs": "^2.0.0",
49
49
  "undici": "^7.16.0",
50
50
  "xml2js": "^0.6.2",
package/src/isbn-issn.js CHANGED
@@ -29,8 +29,14 @@ export default ({hyphenateISBN = false, handleInvalid = false} = {}) => {
29
29
 
30
30
  function invalidISBN(isbn) {
31
31
  const isbnOnly = getFirstWord(isbn);
32
- const auditedIsbn = ISBN.audit(isbnOnly);
33
- return !auditedIsbn.validIsbn;
32
+ try {
33
+ const auditedIsbn = ISBN.audit(isbnOnly);
34
+ return !auditedIsbn.validIsbn;
35
+ }
36
+ catch {
37
+ return true;
38
+ }
39
+
34
40
  }
35
41
 
36
42
  function invalidSubfield(subfield) {
@@ -238,9 +244,8 @@ export default ({hyphenateISBN = false, handleInvalid = false} = {}) => {
238
244
  function normalizeIsbnValue(value) {
239
245
  const trimmedValue = getFirstWord(value);
240
246
  //const trimmedValue = trimISBN(value); // NB! This might lose information that should be stored in $q...
241
- const auditResult = ISBN.audit(trimmedValue);
242
- if (!auditResult.validIsbn) {
243
- return undefined;
247
+ if (invalidISBN(trimmedValue)) {
248
+ return undefined; // should this return value (= nothing normalized), not undefined?
244
249
  }
245
250
  const numbersOnly = trimmedValue.replace(/[^0-9Xx]+/ug, '');
246
251
  const parsedIsbn = ISBN.parse(trimmedValue);