vscode/extensions/extension-editing/src/jsonReconstruct.ts
mxwj 018ff30de3
Some checks failed
Monaco Editor checks / Monaco Editor checks (push) Has been cancelled
Initial commit
2024-11-15 14:29:18 +08:00

184 lines
3.8 KiB
TypeScript

/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/**
* This class has a very specific purpose:
*
* It can return convert offset within a decoded JSON string to offset within the encoded JSON string.
*/
export class JsonStringScanner {
private resultChars = 0;
private pos = 0;
/**
*
* @param text the encoded JSON string
* @param pos must not include ", ie must be `stringJSONNode.offset + 1`
*/
constructor(private readonly text: string, initialPos: number /* offset within `text` */) {
this.pos = initialPos;
}
// note that we don't do bound checks here, because we know that the offset is within the string
getOffsetInEncoded(offsetDecoded: number) {
let start = this.pos;
while (true) {
if (this.resultChars > offsetDecoded) {
return start;
}
const ch = this.text.charCodeAt(this.pos);
if (ch === CharacterCodes.backslash) {
start = this.pos;
this.pos++;
const ch2 = this.text.charCodeAt(this.pos++);
switch (ch2) {
case CharacterCodes.doubleQuote:
case CharacterCodes.backslash:
case CharacterCodes.slash:
case CharacterCodes.b:
case CharacterCodes.f:
case CharacterCodes.n:
case CharacterCodes.r:
case CharacterCodes.t:
this.resultChars += 1;
break;
case CharacterCodes.u: {
const ch3 = this.scanHexDigits(4, true);
if (ch3 >= 0) {
this.resultChars += String.fromCharCode(ch3).length;
}
break;
}
}
continue;
}
start = this.pos;
this.pos++;
this.resultChars++;
}
}
scanHexDigits(count: number, exact?: boolean): number {
let digits = 0;
let value = 0;
while (digits < count || !exact) {
const ch = this.text.charCodeAt(this.pos);
if (ch >= CharacterCodes._0 && ch <= CharacterCodes._9) {
value = value * 16 + ch - CharacterCodes._0;
}
else if (ch >= CharacterCodes.A && ch <= CharacterCodes.F) {
value = value * 16 + ch - CharacterCodes.A + 10;
}
else if (ch >= CharacterCodes.a && ch <= CharacterCodes.f) {
value = value * 16 + ch - CharacterCodes.a + 10;
}
else {
break;
}
this.pos++;
digits++;
}
if (digits < count) {
value = -1;
}
return value;
}
}
const enum CharacterCodes {
lineFeed = 0x0A, // \n
carriageReturn = 0x0D, // \r
space = 0x0020, // " "
_0 = 0x30,
_1 = 0x31,
_2 = 0x32,
_3 = 0x33,
_4 = 0x34,
_5 = 0x35,
_6 = 0x36,
_7 = 0x37,
_8 = 0x38,
_9 = 0x39,
a = 0x61,
b = 0x62,
c = 0x63,
d = 0x64,
e = 0x65,
f = 0x66,
g = 0x67,
h = 0x68,
i = 0x69,
j = 0x6A,
k = 0x6B,
l = 0x6C,
m = 0x6D,
n = 0x6E,
o = 0x6F,
p = 0x70,
q = 0x71,
r = 0x72,
s = 0x73,
t = 0x74,
u = 0x75,
v = 0x76,
w = 0x77,
x = 0x78,
y = 0x79,
z = 0x7A,
A = 0x41,
B = 0x42,
C = 0x43,
D = 0x44,
E = 0x45,
F = 0x46,
G = 0x47,
H = 0x48,
I = 0x49,
J = 0x4A,
K = 0x4B,
L = 0x4C,
M = 0x4D,
N = 0x4E,
O = 0x4F,
P = 0x50,
Q = 0x51,
R = 0x52,
S = 0x53,
T = 0x54,
U = 0x55,
V = 0x56,
W = 0x57,
X = 0x58,
Y = 0x59,
Z = 0x5a,
asterisk = 0x2A, // *
backslash = 0x5C, // \
closeBrace = 0x7D, // }
closeBracket = 0x5D, // ]
colon = 0x3A, // :
comma = 0x2C, // ,
dot = 0x2E, // .
doubleQuote = 0x22, // "
minus = 0x2D, // -
openBrace = 0x7B, // {
openBracket = 0x5B, // [
plus = 0x2B, // +
slash = 0x2F, // /
formFeed = 0x0C, // \f
tab = 0x09, // \t
}