Skip to content

Commit 4956cb6

Browse files
authored
Merge pull request #38 from sveltejs/escape-newlines
fix: escape newlines and escape characters when quoting strings
2 parents c64eda1 + 10c6156 commit 4956cb6

File tree

3 files changed

+57
-1
lines changed

3 files changed

+57
-1
lines changed

.changeset/shiny-pianos-clean.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'esrap': patch
3+
---
4+
5+
fix: escape newlines when quoting strings

src/handlers.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,26 @@ function prepend_comments(comments, state, newlines) {
115115
* @param {'\'' | '"'} char
116116
*/
117117
function quote(string, char) {
118-
return char + string.replaceAll(char, '\\' + char) + char;
118+
let out = char;
119+
let escaped = false;
120+
121+
for (const c of string) {
122+
if (escaped) {
123+
out += c;
124+
escaped = false;
125+
} else if (c === '\\') {
126+
out += '\\\\';
127+
escaped = true;
128+
} else if (c === char) {
129+
out += '\\' + c;
130+
} else if (c === '\n') {
131+
out += '\\n';
132+
} else {
133+
out += c;
134+
}
135+
}
136+
137+
return out + char;
119138
}
120139

121140
const OPERATOR_PRECEDENCE = {

test/quotes.test.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,35 @@ test('escape double quotes if present in string literal', () => {
6161

6262
expect(code).toMatchInlineSnapshot(`"const foo = "b\\"ar";"`);
6363
});
64+
65+
test('escapes new lines', () => {
66+
const ast = load('const str = "a\\nb"');
67+
clean(ast);
68+
const code = print(ast).code;
69+
70+
expect(code).toMatchInlineSnapshot(`"const str = 'a\\nb';"`);
71+
});
72+
73+
test('escapes escape characters', () => {
74+
const ast = load('const str = "a\\\\nb"');
75+
clean(ast);
76+
const code = print(ast).code;
77+
78+
expect(code).toMatchInlineSnapshot(`"const str = 'a\\\\nb';"`);
79+
});
80+
81+
test('does not escape already-escaped single quotes', () => {
82+
const ast = load(`const str = 'a\\'b'`);
83+
clean(ast);
84+
const code = print(ast).code;
85+
86+
expect(code).toMatchInlineSnapshot(`"const str = 'a\\'b';"`);
87+
});
88+
89+
test('does not escape already-escaped double quotes', () => {
90+
const ast = load('const str = "a\\"b"');
91+
clean(ast);
92+
const code = print(ast).code;
93+
94+
expect(code).toMatchInlineSnapshot(`"const str = 'a"b';"`);
95+
});

0 commit comments

Comments
 (0)