Correctly output escapes in directives (#9501)

This commit is contained in:
Nicolò Ribaudo 2019-02-15 21:08:45 +01:00 committed by GitHub
parent 0f685d9b42
commit 83cbc11d46
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 2 deletions

View File

@ -50,8 +50,35 @@ export function Directive(node: Object) {
this.semicolon(); this.semicolon();
} }
// These regexes match an even number of \ followed by a quote
const unescapedSingleQuoteRE = /(?:^|[^\\])(?:\\\\)*'/;
const unescapedDoubleQuoteRE = /(?:^|[^\\])(?:\\\\)*"/;
export function DirectiveLiteral(node: Object) {
const raw = this.getPossibleRaw(node);
if (raw != null) {
this.token(raw);
return;
}
const { value } = node;
// NOTE: In directives we can't change escapings,
// because they change the behavior.
// e.g. "us\x65 string" (\x65 is e) is not a "use strict" directive.
if (!unescapedDoubleQuoteRE.test(value)) {
this.token(`"${value}"`);
} else if (!unescapedSingleQuoteRE.test(value)) {
this.token(`'${value}'`);
} else {
throw new Error(
"Malformed AST: it is not possible to print a directive containing" +
" both unescaped single and double quotes.",
);
}
}
export function InterpreterDirective(node: Object) { export function InterpreterDirective(node: Object) {
this.token(`#!${node.value}\n`); this.token(`#!${node.value}\n`);
} }
export { StringLiteral as DirectiveLiteral } from "./types";

View File

@ -1 +1,2 @@
0; // Not a directive
"©"; "©";

View File

@ -1 +1,2 @@
0;// Not a directive
"\u00A9"; "\u00A9";

View File

@ -384,6 +384,48 @@ describe("programmatic generation", function() {
[key: any]: number [key: any]: number
}`); }`);
}); });
describe("directives", function() {
it("preserves escapes", function() {
const directive = t.directive(
t.directiveLiteral(String.raw`us\x65 strict`),
);
const output = generate(directive).code;
expect(output).toBe(String.raw`"us\x65 strict";`);
});
it("preserves escapes in minified output", function() {
// https://github.com/babel/babel/issues/4767
const directive = t.directive(t.directiveLiteral(String.raw`foo\n\t\r`));
const output = generate(directive, { minified: true }).code;
expect(output).toBe(String.raw`"foo\n\t\r";`);
});
it("unescaped single quote", function() {
const directive = t.directive(t.directiveLiteral(String.raw`'\'\"`));
const output = generate(directive).code;
expect(output).toBe(String.raw`"'\'\"";`);
});
it("unescaped double quote", function() {
const directive = t.directive(t.directiveLiteral(String.raw`"\'\"`));
const output = generate(directive).code;
expect(output).toBe(String.raw`'"\'\"';`);
});
it("unescaped single and double quotes together throw", function() {
const directive = t.directive(t.directiveLiteral(String.raw`'"`));
expect(() => {
generate(directive);
}).toThrow();
});
});
}); });
describe("CodeGenerator", function() { describe("CodeGenerator", function() {