This commit is contained in:
Martin Aeschlimann 2021-11-17 15:55:46 +01:00
Родитель 338d55069a
Коммит e87ed1afb4
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 2609A01E695523E3
6 изменённых файлов: 105 добавлений и 34 удалений

Просмотреть файл

@ -1,4 +1,9 @@
4.2.0 /
================
* new API `LanguageService.getLanguageStatus`
4.1.6 / 2021-07-16 4.1.6 / 2021-07-16
================ ================
* Replace minimatch with glob-to-regexp * Replace minimatch with glob-to-regexp

Просмотреть файл

@ -23,7 +23,7 @@ import {
FoldingRange, JSONSchema, SelectionRange, FoldingRangesContext, DocumentSymbolsContext, ColorInformationContext as DocumentColorsContext, FoldingRange, JSONSchema, SelectionRange, FoldingRangesContext, DocumentSymbolsContext, ColorInformationContext as DocumentColorsContext,
TextDocument, TextDocument,
Position, CompletionItem, CompletionList, Hover, Range, SymbolInformation, Diagnostic, Position, CompletionItem, CompletionList, Hover, Range, SymbolInformation, Diagnostic,
TextEdit, FormattingOptions, DocumentSymbol, DefinitionLink, MatchingSchema TextEdit, FormattingOptions, DocumentSymbol, DefinitionLink, MatchingSchema, JSONLanguageStatus
} from './jsonLanguageTypes'; } from './jsonLanguageTypes';
import { findLinks } from './services/jsonLinks'; import { findLinks } from './services/jsonLinks';
import { DocumentLink } from 'vscode-languageserver-types'; import { DocumentLink } from 'vscode-languageserver-types';
@ -41,6 +41,7 @@ export interface LanguageService {
newJSONDocument(rootNode: ASTNode, syntaxDiagnostics?: Diagnostic[]): JSONDocument; newJSONDocument(rootNode: ASTNode, syntaxDiagnostics?: Diagnostic[]): JSONDocument;
resetSchema(uri: string): boolean; resetSchema(uri: string): boolean;
getMatchingSchemas(document: TextDocument, jsonDocument: JSONDocument, schema?: JSONSchema): Thenable<MatchingSchema[]>; getMatchingSchemas(document: TextDocument, jsonDocument: JSONDocument, schema?: JSONSchema): Thenable<MatchingSchema[]>;
getLanguageStatus(document: TextDocument, jsonDocument: JSONDocument): JSONLanguageStatus;
doResolve(item: CompletionItem): Thenable<CompletionItem>; doResolve(item: CompletionItem): Thenable<CompletionItem>;
doComplete(document: TextDocument, position: Position, doc: JSONDocument): Thenable<CompletionList | null>; doComplete(document: TextDocument, position: Position, doc: JSONDocument): Thenable<CompletionList | null>;
findDocumentSymbols(document: TextDocument, doc: JSONDocument, context?: DocumentSymbolsContext): SymbolInformation[]; findDocumentSymbols(document: TextDocument, doc: JSONDocument, context?: DocumentSymbolsContext): SymbolInformation[];
@ -79,6 +80,7 @@ export function getLanguageService(params: LanguageServiceParams): LanguageServi
}, },
resetSchema: (uri: string) => jsonSchemaService.onResourceChange(uri), resetSchema: (uri: string) => jsonSchemaService.onResourceChange(uri),
doValidation: jsonValidation.doValidation.bind(jsonValidation), doValidation: jsonValidation.doValidation.bind(jsonValidation),
getLanguageStatus: jsonValidation.getLanguageStatus.bind(jsonValidation),
parseJSONDocument: (document: TextDocument) => parseJSON(document, { collectComments: true }), parseJSONDocument: (document: TextDocument) => parseJSON(document, { collectComments: true }),
newJSONDocument: (root: ASTNode, diagnostics: Diagnostic[]) => newJSONDocument(root, diagnostics), newJSONDocument: (root: ASTNode, diagnostics: Diagnostic[]) => newJSONDocument(root, diagnostics),
getMatchingSchemas: jsonSchemaService.getMatchingSchemas.bind(jsonSchemaService), getMatchingSchemas: jsonSchemaService.getMatchingSchemas.bind(jsonSchemaService),

Просмотреть файл

@ -15,7 +15,7 @@ import {
SymbolInformation, SymbolKind, DocumentSymbol, Location, Hover, MarkedString, FormattingOptions as LSPFormattingOptions, DefinitionLink, SymbolInformation, SymbolKind, DocumentSymbol, Location, Hover, MarkedString, FormattingOptions as LSPFormattingOptions, DefinitionLink,
CodeActionContext, Command, CodeAction, CodeActionContext, Command, CodeAction,
DocumentHighlight, DocumentLink, WorkspaceEdit, DocumentHighlight, DocumentLink, WorkspaceEdit,
TextEdit, CodeActionKind, TextEdit, CodeActionKind,
TextDocumentEdit, VersionedTextDocumentIdentifier, DocumentHighlightKind TextDocumentEdit, VersionedTextDocumentIdentifier, DocumentHighlightKind
} from 'vscode-languageserver-types'; } from 'vscode-languageserver-types';
@ -33,7 +33,7 @@ export {
SymbolInformation, SymbolKind, DocumentSymbol, Location, Hover, MarkedString, SymbolInformation, SymbolKind, DocumentSymbol, Location, Hover, MarkedString,
CodeActionContext, Command, CodeAction, CodeActionContext, Command, CodeAction,
DocumentHighlight, DocumentLink, WorkspaceEdit, DocumentHighlight, DocumentLink, WorkspaceEdit,
TextEdit, CodeActionKind, TextEdit, CodeActionKind,
TextDocumentEdit, VersionedTextDocumentIdentifier, DocumentHighlightKind TextDocumentEdit, VersionedTextDocumentIdentifier, DocumentHighlightKind
}; };
@ -112,6 +112,10 @@ export interface MatchingSchema {
schema: JSONSchema; schema: JSONSchema;
} }
export interface JSONLanguageStatus {
schemas: string[];
}
export interface LanguageSettings { export interface LanguageSettings {
/** /**
* If set, the validator will return syntax and semantic errors. * If set, the validator will return syntax and semantic errors.
@ -158,12 +162,12 @@ export interface SchemaConfiguration {
* The URI of the schema, which is also the identifier of the schema. * The URI of the schema, which is also the identifier of the schema.
*/ */
uri: string; uri: string;
/** /**
* A list of glob patterns that describe for which file URIs the JSON schema will be used. * A list of glob patterns that describe for which file URIs the JSON schema will be used.
* '*' and '**' wildcards are supported. Exclusion patterns start with '!'. * '*' and '**' wildcards are supported. Exclusion patterns start with '!'.
* For example '*.schema.json', 'package.json', '!foo*.schema.json', 'foo/**\/BADRESP.json'. * For example '*.schema.json', 'package.json', '!foo*.schema.json', 'foo/**\/BADRESP.json'.
* A match succeeds when there is at least one pattern matching and last matching pattern does not start with '!'. * A match succeeds when there is at least one pattern matching and last matching pattern does not start with '!'.
*/ */
fileMatch?: string[]; fileMatch?: string[];
/** /**
* The schema for the given URI. * The schema for the given URI.

Просмотреть файл

@ -11,7 +11,7 @@ import * as Parser from '../parser/jsonParser';
import { SchemaRequestService, WorkspaceContextService, PromiseConstructor, Thenable, MatchingSchema, TextDocument } from '../jsonLanguageTypes'; import { SchemaRequestService, WorkspaceContextService, PromiseConstructor, Thenable, MatchingSchema, TextDocument } from '../jsonLanguageTypes';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
import { createRegex} from '../utils/glob'; import { createRegex } from '../utils/glob';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
@ -159,7 +159,7 @@ class SchemaHandle implements ISchemaHandle {
return this.resolvedSchema; return this.resolvedSchema;
} }
public clearSchema() : boolean { public clearSchema(): boolean {
const hasChanges = !!this.unresolvedSchema; const hasChanges = !!this.unresolvedSchema;
this.resolvedSchema = undefined; this.resolvedSchema = undefined;
this.unresolvedSchema = undefined; this.unresolvedSchema = undefined;
@ -545,31 +545,18 @@ export class JSONSchemaService implements IJSONSchemaService {
return resolveRefs(schema, schema, schemaURL, dependencies).then(_ => new ResolvedSchema(schema, resolveErrors)); return resolveRefs(schema, schema, schemaURL, dependencies).then(_ => new ResolvedSchema(schema, resolveErrors));
} }
private getSchemaProperty(document: Parser.JSONDocument): string | undefined {
public getSchemaForResource(resource: string, document?: Parser.JSONDocument): Thenable<ResolvedSchema | undefined> { if (document.root?.type === 'object') {
for (const p of document.root.properties) {
// first use $schema if present if (p.keyNode.value === '$schema' && p.valueNode?.type === 'string') {
if (document && document.root && document.root.type === 'object') { return p.valueNode.value;
const schemaProperties = document.root.properties.filter(p => (p.keyNode.value === '$schema') && p.valueNode && p.valueNode.type === 'string');
if (schemaProperties.length > 0) {
const valueNode = schemaProperties[0].valueNode;
if (valueNode && valueNode.type === 'string') {
let schemeId = <string>Parser.getNodeValue(valueNode);
if (schemeId && Strings.startsWith(schemeId, '.') && this.contextService) {
schemeId = this.contextService.resolveRelativePath(schemeId, resource);
}
if (schemeId) {
const id = normalizeId(schemeId);
return this.getOrAddSchemaHandle(id).getResolvedSchema();
}
} }
} }
} }
return undefined;
}
if (this.cachedSchemaForResource && this.cachedSchemaForResource.resource === resource) { private getAssociatedSchemas(resource: string): string[] {
return this.cachedSchemaForResource.resolvedSchema;
}
const seen: { [schemaId: string]: boolean } = Object.create(null); const seen: { [schemaId: string]: boolean } = Object.create(null);
const schemas: string[] = []; const schemas: string[] = [];
const normalizedResource = normalizeResourceForMatching(resource); const normalizedResource = normalizeResourceForMatching(resource);
@ -583,6 +570,33 @@ export class JSONSchemaService implements IJSONSchemaService {
} }
} }
} }
return schemas;
}
public getSchemaURIsForResource(resource: string, document?: Parser.JSONDocument): string[] {
let schemeId = document && this.getSchemaProperty(document);
if (schemeId) {
return [schemeId];
}
return this.getAssociatedSchemas(resource);
}
public getSchemaForResource(resource: string, document?: Parser.JSONDocument): Thenable<ResolvedSchema | undefined> {
if (document) {
// first use $schema if present
let schemeId = this.getSchemaProperty(document);
if (schemeId && Strings.startsWith(schemeId, '.') && this.contextService) {
schemeId = this.contextService.resolveRelativePath(schemeId, resource);
}
if (schemeId) {
const id = normalizeId(schemeId);
return this.getOrAddSchemaHandle(id).getResolvedSchema();
}
}
if (this.cachedSchemaForResource && this.cachedSchemaForResource.resource === resource) {
return this.cachedSchemaForResource.resolvedSchema;
}
const schemas = this.getAssociatedSchemas(resource);
const resolvedSchema = schemas.length > 0 ? this.createCombinedSchema(resource, schemas).getResolvedSchema() : this.promise.resolve(undefined); const resolvedSchema = schemas.length > 0 ? this.createCombinedSchema(resource, schemas).getResolvedSchema() : this.promise.resolve(undefined);
this.cachedSchemaForResource = { resource, resolvedSchema }; this.cachedSchemaForResource = { resource, resolvedSchema };
return resolvedSchema; return resolvedSchema;

Просмотреть файл

@ -6,7 +6,7 @@
import { JSONSchemaService, ResolvedSchema, UnresolvedSchema } from './jsonSchemaService'; import { JSONSchemaService, ResolvedSchema, UnresolvedSchema } from './jsonSchemaService';
import { JSONDocument } from '../parser/jsonParser'; import { JSONDocument } from '../parser/jsonParser';
import { TextDocument, ErrorCode, PromiseConstructor, Thenable, LanguageSettings, DocumentLanguageSettings, SeverityLevel, Diagnostic, DiagnosticSeverity, Range } from '../jsonLanguageTypes'; import { TextDocument, ErrorCode, PromiseConstructor, Thenable, LanguageSettings, DocumentLanguageSettings, SeverityLevel, Diagnostic, DiagnosticSeverity, Range, JSONLanguageStatus } from '../jsonLanguageTypes';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
import { JSONSchemaRef, JSONSchema } from '../jsonSchema'; import { JSONSchemaRef, JSONSchema } from '../jsonSchema';
import { isBoolean } from '../utils/objects'; import { isBoolean } from '../utils/objects';
@ -111,6 +111,10 @@ export class JSONValidation {
return getDiagnostics(schema); return getDiagnostics(schema);
}); });
} }
public getLanguageStatus(textDocument: TextDocument, jsonDocument: JSONDocument): JSONLanguageStatus {
return { schemas: this.jsonSchemaService.getSchemaURIsForResource(textDocument.uri, jsonDocument) };
}
} }
let idCounter = 0; let idCounter = 0;

Просмотреть файл

@ -10,7 +10,7 @@ import * as fs from 'fs';
import * as url from 'url'; import * as url from 'url';
import * as path from 'path'; import * as path from 'path';
import { getLanguageService, JSONSchema, SchemaRequestService, TextDocument, MatchingSchema } from '../jsonLanguageService'; import { getLanguageService, JSONSchema, SchemaRequestService, TextDocument, MatchingSchema } from '../jsonLanguageService';
import { DiagnosticSeverity } from '../jsonLanguageTypes'; import { DiagnosticSeverity, SchemaConfiguration } from '../jsonLanguageTypes';
function toDocument(text: string, config?: Parser.JSONDocumentConfig, uri = 'foo://bar/file.json'): { textDoc: TextDocument, jsonDoc: Parser.JSONDocument } { function toDocument(text: string, config?: Parser.JSONDocumentConfig, uri = 'foo://bar/file.json'): { textDoc: TextDocument, jsonDoc: Parser.JSONDocument } {
@ -1459,5 +1459,47 @@ suite('JSON Schema', () => {
} }
}); });
test('getLanguageStatus', async function () {
const schemas: SchemaConfiguration[] = [{
uri: 'https://myschemastore/schema1.json',
fileMatch: ['**/*.json'],
schema: {
type: 'object',
}
},
{
uri: 'https://myschemastore/schema2.json',
fileMatch: ['**/bar.json'],
schema: {
type: 'object',
}
},
{
uri: 'https://myschemastore/schema3.json',
schema: {
type: 'object',
}
}
];
const ls = getLanguageService({ workspaceContext });
ls.configure({ schemas });
{
const { textDoc, jsonDoc } = toDocument('{ }', undefined, 'foo://bar/folder/foo.json');
const info = ls.getLanguageStatus(textDoc, jsonDoc);
assert.deepStrictEqual(info.schemas, ['https://myschemastore/schema1.json']);
}
{
const { textDoc, jsonDoc } = toDocument('{ }', undefined, 'foo://bar/folder/bar.json');
const info = ls.getLanguageStatus(textDoc, jsonDoc);
assert.deepStrictEqual(info.schemas, ['https://myschemastore/schema1.json', 'https://myschemastore/schema2.json']);
}
{
const { textDoc, jsonDoc } = toDocument('{ $schema: "https://myschemastore/schema3.json" }', undefined, 'foo://bar/folder/bar.json');
const info = ls.getLanguageStatus(textDoc, jsonDoc);
assert.deepStrictEqual(info.schemas, ['https://myschemastore/schema3.json']);
}
});
}); });