proper string escaping

This commit is contained in:
Simon Knott 2024-11-04 17:13:40 +01:00
parent 47756f7b23
commit a798374d12
No known key found for this signature in database
GPG key ID: 8CEDC00028084AEC
2 changed files with 114 additions and 13 deletions

View file

@ -55,7 +55,7 @@ class JSCodeGen implements APIRequestCodegen {
// Handle primitive types
if (typeof obj !== 'object') {
if (typeof obj === 'string')
return `'${obj}'`;
return this.stringLiteral(obj);
return String(obj);
}
@ -84,12 +84,17 @@ class JSCodeGen implements APIRequestCodegen {
// Handle keys that need quotes
const formattedKey = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key) ?
key :
`'${key}'`;
this.stringLiteral(key);
return `${nextSpaces}${formattedKey}: ${formattedValue}`;
}).join(',\n');
return `{\n${entries}\n${spaces}}`;
}
private stringLiteral(v: string): string {
v = v.replace(/\\/g, '\\\\').replace(/'/g, '\\\'');
return `'${v}'`;
}
}
class PythonCodeGen implements APIRequestCodegen {
@ -130,7 +135,7 @@ class PythonCodeGen implements APIRequestCodegen {
// Handle primitive types
if (typeof obj !== 'object') {
if (typeof obj === 'string')
return `"${obj.replaceAll('"', '\\"')}"`;
return this.stringLiteral(obj);
if (typeof obj === 'boolean')
return obj ? 'True' : 'False';
return String(obj);
@ -158,11 +163,16 @@ class PythonCodeGen implements APIRequestCodegen {
const entries = Object.entries(obj).map(([key, value]) => {
const formattedValue = this.prettyPrintObject(value, indent, level + 1);
return `${nextSpaces}"${key}": ${formattedValue}`;
return `${nextSpaces}${this.stringLiteral(key)}: ${formattedValue}`;
}).join(',\n');
return `{\n${entries}\n${spaces}}`;
}
private stringLiteral(v: string): string {
v = v.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
return `"${v}"`;
}
}
class CSharpCodeGen implements APIRequestCodegen {
@ -198,10 +208,6 @@ class CSharpCodeGen implements APIRequestCodegen {
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 {
// Handle null and undefined
if (obj === null)
@ -212,7 +218,7 @@ class CSharpCodeGen implements APIRequestCodegen {
// Handle primitive types
if (typeof obj !== 'object') {
if (typeof obj === 'string')
return `"${obj.replace(/"/g, '\\"')}"`;
return this.stringLiteral(obj);
if (typeof obj === 'boolean')
return obj ? 'true' : 'false';
return String(obj);
@ -240,12 +246,18 @@ class CSharpCodeGen implements APIRequestCodegen {
const entries = Object.entries(obj).map(([key, value]) => {
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}`;
}).join(',\n');
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 {
@ -262,16 +274,22 @@ class JavaCodeGen implements APIRequestCodegen {
}
for (const [key, value] of url.searchParams)
options.push(`setQueryParam("${key}", "${value}")`);
options.push(`setQueryParam(${this.stringLiteral(key)}, ${this.stringLiteral(value)})`);
if (body)
options.push(`setData("${body.replaceAll('"', '\\"')}")`);
options.push(`setData(${this.stringLiteral(body)})`);
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)
params.push(`RequestOptions.create()\n .${options.join('\n .')}\n`);
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 {

View file

@ -201,6 +201,27 @@ await page.request.get('http://example.com/foo', {
});`.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', () => {
@ -394,6 +415,28 @@ await page.request.get(
)`.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', () => {
@ -477,6 +520,27 @@ await request.PutAsync("http://example.com/foo", new() {
Headers = new() {
["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());
});
});
@ -587,6 +651,25 @@ request.patch("http://example.com/foo", RequestOptions.create()
}, undefined)).toEqual(`
request.delete("http://example.com/foo", RequestOptions.create()
.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());
});
});