Skip to content

Commit 037c432

Browse files
committed
Switch to jsonc-parser for tolerant json parsing
1 parent 4c6d5f2 commit 037c432

File tree

5 files changed

+86
-256
lines changed

5 files changed

+86
-256
lines changed

l10n/bundle.l10n.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"For more information about the 'console' field, see {0}": "For more information about the 'console' field, see {0}",
3131
"WARNING": "WARNING",
3232
"The C# extension was unable to automatically decode projects in the current workspace to create a runnable launch.json file. A template launch.json file has been created as a placeholder.\n\nIf the server is currently unable to load your project, you can attempt to resolve this by restoring any missing project dependencies (example: run 'dotnet restore') and by fixing any reported errors from building the projects in your workspace.\nIf this allows the server to now load your project then --\n * Delete this file\n * Open the Visual Studio Code command palette (View->Command Palette)\n * run the command: '.NET: Generate Assets for Build and Debug'.\n\nIf your project requires a more complex launch configuration, you may wish to delete this configuration and pick a different template using the 'Add Configuration...' button at the bottom of this file.": "The C# extension was unable to automatically decode projects in the current workspace to create a runnable launch.json file. A template launch.json file has been created as a placeholder.\n\nIf the server is currently unable to load your project, you can attempt to resolve this by restoring any missing project dependencies (example: run 'dotnet restore') and by fixing any reported errors from building the projects in your workspace.\nIf this allows the server to now load your project then --\n * Delete this file\n * Open the Visual Studio Code command palette (View->Command Palette)\n * run the command: '.NET: Generate Assets for Build and Debug'.\n\nIf your project requires a more complex launch configuration, you may wish to delete this configuration and pick a different template using the 'Add Configuration...' button at the bottom of this file.",
33-
"Failed to parse tasks.json file": "Failed to parse tasks.json file",
33+
"Failed to parse tasks.json file: {0}": "Failed to parse tasks.json file: {0}",
3434
"Don't Ask Again": "Don't Ask Again",
3535
"Required assets to build and debug are missing from '{0}'. Add them?": "Required assets to build and debug are missing from '{0}'. Add them?",
3636
"Cancel": "Cancel",

package-lock.json

+12-12
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/json.ts

+2-206
Original file line numberDiff line numberDiff line change
@@ -3,212 +3,8 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
const enum CharCode {
7-
asterisk = 0x2a, // *
8-
backSlash = 0x5c, // \
9-
closeBrace = 0x7d, // }
10-
closeBracket = 0x5d, // ]
11-
comma = 0x2c, // ,
12-
doubleQuote = 0x22, // "
13-
slash = 0x2f, // /
14-
15-
byteOrderMark = 0xfeff,
16-
17-
// line terminator characters (see https://en.wikipedia.org/wiki/Newline#Unicode)
18-
carriageReturn = 0x0d,
19-
formFeed = 0x0c,
20-
lineFeed = 0x0a,
21-
lineSeparator = 0x2028,
22-
nextLine = 0x85,
23-
paragraphSeparator = 0x2029,
24-
verticalTab = 0x0b,
25-
26-
// whitespace characters (see https://en.wikipedia.org/wiki/Whitespace_character#Unicode)
27-
tab = 0x09,
28-
space = 0x20,
29-
nonBreakingSpace = 0xa0,
30-
ogham = 0x1680,
31-
enQuad = 0x2000,
32-
emQuad = 0x2001,
33-
enSpace = 0x2002,
34-
emSpace = 0x2003,
35-
threePerEmSpace = 0x2004,
36-
fourPerEmSpace = 0x2005,
37-
sixPerEmSpace = 0x2006,
38-
figureSpace = 0x2007,
39-
punctuationSpace = 0x2008,
40-
thinSpace = 0x2009,
41-
hairSpace = 0x200a,
42-
zeroWidthSpace = 0x200b,
43-
narrowNoBreakSpace = 0x202f,
44-
mathematicalSpace = 0x205f,
45-
ideographicSpace = 0x3000,
46-
}
47-
48-
function isLineBreak(code: number) {
49-
return (
50-
code === CharCode.lineFeed ||
51-
code === CharCode.carriageReturn ||
52-
code === CharCode.verticalTab ||
53-
code === CharCode.formFeed ||
54-
code === CharCode.lineSeparator ||
55-
code === CharCode.paragraphSeparator
56-
);
57-
}
58-
59-
function isWhitespace(code: number) {
60-
return (
61-
code === CharCode.space ||
62-
code === CharCode.tab ||
63-
code === CharCode.lineFeed ||
64-
code === CharCode.verticalTab ||
65-
code === CharCode.formFeed ||
66-
code === CharCode.carriageReturn ||
67-
code === CharCode.nextLine ||
68-
code === CharCode.nonBreakingSpace ||
69-
code === CharCode.ogham ||
70-
(code >= CharCode.enQuad && code <= CharCode.zeroWidthSpace) ||
71-
code === CharCode.lineSeparator ||
72-
code === CharCode.paragraphSeparator ||
73-
code === CharCode.narrowNoBreakSpace ||
74-
code === CharCode.mathematicalSpace ||
75-
code === CharCode.ideographicSpace ||
76-
code === CharCode.byteOrderMark
77-
);
78-
}
79-
80-
function cleanJsonText(text: string) {
81-
const parts: string[] = [];
82-
let partStart = 0;
83-
84-
let index = 0;
85-
const length = text.length;
86-
87-
function next(): number {
88-
const result = peek();
89-
index++;
90-
return result;
91-
}
92-
93-
function peek(offset = 0): number {
94-
return text.charCodeAt(index + offset);
95-
}
96-
97-
function peekPastWhitespace(): number {
98-
let pos = index;
99-
let code = NaN;
100-
101-
do {
102-
code = text.charCodeAt(pos);
103-
pos++;
104-
} while (isWhitespace(code));
105-
106-
return code;
107-
}
108-
109-
function scanString() {
110-
while (index < length) {
111-
const code = next();
112-
113-
if (code === CharCode.doubleQuote) {
114-
// End of string. We're done
115-
break;
116-
}
117-
118-
if (code === CharCode.backSlash) {
119-
// Skip escaped character. We don't care about verifying the escape sequence.
120-
// We just don't want to accidentally scan an escaped double-quote as the end of the string.
121-
index++;
122-
}
123-
124-
if (isLineBreak(code)) {
125-
// string ended unexpectedly
126-
break;
127-
}
128-
}
129-
}
130-
131-
// eslint-disable-next-line no-constant-condition
132-
while (true) {
133-
const code = next();
134-
135-
switch (code) {
136-
// byte-order mark
137-
case CharCode.byteOrderMark:
138-
// We just skip the byte-order mark
139-
parts.push(text.substring(partStart, index - 1));
140-
partStart = index;
141-
break;
142-
143-
// strings
144-
case CharCode.doubleQuote:
145-
scanString();
146-
break;
147-
148-
// comments
149-
case CharCode.slash:
150-
// Single-line comment
151-
if (peek() === CharCode.slash) {
152-
// Be careful not to include the first slash in the text part.
153-
parts.push(text.substring(partStart, index - 1));
154-
155-
// Start after the second slash and scan until a line-break character is encountered.
156-
index++;
157-
while (index < length) {
158-
if (isLineBreak(peek())) {
159-
break;
160-
}
161-
162-
index++;
163-
}
164-
165-
partStart = index;
166-
}
167-
168-
// Multi-line comment
169-
if (peek() === CharCode.asterisk) {
170-
// Be careful not to include the first slash in the text part.
171-
parts.push(text.substring(partStart, index - 1));
172-
173-
// Start after the asterisk and scan until a */ is encountered.
174-
index++;
175-
while (index < length) {
176-
if (peek() === CharCode.asterisk && peek(1) === CharCode.slash) {
177-
index += 2;
178-
break;
179-
}
180-
181-
index++;
182-
}
183-
184-
partStart = index;
185-
}
186-
187-
break;
188-
189-
case CharCode.comma: {
190-
// Ignore trailing commas in object member lists and array element lists
191-
const nextCode = peekPastWhitespace();
192-
if (nextCode === CharCode.closeBrace || nextCode === CharCode.closeBracket) {
193-
parts.push(text.substring(partStart, index - 1));
194-
partStart = index;
195-
}
196-
197-
break;
198-
}
199-
default:
200-
}
201-
202-
if (index >= length && index > partStart) {
203-
parts.push(text.substring(partStart, length));
204-
break;
205-
}
206-
}
207-
208-
return parts.join('');
209-
}
6+
import { parse } from 'jsonc-parser';
2107

2118
export function tolerantParse(text: string) {
212-
text = cleanJsonText(text);
213-
return JSON.parse(text);
9+
return parse(text);
21410
}

src/shared/assets.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,8 @@ export async function getBuildOperations(generator: AssetGenerator): Promise<Ass
571571
try {
572572
tasksConfiguration = tolerantParse(text);
573573
} catch (error) {
574-
vscode.window.showErrorMessage(vscode.l10n.t('Failed to parse tasks.json file'));
574+
const message = error instanceof Error ? error.message : `${error}`;
575+
vscode.window.showErrorMessage(vscode.l10n.t('Failed to parse tasks.json file: {0}', message));
575576
return resolve({ updateTasksJson: false });
576577
}
577578

0 commit comments

Comments
 (0)