Mobrovac has submitted this change and it was merged. ( https://gerrit.wikimedia.org/r/355097 )
Change subject: Use marcXML translator in addition to dc for ISBN ...................................................................... Use marcXML translator in addition to dc for ISBN Request both dublin core and marcXML data from WorldCat, as marcXML lacks an itemType field, and dublinCore lacks edition and publisher fields. Also fixes some bugs in dublin core translator which were missing some author fields. Add "overwriteAuthors" parameter to Translator; this allows multiple translators to be used on a creators field. Must be used with caution as it make cause duplicate authors. Fix extendGeneral method in translators/util/ which used the same key (contributors) in the translator. Bug: T155161 Change-Id: I58489d2959306b620f9bfa4a5bfb2a81ea7cb4a4 --- M lib/CitoidService.js M lib/Translator.js M lib/XMLReader.js M lib/translators/README.md M lib/translators/bePress.js M lib/translators/coins.js M lib/translators/dublinCore.js M lib/translators/general.js A lib/translators/marcXML.js D lib/translators/template.js.txt M lib/translators/util/index.js M test/features/scraping/isbn.js R test/features/unit/translator.js M test/features/unit/translators/coins.js M test/features/unit/translators/general.js M test/features/unit/translators/util.js 16 files changed, 771 insertions(+), 183 deletions(-) Approvals: Mobrovac: Verified; Looks good to me, approved jenkins-bot: Verified diff --git a/lib/CitoidService.js b/lib/CitoidService.js index 3e234c7..b41f68e 100644 --- a/lib/CitoidService.js +++ b/lib/CitoidService.js @@ -517,8 +517,13 @@ citation.format = cr.format; citation.doi = cr.doi; - var wskeyFormat = 'dc'; var self = this; + + var dcXML; + var scrapeDC; + + var marcXML; + var scrapeMARC; // Set responses if below is rejected function reject(){ @@ -532,16 +537,38 @@ return cr; } - // Make request to WorldCat srn index service - return this.worldCatService.singleRecordRequest(citation.isbn, 'isbn', wskeyFormat).then( - function(body){ - return self.scrapeXML(citation, cr, body, wskeyFormat); + dcXML = this.worldCatService.singleRecordRequest(citation.isbn, 'isbn', 'dc'); + marcXML = this.worldCatService.singleRecordRequest(citation.isbn, 'isbn', 'marc'); + + // Make concurrent requests for the data in both Dublin Core and MarcXML + return BBPromise.all([dcXML, marcXML]).then(function(results){ + + // Promises for scraping results from each of dc and marc + scrapeDC = self.scrapeXML(citation, cr, results[0], 'dc', true); // Boolean at end allows multiple creators translators to be used within the dc translator + scrapeMARC = self.scrapeXML(citation, cr, results[1], 'marc'); + + // Scrape dc first because it can determine type + return scrapeDC.then(function(){ + return scrapeMARC.then(function(){ + citation.responseCode = 200; + citation.source.push('WorldCat'); + return cr; + }, + // If rejected by scrapeMARC, still send 200 because DC was successfully added + function(){ + citation.responseCode = 200; + citation.source.push('WorldCat'); + return cr; + }); }, - // Rejection handler + // If unable to scrape DC, reject. function(){ - return reject(); - } - ); + reject(); + }); + }, + function(){ + reject(); + }); }; @@ -622,8 +649,8 @@ * @param {String} wskeyFormat Format the XML citation will come back in. Can be 'dc', 'marcXML', or WorldCat's native 'openSearch' format * @return {Object} BBPromise for CitoidRequest object */ -CitoidService.prototype.scrapeXML = function(citation, cr, xml, wskeyFormat){ - return this.xml.translate(citation, cr, xml, wskeyFormat); +CitoidService.prototype.scrapeXML = function(citation, cr, xml, wskeyFormat, creatorOverwrite){ + return this.xml.translate(citation, cr, xml, wskeyFormat, creatorOverwrite); }; module.exports = CitoidService; diff --git a/lib/Translator.js b/lib/Translator.js index 8a9b562..f2dd75c 100644 --- a/lib/Translator.js +++ b/lib/Translator.js @@ -18,21 +18,37 @@ * specific type, and a translator specific to that metadata type * @param {Object} metadata flat metadata object (i.e. metadata.openGraph) * @param {Object} translator + * @param {Boolean} creatorOverwrite whether or not unique creator translators can be run multiply */ -Translator.prototype.translate = function(citation, metadata, translator){ +Translator.prototype.translate = function(citation, metadata, translator, creatorOverwrite){ var logger = this.logger; if (!translator || !metadata){return citation;} var property; - Object.keys(metadata).forEach(function(key){ // Loop through results - property = translator[key]; // Look up property in translator - if (property && !citation[property.name]){ // If it has a corresponding translation and won't overwrite properties already set - try { - citation = property.translate(citation, metadata, key); - } catch (e) { - logger.log('debug/scraper', "Failed to translate property " + property.name); + var creatorSubnames = []; // Store types of creators already added + var useCreatorTranslator = false; // Bool for whether a creator translator should be used. + + for (var key in metadata) { + if (metadata.hasOwnProperty(key)) { // Loop through properties of metadata Obj + property = translator[key]; // Look up property in the translator to find the translator function specific to the field + if (!property){continue;} // Skip rest of loop if undefined + // Set bool to determine if current translator is a non-duplicate creators translator subname + if (creatorOverwrite && property.name && property.name === 'creators' && property.subname){ + if (creatorSubnames.indexOf(property.subname)=== -1){ // Run translator if not already in array + useCreatorTranslator = true; + creatorSubnames.push(property.subname); // i.e. 'author' or 'contributor' + } + } + // Don't overwrite properties already set; only allows translator to be run only if it's a non-duplicate creator subtype + if (!citation[property.name] || useCreatorTranslator){ + try { + citation = property.translate(citation, metadata, key); + useCreatorTranslator = false; // Set to false for next iteration + } catch (e) { + logger.log('debug/translator', "Failed to translate property " + property.name); + } } } - }); + } return citation; }; diff --git a/lib/XMLReader.js b/lib/XMLReader.js index 7812099..40c003b 100644 --- a/lib/XMLReader.js +++ b/lib/XMLReader.js @@ -8,6 +8,7 @@ */ var dc = require('./translators/dublinCore.js'); var BBPromise = require('bluebird'); +var marc = require('./translators/marcXML.js'); var xml2js = BBPromise.promisifyAll(require('xml2js')); /** @@ -19,8 +20,8 @@ this.translator = translator; }; -// Process XML which has been converted to a JS obj -function process(jsobj){ +// Process XML which has been converted to a JS obj from DC metadata +function processDC(jsobj){ var record = {}; var recordIDS; var newKey; @@ -56,7 +57,7 @@ return record; } -// Return an itemType given a record jsobj +// Return an itemType given a record jsobj from DC metadata function getItemType(record){ var itemType; // Types for worldcat search API dublincore records @@ -83,49 +84,110 @@ return itemType; } -XMLReader.prototype.translate = function(citationObj, cr, xml, wskeyFormat){ +// Process MarcXML which has been converted to a JS obj +function processMARCXML(jsobj){ + var key; + var value; + var code; + var record = {}; + var i; + var j; + var item; + var subitem; + var trailing = /\s*[\/:;.]*\s*$/; // Regex for trailing punct and white space + for (i = 0; i < jsobj.length; i++){ + item = jsobj[i]; + var tag = item.$.tag; + if (item.subfield){ + for (j = 0; j < item.subfield.length; j++){ + subitem = item.subfield[j]; + code = subitem.$.code; + value = subitem._.replace(trailing, ''); //Remove trailing punctuation and white space + + key = code + tag; // Create key out of tag and subfield code + if (!record[key]){ // If undef, def new key + record[key] = [value]; // Put in Array since same tag/code entry is allowed + } else { + record[key].push(value); // If key already exists, add new value + } + } + } else { + key = tag; + value = item._; + if (!record[key]){ // If undef, def new key + record[key] = [value]; // Put in Array since same tag/code entry is allowed + } else { + record[key].push(value); // If key already exists, add new value + } + } + + } + return record; +} + +// Return an itemType given a MarcXML record JS obj +function getMARCItemType(record){ + var itemType = 'book'; // MarcXML unfortnately does not report the item type, default to book + return itemType; +} + +XMLReader.prototype.translate = function(citationObj, cr, xml, wskeyFormat, creatorOverwrite){ var content = citationObj.content; var translate = this.translator.translate; - var itemType; + var message = 'Unable to retrieve data from ISBN ' + citationObj.isbn; var xmlreader = this; - var record; - var message; - var error; - function reject(){ - error = {Error: message}; - citationObj.responseCode = 404; - citationObj.error = error; - return cr; - } + var itemType; + var record; + var controlfields; return xml2js.parseStringAsync(xml).then(function(result) { - if (result && result.oclcdcs) { - record = process(result.oclcdcs); - content.itemType = getItemType(record); - // dublinCore.js translator properties - content = translate(content, record, dc[content.itemType]); - // Add OCLC number to response, url, and oclc fields - if (record.oclc){ - citationObj.oclc = record.oclc; - content.oclc = record.oclc; - content.url = 'https://www.worldcat.org/oclc/' + record.oclc; + if (wskeyFormat === 'dc'){ + if (result && result.oclcdcs) { + record = processDC(result.oclcdcs); + if (!content.itemType) { + content.itemType = getItemType(record); + } + + // dublinCore.js translator properties; won't overwrite previous values + content = translate(content, record, dc[content.itemType], creatorOverwrite); + + // Add OCLC number to response, url, and oclc fields; may overwrite previous values + if (record.oclc){ + citationObj.oclc = record.oclc; + content.oclc = record.oclc; + content.url = 'https://www.worldcat.org/oclc/' + record.oclc; + } + + return cr; + } else { + return BBPromise.reject(message); } + } else if (wskeyFormat === 'marc'){ + if (result && result.record && result.record.datafield) { + record = processMARCXML(result.record.datafield, record); + if (!content.itemType){ + content.itemType = getMARCItemType(record); + } + controlfields = processMARCXML(result.record.controlfield); + content = translate(content, record, marc[content.itemType], creatorOverwrite); - citationObj.responseCode = 200; - citationObj.source.push('WorldCat'); + // Add OCLC number to response, url, and oclc fields + content.oclc = controlfields['001'][0]; + content.url = 'https://www.worldcat.org/oclc/' + content.oclc; - return cr; - } else { - message = 'Unable to retrieve data from ISBN ' + citationObj.isbn; - return reject(); + citationObj.oclc = content.oclc; + + return cr; + } else { + return BBPromise.reject(message); + } } - }) .catch(function (err) { xmlreader.logger.log('debug/ISBN', err); - return reject(); + return BBPromise.reject(message); }); }; diff --git a/lib/translators/README.md b/lib/translators/README.md index ea123e2..10bada0 100644 --- a/lib/translators/README.md +++ b/lib/translators/README.md @@ -9,6 +9,4 @@ Each translator here corresponds to a type of metadata found in [html-metadata node library](https://github.com/wikimedia/html-metadata). The name of the file matches the keys found in the Object [metadataFunctions](https://github.com/wikimedia/html-metadata/blob/master/lib/index.js) in the library. -A template for writing new translators is found in template.js.txt. - Utility functions that are used across translators are found in ./util. \ No newline at end of file diff --git a/lib/translators/bePress.js b/lib/translators/bePress.js index 18072b3..388d6db 100644 --- a/lib/translators/bePress.js +++ b/lib/translators/bePress.js @@ -33,7 +33,7 @@ // Shortcut for extendWithCreators utility function extendWithCreators(creatorName){ - return extendGeneral(exports.general, creatorName); + return extendGeneral(exports.general, creatorName, 'author'); } // Create a general type with the author in the creator field once since it is used many times. diff --git a/lib/translators/coins.js b/lib/translators/coins.js index 5c178b0..f97db93 100644 --- a/lib/translators/coins.js +++ b/lib/translators/coins.js @@ -3,7 +3,6 @@ var ex = require('../Exporter.js'); var ut = require('./util/index.js'); -var eg = ut.extendGeneral; var generateCreatorObj = ut.generateCreatorObj; var makeTranslator = ut.makeTranslator; var makeListTranslator = ut.makeListTranslator; @@ -38,11 +37,6 @@ title: makeTranslator('title'), date: makeTranslator('date', fixDate) }; - -// Shortcut for extendGeneral utility -function extendGeneral(creatorName){ - return eg(exports.general, creatorName); -} /** * Methods that are used by multiple types diff --git a/lib/translators/dublinCore.js b/lib/translators/dublinCore.js index c2e1c7c..95c4134 100644 --- a/lib/translators/dublinCore.js +++ b/lib/translators/dublinCore.js @@ -8,8 +8,6 @@ var makeTranslator = ut.makeTranslator; var makeCreatorsTranslator = ut.makeCreatorsTranslator; -var eg = ut.extendGeneral; - /** * Dublin core type values : Zotero type field values @@ -35,40 +33,54 @@ * Object with fields common to all but a few types * @type {Object} */ -exports.general = { +exports.generalWithAuthor = { title: makeTranslator('title'), date: makeTranslator('date', fixDate), language: makeTranslator('language', fixLang), abstract: makeTranslator('abstractNote'), + creator: makeCreatorsTranslator('author'), contributor: makeCreatorsTranslator('contributor') }; - -/* Function to add arbitrary creator function to the exports.general obj*/ -function extendGeneral(creatorName){ - return eg(exports.general, creatorName); -} - -// Create frequently used general types once. -exports.generalWithAuthor = extendGeneral('author'); exports.generalWithAuthorAndPublisher = Object.assign({}, exports.generalWithAuthor, { publisher: makeTranslator('publisher') }); /* Complete list of Zotero types with field translators in the Object */ -exports.artwork = extendGeneral('artist'); +exports.artwork = { + title: makeTranslator('title'), + date: makeTranslator('date', fixDate), + language: makeTranslator('language', fixLang), + abstract: makeTranslator('abstractNote'), + creator: makeCreatorsTranslator('artist'), + contributor: makeCreatorsTranslator('contributor') +}; exports.attachment = { title: makeTranslator('title') }; -exports.audioRecording = Object.assign({}, extendGeneral('performer'), { +exports.audioRecording = { + title: makeTranslator('title'), + date: makeTranslator('date', fixDate), + language: makeTranslator('language', fixLang), + abstract: makeTranslator('abstractNote'), + creator: makeCreatorsTranslator('performer'), + contributor: makeCreatorsTranslator('contributor'), publisher: makeTranslator('label') -}); -exports.bill = extendGeneral('sponsor'); +}; +exports.bill = { + title: makeTranslator('title'), + date: makeTranslator('date', fixDate), + language: makeTranslator('language', fixLang), + abstract: makeTranslator('abstractNote'), + creator: makeCreatorsTranslator('sponsor'), + contributor: makeCreatorsTranslator('contributor') +}; exports.blogPost = exports.generalWithAuthor; exports.book = exports.generalWithAuthorAndPublisher; exports.bookSection = exports.generalWithAuthorAndPublisher; exports['case'] = { - author: makeCreatorsTranslator('author'), + creator: makeCreatorsTranslator('author'), + contributor: makeCreatorsTranslator('contributor'), title: makeTranslator('caseName'), language: makeTranslator('language', fixLang), abstract: makeTranslator('abstractNote') @@ -78,6 +90,7 @@ title: makeTranslator('title'), date: makeTranslator('date', fixDate), creator: makeCreatorsTranslator('programmer'), + contributor: makeCreatorsTranslator('contributor'), publisher: makeTranslator('company') }; exports.conferencePaper = exports.generalWithAuthorAndPublisher; @@ -85,51 +98,93 @@ exports.document = exports.generalWithAuthorAndPublisher; exports.email = { author: makeCreatorsTranslator('author'), + contributor: makeCreatorsTranslator('contributor'), title: makeTranslator('subject'), date: makeTranslator('date', fixDate), language: makeTranslator('language', fixLang), abstract: makeTranslator('abstractNote') }; exports.encyclopediaArticle = exports.generalWithAuthorAndPublisher; -exports.film = Object.assign({}, extendGeneral('director'), { +exports.film = { + title: makeTranslator('title'), + date: makeTranslator('date', fixDate), + language: makeTranslator('language', fixLang), + abstract: makeTranslator('abstractNote'), + creator: makeCreatorsTranslator('director'), + contributor: makeCreatorsTranslator('contributor'), publisher: makeTranslator('distributor') -}); +}; exports.forumPost = exports.generalWithAuthor; -exports.hearing = Object.assign({}, extendGeneral('contributor'), { +exports.hearing = { + title: makeTranslator('title'), + date: makeTranslator('date', fixDate), + language: makeTranslator('language', fixLang), + abstract: makeTranslator('abstractNote'), + creator: makeCreatorsTranslator('contributor'), + contributor: makeCreatorsTranslator('contributor'), publisher: makeTranslator('publisher') -}); +}; exports.instantMessage = exports.generalWithAuthor; -exports.interview = extendGeneral('interviewee'); +exports.interview = { + title: makeTranslator('title'), + date: makeTranslator('date', fixDate), + language: makeTranslator('language', fixLang), + abstract: makeTranslator('abstractNote'), + creator: makeCreatorsTranslator('interviewee'), + contributor: makeCreatorsTranslator('contributor'), + publisher: makeTranslator('publisher') +}; exports.journalArticle = exports.generalWithAuthor; exports.letter = exports.generalWithAuthor; exports.magazineArticle = exports.generalWithAuthor; exports.manuscript = exports.generalWithAuthor; -exports.map = Object.assign({}, extendGeneral('cartographer'),{ +exports.map = { + title: makeTranslator('title'), + date: makeTranslator('date', fixDate), + language: makeTranslator('language', fixLang), + abstract: makeTranslator('abstractNote'), + creator: makeCreatorsTranslator('cartographer'), + contributor: makeCreatorsTranslator('contributor'), publisher: makeTranslator('publisher') -}); +}; exports.newspaperArticle = exports.generalWithAuthor; exports.note = {}; // Has no fields exports.patent = { - author: makeCreatorsTranslator('inventor'), + creator: makeCreatorsTranslator('inventor'), + contributor: makeCreatorsTranslator('contributor'), title: makeTranslator('title'), language: makeTranslator('language', fixLang), abstract: makeTranslator('abstractNote') }; exports.podcast = { - author: makeCreatorsTranslator('podcaster'), + creator: makeCreatorsTranslator('podcaster'), + contributor: makeCreatorsTranslator('contributor'), title: makeTranslator('title'), language: makeTranslator('language', fixLang), abstract: makeTranslator('abstractNote') }; -exports.presentation = extendGeneral('presenter'); -exports.radioBroadcast = Object.assign({}, extendGeneral('director'),{ +exports.presentation = { + title: makeTranslator('title'), + date: makeTranslator('date', fixDate), + language: makeTranslator('language', fixLang), + abstract: makeTranslator('abstractNote'), + creator: makeCreatorsTranslator('presenter'), + contributor: makeCreatorsTranslator('contributor') +}; +exports.radioBroadcast = { + title: makeTranslator('title'), + date: makeTranslator('date', fixDate), + language: makeTranslator('language', fixLang), + abstract: makeTranslator('abstractNote'), + creator: makeCreatorsTranslator('director'), publisher: makeTranslator('network') -}); +}; exports.report = Object.assign({}, exports.generalWithAuthor, { publisher: makeTranslator('institution') }); exports.statute = { - author: makeCreatorsTranslator('author'), + creator: makeCreatorsTranslator('author'), + contributor: makeCreatorsTranslator('contributor'), title: makeTranslator('nameOfAct'), language: makeTranslator('language', fixLang), abstract: makeTranslator('abstractNote') @@ -137,10 +192,22 @@ exports.thesis = Object.assign({}, exports.generalWithAuthor, { publisher: makeTranslator('university') }); -exports.tvBroadcast = Object.assign({}, extendGeneral('director'), { +exports.tvBroadcast = { + title: makeTranslator('title'), + date: makeTranslator('date', fixDate), + language: makeTranslator('language', fixLang), + abstract: makeTranslator('abstractNote'), + creator: makeCreatorsTranslator('director'), + contributor: makeCreatorsTranslator('contributor'), publisher: makeTranslator('network') -}); -exports.videoRecording = Object.assign({}, extendGeneral('director'), { +}; +exports.videoRecording = { + title: makeTranslator('title'), + date: makeTranslator('date', fixDate), + language: makeTranslator('language', fixLang), + abstract: makeTranslator('abstractNote'), + creator: makeCreatorsTranslator('director'), + contributor: makeCreatorsTranslator('contributor'), publisher: makeTranslator('studio') -}); +}; exports.webpage = exports.generalWithAuthor; \ No newline at end of file diff --git a/lib/translators/general.js b/lib/translators/general.js index f7e1cc7..fc80ea2 100644 --- a/lib/translators/general.js +++ b/lib/translators/general.js @@ -22,7 +22,7 @@ // Shortcut for extendGeneral utility function extendGeneral(creatorName){ - return eg(exports.general, creatorName); + return eg(exports.general, creatorName, 'author'); } // Create a general type with the author in the creator field once since it is used many times. diff --git a/lib/translators/marcXML.js b/lib/translators/marcXML.js new file mode 100644 index 0000000..2e94407 --- /dev/null +++ b/lib/translators/marcXML.js @@ -0,0 +1,390 @@ +'use strict'; + +var ex = require('../Exporter.js'); +var ut = require('./util/index.js'); + +var fixDate = ex.fixDate; +var fixLang = ex.fixLang; +var vISBN = ex.validateISBN; +var vISSN = ex.validateISSN; + +var makeTranslator = ut.makeTranslator; +var makeCreatorsTranslator = ut.makeCreatorsTranslator; +var makeListTranslator = ut.makeListTranslator; +var makePagesTranslator = ut.makePagesTranslator; + +/** + * Translator for MARCXML + */ + +exports.artwork = { // No publisher + a520: makeTranslator('abstractNote'), // Summary, etc. + c260: makeTranslator('date', fixDate), // Date of publication, distribution, etc. + f100: makeTranslator('date', fixDate), // Date of a work + b260: makeTranslator('publisher'), // Name of publisher, distributor, etc + t100: makeTranslator('title'), + a245: makeTranslator('title'), + c245: makeCreatorsTranslator('artist'), // Personal name + a100: makeCreatorsTranslator('artist'), // Personal name + a700: makeCreatorsTranslator('contributor'), + l100: makeTranslator('language', fixLang) +}; +exports.attachment = { + t100: makeTranslator('title'), + a245: makeTranslator('title') +}; +exports.audioRecording = { + a520: makeTranslator('abstractNote'), // Summary, etc. + c260: makeTranslator('date', fixDate), // Date of publication, distribution, etc. + f100: makeTranslator('date', fixDate), // Date of a work + b260: makeTranslator('label'), // Name of publisher, distributor, etc + t100: makeTranslator('title'), + a245: makeTranslator('title'), + c245: makeCreatorsTranslator('performer'), // Personal name + a100: makeCreatorsTranslator('performer'), // Personal name + d773: makeTranslator('place'), + a260: makeTranslator('place'), // Place of publication, distribution, etc., + a264: makeTranslator('place'), // Place of publication, distribution, etc., + a700: makeCreatorsTranslator('contributor'), + l100: makeTranslator('language', fixLang), + g773: makeTranslator('volume'), + a020: makeListTranslator('ISBN', vISBN) // International Standard Book Number +}; +exports.bill = { + a520: makeTranslator('abstractNote'), // Summary, etc. + c260: makeTranslator('date', fixDate), // Date of publication, distribution, etc. + f100: makeTranslator('date', fixDate), // Date of a work + b260: makeTranslator('label'), // Name of publisher, distributor, etc + t100: makeTranslator('title'), + a245: makeTranslator('title'), + c245: makeCreatorsTranslator('sponsor'), // Personal name + a100: makeCreatorsTranslator('sponsor'), // Personal name + a700: makeCreatorsTranslator('contributor'), + l100: makeTranslator('language', fixLang), + a020: makeListTranslator('ISBN', vISBN) // International Standard Book Number +}; +exports.blogPost = { + t100: makeTranslator('title'), // Title of work + a245: makeTranslator('title'), // Title + c260: makeTranslator('date', fixDate), // Date of publication, distribution, etc. + f100: makeTranslator('date', fixDate), // Date of a work + l100: makeTranslator('language', fixLang), // Language of a work + a520: makeTranslator('abstractNote'), // Summary, etc. + c245: makeCreatorsTranslator('author'), // Personal name + a100: makeCreatorsTranslator('author'), // Personal name + t773: makeTranslator('blogTitle'), + a700: makeCreatorsTranslator('contributor') +}; +exports.book = { + t100: makeTranslator('title'), // Title of work + a245: makeTranslator('title'), // Title + c260: makeTranslator('date', fixDate), // Date of publication, distribution, etc. + f100: makeTranslator('date', fixDate), // Date of a work + l100: makeTranslator('language', fixLang), // Language of a work + a520: makeTranslator('abstractNote'), // Summary, etc. + a250: makeTranslator('edition'), // Edition statement + b773: makeTranslator('edition'), + a264: makeTranslator('place'), + d773: makeTranslator('place'), + a260: makeTranslator('place'), // Place of publication, distribution, etc., + a020: makeListTranslator('ISBN', vISBN), // International Standard Book Number + b260: makeTranslator('publisher'), // Name of publisher, distributor, etc. + c245: makeCreatorsTranslator('author'), // Personal name + //a100: makeCreatorsTranslator('author'), // Personal name + a700: makeCreatorsTranslator('contributor'), + g773: makeTranslator('volume'), + a300: makeTranslator('numPages') +}; +exports.bookSection = { + t100: makeTranslator('title'), // Title of work + a245: makeTranslator('title'), // Title + c260: makeTranslator('date', fixDate), // Date of publication, distribution, etc. + f100: makeTranslator('date', fixDate), // Date of a work + l100: makeTranslator('language', fixLang), // Language of a work + a520: makeTranslator('abstractNote'), // Summary, etc. + a250: makeTranslator('edition'), // Edition statement + b773: makeTranslator('edition'), + a264: makeTranslator('place'), + d773: makeTranslator('place'), + a260: makeTranslator('place'), // Place of publication, distribution, etc., + a020: makeListTranslator('ISBN', vISBN), // International Standard Book Number + b260: makeTranslator('publisher'), // Name of publisher, distributor, etc. + c245: makeCreatorsTranslator('author'), // Personal name + a100: makeCreatorsTranslator('author'), // Personal name + a700: makeCreatorsTranslator('contributor'), + t773: makeTranslator('bookTitle'), + g773: makeTranslator('volume') +}; +exports['case'] = { // No publisher + a520: makeTranslator('abstractNote'), + t100: makeTranslator('caseName'), + f100: makeTranslator('dateDecided'), + c260: makeTranslator('dateDecided'), + a100: makeCreatorsTranslator('author'), + l100: makeTranslator('language', fixLang), + q773: makeTranslator('firstPage') +}; +exports.computerProgram = { // No language field + a520: makeTranslator('abstractNote'), + t100: makeTranslator('title'), + a100: makeCreatorsTranslator('programmer'), + d773: makeTranslator('place'), + a260: makeTranslator('place'), + a020: makeListTranslator('ISBN', vISBN) +}; +exports.conferencePaper = { + a520: makeTranslator('abstractNote'), + t100: makeTranslator('title'), + a100: makeCreatorsTranslator('author'), + f100: makeTranslator('date', fixDate), + c260: makeTranslator('date', fixDate), + g773: makeTranslator('volume'), + a264: makeTranslator('place'), + d773: makeTranslator('place'), + a260: makeTranslator('place'), + t773: makeTranslator('proceedingsTitle'), + b260: makeTranslator('publisher'), + l100: makeTranslator('language', fixLang), + a020: makeListTranslator('ISBN', vISBN) +}; +exports.dictionaryEntry = { + a520: makeTranslator('abstractNote'), + t100: makeTranslator('title'), + a100: makeCreatorsTranslator('author'), + f100: makeTranslator('date',fixDate), + c260: makeTranslator('date', fixDate), + a264: makeTranslator('place'), + d773: makeTranslator('place'), + a260: makeTranslator('place'), + t773: makeTranslator('dictionaryTitle'), + b260: makeTranslator('publisher'), + l100: makeTranslator('language', fixLang), + a020: makeListTranslator('ISBN', vISBN) +}; +exports.document = exports.generalWithAuthor; +exports.email = { + a520: makeTranslator('abstractNote'), + f100: makeTranslator('date', fixDate), + c260: makeTranslator('date', fixDate), + t100: makeTranslator('subject'), + l100: makeTranslator('language', fixLang), + a100: makeCreatorsTranslator('author') +}; +exports.encyclopediaArticle = { + a520: makeTranslator('abstractNote'), + t100: makeTranslator('title'), + a100: makeCreatorsTranslator('author'), + f100: makeTranslator('date', fixDate), + t773: makeTranslator('encyclopediaTitle'), + a264: makeTranslator('place'), + d773: makeTranslator('place'), + a260: makeTranslator('place'), + b260: makeTranslator('publisher'), + l100: makeTranslator('language', fixLang), + q773: makeTranslator('pages'), + a020: makeListTranslator('ISBN', vISBN) +}; +exports.film = { + a520: makeTranslator('abstractNote'), + t100: makeTranslator('title'), + a100: makeCreatorsTranslator('director'), + c260: makeTranslator('date', fixDate), + f100: makeTranslator('date', fixDate) +}; +exports.forumPost = exports.blogPost; +exports.hearing = { + a520: makeTranslator('abstractNote'), + t100: makeTranslator('title'), + a100: makeCreatorsTranslator('contributor'), + a264: makeTranslator('place'), + d773: makeTranslator('place'), + a260: makeTranslator('place'), + c260: makeTranslator('date', fixDate), + f100: makeTranslator('date', fixDate), + q773: makeTranslator('pages') +}; +exports.instantMessage = exports.blogPost; +exports.interview = { + a520: makeTranslator('abstractNote'), + t100: makeTranslator('title'), + a100: makeCreatorsTranslator('interviewee'), + c260: makeTranslator('date', fixDate), + f100: makeTranslator('date', fixDate), + l100: makeTranslator('language', fixLang) +}; +exports.journalArticle = { + a520: makeTranslator('abstractNote'), + t100: makeTranslator('title'), + a100: makeCreatorsTranslator('author'), + r773: makeTranslator('issue'), + g773: makeTranslator('volume'), + f100: makeTranslator('date', fixDate), + c260: makeTranslator('date', fixDate), + a490: makeTranslator('seriesTitle'), + t773: makeTranslator('publicationTitle'), + x773: makeListTranslator('ISSN', vISSN), + l100: makeTranslator('language', fixLang) +}; +exports.letter = { + a520: makeTranslator('abstractNote'), + t100: makeTranslator('title'), + a100: makeCreatorsTranslator('author'), + f100: makeTranslator('date', fixDate), + c260: makeTranslator('date', fixDate), + l100: makeTranslator('language', fixLang) +}; +exports.magazineArticle = { + a520: makeTranslator('abstractNote'), + t100: makeTranslator('title'), + a100: makeCreatorsTranslator('author'), + f100: makeTranslator('date', fixDate), + c260: makeTranslator('date', fixDate), + t773: makeTranslator('publicationTitle'), + l100: makeTranslator('language', fixLang), + x773: makeListTranslator('ISSN', vISSN) +}; +exports.manuscript = { + a520: makeTranslator('abstractNote'), + t100: makeTranslator('title'), + a100: makeCreatorsTranslator('author'), + a264: makeTranslator('place'), + d773: makeTranslator('place'), + a260: makeTranslator('place'), + f100: makeTranslator('date', fixDate), + c260: makeTranslator('date', fixDate), + l100: makeTranslator('language', fixLang) +}; +exports.map = { + a520: makeTranslator('abstractNote'), + t100: makeTranslator('title'), + a100: makeCreatorsTranslator('cartographer'), + f100: makeTranslator('date', fixDate), + c260: makeTranslator('date', fixDate), + t773: makeTranslator('seriesTitle'), + a490: makeTranslator('seriesTitle'), + a264: makeTranslator('place'), + d773: makeTranslator('place'), + a260: makeTranslator('place'), + b260: makeTranslator('publisher'), + l100: makeTranslator('language', fixLang), + a020: makeListTranslator('ISBN', vISBN) +}; +exports.newspaperArticle = { + a520: makeTranslator('abstractNote'), + t100: makeTranslator('title'), + a100: makeCreatorsTranslator('author'), + f100: makeTranslator('date', fixDate), + c260: makeTranslator('date', fixDate), + a264: makeTranslator('place'), + d773: makeTranslator('place'), + a260: makeTranslator('place'), + t773: makeTranslator('publicationTitle'), + l100: makeTranslator('language', fixLang), + x773: makeListTranslator('ISSN', vISSN) +}; +exports.note = {}; // Has no fields +exports.patent = { + a520: makeTranslator('abstractNote'), + t100: makeTranslator('title'), + l100: makeTranslator('language', fixLang), + a264: makeTranslator('place'), + d773: makeTranslator('place'), + a260: makeTranslator('place'), + a100: makeCreatorsTranslator('inventor'), + f100: makeTranslator('issueDate'), + c260: makeTranslator('issueDate') +}; +exports.podcast = { + a520: makeTranslator('abstractNote'), + t100: makeTranslator('title'), + a100: makeCreatorsTranslator('podcaster'), + t773: makeTranslator('seriesTitle'), + a490: makeTranslator('seriesTitle'), + l100: makeTranslator('language', fixLang) +}; +exports.presentation = { + a520: makeTranslator('abstractNote'), + f100: makeTranslator('date', fixDate), + c260: makeTranslator('date', fixDate), + t100: makeTranslator('title'), + a264: makeTranslator('place'), + d773: makeTranslator('place'), + a260: makeTranslator('place'), + l100: makeTranslator('language', fixLang), + a100: makeCreatorsTranslator('presenter') +}; +exports.radioBroadcast = { + a520: makeTranslator('abstractNote'), + t100: makeTranslator('title'), + a100: makeCreatorsTranslator('director'), + f100: makeTranslator('date', fixDate), + c260: makeTranslator('date', fixDate), + l100: makeTranslator('language', fixLang) +}; +exports.report = { + a520: makeTranslator('abstractNote'), + t100: makeTranslator('title'), + a100: makeCreatorsTranslator('author'), + f100: makeTranslator('date', fixDate), + c260: makeTranslator('date', fixDate), + t773: makeTranslator('seriesTitle'), + a490: makeTranslator('seriesTitle'), + a264: makeTranslator('place'), + d773: makeTranslator('place'), + a260: makeTranslator('place'), + r773: makeTranslator('number'), + u773: makeTranslator('number'), + l100: makeTranslator('language', fixLang) +}; +exports.statute = { + a520: makeTranslator('abstractNote'), + t100: makeTranslator('nameOfAct'), + a100: makeCreatorsTranslator('author'), + f100: makeTranslator('dateEnacted'), + c260: makeTranslator('dateEnacted', fixDate), + l100: makeTranslator('language', fixLang) +}; +exports.thesis = { + a520: makeTranslator('abstractNote'), + t100: makeTranslator('title'), + a100: makeCreatorsTranslator('author'), + f100: makeTranslator('date', fixDate), + c260: makeTranslator('date', fixDate), + a264: makeTranslator('place'), + d773: makeTranslator('place'), + a260: makeTranslator('place'), + l100: makeTranslator('language', fixLang), + b260: makeTranslator('university') +}; +exports.tvBroadcast = { + a520: makeTranslator('abstractNote'), + t100: makeTranslator('title'), + a100: makeCreatorsTranslator('director'), + f100: makeTranslator('date', fixDate), + c260: makeTranslator('date', fixDate), + a264: makeTranslator('place'), + a260: makeTranslator('place'), + d773: makeTranslator('place'), + l100: makeTranslator('language', fixLang) +}; +exports.videoRecording = { + a520: makeTranslator('abstractNote'), + t100: makeTranslator('title'), + a100: makeCreatorsTranslator('director'), + f100: makeTranslator('date',fixDate), + c260: makeTranslator('date', fixDate), + t773: makeTranslator('seriesTitle'), + a490: makeTranslator('seriesTitle'), + a264: makeTranslator('place'), + a260: makeTranslator('place'), + d773: makeTranslator('place'), + l100: makeTranslator('language', fixLang), + a020: makeListTranslator('ISBN', vISBN) +}; +exports.webpage = { + a520: makeTranslator('abstractNote'), + t100: makeTranslator('title'), + a100: makeCreatorsTranslator('author'), + f100: makeTranslator('date',fixDate), + l100: makeTranslator('language', fixLang) +}; \ No newline at end of file diff --git a/lib/translators/template.js.txt b/lib/translators/template.js.txt deleted file mode 100644 index 02f2429..0000000 --- a/lib/translators/template.js.txt +++ /dev/null @@ -1,69 +0,0 @@ -'use strict'; - -var makeTranslator = require('./util/index.js').makeTranslator; -var addCreators = require('./util/index.js').addCreators; -var eg = require('./util/index.js').extendGeneral; -var makeCreatorsTranslator = require('./util/index.js').makeCreatorsTranslator; - -/** - * Template field values : translators made with Zotero type field values - * @type {Object} - */ - -exports.general = { - urlTemplateField: makeTranslator('url'), - abstractTemplateField: makeTranslator('abstractNote'), - publisherTemplateField: makeTranslator('publisher'), - titleTemplateField: makeTranslator('title') -}; - -// Shortcut for extendGeneral utility -function extendGeneral(creatorName){ - return eg(exports.general, creatorName); -} - -// Create a general type with the author in the creator field once since it is used many times. -exports.generalWithAuthor = extendGeneral('author'); - -/* Complete list of Zotero types with field translators in the Object */ -exports.artwork = extendGeneral('artist'); -exports.attachment = { - title: makeTranslator('title') -}; -exports.audioRecording = extendGeneral('performer'); -exports.bill = extendGeneral('sponsor'); -exports.blogPost = exports.generalWithAuthor; -exports.book = exports.generalWithAuthor; -exports.bookSection = exports.generalWithAuthor; -exports['case'] = exports.generalWithAuthor; -exports.computerProgram = { // No language field - title: makeTranslator('title'), - creator: makeCreatorsTranslator('programmer') -}; -exports.conferencePaper = exports.generalWithAuthor; -exports.dictionaryEntry = exports.generalWithAuthor; -exports.document = exports.generalWithAuthor; -exports.email = exports.generalWithAuthor; -exports.encyclopediaArticle = exports.generalWithAuthor; -exports.film = extendGeneral('director'); -exports.forumPost = exports.generalWithAuthor; -exports.hearing = extendGeneral('contributor'); -exports.instantMessage = exports.generalWithAuthor; -exports.interview = extendGeneral('interviewee'); -exports.journalArticle = exports.generalWithAuthor; -exports.letter = exports.generalWithAuthor; -exports.magazineArticle = exports.generalWithAuthor; -exports.manuscript = exports.generalWithAuthor; -exports.map = extendGeneral('cartographer'); -exports.newspaperArticle = exports.generalWithAuthor; -exports.note = {}; // Has no fields -exports.patent = extendGeneral('inventor'); -exports.podcast = extendGeneral('podcaster'); -exports.presentation = extendGeneral('presenter'); -exports.radioBroadcast = extendGeneral('director'); -exports.report = exports.generalWithAuthor; -exports.statute = exports.generalWithAuthor; -exports.thesis = exports.generalWithAuthor; -exports.tvBroadcast = extendGeneral('director'); -exports.videoRecording = extendGeneral('director'); -exports.webpage = exports.generalWithAuthor; \ No newline at end of file diff --git a/lib/translators/util/index.js b/lib/translators/util/index.js index a4dd747..6e66edf 100644 --- a/lib/translators/util/index.js +++ b/lib/translators/util/index.js @@ -95,14 +95,19 @@ } return { name: 'creators', + subname: creatorType, translate: translateProp }; }; /* Function to add arbitrary creator function to the exports.general obj*/ -exports.extendGeneral = function(generalObj, creatorType){ +exports.extendGeneral = function(generalObj, creatorType, key){ + if (!key){ + throw new Error('a key is required'); + } var extendedType = {}; - Object.assign(extendedType, generalObj, {creator: exports.makeCreatorsTranslator(creatorType)}); + Object.assign(extendedType, generalObj); + extendedType[key] = exports.makeCreatorsTranslator(creatorType); return extendedType; }; diff --git a/test/features/scraping/isbn.js b/test/features/scraping/isbn.js index 037c778..e070782 100644 --- a/test/features/scraping/isbn.js +++ b/test/features/scraping/isbn.js @@ -92,8 +92,8 @@ assert.isInArray(res.body[0].source, 'WorldCat'); assert.deepEqual(res.body[0].author, [['Barrett, Daniel', 'J.']], 'Unexpected value:' + res.body[0].author); assert.deepEqual(res.body[0].publisher, 'O\'Reilly', 'Unexpected value; expected O\'Reilly, got ' + res.body[0].publisher); - //assert.deepEqual(res.body[0].place, 'Sebastapool, Calif.', 'Unexpected value; expected Sebastapool, Calif., got ' + res.body[0].place); // Not currently working with Worldcat Search API - not present in results - //assert.deepEqual(res.body[0].edition, '1st ed.', 'Unexpected value; expected 1st ed., got ' + res.body[0].edition); // Not currently working with Worldcat Search API - present in description tag + assert.deepEqual(res.body[0].place, 'Sebastapool, Calif.', 'Unexpected value; expected Sebastapool, Calif., got ' + res.body[0].place); // Not currently working with Worldcat Search API - not present in results + assert.deepEqual(res.body[0].edition, '1st ed', 'Unexpected value; expected 1st ed, got ' + res.body[0].edition); // Not currently working with Worldcat Search API - present in description tag assert.deepEqual(res.body[0].date, '2009', 'Unexpected value; expected 2009, got ' + res.body[0].date); assert.isInArray(res.body[0].ISBN, '9780596519797'); assert.deepEqual(res.body[0].itemType, 'book', 'Wrong itemType; expected book, got ' + res.body[0].itemType); @@ -108,7 +108,7 @@ assert.isInArray(res.body[0].source, 'WorldCat'); assert.deepEqual(res.body[0].contributor, [['Sheen,','Martin.'],['Cohen,','Bonni.'],['Thomson,','Richard.'],['DK Publishing,','Inc.']], 'Unexpected value:' + res.body[0].author); // only get this sometimes assert.deepEqual(res.body[0].studio, 'DK Pub', 'Unexpected value; expected DK Pub, got ' + res.body[0].studio); - //assert.deepEqual(res.body[0].place, 'New York', 'Unexpected value; expected New York, got ' + res.body[0].place); + assert.deepEqual(res.body[0].place, 'New York', 'Unexpected value; expected New York, got ' + res.body[0].place); assert.deepEqual(res.body[0].date, '2010, ©1996', 'Unexpected value; expected 2010, ©1996, got ' + res.body[0].date); // Not currently working with worldcat; date is returned to us as '2010, ©1996' assert.isInArray(res.body[0].ISBN, '9780756662967'); assert.deepEqual(res.body[0].itemType, 'videoRecording', 'Wrong itemType; expected videoRecording, got ' + res.body[0].itemType); @@ -129,15 +129,16 @@ }); }); - it('valid ISBN with funky author field', function() { + it('valid ISBN with author and contributor', function() { return server.query('9780439784542').then(function(res) { assert.status(res, 200); assert.checkCitation(res, 'Harry Potter and the Half-Blood Prince'); assert.deepEqual(!!res.body[0].oclc, true, 'Missing OCLC'); assert.isInArray(res.body[0].source, 'WorldCat'); - assert.deepEqual(!!res.body[0].contributor, true, 'Missing contributor'); - //assert.deepEqual(res.body[0].place, 'New York, NY', 'Unexpected value; expected New York, NY, got ' + res.body[0].place); - //assert.deepEqual(res.body[0].edition, '1st American ed.', 'Unexpected value; expected 1st ed., got ' + res.body[0].edition); + assert.deepEqual(res.body[0].contributor,[['GrandPré,','Mary,']], 'Missing contributor'); + assert.deepEqual(res.body[0].author, [['Rowling, J.', 'K.,']], 'Missing author'); + assert.deepEqual(res.body[0].place, 'New York, NY', 'Unexpected value; expected New York, NY, got ' + res.body[0].place); + assert.deepEqual(res.body[0].edition, 'First American edition', 'Unexpected value; expected First American edition, got ' + res.body[0].edition); assert.isInArray(res.body[0].ISBN, '9780439784542'); assert.deepEqual(res.body[0].itemType, 'book', 'Wrong itemType; expected book, got ' + res.body[0].itemType); }); diff --git a/test/features/unit/scraper.js b/test/features/unit/translator.js similarity index 74% rename from test/features/unit/scraper.js rename to test/features/unit/translator.js index 47796ec..6db3a78 100644 --- a/test/features/unit/scraper.js +++ b/test/features/unit/translator.js @@ -29,11 +29,13 @@ {value:article, name:'article'} ]; +var app = { + logger: function(){} +}; +var translator = new Translator(app); + describe('translate function: ', function() { - var app = { - logger: function(){} - }; - var translator = new Translator(app); + var types = new CachedTypes(); var citation; var result; @@ -98,3 +100,44 @@ }); }); + +describe('check specific results', function() { + it('sets right info from webpage for general metadata', function() { + return meta.parseAll(article).then(function(metadata){ + var citation = translator.translate({itemType:'webpage'}, metadata.general, gen.webpage); + var expected = { + itemType: "webpage", + creators: [ + { + creatorType: "author", + lastName: "Lvr", + firstName: "Turtle" + } + ], + url: "http://example.com/turtles", + abstractNote: "Exposition on the awesomeness of turtles", + title: "Turtles are AWESOME!!1 | Awesome Turtles Website", + language: "en" + } + assert.deepEqual(citation, expected); + }); + }); + it('sets right info from webpage for bepress metadata', function() { + return meta.parseAll(article).then(function(metadata){ + var citation = translator.translate({itemType:'webpage'}, metadata.bePress, bp.webpage); + var expected = { + itemType: "webpage", + creators: [ + { + creatorType: "author", + lastName: "Lvr", + firstName: "Turtle" + } + ], + date: "2012", + title: "Turtles are AWESOME!!1" + } + assert.deepEqual(citation, expected); + }); + }); +}); diff --git a/test/features/unit/translators/coins.js b/test/features/unit/translators/coins.js index 280ff44..a5b112b 100644 --- a/test/features/unit/translators/coins.js +++ b/test/features/unit/translators/coins.js @@ -4,7 +4,7 @@ var coins = require('../../../../lib/translators/coins.js'); -describe('coins unit', function() { +describe('coins metadata', function() { var result; var expected; diff --git a/test/features/unit/translators/general.js b/test/features/unit/translators/general.js index 433d229..c0d8517 100644 --- a/test/features/unit/translators/general.js +++ b/test/features/unit/translators/general.js @@ -17,7 +17,7 @@ lastName: 'One' }] }; - result = gen.generalWithAuthor.creator.translate({}, {author:['One']}, 'author'); + result = gen.generalWithAuthor.author.translate({}, {author:['One']}, 'author'); assert.deepEqual(result, expected); }); @@ -29,7 +29,7 @@ lastName: 'One' }] }; - result = gen.generalWithAuthor.creator.translate({}, {author:'One'}, 'author'); + result = gen.generalWithAuthor.author.translate({}, {author:'One'}, 'author'); assert.deepEqual(result, expected); }); @@ -41,7 +41,7 @@ lastName: 'Two' }] }; - result = gen.generalWithAuthor.creator.translate({}, {author:'One Two'}, 'author'); + result = gen.generalWithAuthor.author.translate({}, {author:'One Two'}, 'author'); assert.deepEqual(result, expected); }); @@ -53,7 +53,7 @@ lastName: 'Three' }] }; - result = gen.generalWithAuthor.creator.translate({}, {author:'One Two Three'}, 'author'); + result = gen.generalWithAuthor.author.translate({}, {author:'One Two Three'}, 'author'); assert.deepEqual(result, expected); }); @@ -65,7 +65,7 @@ lastName: 'GrandPré.' }] }; - result = gen.generalWithAuthor.creator.translate({}, {author:'J.K. Rowling ; illustrations by Mary GrandPré.'}, 'author'); + result = gen.generalWithAuthor.author.translate({}, {author:'J.K. Rowling ; illustrations by Mary GrandPré.'}, 'author'); assert.deepEqual(result, expected); }); }); diff --git a/test/features/unit/translators/util.js b/test/features/unit/translators/util.js index aab04ab..a9c0106 100644 --- a/test/features/unit/translators/util.js +++ b/test/features/unit/translators/util.js @@ -19,6 +19,8 @@ var result; var expected; var input; + var author; + var contributor; describe('makeTranslator function: ', function() { @@ -105,4 +107,56 @@ assert.deepEqual(result, expected); }); }); + + describe('makeCreatorsTranslator function: ', function() { + + it('Correctly adds author', function() { + input = ['Daniel J. Barrett']; + expected = { + creators: [{ + 'creatorType':'author', + 'firstName': 'Daniel J.', + 'lastName': 'Barrett' + }] + }; + result = ut.makeCreatorsTranslator('author').translate({}, {author:input}, 'author'); + assert.deepEqual(result, expected); + }); + + it('Doesn not like format Last name, first name', function() { + input = ['Barrett, Daniel J.']; + expected = { + creators: [{ + 'creatorType':'author', + 'firstName': 'Barrett, Daniel', + 'lastName': 'J.' + }] + }; + result = ut.makeCreatorsTranslator('author').translate({}, {author:input}, 'author'); + assert.deepEqual(result, expected); + }); + + it('Correctly adds two different contributor types', function() { + author = 'J.K. Rowling'; + contributor = 'Mary GrandPré' + expected = { + creators: [{ + 'creatorType':'author', + 'firstName': 'J.K.', + 'lastName': 'Rowling' + }, + { + 'creatorType':'contributor', + 'firstName': 'Mary', + 'lastName': 'GrandPré' + }] + }; + result = ut.makeCreatorsTranslator('author').translate({}, {author:author}, 'author'); + result = ut.makeCreatorsTranslator('contributor').translate(result, {contributor:contributor}, 'contributor'); + assert.deepEqual(result, expected); + }); + + + + }); }); -- To view, visit https://gerrit.wikimedia.org/r/355097 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I58489d2959306b620f9bfa4a5bfb2a81ea7cb4a4 Gerrit-PatchSet: 10 Gerrit-Project: mediawiki/services/citoid Gerrit-Branch: master Gerrit-Owner: Mvolz <mv...@wikimedia.org> Gerrit-Reviewer: Mobrovac <mobro...@wikimedia.org> Gerrit-Reviewer: Mvolz <mv...@wikimedia.org> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits