提交 1ddee875 编写于 作者: M Martin Aeschlimann

extract jsonLangaugeService

上级 573844e4
......@@ -10,7 +10,7 @@ import SchemaService = require('./jsonSchemaService');
import JsonSchema = require('./jsonSchema');
import {IJSONWorkerContribution} from './jsonContributions';
import {CompletionItem, CompletionItemKind, CompletionList, TextDocument, Position, Range, TextEdit, RemoteConsole} from 'vscode-languageserver';
import {CompletionItem, CompletionItemKind, CompletionList, TextDocument, Position, Range, TextEdit} from 'vscode-languageserver';
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
......@@ -26,12 +26,10 @@ export class JSONCompletion {
private schemaService: SchemaService.IJSONSchemaService;
private contributions: IJSONWorkerContribution[];
private console: RemoteConsole;
constructor(schemaService: SchemaService.IJSONSchemaService, console: RemoteConsole, contributions: IJSONWorkerContribution[] = []) {
constructor(schemaService: SchemaService.IJSONSchemaService, contributions: IJSONWorkerContribution[] = []) {
this.schemaService = schemaService;
this.contributions = contributions;
this.console = console;
}
public doResolve(item: CompletionItem) : Thenable<CompletionItem> {
......@@ -80,10 +78,10 @@ export class JSONCompletion {
result.isIncomplete = true;
},
error: (message: string) => {
this.console.error(message);
console.error(message);
},
log: (message: string) => {
this.console.log(message);
console.log(message);
}
};
......
......@@ -14,7 +14,7 @@ export class JSONDocumentSymbols {
constructor() {
}
public compute(document: TextDocument, doc: Parser.JSONDocument): Promise<SymbolInformation[]> {
public findDocumentSymbols(document: TextDocument, doc: Parser.JSONDocument): Promise<SymbolInformation[]> {
let root = doc.root;
if (!root) {
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {TextDocument, Position, CompletionItem, CompletionList, Hover, Range, SymbolInformation, Diagnostic,
TextEdit, FormattingOptions} from 'vscode-languageserver';
import {JSONCompletion} from './jsonCompletion';
import {JSONHover} from './jsonHover';
import {JSONValidation} from './jsonValidation';
import {IJSONSchema} from './jsonSchema';
import {JSONDocumentSymbols} from './jsonDocumentSymbols';
import {parse as parseJSON, JSONDocument} from './jsonParser';
import {schemaContributions} from './configuration';
import {XHROptions, XHRResponse} from 'request-light';
import {JSONSchemaService} from './jsonSchemaService';
import {IJSONWorkerContribution} from './jsonContributions';
import {format as formatJSON} from './jsonFormatter';
export interface LanguageService {
configure(schemaConfiguration: JSONSchemaConfiguration[]): void;
doValidation(document: TextDocument, jsonDocument: JSONDocument): Thenable<Diagnostic[]>;
parseJSONDocument(document: TextDocument): JSONDocument;
resetSchema(uri: string): boolean;
doResolve(item: CompletionItem): Thenable<CompletionItem>;
doComplete(document: TextDocument, position: Position, doc: JSONDocument): Thenable<CompletionList>;
findDocumentSymbols(document: TextDocument, doc: JSONDocument): Promise<SymbolInformation[]>;
doHover(document: TextDocument, position: Position, doc: JSONDocument): Thenable<Hover>;
format(document: TextDocument, range: Range, options: FormattingOptions): Thenable<TextEdit[]>;
}
export interface JSONSchemaConfiguration {
uri: string;
fileMatch?: string[];
schema?: IJSONSchema;
}
export interface TelemetryService {
log(key: string, data: any): void;
}
export interface WorkspaceContextService {
resolveRelativePath(relativePath: string, resource: string): string;
}
export interface RequestService {
(options: XHROptions): Thenable<XHRResponse>;
}
export function getLanguageService(contributions: IJSONWorkerContribution[], request: RequestService, workspaceContext: WorkspaceContextService, telemetry: TelemetryService): LanguageService {
let jsonSchemaService = new JSONSchemaService(request, workspaceContext, telemetry);
jsonSchemaService.setSchemaContributions(schemaContributions);
let jsonCompletion = new JSONCompletion(jsonSchemaService, contributions);
let jsonHover = new JSONHover(jsonSchemaService, contributions);
let jsonDocumentSymbols = new JSONDocumentSymbols();
let jsonValidation = new JSONValidation(jsonSchemaService);
return {
configure: (schemaConf: JSONSchemaConfiguration[]) => {
schemaConf.forEach(settings => {
jsonSchemaService.registerExternalSchema(settings.uri, settings.fileMatch, settings.schema);
});
},
resetSchema: (uri: string) => {
return jsonSchemaService.onResourceChange(uri);
},
doValidation: jsonValidation.doValidation.bind(jsonValidation),
parseJSONDocument: (document: TextDocument) => parseJSON(document.getText()),
doResolve: jsonCompletion.doResolve.bind(jsonCompletion),
doComplete: jsonCompletion.doComplete.bind(jsonCompletion),
findDocumentSymbols: jsonDocumentSymbols.findDocumentSymbols.bind(jsonDocumentSymbols),
doHover: jsonHover.doHover.bind(jsonHover),
format: (document, range, options) => Promise.resolve(formatJSON(document, range, options))
};
}
......@@ -6,11 +6,11 @@
import Json = require('jsonc-parser');
import {IJSONSchema, IJSONSchemaMap} from './jsonSchema';
import {XHROptions, XHRResponse, getErrorStatusDescription} from 'request-light';
import {XHRResponse, getErrorStatusDescription} from 'request-light';
import URI from './utils/uri';
import Strings = require('./utils/strings');
import Parser = require('./jsonParser');
import {RemoteConsole} from 'vscode-languageserver';
import {TelemetryService, RequestService, WorkspaceContextService} from './jsonLanguageService';
import * as nls from 'vscode-nls';
......@@ -201,18 +201,6 @@ export class ResolvedSchema {
}
}
export interface ITelemetryService {
log(key: string, data: any): void;
}
export interface IWorkspaceContextService {
resolveRelativePath(relativePath: string, resource: string): string;
}
export interface IRequestService {
(options: XHROptions): Thenable<XHRResponse>;
}
export class JSONSchemaService implements IJSONSchemaService {
private contributionSchemas: { [id: string]: SchemaHandle };
......@@ -222,12 +210,12 @@ export class JSONSchemaService implements IJSONSchemaService {
private filePatternAssociations: FilePatternAssociation[];
private filePatternAssociationById: { [id: string]: FilePatternAssociation };
private contextService: IWorkspaceContextService;
private contextService: WorkspaceContextService;
private callOnDispose: Function[];
private telemetryService: ITelemetryService;
private requestService: IRequestService;
private telemetryService: TelemetryService;
private requestService: RequestService;
constructor(requestService: IRequestService, contextService?: IWorkspaceContextService, telemetryService?: ITelemetryService, private console?: RemoteConsole) {
constructor(requestService: RequestService, contextService?: WorkspaceContextService, telemetryService?: TelemetryService) {
this.contextService = contextService;
this.requestService = requestService;
this.telemetryService = telemetryService;
......
......@@ -6,8 +6,7 @@
import {
IPCMessageReader, IPCMessageWriter, createConnection, IConnection,
TextDocuments, TextDocument, Diagnostic, DiagnosticSeverity,
InitializeParams, InitializeResult, NotificationType, RequestType
TextDocuments, TextDocument, InitializeParams, InitializeResult, NotificationType, RequestType
} from 'vscode-languageserver';
import {xhr, XHROptions, XHRResponse, configure as configureHttpRequests} from 'request-light';
......@@ -15,18 +14,15 @@ import path = require('path');
import fs = require('fs');
import URI from './utils/uri';
import Strings = require('./utils/strings');
import {JSONSchemaService, ISchemaAssociations} from './jsonSchemaService';
import {parse as parseJSON, ObjectASTNode, JSONDocument} from './jsonParser';
import {JSONCompletion} from './jsonCompletion';
import {JSONHover} from './jsonHover';
import {ISchemaAssociations} from './jsonSchemaService';
import {JSONDocument} from './jsonParser';
import {IJSONSchema} from './jsonSchema';
import {JSONDocumentSymbols} from './jsonDocumentSymbols';
import {format as formatJSON} from './jsonFormatter';
import {schemaContributions} from './configuration';
import {ProjectJSONContribution} from './jsoncontributions/projectJSONContribution';
import {GlobPatternContribution} from './jsoncontributions/globPatternContribution';
import {FileAssociationContribution} from './jsoncontributions/fileAssociationContribution';
import {JSONSchemaConfiguration, getLanguageService} from './jsonLanguageService';
import * as nls from 'vscode-nls';
nls.config(process.env['VSCODE_NLS_CONFIG']);
......@@ -42,6 +38,9 @@ namespace VSCodeContentRequest {
// stdin / stdout for message passing
let connection: IConnection = createConnection(new IPCMessageReader(process), new IPCMessageWriter(process));
console.log = connection.console.log.bind(connection.console);
console.error = connection.console.error.bind(connection.console);
// Create a simple text document manager. The text document manager
// supports full document sync only
let documents: TextDocuments = new TextDocuments();
......@@ -115,13 +114,7 @@ let contributions = [
new GlobPatternContribution(),
filesAssociationContribution
];
let jsonSchemaService = new JSONSchemaService(request, workspaceContext, telemetry, connection.console);
jsonSchemaService.setSchemaContributions(schemaContributions);
let jsonCompletion = new JSONCompletion(jsonSchemaService, connection.console, contributions);
let jsonHover = new JSONHover(jsonSchemaService, contributions);
let jsonDocumentSymbols = new JSONDocumentSymbols();
let languageService = getLanguageService(contributions, request, workspaceContext, telemetry);
// The content of a text document has changed. This event is emitted
// when the text document first opened or when its content has changed.
......@@ -134,7 +127,7 @@ interface Settings {
json: {
schemas: JSONSchemaSettings[];
};
http : {
http: {
proxy: string;
proxyStrictSSL: boolean;
};
......@@ -146,8 +139,8 @@ interface JSONSchemaSettings {
schema?: IJSONSchema;
}
let jsonConfigurationSettings : JSONSchemaSettings[] = void 0;
let schemaAssociations : ISchemaAssociations = void 0;
let jsonConfigurationSettings: JSONSchemaSettings[] = void 0;
let schemaAssociations: ISchemaAssociations = void 0;
// The settings have changed. Is send on server activation as well.
connection.onDidChangeConfiguration((change) => {
......@@ -165,13 +158,13 @@ connection.onNotification(SchemaAssociationNotification.type, (associations) =>
});
function updateConfiguration() {
jsonSchemaService.clearExternalSchemas();
let schemaConfigs: JSONSchemaConfiguration[] = [];
if (schemaAssociations) {
for (var pattern in schemaAssociations) {
let association = schemaAssociations[pattern];
if (Array.isArray(association)) {
association.forEach(url => {
jsonSchemaService.registerExternalSchema(url, [pattern]);
association.forEach(uri => {
schemaConfigs.push({ uri, fileMatch: [pattern] });
});
}
}
......@@ -179,23 +172,25 @@ function updateConfiguration() {
if (jsonConfigurationSettings) {
jsonConfigurationSettings.forEach((schema) => {
if (schema.fileMatch) {
let url = schema.url;
if (!url && schema.schema) {
url = schema.schema.id;
if (!url) {
url = 'vscode://schemas/custom/' + encodeURIComponent(schema.fileMatch.join('&'));
let uri = schema.url;
if (!uri && schema.schema) {
uri = schema.schema.id;
if (!uri) {
uri = 'vscode://schemas/custom/' + encodeURIComponent(schema.fileMatch.join('&'));
}
}
if (Strings.startsWith(url, '.') && workspaceRoot) {
if (Strings.startsWith(uri, '.') && workspaceRoot) {
// workspace relative path
url = URI.file(path.normalize(path.join(workspaceRoot.fsPath, url))).toString();
uri = URI.file(path.normalize(path.join(workspaceRoot.fsPath, uri))).toString();
}
if (url) {
jsonSchemaService.registerExternalSchema(url, schema.fileMatch, schema.schema);
if (uri) {
schemaConfigs.push({ uri, fileMatch: schema.fileMatch, schema: schema.schema });
}
}
});
}
languageService.configure(schemaConfigs);
// Revalidate any open text documents
documents.all().forEach(validateTextDocument);
}
......@@ -209,40 +204,7 @@ function validateTextDocument(textDocument: TextDocument): void {
}
let jsonDocument = getJSONDocument(textDocument);
jsonSchemaService.getSchemaForResource(textDocument.uri, jsonDocument).then(schema => {
if (schema) {
if (schema.errors.length && jsonDocument.root) {
let astRoot = jsonDocument.root;
let property = astRoot.type === 'object' ? (<ObjectASTNode>astRoot).getFirstProperty('$schema') : null;
if (property) {
let node = property.value || property;
jsonDocument.warnings.push({ location: { start: node.start, end: node.end }, message: schema.errors[0] });
} else {
jsonDocument.warnings.push({ location: { start: astRoot.start, end: astRoot.start + 1 }, message: schema.errors[0] });
}
} else {
jsonDocument.validate(schema.schema);
}
}
let diagnostics: Diagnostic[] = [];
let added: { [signature: string]: boolean } = {};
jsonDocument.errors.concat(jsonDocument.warnings).forEach((error, idx) => {
// remove duplicated messages
let signature = error.location.start + ' ' + error.location.end + ' ' + error.message;
if (!added[signature]) {
added[signature] = true;
let range = {
start: textDocument.positionAt(error.location.start),
end: textDocument.positionAt(error.location.end)
};
diagnostics.push({
severity: idx >= jsonDocument.errors.length ? DiagnosticSeverity.Warning : DiagnosticSeverity.Error,
range: range,
message: error.message
});
}
});
languageService.doValidation(textDocument, jsonDocument).then(diagnostics => {
// Send the computed diagnostics to VSCode.
connection.sendDiagnostics({ uri: textDocument.uri, diagnostics });
});
......@@ -252,7 +214,7 @@ connection.onDidChangeWatchedFiles((change) => {
// Monitored files have changed in VSCode
let hasChanges = false;
change.changes.forEach(c => {
if (jsonSchemaService.onResourceChange(c.uri)) {
if (languageService.resetSchema(c.uri)) {
hasChanges = true;
}
});
......@@ -262,39 +224,39 @@ connection.onDidChangeWatchedFiles((change) => {
});
function getJSONDocument(document: TextDocument): JSONDocument {
return parseJSON(document.getText());
return languageService.parseJSONDocument(document);
}
connection.onCompletion(textDocumentPosition => {
let document = documents.get(textDocumentPosition.textDocument.uri);
let jsonDocument = getJSONDocument(document);
return jsonCompletion.doComplete(document, textDocumentPosition.position, jsonDocument);
return languageService.doComplete(document, textDocumentPosition.position, jsonDocument);
});
connection.onCompletionResolve(completionItem => {
return jsonCompletion.doResolve(completionItem);
return languageService.doResolve(completionItem);
});
connection.onHover(textDocumentPositionParams => {
let document = documents.get(textDocumentPositionParams.textDocument.uri);
let jsonDocument = getJSONDocument(document);
return jsonHover.doHover(document, textDocumentPositionParams.position, jsonDocument);
return languageService.doHover(document, textDocumentPositionParams.position, jsonDocument);
});
connection.onDocumentSymbol(documentSymbolParams => {
let document = documents.get(documentSymbolParams.textDocument.uri);
let jsonDocument = getJSONDocument(document);
return jsonDocumentSymbols.compute(document, jsonDocument);
return languageService.findDocumentSymbols(document, jsonDocument);
});
connection.onDocumentFormatting(formatParams => {
let document = documents.get(formatParams.textDocument.uri);
return formatJSON(document, null, formatParams.options);
return languageService.format(document, null, formatParams.options);
});
connection.onDocumentRangeFormatting(formatParams => {
let document = documents.get(formatParams.textDocument.uri);
return formatJSON(document, formatParams.range, formatParams.options);
return languageService.format(document, formatParams.range, formatParams.options);
});
// Listen on the connection
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {JSONSchemaService} from './jsonSchemaService';
import {JSONDocument, ObjectASTNode} from './jsonParser';
import {TextDocument, Diagnostic, DiagnosticSeverity} from 'vscode-languageserver';
export class JSONValidation {
private jsonSchemaService: JSONSchemaService;
public constructor(jsonSchemaService: JSONSchemaService) {
this.jsonSchemaService = jsonSchemaService;
}
public doValidation(textDocument: TextDocument, jsonDocument: JSONDocument) {
return this.jsonSchemaService.getSchemaForResource(textDocument.uri, jsonDocument).then(schema => {
if (schema) {
if (schema.errors.length && jsonDocument.root) {
let astRoot = jsonDocument.root;
let property = astRoot.type === 'object' ? (<ObjectASTNode>astRoot).getFirstProperty('$schema') : null;
if (property) {
let node = property.value || property;
jsonDocument.warnings.push({ location: { start: node.start, end: node.end }, message: schema.errors[0] });
} else {
jsonDocument.warnings.push({ location: { start: astRoot.start, end: astRoot.start + 1 }, message: schema.errors[0] });
}
} else {
jsonDocument.validate(schema.schema);
}
}
let diagnostics: Diagnostic[] = [];
let added: { [signature: string]: boolean } = {};
jsonDocument.errors.concat(jsonDocument.warnings).forEach((error, idx) => {
// remove duplicated messages
let signature = error.location.start + ' ' + error.location.end + ' ' + error.message;
if (!added[signature]) {
added[signature] = true;
let range = {
start: textDocument.positionAt(error.location.start),
end: textDocument.positionAt(error.location.end)
};
diagnostics.push({
severity: idx >= jsonDocument.errors.length ? DiagnosticSeverity.Warning : DiagnosticSeverity.Error,
range: range,
message: error.message
});
}
});
return diagnostics;
});
}
}
\ No newline at end of file
......@@ -8,7 +8,7 @@ import {MarkedString, CompletionItemKind, CompletionItem} from 'vscode-languages
import Strings = require('../utils/strings');
import {XHRResponse, getErrorStatusDescription} from 'request-light';
import {IJSONWorkerContribution, ISuggestionsCollector} from '../jsonContributions';
import {IRequestService} from '../jsonSchemaService';
import {RequestService} from '../jsonLanguageService';
import {JSONLocation} from '../jsonLocation';
import * as nls from 'vscode-nls';
......@@ -30,12 +30,12 @@ interface NugetServices {
export class ProjectJSONContribution implements IJSONWorkerContribution {
private requestService : IRequestService;
private requestService : RequestService;
private cachedProjects: { [id: string]: { version: string, description: string, time: number }} = {};
private cacheSize: number = 0;
private nugetIndexPromise: Thenable<NugetServices>;
public constructor(requestService: IRequestService) {
public constructor(requestService: RequestService) {
this.requestService = requestService;
}
......
......@@ -36,7 +36,7 @@ suite('JSON Completion', () => {
let idx = stringAfter ? value.indexOf(stringAfter) : 0;
let schemaService = new SchemaService.JSONSchemaService(requestService);
let completionProvider = new JSONCompletion(schemaService, console);
let completionProvider = new JSONCompletion(schemaService);
if (schema) {
let id = "http://myschemastore/test1";
schemaService.registerExternalSchema(id, ["*.json"], schema);
......
......@@ -22,7 +22,7 @@ suite('JSON Document Symbols', () => {
var document = TextDocument.create(uri, 'json', 0, value);
var jsonDoc = Parser.parse(value);
return symbolProvider.compute(document, jsonDoc);
return symbolProvider.findDocumentSymbols(document, jsonDoc);
}
var assertOutline: any = function(actual: SymbolInformation[], expected: any[], message: string) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册