UNPKG

awesome-string

Version:

The ultimate JavaScript string library

157 lines (155 loc) 4.3 kB
import coerceToString from 'helper/string/coerce_to_string'; import hasSubstringAtIndex from 'helper/string/has_substring_at_index'; import parseTagList from 'helper/strip/parse_tag_list'; import parseTagName from 'helper/strip/parse_tag_name'; const STATE_OUTPUT = 0; const STATE_HTML = 1; const STATE_EXCLAMATION = 2; const STATE_COMMENT = 3; /** * Strips HTML tags from `subject`. * * @function stripTags * @static * @since 1.1.0 * @memberOf Strip * @param {string} [subject=''] The string to strip from. * @param {string|Array} [allowableTags] The string `'<tag1><tag2>'` or array `['tag1', 'tag2']` of tags that should not be stripped. * @param {string} [replacement=''] The string to replace the stripped tag. * @return {string} Returns the stripped string. * @example * * as.stripTags('<span><a href="#">Summer</a> is nice</span>'); * // => 'Summer is nice' * * as.stripTags('<span><i>Winter</i> is <b>cold</b></span>', ['b', 'i']); * // => '<i>Winter</i> is <b>cold</b>' * * as.stripTags('Sun<br/>set', '', '-'); * // => 'Sun-set' */ export default function trim(subject, allowableTags, replacement) { subject = coerceToString(subject); if (subject === '') { return ''; } if (!Array.isArray(allowableTags)) { const allowableTagsString = coerceToString(allowableTags); allowableTags = allowableTagsString === '' ? [] : parseTagList(allowableTagsString); } const replacementString = coerceToString(replacement); const length = subject.length; const hasAllowableTags = allowableTags.length > 0; const hasSubstring = hasSubstringAtIndex.bind(null, subject); let state = STATE_OUTPUT; let depth = 0; let output = ''; let tagContent = ''; let quote = null; for (let index = 0; index < length; index++) { const char = subject[index]; let advance = false; switch (char) { case '<': if (quote) { break; } if (hasSubstring('< ', index, false)) { advance = true; break; } if (state === STATE_OUTPUT) { advance = true; state = STATE_HTML; break; } if (state === STATE_HTML) { depth++; break; } advance = true; break; case '!': if (state === STATE_HTML && hasSubstring('<!', index)) { state = STATE_EXCLAMATION; break; } advance = true; break; case '-': if (state === STATE_EXCLAMATION && hasSubstring('!--', index)) { state = STATE_COMMENT; break; } advance = true; break; case '"': case "'": if (state === STATE_HTML) { if (quote === char) { quote = null; } else if (!quote) { quote = char; } } advance = true; break; case 'E': case 'e': if (state === STATE_EXCLAMATION && hasSubstring('doctype', index)) { state = STATE_HTML; break; } advance = true; break; case '>': if (depth > 0) { depth--; break; } if (quote) { break; } if (state === STATE_HTML) { quote = null; state = STATE_OUTPUT; if (hasAllowableTags) { tagContent += '>'; const tagName = parseTagName(tagContent); if (allowableTags.indexOf(tagName.toLowerCase()) !== -1) { output += tagContent; } else { output += replacementString; } tagContent = ''; } else { output += replacementString; } break; } if (state === STATE_EXCLAMATION || state === STATE_COMMENT && hasSubstring('-->', index)) { quote = null; state = STATE_OUTPUT; tagContent = ''; break; } advance = true; break; default: advance = true; } if (advance) { switch (state) { case STATE_OUTPUT: output += char; break; case STATE_HTML: if (hasAllowableTags) { tagContent += char; } break; } } } return output; }