proper string escaping
This commit is contained in:
parent
47756f7b23
commit
a798374d12
|
|
@ -55,7 +55,7 @@ class JSCodeGen implements APIRequestCodegen {
|
||||||
// Handle primitive types
|
// Handle primitive types
|
||||||
if (typeof obj !== 'object') {
|
if (typeof obj !== 'object') {
|
||||||
if (typeof obj === 'string')
|
if (typeof obj === 'string')
|
||||||
return `'${obj}'`;
|
return this.stringLiteral(obj);
|
||||||
return String(obj);
|
return String(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,12 +84,17 @@ class JSCodeGen implements APIRequestCodegen {
|
||||||
// Handle keys that need quotes
|
// Handle keys that need quotes
|
||||||
const formattedKey = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key) ?
|
const formattedKey = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key) ?
|
||||||
key :
|
key :
|
||||||
`'${key}'`;
|
this.stringLiteral(key);
|
||||||
return `${nextSpaces}${formattedKey}: ${formattedValue}`;
|
return `${nextSpaces}${formattedKey}: ${formattedValue}`;
|
||||||
}).join(',\n');
|
}).join(',\n');
|
||||||
|
|
||||||
return `{\n${entries}\n${spaces}}`;
|
return `{\n${entries}\n${spaces}}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private stringLiteral(v: string): string {
|
||||||
|
v = v.replace(/\\/g, '\\\\').replace(/'/g, '\\\'');
|
||||||
|
return `'${v}'`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PythonCodeGen implements APIRequestCodegen {
|
class PythonCodeGen implements APIRequestCodegen {
|
||||||
|
|
@ -130,7 +135,7 @@ class PythonCodeGen implements APIRequestCodegen {
|
||||||
// Handle primitive types
|
// Handle primitive types
|
||||||
if (typeof obj !== 'object') {
|
if (typeof obj !== 'object') {
|
||||||
if (typeof obj === 'string')
|
if (typeof obj === 'string')
|
||||||
return `"${obj.replaceAll('"', '\\"')}"`;
|
return this.stringLiteral(obj);
|
||||||
if (typeof obj === 'boolean')
|
if (typeof obj === 'boolean')
|
||||||
return obj ? 'True' : 'False';
|
return obj ? 'True' : 'False';
|
||||||
return String(obj);
|
return String(obj);
|
||||||
|
|
@ -158,11 +163,16 @@ class PythonCodeGen implements APIRequestCodegen {
|
||||||
|
|
||||||
const entries = Object.entries(obj).map(([key, value]) => {
|
const entries = Object.entries(obj).map(([key, value]) => {
|
||||||
const formattedValue = this.prettyPrintObject(value, indent, level + 1);
|
const formattedValue = this.prettyPrintObject(value, indent, level + 1);
|
||||||
return `${nextSpaces}"${key}": ${formattedValue}`;
|
return `${nextSpaces}${this.stringLiteral(key)}: ${formattedValue}`;
|
||||||
}).join(',\n');
|
}).join(',\n');
|
||||||
|
|
||||||
return `{\n${entries}\n${spaces}}`;
|
return `{\n${entries}\n${spaces}}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private stringLiteral(v: string): string {
|
||||||
|
v = v.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
||||||
|
return `"${v}"`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CSharpCodeGen implements APIRequestCodegen {
|
class CSharpCodeGen implements APIRequestCodegen {
|
||||||
|
|
@ -198,10 +208,6 @@ class CSharpCodeGen implements APIRequestCodegen {
|
||||||
return method[0].toUpperCase() + method.slice(1) + 'Async';
|
return method[0].toUpperCase() + method.slice(1) + 'Async';
|
||||||
}
|
}
|
||||||
|
|
||||||
private indent(v: string, level: number): string {
|
|
||||||
return v.split('\n').map(s => ' '.repeat(level) + s).join('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
private prettyPrintObject(obj: any, indent = 2, level = 0): string {
|
private prettyPrintObject(obj: any, indent = 2, level = 0): string {
|
||||||
// Handle null and undefined
|
// Handle null and undefined
|
||||||
if (obj === null)
|
if (obj === null)
|
||||||
|
|
@ -212,7 +218,7 @@ class CSharpCodeGen implements APIRequestCodegen {
|
||||||
// Handle primitive types
|
// Handle primitive types
|
||||||
if (typeof obj !== 'object') {
|
if (typeof obj !== 'object') {
|
||||||
if (typeof obj === 'string')
|
if (typeof obj === 'string')
|
||||||
return `"${obj.replace(/"/g, '\\"')}"`;
|
return this.stringLiteral(obj);
|
||||||
if (typeof obj === 'boolean')
|
if (typeof obj === 'boolean')
|
||||||
return obj ? 'true' : 'false';
|
return obj ? 'true' : 'false';
|
||||||
return String(obj);
|
return String(obj);
|
||||||
|
|
@ -240,12 +246,18 @@ class CSharpCodeGen implements APIRequestCodegen {
|
||||||
|
|
||||||
const entries = Object.entries(obj).map(([key, value]) => {
|
const entries = Object.entries(obj).map(([key, value]) => {
|
||||||
const formattedValue = this.prettyPrintObject(value, indent, level + 1);
|
const formattedValue = this.prettyPrintObject(value, indent, level + 1);
|
||||||
const formattedKey = level === 0 ? key : `["${key}"]`;
|
const formattedKey = level === 0 ? key : `[${this.stringLiteral(key)}]`;
|
||||||
return `${nextSpaces}${formattedKey} = ${formattedValue}`;
|
return `${nextSpaces}${formattedKey} = ${formattedValue}`;
|
||||||
}).join(',\n');
|
}).join(',\n');
|
||||||
|
|
||||||
return `new() {\n${entries}\n${spaces}}`;
|
return `new() {\n${entries}\n${spaces}}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private stringLiteral(v: string): string {
|
||||||
|
// escape douvle quotes and backslashes
|
||||||
|
v = v.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
||||||
|
return `"${v}"`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class JavaCodeGen implements APIRequestCodegen {
|
class JavaCodeGen implements APIRequestCodegen {
|
||||||
|
|
@ -262,16 +274,22 @@ class JavaCodeGen implements APIRequestCodegen {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [key, value] of url.searchParams)
|
for (const [key, value] of url.searchParams)
|
||||||
options.push(`setQueryParam("${key}", "${value}")`);
|
options.push(`setQueryParam(${this.stringLiteral(key)}, ${this.stringLiteral(value)})`);
|
||||||
if (body)
|
if (body)
|
||||||
options.push(`setData("${body.replaceAll('"', '\\"')}")`);
|
options.push(`setData(${this.stringLiteral(body)})`);
|
||||||
for (const header of request.headers)
|
for (const header of request.headers)
|
||||||
options.push(`setHeader("${header.name}", "${header.value}")`);
|
options.push(`setHeader(${this.stringLiteral(header.name)}, ${this.stringLiteral(header.value)})`);
|
||||||
|
|
||||||
if (options.length > 0)
|
if (options.length > 0)
|
||||||
params.push(`RequestOptions.create()\n .${options.join('\n .')}\n`);
|
params.push(`RequestOptions.create()\n .${options.join('\n .')}\n`);
|
||||||
return `request.${method}(${params.join(', ')});`;
|
return `request.${method}(${params.join(', ')});`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private stringLiteral(v: string): string {
|
||||||
|
// escape douvle quotes and backslashes
|
||||||
|
v = v.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
||||||
|
return `"${v}"`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAPIRequestCodeGen(language: Language): APIRequestCodegen {
|
export function getAPIRequestCodeGen(language: Language): APIRequestCodegen {
|
||||||
|
|
|
||||||
|
|
@ -201,6 +201,27 @@ await page.request.get('http://example.com/foo', {
|
||||||
});`.trim());
|
});`.trim());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('escape sequences', () => {
|
||||||
|
expect(impl.generatePlaywrightRequestCall({
|
||||||
|
url: 'http://example.com/foo',
|
||||||
|
method: 'GET',
|
||||||
|
headers: [
|
||||||
|
{ name: 'F\\o', value: 'B\\r' },
|
||||||
|
],
|
||||||
|
httpVersion: '1.1',
|
||||||
|
cookies: [],
|
||||||
|
queryString: [],
|
||||||
|
headersSize: 0,
|
||||||
|
bodySize: 0,
|
||||||
|
comment: '',
|
||||||
|
}, undefined)).toEqual(`
|
||||||
|
await page.request.get('http://example.com/foo', {
|
||||||
|
headers: {
|
||||||
|
'F\\\\o': 'B\\\\r'
|
||||||
|
}
|
||||||
|
});`.trim());
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test.describe('python', () => {
|
test.describe('python', () => {
|
||||||
|
|
@ -394,6 +415,28 @@ await page.request.get(
|
||||||
)`.trim());
|
)`.trim());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('escape sequences', () => {
|
||||||
|
expect(impl.generatePlaywrightRequestCall({
|
||||||
|
url: 'http://example.com/foo',
|
||||||
|
method: 'GET',
|
||||||
|
headers: [
|
||||||
|
{ name: 'F\\o', value: 'B\\r' },
|
||||||
|
],
|
||||||
|
httpVersion: '1.1',
|
||||||
|
cookies: [],
|
||||||
|
queryString: [],
|
||||||
|
headersSize: 0,
|
||||||
|
bodySize: 0,
|
||||||
|
comment: '',
|
||||||
|
}, undefined)).toEqual(`
|
||||||
|
await page.request.get(
|
||||||
|
"http://example.com/foo",
|
||||||
|
headers={
|
||||||
|
"F\\\\o": "B\\\\r"
|
||||||
|
}
|
||||||
|
)`.trim());
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test.describe('csharp', () => {
|
test.describe('csharp', () => {
|
||||||
|
|
@ -477,6 +520,27 @@ await request.PutAsync("http://example.com/foo", new() {
|
||||||
Headers = new() {
|
Headers = new() {
|
||||||
["Content-Type"] = "application/json"
|
["Content-Type"] = "application/json"
|
||||||
}
|
}
|
||||||
|
});`.trim());
|
||||||
|
});
|
||||||
|
|
||||||
|
test('escape sequences', () => {
|
||||||
|
expect(impl.generatePlaywrightRequestCall({
|
||||||
|
url: 'http://example.com/foo',
|
||||||
|
method: 'GET',
|
||||||
|
headers: [
|
||||||
|
{ name: 'F\\o', value: 'B\\r' },
|
||||||
|
],
|
||||||
|
httpVersion: '1.1',
|
||||||
|
cookies: [],
|
||||||
|
queryString: [],
|
||||||
|
headersSize: 0,
|
||||||
|
bodySize: 0,
|
||||||
|
comment: '',
|
||||||
|
}, undefined)).toEqual(`
|
||||||
|
await request.GetAsync("http://example.com/foo", new() {
|
||||||
|
Headers = new() {
|
||||||
|
["F\\\\o"] = "B\\\\r"
|
||||||
|
}
|
||||||
});`.trim());
|
});`.trim());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -587,6 +651,25 @@ request.patch("http://example.com/foo", RequestOptions.create()
|
||||||
}, undefined)).toEqual(`
|
}, undefined)).toEqual(`
|
||||||
request.delete("http://example.com/foo", RequestOptions.create()
|
request.delete("http://example.com/foo", RequestOptions.create()
|
||||||
.setHeader("Authorization", "Bearer token")
|
.setHeader("Authorization", "Bearer token")
|
||||||
|
);`.trim());
|
||||||
|
});
|
||||||
|
|
||||||
|
test('escape sequences', () => {
|
||||||
|
expect(impl.generatePlaywrightRequestCall({
|
||||||
|
url: 'http://example.com/foo',
|
||||||
|
method: 'GET',
|
||||||
|
headers: [
|
||||||
|
{ name: 'F\\o', value: 'B\\r' },
|
||||||
|
],
|
||||||
|
httpVersion: '1.1',
|
||||||
|
cookies: [],
|
||||||
|
queryString: [],
|
||||||
|
headersSize: 0,
|
||||||
|
bodySize: 0,
|
||||||
|
comment: '',
|
||||||
|
}, undefined)).toEqual(`
|
||||||
|
request.get(\"http://example.com/foo\", RequestOptions.create()
|
||||||
|
.setHeader(\"F\\\\o\", \"B\\\\r\")
|
||||||
);`.trim());
|
);`.trim());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue