Browse Source

Merge pull request #4299 from mevisioam/json-worker-access

Expose JSON worker
Martin Aeschlimann 1 year ago
parent
commit
698e0ecafd

+ 13 - 3
src/language/json/jsonMode.ts

@@ -10,6 +10,18 @@ import * as languageFeatures from '../common/lspLanguageFeatures';
 import { createTokenizationSupport } from './tokenization';
 import { Uri, IDisposable, languages, editor } from '../../fillers/monaco-editor-core';
 
+let worker: languageFeatures.WorkerAccessor<JSONWorker>;
+
+export function getWorker(): Promise<(...uris: Uri[]) => Promise<JSONWorker>> {
+	return new Promise((resolve, reject) => {
+		if (!worker) {
+			return reject('JSON not registered!');
+		}
+
+		resolve(worker);
+	});
+}
+
 class JSONDiagnosticsAdapter extends languageFeatures.DiagnosticsAdapter<JSONWorker> {
 	constructor(
 		languageId: string,
@@ -44,9 +56,7 @@ export function setupMode(defaults: LanguageServiceDefaults): IDisposable {
 	const client = new WorkerManager(defaults);
 	disposables.push(client);
 
-	const worker: languageFeatures.WorkerAccessor<JSONWorker> = (
-		...uris: Uri[]
-	): Promise<JSONWorker> => {
+	worker = (...uris: Uri[]): Promise<JSONWorker> => {
 		return client.getLanguageServiceWorker(...uris);
 	};
 

+ 16 - 0
src/language/json/jsonWorker.ts

@@ -144,6 +144,22 @@ export class JSONWorker {
 		let ranges = this._languageService.getSelectionRanges(document, positions, jsonDocument);
 		return Promise.resolve(ranges);
 	}
+	async parseJSONDocument(uri: string): Promise<jsonService.JSONDocument | null> {
+		let document = this._getTextDocument(uri);
+		if (!document) {
+			return null;
+		}
+		let jsonDocument = this._languageService.parseJSONDocument(document);
+		return Promise.resolve(jsonDocument);
+	}
+	async getMatchingSchemas(uri: string): Promise<jsonService.MatchingSchema[]> {
+		let document = this._getTextDocument(uri);
+		if (!document) {
+			return [];
+		}
+		let jsonDocument = this._languageService.parseJSONDocument(document);
+		return Promise.resolve(this._languageService.getMatchingSchemas(document, jsonDocument));
+	}
 	private _getTextDocument(uri: string): jsonService.TextDocument | null {
 		let models = this._ctx.getMirrorModels();
 		for (let model of models) {

+ 148 - 3
src/language/json/monaco.contribution.ts

@@ -4,10 +4,147 @@
  *--------------------------------------------------------------------------------------------*/
 
 import * as mode from './jsonMode';
-import { Emitter, IEvent, languages } from '../../fillers/monaco-editor-core';
+import { Emitter, IEvent, languages, Uri } from 'monaco-editor-core';
+
+// ---- JSON service types ----
+export interface BaseASTNode {
+	readonly type: 'object' | 'array' | 'property' | 'string' | 'number' | 'boolean' | 'null';
+	readonly parent?: ASTNode;
+	readonly offset: number;
+	readonly length: number;
+	readonly children?: ASTNode[];
+	readonly value?: string | boolean | number | null;
+}
+export interface ObjectASTNode extends BaseASTNode {
+	readonly type: 'object';
+	readonly properties: PropertyASTNode[];
+	readonly children: ASTNode[];
+}
+export interface PropertyASTNode extends BaseASTNode {
+	readonly type: 'property';
+	readonly keyNode: StringASTNode;
+	readonly valueNode?: ASTNode;
+	readonly colonOffset?: number;
+	readonly children: ASTNode[];
+}
+export interface ArrayASTNode extends BaseASTNode {
+	readonly type: 'array';
+	readonly items: ASTNode[];
+	readonly children: ASTNode[];
+}
+export interface StringASTNode extends BaseASTNode {
+	readonly type: 'string';
+	readonly value: string;
+}
+export interface NumberASTNode extends BaseASTNode {
+	readonly type: 'number';
+	readonly value: number;
+	readonly isInteger: boolean;
+}
+export interface BooleanASTNode extends BaseASTNode {
+	readonly type: 'boolean';
+	readonly value: boolean;
+}
+export interface NullASTNode extends BaseASTNode {
+	readonly type: 'null';
+	readonly value: null;
+}
 
-// --- JSON configuration and defaults ---------
+export type ASTNode =
+	| ObjectASTNode
+	| PropertyASTNode
+	| ArrayASTNode
+	| StringASTNode
+	| NumberASTNode
+	| BooleanASTNode
+	| NullASTNode;
+
+export type JSONDocument = {
+	root: ASTNode | undefined;
+	getNodeFromOffset(offset: number, includeRightBound?: boolean): ASTNode | undefined;
+};
+
+export type JSONSchemaRef = JSONSchema | boolean;
 
+export interface JSONSchemaMap {
+	[name: string]: JSONSchemaRef;
+}
+
+export interface JSONSchema {
+	id?: string;
+	$id?: string;
+	$schema?: string;
+	type?: string | string[];
+	title?: string;
+	default?: any;
+	definitions?: {
+		[name: string]: JSONSchema;
+	};
+	description?: string;
+	properties?: JSONSchemaMap;
+	patternProperties?: JSONSchemaMap;
+	additionalProperties?: boolean | JSONSchemaRef;
+	minProperties?: number;
+	maxProperties?: number;
+	dependencies?:
+		| JSONSchemaMap
+		| {
+				[prop: string]: string[];
+		  };
+	items?: JSONSchemaRef | JSONSchemaRef[];
+	minItems?: number;
+	maxItems?: number;
+	uniqueItems?: boolean;
+	additionalItems?: boolean | JSONSchemaRef;
+	pattern?: string;
+	minLength?: number;
+	maxLength?: number;
+	minimum?: number;
+	maximum?: number;
+	exclusiveMinimum?: boolean | number;
+	exclusiveMaximum?: boolean | number;
+	multipleOf?: number;
+	required?: string[];
+	$ref?: string;
+	anyOf?: JSONSchemaRef[];
+	allOf?: JSONSchemaRef[];
+	oneOf?: JSONSchemaRef[];
+	not?: JSONSchemaRef;
+	enum?: any[];
+	format?: string;
+	const?: any;
+	contains?: JSONSchemaRef;
+	propertyNames?: JSONSchemaRef;
+	examples?: any[];
+	$comment?: string;
+	if?: JSONSchemaRef;
+	then?: JSONSchemaRef;
+	else?: JSONSchemaRef;
+	defaultSnippets?: {
+		label?: string;
+		description?: string;
+		markdownDescription?: string;
+		body?: any;
+		bodyText?: string;
+	}[];
+	errorMessage?: string;
+	patternErrorMessage?: string;
+	deprecationMessage?: string;
+	enumDescriptions?: string[];
+	markdownEnumDescriptions?: string[];
+	markdownDescription?: string;
+	doNotSuggest?: boolean;
+	suggestSortText?: string;
+	allowComments?: boolean;
+	allowTrailingCommas?: boolean;
+}
+
+export interface MatchingSchema {
+	node: ASTNode;
+	schema: JSONSchema;
+}
+
+// --- JSON configuration and defaults ---------
 export interface DiagnosticsOptions {
 	/**
 	 * If set, the validator will be enabled and perform syntax and schema based validation,
@@ -197,8 +334,16 @@ export const jsonDefaults: LanguageServiceDefaults = new LanguageServiceDefaults
 	modeConfigurationDefault
 );
 
+export interface IJSONWorker {
+	parseJSONDocument(uri: string): Promise<JSONDocument | null>;
+	getMatchingSchemas(uri: string): Promise<MatchingSchema[]>;
+}
+
+export const getWorker = (): Promise<(...uris: Uri[]) => Promise<IJSONWorker>> =>
+	getMode().then((mode) => mode.getWorker());
+
 // export to the global based API
-(<any>languages).json = { jsonDefaults };
+(<any>languages).json = { jsonDefaults, getWorker };
 
 // --- Registration to monaco editor ---