Alex Dima 4 سال پیش
والد
کامیت
0b344d31d0
19فایلهای تغییر یافته به همراه1814 افزوده شده و 1460 حذف شده
  1. 1 1
      .vscode/settings.json
  2. 21 21
      LICENSE.md
  3. 39 37
      README.md
  4. 0 2
      monaco.d.ts
  5. 76 48
      scripts/bundle.js
  6. 4 1
      scripts/dts.js
  7. 4 10
      scripts/release.js
  8. 2 2
      src/fillers/monaco-editor-core-amd.ts
  9. 9 5
      src/fillers/vscode-nls.ts
  10. 1 1
      src/json.worker.ts
  11. 157 109
      src/jsonMode.ts
  12. 159 108
      src/jsonWorker.ts
  13. 717 541
      src/languageFeatures.ts
  14. 199 185
      src/monaco.contribution.ts
  15. 180 156
      src/tokenization.ts
  16. 14 14
      src/tsconfig.esm.json
  17. 14 14
      src/tsconfig.json
  18. 91 87
      src/workerManager.ts
  19. 126 118
      test/index.html

+ 1 - 1
.vscode/settings.json

@@ -6,4 +6,4 @@
 		"**/release": true,
 		"**/out": true
 	}
-}
+}

+ 21 - 21
LICENSE.md

@@ -1,21 +1,21 @@
-The MIT License (MIT)
-
-Copyright (c) Microsoft Corporation
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
+The MIT License (MIT)
+
+Copyright (c) Microsoft Corporation
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 39 - 37
README.md

@@ -1,37 +1,39 @@
-# Monaco JSON
-
-JSON language plugin for the Monaco Editor. It provides the following features when editing JSON files:
-* Code completion, based on JSON schemas or by looking at similar objects in the same file
-* Hovers, based on JSON schemas
-* Validation: Syntax errors and schema validation
-* Formatting
-* Document Symbols
-* Syntax highlighting
-* Color decorators for all properties matching a schema containing `format: "color-hex"'` (non-standard schema extension)
-
-Schemas can be provided by configuration. See [here](https://github.com/Microsoft/monaco-json/blob/master/monaco.d.ts)
-for the API that the JSON plugin offers to configure the JSON language support.
-
-Internally the JSON plugin uses the [vscode-json-languageservice](https://github.com/Microsoft/vscode-json-languageservice)
-node module, providing the implementation of the features listed above. The same module is also used
-in [Visual Studio Code](https://github.com/Microsoft/vscode) to power the JSON editing experience.
-
-## Issues
-
-Please file issues concerning `monaco-json` in the [`monaco-editor` repository](https://github.com/Microsoft/monaco-editor/issues).
-
-## Installing
-
-This npm module is bundled and distributed in the [monaco-editor](https://www.npmjs.com/package/monaco-editor) npm module.
-
-## Development
-
-* `git clone https://github.com/Microsoft/monaco-json`
-* `npm install .`
-* compile with `npm run compile`
-* watch with `npm run watch`
-* `npm run prepublishOnly`
-* open `$/monaco-json/test/index.html` in your favorite browser.
-
-## License
-[MIT](https://github.com/Microsoft/monaco-json/blob/master/LICENSE.md)
+# Monaco JSON
+
+JSON language plugin for the Monaco Editor. It provides the following features when editing JSON files:
+
+- Code completion, based on JSON schemas or by looking at similar objects in the same file
+- Hovers, based on JSON schemas
+- Validation: Syntax errors and schema validation
+- Formatting
+- Document Symbols
+- Syntax highlighting
+- Color decorators for all properties matching a schema containing `format: "color-hex"'` (non-standard schema extension)
+
+Schemas can be provided by configuration. See [here](https://github.com/Microsoft/monaco-json/blob/master/monaco.d.ts)
+for the API that the JSON plugin offers to configure the JSON language support.
+
+Internally the JSON plugin uses the [vscode-json-languageservice](https://github.com/Microsoft/vscode-json-languageservice)
+node module, providing the implementation of the features listed above. The same module is also used
+in [Visual Studio Code](https://github.com/Microsoft/vscode) to power the JSON editing experience.
+
+## Issues
+
+Please file issues concerning `monaco-json` in the [`monaco-editor` repository](https://github.com/Microsoft/monaco-editor/issues).
+
+## Installing
+
+This npm module is bundled and distributed in the [monaco-editor](https://www.npmjs.com/package/monaco-editor) npm module.
+
+## Development
+
+- `git clone https://github.com/Microsoft/monaco-json`
+- `npm install .`
+- compile with `npm run compile`
+- watch with `npm run watch`
+- `npm run prepublishOnly`
+- open `$/monaco-json/test/index.html` in your favorite browser.
+
+## License
+
+[MIT](https://github.com/Microsoft/monaco-json/blob/master/LICENSE.md)

+ 0 - 2
monaco.d.ts

@@ -4,7 +4,6 @@
  *--------------------------------------------------------------------------------------------*/
 
 declare namespace monaco.languages.json {
-
 	export interface DiagnosticsOptions {
 		/**
 		 * If set, the validator will be enabled and perform syntax validation as well as schema based validation.
@@ -87,5 +86,4 @@ declare namespace monaco.languages.json {
 		setModeConfiguration(modeConfiguration: ModeConfiguration): void;
 	}
 	export const jsonDefaults: LanguageServiceDefaults;
-
 }

+ 76 - 48
scripts/bundle.js

@@ -1,7 +1,7 @@
 const requirejs = require('requirejs');
 const path = require('path');
 const fs = require('fs');
-const Terser = require("terser");
+const Terser = require('terser');
 const helpers = require('monaco-plugin-helpers');
 
 const REPO_ROOT = path.resolve(__dirname, '..');
@@ -25,52 +25,80 @@ bundleOne('jsonMode');
 bundleOne('jsonWorker');
 
 function bundleOne(moduleId) {
-	requirejs.optimize({
-		baseUrl: 'out/amd/',
-		name: 'vs/language/json/' + moduleId,
-		out: 'release/dev/' + moduleId + '.js',
-		paths: {
-			'vs/language/json': REPO_ROOT + '/out/amd',
-			'vs/language/json/fillers/monaco-editor-core': REPO_ROOT + '/out/amd/fillers/monaco-editor-core-amd',
+	requirejs.optimize(
+		{
+			baseUrl: 'out/amd/',
+			name: 'vs/language/json/' + moduleId,
+			out: 'release/dev/' + moduleId + '.js',
+			paths: {
+				'vs/language/json': REPO_ROOT + '/out/amd',
+				'vs/language/json/fillers/monaco-editor-core':
+					REPO_ROOT + '/out/amd/fillers/monaco-editor-core-amd'
+			},
+			optimize: 'none',
+			packages: [
+				{
+					name: 'vscode-json-languageservice',
+					location: path.join(
+						REPO_ROOT,
+						'node_modules/vscode-json-languageservice/lib/umd'
+					),
+					main: 'jsonLanguageService'
+				},
+				{
+					name: 'vscode-languageserver-types',
+					location: path.join(
+						REPO_ROOT,
+						'node_modules/vscode-languageserver-types/lib/umd'
+					),
+					main: 'main'
+				},
+				{
+					name: 'vscode-languageserver-textdocument',
+					location: path.join(
+						REPO_ROOT,
+						'node_modules/vscode-languageserver-textdocument/lib/umd'
+					),
+					main: 'main'
+				},
+				{
+					name: 'jsonc-parser',
+					location: path.join(REPO_ROOT, 'node_modules/jsonc-parser/lib/umd'),
+					main: 'main'
+				},
+				{
+					name: 'vscode-uri',
+					location: path.join(REPO_ROOT, 'node_modules/vscode-uri/lib/umd'),
+					main: 'index'
+				},
+				{
+					name: 'vscode-nls',
+					location: path.join(REPO_ROOT, '/out/amd/fillers'),
+					main: 'vscode-nls'
+				}
+			]
 		},
-		optimize: 'none',
-		packages: [{
-			name: 'vscode-json-languageservice',
-			location: path.join(REPO_ROOT, 'node_modules/vscode-json-languageservice/lib/umd'),
-			main: 'jsonLanguageService'
-		}, {
-			name: 'vscode-languageserver-types',
-			location: path.join(REPO_ROOT, 'node_modules/vscode-languageserver-types/lib/umd'),
-			main: 'main'
-		}, {
-			name: 'vscode-languageserver-textdocument',
-			location: path.join(REPO_ROOT, 'node_modules/vscode-languageserver-textdocument/lib/umd'),
-			main: 'main'
-		}, {
-			name: 'jsonc-parser',
-			location: path.join(REPO_ROOT, 'node_modules/jsonc-parser/lib/umd'),
-			main: 'main'
-		}, {
-			name: 'vscode-uri',
-			location: path.join(REPO_ROOT, 'node_modules/vscode-uri/lib/umd'),
-			main: 'index'
-		}, {
-			name: 'vscode-nls',
-			location: path.join(REPO_ROOT, '/out/amd/fillers'),
-			main: 'vscode-nls'
-		}]
-	}, async function (buildResponse) {
-		const devFilePath = path.join(REPO_ROOT, 'release/dev/' + moduleId + '.js');
-		const minFilePath = path.join(REPO_ROOT, 'release/min/' + moduleId + '.js');
-		const fileContents = fs.readFileSync(devFilePath).toString();
-		console.log(`Minifying ${devFilePath}...`);
-		const result = await Terser.minify(fileContents, {
-			output: {
-				comments: 'some'
-			}
-		});
-		console.log(`Done minifying ${devFilePath}.`);
-		try { fs.mkdirSync(path.join(REPO_ROOT, 'release/min')) } catch (err) { }
-		fs.writeFileSync(minFilePath, BUNDLED_FILE_HEADER + result.code);
-	})
+		async function (buildResponse) {
+			const devFilePath = path.join(
+				REPO_ROOT,
+				'release/dev/' + moduleId + '.js'
+			);
+			const minFilePath = path.join(
+				REPO_ROOT,
+				'release/min/' + moduleId + '.js'
+			);
+			const fileContents = fs.readFileSync(devFilePath).toString();
+			console.log(`Minifying ${devFilePath}...`);
+			const result = await Terser.minify(fileContents, {
+				output: {
+					comments: 'some'
+				}
+			});
+			console.log(`Done minifying ${devFilePath}.`);
+			try {
+				fs.mkdirSync(path.join(REPO_ROOT, 'release/min'));
+			} catch (err) {}
+			fs.writeFileSync(minFilePath, BUNDLED_FILE_HEADER + result.code);
+		}
+	);
 }

+ 4 - 1
scripts/dts.js

@@ -10,7 +10,10 @@ const REPO_ROOT = path.join(__dirname, '../');
 const SRC_PATH = path.join(REPO_ROOT, 'out/amd/monaco.contribution.d.ts');
 const DST_PATH = path.join(REPO_ROOT, 'monaco.d.ts');
 
-const lines = fs.readFileSync(SRC_PATH).toString().split(/\r\n|\r|\n/);
+const lines = fs
+	.readFileSync(SRC_PATH)
+	.toString()
+	.split(/\r\n|\r|\n/);
 let result = [
 	`/*---------------------------------------------------------------------------------------------`,
 	` *  Copyright (c) Microsoft Corporation. All rights reserved.`,

+ 4 - 10
scripts/release.js

@@ -12,19 +12,13 @@ helpers.packageESM({
 	repoRoot: REPO_ROOT,
 	esmSource: 'out/esm',
 	esmDestination: 'release/esm',
-	entryPoints: [
-		'monaco.contribution.js',
-		'jsonMode.js',
-		'json.worker.js'
-	],
+	entryPoints: ['monaco.contribution.js', 'jsonMode.js', 'json.worker.js'],
 	resolveAlias: {
-		'vscode-nls': path.join(REPO_ROOT, "out/esm/fillers/vscode-nls.js")
+		'vscode-nls': path.join(REPO_ROOT, 'out/esm/fillers/vscode-nls.js')
 	},
-	resolveSkip: [
-		'monaco-editor-core'
-	],
+	resolveSkip: ['monaco-editor-core'],
 	destinationFolderSimplification: {
-		'node_modules': '_deps',
+		node_modules: '_deps',
 		'jsonc-parser/lib/esm': 'jsonc-parser',
 		'vscode-languageserver-types/lib/esm': 'vscode-languageserver-types',
 		'vscode-uri/lib/esm': 'vscode-uri',

+ 2 - 2
src/fillers/monaco-editor-core-amd.ts

@@ -7,6 +7,6 @@
 
 declare var define;
 
-define([], function() {
-    return (<any>self).monaco;
+define([], function () {
+	return (<any>self).monaco;
 });

+ 9 - 5
src/fillers/vscode-nls.ts

@@ -20,7 +20,7 @@ export interface LoadFunc {
 }
 
 function format(message: string, args: any[]): string {
-	let result:string;
+	let result: string;
 
 	if (args.length === 0) {
 		result = message;
@@ -33,14 +33,18 @@ function format(message: string, args: any[]): string {
 	return result;
 }
 
-function localize(key: string | LocalizeInfo, message: string, ...args: any[]): string {
+function localize(
+	key: string | LocalizeInfo,
+	message: string,
+	...args: any[]
+): string {
 	return format(message, args);
 }
 
 export function loadMessageBundle(file?: string): LocalizeFunc {
-    return localize;
+	return localize;
 }
 
 export function config(opt?: Options | string): LoadFunc {
-    return loadMessageBundle;
-}
+	return loadMessageBundle;
+}

+ 1 - 1
src/json.worker.ts

@@ -9,6 +9,6 @@ import { JSONWorker } from './jsonWorker';
 self.onmessage = () => {
 	// ignore the first message
 	worker.initialize((ctx, createData) => {
-		return new JSONWorker(ctx, createData)
+		return new JSONWorker(ctx, createData);
 	});
 };

+ 157 - 109
src/jsonMode.ts

@@ -1,109 +1,157 @@
-/*---------------------------------------------------------------------------------------------
- *  Copyright (c) Microsoft Corporation. All rights reserved.
- *  Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { WorkerManager } from './workerManager';
-import type { JSONWorker } from './jsonWorker';
-import { LanguageServiceDefaults } from './monaco.contribution';
-import * as languageFeatures from './languageFeatures';
-import { createTokenizationSupport } from './tokenization';
-import { Uri, IDisposable, languages } from './fillers/monaco-editor-core'
-
-export function setupMode(defaults: LanguageServiceDefaults): IDisposable {
-
-	const disposables: IDisposable[] = [];
-	const providers: IDisposable[] = [];
-
-	const client = new WorkerManager(defaults);
-	disposables.push(client);
-
-	const worker: languageFeatures.WorkerAccessor = (...uris: Uri[]): Promise<JSONWorker> => {
-		return client.getLanguageServiceWorker(...uris);
-	};
-
-
-	function registerProviders(): void {
-		const { languageId, modeConfiguration } = defaults;
-
-		disposeAll(providers);
-
-		if (modeConfiguration.documentFormattingEdits) {
-			providers.push(languages.registerDocumentFormattingEditProvider(languageId, new languageFeatures.DocumentFormattingEditProvider(worker)));
-		}
-		if (modeConfiguration.documentRangeFormattingEdits) {
-			providers.push(languages.registerDocumentRangeFormattingEditProvider(languageId, new languageFeatures.DocumentRangeFormattingEditProvider(worker)));
-		}
-		if (modeConfiguration.completionItems) {
-			providers.push(languages.registerCompletionItemProvider(languageId, new languageFeatures.CompletionAdapter(worker)));
-		}
-		if (modeConfiguration.hovers) {
-			providers.push(languages.registerHoverProvider(languageId, new languageFeatures.HoverAdapter(worker)));
-		}
-		if (modeConfiguration.documentSymbols) {
-			providers.push(languages.registerDocumentSymbolProvider(languageId, new languageFeatures.DocumentSymbolAdapter(worker)));
-		}
-		if (modeConfiguration.tokens) {
-			providers.push(languages.setTokensProvider(languageId, createTokenizationSupport(true)));
-		}
-		if (modeConfiguration.colors) {
-			providers.push(languages.registerColorProvider(languageId, new languageFeatures.DocumentColorAdapter(worker)));
-		}
-		if (modeConfiguration.foldingRanges) {
-			providers.push(languages.registerFoldingRangeProvider(languageId, new languageFeatures.FoldingRangeAdapter(worker)));
-		}
-		if (modeConfiguration.diagnostics) {
-			providers.push(new languageFeatures.DiagnosticsAdapter(languageId, worker, defaults));
-		}
-		if (modeConfiguration.selectionRanges) {
-			providers.push(languages.registerSelectionRangeProvider(languageId, new languageFeatures.SelectionRangeAdapter(worker)));
-		}
-	}
-
-	registerProviders();
-
-	disposables.push(languages.setLanguageConfiguration(defaults.languageId, richEditConfiguration));
-
-	let modeConfiguration = defaults.modeConfiguration;
-	defaults.onDidChange((newDefaults) => {
-		if (newDefaults.modeConfiguration !== modeConfiguration) {
-			modeConfiguration = newDefaults.modeConfiguration;
-			registerProviders();
-		}
-	});
-
-	disposables.push(asDisposable(providers));
-
-	return asDisposable(disposables);
-}
-
-function asDisposable(disposables: IDisposable[]): IDisposable {
-	return { dispose: () => disposeAll(disposables) };
-}
-
-function disposeAll(disposables: IDisposable[]) {
-	while (disposables.length) {
-		disposables.pop().dispose();
-	}
-}
-
-const richEditConfiguration: languages.LanguageConfiguration = {
-	wordPattern: /(-?\d*\.\d\w*)|([^\[\{\]\}\:\"\,\s]+)/g,
-
-	comments: {
-		lineComment: '//',
-		blockComment: ['/*', '*/']
-	},
-
-	brackets: [
-		['{', '}'],
-		['[', ']']
-	],
-
-	autoClosingPairs: [
-		{ open: '{', close: '}', notIn: ['string'] },
-		{ open: '[', close: ']', notIn: ['string'] },
-		{ open: '"', close: '"', notIn: ['string'] }
-	]
-};
-
+/*---------------------------------------------------------------------------------------------
+ *  Copyright (c) Microsoft Corporation. All rights reserved.
+ *  Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { WorkerManager } from './workerManager';
+import type { JSONWorker } from './jsonWorker';
+import { LanguageServiceDefaults } from './monaco.contribution';
+import * as languageFeatures from './languageFeatures';
+import { createTokenizationSupport } from './tokenization';
+import { Uri, IDisposable, languages } from './fillers/monaco-editor-core';
+
+export function setupMode(defaults: LanguageServiceDefaults): IDisposable {
+	const disposables: IDisposable[] = [];
+	const providers: IDisposable[] = [];
+
+	const client = new WorkerManager(defaults);
+	disposables.push(client);
+
+	const worker: languageFeatures.WorkerAccessor = (
+		...uris: Uri[]
+	): Promise<JSONWorker> => {
+		return client.getLanguageServiceWorker(...uris);
+	};
+
+	function registerProviders(): void {
+		const { languageId, modeConfiguration } = defaults;
+
+		disposeAll(providers);
+
+		if (modeConfiguration.documentFormattingEdits) {
+			providers.push(
+				languages.registerDocumentFormattingEditProvider(
+					languageId,
+					new languageFeatures.DocumentFormattingEditProvider(worker)
+				)
+			);
+		}
+		if (modeConfiguration.documentRangeFormattingEdits) {
+			providers.push(
+				languages.registerDocumentRangeFormattingEditProvider(
+					languageId,
+					new languageFeatures.DocumentRangeFormattingEditProvider(worker)
+				)
+			);
+		}
+		if (modeConfiguration.completionItems) {
+			providers.push(
+				languages.registerCompletionItemProvider(
+					languageId,
+					new languageFeatures.CompletionAdapter(worker)
+				)
+			);
+		}
+		if (modeConfiguration.hovers) {
+			providers.push(
+				languages.registerHoverProvider(
+					languageId,
+					new languageFeatures.HoverAdapter(worker)
+				)
+			);
+		}
+		if (modeConfiguration.documentSymbols) {
+			providers.push(
+				languages.registerDocumentSymbolProvider(
+					languageId,
+					new languageFeatures.DocumentSymbolAdapter(worker)
+				)
+			);
+		}
+		if (modeConfiguration.tokens) {
+			providers.push(
+				languages.setTokensProvider(languageId, createTokenizationSupport(true))
+			);
+		}
+		if (modeConfiguration.colors) {
+			providers.push(
+				languages.registerColorProvider(
+					languageId,
+					new languageFeatures.DocumentColorAdapter(worker)
+				)
+			);
+		}
+		if (modeConfiguration.foldingRanges) {
+			providers.push(
+				languages.registerFoldingRangeProvider(
+					languageId,
+					new languageFeatures.FoldingRangeAdapter(worker)
+				)
+			);
+		}
+		if (modeConfiguration.diagnostics) {
+			providers.push(
+				new languageFeatures.DiagnosticsAdapter(languageId, worker, defaults)
+			);
+		}
+		if (modeConfiguration.selectionRanges) {
+			providers.push(
+				languages.registerSelectionRangeProvider(
+					languageId,
+					new languageFeatures.SelectionRangeAdapter(worker)
+				)
+			);
+		}
+	}
+
+	registerProviders();
+
+	disposables.push(
+		languages.setLanguageConfiguration(
+			defaults.languageId,
+			richEditConfiguration
+		)
+	);
+
+	let modeConfiguration = defaults.modeConfiguration;
+	defaults.onDidChange((newDefaults) => {
+		if (newDefaults.modeConfiguration !== modeConfiguration) {
+			modeConfiguration = newDefaults.modeConfiguration;
+			registerProviders();
+		}
+	});
+
+	disposables.push(asDisposable(providers));
+
+	return asDisposable(disposables);
+}
+
+function asDisposable(disposables: IDisposable[]): IDisposable {
+	return { dispose: () => disposeAll(disposables) };
+}
+
+function disposeAll(disposables: IDisposable[]) {
+	while (disposables.length) {
+		disposables.pop().dispose();
+	}
+}
+
+const richEditConfiguration: languages.LanguageConfiguration = {
+	wordPattern: /(-?\d*\.\d\w*)|([^\[\{\]\}\:\"\,\s]+)/g,
+
+	comments: {
+		lineComment: '//',
+		blockComment: ['/*', '*/']
+	},
+
+	brackets: [
+		['{', '}'],
+		['[', ']']
+	],
+
+	autoClosingPairs: [
+		{ open: '{', close: '}', notIn: ['string'] },
+		{ open: '[', close: ']', notIn: ['string'] },
+		{ open: '"', close: '"', notIn: ['string'] }
+	]
+};

+ 159 - 108
src/jsonWorker.ts

@@ -1,108 +1,159 @@
-/*---------------------------------------------------------------------------------------------
- *  Copyright (c) Microsoft Corporation. All rights reserved.
- *  Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import * as jsonService from 'vscode-json-languageservice';
-import type { worker } from './fillers/monaco-editor-core'
-
-let defaultSchemaRequestService;
-if (typeof fetch !== 'undefined') {
-	defaultSchemaRequestService = function (url) { return fetch(url).then(response => response.text()) };
-}
-
-export class JSONWorker {
-
-	private _ctx: worker.IWorkerContext;
-	private _languageService: jsonService.LanguageService;
-	private _languageSettings: jsonService.LanguageSettings;
-	private _languageId: string;
-
-	constructor(ctx: worker.IWorkerContext, createData: ICreateData) {
-		this._ctx = ctx;
-		this._languageSettings = createData.languageSettings;
-		this._languageId = createData.languageId;
-		this._languageService = jsonService.getLanguageService({
-			schemaRequestService: createData.enableSchemaRequest && defaultSchemaRequestService
-		});
-		this._languageService.configure(this._languageSettings);
-	}
-
-	async doValidation(uri: string): Promise<jsonService.Diagnostic[]> {
-		let document = this._getTextDocument(uri);
-		if (document) {
-			let jsonDocument = this._languageService.parseJSONDocument(document);
-			return this._languageService.doValidation(document, jsonDocument);
-		}
-		return Promise.resolve([]);
-	}
-	async doComplete(uri: string, position: jsonService.Position): Promise<jsonService.CompletionList> {
-		let document = this._getTextDocument(uri);
-		let jsonDocument = this._languageService.parseJSONDocument(document);
-		return this._languageService.doComplete(document, position, jsonDocument);
-	}
-	async doResolve(item: jsonService.CompletionItem): Promise<jsonService.CompletionItem> {
-		return this._languageService.doResolve(item);
-	}
-	async doHover(uri: string, position: jsonService.Position): Promise<jsonService.Hover> {
-		let document = this._getTextDocument(uri);
-		let jsonDocument = this._languageService.parseJSONDocument(document);
-		return this._languageService.doHover(document, position, jsonDocument);
-	}
-	async format(uri: string, range: jsonService.Range, options: jsonService.FormattingOptions): Promise<jsonService.TextEdit[]> {
-		let document = this._getTextDocument(uri);
-		let textEdits = this._languageService.format(document, range, options);
-		return Promise.resolve(textEdits);
-	}
-	async resetSchema(uri: string): Promise<boolean> {
-		return Promise.resolve(this._languageService.resetSchema(uri));
-	}
-	async findDocumentSymbols(uri: string): Promise<jsonService.SymbolInformation[]> {
-		let document = this._getTextDocument(uri);
-		let jsonDocument = this._languageService.parseJSONDocument(document);
-		let symbols = this._languageService.findDocumentSymbols(document, jsonDocument);
-		return Promise.resolve(symbols);
-	}
-	async findDocumentColors(uri: string): Promise<jsonService.ColorInformation[]> {
-		let document = this._getTextDocument(uri);
-		let jsonDocument = this._languageService.parseJSONDocument(document);
-		let colorSymbols = this._languageService.findDocumentColors(document, jsonDocument);
-		return Promise.resolve(colorSymbols);
-	}
-	async getColorPresentations(uri: string, color: jsonService.Color, range: jsonService.Range): Promise<jsonService.ColorPresentation[]> {
-		let document = this._getTextDocument(uri);
-		let jsonDocument = this._languageService.parseJSONDocument(document);
-		let colorPresentations = this._languageService.getColorPresentations(document, jsonDocument, color, range);
-		return Promise.resolve(colorPresentations);
-	}
-	async getFoldingRanges(uri: string, context?: { rangeLimit?: number; }): Promise<jsonService.FoldingRange[]> {
-		let document = this._getTextDocument(uri);
-		let ranges = this._languageService.getFoldingRanges(document, context);
-		return Promise.resolve(ranges);
-	}
-	async getSelectionRanges(uri: string, positions: jsonService.Position[]): Promise<jsonService.SelectionRange[]> {
-		let document = this._getTextDocument(uri);
-		let jsonDocument = this._languageService.parseJSONDocument(document);
-		let ranges = this._languageService.getSelectionRanges(document, positions, jsonDocument);
-		return Promise.resolve(ranges);
-	}
-	private _getTextDocument(uri: string): jsonService.TextDocument {
-		let models = this._ctx.getMirrorModels();
-		for (let model of models) {
-			if (model.uri.toString() === uri) {
-				return jsonService.TextDocument.create(uri, this._languageId, model.version, model.getValue());
-			}
-		}
-		return null;
-	}
-}
-
-export interface ICreateData {
-	languageId: string;
-	languageSettings: jsonService.LanguageSettings;
-	enableSchemaRequest: boolean;
-}
-
-export function create(ctx: worker.IWorkerContext, createData: ICreateData): JSONWorker {
-	return new JSONWorker(ctx, createData);
-}
+/*---------------------------------------------------------------------------------------------
+ *  Copyright (c) Microsoft Corporation. All rights reserved.
+ *  Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import * as jsonService from 'vscode-json-languageservice';
+import type { worker } from './fillers/monaco-editor-core';
+
+let defaultSchemaRequestService;
+if (typeof fetch !== 'undefined') {
+	defaultSchemaRequestService = function (url) {
+		return fetch(url).then((response) => response.text());
+	};
+}
+
+export class JSONWorker {
+	private _ctx: worker.IWorkerContext;
+	private _languageService: jsonService.LanguageService;
+	private _languageSettings: jsonService.LanguageSettings;
+	private _languageId: string;
+
+	constructor(ctx: worker.IWorkerContext, createData: ICreateData) {
+		this._ctx = ctx;
+		this._languageSettings = createData.languageSettings;
+		this._languageId = createData.languageId;
+		this._languageService = jsonService.getLanguageService({
+			schemaRequestService:
+				createData.enableSchemaRequest && defaultSchemaRequestService
+		});
+		this._languageService.configure(this._languageSettings);
+	}
+
+	async doValidation(uri: string): Promise<jsonService.Diagnostic[]> {
+		let document = this._getTextDocument(uri);
+		if (document) {
+			let jsonDocument = this._languageService.parseJSONDocument(document);
+			return this._languageService.doValidation(document, jsonDocument);
+		}
+		return Promise.resolve([]);
+	}
+	async doComplete(
+		uri: string,
+		position: jsonService.Position
+	): Promise<jsonService.CompletionList> {
+		let document = this._getTextDocument(uri);
+		let jsonDocument = this._languageService.parseJSONDocument(document);
+		return this._languageService.doComplete(document, position, jsonDocument);
+	}
+	async doResolve(
+		item: jsonService.CompletionItem
+	): Promise<jsonService.CompletionItem> {
+		return this._languageService.doResolve(item);
+	}
+	async doHover(
+		uri: string,
+		position: jsonService.Position
+	): Promise<jsonService.Hover> {
+		let document = this._getTextDocument(uri);
+		let jsonDocument = this._languageService.parseJSONDocument(document);
+		return this._languageService.doHover(document, position, jsonDocument);
+	}
+	async format(
+		uri: string,
+		range: jsonService.Range,
+		options: jsonService.FormattingOptions
+	): Promise<jsonService.TextEdit[]> {
+		let document = this._getTextDocument(uri);
+		let textEdits = this._languageService.format(document, range, options);
+		return Promise.resolve(textEdits);
+	}
+	async resetSchema(uri: string): Promise<boolean> {
+		return Promise.resolve(this._languageService.resetSchema(uri));
+	}
+	async findDocumentSymbols(
+		uri: string
+	): Promise<jsonService.SymbolInformation[]> {
+		let document = this._getTextDocument(uri);
+		let jsonDocument = this._languageService.parseJSONDocument(document);
+		let symbols = this._languageService.findDocumentSymbols(
+			document,
+			jsonDocument
+		);
+		return Promise.resolve(symbols);
+	}
+	async findDocumentColors(
+		uri: string
+	): Promise<jsonService.ColorInformation[]> {
+		let document = this._getTextDocument(uri);
+		let jsonDocument = this._languageService.parseJSONDocument(document);
+		let colorSymbols = this._languageService.findDocumentColors(
+			document,
+			jsonDocument
+		);
+		return Promise.resolve(colorSymbols);
+	}
+	async getColorPresentations(
+		uri: string,
+		color: jsonService.Color,
+		range: jsonService.Range
+	): Promise<jsonService.ColorPresentation[]> {
+		let document = this._getTextDocument(uri);
+		let jsonDocument = this._languageService.parseJSONDocument(document);
+		let colorPresentations = this._languageService.getColorPresentations(
+			document,
+			jsonDocument,
+			color,
+			range
+		);
+		return Promise.resolve(colorPresentations);
+	}
+	async getFoldingRanges(
+		uri: string,
+		context?: { rangeLimit?: number }
+	): Promise<jsonService.FoldingRange[]> {
+		let document = this._getTextDocument(uri);
+		let ranges = this._languageService.getFoldingRanges(document, context);
+		return Promise.resolve(ranges);
+	}
+	async getSelectionRanges(
+		uri: string,
+		positions: jsonService.Position[]
+	): Promise<jsonService.SelectionRange[]> {
+		let document = this._getTextDocument(uri);
+		let jsonDocument = this._languageService.parseJSONDocument(document);
+		let ranges = this._languageService.getSelectionRanges(
+			document,
+			positions,
+			jsonDocument
+		);
+		return Promise.resolve(ranges);
+	}
+	private _getTextDocument(uri: string): jsonService.TextDocument {
+		let models = this._ctx.getMirrorModels();
+		for (let model of models) {
+			if (model.uri.toString() === uri) {
+				return jsonService.TextDocument.create(
+					uri,
+					this._languageId,
+					model.version,
+					model.getValue()
+				);
+			}
+		}
+		return null;
+	}
+}
+
+export interface ICreateData {
+	languageId: string;
+	languageSettings: jsonService.LanguageSettings;
+	enableSchemaRequest: boolean;
+}
+
+export function create(
+	ctx: worker.IWorkerContext,
+	createData: ICreateData
+): JSONWorker {
+	return new JSONWorker(ctx, createData);
+}

+ 717 - 541
src/languageFeatures.ts

@@ -1,541 +1,717 @@
-/*---------------------------------------------------------------------------------------------
- *  Copyright (c) Microsoft Corporation. All rights reserved.
- *  Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { LanguageServiceDefaults } from './monaco.contribution';
-import type { JSONWorker } from './jsonWorker';
-import { Uri, Position, Range, IRange, CancellationToken, IDisposable, editor, languages, MarkerSeverity, IMarkdownString } from './fillers/monaco-editor-core'
-import * as jsonService from 'vscode-json-languageservice';
-
-
-export interface WorkerAccessor {
-	(...more: Uri[]): Promise<JSONWorker>
-}
-
-// --- diagnostics --- ---
-
-export class DiagnosticsAdapter {
-
-	private _disposables: IDisposable[] = [];
-	private _listener: { [uri: string]: IDisposable } = Object.create(null);
-
-	constructor(private _languageId: string, private _worker: WorkerAccessor, defaults: LanguageServiceDefaults) {
-		const onModelAdd = (model: editor.IModel): void => {
-			let modeId = model.getModeId();
-			if (modeId !== this._languageId) {
-				return;
-			}
-
-			let handle: number;
-			this._listener[model.uri.toString()] = model.onDidChangeContent(() => {
-				clearTimeout(handle);
-				handle = setTimeout(() => this._doValidate(model.uri, modeId), 500);
-			});
-
-			this._doValidate(model.uri, modeId);
-		};
-
-		const onModelRemoved = (model: editor.IModel): void => {
-			editor.setModelMarkers(model, this._languageId, []);
-			let uriStr = model.uri.toString();
-			let listener = this._listener[uriStr];
-			if (listener) {
-				listener.dispose();
-				delete this._listener[uriStr];
-			}
-		};
-
-		this._disposables.push(editor.onDidCreateModel(onModelAdd));
-		this._disposables.push(editor.onWillDisposeModel(model => {
-			onModelRemoved(model);
-			this._resetSchema(model.uri);
-		}));
-		this._disposables.push(editor.onDidChangeModelLanguage(event => {
-			onModelRemoved(event.model);
-			onModelAdd(event.model);
-			this._resetSchema(event.model.uri);
-		}));
-
-		this._disposables.push(defaults.onDidChange(_ => {
-			editor.getModels().forEach(model => {
-				if (model.getModeId() === this._languageId) {
-					onModelRemoved(model);
-					onModelAdd(model);
-				}
-			});
-		}));
-
-		this._disposables.push({
-			dispose: () => {
-				editor.getModels().forEach(onModelRemoved);
-				for (let key in this._listener) {
-					this._listener[key].dispose();
-				}
-			}
-		});
-
-		editor.getModels().forEach(onModelAdd);
-	}
-
-	public dispose(): void {
-		this._disposables.forEach(d => d && d.dispose());
-		this._disposables = [];
-	}
-
-	private _resetSchema(resource: Uri): void {
-		this._worker().then(worker => {
-			worker.resetSchema(resource.toString());
-		});
-	}
-
-	private _doValidate(resource: Uri, languageId: string): void {
-		this._worker(resource).then(worker => {
-			return worker.doValidation(resource.toString()).then(diagnostics => {
-				const markers = diagnostics.map(d => toDiagnostics(resource, d));
-				let model = editor.getModel(resource);
-				if (model && model.getModeId() === languageId) {
-					editor.setModelMarkers(model, languageId, markers);
-				}
-			});
-		}).then(undefined, err => {
-			console.error(err);
-		});
-	}
-}
-
-
-function toSeverity(lsSeverity: number): MarkerSeverity {
-	switch (lsSeverity) {
-		case jsonService.DiagnosticSeverity.Error: return MarkerSeverity.Error;
-		case jsonService.DiagnosticSeverity.Warning: return MarkerSeverity.Warning;
-		case jsonService.DiagnosticSeverity.Information: return MarkerSeverity.Info;
-		case jsonService.DiagnosticSeverity.Hint: return MarkerSeverity.Hint;
-		default:
-			return MarkerSeverity.Info;
-	}
-}
-
-function toDiagnostics(resource: Uri, diag: jsonService.Diagnostic): editor.IMarkerData {
-	let code = typeof diag.code === 'number' ? String(diag.code) : <string>diag.code;
-
-	return {
-		severity: toSeverity(diag.severity),
-		startLineNumber: diag.range.start.line + 1,
-		startColumn: diag.range.start.character + 1,
-		endLineNumber: diag.range.end.line + 1,
-		endColumn: diag.range.end.character + 1,
-		message: diag.message,
-		code: code,
-		source: diag.source
-	};
-}
-
-// --- completion ------
-
-function fromPosition(position: Position): jsonService.Position {
-	if (!position) {
-		return void 0;
-	}
-	return { character: position.column - 1, line: position.lineNumber - 1 };
-}
-
-function fromRange(range: IRange): jsonService.Range {
-	if (!range) {
-		return void 0;
-	}
-	return { start: { line: range.startLineNumber - 1, character: range.startColumn - 1 }, end: { line: range.endLineNumber - 1, character: range.endColumn - 1 } };
-}
-function toRange(range: jsonService.Range): Range {
-	if (!range) {
-		return void 0;
-	}
-	return new Range(range.start.line + 1, range.start.character + 1, range.end.line + 1, range.end.character + 1);
-}
-
-function toCompletionItemKind(kind: number): languages.CompletionItemKind {
-	let mItemKind = languages.CompletionItemKind;
-
-	switch (kind) {
-		case jsonService.CompletionItemKind.Text: return mItemKind.Text;
-		case jsonService.CompletionItemKind.Method: return mItemKind.Method;
-		case jsonService.CompletionItemKind.Function: return mItemKind.Function;
-		case jsonService.CompletionItemKind.Constructor: return mItemKind.Constructor;
-		case jsonService.CompletionItemKind.Field: return mItemKind.Field;
-		case jsonService.CompletionItemKind.Variable: return mItemKind.Variable;
-		case jsonService.CompletionItemKind.Class: return mItemKind.Class;
-		case jsonService.CompletionItemKind.Interface: return mItemKind.Interface;
-		case jsonService.CompletionItemKind.Module: return mItemKind.Module;
-		case jsonService.CompletionItemKind.Property: return mItemKind.Property;
-		case jsonService.CompletionItemKind.Unit: return mItemKind.Unit;
-		case jsonService.CompletionItemKind.Value: return mItemKind.Value;
-		case jsonService.CompletionItemKind.Enum: return mItemKind.Enum;
-		case jsonService.CompletionItemKind.Keyword: return mItemKind.Keyword;
-		case jsonService.CompletionItemKind.Snippet: return mItemKind.Snippet;
-		case jsonService.CompletionItemKind.Color: return mItemKind.Color;
-		case jsonService.CompletionItemKind.File: return mItemKind.File;
-		case jsonService.CompletionItemKind.Reference: return mItemKind.Reference;
-	}
-	return mItemKind.Property;
-}
-
-function fromCompletionItemKind(kind: languages.CompletionItemKind): jsonService.CompletionItemKind {
-	let mItemKind = languages.CompletionItemKind;
-
-	switch (kind) {
-		case mItemKind.Text: return jsonService.CompletionItemKind.Text;
-		case mItemKind.Method: return jsonService.CompletionItemKind.Method;
-		case mItemKind.Function: return jsonService.CompletionItemKind.Function;
-		case mItemKind.Constructor: return jsonService.CompletionItemKind.Constructor;
-		case mItemKind.Field: return jsonService.CompletionItemKind.Field;
-		case mItemKind.Variable: return jsonService.CompletionItemKind.Variable;
-		case mItemKind.Class: return jsonService.CompletionItemKind.Class;
-		case mItemKind.Interface: return jsonService.CompletionItemKind.Interface;
-		case mItemKind.Module: return jsonService.CompletionItemKind.Module;
-		case mItemKind.Property: return jsonService.CompletionItemKind.Property;
-		case mItemKind.Unit: return jsonService.CompletionItemKind.Unit;
-		case mItemKind.Value: return jsonService.CompletionItemKind.Value;
-		case mItemKind.Enum: return jsonService.CompletionItemKind.Enum;
-		case mItemKind.Keyword: return jsonService.CompletionItemKind.Keyword;
-		case mItemKind.Snippet: return jsonService.CompletionItemKind.Snippet;
-		case mItemKind.Color: return jsonService.CompletionItemKind.Color;
-		case mItemKind.File: return jsonService.CompletionItemKind.File;
-		case mItemKind.Reference: return jsonService.CompletionItemKind.Reference;
-	}
-	return jsonService.CompletionItemKind.Property;
-}
-
-function toTextEdit(textEdit: jsonService.TextEdit): editor.ISingleEditOperation {
-	if (!textEdit) {
-		return void 0;
-	}
-	return {
-		range: toRange(textEdit.range),
-		text: textEdit.newText
-	}
-}
-
-export class CompletionAdapter implements languages.CompletionItemProvider {
-
-	constructor(private _worker: WorkerAccessor) {
-	}
-
-	public get triggerCharacters(): string[] {
-		return [' ', ':'];
-	}
-
-	provideCompletionItems(model: editor.IReadOnlyModel, position: Position, context: languages.CompletionContext, token: CancellationToken): Promise<languages.CompletionList> {
-		const resource = model.uri;
-
-		return this._worker(resource).then(worker => {
-			return worker.doComplete(resource.toString(), fromPosition(position));
-		}).then(info => {
-			if (!info) {
-				return;
-			}
-			const wordInfo = model.getWordUntilPosition(position);
-			const wordRange = new Range(position.lineNumber, wordInfo.startColumn, position.lineNumber, wordInfo.endColumn);
-
-			let items: languages.CompletionItem[] = info.items.map(entry => {
-				let item: languages.CompletionItem = {
-					label: entry.label,
-					insertText: entry.insertText || entry.label,
-					sortText: entry.sortText,
-					filterText: entry.filterText,
-					documentation: entry.documentation,
-					detail: entry.detail,
-					range: wordRange,
-					kind: toCompletionItemKind(entry.kind),
-				};
-				if (entry.textEdit) {
-					item.range = toRange(entry.textEdit.range);
-					item.insertText = entry.textEdit.newText;
-				}
-				if (entry.additionalTextEdits) {
-					item.additionalTextEdits = entry.additionalTextEdits.map(toTextEdit)
-				}
-				if (entry.insertTextFormat === jsonService.InsertTextFormat.Snippet) {
-					item.insertTextRules = languages.CompletionItemInsertTextRule.InsertAsSnippet;
-				}
-				return item;
-			});
-
-			return {
-				isIncomplete: info.isIncomplete,
-				suggestions: items
-			};
-		});
-	}
-}
-
-function isMarkupContent(thing: any): thing is jsonService.MarkupContent {
-	return thing && typeof thing === 'object' && typeof (<jsonService.MarkupContent>thing).kind === 'string';
-}
-
-function toMarkdownString(entry: jsonService.MarkupContent | jsonService.MarkedString): IMarkdownString {
-	if (typeof entry === 'string') {
-		return {
-			value: entry
-		};
-	}
-	if (isMarkupContent(entry)) {
-		if (entry.kind === 'plaintext') {
-			return {
-				value: entry.value.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&')
-			};
-		}
-		return {
-			value: entry.value
-		};
-	}
-
-	return { value: '```' + entry.language + '\n' + entry.value + '\n```\n' };
-}
-
-function toMarkedStringArray(contents: jsonService.MarkupContent | jsonService.MarkedString | jsonService.MarkedString[]): IMarkdownString[] {
-	if (!contents) {
-		return void 0;
-	}
-	if (Array.isArray(contents)) {
-		return contents.map(toMarkdownString);
-	}
-	return [toMarkdownString(contents)];
-}
-
-
-// --- hover ------
-
-export class HoverAdapter implements languages.HoverProvider {
-
-	constructor(private _worker: WorkerAccessor) {
-	}
-
-	provideHover(model: editor.IReadOnlyModel, position: Position, token: CancellationToken): Promise<languages.Hover> {
-		let resource = model.uri;
-
-		return this._worker(resource).then(worker => {
-			return worker.doHover(resource.toString(), fromPosition(position));
-		}).then(info => {
-			if (!info) {
-				return;
-			}
-			return <languages.Hover>{
-				range: toRange(info.range),
-				contents: toMarkedStringArray(info.contents)
-			};
-		});
-	}
-}
-
-// --- definition ------
-
-function toLocation(location: jsonService.Location): languages.Location {
-	return {
-		uri: Uri.parse(location.uri),
-		range: toRange(location.range)
-	};
-}
-
-
-// --- document symbols ------
-
-function toSymbolKind(kind: jsonService.SymbolKind): languages.SymbolKind {
-	let mKind = languages.SymbolKind;
-
-	switch (kind) {
-		case jsonService.SymbolKind.File: return mKind.Array;
-		case jsonService.SymbolKind.Module: return mKind.Module;
-		case jsonService.SymbolKind.Namespace: return mKind.Namespace;
-		case jsonService.SymbolKind.Package: return mKind.Package;
-		case jsonService.SymbolKind.Class: return mKind.Class;
-		case jsonService.SymbolKind.Method: return mKind.Method;
-		case jsonService.SymbolKind.Property: return mKind.Property;
-		case jsonService.SymbolKind.Field: return mKind.Field;
-		case jsonService.SymbolKind.Constructor: return mKind.Constructor;
-		case jsonService.SymbolKind.Enum: return mKind.Enum;
-		case jsonService.SymbolKind.Interface: return mKind.Interface;
-		case jsonService.SymbolKind.Function: return mKind.Function;
-		case jsonService.SymbolKind.Variable: return mKind.Variable;
-		case jsonService.SymbolKind.Constant: return mKind.Constant;
-		case jsonService.SymbolKind.String: return mKind.String;
-		case jsonService.SymbolKind.Number: return mKind.Number;
-		case jsonService.SymbolKind.Boolean: return mKind.Boolean;
-		case jsonService.SymbolKind.Array: return mKind.Array;
-	}
-	return mKind.Function;
-}
-
-
-export class DocumentSymbolAdapter implements languages.DocumentSymbolProvider {
-
-	constructor(private _worker: WorkerAccessor) {
-	}
-
-	public provideDocumentSymbols(model: editor.IReadOnlyModel, token: CancellationToken): Promise<languages.DocumentSymbol[]> {
-		const resource = model.uri;
-
-		return this._worker(resource).then(worker => worker.findDocumentSymbols(resource.toString())).then(items => {
-			if (!items) {
-				return;
-			}
-			return items.map(item => ({
-				name: item.name,
-				detail: '',
-				containerName: item.containerName,
-				kind: toSymbolKind(item.kind),
-				range: toRange(item.location.range),
-				selectionRange: toRange(item.location.range),
-				tags: []
-			}));
-		});
-	}
-}
-
-
-function fromFormattingOptions(options: languages.FormattingOptions): jsonService.FormattingOptions {
-	return {
-		tabSize: options.tabSize,
-		insertSpaces: options.insertSpaces
-	};
-}
-
-export class DocumentFormattingEditProvider implements languages.DocumentFormattingEditProvider {
-
-	constructor(private _worker: WorkerAccessor) {
-	}
-
-	public provideDocumentFormattingEdits(model: editor.IReadOnlyModel, options: languages.FormattingOptions, token: CancellationToken): Promise<editor.ISingleEditOperation[]> {
-		const resource = model.uri;
-
-		return this._worker(resource).then(worker => {
-			return worker.format(resource.toString(), null, fromFormattingOptions(options)).then(edits => {
-				if (!edits || edits.length === 0) {
-					return;
-				}
-				return edits.map(toTextEdit);
-			});
-		});
-	}
-}
-
-export class DocumentRangeFormattingEditProvider implements languages.DocumentRangeFormattingEditProvider {
-
-	constructor(private _worker: WorkerAccessor) {
-	}
-
-	public provideDocumentRangeFormattingEdits(model: editor.IReadOnlyModel, range: Range, options: languages.FormattingOptions, token: CancellationToken): Promise<editor.ISingleEditOperation[]> {
-		const resource = model.uri;
-
-		return this._worker(resource).then(worker => {
-			return worker.format(resource.toString(), fromRange(range), fromFormattingOptions(options)).then(edits => {
-				if (!edits || edits.length === 0) {
-					return;
-				}
-				return edits.map(toTextEdit);
-			});
-		});
-	}
-}
-
-export class DocumentColorAdapter implements languages.DocumentColorProvider {
-
-	constructor(private _worker: WorkerAccessor) {
-	}
-
-	public provideDocumentColors(model: editor.IReadOnlyModel, token: CancellationToken): Promise<languages.IColorInformation[]> {
-		const resource = model.uri;
-
-		return this._worker(resource).then(worker => worker.findDocumentColors(resource.toString())).then(infos => {
-			if (!infos) {
-				return;
-			}
-			return infos.map(item => ({
-				color: item.color,
-				range: toRange(item.range)
-			}));
-		});
-	}
-
-	public provideColorPresentations(model: editor.IReadOnlyModel, info: languages.IColorInformation, token: CancellationToken): Promise<languages.IColorPresentation[]> {
-		const resource = model.uri;
-
-		return this._worker(resource).then(worker => worker.getColorPresentations(resource.toString(), info.color, fromRange(info.range))).then(presentations => {
-			if (!presentations) {
-				return;
-			}
-			return presentations.map(presentation => {
-				let item: languages.IColorPresentation = {
-					label: presentation.label,
-				};
-				if (presentation.textEdit) {
-					item.textEdit = toTextEdit(presentation.textEdit)
-				}
-				if (presentation.additionalTextEdits) {
-					item.additionalTextEdits = presentation.additionalTextEdits.map(toTextEdit)
-				}
-				return item;
-			});
-		});
-	}
-}
-
-export class FoldingRangeAdapter implements languages.FoldingRangeProvider {
-
-	constructor(private _worker: WorkerAccessor) {
-	}
-
-	public provideFoldingRanges(model: editor.IReadOnlyModel, context: languages.FoldingContext, token: CancellationToken): Promise<languages.FoldingRange[]> {
-		const resource = model.uri;
-
-		return this._worker(resource).then(worker => worker.getFoldingRanges(resource.toString(), context)).then(ranges => {
-			if (!ranges) {
-				return;
-			}
-			return ranges.map(range => {
-				let result: languages.FoldingRange = {
-					start: range.startLine + 1,
-					end: range.endLine + 1
-				};
-				if (typeof range.kind !== 'undefined') {
-					result.kind = toFoldingRangeKind(<jsonService.FoldingRangeKind>range.kind);
-				}
-				return result;
-			});
-		});
-	}
-
-}
-
-function toFoldingRangeKind(kind: jsonService.FoldingRangeKind): languages.FoldingRangeKind {
-	switch (kind) {
-		case jsonService.FoldingRangeKind.Comment: return languages.FoldingRangeKind.Comment;
-		case jsonService.FoldingRangeKind.Imports: return languages.FoldingRangeKind.Imports;
-		case jsonService.FoldingRangeKind.Region: return languages.FoldingRangeKind.Region;
-	}
-	return void 0;
-}
-
-export class SelectionRangeAdapter implements languages.SelectionRangeProvider {
-
-	constructor(private _worker: WorkerAccessor) {
-	}
-
-	public provideSelectionRanges(model: editor.IReadOnlyModel, positions: Position[], token: CancellationToken): Promise<languages.SelectionRange[][]> {
-		const resource = model.uri;
-
-		return this._worker(resource).then(worker => worker.getSelectionRanges(resource.toString(), positions.map(fromPosition))).then(selectionRanges => {
-			if (!selectionRanges) {
-				return;
-			}
-			return selectionRanges.map(selectionRange => {
-				const result: languages.SelectionRange[] = [];
-				while (selectionRange) {
-					result.push({ range: toRange(selectionRange.range) });
-					selectionRange = selectionRange.parent;
-				}
-				return result;
-			});
-		});
-	}
-
-}
+/*---------------------------------------------------------------------------------------------
+ *  Copyright (c) Microsoft Corporation. All rights reserved.
+ *  Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { LanguageServiceDefaults } from './monaco.contribution';
+import type { JSONWorker } from './jsonWorker';
+import {
+	Uri,
+	Position,
+	Range,
+	IRange,
+	CancellationToken,
+	IDisposable,
+	editor,
+	languages,
+	MarkerSeverity,
+	IMarkdownString
+} from './fillers/monaco-editor-core';
+import * as jsonService from 'vscode-json-languageservice';
+
+export interface WorkerAccessor {
+	(...more: Uri[]): Promise<JSONWorker>;
+}
+
+// --- diagnostics --- ---
+
+export class DiagnosticsAdapter {
+	private _disposables: IDisposable[] = [];
+	private _listener: { [uri: string]: IDisposable } = Object.create(null);
+
+	constructor(
+		private _languageId: string,
+		private _worker: WorkerAccessor,
+		defaults: LanguageServiceDefaults
+	) {
+		const onModelAdd = (model: editor.IModel): void => {
+			let modeId = model.getModeId();
+			if (modeId !== this._languageId) {
+				return;
+			}
+
+			let handle: number;
+			this._listener[model.uri.toString()] = model.onDidChangeContent(() => {
+				clearTimeout(handle);
+				handle = setTimeout(() => this._doValidate(model.uri, modeId), 500);
+			});
+
+			this._doValidate(model.uri, modeId);
+		};
+
+		const onModelRemoved = (model: editor.IModel): void => {
+			editor.setModelMarkers(model, this._languageId, []);
+			let uriStr = model.uri.toString();
+			let listener = this._listener[uriStr];
+			if (listener) {
+				listener.dispose();
+				delete this._listener[uriStr];
+			}
+		};
+
+		this._disposables.push(editor.onDidCreateModel(onModelAdd));
+		this._disposables.push(
+			editor.onWillDisposeModel((model) => {
+				onModelRemoved(model);
+				this._resetSchema(model.uri);
+			})
+		);
+		this._disposables.push(
+			editor.onDidChangeModelLanguage((event) => {
+				onModelRemoved(event.model);
+				onModelAdd(event.model);
+				this._resetSchema(event.model.uri);
+			})
+		);
+
+		this._disposables.push(
+			defaults.onDidChange((_) => {
+				editor.getModels().forEach((model) => {
+					if (model.getModeId() === this._languageId) {
+						onModelRemoved(model);
+						onModelAdd(model);
+					}
+				});
+			})
+		);
+
+		this._disposables.push({
+			dispose: () => {
+				editor.getModels().forEach(onModelRemoved);
+				for (let key in this._listener) {
+					this._listener[key].dispose();
+				}
+			}
+		});
+
+		editor.getModels().forEach(onModelAdd);
+	}
+
+	public dispose(): void {
+		this._disposables.forEach((d) => d && d.dispose());
+		this._disposables = [];
+	}
+
+	private _resetSchema(resource: Uri): void {
+		this._worker().then((worker) => {
+			worker.resetSchema(resource.toString());
+		});
+	}
+
+	private _doValidate(resource: Uri, languageId: string): void {
+		this._worker(resource)
+			.then((worker) => {
+				return worker.doValidation(resource.toString()).then((diagnostics) => {
+					const markers = diagnostics.map((d) => toDiagnostics(resource, d));
+					let model = editor.getModel(resource);
+					if (model && model.getModeId() === languageId) {
+						editor.setModelMarkers(model, languageId, markers);
+					}
+				});
+			})
+			.then(undefined, (err) => {
+				console.error(err);
+			});
+	}
+}
+
+function toSeverity(lsSeverity: number): MarkerSeverity {
+	switch (lsSeverity) {
+		case jsonService.DiagnosticSeverity.Error:
+			return MarkerSeverity.Error;
+		case jsonService.DiagnosticSeverity.Warning:
+			return MarkerSeverity.Warning;
+		case jsonService.DiagnosticSeverity.Information:
+			return MarkerSeverity.Info;
+		case jsonService.DiagnosticSeverity.Hint:
+			return MarkerSeverity.Hint;
+		default:
+			return MarkerSeverity.Info;
+	}
+}
+
+function toDiagnostics(
+	resource: Uri,
+	diag: jsonService.Diagnostic
+): editor.IMarkerData {
+	let code =
+		typeof diag.code === 'number' ? String(diag.code) : <string>diag.code;
+
+	return {
+		severity: toSeverity(diag.severity),
+		startLineNumber: diag.range.start.line + 1,
+		startColumn: diag.range.start.character + 1,
+		endLineNumber: diag.range.end.line + 1,
+		endColumn: diag.range.end.character + 1,
+		message: diag.message,
+		code: code,
+		source: diag.source
+	};
+}
+
+// --- completion ------
+
+function fromPosition(position: Position): jsonService.Position {
+	if (!position) {
+		return void 0;
+	}
+	return { character: position.column - 1, line: position.lineNumber - 1 };
+}
+
+function fromRange(range: IRange): jsonService.Range {
+	if (!range) {
+		return void 0;
+	}
+	return {
+		start: {
+			line: range.startLineNumber - 1,
+			character: range.startColumn - 1
+		},
+		end: { line: range.endLineNumber - 1, character: range.endColumn - 1 }
+	};
+}
+function toRange(range: jsonService.Range): Range {
+	if (!range) {
+		return void 0;
+	}
+	return new Range(
+		range.start.line + 1,
+		range.start.character + 1,
+		range.end.line + 1,
+		range.end.character + 1
+	);
+}
+
+function toCompletionItemKind(kind: number): languages.CompletionItemKind {
+	let mItemKind = languages.CompletionItemKind;
+
+	switch (kind) {
+		case jsonService.CompletionItemKind.Text:
+			return mItemKind.Text;
+		case jsonService.CompletionItemKind.Method:
+			return mItemKind.Method;
+		case jsonService.CompletionItemKind.Function:
+			return mItemKind.Function;
+		case jsonService.CompletionItemKind.Constructor:
+			return mItemKind.Constructor;
+		case jsonService.CompletionItemKind.Field:
+			return mItemKind.Field;
+		case jsonService.CompletionItemKind.Variable:
+			return mItemKind.Variable;
+		case jsonService.CompletionItemKind.Class:
+			return mItemKind.Class;
+		case jsonService.CompletionItemKind.Interface:
+			return mItemKind.Interface;
+		case jsonService.CompletionItemKind.Module:
+			return mItemKind.Module;
+		case jsonService.CompletionItemKind.Property:
+			return mItemKind.Property;
+		case jsonService.CompletionItemKind.Unit:
+			return mItemKind.Unit;
+		case jsonService.CompletionItemKind.Value:
+			return mItemKind.Value;
+		case jsonService.CompletionItemKind.Enum:
+			return mItemKind.Enum;
+		case jsonService.CompletionItemKind.Keyword:
+			return mItemKind.Keyword;
+		case jsonService.CompletionItemKind.Snippet:
+			return mItemKind.Snippet;
+		case jsonService.CompletionItemKind.Color:
+			return mItemKind.Color;
+		case jsonService.CompletionItemKind.File:
+			return mItemKind.File;
+		case jsonService.CompletionItemKind.Reference:
+			return mItemKind.Reference;
+	}
+	return mItemKind.Property;
+}
+
+function fromCompletionItemKind(
+	kind: languages.CompletionItemKind
+): jsonService.CompletionItemKind {
+	let mItemKind = languages.CompletionItemKind;
+
+	switch (kind) {
+		case mItemKind.Text:
+			return jsonService.CompletionItemKind.Text;
+		case mItemKind.Method:
+			return jsonService.CompletionItemKind.Method;
+		case mItemKind.Function:
+			return jsonService.CompletionItemKind.Function;
+		case mItemKind.Constructor:
+			return jsonService.CompletionItemKind.Constructor;
+		case mItemKind.Field:
+			return jsonService.CompletionItemKind.Field;
+		case mItemKind.Variable:
+			return jsonService.CompletionItemKind.Variable;
+		case mItemKind.Class:
+			return jsonService.CompletionItemKind.Class;
+		case mItemKind.Interface:
+			return jsonService.CompletionItemKind.Interface;
+		case mItemKind.Module:
+			return jsonService.CompletionItemKind.Module;
+		case mItemKind.Property:
+			return jsonService.CompletionItemKind.Property;
+		case mItemKind.Unit:
+			return jsonService.CompletionItemKind.Unit;
+		case mItemKind.Value:
+			return jsonService.CompletionItemKind.Value;
+		case mItemKind.Enum:
+			return jsonService.CompletionItemKind.Enum;
+		case mItemKind.Keyword:
+			return jsonService.CompletionItemKind.Keyword;
+		case mItemKind.Snippet:
+			return jsonService.CompletionItemKind.Snippet;
+		case mItemKind.Color:
+			return jsonService.CompletionItemKind.Color;
+		case mItemKind.File:
+			return jsonService.CompletionItemKind.File;
+		case mItemKind.Reference:
+			return jsonService.CompletionItemKind.Reference;
+	}
+	return jsonService.CompletionItemKind.Property;
+}
+
+function toTextEdit(
+	textEdit: jsonService.TextEdit
+): editor.ISingleEditOperation {
+	if (!textEdit) {
+		return void 0;
+	}
+	return {
+		range: toRange(textEdit.range),
+		text: textEdit.newText
+	};
+}
+
+export class CompletionAdapter implements languages.CompletionItemProvider {
+	constructor(private _worker: WorkerAccessor) {}
+
+	public get triggerCharacters(): string[] {
+		return [' ', ':'];
+	}
+
+	provideCompletionItems(
+		model: editor.IReadOnlyModel,
+		position: Position,
+		context: languages.CompletionContext,
+		token: CancellationToken
+	): Promise<languages.CompletionList> {
+		const resource = model.uri;
+
+		return this._worker(resource)
+			.then((worker) => {
+				return worker.doComplete(resource.toString(), fromPosition(position));
+			})
+			.then((info) => {
+				if (!info) {
+					return;
+				}
+				const wordInfo = model.getWordUntilPosition(position);
+				const wordRange = new Range(
+					position.lineNumber,
+					wordInfo.startColumn,
+					position.lineNumber,
+					wordInfo.endColumn
+				);
+
+				let items: languages.CompletionItem[] = info.items.map((entry) => {
+					let item: languages.CompletionItem = {
+						label: entry.label,
+						insertText: entry.insertText || entry.label,
+						sortText: entry.sortText,
+						filterText: entry.filterText,
+						documentation: entry.documentation,
+						detail: entry.detail,
+						range: wordRange,
+						kind: toCompletionItemKind(entry.kind)
+					};
+					if (entry.textEdit) {
+						item.range = toRange(entry.textEdit.range);
+						item.insertText = entry.textEdit.newText;
+					}
+					if (entry.additionalTextEdits) {
+						item.additionalTextEdits = entry.additionalTextEdits.map(
+							toTextEdit
+						);
+					}
+					if (entry.insertTextFormat === jsonService.InsertTextFormat.Snippet) {
+						item.insertTextRules =
+							languages.CompletionItemInsertTextRule.InsertAsSnippet;
+					}
+					return item;
+				});
+
+				return {
+					isIncomplete: info.isIncomplete,
+					suggestions: items
+				};
+			});
+	}
+}
+
+function isMarkupContent(thing: any): thing is jsonService.MarkupContent {
+	return (
+		thing &&
+		typeof thing === 'object' &&
+		typeof (<jsonService.MarkupContent>thing).kind === 'string'
+	);
+}
+
+function toMarkdownString(
+	entry: jsonService.MarkupContent | jsonService.MarkedString
+): IMarkdownString {
+	if (typeof entry === 'string') {
+		return {
+			value: entry
+		};
+	}
+	if (isMarkupContent(entry)) {
+		if (entry.kind === 'plaintext') {
+			return {
+				value: entry.value.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&')
+			};
+		}
+		return {
+			value: entry.value
+		};
+	}
+
+	return { value: '```' + entry.language + '\n' + entry.value + '\n```\n' };
+}
+
+function toMarkedStringArray(
+	contents:
+		| jsonService.MarkupContent
+		| jsonService.MarkedString
+		| jsonService.MarkedString[]
+): IMarkdownString[] {
+	if (!contents) {
+		return void 0;
+	}
+	if (Array.isArray(contents)) {
+		return contents.map(toMarkdownString);
+	}
+	return [toMarkdownString(contents)];
+}
+
+// --- hover ------
+
+export class HoverAdapter implements languages.HoverProvider {
+	constructor(private _worker: WorkerAccessor) {}
+
+	provideHover(
+		model: editor.IReadOnlyModel,
+		position: Position,
+		token: CancellationToken
+	): Promise<languages.Hover> {
+		let resource = model.uri;
+
+		return this._worker(resource)
+			.then((worker) => {
+				return worker.doHover(resource.toString(), fromPosition(position));
+			})
+			.then((info) => {
+				if (!info) {
+					return;
+				}
+				return <languages.Hover>{
+					range: toRange(info.range),
+					contents: toMarkedStringArray(info.contents)
+				};
+			});
+	}
+}
+
+// --- definition ------
+
+function toLocation(location: jsonService.Location): languages.Location {
+	return {
+		uri: Uri.parse(location.uri),
+		range: toRange(location.range)
+	};
+}
+
+// --- document symbols ------
+
+function toSymbolKind(kind: jsonService.SymbolKind): languages.SymbolKind {
+	let mKind = languages.SymbolKind;
+
+	switch (kind) {
+		case jsonService.SymbolKind.File:
+			return mKind.Array;
+		case jsonService.SymbolKind.Module:
+			return mKind.Module;
+		case jsonService.SymbolKind.Namespace:
+			return mKind.Namespace;
+		case jsonService.SymbolKind.Package:
+			return mKind.Package;
+		case jsonService.SymbolKind.Class:
+			return mKind.Class;
+		case jsonService.SymbolKind.Method:
+			return mKind.Method;
+		case jsonService.SymbolKind.Property:
+			return mKind.Property;
+		case jsonService.SymbolKind.Field:
+			return mKind.Field;
+		case jsonService.SymbolKind.Constructor:
+			return mKind.Constructor;
+		case jsonService.SymbolKind.Enum:
+			return mKind.Enum;
+		case jsonService.SymbolKind.Interface:
+			return mKind.Interface;
+		case jsonService.SymbolKind.Function:
+			return mKind.Function;
+		case jsonService.SymbolKind.Variable:
+			return mKind.Variable;
+		case jsonService.SymbolKind.Constant:
+			return mKind.Constant;
+		case jsonService.SymbolKind.String:
+			return mKind.String;
+		case jsonService.SymbolKind.Number:
+			return mKind.Number;
+		case jsonService.SymbolKind.Boolean:
+			return mKind.Boolean;
+		case jsonService.SymbolKind.Array:
+			return mKind.Array;
+	}
+	return mKind.Function;
+}
+
+export class DocumentSymbolAdapter implements languages.DocumentSymbolProvider {
+	constructor(private _worker: WorkerAccessor) {}
+
+	public provideDocumentSymbols(
+		model: editor.IReadOnlyModel,
+		token: CancellationToken
+	): Promise<languages.DocumentSymbol[]> {
+		const resource = model.uri;
+
+		return this._worker(resource)
+			.then((worker) => worker.findDocumentSymbols(resource.toString()))
+			.then((items) => {
+				if (!items) {
+					return;
+				}
+				return items.map((item) => ({
+					name: item.name,
+					detail: '',
+					containerName: item.containerName,
+					kind: toSymbolKind(item.kind),
+					range: toRange(item.location.range),
+					selectionRange: toRange(item.location.range),
+					tags: []
+				}));
+			});
+	}
+}
+
+function fromFormattingOptions(
+	options: languages.FormattingOptions
+): jsonService.FormattingOptions {
+	return {
+		tabSize: options.tabSize,
+		insertSpaces: options.insertSpaces
+	};
+}
+
+export class DocumentFormattingEditProvider
+	implements languages.DocumentFormattingEditProvider {
+	constructor(private _worker: WorkerAccessor) {}
+
+	public provideDocumentFormattingEdits(
+		model: editor.IReadOnlyModel,
+		options: languages.FormattingOptions,
+		token: CancellationToken
+	): Promise<editor.ISingleEditOperation[]> {
+		const resource = model.uri;
+
+		return this._worker(resource).then((worker) => {
+			return worker
+				.format(resource.toString(), null, fromFormattingOptions(options))
+				.then((edits) => {
+					if (!edits || edits.length === 0) {
+						return;
+					}
+					return edits.map(toTextEdit);
+				});
+		});
+	}
+}
+
+export class DocumentRangeFormattingEditProvider
+	implements languages.DocumentRangeFormattingEditProvider {
+	constructor(private _worker: WorkerAccessor) {}
+
+	public provideDocumentRangeFormattingEdits(
+		model: editor.IReadOnlyModel,
+		range: Range,
+		options: languages.FormattingOptions,
+		token: CancellationToken
+	): Promise<editor.ISingleEditOperation[]> {
+		const resource = model.uri;
+
+		return this._worker(resource).then((worker) => {
+			return worker
+				.format(
+					resource.toString(),
+					fromRange(range),
+					fromFormattingOptions(options)
+				)
+				.then((edits) => {
+					if (!edits || edits.length === 0) {
+						return;
+					}
+					return edits.map(toTextEdit);
+				});
+		});
+	}
+}
+
+export class DocumentColorAdapter implements languages.DocumentColorProvider {
+	constructor(private _worker: WorkerAccessor) {}
+
+	public provideDocumentColors(
+		model: editor.IReadOnlyModel,
+		token: CancellationToken
+	): Promise<languages.IColorInformation[]> {
+		const resource = model.uri;
+
+		return this._worker(resource)
+			.then((worker) => worker.findDocumentColors(resource.toString()))
+			.then((infos) => {
+				if (!infos) {
+					return;
+				}
+				return infos.map((item) => ({
+					color: item.color,
+					range: toRange(item.range)
+				}));
+			});
+	}
+
+	public provideColorPresentations(
+		model: editor.IReadOnlyModel,
+		info: languages.IColorInformation,
+		token: CancellationToken
+	): Promise<languages.IColorPresentation[]> {
+		const resource = model.uri;
+
+		return this._worker(resource)
+			.then((worker) =>
+				worker.getColorPresentations(
+					resource.toString(),
+					info.color,
+					fromRange(info.range)
+				)
+			)
+			.then((presentations) => {
+				if (!presentations) {
+					return;
+				}
+				return presentations.map((presentation) => {
+					let item: languages.IColorPresentation = {
+						label: presentation.label
+					};
+					if (presentation.textEdit) {
+						item.textEdit = toTextEdit(presentation.textEdit);
+					}
+					if (presentation.additionalTextEdits) {
+						item.additionalTextEdits = presentation.additionalTextEdits.map(
+							toTextEdit
+						);
+					}
+					return item;
+				});
+			});
+	}
+}
+
+export class FoldingRangeAdapter implements languages.FoldingRangeProvider {
+	constructor(private _worker: WorkerAccessor) {}
+
+	public provideFoldingRanges(
+		model: editor.IReadOnlyModel,
+		context: languages.FoldingContext,
+		token: CancellationToken
+	): Promise<languages.FoldingRange[]> {
+		const resource = model.uri;
+
+		return this._worker(resource)
+			.then((worker) => worker.getFoldingRanges(resource.toString(), context))
+			.then((ranges) => {
+				if (!ranges) {
+					return;
+				}
+				return ranges.map((range) => {
+					let result: languages.FoldingRange = {
+						start: range.startLine + 1,
+						end: range.endLine + 1
+					};
+					if (typeof range.kind !== 'undefined') {
+						result.kind = toFoldingRangeKind(
+							<jsonService.FoldingRangeKind>range.kind
+						);
+					}
+					return result;
+				});
+			});
+	}
+}
+
+function toFoldingRangeKind(
+	kind: jsonService.FoldingRangeKind
+): languages.FoldingRangeKind {
+	switch (kind) {
+		case jsonService.FoldingRangeKind.Comment:
+			return languages.FoldingRangeKind.Comment;
+		case jsonService.FoldingRangeKind.Imports:
+			return languages.FoldingRangeKind.Imports;
+		case jsonService.FoldingRangeKind.Region:
+			return languages.FoldingRangeKind.Region;
+	}
+	return void 0;
+}
+
+export class SelectionRangeAdapter implements languages.SelectionRangeProvider {
+	constructor(private _worker: WorkerAccessor) {}
+
+	public provideSelectionRanges(
+		model: editor.IReadOnlyModel,
+		positions: Position[],
+		token: CancellationToken
+	): Promise<languages.SelectionRange[][]> {
+		const resource = model.uri;
+
+		return this._worker(resource)
+			.then((worker) =>
+				worker.getSelectionRanges(
+					resource.toString(),
+					positions.map(fromPosition)
+				)
+			)
+			.then((selectionRanges) => {
+				if (!selectionRanges) {
+					return;
+				}
+				return selectionRanges.map((selectionRange) => {
+					const result: languages.SelectionRange[] = [];
+					while (selectionRange) {
+						result.push({ range: toRange(selectionRange.range) });
+						selectionRange = selectionRange.parent;
+					}
+					return result;
+				});
+			});
+	}
+}

+ 199 - 185
src/monaco.contribution.ts

@@ -1,185 +1,199 @@
-/*---------------------------------------------------------------------------------------------
- *  Copyright (c) Microsoft Corporation. All rights reserved.
- *  Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import * as mode from './jsonMode';
-import { Emitter, IEvent, languages } from './fillers/monaco-editor-core'
-
-// --- JSON configuration and defaults ---------
-
-export interface DiagnosticsOptions {
-	/**
-	 * If set, the validator will be enabled and perform syntax validation as well as schema based validation.
-	 */
-	readonly validate?: boolean;
-	/**
-	 * If set, comments are tolerated. If set to false, syntax errors will be emitted for comments.
-	 */
-	readonly allowComments?: boolean;
-	/**
-	 * A list of known schemas and/or associations of schemas to file names.
-	 */
-	readonly schemas?: {
-		/**
-		 * The URI of the schema, which is also the identifier of the schema.
-		 */
-		readonly uri: string;
-		/**
-		 * A list of file names that are associated to the schema. The '*' wildcard can be used. For example '*.schema.json', 'package.json'
-		 */
-		readonly fileMatch?: string[];
-		/**
-		 * The schema for the given URI.
-		 */
-		readonly schema?: any;
-	}[];
-	/**
-	 *  If set, the schema service would load schema content on-demand with 'fetch' if available
-	 */
-	readonly enableSchemaRequest?: boolean;
-}
-
-export interface ModeConfiguration {
-	/**
-	 * Defines whether the built-in documentFormattingEdit provider is enabled.
-	 */
-	readonly documentFormattingEdits?: boolean;
-
-	/**
-	 * Defines whether the built-in documentRangeFormattingEdit provider is enabled.
-	 */
-	readonly documentRangeFormattingEdits?: boolean;
-
-	/**
-	 * Defines whether the built-in completionItemProvider is enabled.
-	 */
-	readonly completionItems?: boolean;
-
-	/**
-	 * Defines whether the built-in hoverProvider is enabled.
-	 */
-	readonly hovers?: boolean;
-
-	/**
-	 * Defines whether the built-in documentSymbolProvider is enabled.
-	 */
-	readonly documentSymbols?: boolean;
-
-	/**
-	 * Defines whether the built-in tokens provider is enabled.
-	 */
-	readonly tokens?: boolean;
-
-	/**
-	 * Defines whether the built-in color provider is enabled.
-	 */
-	readonly colors?: boolean;
-
-	/**
-	 * Defines whether the built-in foldingRange provider is enabled.
-	 */
-	readonly foldingRanges?: boolean;
-
-	/**
-	 * Defines whether the built-in diagnostic provider is enabled.
-	 */
-	readonly diagnostics?: boolean;
-
-	/**
-	 * Defines whether the built-in selection range provider is enabled.
-	 */
-	readonly selectionRanges?: boolean;
-
-}
-
-export interface LanguageServiceDefaults {
-	readonly languageId: string;
-	readonly onDidChange: IEvent<LanguageServiceDefaults>;
-	readonly diagnosticsOptions: DiagnosticsOptions;
-	readonly modeConfiguration: ModeConfiguration;
-	setDiagnosticsOptions(options: DiagnosticsOptions): void;
-	setModeConfiguration(modeConfiguration: ModeConfiguration): void;
-}
-
-class LanguageServiceDefaultsImpl implements LanguageServiceDefaults {
-
-	private _onDidChange = new Emitter<LanguageServiceDefaults>();
-	private _diagnosticsOptions: DiagnosticsOptions;
-	private _modeConfiguration: ModeConfiguration;
-	private _languageId: string;
-
-	constructor(languageId: string, diagnosticsOptions: DiagnosticsOptions, modeConfiguration: ModeConfiguration) {
-		this._languageId = languageId;
-		this.setDiagnosticsOptions(diagnosticsOptions);
-		this.setModeConfiguration(modeConfiguration);
-	}
-
-	get onDidChange(): IEvent<LanguageServiceDefaults> {
-		return this._onDidChange.event;
-	}
-
-	get languageId(): string {
-		return this._languageId;
-	}
-
-	get modeConfiguration(): ModeConfiguration {
-		return this._modeConfiguration;
-	}
-
-	get diagnosticsOptions(): DiagnosticsOptions {
-		return this._diagnosticsOptions;
-	}
-
-	setDiagnosticsOptions(options: DiagnosticsOptions): void {
-		this._diagnosticsOptions = options || Object.create(null);
-		this._onDidChange.fire(this);
-	}
-
-	setModeConfiguration(modeConfiguration: ModeConfiguration): void {
-		this._modeConfiguration = modeConfiguration || Object.create(null);
-		this._onDidChange.fire(this);
-	};
-}
-
-const diagnosticDefault: Required<DiagnosticsOptions> = {
-	validate: true,
-	allowComments: true,
-	schemas: [],
-	enableSchemaRequest: false
-};
-
-const modeConfigurationDefault: Required<ModeConfiguration> = {
-	documentFormattingEdits: true,
-	documentRangeFormattingEdits: true,
-	completionItems: true,
-	hovers: true,
-	documentSymbols: true,
-	tokens: true,
-	colors: true,
-	foldingRanges: true,
-	diagnostics: true,
-	selectionRanges: true
-}
-
-export const jsonDefaults: LanguageServiceDefaults = new LanguageServiceDefaultsImpl('json', diagnosticDefault, modeConfigurationDefault);
-
-// export to the global based API
-(<any>languages).json = { jsonDefaults };
-
-// --- Registration to monaco editor ---
-
-function getMode(): Promise<typeof mode> {
-	return import('./jsonMode');
-}
-
-languages.register({
-	id: 'json',
-	extensions: ['.json', '.bowerrc', '.jshintrc', '.jscsrc', '.eslintrc', '.babelrc', '.har'],
-	aliases: ['JSON', 'json'],
-	mimetypes: ['application/json'],
-});
-
-languages.onLanguage('json', () => {
-	getMode().then(mode => mode.setupMode(jsonDefaults));
-});
+/*---------------------------------------------------------------------------------------------
+ *  Copyright (c) Microsoft Corporation. All rights reserved.
+ *  Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import * as mode from './jsonMode';
+import { Emitter, IEvent, languages } from './fillers/monaco-editor-core';
+
+// --- JSON configuration and defaults ---------
+
+export interface DiagnosticsOptions {
+	/**
+	 * If set, the validator will be enabled and perform syntax validation as well as schema based validation.
+	 */
+	readonly validate?: boolean;
+	/**
+	 * If set, comments are tolerated. If set to false, syntax errors will be emitted for comments.
+	 */
+	readonly allowComments?: boolean;
+	/**
+	 * A list of known schemas and/or associations of schemas to file names.
+	 */
+	readonly schemas?: {
+		/**
+		 * The URI of the schema, which is also the identifier of the schema.
+		 */
+		readonly uri: string;
+		/**
+		 * A list of file names that are associated to the schema. The '*' wildcard can be used. For example '*.schema.json', 'package.json'
+		 */
+		readonly fileMatch?: string[];
+		/**
+		 * The schema for the given URI.
+		 */
+		readonly schema?: any;
+	}[];
+	/**
+	 *  If set, the schema service would load schema content on-demand with 'fetch' if available
+	 */
+	readonly enableSchemaRequest?: boolean;
+}
+
+export interface ModeConfiguration {
+	/**
+	 * Defines whether the built-in documentFormattingEdit provider is enabled.
+	 */
+	readonly documentFormattingEdits?: boolean;
+
+	/**
+	 * Defines whether the built-in documentRangeFormattingEdit provider is enabled.
+	 */
+	readonly documentRangeFormattingEdits?: boolean;
+
+	/**
+	 * Defines whether the built-in completionItemProvider is enabled.
+	 */
+	readonly completionItems?: boolean;
+
+	/**
+	 * Defines whether the built-in hoverProvider is enabled.
+	 */
+	readonly hovers?: boolean;
+
+	/**
+	 * Defines whether the built-in documentSymbolProvider is enabled.
+	 */
+	readonly documentSymbols?: boolean;
+
+	/**
+	 * Defines whether the built-in tokens provider is enabled.
+	 */
+	readonly tokens?: boolean;
+
+	/**
+	 * Defines whether the built-in color provider is enabled.
+	 */
+	readonly colors?: boolean;
+
+	/**
+	 * Defines whether the built-in foldingRange provider is enabled.
+	 */
+	readonly foldingRanges?: boolean;
+
+	/**
+	 * Defines whether the built-in diagnostic provider is enabled.
+	 */
+	readonly diagnostics?: boolean;
+
+	/**
+	 * Defines whether the built-in selection range provider is enabled.
+	 */
+	readonly selectionRanges?: boolean;
+}
+
+export interface LanguageServiceDefaults {
+	readonly languageId: string;
+	readonly onDidChange: IEvent<LanguageServiceDefaults>;
+	readonly diagnosticsOptions: DiagnosticsOptions;
+	readonly modeConfiguration: ModeConfiguration;
+	setDiagnosticsOptions(options: DiagnosticsOptions): void;
+	setModeConfiguration(modeConfiguration: ModeConfiguration): void;
+}
+
+class LanguageServiceDefaultsImpl implements LanguageServiceDefaults {
+	private _onDidChange = new Emitter<LanguageServiceDefaults>();
+	private _diagnosticsOptions: DiagnosticsOptions;
+	private _modeConfiguration: ModeConfiguration;
+	private _languageId: string;
+
+	constructor(
+		languageId: string,
+		diagnosticsOptions: DiagnosticsOptions,
+		modeConfiguration: ModeConfiguration
+	) {
+		this._languageId = languageId;
+		this.setDiagnosticsOptions(diagnosticsOptions);
+		this.setModeConfiguration(modeConfiguration);
+	}
+
+	get onDidChange(): IEvent<LanguageServiceDefaults> {
+		return this._onDidChange.event;
+	}
+
+	get languageId(): string {
+		return this._languageId;
+	}
+
+	get modeConfiguration(): ModeConfiguration {
+		return this._modeConfiguration;
+	}
+
+	get diagnosticsOptions(): DiagnosticsOptions {
+		return this._diagnosticsOptions;
+	}
+
+	setDiagnosticsOptions(options: DiagnosticsOptions): void {
+		this._diagnosticsOptions = options || Object.create(null);
+		this._onDidChange.fire(this);
+	}
+
+	setModeConfiguration(modeConfiguration: ModeConfiguration): void {
+		this._modeConfiguration = modeConfiguration || Object.create(null);
+		this._onDidChange.fire(this);
+	}
+}
+
+const diagnosticDefault: Required<DiagnosticsOptions> = {
+	validate: true,
+	allowComments: true,
+	schemas: [],
+	enableSchemaRequest: false
+};
+
+const modeConfigurationDefault: Required<ModeConfiguration> = {
+	documentFormattingEdits: true,
+	documentRangeFormattingEdits: true,
+	completionItems: true,
+	hovers: true,
+	documentSymbols: true,
+	tokens: true,
+	colors: true,
+	foldingRanges: true,
+	diagnostics: true,
+	selectionRanges: true
+};
+
+export const jsonDefaults: LanguageServiceDefaults = new LanguageServiceDefaultsImpl(
+	'json',
+	diagnosticDefault,
+	modeConfigurationDefault
+);
+
+// export to the global based API
+(<any>languages).json = { jsonDefaults };
+
+// --- Registration to monaco editor ---
+
+function getMode(): Promise<typeof mode> {
+	return import('./jsonMode');
+}
+
+languages.register({
+	id: 'json',
+	extensions: [
+		'.json',
+		'.bowerrc',
+		'.jshintrc',
+		'.jscsrc',
+		'.eslintrc',
+		'.babelrc',
+		'.har'
+	],
+	aliases: ['JSON', 'json'],
+	mimetypes: ['application/json']
+});
+
+languages.onLanguage('json', () => {
+	getMode().then((mode) => mode.setupMode(jsonDefaults));
+});

+ 180 - 156
src/tokenization.ts

@@ -4,13 +4,22 @@
  *--------------------------------------------------------------------------------------------*/
 
 import * as json from 'jsonc-parser';
-import { languages } from './fillers/monaco-editor-core'
-
-export function createTokenizationSupport(supportComments: boolean): languages.TokensProvider {
-    return {
-        getInitialState: () => new JSONState(null, null, false),
-        tokenize: (line, state, offsetDelta?, stopAtOffset?) => tokenize(supportComments, line, <JSONState>state, offsetDelta, stopAtOffset)
-    };
+import { languages } from './fillers/monaco-editor-core';
+
+export function createTokenizationSupport(
+	supportComments: boolean
+): languages.TokensProvider {
+	return {
+		getInitialState: () => new JSONState(null, null, false),
+		tokenize: (line, state, offsetDelta?, stopAtOffset?) =>
+			tokenize(
+				supportComments,
+				line,
+				<JSONState>state,
+				offsetDelta,
+				stopAtOffset
+			)
+	};
 }
 
 export const TOKEN_DELIM_OBJECT = 'delimiter.bracket.json';
@@ -26,155 +35,170 @@ export const TOKEN_COMMENT_BLOCK = 'comment.block.json';
 export const TOKEN_COMMENT_LINE = 'comment.line.json';
 
 class JSONState implements languages.IState {
-
-    private _state: languages.IState;
-
-    public scanError: json.ScanError;
-    public lastWasColon: boolean;
-
-    constructor(state: languages.IState, scanError: json.ScanError, lastWasColon: boolean) {
-        this._state = state;
-        this.scanError = scanError;
-        this.lastWasColon = lastWasColon;
-    }
-
-    public clone(): JSONState {
-        return new JSONState(this._state, this.scanError, this.lastWasColon);
-    }
-
-    public equals(other: languages.IState): boolean {
-        if (other === this) {
-            return true;
-        }
-        if (!other || !(other instanceof JSONState)) {
-            return false;
-        }
-        return this.scanError === (<JSONState>other).scanError &&
-            this.lastWasColon === (<JSONState>other).lastWasColon;
-    }
-
-    public getStateData(): languages.IState {
-        return this._state;
-    }
-
-    public setStateData(state: languages.IState): void {
-        this._state = state;
-    }
+	private _state: languages.IState;
+
+	public scanError: json.ScanError;
+	public lastWasColon: boolean;
+
+	constructor(
+		state: languages.IState,
+		scanError: json.ScanError,
+		lastWasColon: boolean
+	) {
+		this._state = state;
+		this.scanError = scanError;
+		this.lastWasColon = lastWasColon;
+	}
+
+	public clone(): JSONState {
+		return new JSONState(this._state, this.scanError, this.lastWasColon);
+	}
+
+	public equals(other: languages.IState): boolean {
+		if (other === this) {
+			return true;
+		}
+		if (!other || !(other instanceof JSONState)) {
+			return false;
+		}
+		return (
+			this.scanError === (<JSONState>other).scanError &&
+			this.lastWasColon === (<JSONState>other).lastWasColon
+		);
+	}
+
+	public getStateData(): languages.IState {
+		return this._state;
+	}
+
+	public setStateData(state: languages.IState): void {
+		this._state = state;
+	}
 }
 
-function tokenize(comments: boolean, line: string, state: JSONState, offsetDelta: number = 0, stopAtOffset?: number): languages.ILineTokens {
-
-    // handle multiline strings and block comments
-    var numberOfInsertedCharacters = 0,
-        adjustOffset = false;
-
-    switch (state.scanError) {
-        case json.ScanError.UnexpectedEndOfString:
-            line = '"' + line;
-            numberOfInsertedCharacters = 1;
-            break;
-        case json.ScanError.UnexpectedEndOfComment:
-            line = '/*' + line;
-            numberOfInsertedCharacters = 2;
-            break;
-    }
-
-    var scanner = json.createScanner(line),
-        kind: json.SyntaxKind,
-        ret: languages.ILineTokens,
-        lastWasColon = state.lastWasColon;
-
-    ret = {
-        tokens: <languages.IToken[]>[],
-        endState: state.clone()
-    };
-
-    while (true) {
-
-        var offset = offsetDelta + scanner.getPosition(),
-            type = '';
-
-        kind = scanner.scan();
-        if (kind === json.SyntaxKind.EOF) {
-            break;
-        }
-
-        // Check that the scanner has advanced
-        if (offset === offsetDelta + scanner.getPosition()) {
-            throw new Error('Scanner did not advance, next 3 characters are: ' + line.substr(scanner.getPosition(), 3));
-        }
-
-        // In case we inserted /* or " character, we need to
-        // adjust the offset of all tokens (except the first)
-        if (adjustOffset) {
-            offset -= numberOfInsertedCharacters;
-        }
-        adjustOffset = numberOfInsertedCharacters > 0;
-
-
-        // brackets and type
-        switch (kind) {
-            case json.SyntaxKind.OpenBraceToken:
-                type = TOKEN_DELIM_OBJECT;
-                lastWasColon = false;
-                break;
-            case json.SyntaxKind.CloseBraceToken:
-                type = TOKEN_DELIM_OBJECT;
-                lastWasColon = false;
-                break;
-            case json.SyntaxKind.OpenBracketToken:
-                type = TOKEN_DELIM_ARRAY;
-                lastWasColon = false;
-                break;
-            case json.SyntaxKind.CloseBracketToken:
-                type = TOKEN_DELIM_ARRAY;
-                lastWasColon = false;
-                break;
-            case json.SyntaxKind.ColonToken:
-                type = TOKEN_DELIM_COLON;
-                lastWasColon = true;
-                break;
-            case json.SyntaxKind.CommaToken:
-                type = TOKEN_DELIM_COMMA;
-                lastWasColon = false;
-                break;
-            case json.SyntaxKind.TrueKeyword:
-            case json.SyntaxKind.FalseKeyword:
-                type = TOKEN_VALUE_BOOLEAN;
-                lastWasColon = false;
-                break;
-            case json.SyntaxKind.NullKeyword:
-                type = TOKEN_VALUE_NULL;
-                lastWasColon = false;
-                break;
-            case json.SyntaxKind.StringLiteral:
-                type = lastWasColon ? TOKEN_VALUE_STRING : TOKEN_PROPERTY_NAME;
-                lastWasColon = false;
-                break;
-            case json.SyntaxKind.NumericLiteral:
-                type = TOKEN_VALUE_NUMBER;
-                lastWasColon = false;
-                break;
-        }
-
-        // comments, iff enabled
-        if (comments) {
-            switch (kind) {
-                case json.SyntaxKind.LineCommentTrivia:
-                    type = TOKEN_COMMENT_LINE;
-                    break;
-                case json.SyntaxKind.BlockCommentTrivia:
-                    type = TOKEN_COMMENT_BLOCK;
-                    break;
-            }
-        }
-
-        ret.endState = new JSONState(state.getStateData(), scanner.getTokenError(), lastWasColon);
-        ret.tokens.push({
-            startIndex: offset,
-            scopes: type
-        });
-    }
-
-    return ret;
+function tokenize(
+	comments: boolean,
+	line: string,
+	state: JSONState,
+	offsetDelta: number = 0,
+	stopAtOffset?: number
+): languages.ILineTokens {
+	// handle multiline strings and block comments
+	var numberOfInsertedCharacters = 0,
+		adjustOffset = false;
+
+	switch (state.scanError) {
+		case json.ScanError.UnexpectedEndOfString:
+			line = '"' + line;
+			numberOfInsertedCharacters = 1;
+			break;
+		case json.ScanError.UnexpectedEndOfComment:
+			line = '/*' + line;
+			numberOfInsertedCharacters = 2;
+			break;
+	}
+
+	var scanner = json.createScanner(line),
+		kind: json.SyntaxKind,
+		ret: languages.ILineTokens,
+		lastWasColon = state.lastWasColon;
+
+	ret = {
+		tokens: <languages.IToken[]>[],
+		endState: state.clone()
+	};
+
+	while (true) {
+		var offset = offsetDelta + scanner.getPosition(),
+			type = '';
+
+		kind = scanner.scan();
+		if (kind === json.SyntaxKind.EOF) {
+			break;
+		}
+
+		// Check that the scanner has advanced
+		if (offset === offsetDelta + scanner.getPosition()) {
+			throw new Error(
+				'Scanner did not advance, next 3 characters are: ' +
+					line.substr(scanner.getPosition(), 3)
+			);
+		}
+
+		// In case we inserted /* or " character, we need to
+		// adjust the offset of all tokens (except the first)
+		if (adjustOffset) {
+			offset -= numberOfInsertedCharacters;
+		}
+		adjustOffset = numberOfInsertedCharacters > 0;
+
+		// brackets and type
+		switch (kind) {
+			case json.SyntaxKind.OpenBraceToken:
+				type = TOKEN_DELIM_OBJECT;
+				lastWasColon = false;
+				break;
+			case json.SyntaxKind.CloseBraceToken:
+				type = TOKEN_DELIM_OBJECT;
+				lastWasColon = false;
+				break;
+			case json.SyntaxKind.OpenBracketToken:
+				type = TOKEN_DELIM_ARRAY;
+				lastWasColon = false;
+				break;
+			case json.SyntaxKind.CloseBracketToken:
+				type = TOKEN_DELIM_ARRAY;
+				lastWasColon = false;
+				break;
+			case json.SyntaxKind.ColonToken:
+				type = TOKEN_DELIM_COLON;
+				lastWasColon = true;
+				break;
+			case json.SyntaxKind.CommaToken:
+				type = TOKEN_DELIM_COMMA;
+				lastWasColon = false;
+				break;
+			case json.SyntaxKind.TrueKeyword:
+			case json.SyntaxKind.FalseKeyword:
+				type = TOKEN_VALUE_BOOLEAN;
+				lastWasColon = false;
+				break;
+			case json.SyntaxKind.NullKeyword:
+				type = TOKEN_VALUE_NULL;
+				lastWasColon = false;
+				break;
+			case json.SyntaxKind.StringLiteral:
+				type = lastWasColon ? TOKEN_VALUE_STRING : TOKEN_PROPERTY_NAME;
+				lastWasColon = false;
+				break;
+			case json.SyntaxKind.NumericLiteral:
+				type = TOKEN_VALUE_NUMBER;
+				lastWasColon = false;
+				break;
+		}
+
+		// comments, iff enabled
+		if (comments) {
+			switch (kind) {
+				case json.SyntaxKind.LineCommentTrivia:
+					type = TOKEN_COMMENT_LINE;
+					break;
+				case json.SyntaxKind.BlockCommentTrivia:
+					type = TOKEN_COMMENT_BLOCK;
+					break;
+			}
+		}
+
+		ret.endState = new JSONState(
+			state.getStateData(),
+			scanner.getTokenError(),
+			lastWasColon
+		);
+		ret.tokens.push({
+			startIndex: offset,
+			scopes: type
+		});
+	}
+
+	return ret;
 }

+ 14 - 14
src/tsconfig.esm.json

@@ -1,16 +1,16 @@
 {
-  "compilerOptions": {
-    "declaration": true,
-    "module": "esnext",
-    "moduleResolution": "node",
-    "outDir": "../out/esm",
-    "target": "es5",
-    "lib": [
-      "dom",
-      "es5",
-      "es2015.collection",
-      "es2015.promise",
-      "es2015.iterable"
-    ]
-  }
+	"compilerOptions": {
+		"declaration": true,
+		"module": "esnext",
+		"moduleResolution": "node",
+		"outDir": "../out/esm",
+		"target": "es5",
+		"lib": [
+			"dom",
+			"es5",
+			"es2015.collection",
+			"es2015.promise",
+			"es2015.iterable"
+		]
+	}
 }

+ 14 - 14
src/tsconfig.json

@@ -1,16 +1,16 @@
 {
-  "compilerOptions": {
-    "module": "amd",
-    "moduleResolution": "node",
-    "outDir": "../out/amd",
-    "declaration": true,
-    "target": "es5",
-    "lib": [
-      "dom",
-      "es5",
-      "es2015.collection",
-      "es2015.promise",
-      "es2015.iterable"
-    ]
-  }
+	"compilerOptions": {
+		"module": "amd",
+		"moduleResolution": "node",
+		"outDir": "../out/amd",
+		"declaration": true,
+		"target": "es5",
+		"lib": [
+			"dom",
+			"es5",
+			"es2015.collection",
+			"es2015.promise",
+			"es2015.iterable"
+		]
+	}
 }

+ 91 - 87
src/workerManager.ts

@@ -1,87 +1,91 @@
-/*---------------------------------------------------------------------------------------------
- *  Copyright (c) Microsoft Corporation. All rights reserved.
- *  Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import { LanguageServiceDefaults } from './monaco.contribution';
-import type { JSONWorker } from './jsonWorker';
-import { IDisposable, Uri, editor } from './fillers/monaco-editor-core'
-
-const STOP_WHEN_IDLE_FOR = 2 * 60 * 1000; // 2min
-
-export class WorkerManager {
-
-	private _defaults: LanguageServiceDefaults;
-	private _idleCheckInterval: number;
-	private _lastUsedTime: number;
-	private _configChangeListener: IDisposable;
-
-	private _worker: editor.MonacoWebWorker<JSONWorker>;
-	private _client: Promise<JSONWorker>;
-
-	constructor(defaults: LanguageServiceDefaults) {
-		this._defaults = defaults;
-		this._worker = null;
-		this._idleCheckInterval = setInterval(() => this._checkIfIdle(), 30 * 1000);
-		this._lastUsedTime = 0;
-		this._configChangeListener = this._defaults.onDidChange(() => this._stopWorker());
-	}
-
-	private _stopWorker(): void {
-		if (this._worker) {
-			this._worker.dispose();
-			this._worker = null;
-		}
-		this._client = null;
-	}
-
-	dispose(): void {
-		clearInterval(this._idleCheckInterval);
-		this._configChangeListener.dispose();
-		this._stopWorker();
-	}
-
-	private _checkIfIdle(): void {
-		if (!this._worker) {
-			return;
-		}
-		let timePassedSinceLastUsed = Date.now() - this._lastUsedTime;
-		if (timePassedSinceLastUsed > STOP_WHEN_IDLE_FOR) {
-			this._stopWorker();
-		}
-	}
-
-	private _getClient(): Promise<JSONWorker> {
-		this._lastUsedTime = Date.now();
-
-		if (!this._client) {
-			this._worker = editor.createWebWorker<JSONWorker>({
-
-				// module that exports the create() method and returns a `JSONWorker` instance
-				moduleId: 'vs/language/json/jsonWorker',
-
-				label: this._defaults.languageId,
-
-				// passed in to the create() method
-				createData: {
-					languageSettings: this._defaults.diagnosticsOptions,
-					languageId: this._defaults.languageId,
-					enableSchemaRequest: this._defaults.diagnosticsOptions.enableSchemaRequest
-				}
-			});
-
-			this._client = <Promise<JSONWorker>><any>this._worker.getProxy();
-		}
-
-		return this._client;
-	}
-
-	getLanguageServiceWorker(...resources: Uri[]): Promise<JSONWorker> {
-		let _client: JSONWorker;
-		return this._getClient().then((client) => {
-			_client = client
-		}).then(_ => {
-			return this._worker.withSyncedResources(resources)
-		}).then(_ => _client);
-	}
-}
+/*---------------------------------------------------------------------------------------------
+ *  Copyright (c) Microsoft Corporation. All rights reserved.
+ *  Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { LanguageServiceDefaults } from './monaco.contribution';
+import type { JSONWorker } from './jsonWorker';
+import { IDisposable, Uri, editor } from './fillers/monaco-editor-core';
+
+const STOP_WHEN_IDLE_FOR = 2 * 60 * 1000; // 2min
+
+export class WorkerManager {
+	private _defaults: LanguageServiceDefaults;
+	private _idleCheckInterval: number;
+	private _lastUsedTime: number;
+	private _configChangeListener: IDisposable;
+
+	private _worker: editor.MonacoWebWorker<JSONWorker>;
+	private _client: Promise<JSONWorker>;
+
+	constructor(defaults: LanguageServiceDefaults) {
+		this._defaults = defaults;
+		this._worker = null;
+		this._idleCheckInterval = setInterval(() => this._checkIfIdle(), 30 * 1000);
+		this._lastUsedTime = 0;
+		this._configChangeListener = this._defaults.onDidChange(() =>
+			this._stopWorker()
+		);
+	}
+
+	private _stopWorker(): void {
+		if (this._worker) {
+			this._worker.dispose();
+			this._worker = null;
+		}
+		this._client = null;
+	}
+
+	dispose(): void {
+		clearInterval(this._idleCheckInterval);
+		this._configChangeListener.dispose();
+		this._stopWorker();
+	}
+
+	private _checkIfIdle(): void {
+		if (!this._worker) {
+			return;
+		}
+		let timePassedSinceLastUsed = Date.now() - this._lastUsedTime;
+		if (timePassedSinceLastUsed > STOP_WHEN_IDLE_FOR) {
+			this._stopWorker();
+		}
+	}
+
+	private _getClient(): Promise<JSONWorker> {
+		this._lastUsedTime = Date.now();
+
+		if (!this._client) {
+			this._worker = editor.createWebWorker<JSONWorker>({
+				// module that exports the create() method and returns a `JSONWorker` instance
+				moduleId: 'vs/language/json/jsonWorker',
+
+				label: this._defaults.languageId,
+
+				// passed in to the create() method
+				createData: {
+					languageSettings: this._defaults.diagnosticsOptions,
+					languageId: this._defaults.languageId,
+					enableSchemaRequest: this._defaults.diagnosticsOptions
+						.enableSchemaRequest
+				}
+			});
+
+			this._client = <Promise<JSONWorker>>(<any>this._worker.getProxy());
+		}
+
+		return this._client;
+	}
+
+	getLanguageServiceWorker(...resources: Uri[]): Promise<JSONWorker> {
+		let _client: JSONWorker;
+		return this._getClient()
+			.then((client) => {
+				_client = client;
+			})
+			.then((_) => {
+				return this._worker.withSyncedResources(resources);
+			})
+			.then((_) => _client);
+	}
+}

+ 126 - 118
test/index.html

@@ -1,118 +1,126 @@
-<!DOCTYPE html>
-<html>
-<head>
-	<meta http-equiv="X-UA-Compatible" content="IE=edge" />
-	<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
-	<link rel="stylesheet" data-name="vs/editor/editor.main" href="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.css">
-</head>
-<body>
-
-<h2>Monaco Editor JSON test page</h2>
-<div id="container" style="width:800px;height:600px;border:1px solid grey"></div>
-
-<script>
-	// Loading basic-languages to get the json language definition
-	var paths = {
-		'vs/basic-languages': '../node_modules/monaco-languages/release/dev',
-		'vs/language/json': '../release/dev',
-		'vs': '../node_modules/monaco-editor-core/dev/vs'
-	};
-	if (document.location.protocol === 'http:') {
-		// Add support for running local http server
-		let testIndex = document.location.pathname.indexOf('/test/');
-		if (testIndex !== -1) {
-			let prefix = document.location.pathname.substr(0, testIndex);
-			paths['vs/language/json'] = prefix + '/release/dev';
-		}
-	}
-	var require = {
-		paths: paths
-	};
-</script>
-<script src="../node_modules/monaco-editor-core/dev/vs/loader.js"></script>
-<script src="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.nls.js"></script>
-<script src="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.js"></script>
-
-<script>
-	require([
-		'vs/basic-languages/monaco.contribution',
-		'vs/language/json/monaco.contribution'
-	], function() {
-		var editor = monaco.editor.create(document.getElementById('container'), {
-			value: [
-				'{',
-				'	"type": "team",',
-				'	"test": {',
-				'		"testPage": "tools/testing/run-tests.htm",',
-				'		"enabled": true',
-				'	},',
-				'	"search": {',
-				'		"excludeFolders": [',
-				'			".git",',
-				'			"node_modules",',
-				'			"tools/bin",',
-				'			"tools/counts",',
-				'			"tools/policheck",',
-				'			"tools/tfs_build_extensions",',
-				'			"tools/testing/jscoverage",',
-				'			"tools/testing/qunit",',
-				'			"tools/testing/chutzpah",',
-				'			"server.net"',
-				'		]',
-				'	},',
-				'	"languages": {',
-				'		"vs.languages.typescript": {',
-				'			"validationSettings": [{',
-				'				"scope":"/",',
-				'				"noImplicitAny":true,',
-				'				"noLib":false,',
-				'				"extraLibs":[],',
-				'				"semanticValidation":true,',
-				'				"syntaxValidation":true,',
-				'				"codeGenTarget":"ES5",',
-				'				"moduleGenTarget":"",',
-				'				"lint": {',
-				'					"emptyBlocksWithoutComment": "warning",',
-				'					"curlyBracketsMustNotBeOmitted": "warning",',
-				'					"comparisonOperatorsNotStrict": "warning",',
-				'					"missingSemicolon": "warning",',
-				'					"unknownTypeOfResults": "warning",',
-				'					"semicolonsInsteadOfBlocks": "warning",',
-				'					"functionsInsideLoops": "warning",',
-				'					"functionsWithoutReturnType": "warning",',
-				'					"tripleSlashReferenceAlike": "warning",',
-				'					"unusedImports": "warning",',
-				'					"unusedVariables": "warning",',
-				'					"unusedFunctions": "warning",',
-				'					"unusedMembers": "warning"',
-				'				}',
-				'			},',
-				'			{',
-				'				"scope":"/client",',
-				'				"baseUrl":"/client",',
-				'				"moduleGenTarget":"amd"',
-				'			},',
-				'			{',
-				'				"scope":"/server",',
-				'				"moduleGenTarget":"commonjs"',
-				'			},',
-				'			{',
-				'				"scope":"/build",',
-				'				"moduleGenTarget":"commonjs"',
-				'			},',
-				'			{',
-				'				"scope":"/node_modules/nake",',
-				'				"moduleGenTarget":"commonjs"',
-				'			}],',
-				'			"allowMultipleWorkers": true',
-				'		}',
-				'	}',
-				'}',
-			].join('\n'),
-			language: 'json'
-		});
-	});
-</script>
-
-</body>
-</html>
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
+		<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+		<link
+			rel="stylesheet"
+			data-name="vs/editor/editor.main"
+			href="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.css"
+		/>
+	</head>
+	<body>
+		<h2>Monaco Editor JSON test page</h2>
+		<div
+			id="container"
+			style="width: 800px; height: 600px; border: 1px solid grey"
+		></div>
+
+		<script>
+			// Loading basic-languages to get the json language definition
+			var paths = {
+				'vs/basic-languages': '../node_modules/monaco-languages/release/dev',
+				'vs/language/json': '../release/dev',
+				vs: '../node_modules/monaco-editor-core/dev/vs'
+			};
+			if (document.location.protocol === 'http:') {
+				// Add support for running local http server
+				let testIndex = document.location.pathname.indexOf('/test/');
+				if (testIndex !== -1) {
+					let prefix = document.location.pathname.substr(0, testIndex);
+					paths['vs/language/json'] = prefix + '/release/dev';
+				}
+			}
+			var require = {
+				paths: paths
+			};
+		</script>
+		<script src="../node_modules/monaco-editor-core/dev/vs/loader.js"></script>
+		<script src="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.nls.js"></script>
+		<script src="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.js"></script>
+
+		<script>
+			require([
+				'vs/basic-languages/monaco.contribution',
+				'vs/language/json/monaco.contribution'
+			], function () {
+				var editor = monaco.editor.create(
+					document.getElementById('container'),
+					{
+						value: [
+							'{',
+							'	"type": "team",',
+							'	"test": {',
+							'		"testPage": "tools/testing/run-tests.htm",',
+							'		"enabled": true',
+							'	},',
+							'	"search": {',
+							'		"excludeFolders": [',
+							'			".git",',
+							'			"node_modules",',
+							'			"tools/bin",',
+							'			"tools/counts",',
+							'			"tools/policheck",',
+							'			"tools/tfs_build_extensions",',
+							'			"tools/testing/jscoverage",',
+							'			"tools/testing/qunit",',
+							'			"tools/testing/chutzpah",',
+							'			"server.net"',
+							'		]',
+							'	},',
+							'	"languages": {',
+							'		"vs.languages.typescript": {',
+							'			"validationSettings": [{',
+							'				"scope":"/",',
+							'				"noImplicitAny":true,',
+							'				"noLib":false,',
+							'				"extraLibs":[],',
+							'				"semanticValidation":true,',
+							'				"syntaxValidation":true,',
+							'				"codeGenTarget":"ES5",',
+							'				"moduleGenTarget":"",',
+							'				"lint": {',
+							'					"emptyBlocksWithoutComment": "warning",',
+							'					"curlyBracketsMustNotBeOmitted": "warning",',
+							'					"comparisonOperatorsNotStrict": "warning",',
+							'					"missingSemicolon": "warning",',
+							'					"unknownTypeOfResults": "warning",',
+							'					"semicolonsInsteadOfBlocks": "warning",',
+							'					"functionsInsideLoops": "warning",',
+							'					"functionsWithoutReturnType": "warning",',
+							'					"tripleSlashReferenceAlike": "warning",',
+							'					"unusedImports": "warning",',
+							'					"unusedVariables": "warning",',
+							'					"unusedFunctions": "warning",',
+							'					"unusedMembers": "warning"',
+							'				}',
+							'			},',
+							'			{',
+							'				"scope":"/client",',
+							'				"baseUrl":"/client",',
+							'				"moduleGenTarget":"amd"',
+							'			},',
+							'			{',
+							'				"scope":"/server",',
+							'				"moduleGenTarget":"commonjs"',
+							'			},',
+							'			{',
+							'				"scope":"/build",',
+							'				"moduleGenTarget":"commonjs"',
+							'			},',
+							'			{',
+							'				"scope":"/node_modules/nake",',
+							'				"moduleGenTarget":"commonjs"',
+							'			}],',
+							'			"allowMultipleWorkers": true',
+							'		}',
+							'	}',
+							'}'
+						].join('\n'),
+						language: 'json'
+					}
+				);
+			});
+		</script>
+	</body>
+</html>