@@ -13,6 +13,7 @@ import type {
13
13
Expression ,
14
14
} from "estree"
15
15
import type { AST } from "eslint"
16
+ import { PatternMatcher } from "eslint-utils"
16
17
import type {
17
18
JSONNode ,
18
19
JSONProgram ,
@@ -48,6 +49,10 @@ import type { TokenStore, MaybeNodeOrToken } from "./token-store"
48
49
import { isComma } from "./token-store"
49
50
50
51
const 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
51
56
52
57
export type JSONSyntaxContext = {
53
58
trailingCommas : boolean
@@ -59,6 +64,9 @@ export type JSONSyntaxContext = {
59
64
infinities : boolean
60
65
nans : boolean
61
66
numericSeparators : boolean
67
+ binaryNumericLiterals : boolean
68
+ octalNumericLiterals : boolean
69
+ legacyOctalNumericLiterals : boolean
62
70
invalidJsonNumbers : boolean
63
71
//
64
72
multilineStrings : boolean
@@ -70,6 +78,8 @@ export type JSONSyntaxContext = {
70
78
regExpLiterals : boolean
71
79
templateLiterals : boolean
72
80
bigintLiterals : boolean
81
+ unicodeCodepointEscapes : boolean
82
+ escapeSequenceInIdentifier : boolean
73
83
}
74
84
75
85
export function convertNode (
@@ -141,7 +151,7 @@ export function convertNode(
141
151
return convertUnaryExpressionNode ( node , tokens , ctx )
142
152
}
143
153
if ( node . type === "Identifier" ) {
144
- return convertIdentifierNode ( node , tokens )
154
+ return convertIdentifierNode ( node , tokens , ctx )
145
155
}
146
156
if ( node . type === "TemplateLiteral" ) {
147
157
return convertTemplateLiteralNode ( node , tokens , ctx )
@@ -461,6 +471,24 @@ function validateLiteral(node: Literal, ctx: JSONSyntaxContext) {
461
471
} )
462
472
}
463
473
}
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
+ }
464
492
if ( ! ctx . invalidJsonNumbers ) {
465
493
try {
466
494
JSON . parse ( text )
@@ -470,7 +498,9 @@ function validateLiteral(node: Literal, ctx: JSONSyntaxContext) {
470
498
}
471
499
}
472
500
if (
473
- ( ! ctx . multilineStrings || ! ctx . singleQuotes ) &&
501
+ ( ! ctx . multilineStrings ||
502
+ ! ctx . singleQuotes ||
503
+ ! ctx . unicodeCodepointEscapes ) &&
474
504
typeof value === "string"
475
505
) {
476
506
if ( ! ctx . singleQuotes ) {
@@ -483,6 +513,11 @@ function validateLiteral(node: Literal, ctx: JSONSyntaxContext) {
483
513
return throwUnexpectedError ( "multiline string" , node )
484
514
}
485
515
}
516
+ if ( ! ctx . unicodeCodepointEscapes ) {
517
+ if ( codePointEscapeMatcher . test ( node . raw ! ) ) {
518
+ return throwUnexpectedError ( "unicode codepoint escape" , node )
519
+ }
520
+ }
486
521
}
487
522
488
523
return undefined
@@ -547,11 +582,18 @@ function convertUnaryExpressionNode(
547
582
function convertIdentifierNode (
548
583
node : Identifier ,
549
584
tokens : TokenStore ,
585
+ ctx : JSONSyntaxContext ,
550
586
) : JSONIdentifier {
551
587
/* istanbul ignore next */
552
588
if ( node . type !== "Identifier" ) {
553
589
return throwUnexpectedNodeError ( node , tokens )
554
590
}
591
+
592
+ if ( ! ctx . escapeSequenceInIdentifier ) {
593
+ if ( node . name . length < node . range ! [ 1 ] - node . range ! [ 0 ] ) {
594
+ return throwUnexpectedError ( "escape sequence" , node )
595
+ }
596
+ }
555
597
const nn : JSONIdentifier = {
556
598
type : "JSONIdentifier" ,
557
599
name : node . name ,
@@ -591,6 +633,11 @@ function convertTemplateLiteralNode(
591
633
return throwUnexpectedTokenError ( "$" , loc )
592
634
}
593
635
636
+ if ( ! ctx . unicodeCodepointEscapes ) {
637
+ if ( codePointEscapeMatcher . test ( node . quasis [ 0 ] . value . raw ) ) {
638
+ return throwUnexpectedError ( "unicode codepoint escape" , node )
639
+ }
640
+ }
594
641
const quasis : [ JSONTemplateElement ] = [
595
642
convertTemplateElementNode ( node . quasis [ 0 ] , tokens ) ,
596
643
]
0 commit comments