1
>
/*---------------------------------------------------------------------------------------------
json.ts
2
>
* Copyright (c) Microsoft Corporation. All rights reserved.
3
>
* Licensed under the MIT License. See License.txt in the project root for license information.
4
>
*--------------------------------------------------------------------------------------------*/
5
>
6
>
export const enum ScanError {
7
>
None = 0,
8
>
UnexpectedEndOfComment = 1,
9
>
UnexpectedEndOfString = 2,
10
>
UnexpectedEndOfNumber = 3,
11
>
InvalidUnicode = 4,
12
>
InvalidEscapeCharacter = 5,
13
>
InvalidCharacter = 6
14
>
}
15
>
16
>
export const enum SyntaxKind {
17
>
OpenBraceToken = 1,
18
>
CloseBraceToken = 2,
19
>
OpenBracketToken = 3,
20
>
CloseBracketToken = 4,
21
>
CommaToken = 5,
22
>
ColonToken = 6,
23
>
NullKeyword = 7,
24
>
TrueKeyword = 8,
25
>
FalseKeyword = 9,
26
>
StringLiteral = 10,
27
>
NumericLiteral = 11,
28
>
LineCommentTrivia = 12,
29
>
BlockCommentTrivia = 13,
30
>
LineBreakTrivia = 14,
31
>
Trivia = 15,
32
>
Unknown = 16,
33
>
EOF = 17
34
>
}
35
>
36
>
/**
37
>
* The scanner object, representing a JSON scanner at a position in the input string.
38
>
*/
39
>
export interface JSONScanner {
40
>
/**
41
>
* Sets the scan position to a new offset. A call to 'scan' is needed to get the first token.
42
>
*/
43
>
setPosition(pos: number): void;
44
>
/**
45
>
* Read the next token. Returns the token code.
46
>
*/
47
>
scan(): SyntaxKind;
48
>
/**
49
>
* Returns the current scan position, which is after the last read token.
50
>
*/
51
>
getPosition(): number;
52
>
/**
53
>
* Returns the last read token.
54
>
*/
55
>
getToken(): SyntaxKind;
56
>
/**
57
>
* Returns the last read token value. The value for strings is the decoded string content. For numbers its of type number, for boolean it's true or false.
58
>
*/
59
>
getTokenValue(): string;
60
>
/**
61
>
* The start offset of the last read token.
62
>
*/
63
>
getTokenOffset(): number;
64
>
/**
65
>
* The length of the last read token.
66
>
*/
67
>
getTokenLength(): number;
68
>
/**
69
>
* An error code of the last scan.
70
>
*/
71
>
getTokenError(): ScanError;
72
>
}
73
>
74
>
75
>
76
>
export interface ParseError {
77
>
error: ParseErrorCode;
78
>
offset: number;
79
>
length: number;
80
>
}
81
>
82
>
export const enum ParseErrorCode {
83
>
InvalidSymbol = 1,
84
>
InvalidNumberFormat = 2,
85
>
PropertyNameExpected = 3,
86
>
ValueExpected = 4,
87
>
ColonExpected = 5,
88
>
CommaExpected = 6,
89
>
CloseBraceExpected = 7,
90
>
CloseBracketExpected = 8,
91
>
EndOfFileExpected = 9,
92
>
InvalidCommentToken = 10,
93
>
UnexpectedEndOfComment = 11,
94
>
UnexpectedEndOfString = 12,
95
>
UnexpectedEndOfNumber = 13,
96
>
InvalidUnicode = 14,
97
>
InvalidEscapeCharacter = 15,
98
>
InvalidCharacter = 16
99
>
}
100
>
101
>
export type NodeType = 'object' | 'array' | 'property' | 'string' | 'number' | 'boolean' | 'null';
102
>
103
>
export interface Node {
104
>
readonly type: NodeType;
105
>
readonly value?: any;
106
>
readonly offset: number;
107
>
readonly length: number;
108
>
readonly colonOffset?: number;
109
>
readonly parent?: Node;
110
>
readonly children?: Node[];
111
>
}
112
>
113
>
export type Segment = string | number;
114
>
export type JSONPath = Segment[];
115
>
116
>
export interface Location {
117
>
/**
118
>
* The previous property key or literal value (string, number, boolean or null) or undefined.
119
>
*/
120
>
previousNode?: Node;
121
>
/**
122
>
* The path describing the location in the JSON document. The path consists of a sequence strings
123
>
* representing an object property or numbers for array indices.
124
>
*/
125
>
path: JSONPath;
126
>
/**
127
>
* Matches the locations path against a pattern consisting of strings (for properties) and numbers (for array indices).
128
>
* '*' will match a single segment, of any property name or index.
129
>
* '**' will match a sequence of segments or no segment, of any property name or index.
130
>
*/
131
>
matches: (patterns: JSONPath) => boolean;
132
>
/**
133
>
* If set, the location's offset is at a property key.
134
>
*/
135
>
isAtPropertyKey: boolean;
136
>
}
137
>
138
>
export interface ParseOptions {
139
>
disallowComments?: boolean;
140
>
allowTrailingComma?: boolean;
141
>
allowEmptyContent?: boolean;
142
>
}
143
>
144
>
export namespace ParseOptions {
145
>
export const DEFAULT = {
146
>
allowTrailingComma: true
147
>
};
148
>
}
149
>
150
>
export interface JSONVisitor {
151
>
/**
152
>
* Invoked when an open brace is encountered and an object is started. The offset and length represent the location of the open brace.
153
>
*/
154
>
onObjectBegin?: (offset: number, length: number) => void;
155
>
156
>
/**
157
>
* Invoked when a property is encountered. The offset and length represent the location of the property name.
158
>
*/
159
>
onObjectProperty?: (property: string, offset: number, length: number) => void;
160
>
161
>
/**
162
>
* Invoked when a closing brace is encountered and an object is completed. The offset and length represent the location of the closing brace.
163
>
*/
164
>
onObjectEnd?: (offset: number, length: number) => void;
165
>
166
>
/**
167
>
* Invoked when an open bracket is encountered. The offset and length represent the location of the open bracket.
168
>
*/
169
>
onArrayBegin?: (offset: number, length: number) => void;
170
>
171
>
/**
172
>
* Invoked when a closing bracket is encountered. The offset and length represent the location of the closing bracket.
173
>
*/
174
>
onArrayEnd?: (offset: number, length: number) => void;
175
>
176
>
/**
177
>
* Invoked when a literal value is encountered. The offset and length represent the location of the literal value.
178
>
*/
179
>
onLiteralValue?: (value: any, offset: number, length: number) => void;
180
>
181
>
/**
182
>
* Invoked when a comma or colon separator is encountered. The offset and length represent the location of the separator.
183
>
*/
184
>
onSeparator?: (character: string, offset: number, length: number) => void;
185
>
186
>
/**
187
>
* When comments are allowed, invoked when a line or block comment is encountered. The offset and length represent the location of the comment.
188
>
*/
189
>
onComment?: (offset: number, length: number) => void;
190
>
191
>
/**
192
>
* Invoked on an error.
193
>
*/
194
>
onError?: (error: ParseErrorCode, offset: number, length: number) => void;
195
>
}
196
>
197
>
/**
198
>
* Creates a JSON scanner on the given text.
199
>
* If ignoreTrivia is set, whitespaces or comments are ignored.
200
>
*/
201
>
export function createScanner(text: string, ignoreTrivia: boolean = false): JSONScanner {
203
>
let pos = 0;
204
>
const len = text.length;
205
>
let value: string = '';
206
>
let tokenOffset = 0;
207
>
let token: SyntaxKind = SyntaxKind.Unknown;
208
>
let scanError: ScanError = ScanError.None;
209
>
210
>
function scanHexDigits(count: number): number {
212
>
let hexValue = 0;
213
>
while (digits < count) {
214
>
const ch = text.charCodeAt(pos);
215
>
if (ch >= CharacterCodes._0 && ch <= CharacterCodes._9) {
216
>
hexValue = hexValue * 16 + ch - CharacterCodes._0;
217
>
}
218
>
else if (ch >= CharacterCodes.A && ch <= CharacterCodes.F) {
219
>
hexValue = hexValue * 16 + ch - CharacterCodes.A + 10;
220
>
}
221
else if (ch >= CharacterCodes.a && ch <= CharacterCodes.f) {
222
hexValue = hexValue * 16 + ch - CharacterCodes.a + 10;