sanitize-html 1.22.1 → 1.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  ## Changelog
2
2
 
3
+ 1.23.0:
4
+ - Adds eslint configuration and adds eslint to test script.
5
+ - Sets `sideEffects: false` on package.json to allow module bundlers like webpack tree-shake this module and all the dependencies from client build. Thanks to [Egor Voronov](https://github.com/egorvoronov) for the contribution.
6
+ - Adds the `tagName` (HTML element name) as a second parameter passed to `textFilter`. Thanks to [Slava](https://github.com/slavaGanzin) for the contribution.
7
+
3
8
  1.22.1: Increases the patch version of `lodash.mergewith` to enforce an audit fix.
4
9
 
5
10
  1.22.0: bumped `htmlparser2` dependency to the 4.x series. This fixes longstanding bugs and should cause no bc breaks for this module, since the only bc breaks upstream are in regard to features we don't expose in this module.
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # sanitize-html
2
2
 
3
- [![CircleCI](https://circleci.com/gh/punkave/sanitize-html/tree/master.svg?style=svg)](https://circleci.com/gh/punkave/sanitize-html/tree/master)
3
+ [![CircleCI](https://circleci.com/gh/apostrophecms/sanitize-html/tree/master.svg?style=svg)](https://circleci.com/gh/apostrophecms/sanitize-html/tree/master)
4
4
 
5
- <a href="https://apostrophecms.org/"><img src="https://raw.github.com/punkave/sanitize-html/master/logos/logo-box-madefor.png" align="right" /></a>
5
+ <a href="https://apostrophecms.com/"><img src="https://raw.github.com/apostrophecms/sanitize-html/master/logos/logo-box-madefor.png" align="right" /></a>
6
6
 
7
7
  `sanitize-html` provides a simple HTML sanitizer with a clear API.
8
8
 
@@ -318,7 +318,9 @@ We can do that with the following filter:
318
318
  sanitizeHtml(
319
319
  '<p>some text...</p>',
320
320
  {
321
- textFilter: function(text) {
321
+ textFilter: function(text, tagName) {
322
+ if (['a'].indexOf(tagName) > -1) return //Skip anchor tags
323
+
322
324
  return text.replace(/\.\.\./, '&hellip;');
323
325
  }
324
326
  }
@@ -515,10 +517,10 @@ Valid values are: `'discard'` (default), `'escape'` (escape the tag) and `'recur
515
517
 
516
518
  ## Changelog
517
519
 
518
- [The changelog is now in a separate file for readability.](https://github.com/punkave/sanitize-html/blob/master/CHANGELOG.md)
520
+ [The changelog is now in a separate file for readability.](https://github.com/apostrophecms/sanitize-html/blob/master/CHANGELOG.md)
519
521
 
520
522
  ## Support
521
523
 
522
- Feel free to open issues on [github](http://github.com/punkave/sanitize-html).
524
+ Feel free to open issues on [github](http://github.com/apostrophecms/sanitize-html).
523
525
 
524
- <a href="http://punkave.com/"><img src="https://raw.github.com/punkave/sanitize-html/master/logos/logo-box-builtby.png" /></a>
526
+ <a href="http://apostrophecms.com/"><img src="https://raw.github.com/apostrophecms/sanitize-html/master/logos/logo-box-builtby.png" /></a>
@@ -20807,6 +20807,7 @@ function extend() {
20807
20807
  }
20808
20808
 
20809
20809
  },{}],83:[function(require,module,exports){
20810
+ /* eslint-disable no-useless-escape */
20810
20811
  var htmlparser = require('htmlparser2');
20811
20812
  var extend = require('xtend');
20812
20813
  var quoteRegexp = require('lodash.escaperegexp');
@@ -20819,9 +20820,11 @@ var postcss = require('postcss');
20819
20820
  var url = require('url');
20820
20821
 
20821
20822
  function each(obj, cb) {
20822
- if (obj) Object.keys(obj).forEach(function (key) {
20823
- cb(obj[key], key);
20824
- });
20823
+ if (obj) {
20824
+ Object.keys(obj).forEach(function (key) {
20825
+ cb(obj[key], key);
20826
+ });
20827
+ }
20825
20828
  }
20826
20829
 
20827
20830
  // Avoid false positives with .__proto__, .hasOwnProperty, etc.
@@ -20841,7 +20844,7 @@ function filter(a, cb) {
20841
20844
  }
20842
20845
 
20843
20846
  function isEmptyObject(obj) {
20844
- for(var key in obj) {
20847
+ for (var key in obj) {
20845
20848
  if (has(obj, key)) {
20846
20849
  return false;
20847
20850
  }
@@ -20882,8 +20885,8 @@ function sanitizeHtml(html, options, _recursing) {
20882
20885
 
20883
20886
  this.updateParentNodeText = function() {
20884
20887
  if (stack.length) {
20885
- var parentFrame = stack[stack.length - 1];
20886
- parentFrame.text += that.text;
20888
+ var parentFrame = stack[stack.length - 1];
20889
+ parentFrame.text += that.text;
20887
20890
  }
20888
20891
  };
20889
20892
  }
@@ -20907,14 +20910,14 @@ function sanitizeHtml(html, options, _recursing) {
20907
20910
  var nonTextTagsArray = options.nonTextTags || [ 'script', 'style', 'textarea' ];
20908
20911
  var allowedAttributesMap;
20909
20912
  var allowedAttributesGlobMap;
20910
- if(options.allowedAttributes) {
20913
+ if (options.allowedAttributes) {
20911
20914
  allowedAttributesMap = {};
20912
20915
  allowedAttributesGlobMap = {};
20913
20916
  each(options.allowedAttributes, function(attributes, tag) {
20914
20917
  allowedAttributesMap[tag] = [];
20915
20918
  var globRegex = [];
20916
20919
  attributes.forEach(function(obj) {
20917
- if(isString(obj) && obj.indexOf('*') >= 0) {
20920
+ if (isString(obj) && obj.indexOf('*') >= 0) {
20918
20921
  globRegex.push(quoteRegexp(obj).replace(/\\\*/g, '.*'));
20919
20922
  } else {
20920
20923
  allowedAttributesMap[tag].push(obj);
@@ -20926,14 +20929,14 @@ function sanitizeHtml(html, options, _recursing) {
20926
20929
  var allowedClassesMap = {};
20927
20930
  each(options.allowedClasses, function(classes, tag) {
20928
20931
  // Implicitly allows the class attribute
20929
- if(allowedAttributesMap) {
20932
+ if (allowedAttributesMap) {
20930
20933
  if (!has(allowedAttributesMap, tag)) {
20931
20934
  allowedAttributesMap[tag] = [];
20932
20935
  }
20933
20936
  allowedAttributesMap[tag].push('class');
20934
20937
  }
20935
20938
 
20936
- allowedClassesMap[tag] = classes
20939
+ allowedClassesMap[tag] = classes;
20937
20940
  });
20938
20941
 
20939
20942
  var transformTagsMap = {};
@@ -20969,7 +20972,7 @@ function sanitizeHtml(html, options, _recursing) {
20969
20972
  stack.push(frame);
20970
20973
 
20971
20974
  var skip = false;
20972
- var hasText = frame.text ? true : false;
20975
+ var hasText = !!frame.text;
20973
20976
  var transformedTag;
20974
20977
  if (has(transformTagsMap, name)) {
20975
20978
  transformedTag = transformTagsMap[name](name, attribs);
@@ -21029,11 +21032,11 @@ function sanitizeHtml(html, options, _recursing) {
21029
21032
  // as necessary if there are specific values defined.
21030
21033
  var passedAllowedAttributesMapCheck = false;
21031
21034
  if (!allowedAttributesMap ||
21032
- (has(allowedAttributesMap, name) && allowedAttributesMap[name].indexOf(a) !== -1 ) ||
21033
- (allowedAttributesMap['*'] && allowedAttributesMap['*'].indexOf(a) !== -1 ) ||
21035
+ (has(allowedAttributesMap, name) && allowedAttributesMap[name].indexOf(a) !== -1) ||
21036
+ (allowedAttributesMap['*'] && allowedAttributesMap['*'].indexOf(a) !== -1) ||
21034
21037
  (has(allowedAttributesGlobMap, name) && allowedAttributesGlobMap[name].test(a)) ||
21035
21038
  (allowedAttributesGlobMap['*'] && allowedAttributesGlobMap['*'].test(a))) {
21036
- passedAllowedAttributesMapCheck = true;
21039
+ passedAllowedAttributesMapCheck = true;
21037
21040
  } else if (allowedAttributesMap && allowedAttributesMap[name]) {
21038
21041
  for (const o of allowedAttributesMap[name]) {
21039
21042
  if (isPlainObject(o) && o.name && (o.name === a)) {
@@ -21075,8 +21078,8 @@ function sanitizeHtml(html, options, _recursing) {
21075
21078
  var isRelativeUrl = parsed && parsed.host === null && parsed.protocol === null;
21076
21079
  if (isRelativeUrl) {
21077
21080
  // default value of allowIframeRelativeUrls is true unless allowIframeHostnames specified
21078
- allowed = has(options, "allowIframeRelativeUrls") ?
21079
- options.allowIframeRelativeUrls : !options.allowedIframeHostnames;
21081
+ allowed = has(options, "allowIframeRelativeUrls")
21082
+ ? options.allowIframeRelativeUrls : !options.allowedIframeHostnames;
21080
21083
  } else if (options.allowedIframeHostnames) {
21081
21084
  allowed = options.allowedIframeHostnames.find(function (hostname) {
21082
21085
  return hostname === parsed.hostname;
@@ -21131,7 +21134,7 @@ function sanitizeHtml(html, options, _recursing) {
21131
21134
 
21132
21135
  value = stringifyStyleAttributes(filteredAST);
21133
21136
 
21134
- if(value.length === 0) {
21137
+ if (value.length === 0) {
21135
21138
  delete frame.attribs[a];
21136
21139
  return;
21137
21140
  }
@@ -21166,7 +21169,7 @@ function sanitizeHtml(html, options, _recursing) {
21166
21169
  if (skipText) {
21167
21170
  return;
21168
21171
  }
21169
- var lastFrame = stack[stack.length-1];
21172
+ var lastFrame = stack[stack.length - 1];
21170
21173
  var tag;
21171
21174
 
21172
21175
  if (lastFrame) {
@@ -21184,14 +21187,14 @@ function sanitizeHtml(html, options, _recursing) {
21184
21187
  } else {
21185
21188
  var escaped = escapeHtml(text, false);
21186
21189
  if (options.textFilter) {
21187
- result += options.textFilter(escaped);
21190
+ result += options.textFilter(escaped, tag);
21188
21191
  } else {
21189
21192
  result += escaped;
21190
21193
  }
21191
21194
  }
21192
21195
  if (stack.length) {
21193
- var frame = stack[stack.length - 1];
21194
- frame.text += text;
21196
+ var frame = stack[stack.length - 1];
21197
+ frame.text += text;
21195
21198
  }
21196
21199
  },
21197
21200
  onclosetag: function(name) {
@@ -21229,15 +21232,15 @@ function sanitizeHtml(html, options, _recursing) {
21229
21232
  }
21230
21233
 
21231
21234
  if (options.exclusiveFilter && options.exclusiveFilter(frame)) {
21232
- result = result.substr(0, frame.tagPosition);
21233
- return;
21235
+ result = result.substr(0, frame.tagPosition);
21236
+ return;
21234
21237
  }
21235
21238
 
21236
21239
  frame.updateParentNodeText();
21237
21240
 
21238
21241
  if (options.selfClosing.indexOf(name) !== -1) {
21239
- // Already output />
21240
- return;
21242
+ // Already output />
21243
+ return;
21241
21244
  }
21242
21245
 
21243
21246
  result += "</" + name + ">";
@@ -21253,7 +21256,7 @@ function sanitizeHtml(html, options, _recursing) {
21253
21256
  return result;
21254
21257
 
21255
21258
  function escapeHtml(s, quote) {
21256
- if (typeof(s) !== 'string') {
21259
+ if (typeof (s) !== 'string') {
21257
21260
  s = s + '';
21258
21261
  }
21259
21262
  if (options.parser.decodeEntities) {
@@ -21280,6 +21283,7 @@ function sanitizeHtml(html, options, _recursing) {
21280
21283
  // Browsers ignore character codes of 32 (space) and below in a surprising
21281
21284
  // number of situations. Start reading here:
21282
21285
  // https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Embedded_tab
21286
+ // eslint-disable-next-line no-control-regex
21283
21287
  href = href.replace(/[\x00-\x20]+/g, '');
21284
21288
  // Clobber any comments in URLs, which the browser might
21285
21289
  // interpret inside an XML data island, allowing
@@ -5557,7 +5557,7 @@ if(psychotic){result.hostname=result.host=isAbsolute?'':srcPath.length?srcPath.s
5557
5557
  //this especially happens in cases like
5558
5558
  //url.resolveObject('mailto:local1@domain1', 'local2@domain2')
5559
5559
  var authInHost=result.host&&result.host.indexOf('@')>0?result.host.split('@'):false;if(authInHost){result.auth=authInHost.shift();result.host=result.hostname=authInHost.shift();}}mustEndAbs=mustEndAbs||result.host&&srcPath.length;if(mustEndAbs&&!isAbsolute){srcPath.unshift('');}if(!srcPath.length){result.pathname=null;result.path=null;}else{result.pathname=srcPath.join('/');}//to support request.http
5560
- if(!util.isNull(result.pathname)||!util.isNull(result.search)){result.path=(result.pathname?result.pathname:'')+(result.search?result.search:'');}result.auth=relative.auth||result.auth;result.slashes=result.slashes||relative.slashes;result.href=result.format();return result;};Url.prototype.parseHost=function(){var host=this.host;var port=portPattern.exec(host);if(port){port=port[0];if(port!==':'){this.port=port.substr(1);}host=host.substr(0,host.length-port.length);}if(host)this.hostname=host;};},{"./util":81,"punycode":64,"querystring":67}],81:[function(require,module,exports){'use strict';module.exports={isString:function isString(arg){return typeof arg==='string';},isObject:function isObject(arg){return _typeof(arg)==='object'&&arg!==null;},isNull:function isNull(arg){return arg===null;},isNullOrUndefined:function isNullOrUndefined(arg){return arg==null;}};},{}],82:[function(require,module,exports){module.exports=extend;var hasOwnProperty=Object.prototype.hasOwnProperty;function extend(){var target={};for(var i=0;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(hasOwnProperty.call(source,key)){target[key]=source[key];}}}return target;}},{}],83:[function(require,module,exports){var htmlparser=require('htmlparser2');var extend=require('xtend');var quoteRegexp=require('lodash.escaperegexp');var cloneDeep=require('lodash.clonedeep');var mergeWith=require('lodash.mergewith');var isString=require('lodash.isstring');var isPlainObject=require('lodash.isplainobject');var srcset=require('srcset');var postcss=require('postcss');var url=require('url');function each(obj,cb){if(obj)Object.keys(obj).forEach(function(key){cb(obj[key],key);});}// Avoid false positives with .__proto__, .hasOwnProperty, etc.
5560
+ if(!util.isNull(result.pathname)||!util.isNull(result.search)){result.path=(result.pathname?result.pathname:'')+(result.search?result.search:'');}result.auth=relative.auth||result.auth;result.slashes=result.slashes||relative.slashes;result.href=result.format();return result;};Url.prototype.parseHost=function(){var host=this.host;var port=portPattern.exec(host);if(port){port=port[0];if(port!==':'){this.port=port.substr(1);}host=host.substr(0,host.length-port.length);}if(host)this.hostname=host;};},{"./util":81,"punycode":64,"querystring":67}],81:[function(require,module,exports){'use strict';module.exports={isString:function isString(arg){return typeof arg==='string';},isObject:function isObject(arg){return _typeof(arg)==='object'&&arg!==null;},isNull:function isNull(arg){return arg===null;},isNullOrUndefined:function isNullOrUndefined(arg){return arg==null;}};},{}],82:[function(require,module,exports){module.exports=extend;var hasOwnProperty=Object.prototype.hasOwnProperty;function extend(){var target={};for(var i=0;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(hasOwnProperty.call(source,key)){target[key]=source[key];}}}return target;}},{}],83:[function(require,module,exports){/* eslint-disable no-useless-escape */var htmlparser=require('htmlparser2');var extend=require('xtend');var quoteRegexp=require('lodash.escaperegexp');var cloneDeep=require('lodash.clonedeep');var mergeWith=require('lodash.mergewith');var isString=require('lodash.isstring');var isPlainObject=require('lodash.isplainobject');var srcset=require('srcset');var postcss=require('postcss');var url=require('url');function each(obj,cb){if(obj){Object.keys(obj).forEach(function(key){cb(obj[key],key);});}}// Avoid false positives with .__proto__, .hasOwnProperty, etc.
5561
5561
  function has(obj,key){return{}.hasOwnProperty.call(obj,key);}// Returns those elements of `a` for which `cb(a)` returns truthy
5562
5562
  function filter(a,cb){var n=[];each(a,function(v){if(cb(v)){n.push(v);}});return n;}function isEmptyObject(obj){for(var key in obj){if(has(obj,key)){return false;}}return true;}module.exports=sanitizeHtml;// A valid attribute name.
5563
5563
  // We use a tolerant definition based on the set of strings defined by
@@ -5580,7 +5580,7 @@ this.updateParentNodeText=function(){if(stack.length){var parentFrame=stack[stac
5580
5580
  // If we are not allowing these tags, we should drop their content too.
5581
5581
  // For other tags you would drop the tag but keep its content.
5582
5582
  var nonTextTagsArray=options.nonTextTags||['script','style','textarea'];var allowedAttributesMap;var allowedAttributesGlobMap;if(options.allowedAttributes){allowedAttributesMap={};allowedAttributesGlobMap={};each(options.allowedAttributes,function(attributes,tag){allowedAttributesMap[tag]=[];var globRegex=[];attributes.forEach(function(obj){if(isString(obj)&&obj.indexOf('*')>=0){globRegex.push(quoteRegexp(obj).replace(/\\\*/g,'.*'));}else{allowedAttributesMap[tag].push(obj);}});allowedAttributesGlobMap[tag]=new RegExp('^('+globRegex.join('|')+')$');});}var allowedClassesMap={};each(options.allowedClasses,function(classes,tag){// Implicitly allows the class attribute
5583
- if(allowedAttributesMap){if(!has(allowedAttributesMap,tag)){allowedAttributesMap[tag]=[];}allowedAttributesMap[tag].push('class');}allowedClassesMap[tag]=classes;});var transformTagsMap={};var transformTagsAll;each(options.transformTags,function(transform,tag){var transFun;if(typeof transform==='function'){transFun=transform;}else if(typeof transform==="string"){transFun=sanitizeHtml.simpleTransform(transform);}if(tag==='*'){transformTagsAll=transFun;}else{transformTagsMap[tag]=transFun;}});var depth=0;var stack=[];var skipMap={};var transformMap={};var skipText=false;var skipTextDepth=0;var parser=new htmlparser.Parser({onopentag:function onopentag(name,attribs){if(skipText){skipTextDepth++;return;}var frame=new Frame(name,attribs);stack.push(frame);var skip=false;var hasText=frame.text?true:false;var transformedTag;if(has(transformTagsMap,name)){transformedTag=transformTagsMap[name](name,attribs);frame.attribs=attribs=transformedTag.attribs;if(transformedTag.text!==undefined){frame.innerText=transformedTag.text;}if(name!==transformedTag.tagName){frame.name=name=transformedTag.tagName;transformMap[depth]=transformedTag.tagName;}}if(transformTagsAll){transformedTag=transformTagsAll(name,attribs);frame.attribs=attribs=transformedTag.attribs;if(name!==transformedTag.tagName){frame.name=name=transformedTag.tagName;transformMap[depth]=transformedTag.tagName;}}if(options.allowedTags&&options.allowedTags.indexOf(name)===-1||options.disallowedTagsMode==='recursiveEscape'&&!isEmptyObject(skipMap)){skip=true;skipMap[depth]=true;if(options.disallowedTagsMode==='discard'){if(nonTextTagsArray.indexOf(name)!==-1){skipText=true;skipTextDepth=1;}}skipMap[depth]=true;}depth++;if(skip){if(options.disallowedTagsMode==='discard'){// We want the contents but not this tag
5583
+ if(allowedAttributesMap){if(!has(allowedAttributesMap,tag)){allowedAttributesMap[tag]=[];}allowedAttributesMap[tag].push('class');}allowedClassesMap[tag]=classes;});var transformTagsMap={};var transformTagsAll;each(options.transformTags,function(transform,tag){var transFun;if(typeof transform==='function'){transFun=transform;}else if(typeof transform==="string"){transFun=sanitizeHtml.simpleTransform(transform);}if(tag==='*'){transformTagsAll=transFun;}else{transformTagsMap[tag]=transFun;}});var depth=0;var stack=[];var skipMap={};var transformMap={};var skipText=false;var skipTextDepth=0;var parser=new htmlparser.Parser({onopentag:function onopentag(name,attribs){if(skipText){skipTextDepth++;return;}var frame=new Frame(name,attribs);stack.push(frame);var skip=false;var hasText=!!frame.text;var transformedTag;if(has(transformTagsMap,name)){transformedTag=transformTagsMap[name](name,attribs);frame.attribs=attribs=transformedTag.attribs;if(transformedTag.text!==undefined){frame.innerText=transformedTag.text;}if(name!==transformedTag.tagName){frame.name=name=transformedTag.tagName;transformMap[depth]=transformedTag.tagName;}}if(transformTagsAll){transformedTag=transformTagsAll(name,attribs);frame.attribs=attribs=transformedTag.attribs;if(name!==transformedTag.tagName){frame.name=name=transformedTag.tagName;transformMap[depth]=transformedTag.tagName;}}if(options.allowedTags&&options.allowedTags.indexOf(name)===-1||options.disallowedTagsMode==='recursiveEscape'&&!isEmptyObject(skipMap)){skip=true;skipMap[depth]=true;if(options.disallowedTagsMode==='discard'){if(nonTextTagsArray.indexOf(name)!==-1){skipText=true;skipTextDepth=1;}}skipMap[depth]=true;}depth++;if(skip){if(options.disallowedTagsMode==='discard'){// We want the contents but not this tag
5584
5584
  return;}tempResult=result;result='';}result+='<'+name;if(!allowedAttributesMap||has(allowedAttributesMap,name)||allowedAttributesMap['*']){each(attribs,function(value,a){if(!VALID_HTML_ATTRIBUTE_NAME.test(a)){// This prevents part of an attribute name in the output from being
5585
5585
  // interpreted as the end of an attribute, or end of a tag.
5586
5586
  delete frame.attribs[a];return;}var parsed;// check allowedAttributesMap for the element and attribute and modify the value
@@ -5597,7 +5597,7 @@ text=lastFrame.innerText!==undefined?lastFrame.innerText:text;}if(options.disall
5597
5597
  // script tags is, by definition, game over for XSS protection, so if that's
5598
5598
  // your concern, don't allow them. The same is essentially true for style tags
5599
5599
  // which have their own collection of XSS vectors.
5600
- result+=text;}else{var escaped=escapeHtml(text,false);if(options.textFilter){result+=options.textFilter(escaped);}else{result+=escaped;}}if(stack.length){var frame=stack[stack.length-1];frame.text+=text;}},onclosetag:function onclosetag(name){if(skipText){skipTextDepth--;if(!skipTextDepth){skipText=false;}else{return;}}var frame=stack.pop();if(!frame){// Do not crash on bad markup
5600
+ result+=text;}else{var escaped=escapeHtml(text,false);if(options.textFilter){result+=options.textFilter(escaped,tag);}else{result+=escaped;}}if(stack.length){var frame=stack[stack.length-1];frame.text+=text;}},onclosetag:function onclosetag(name){if(skipText){skipTextDepth--;if(!skipTextDepth){skipText=false;}else{return;}}var frame=stack.pop();if(!frame){// Do not crash on bad markup
5601
5601
  return;}skipText=false;depth--;var skip=skipMap[depth];if(skip){delete skipMap[depth];if(options.disallowedTagsMode==='discard'){frame.updateParentNodeText();return;}tempResult=result;result='';}if(transformMap[depth]){name=transformMap[depth];delete transformMap[depth];}if(options.exclusiveFilter&&options.exclusiveFilter(frame)){result=result.substr(0,frame.tagPosition);return;}frame.updateParentNodeText();if(options.selfClosing.indexOf(name)!==-1){// Already output />
5602
5602
  return;}result+="</"+name+">";if(skip){result=tempResult+escapeHtml(result);tempResult='';}}},options.parser);parser.write(html);parser.end();return result;function escapeHtml(s,quote){if(typeof s!=='string'){s=s+'';}if(options.parser.decodeEntities){s=s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/\>/g,'&gt;');if(quote){s=s.replace(/\"/g,'&quot;');}}// TODO: this is inadequate because it will pass `&0;`. This approach
5603
5603
  // will not work, each & must be considered with regard to whether it
@@ -5608,6 +5608,7 @@ s=s.replace(/&(?![a-zA-Z0-9#]{1,20};)/g,'&amp;')// Match ampersands not part of
5608
5608
  .replace(/</g,'&lt;').replace(/\>/g,'&gt;');if(quote){s=s.replace(/\"/g,'&quot;');}return s;}function naughtyHref(name,href){// Browsers ignore character codes of 32 (space) and below in a surprising
5609
5609
  // number of situations. Start reading here:
5610
5610
  // https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Embedded_tab
5611
+ // eslint-disable-next-line no-control-regex
5611
5612
  href=href.replace(/[\x00-\x20]+/g,'');// Clobber any comments in URLs, which the browser might
5612
5613
  // interpret inside an XML data island, allowing
5613
5614
  // a javascript: URL to be snuck through