@@ -13,6 +13,7 @@ import type {
1313 Expression ,
1414} from "estree"
1515import type { AST } from "eslint"
16+ import { PatternMatcher } from "eslint-utils"
1617import type {
1718 JSONNode ,
1819 JSONProgram ,
@@ -48,6 +49,10 @@ import type { TokenStore, MaybeNodeOrToken } from "./token-store"
4849import { isComma } from "./token-store"
4950
5051const lineBreakPattern = / \r \n | [ \r \n \u2028 \u2029 ] / u
52+ const codePointEscapeMatcher = new PatternMatcher ( / \\ u \{ [ \d a - f A - F ] + \} / gu)
53+ const octalNumericLiteralPattern = / ^ 0 [ o O ] / u
54+ const legacyOctalNumericLiteralPattern = / ^ 0 [ 0 - 7 ] / u
55+ const binaryNumericLiteralPattern = / ^ 0 [ b B ] / u
5156
5257export type JSONSyntaxContext = {
5358 trailingCommas : boolean
@@ -59,6 +64,9 @@ export type JSONSyntaxContext = {
5964 infinities : boolean
6065 nans : boolean
6166 numericSeparators : boolean
67+ binaryNumericLiterals : boolean
68+ octalNumericLiterals : boolean
69+ legacyOctalNumericLiterals : boolean
6270 invalidJsonNumbers : boolean
6371 //
6472 multilineStrings : boolean
@@ -70,6 +78,8 @@ export type JSONSyntaxContext = {
7078 regExpLiterals : boolean
7179 templateLiterals : boolean
7280 bigintLiterals : boolean
81+ unicodeCodepointEscapes : boolean
82+ escapeSequenceInIdentifier : boolean
7383}
7484
7585export function convertNode (
@@ -141,7 +151,7 @@ export function convertNode(
141151 return convertUnaryExpressionNode ( node , tokens , ctx )
142152 }
143153 if ( node . type === "Identifier" ) {
144- return convertIdentifierNode ( node , tokens )
154+ return convertIdentifierNode ( node , tokens , ctx )
145155 }
146156 if ( node . type === "TemplateLiteral" ) {
147157 return convertTemplateLiteralNode ( node , tokens , ctx )
@@ -461,6 +471,24 @@ function validateLiteral(node: Literal, ctx: JSONSyntaxContext) {
461471 } )
462472 }
463473 }
474+ if ( ! ctx . octalNumericLiterals ) {
475+ if ( octalNumericLiteralPattern . test ( text ) ) {
476+ return throwUnexpectedError ( "octal numeric literal" , node )
477+ }
478+ }
479+ if ( ! ctx . legacyOctalNumericLiterals ) {
480+ if ( legacyOctalNumericLiteralPattern . test ( text ) ) {
481+ return throwUnexpectedError (
482+ "legacy octal numeric literal" ,
483+ node ,
484+ )
485+ }
486+ }
487+ if ( ! ctx . binaryNumericLiterals ) {
488+ if ( binaryNumericLiteralPattern . test ( text ) ) {
489+ return throwUnexpectedError ( "binary numeric literal" , node )
490+ }
491+ }
464492 if ( ! ctx . invalidJsonNumbers ) {
465493 try {
466494 JSON . parse ( text )
@@ -470,7 +498,9 @@ function validateLiteral(node: Literal, ctx: JSONSyntaxContext) {
470498 }
471499 }
472500 if (
473- ( ! ctx . multilineStrings || ! ctx . singleQuotes ) &&
501+ ( ! ctx . multilineStrings ||
502+ ! ctx . singleQuotes ||
503+ ! ctx . unicodeCodepointEscapes ) &&
474504 typeof value === "string"
475505 ) {
476506 if ( ! ctx . singleQuotes ) {
@@ -483,6 +513,11 @@ function validateLiteral(node: Literal, ctx: JSONSyntaxContext) {
483513 return throwUnexpectedError ( "multiline string" , node )
484514 }
485515 }
516+ if ( ! ctx . unicodeCodepointEscapes ) {
517+ if ( codePointEscapeMatcher . test ( node . raw ! ) ) {
518+ return throwUnexpectedError ( "unicode codepoint escape" , node )
519+ }
520+ }
486521 }
487522
488523 return undefined
@@ -547,11 +582,18 @@ function convertUnaryExpressionNode(
547582function convertIdentifierNode (
548583 node : Identifier ,
549584 tokens : TokenStore ,
585+ ctx : JSONSyntaxContext ,
550586) : JSONIdentifier {
551587 /* istanbul ignore next */
552588 if ( node . type !== "Identifier" ) {
553589 return throwUnexpectedNodeError ( node , tokens )
554590 }
591+
592+ if ( ! ctx . escapeSequenceInIdentifier ) {
593+ if ( node . name . length < node . range ! [ 1 ] - node . range ! [ 0 ] ) {
594+ return throwUnexpectedError ( "escape sequence" , node )
595+ }
596+ }
555597 const nn : JSONIdentifier = {
556598 type : "JSONIdentifier" ,
557599 name : node . name ,
@@ -591,6 +633,11 @@ function convertTemplateLiteralNode(
591633 return throwUnexpectedTokenError ( "$" , loc )
592634 }
593635
636+ if ( ! ctx . unicodeCodepointEscapes ) {
637+ if ( codePointEscapeMatcher . test ( node . quasis [ 0 ] . value . raw ) ) {
638+ return throwUnexpectedError ( "unicode codepoint escape" , node )
639+ }
640+ }
594641 const quasis : [ JSONTemplateElement ] = [
595642 convertTemplateElementNode ( node . quasis [ 0 ] , tokens ) ,
596643 ]
0 commit comments