You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							127 lines
						
					
					
						
							3.3 KiB
						
					
					
				
			
		
		
	
	
							127 lines
						
					
					
						
							3.3 KiB
						
					
					
				"use strict";
 | 
						|
 | 
						|
const fastDecode = require("fast-decode-uri-component");
 | 
						|
 | 
						|
const plusRegex = /\+/g;
 | 
						|
const Empty = function () {};
 | 
						|
Empty.prototype = Object.create(null);
 | 
						|
 | 
						|
/**
 | 
						|
 * @callback parse
 | 
						|
 * @param {string} input
 | 
						|
 */
 | 
						|
function parse(input) {
 | 
						|
  // Optimization: Use new Empty() instead of Object.create(null) for performance
 | 
						|
  // v8 has a better optimization for initializing functions compared to Object
 | 
						|
  const result = new Empty();
 | 
						|
 | 
						|
  if (typeof input !== "string") {
 | 
						|
    return result;
 | 
						|
  }
 | 
						|
 | 
						|
  let inputLength = input.length;
 | 
						|
  let key = "";
 | 
						|
  let value = "";
 | 
						|
  let startingIndex = -1;
 | 
						|
  let equalityIndex = -1;
 | 
						|
  let shouldDecodeKey = false;
 | 
						|
  let shouldDecodeValue = false;
 | 
						|
  let keyHasPlus = false;
 | 
						|
  let valueHasPlus = false;
 | 
						|
  let hasBothKeyValuePair = false;
 | 
						|
  let c = 0;
 | 
						|
 | 
						|
  // Have a boundary of input.length + 1 to access last pair inside the loop.
 | 
						|
  for (let i = 0; i < inputLength + 1; i++) {
 | 
						|
    c = i !== inputLength ? input.charCodeAt(i) : 38;
 | 
						|
 | 
						|
    // Handle '&' and end of line to pass the current values to result
 | 
						|
    if (c === 38) {
 | 
						|
      hasBothKeyValuePair = equalityIndex > startingIndex;
 | 
						|
 | 
						|
      // Optimization: Reuse equality index to store the end of key
 | 
						|
      if (!hasBothKeyValuePair) {
 | 
						|
        equalityIndex = i;
 | 
						|
      }
 | 
						|
 | 
						|
      key = input.slice(startingIndex + 1, equalityIndex);
 | 
						|
 | 
						|
      // Add key/value pair only if the range size is greater than 1; a.k.a. contains at least "="
 | 
						|
      if (hasBothKeyValuePair || key.length > 0) {
 | 
						|
        // Optimization: Replace '+' with space
 | 
						|
        if (keyHasPlus) {
 | 
						|
          key = key.replace(plusRegex, " ");
 | 
						|
        }
 | 
						|
 | 
						|
        // Optimization: Do not decode if it's not necessary.
 | 
						|
        if (shouldDecodeKey) {
 | 
						|
          key = fastDecode(key) || key;
 | 
						|
        }
 | 
						|
 | 
						|
        if (hasBothKeyValuePair) {
 | 
						|
          value = input.slice(equalityIndex + 1, i);
 | 
						|
 | 
						|
          if (valueHasPlus) {
 | 
						|
            value = value.replace(plusRegex, " ");
 | 
						|
          }
 | 
						|
 | 
						|
          if (shouldDecodeValue) {
 | 
						|
            value = fastDecode(value) || value;
 | 
						|
          }
 | 
						|
        }
 | 
						|
        const currentValue = result[key];
 | 
						|
 | 
						|
        if (currentValue === undefined) {
 | 
						|
          result[key] = value;
 | 
						|
        } else {
 | 
						|
          // Optimization: value.pop is faster than Array.isArray(value)
 | 
						|
          if (currentValue.pop) {
 | 
						|
            currentValue.push(value);
 | 
						|
          } else {
 | 
						|
            result[key] = [currentValue, value];
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      // Reset reading key value pairs
 | 
						|
      value = "";
 | 
						|
      startingIndex = i;
 | 
						|
      equalityIndex = i;
 | 
						|
      shouldDecodeKey = false;
 | 
						|
      shouldDecodeValue = false;
 | 
						|
      keyHasPlus = false;
 | 
						|
      valueHasPlus = false;
 | 
						|
    }
 | 
						|
    // Check '='
 | 
						|
    else if (c === 61) {
 | 
						|
      if (equalityIndex <= startingIndex) {
 | 
						|
        equalityIndex = i;
 | 
						|
      }
 | 
						|
      // If '=' character occurs again, we should decode the input.
 | 
						|
      else {
 | 
						|
        shouldDecodeValue = true;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    // Check '+', and remember to replace it with empty space.
 | 
						|
    else if (c === 43) {
 | 
						|
      if (equalityIndex > startingIndex) {
 | 
						|
        valueHasPlus = true;
 | 
						|
      } else {
 | 
						|
        keyHasPlus = true;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    // Check '%' character for encoding
 | 
						|
    else if (c === 37) {
 | 
						|
      if (equalityIndex > startingIndex) {
 | 
						|
        shouldDecodeValue = true;
 | 
						|
      } else {
 | 
						|
        shouldDecodeKey = true;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
module.exports = parse;
 |