WIP: try to add snippet escaping in emitter

This commit is contained in:
Gabriela Araujo Britto
2021-10-06 18:25:13 -07:00
parent d7809c1122
commit 41a3c196dc
2 changed files with 61 additions and 13 deletions

View File

@@ -911,6 +911,9 @@ namespace ts {
const parenthesizer = factory.parenthesizer;
const emitBinaryExpression = createEmitBinaryExpression();
// Snippets
let inSnippet = false;
reset();
return {
// public API
@@ -1283,8 +1286,9 @@ namespace ts {
currentParenthesizerRule = undefined;
}
function pipelineEmitWithHintWorker(hint: EmitHint, node: Node, allowSnippets = true): void {
if (allowSnippets) {
// >> TODO: remove allowSnippets
function pipelineEmitWithHintWorker(hint: EmitHint, node: Node, _allowSnippets = true): void {
if (!inSnippet) {
const snippet = getSnippetElement(node);
if (snippet) {
return emitSnippetNode(hint, node, snippet);
@@ -1877,14 +1881,19 @@ namespace ts {
const text = getLiteralTextOfNode(node, printerOptions.neverAsciiEscape, jsxAttributeEscape);
if ((printerOptions.sourceMap || printerOptions.inlineSourceMap)
&& (node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind))) {
writeLiteral(text);
writeLiteral(inSnippet ? escapeSnippetText(text) : text);
}
else {
// Quick info expects all literals to be called with writeStringLiteral, as there's no specific type for numberLiterals
writeStringLiteral(text);
writeStringLiteral(inSnippet ? escapeSnippetText(text) : text);
}
}
// TODO: move this
function escapeSnippetText(text: string): string {
return text.replace(/\$/gm, "\\$");
}
// SyntaxKind.UnparsedSource
// SyntaxKind.UnparsedPrepend
function emitUnparsedSourceOrPrepend(unparsed: UnparsedSource | UnparsedPrepend) {
@@ -1935,12 +1944,16 @@ namespace ts {
//
function emitSnippetNode(hint: EmitHint, node: Node, snippet: SnippetElement) {
inSnippet = true;
switch (snippet.kind) {
case SnippetKind.Placeholder:
return emitPlaceholder(hint, node, snippet);
emitPlaceholder(hint, node, snippet);
break;
case SnippetKind.TabStop:
return emitTabStop(snippet);
emitTabStop(snippet);
break;
}
inSnippet = false;
}
function emitPlaceholder(hint: EmitHint, node: Node, snippet: Placeholder) {
@@ -1960,7 +1973,8 @@ namespace ts {
function emitIdentifier(node: Identifier) {
const writeText = node.symbol ? writeSymbol : write;
writeText(getTextOfNode(node, /*includeTrivia*/ false), node.symbol);
const text = getTextOfNode(node, /*includeTrivia*/ false);
writeText(inSnippet ? escapeSnippetText(text) : text, node.symbol);
emitList(node, node.typeArguments, ListFormat.TypeParameters); // Call emitList directly since it could be an array of TypeParameterDeclarations _or_ type arguments
}
@@ -1970,7 +1984,8 @@ namespace ts {
function emitPrivateIdentifier(node: PrivateIdentifier) {
const writeText = node.symbol ? writeSymbol : write;
writeText(getTextOfNode(node, /*includeTrivia*/ false), node.symbol);
const text = getTextOfNode(node, /*includeTrivia*/ false);
writeText(inSnippet ? escapeSnippetText(text) : text, node.symbol);
}

View File

@@ -1,13 +1,36 @@
/* eslint-disable no-fallthrough */
/* @internal */
namespace ts.snippets {
// interface SnippetWriter extends EmitTextWriter, PrintHandlers {}
// function createSnippetWriter(newLine: string): SnippetWriter {
// const substituteNode = (hint: EmitHint, node: Node) => {
// switch (hint) {
// case EmitHint.IdentifierName:
// // >> TODO: do escaping here
// return node;
// const substituteNode = (_hint: EmitHint, node: Node) => {
// switch (node.kind) {
// // Comments:
// // TODO: doesn't work because comments are `TextRanges` with a syntax kind, but are not nodes.
// // case SyntaxKind.SingleLineCommentTrivia:
// // case SyntaxKind.MultiLineCommentTrivia:
// // return escapeTrivia(node);
// // >> comments are emitted in previous phase
// // String-like literals:
// case SyntaxKind.StringLiteral: // >> emitLiteral
// return escapeLiteralLikeNode(node as StringLiteral);
// case SyntaxKind.RegularExpressionLiteral: // >> emitLiteral
// return escapeLiteralLikeNode(node as RegularExpressionLiteral);
// case SyntaxKind.NoSubstitutionTemplateLiteral: // >> emitLiteral
// // Has .rawText but also .text
// // Templates:
// // >> .rawText
// case SyntaxKind.TemplateHead: // >> emitLiteral
// case SyntaxKind.TemplateMiddle: // >> emitLiteral
// case SyntaxKind.TemplateTail: // >> emitLiteral
// // Identifiers:
// case SyntaxKind.Identifier: // >> emitIdentifier
// case SyntaxKind.PrivateIdentifier: // >> emitPrivateIdentifier
// // Other:
// // >> TODO: JSX? JSDoc?
// return undefined;
// }
// return node;
// };
@@ -20,4 +43,14 @@ namespace ts.snippets {
// substituteNode,
// };
// }
// function escapeLiteralLikeNode<T extends LiteralLikeNode>(node: T): T {
// const copy = getSynthesizedDeepClone(node);
// copy.text = escapeSnippetText(node.text);
// return copy;
// }
// function escapeSnippetText(text: string): string {
// return text.replace(/\$/gm, "\\$");
// }
}