1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-28 16:20:57 -05:00

fix(ext/node): querystring stringify without encode callback (#21740)

Fixes https://github.com/denoland/deno/issues/21734

Changes:
- Use default encode when options do not provide a encode callback.
- Remove internal TS for `node:querystring`. Its not helping catching
bugs like this because of invalid type assumptions and use of `any`,
more of a maintenance burden.
This commit is contained in:
Divy Srivastava 2024-01-02 10:24:11 +05:30 committed by GitHub
parent b21462355a
commit 642c4a44a5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 52 additions and 63 deletions

View file

@ -28,3 +28,24 @@ Deno.test({
}); });
}, },
}); });
// https://github.com/denoland/deno/issues/21734
Deno.test({
name: "stringify options no encode",
fn() {
assertEquals(
stringify(
{
a: "hello",
b: 5,
c: true,
d: ["foo", "bar"],
},
"&",
"=",
{},
),
"a=hello&b=5&c=true&d=foo&d=bar",
);
},
});

View file

@ -523,7 +523,7 @@ deno_core::extension!(deno_node,
"perf_hooks.ts" with_specifier "node:perf_hooks", "perf_hooks.ts" with_specifier "node:perf_hooks",
"process.ts" with_specifier "node:process", "process.ts" with_specifier "node:process",
"punycode.ts" with_specifier "node:punycode", "punycode.ts" with_specifier "node:punycode",
"querystring.ts" with_specifier "node:querystring", "querystring.js" with_specifier "node:querystring",
"readline.ts" with_specifier "node:readline", "readline.ts" with_specifier "node:readline",
"repl.ts" with_specifier "node:repl", "repl.ts" with_specifier "node:repl",
"stream.ts" with_specifier "node:stream", "stream.ts" with_specifier "node:stream",

View file

@ -22,7 +22,7 @@ export const encode = stringify;
* replaces encodeURIComponent() * replaces encodeURIComponent()
* @see https://www.ecma-international.org/ecma-262/5.1/#sec-15.1.3.4 * @see https://www.ecma-international.org/ecma-262/5.1/#sec-15.1.3.4
*/ */
function qsEscape(str: unknown): string { function qsEscape(str) {
if (typeof str !== "string") { if (typeof str !== "string") {
if (typeof str === "object") { if (typeof str === "object") {
str = String(str); str = String(str);
@ -30,7 +30,7 @@ function qsEscape(str: unknown): string {
str += ""; str += "";
} }
} }
return encodeStr(str as string, noEscape, hexTable); return encodeStr(str, noEscape, hexTable);
} }
/** /**
@ -42,29 +42,6 @@ function qsEscape(str: unknown): string {
*/ */
export const escape = qsEscape; export const escape = qsEscape;
export interface ParsedUrlQuery {
[key: string]: string | string[] | undefined;
}
export interface ParsedUrlQueryInput {
[key: string]:
| string
| number
| boolean
| ReadonlyArray<string>
| ReadonlyArray<number>
| ReadonlyArray<boolean>
| null
| undefined;
}
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;
}
// deno-fmt-ignore // deno-fmt-ignore
const isHexTable = new Int8Array([ const isHexTable = new Int8Array([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15
@ -85,7 +62,7 @@ const isHexTable = new Int8Array([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ... 256 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ... 256
]); ]);
function charCodes(str: string): number[] { function charCodes(str) {
const ret = new Array(str.length); const ret = new Array(str.length);
for (let i = 0; i < str.length; ++i) { for (let i = 0; i < str.length; ++i) {
ret[i] = str.charCodeAt(i); ret[i] = str.charCodeAt(i);
@ -94,12 +71,12 @@ function charCodes(str: string): number[] {
} }
function addKeyVal( function addKeyVal(
obj: ParsedUrlQuery, obj,
key: string, key,
value: string, value,
keyEncoded: boolean, keyEncoded,
valEncoded: boolean, valEncoded,
decode: (encodedURIComponent: string) => string, decode,
) { ) {
if (key.length > 0 && keyEncoded) { if (key.length > 0 && keyEncoded) {
key = decode(key); key = decode(key);
@ -115,10 +92,10 @@ function addKeyVal(
// A simple Array-specific property check is enough here to // A simple Array-specific property check is enough here to
// distinguish from a string value and is faster and still safe // distinguish from a string value and is faster and still safe
// since we are generating all of the values being assigned. // since we are generating all of the values being assigned.
if ((curValue as string[]).pop) { if (curValue.pop) {
(curValue as string[])[curValue!.length] = value; curValue[curValue.length] = value;
} else { } else {
obj[key] = [curValue as string, value]; obj[key] = [curValue, value];
} }
} }
} }
@ -135,12 +112,12 @@ function addKeyVal(
* @see Tested in test-querystring.js * @see Tested in test-querystring.js
*/ */
export function parse( export function parse(
str: string, str,
sep = "&", sep = "&",
eq = "=", eq = "=",
{ decodeURIComponent = unescape, maxKeys = 1000 }: ParseOptions = {}, { decodeURIComponent = unescape, maxKeys = 1000 } = {},
): ParsedUrlQuery { ) {
const obj: ParsedUrlQuery = Object.create(null); const obj = Object.create(null);
if (typeof str !== "string" || str.length === 0) { if (typeof str !== "string" || str.length === 0) {
return obj; return obj;
@ -298,11 +275,6 @@ export function parse(
return obj; return obj;
} }
interface StringifyOptions {
/** The function to use when converting URL-unsafe characters to percent-encoding in the query string. */
encodeURIComponent: (string: string) => string;
}
/** /**
* These characters do not need escaping when generating query strings: * These characters do not need escaping when generating query strings:
* ! - . _ ~ * ! - . _ ~
@ -323,8 +295,7 @@ const noEscape = new Int8Array([
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, // 112 - 127 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, // 112 - 127
]); ]);
// deno-lint-ignore no-explicit-any function stringifyPrimitive(v) {
function stringifyPrimitive(v: any): string {
if (typeof v === "string") { if (typeof v === "string") {
return v; return v;
} }
@ -341,15 +312,13 @@ function stringifyPrimitive(v: any): string {
} }
function encodeStringifiedCustom( function encodeStringifiedCustom(
// deno-lint-ignore no-explicit-any v,
v: any, encode,
encode: (string: string) => string, ) {
): string {
return encode(stringifyPrimitive(v)); return encode(stringifyPrimitive(v));
} }
// deno-lint-ignore no-explicit-any function encodeStringified(v, encode) {
function encodeStringified(v: any, encode: (string: string) => string): string {
if (typeof v === "string") { if (typeof v === "string") {
return (v.length ? encode(v) : ""); return (v.length ? encode(v) : "");
} }
@ -378,15 +347,14 @@ function encodeStringified(v: any, encode: (string: string) => string): string {
* @see Tested in `test-querystring.js` * @see Tested in `test-querystring.js`
*/ */
export function stringify( export function stringify(
// deno-lint-ignore no-explicit-any obj,
obj: Record<string, any>, sep,
sep?: string, eq,
eq?: string, options,
options?: StringifyOptions, ) {
): string {
sep ||= "&"; sep ||= "&";
eq ||= "="; eq ||= "=";
const encode = options ? options.encodeURIComponent : qsEscape; const encode = options ? (options.encodeURIComponent || qsEscape) : qsEscape;
const convert = options ? encodeStringifiedCustom : encodeStringified; const convert = options ? encodeStringifiedCustom : encodeStringified;
if (obj !== null && typeof obj === "object") { if (obj !== null && typeof obj === "object") {
@ -448,7 +416,7 @@ const unhexTable = new Int8Array([
/** /**
* A safe fast alternative to decodeURIComponent * A safe fast alternative to decodeURIComponent
*/ */
export function unescapeBuffer(s: string, decodeSpaces = false): Buffer { export function unescapeBuffer(s, decodeSpaces = false) {
const out = Buffer.alloc(s.length); const out = Buffer.alloc(s.length);
let index = 0; let index = 0;
let outIndex = 0; let outIndex = 0;
@ -490,7 +458,7 @@ export function unescapeBuffer(s: string, decodeSpaces = false): Buffer {
return hasHex ? out.slice(0, outIndex) : out; return hasHex ? out.slice(0, outIndex) : out;
} }
function qsUnescape(s: string): string { function qsUnescape(s) {
try { try {
return decodeURIComponent(s); return decodeURIComponent(s);
} catch { } catch {

View file

@ -181,7 +181,7 @@
"node:perf_hooks": "../ext/node/polyfills/perf_hooks.ts", "node:perf_hooks": "../ext/node/polyfills/perf_hooks.ts",
"node:process": "../ext/node/polyfills/process.ts", "node:process": "../ext/node/polyfills/process.ts",
"node:punycode": "../ext/node/polyfills/punycode.ts", "node:punycode": "../ext/node/polyfills/punycode.ts",
"node:querystring": "../ext/node/polyfills/querystring.ts", "node:querystring": "../ext/node/polyfills/querystring.js",
"node:readline": "../ext/node/polyfills/readline.ts", "node:readline": "../ext/node/polyfills/readline.ts",
"ext:deno_node/readline/promises.ts": "../ext/node/polyfills/readline/promises.ts", "ext:deno_node/readline/promises.ts": "../ext/node/polyfills/readline/promises.ts",
"ext:deno_node/repl.ts": "../ext/node/polyfills/repl.ts", "ext:deno_node/repl.ts": "../ext/node/polyfills/repl.ts",