Arlolra has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/256149

Change subject: Don't extend the prototype of native objects
......................................................................

Don't extend the prototype of native objects

 * We've enabled the `freeze` option in jshint but apparently it doesn't
   catch `Object.defineProperty` method of doing this.

 * Also, add core-upgrade.js to the files we're explicitly linting. Why
   does the package.json even have these declarations? Isn't that the
   point of having a .jshintignore file?

Change-Id: Ib96bb9ec9f555d07da2b068ae21d5e68733d19b9
---
M core-upgrade.js
M lib/html2wt/LinkHandler.js
M lib/html2wt/SerializerState.js
M lib/html2wt/WikitextSerializer.js
M lib/html2wt/escapeWikitext.js
M lib/utils/DOMTraverser.js
M lib/utils/DOMUtils.js
M lib/utils/Util.js
M lib/utils/jsutils.js
M lib/wt2html/TokenTransformManager.js
M lib/wt2html/XMLSerializer.js
M lib/wt2html/parser.js
M lib/wt2html/pegTokenizer.pegjs.txt
M lib/wt2html/pp/dom.t.TableFixups.js
M lib/wt2html/pp/wrapTemplates.js
M lib/wt2html/tokenizer.js
M lib/wt2html/tokenizer.utils.js
M lib/wt2html/tt/LinkHandler.js
M lib/wt2html/tt/ListHandler.js
M lib/wt2html/tt/ParagraphWrapper.js
M lib/wt2html/tt/TokenCollector.js
M package.json
22 files changed, 86 insertions(+), 51 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/services/parsoid 
refs/changes/49/256149/1

diff --git a/core-upgrade.js b/core-upgrade.js
index 9ab279b..fa39a32 100644
--- a/core-upgrade.js
+++ b/core-upgrade.js
@@ -1,8 +1,3 @@
-"use strict";
+'use strict';
 require('core-js/shim');
 require('prfun/smash'); // This mutates the global Promise object.
-if (!Array.prototype.last) {
-       Object.defineProperty(Array.prototype, 'last', {
-               value: function() { return this[this.length - 1]; },
-       });
-}
diff --git a/lib/html2wt/LinkHandler.js b/lib/html2wt/LinkHandler.js
index d72515d..6dcd75b 100644
--- a/lib/html2wt/LinkHandler.js
+++ b/lib/html2wt/LinkHandler.js
@@ -3,6 +3,7 @@
 
 var url = require('url');
 var Util = require('../utils/Util.js').Util;
+var JSUtils = require('../utils/JSUtils.js').JSUtils;
 var DU = require('../utils/DOMUtils.js').DOMUtils;
 var Title = require('../mw/Title.js').Title;
 var CT = require('./ConstrainedText.js');
@@ -11,6 +12,7 @@
 var ExtLinkText = CT.ExtLinkText;
 var MagicLinkText = CT.MagicLinkText;
 var WikiLinkText = CT.WikiLinkText;
+var lastItem = JSUtils.lastItem;
 
 
 var splitLinkContentString = function(contentString, dp, target) {
@@ -1091,7 +1093,7 @@
                        if (idx < 0) {
                                // New option, default to English localization 
for most languages
                                // TODO: use first alias (localized) instead 
for RTL languages (T53852)
-                               no.ak = no.ak.last();
+                               no.ak = lastItem(no.ak);
                                changed = true;
                                return; /* new option */
                        }
@@ -1112,7 +1114,7 @@
                                no.ak = opts[idx].ak;
                                no.v = undefined; // prevent double substitution
                        } else {
-                               no.ak = no.ak.last();
+                               no.ak = lastItem(no.ak);
                                if (!(no.ck === 'caption' && a !== undefined)) {
                                        changed = true;
                                }
diff --git a/lib/html2wt/SerializerState.js b/lib/html2wt/SerializerState.js
index a875ff9..ad29fa2 100644
--- a/lib/html2wt/SerializerState.js
+++ b/lib/html2wt/SerializerState.js
@@ -112,7 +112,7 @@
 };
 
 SLCP.enforced = function() {
-       return this._stack.length > 0 && this._stack.last();
+       return this._stack.length > 0 && JSUtils.lastItem(this._stack);
 };
 
 SLCP.disable = function() {
diff --git a/lib/html2wt/WikitextSerializer.js 
b/lib/html2wt/WikitextSerializer.js
index 3127ccd..2cb11a8 100644
--- a/lib/html2wt/WikitextSerializer.js
+++ b/lib/html2wt/WikitextSerializer.js
@@ -28,6 +28,7 @@
 var util = require('util');
 var Util = require('../utils/Util.js').Util;
 var DU = require('../utils/DOMUtils.js').DOMUtils;
+var JSUtils = require('../utils/JSUtils.js').JSUtils;
 var wtConsts = require('../config/WikitextConstants.js');
 var WTSUtils = require('./WTSUtils.js').WTSUtils;
 var pd = require('../wt2html/parser.defines.js');
@@ -42,6 +43,7 @@
 var Consts = wtConsts.WikitextConstants;
 var tagHandlers = DOMHandlers.tagHandlers;
 var htmlElementHandler = DOMHandlers.htmlElementHandler;
+var lastItem = JSUtils.lastItem;
 
 
 /**
@@ -1145,7 +1147,7 @@
                                                && j + 2 < n
                                                && p[j + 1] === ""
                                                && p[j + 2][0] === "'"
-                                               && p[j + 2] === 
stack[stack.length - 1])
+                                               && p[j + 2] === lastItem(stack))
                                        )) {
                                        nowikiIndex = j;
                                }
@@ -1156,7 +1158,7 @@
                                //   mediawiki.wikitext.constants.js, <br> is 
the most common
                                //   culprit. )
                                continue;
-                       } else if (tag[0] === "'" && stack[stack.length - 1] 
=== tag) {
+                       } else if (tag[0] === "'" && lastItem(stack) === tag) {
                                stack.pop();
                                quotesOnStack--;
                        } else {
diff --git a/lib/html2wt/escapeWikitext.js b/lib/html2wt/escapeWikitext.js
index 9c30413..4b83c72 100644
--- a/lib/html2wt/escapeWikitext.js
+++ b/lib/html2wt/escapeWikitext.js
@@ -4,6 +4,7 @@
 var wtConsts = require('../config/WikitextConstants.js');
 var DU = require('../utils/DOMUtils.js').DOMUtils;
 var Util = require('../utils/Util.js').Util;
+var JSUtils = require('../utils/JSUtils.js').JSUtils;
 var PegTokenizer = require('../wt2html/tokenizer.js').PegTokenizer;
 var pd = require('../wt2html/parser.defines.js');
 var SanitizerConstants = 
require('../wt2html/tt/Sanitizer.js').SanitizerConstants;
@@ -592,7 +593,7 @@
        }
 
        // Context-specific escape handler
-       var wteHandler = state.wteHandlerStack.last();
+       var wteHandler = JSUtils.lastItem(state.wteHandlerStack);
        if (wteHandler && wteHandler(state, text, opts)) {
                state.env.log("trace/wt-escape", "---Context-specific escape 
handler---");
                return this.escapedText(state, false, text, true);
diff --git a/lib/utils/DOMTraverser.js b/lib/utils/DOMTraverser.js
index 96711ef..d6c79e5 100644
--- a/lib/utils/DOMTraverser.js
+++ b/lib/utils/DOMTraverser.js
@@ -1,6 +1,7 @@
 'use strict';
 
 var DU = require('./DOMUtils.js').DOMUtils;
+var JSUtils = require('./JSUtils.js').JSUtils;
 
 
 /**
@@ -97,7 +98,7 @@
                                var about = workNode.getAttribute("about");
                                tplInfo = {
                                        first: workNode,
-                                       last: DU.getAboutSiblings(workNode, 
about).last(),
+                                       last: 
JSUtils.lastItem(DU.getAboutSiblings(workNode, about)),
                                        dsr: DU.getDataParsoid(workNode).dsr,
                                        clear: false,
                                };
diff --git a/lib/utils/DOMUtils.js b/lib/utils/DOMUtils.js
index b2d5f05..fc7c62a 100644
--- a/lib/utils/DOMUtils.js
+++ b/lib/utils/DOMUtils.js
@@ -16,6 +16,8 @@
 // define some constructor shortcuts
 var ParsoidCacheRequest = ApiRequest.ParsoidCacheRequest;
 var TemplateRequest = ApiRequest.TemplateRequest;
+var lastItem = JSUtils.lastItem;
+
 
 /**
  * @class DOMUtils
@@ -1490,7 +1492,7 @@
                }
 
                // Remove already consumed trailing IEW, if any
-               while (nodes.length && this.isIEW(nodes.last())) {
+               while (nodes.length && this.isIEW(lastItem(nodes))) {
                        nodes.pop();
                }
 
@@ -1509,7 +1511,7 @@
        skipOverEncapsulatedContent: function(node) {
                var about = node.getAttribute('about');
                if (about) {
-                       return this.getAboutSiblings(node, 
about).last().nextSibling;
+                       return lastItem(this.getAboutSiblings(node, 
about)).nextSibling;
                } else {
                        return node.nextSibling;
                }
@@ -1583,7 +1585,7 @@
                                                                }).join(''),
                                                        };
                                                }
-                                               node = nodes.last();
+                                               node = lastItem(nodes);
                                        } else {
                                                
doExtractExpansions(node.firstChild);
                                        }
@@ -1720,7 +1722,7 @@
                // content. It could potentially introduce minor rendering 
differences when
                // compared to PHP parser output, but we'll swallow it for now.
                var firstNode = nodes[0];
-               var lastNode = nodes.length > 1 ? nodes.last() : null;
+               var lastNode = nodes.length > 1 ? lastItem(nodes) : null;
                var wrapperType;
                if (opts.noPWrapping) {
                        // If the DOM fragment is being processed in the 
context where P wrapping
diff --git a/lib/utils/Util.js b/lib/utils/Util.js
index f637b21..8ca2dfd 100644
--- a/lib/utils/Util.js
+++ b/lib/utils/Util.js
@@ -13,6 +13,7 @@
 var Consts = require('../config/WikitextConstants.js').WikitextConstants;
 var JSUtils = require('./jsutils.js').JSUtils;
 
+var lastItem = JSUtils.lastItem;
 
 // This is a circular dependency.  Don't use anything from defines at module
 // evaluation time.  (For example, we can't define the usual local variable
@@ -960,7 +961,7 @@
                        return tokens;
                }
                // Strip 'end' token
-               if (tokens.length && tokens.last().constructor === pd.EOFTk) {
+               if (tokens.length && lastItem(tokens).constructor === pd.EOFTk) 
{
                        var rank = tokens.rank;
                        tokens = tokens.slice(0, -1);
                        tokens.rank = rank;
@@ -973,9 +974,9 @@
        // stripEOFTkfromTokens, but unclear if this is still needed.
        // TODO: remove this if this is not needed any more!
        stripTrailingNewlinesFromTokens: function(tokens) {
-               var token = tokens.last();
+               var token = lastItem(tokens);
                var lastMatches = function(toks) {
-                       var lastTok = toks.last();
+                       var lastTok = lastItem(toks);
                        return lastTok && (
                                        lastTok.constructor === pd.NlTk ||
                                        lastTok.constructor === String && 
/^\s+$/.test(token));
@@ -1078,7 +1079,7 @@
                }
                var bits = path.split('#');
                if (bits.length > 1) {
-                       anchor = bits[bits.length - 1];
+                       anchor = lastItem(bits);
                        path = path.substr(0, path.length - anchor.length - 1);
                }
                host = host.replace(/[%#|]/g, function(m) {
diff --git a/lib/utils/jsutils.js b/lib/utils/jsutils.js
index 8bbc1f7..15df5a2 100644
--- a/lib/utils/jsutils.js
+++ b/lib/utils/jsutils.js
@@ -9,7 +9,14 @@
        throw new TypeError("Mutation attempted on read-only collection.");
 };
 
+var lastItem = function(array) {
+       console.assert(Array.isArray(array));
+       return array[array.length - 1];
+};
+
 var JSUtils = {
+
+       lastItem: lastItem,
 
        // in ES7 it should be `new Map(Object.entries(obj))`
        mapObject: function(obj) {
@@ -113,7 +120,7 @@
        // an object, with a `flags` property (as shown in the example above).
        rejoin: function() {
                var regexps = Array.prototype.slice.call(arguments);
-               var last = regexps[regexps.length - 1];
+               var last = lastItem(regexps);
                var flags;
                if (typeof (last) === 'object') {
                        if (last instanceof RegExp) {
diff --git a/lib/wt2html/TokenTransformManager.js 
b/lib/wt2html/TokenTransformManager.js
index 5ece6eb..268a7dd 100644
--- a/lib/wt2html/TokenTransformManager.js
+++ b/lib/wt2html/TokenTransformManager.js
@@ -25,6 +25,7 @@
 var KV = defines.KV;
 var EOFTk = defines.EOFTk;
 var Params = defines.Params;
+var lastItem = JSUtils.lastItem;
 
 // forward declarations
 var TokenAccumulator, Frame;
@@ -323,7 +324,8 @@
        function checkForEOFTkErrors(ttm, ret, atEnd) {
                if (ttm.frame.depth === 0 &&
                                ret.tokens && ret.tokens.length) {
-                       if (atEnd && ret.tokens.last() && 
ret.tokens.last().constructor !== EOFTk) {
+                       var last = atEnd && lastItem(ret.tokens);
+                       if (last && last.constructor !== EOFTk) {
                                self.env.log("error", "EOFTk went missing in 
AsyncTokenTransformManager");
                                ret.tokens.push(new EOFTk());
                        }
@@ -550,7 +552,7 @@
 
        var inputRank = tokens.rank || 0;
        while (workStack.length > 0) {
-               var curChunk = workStack.last();
+               var curChunk = lastItem(workStack);
 
                // Once the chunk is processed, switch to a new accum
                // if it has async mode set since it might generate more
@@ -884,7 +886,7 @@
        while (workStack.length > 0) {
                var token, minRank;
 
-               var curChunk = workStack.last();
+               var curChunk = lastItem(workStack);
                minRank = curChunk.rank || this.phaseEndRank - 1;
                token = curChunk[curChunk.eltIndex++];
                if (curChunk.eltIndex === curChunk.length) {
@@ -916,7 +918,7 @@
 
                if (res.tokens && res.tokens.length) {
                        if (token.constructor === EOFTk &&
-                               res.tokens.last().constructor !== EOFTk) {
+                               lastItem(res.tokens).constructor !== EOFTk) {
                                this.env.log("error", "EOFTk was dropped by " + 
transformer.name);
                                // fix it up for now by adding it back in
                                res.tokens.push(token);
@@ -1143,7 +1145,7 @@
                return;
        }
 
-       var lastChunk = this.siblingChunks.last();
+       var lastChunk = lastItem(this.siblingChunks);
        if (!tokens.rank) {
                this.manager.env.log('error/tta/conc/rank/none', tokens);
                tokens.rank = this.manager.phaseEndRank;
@@ -1417,7 +1419,7 @@
                                this.onThunkEvent.bind(this, eventState, true));
                pipeline.addListener('end',
                                this.onThunkEvent.bind(this, eventState, 
false));
-               if (chunk[chunk.length - 1].constructor === EOFTk) {
+               if (lastItem(chunk).constructor === EOFTk) {
                        pipeline.process(chunk, this.title);
                } else {
                        var newChunk = JSUtils.pushArray(chunk, 
this._eofTkList);
diff --git a/lib/wt2html/XMLSerializer.js b/lib/wt2html/XMLSerializer.js
index c6b4194..9e6ec48 100644
--- a/lib/wt2html/XMLSerializer.js
+++ b/lib/wt2html/XMLSerializer.js
@@ -3,6 +3,9 @@
  */
 'use strict';
 
+var JSUtils = require('../utils/JSUtils.js').JSUtils;
+
+
 // nodeType constants
 var ELEMENT_NODE = 1;
 var TEXT_NODE = 3;
@@ -187,7 +190,7 @@
                        } else if (DU.isFirstEncapsulationWrapperNode(node) ||
                                        DU.hasExpandedAttrsType(node)) {
                                var about = node.getAttribute('about');
-                               out.last = DU.getAboutSiblings(node, 
about).last();
+                               out.last = 
JSUtils.lastItem(DU.getAboutSiblings(node, about));
                                out.uid = newUid;
                        }
                }
diff --git a/lib/wt2html/parser.js b/lib/wt2html/parser.js
index 01122c1..00033ef 100644
--- a/lib/wt2html/parser.js
+++ b/lib/wt2html/parser.js
@@ -29,6 +29,7 @@
 var DOMFragmentBuilder = 
require('./tt/DOMFragmentBuilder.js').DOMFragmentBuilder;
 var TreeBuilder = require('./HTML5TreeBuilder.js').TreeBuilder;
 var DOMPostProcessor = require('./DOMPostProcessor.js').DOMPostProcessor;
+var JSUtils = require('../utils/JSUtils.js').JSUtils;
 
 var SyncTokenTransformManager = 
TokenTransformManager.SyncTokenTransformManager;
 var AsyncTokenTransformManager = 
TokenTransformManager.AsyncTokenTransformManager;
@@ -399,7 +400,7 @@
        this.pipeLineType = type;
        this.stages = stages;
        this.first = stages[0];
-       this.last = stages.last();
+       this.last = JSUtils.lastItem(stages);
        this.env = env;
 };
 
diff --git a/lib/wt2html/pegTokenizer.pegjs.txt 
b/lib/wt2html/pegTokenizer.pegjs.txt
index cabec7c..77eecaa 100644
--- a/lib/wt2html/pegTokenizer.pegjs.txt
+++ b/lib/wt2html/pegTokenizer.pegjs.txt
@@ -9,6 +9,7 @@
     var pegIncludes = options.pegIncludes;
     var DU = pegIncludes.DOMUtils;
     var Util = pegIncludes.Util;
+    var JSUtils = pegIncludes.JSUtils;
     var PegTokenizer = pegIncludes.PegTokenizer;
     var defines = pegIncludes.defines;
     var constants = pegIncludes.constants;
@@ -22,6 +23,7 @@
     var NlTk = defines.NlTk;
     var CommentTk = defines.CommentTk;
     var EOFTk = defines.EOFTk;
+    var lastItem = JSUtils.lastItem;
 
     var inlineBreaks = tu.inlineBreaks;
     var stops = new tu.SyntaxStops();
@@ -326,7 +328,7 @@
         }
         if (e.length > level) {
             var extras2 = e.substr(0, e.length - level);
-            var lastElem = c[c.length - 1];
+            var lastElem = lastItem(c);
             if (lastElem.constructor === String) {
                 c[c.length - 1] += extras2;
             } else {
@@ -561,7 +563,7 @@
     // yank trailing punctuation out of this match.
     var url = tu.flattenStringlist([proto, addr].concat(path));
     // only need to look at last element; HTML entities are strip-proof.
-    var last = url[url.length - 1];
+    var last = lastItem(url);
     var trim = 0;
     if (last && last.constructor === String) {
       var strip = ',;\\.:!?';
@@ -1946,8 +1948,8 @@
     // templates, so we shouldn't ever be tokenizing inInclude.
     // Last line should be empty (except for comments)
     if (incl !== "includeonly" && stops.onStack("sol_il")) {
-      var last = inclContent.split("\n");
-      if (!/^(<!--([^-]|-(?!->))*-->)*$/.test(last[last.length - 1])) {
+      var last = lastItem(inclContent.split('\n'));
+      if (!/^(<!--([^-]|-(?!->))*-->)*$/.test(last)) {
         return false;
       }
     }
diff --git a/lib/wt2html/pp/dom.t.TableFixups.js 
b/lib/wt2html/pp/dom.t.TableFixups.js
index a8cb105..a36b24f 100644
--- a/lib/wt2html/pp/dom.t.TableFixups.js
+++ b/lib/wt2html/pp/dom.t.TableFixups.js
@@ -1,6 +1,7 @@
 'use strict';
 
 var Util = require('../../utils/Util.js').Util;
+var JSUtils = require('../../utils/JSUtils.js').JSUtils;
 var DU = require('../../utils/DOMUtils.js').DOMUtils;
 var PegTokenizer = require('../tokenizer.js').PegTokenizer;
 var defines = require('../parser.defines.js');
@@ -232,7 +233,7 @@
                }
 
                // Are we done accumulating?
-               if (/(?:^|[^|])\|(?:[^|]|$)/.test(buf.last())) {
+               if (/(?:^|[^|])\|(?:[^|]|$)/.test(JSUtils.lastItem(buf))) {
                        return buildRes();
                }
 
diff --git a/lib/wt2html/pp/wrapTemplates.js b/lib/wt2html/pp/wrapTemplates.js
index 7b82b41..beb8776 100644
--- a/lib/wt2html/pp/wrapTemplates.js
+++ b/lib/wt2html/pp/wrapTemplates.js
@@ -31,8 +31,11 @@
 'use strict';
 
 var DU = require('../../utils/DOMUtils.js').DOMUtils;
+var JSUtils = require('../../utils/JSUtils.js').JSUtils;
 var Util = require('../../utils/Util.js').Util;
 var dumpDOM = require('./dumper.js').dumpDOM;
+
+var lastItem = JSUtils.lastItem;
 
 
 function expandRangeToAvoidSpanWrapping(range, startsWithText) {
@@ -293,7 +296,7 @@
                var dsr = dp.dsr;
 
                if (tplArray.length > 0) {
-                       var prevTplInfo = tplArray[tplArray.length - 1];
+                       var prevTplInfo = lastItem(tplArray);
                        if (prevTplInfo.dsr[1] < dsr[0]) {
                                tplArray.push({ wt: 
env.page.src.substring(prevTplInfo.dsr[1], dsr[0]) });
                        }
@@ -682,7 +685,7 @@
                        }
 
                        // Add any trailing wikitext
-                       var lastTplInfo = tplArray[tplArray.length - 1];
+                       var lastTplInfo = lastItem(tplArray);
                        if (lastTplInfo.dsr[1] < dp1.dsr[1]) {
                                tplArray.push({ wt: 
env.page.src.substring(lastTplInfo.dsr[1], dp1.dsr[1]) });
                        }
diff --git a/lib/wt2html/tokenizer.js b/lib/wt2html/tokenizer.js
index 095a0b8..50ad784 100644
--- a/lib/wt2html/tokenizer.js
+++ b/lib/wt2html/tokenizer.js
@@ -32,6 +32,7 @@
        tu: require('./tokenizer.utils.js'),
        constants: require('../config/WikitextConstants.js').WikitextConstants,
        DOMUtils: require('../utils/DOMUtils.js').DOMUtils,
+       JSUtils: JSUtils,
        Util: require('../utils/Util.js').Util,
        // defined below to satisfy JSHint
        PegTokenizer: null,
diff --git a/lib/wt2html/tokenizer.utils.js b/lib/wt2html/tokenizer.utils.js
index e34a0bc..9cdadba 100644
--- a/lib/wt2html/tokenizer.utils.js
+++ b/lib/wt2html/tokenizer.utils.js
@@ -5,6 +5,7 @@
 'use strict';
 
 var defines = require('./parser.defines.js');
+var JSUtils = require('../utils/JSUtils.js').JSUtils;
 
 var KV = defines.KV;
 var TagTk = defines.TagTk;
@@ -380,7 +381,7 @@
        if (stack === undefined || stack.length === 0) {
                return false;
        } else {
-               return stack[stack.length - 1];
+               return JSUtils.lastItem(stack);
        }
 };
 
diff --git a/lib/wt2html/tt/LinkHandler.js b/lib/wt2html/tt/LinkHandler.js
index a5516ed..c13b6f1 100644
--- a/lib/wt2html/tt/LinkHandler.js
+++ b/lib/wt2html/tt/LinkHandler.js
@@ -13,6 +13,7 @@
 var sanitizerLib = require('./Sanitizer.js');
 var Util = require('../../utils/Util.js').Util;
 var DU = require('../../utils/DOMUtils.js').DOMUtils;
+var JSUtils = require('../../utils/jsutils.js').JSUtils;
 
 // define some constructor shortcuts
 var KV = defines.KV;
@@ -22,6 +23,7 @@
 var EndTagTk = defines.EndTagTk;
 var Sanitizer = sanitizerLib.Sanitizer;
 var SanitizerConstants = sanitizerLib.SanitizerConstants;
+var lastItem = JSUtils.lastItem;
 
 
 function WikiLinkHandler(manager, options) {
@@ -1513,7 +1515,7 @@
        var allowedPrefixes = this.manager.env.conf.wiki.allowExternalImages;
        var bits = href.split('.');
        var hasImageExtension = bits.length > 1 &&
-               this._imageExtensions.hasOwnProperty(bits[bits.length - 1]) &&
+               this._imageExtensions.hasOwnProperty(lastItem(bits)) &&
                href.match(/^https?:\/\//i);
        // Typical settings for mediawiki configuration variables
        // $wgAllowExternalImages and $wgAllowExternalImagesFrom will
@@ -1546,7 +1548,7 @@
        if (this._hasImageLink(href)) {
                tagAttrs = [
                        new KV('src', href),
-                       new KV('alt', href.split('/').last()),
+                       new KV('alt', lastItem(href.split('/'))),
                        new KV('rel', 'mw:externalImage'),
                ];
 
@@ -1630,7 +1632,7 @@
                        content = [
                                new SelfclosingTagTk('img', [
                                        new KV('src', src),
-                                       new KV('alt', src.split('/').last()),
+                                       new KV('alt', lastItem(src.split('/'))),
                                ], { type: 'extlink' }),
                        ];
                }
diff --git a/lib/wt2html/tt/ListHandler.js b/lib/wt2html/tt/ListHandler.js
index 4d2a555..91d7f1e 100644
--- a/lib/wt2html/tt/ListHandler.js
+++ b/lib/wt2html/tt/ListHandler.js
@@ -3,6 +3,7 @@
  */
 'use strict';
 
+var JSUtils = require('../../utils/jsutils.js').JSUtils;
 var Util = require('../../utils/Util.js').Util;
 var defines = require('../parser.defines.js');
 
@@ -10,6 +11,7 @@
 var NlTk = defines.NlTk;
 var TagTk = defines.TagTk;
 var EndTagTk = defines.EndTagTk;
+var lastItem = JSUtils.lastItem;
 
 
 function ListHandler(manager) {
@@ -200,7 +202,7 @@
                if (this.currListFrame) {
                        // Ignoring colons inside tags to prevent illegal 
overlapping.
                        // Attempts to mimic findColonNoLinks in the php parser.
-                       if (token.bullets.last() === ":" && 
this.currListFrame.numOpenTags > 0) {
+                       if (lastItem(token.bullets) === ':' && 
this.currListFrame.numOpenTags > 0) {
                                return { token: ":" };
                        }
                } else {
diff --git a/lib/wt2html/tt/ParagraphWrapper.js 
b/lib/wt2html/tt/ParagraphWrapper.js
index b62b1ba..2172eb3 100644
--- a/lib/wt2html/tt/ParagraphWrapper.js
+++ b/lib/wt2html/tt/ParagraphWrapper.js
@@ -9,6 +9,7 @@
 var Util = require('../../utils/Util.js').Util;
 var defines = require('../parser.defines.js');
 var Consts = require('../../config/WikitextConstants.js').WikitextConstants;
+var JSUtils = require('../../utils/jsutils.js').JSUtils;
 
 // define some constructor shortcuts
 var CommentTk = defines.CommentTk;
@@ -17,6 +18,7 @@
 var TagTk = defines.TagTk;
 var SelfclosingTagTk = defines.SelfclosingTagTk;
 var EndTagTk = defines.EndTagTk;
+var lastItem = JSUtils.lastItem;
 
 
 function ParagraphWrapper(manager, options) {
@@ -330,7 +332,7 @@
                        // 1. Close any open p-tag
                        this.closeOpenPTag(resToks);
 
-                       var topTag = this.tableTags.length > 0 ? 
this.tableTags.last(): null;
+                       var topTag = this.tableTags.length > 0 ? 
lastItem(this.tableTags) : null;
                        if (!topTag || topTag === 'td' || topTag === 'th') {
                                // 2. Discard 3 newlines (the p-br-p section
                                // serializes back to 3 newlines)
@@ -387,10 +389,10 @@
 //          popping as long as the elements in this array match. Pass
 //          null to disable.
 function popTags(tblTags, popUntil, popThen) {
-       while (popUntil && tblTags.length > 0 && 
popUntil.indexOf(tblTags.last()) === -1) {
+       while (popUntil && tblTags.length > 0 && 
popUntil.indexOf(lastItem(tblTags)) === -1) {
                tblTags.pop();
        }
-       while (popThen && tblTags.length > 0 && popThen.indexOf(tblTags.last()) 
!== -1) {
+       while (popThen && tblTags.length > 0 && 
popThen.indexOf(lastItem(tblTags)) !== -1) {
                tblTags.pop();
        }
 }
diff --git a/lib/wt2html/tt/TokenCollector.js b/lib/wt2html/tt/TokenCollector.js
index 46c639b..8066f3a 100644
--- a/lib/wt2html/tt/TokenCollector.js
+++ b/lib/wt2html/tt/TokenCollector.js
@@ -1,11 +1,15 @@
 'use strict';
 
-// define some constructor shortcuts
 var defines = require('../parser.defines.js');
+var JSUtils = require('../../utils/jsutils.js').JSUtils;
+
+// define some constructor shortcuts
 var EOFTk = defines.EOFTk;
 var TagTk = defines.TagTk;
 var SelfclosingTagTk = defines.SelfclosingTagTk;
 var EndTagTk = defines.EndTagTk;
+var lastItem = JSUtils.lastItem;
+
 
 /**
  * @class
@@ -109,7 +113,7 @@
 
                        var res = this.toEnd ? this.transformation(allToks) : { 
tokens: allToks };
                        if (res.tokens && res.tokens.length &&
-                                       res.tokens.last().constructor !== 
EOFTk) {
+                                       lastItem(res.tokens).constructor !== 
EOFTk) {
                                this.manager.env.log("error", this.name, 
"handler dropped the EOFTk!");
 
                                // preserve the EOFTk
@@ -138,7 +142,7 @@
  */
 TokenCollector.prototype._onAnyToken = function(token, frame, cb) {
        // Simply collect anything ordinary in between
-       this.scopeStack[this.scopeStack.length - 1].push(token);
+       lastItem(this.scopeStack).push(token);
        return { };
 };
 
diff --git a/package.json b/package.json
index 0507ebc..41be555 100644
--- a/package.json
+++ b/package.json
@@ -47,9 +47,9 @@
     "lint": "npm run dump-tokenizer && npm run jscs && npm run jshint",
     "no-0.8": "node -e 'process.exit(/v0[.][0-8][.]/.test(process.version) ? 0 
: 1)' || (npm run nsp && npm run lint)",
     "start": "node bin/server.js",
-    "jshint": "jshint bin lib tests tools",
-    "jscs": "jscs bin lib tests tools",
-    "jscs-fix": "jscs --fix bin lib tests tools",
+    "jshint": "jshint bin lib tests tools core-upgrade.js",
+    "jscs": "jscs bin lib tests tools core-upgrade.js",
+    "jscs-fix": "jscs --fix bin lib tests tools core-upgrade.js",
     "dump-tokenizer": "node lib/wt2html/tokenizer.js",
     "mocha": "mocha --opts tests/mocha/mocha.opts tests/mocha",
     "parserTests": "node bin/parserTests.js --wt2html --wt2wt --html2wt 
--html2html --selser --no-color --quiet --blacklist",

-- 
To view, visit https://gerrit.wikimedia.org/r/256149
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib96bb9ec9f555d07da2b068ae21d5e68733d19b9
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/services/parsoid
Gerrit-Branch: master
Gerrit-Owner: Arlolra <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to