// tslint:disable-next-line:missing-jsdoc import * as Lint from "tslint"; import * as ts from "typescript"; // The walker takes care of all the work. class UnicodeEscapeBracesWalker extends Lint.RuleWalker { protected visitStringLiteral(node: ts.StringLiteral): void { this.visitLiteralExpression(node); super.visitStringLiteral(node); } protected visitNode(node: ts.Node): void { if (node.kind === ts.SyntaxKind.NoSubstitutionTemplateLiteral) { this.visitLiteralExpression(node as ts.NoSubstitutionTemplateLiteral); } else if (node.kind === ts.SyntaxKind.TemplateHead) { this.visitLiteralExpression(node as ts.TemplateHead); } super.visitNode(node); } private visitLiteralExpression( node: ts.LiteralExpression | ts.LiteralLikeNode): void { const { text } = node; const start = node.getStart(); // tslint:disable-next-line:no-constant-condition while (true) { const match = /\\u[^{]/g.exec(text); if (match === null) { break; } this.addFailureAt(start + match.index, 2, Rule.FAILURE_STRING); } } } export class Rule extends Lint.Rules.AbstractRule { public static metadata: Lint.IRuleMetadata = { ruleName: "unicode-escape-braces", type: "maintainability", description: "Always use braces in unicode escapes.", rationale: "\ ECMAScript 2015 (6th edition) introduces a syntax whereby Unicode escapes can \ be encoded with braces. For Unicode escapes that require more than 4 \ hexadecimal digits, the braces are mandatory for proper interpretation. \ \ For instance '\\u10FFFF' would be interpreted as the character U+10FF followed \ by two 'F' characters. In order to be interpeted as U+10FFFF it must be \ encoded as '\\u{10FFFF}'. It is easy to forget to put the braces and end up \ with an incorrect string. As far as JavaScript and TypeScript are concerned \ there's no problem with '\\u10FFFF'. \ \ It is also easy to make mistakes with shorter escapes. For instace, \ '\\u123Bar' does not encode the word 'Bar' preceded by the character U+123. \ It encodes the character U+123B followed by 'ar'. \ \ This rule requires that all unicode escapes use braces.", options: null, optionsDescription: "", typescriptOnly: true, }; public static FAILURE_STRING: string = "unicode escapes must use braces"; public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { return this.applyWithWalker( new UnicodeEscapeBracesWalker(sourceFile, this.getOptions())); } }