Fix lint issues in feedReader.js

This commit is contained in:
J. Ryan Stinnett 2021-05-07 15:19:58 +01:00
parent bc4aafa8e4
commit 088483b776

View file

@ -53,16 +53,15 @@
* @method {void} terminate Stops retrieving/parsing the feed. Data parsed up * @method {void} terminate Stops retrieving/parsing the feed. Data parsed up
* to this point is still available. * to this point is still available.
*/ */
Zotero.FeedReader = function(url) { Zotero.FeedReader = function (url) {
if (!url) throw new Error("Feed URL must be supplied"); if (!url) throw new Error("Feed URL must be supplied");
this._url = url; this._url = url;
this._feedItems = [Zotero.Promise.defer()]; this._feedItems = [Zotero.Promise.defer()];
this._feedProcessed = Zotero.Promise.defer(); this._feedProcessed = Zotero.Promise.defer();
let feedFetched = Zotero.Promise.defer(); let feedFetched = Zotero.Promise.defer();
feedFetched.promise.then(function(feed) { feedFetched.promise.then(function (feed) {
let info = {}; let info = {};
info.title = feed.title ? feed.title.plainText() : ''; info.title = feed.title ? feed.title.plainText() : '';
@ -93,7 +92,7 @@ Zotero.FeedReader = function(url) {
if (issn) info.ISSN = issn; if (issn) info.ISSN = issn;
let isbn = Zotero.FeedReader._getFeedField(feed, 'isbn', 'prism') let isbn = Zotero.FeedReader._getFeedField(feed, 'isbn', 'prism')
|| Zotero.FeedReader._getFeedField(feed, 'isbn') || Zotero.FeedReader._getFeedField(feed, 'isbn');
if (isbn) info.ISBN = isbn; if (isbn) info.ISBN = isbn;
let language = Zotero.FeedReader._getFeedField(feed, 'language', 'dc') let language = Zotero.FeedReader._getFeedField(feed, 'language', 'dc')
@ -105,10 +104,10 @@ Zotero.FeedReader = function(url) {
this._feedProperties = info; this._feedProperties = info;
this._feed = feed; this._feed = feed;
}.bind(this)).then(function(){ }.bind(this)).then(function () {
let items = this._feed.items; let items = this._feed.items;
if (items && items.length) { if (items && items.length) {
for (let i=0; i<items.length; i++) { for (let i = 0; i < items.length; i++) {
let item = items.queryElementAt(i, Components.interfaces.nsIFeedEntry); let item = items.queryElementAt(i, Components.interfaces.nsIFeedEntry);
if (!item) continue; if (!item) continue;
@ -121,10 +120,11 @@ Zotero.FeedReader = function(url) {
} }
} }
this._feedProcessed.resolve(); this._feedProcessed.resolve();
}.bind(this)).catch(function(e) { }.bind(this)).catch(function (e) {
Zotero.debug("Feed processing failed " + e.message); Zotero.debug("Feed processing failed " + e.message);
this._feedProcessed.reject(e); this._feedProcessed.reject(e);
}.bind(this)).finally(function() { // eslint-disable-next-line newline-per-chained-call
}.bind(this)).finally(function () {
// Make sure the last promise gets resolved to null // Make sure the last promise gets resolved to null
let lastItem = this._feedItems[this._feedItems.length - 1]; let lastItem = this._feedItems[this._feedItems.length - 1];
lastItem.resolve(null); lastItem.resolve(null);
@ -133,16 +133,16 @@ Zotero.FeedReader = function(url) {
// Set up asynchronous feed processor // Set up asynchronous feed processor
let feedProcessor = Components.classes["@mozilla.org/feed-processor;1"] let feedProcessor = Components.classes["@mozilla.org/feed-processor;1"]
.createInstance(Components.interfaces.nsIFeedProcessor); .createInstance(Components.interfaces.nsIFeedProcessor);
let feedUrl = Services.io.newURI(url, null, null); let feedUrl = Services.io.newURI(url, null, null);
feedProcessor.parseAsync(null, feedUrl); feedProcessor.parseAsync(null, feedUrl);
/*
* MDN suggests that we could use nsIFeedProgressListener to handle the feed
* as it gets loaded, but this is actually not implemented (as of 32.0.3),
* so we have to load the whole feed and handle it in handleResult.
*/
feedProcessor.listener = { feedProcessor.listener = {
/*
* MDN suggests that we could use nsIFeedProgressListener to handle the feed
* as it gets loaded, but this is actually not implemented (as of 32.0.3),
* so we have to load the whole feed and handle it in handleResult.
*/
handleResult: (result) => { handleResult: (result) => {
if (!result.doc) { if (!result.doc) {
this.terminate("No Feed"); this.terminate("No Feed");
@ -156,12 +156,12 @@ Zotero.FeedReader = function(url) {
Zotero.debug("FeedReader: Fetching feed from " + feedUrl.spec); Zotero.debug("FeedReader: Fetching feed from " + feedUrl.spec);
this._channel = Services.io.newChannelFromURI2(feedUrl, null, this._channel = Services.io.newChannelFromURI2(feedUrl, null,
Services.scriptSecurityManager.getSystemPrincipal(), null, Services.scriptSecurityManager.getSystemPrincipal(), null,
Ci.nsILoadInfo.SEC_NORMAL, Ci.nsIContentPolicy.TYPE_OTHER); Ci.nsILoadInfo.SEC_NORMAL, Ci.nsIContentPolicy.TYPE_OTHER);
this._channel.loadFlags |= Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE; this._channel.loadFlags |= Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE;
this._channel.asyncOpen(feedProcessor, null); // Sends an HTTP request this._channel.asyncOpen(feedProcessor, null); // Sends an HTTP request
} };
/* /*
* The constructor initiates async feed processing, but _feedProcessed * The constructor initiates async feed processing, but _feedProcessed
@ -175,7 +175,7 @@ Zotero.FeedReader.prototype.process = Zotero.Promise.coroutine(function* () {
* Terminate feed processing at any given time * Terminate feed processing at any given time
* @param {String} status Reason for terminating processing * @param {String} status Reason for terminating processing
*/ */
Zotero.FeedReader.prototype.terminate = function(status) { Zotero.FeedReader.prototype.terminate = function (status) {
Zotero.debug("FeedReader: Terminating feed reader (" + status + ")"); Zotero.debug("FeedReader: Terminating feed reader (" + status + ")");
// Reject feed promise if not resolved yet // Reject feed promise if not resolved yet
@ -203,11 +203,11 @@ Zotero.FeedReader.prototype.terminate = function(status) {
}; };
Zotero.defineProperty(Zotero.FeedReader.prototype, 'feedProperties', { Zotero.defineProperty(Zotero.FeedReader.prototype, 'feedProperties', {
get: function(){ get: function () {
if (!this._feedProperties) { if (!this._feedProperties) {
throw new Error("Feed has not been resolved yet. Try calling FeedReader#process first") throw new Error("Feed has not been resolved yet. Try calling FeedReader#process first");
} }
return this._feedProperties return this._feedProperties;
} }
}); });
@ -220,18 +220,19 @@ Zotero.defineProperty(Zotero.FeedReader.prototype, 'feedProperties', {
* for termination. * for termination.
*/ */
Zotero.defineProperty(Zotero.FeedReader.prototype, 'ItemIterator', { Zotero.defineProperty(Zotero.FeedReader.prototype, 'ItemIterator', {
get: function() { get: function () {
let items = this._feedItems; let items = this._feedItems;
// eslint-disable-next-line consistent-this
let feedReader = this; let feedReader = this;
let iterator = function() { let iterator = function () {
if (!feedReader._feedProperties) { if (!feedReader._feedProperties) {
throw new Error("Feed has not been resolved yet. Try calling FeedReader#process first") throw new Error("Feed has not been resolved yet. Try calling FeedReader#process first");
} }
this.index = 0; this.index = 0;
}; };
iterator.prototype.next = function() { iterator.prototype.next = function () {
let item = items[this.index++]; let item = items[this.index++];
return { return {
value: item ? item.promise : null, value: item ? item.promise : null,
@ -239,23 +240,23 @@ Zotero.defineProperty(Zotero.FeedReader.prototype, 'ItemIterator', {
}; };
}; };
iterator.prototype.last = function() { iterator.prototype.last = function () {
return items[items.length-1]; return items[items.length - 1];
} };
return iterator; return iterator;
} }
}, {lazy: true}); }, { lazy: true });
/***************************** /*****************************
* Item processing functions * * Item processing functions *
*****************************/ *****************************/
/** /**
* Determine item type based on item data * Determine item type based on item data
*/ */
Zotero.FeedReader._guessItemType = function(item) { Zotero.FeedReader._guessItemType = function (item) {
// Default to journalArticle // Default to journalArticle
item.itemType = 'journalArticle'; item.itemType = 'journalArticle';
@ -288,12 +289,12 @@ Zotero.FeedReader._guessItemType = function(item) {
/* /*
* Fetch creators from given field of a feed entry * Fetch creators from given field of a feed entry
*/ */
Zotero.FeedReader._processCreators = function(feedEntry, field, role) { Zotero.FeedReader._processCreators = function (feedEntry, field, role) {
let names = [], let names = [],
nameStr; nameStr;
try { try {
let personArr = feedEntry[field]; // Seems like this part can throw if there is no author data in the feed let personArr = feedEntry[field]; // Seems like this part can throw if there is no author data in the feed
for (let i=0; i<personArr.length; i++) { for (let i = 0; i < personArr.length; i++) {
let person = personArr.queryElementAt(i, Components.interfaces.nsIFeedPerson); let person = personArr.queryElementAt(i, Components.interfaces.nsIFeedPerson);
if (!person || !person.name) continue; if (!person || !person.name) continue;
@ -301,25 +302,25 @@ Zotero.FeedReader._processCreators = function(feedEntry, field, role) {
if (!name) continue; if (!name) continue;
let commas = name.split(',').length - 1, let commas = name.split(',').length - 1,
other = name.split(/\s(?:and|&)\s|;/).length - 1, other = name.split(/\s(?:and|&)\s|;/).length - 1;
separators = commas + other; if (personArr.length == 1
if (personArr.length == 1 &&
// Has typical name separators // Has typical name separators
(other || commas > 1 && (other || commas > 1
// If only one comma and first part has more than one space, // If only one comma and first part has more than one space,
// it's probably not lastName, firstName // it's probably not lastName, firstName
|| (commas == 1 && name.split(/\s*,/)[0].indexOf(' ') != -1) || (commas == 1 && name.split(/\s*,/)[0].indexOf(' ') != -1)
) )
) { ) {
// Probably multiple authors listed in a single field // Probably multiple authors listed in a single field
nameStr = name; nameStr = name;
break; // For clarity. personArr.length == 1 anyway break; // For clarity. personArr.length == 1 anyway
} else { }
else {
names.push(name); names.push(name);
} }
} }
} }
catch(e) { catch (e) {
if (e.result != Components.results.NS_ERROR_FAILURE) throw e; if (e.result != Components.results.NS_ERROR_FAILURE) throw e;
if (field != 'authors') return []; if (field != 'authors') return [];
@ -335,7 +336,7 @@ Zotero.FeedReader._processCreators = function(feedEntry, field, role) {
} }
let creators = []; let creators = [];
for (let i=0; i<names.length; i++) { for (let i = 0; i < names.length; i++) {
let creator = Zotero.Utilities.cleanAuthor( let creator = Zotero.Utilities.cleanAuthor(
names[i], names[i],
role, role,
@ -352,18 +353,18 @@ Zotero.FeedReader._processCreators = function(feedEntry, field, role) {
creators.push(creator); creators.push(creator);
} }
return creators; return creators;
} };
/* /*
* Parse feed entry into a Zotero item * Parse feed entry into a Zotero item
*/ */
Zotero.FeedReader._getFeedItem = function(feedEntry, feedInfo) { Zotero.FeedReader._getFeedItem = function (feedEntry, feedInfo) {
// ID is not required, but most feeds have these and we have to rely on them // ID is not required, but most feeds have these and we have to rely on them
// to handle updating properly // to handle updating properly
// Can probably fall back to links on missing id - unlikely to change // Can probably fall back to links on missing id - unlikely to change
if (!feedEntry.id && !feedEntry.link) { if (!feedEntry.id && !feedEntry.link) {
Zotero.debug("FeedReader: Feed item missing an ID or link - discarding"); Zotero.debug("FeedReader: Feed item missing an ID or link - discarding");
return; return null;
} }
let item = { let item = {
@ -394,7 +395,7 @@ Zotero.FeedReader._getFeedItem = function(feedEntry, feedInfo) {
item.creators = Zotero.FeedReader._processCreators(feedEntry, 'authors', 'author'); item.creators = Zotero.FeedReader._processCreators(feedEntry, 'authors', 'author');
if (!item.creators.length) { if (!item.creators.length) {
// Use feed authors as item author. Maybe not the best idea. // Use feed authors as item author. Maybe not the best idea.
for (let i=0; i<feedInfo.creators.length; i++) { for (let i = 0; i < feedInfo.creators.length; i++) {
if (feedInfo.creators[i].creatorType != 'author') continue; if (feedInfo.creators[i].creatorType != 'author') continue;
item.creators.push(feedInfo.creators[i]); item.creators.push(feedInfo.creators[i]);
} }
@ -426,27 +427,26 @@ Zotero.FeedReader._getFeedItem = function(feedEntry, feedInfo) {
let startPage = Zotero.FeedReader._getFeedField(feedEntry, 'startPage'); let startPage = Zotero.FeedReader._getFeedField(feedEntry, 'startPage');
let endPage = Zotero.FeedReader._getFeedField(feedEntry, 'endPage'); let endPage = Zotero.FeedReader._getFeedField(feedEntry, 'endPage');
if (startPage || endPage) { if (startPage || endPage) {
item.pages = ( startPage || '' ) item.pages = (startPage || '')
+ ( endPage && startPage ? '' : '' ) + (endPage && startPage ? '' : '')
+ ( endPage || '' ); + (endPage || '');
} }
let issn = Zotero.FeedReader._getFeedField(feedEntry, 'issn', 'prism'); let issn = Zotero.FeedReader._getFeedField(feedEntry, 'issn', 'prism');
if (issn) item.ISSN = issn; if (issn) item.ISSN = issn;
let isbn = Zotero.FeedReader._getFeedField(feedEntry, 'isbn', 'prism') let isbn = Zotero.FeedReader._getFeedField(feedEntry, 'isbn', 'prism')
|| Zotero.FeedReader._getFeedField(feedEntry, 'isbn') || Zotero.FeedReader._getFeedField(feedEntry, 'isbn');
if (isbn) item.ISBN = isbn; if (isbn) item.ISBN = isbn;
let identifier = Zotero.FeedReader._getFeedField(feedEntry, 'identifier', 'dc'); let identifier = Zotero.FeedReader._getFeedField(feedEntry, 'identifier', 'dc');
if (identifier) { if (identifier) {
let cleanId = Zotero.Utilities.cleanDOI(identifier); for (let type of ['DOI', 'ISBN', 'ISSN']) {
if (cleanId) { let cleanId = Zotero.Utilities[`clean${type}`](identifier);
if (!item.DOI) item.DOI = cleanId; if (cleanId) {
} else if (cleanId = Zotero.Utilities.cleanISBN(identifier)) { if (!item[type]) item[type] = cleanId;
if (!item.ISBN) item.ISBN = cleanId; break;
} else if (cleanId = Zotero.Utilities.cleanISSN(identifier)) { }
if (!item.ISSN) item.ISSN = cleanId;
} }
} }
@ -465,7 +465,7 @@ Zotero.FeedReader._getFeedItem = function(feedEntry, feedInfo) {
/** Incorporate missing values from feed metadata **/ /** Incorporate missing values from feed metadata **/
let supplementFields = ['publicationTitle', 'ISSN', 'publisher', 'rights', 'language']; let supplementFields = ['publicationTitle', 'ISSN', 'publisher', 'rights', 'language'];
for (let i=0; i<supplementFields.length; i++) { for (let i = 0; i < supplementFields.length; i++) {
let field = supplementFields[i]; let field = supplementFields[i];
if (!item[field] && feedInfo[field]) { if (!item[field] && feedInfo[field]) {
item[field] = feedInfo[field]; item[field] = feedInfo[field];
@ -477,7 +477,7 @@ Zotero.FeedReader._getFeedItem = function(feedEntry, feedInfo) {
item.enclosedItems = Zotero.FeedReader._getEnclosedItems(feedEntry); item.enclosedItems = Zotero.FeedReader._getEnclosedItems(feedEntry);
return item; return item;
} };
/********************* /*********************
* Utility functions * * Utility functions *
@ -485,7 +485,7 @@ Zotero.FeedReader._getFeedItem = function(feedEntry, feedInfo) {
/* /*
* Convert HTML-formatted text to Zotero-compatible formatting * Convert HTML-formatted text to Zotero-compatible formatting
*/ */
Zotero.FeedReader._getRichText = function(feedText, field) { Zotero.FeedReader._getRichText = function (feedText, field) {
let domDiv = Zotero.Utilities.Internal.getDOMDocument().createElement("div"); let domDiv = Zotero.Utilities.Internal.getDOMDocument().createElement("div");
let domFragment = feedText.createDocumentFragment(domDiv); let domFragment = feedText.createDocumentFragment(domDiv);
return Zotero.Utilities.dom2text(domFragment, field); return Zotero.Utilities.dom2text(domFragment, field);
@ -497,37 +497,39 @@ Zotero.FeedReader._getRichText = function(feedText, field) {
// Properties are stored internally as ns+name, but only some namespaces are // Properties are stored internally as ns+name, but only some namespaces are
// supported. Others are just "null" // supported. Others are just "null"
let ns = { let ns = {
'prism': 'null', prism: 'null',
'dc': 'dc:' dc: 'dc:'
} };
Zotero.FeedReader._getFeedField = function(feedEntry, field, namespace) { Zotero.FeedReader._getFeedField = function (feedEntry, field, namespace) {
let prefix = namespace ? ns[namespace] || 'null' : ''; let prefix = namespace ? ns[namespace] || 'null' : '';
try { try {
return feedEntry.fields.getPropertyAsAUTF8String(prefix+field); return feedEntry.fields.getPropertyAsAUTF8String(prefix + field);
} catch(e) {} }
catch (e) {}
try { try {
if (namespace && !ns[namespace]) { if (namespace && !ns[namespace]) {
prefix = namespace + ':'; prefix = namespace + ':';
return feedEntry.fields.getPropertyAsAUTF8String(prefix+field); return feedEntry.fields.getPropertyAsAUTF8String(prefix + field);
} }
} catch(e) {} }
catch (e) { }
return; return null;
} };
Zotero.FeedReader._getEnclosedItems = function(feedEntry) { Zotero.FeedReader._getEnclosedItems = function (feedEntry) {
var enclosedItems = []; var enclosedItems = [];
if (feedEntry.enclosures) { if (feedEntry.enclosures) {
for (let i = 0; i < feedEntry.enclosures.length; i++) { for (let i = 0; i < feedEntry.enclosures.length; i++) {
let elem = feedEntry.enclosures.queryElementAt(0, Components.interfaces.nsIPropertyBag2); let elem = feedEntry.enclosures.queryElementAt(0, Components.interfaces.nsIPropertyBag2);
if (elem.get('url')) { if (elem.get('url')) {
let enclosedItem = {url: elem.get('url'), contentType: elem.get('type') || ''}; let enclosedItem = { url: elem.get('url'), contentType: elem.get('type') || '' };
enclosedItems.push(enclosedItem); enclosedItems.push(enclosedItem);
} }
} }
} }
return enclosedItems; return enclosedItems;
} };