summaryrefslogtreecommitdiff
path: root/std/node/querystring.ts
diff options
context:
space:
mode:
Diffstat (limited to 'std/node/querystring.ts')
-rw-r--r--std/node/querystring.ts169
1 files changed, 166 insertions, 3 deletions
diff --git a/std/node/querystring.ts b/std/node/querystring.ts
index ff68b2ae8..73e46c424 100644
--- a/std/node/querystring.ts
+++ b/std/node/querystring.ts
@@ -1,4 +1,167 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-export * from "./_querystring.ts";
-import * as m from "./_querystring.ts";
-export default m;
+
+interface ParseOptions {
+ /** The function to use when decoding percent-encoded characters in the query string. */
+ decodeURIComponent?: (string: string) => string;
+ /** Specifies the maximum number of keys to parse. */
+ maxKeys?: number;
+}
+
+export const hexTable = new Array(256);
+for (let i = 0; i < 256; ++i) {
+ hexTable[i] = "%" + ((i < 16 ? "0" : "") + i.toString(16)).toUpperCase();
+}
+
+/**
+ * Parses a URL query string into a collection of key and value pairs.
+ * @param str The URL query string to parse
+ * @param sep The substring used to delimit key and value pairs in the query string. Default: '&'.
+ * @param eq The substring used to delimit keys and values in the query string. Default: '='.
+ * @param options The parse options
+ */
+export function parse(
+ str: string,
+ sep = "&",
+ eq = "=",
+ { decodeURIComponent = unescape, maxKeys = 1000 }: ParseOptions = {},
+): { [key: string]: string[] | string } {
+ const entries = str
+ .split(sep)
+ .map((entry) => entry.split(eq).map(decodeURIComponent));
+ const final: { [key: string]: string[] | string } = {};
+
+ let i = 0;
+ while (true) {
+ if ((Object.keys(final).length === maxKeys && !!maxKeys) || !entries[i]) {
+ break;
+ }
+
+ const [key, val] = entries[i];
+ if (final[key]) {
+ if (Array.isArray(final[key])) {
+ (final[key] as string[]).push(val);
+ } else {
+ final[key] = [final[key] as string, val];
+ }
+ } else {
+ final[key] = val;
+ }
+
+ i++;
+ }
+
+ return final;
+}
+
+interface StringifyOptions {
+ /** The function to use when converting URL-unsafe characters to percent-encoding in the query string. */
+ encodeURIComponent?: (string: string) => string;
+}
+
+export function encodeStr(
+ str: string,
+ noEscapeTable: number[],
+ hexTable: string[],
+): string {
+ const len = str.length;
+ if (len === 0) return "";
+
+ let out = "";
+ let lastPos = 0;
+
+ for (let i = 0; i < len; i++) {
+ let c = str.charCodeAt(i);
+ // ASCII
+ if (c < 0x80) {
+ if (noEscapeTable[c] === 1) continue;
+ if (lastPos < i) out += str.slice(lastPos, i);
+ lastPos = i + 1;
+ out += hexTable[c];
+ continue;
+ }
+
+ if (lastPos < i) out += str.slice(lastPos, i);
+
+ // Multi-byte characters ...
+ if (c < 0x800) {
+ lastPos = i + 1;
+ out += hexTable[0xc0 | (c >> 6)] + hexTable[0x80 | (c & 0x3f)];
+ continue;
+ }
+ if (c < 0xd800 || c >= 0xe000) {
+ lastPos = i + 1;
+ out += hexTable[0xe0 | (c >> 12)] +
+ hexTable[0x80 | ((c >> 6) & 0x3f)] +
+ hexTable[0x80 | (c & 0x3f)];
+ continue;
+ }
+ // Surrogate pair
+ ++i;
+
+ // This branch should never happen because all URLSearchParams entries
+ // should already be converted to USVString. But, included for
+ // completion's sake anyway.
+ if (i >= len) throw new Deno.errors.InvalidData("invalid URI");
+
+ const c2 = str.charCodeAt(i) & 0x3ff;
+
+ lastPos = i + 1;
+ c = 0x10000 + (((c & 0x3ff) << 10) | c2);
+ out += hexTable[0xf0 | (c >> 18)] +
+ hexTable[0x80 | ((c >> 12) & 0x3f)] +
+ hexTable[0x80 | ((c >> 6) & 0x3f)] +
+ hexTable[0x80 | (c & 0x3f)];
+ }
+ if (lastPos === 0) return str;
+ if (lastPos < len) return out + str.slice(lastPos);
+ return out;
+}
+
+/**
+ * Produces a URL query string from a given obj by iterating through the object's "own properties".
+ * @param obj The object to serialize into a URL query string.
+ * @param sep The substring used to delimit key and value pairs in the query string. Default: '&'.
+ * @param eq The substring used to delimit keys and values in the query string. Default: '='.
+ * @param options The stringify options
+ */
+export function stringify(
+ // deno-lint-ignore no-explicit-any
+ obj: Record<string, any>,
+ sep = "&",
+ eq = "=",
+ { encodeURIComponent = escape }: StringifyOptions = {},
+): string {
+ const final = [];
+
+ for (const entry of Object.entries(obj)) {
+ if (Array.isArray(entry[1])) {
+ for (const val of entry[1]) {
+ final.push(encodeURIComponent(entry[0]) + eq + encodeURIComponent(val));
+ }
+ } else if (typeof entry[1] !== "object" && entry[1] !== undefined) {
+ final.push(entry.map(encodeURIComponent).join(eq));
+ } else {
+ final.push(encodeURIComponent(entry[0]) + eq);
+ }
+ }
+
+ return final.join(sep);
+}
+
+/** Alias of querystring.parse() */
+export const decode = parse;
+/** Alias of querystring.stringify() */
+export const encode = stringify;
+export const unescape = decodeURIComponent;
+export const escape = encodeURIComponent;
+
+export default {
+ parse,
+ encodeStr,
+ stringify,
+ hexTable,
+ decode,
+ encode,
+ unescape,
+ escape,
+};