diff --git a/src/parser/jsonParser.ts b/src/parser/jsonParser.ts index 338156fe..33e3b80d 100644 --- a/src/parser/jsonParser.ts +++ b/src/parser/jsonParser.ts @@ -8,6 +8,7 @@ import { JSONSchema, JSONSchemaRef } from '../jsonSchema'; import { isNumber, equals, isBoolean, isString, isDefined, isObject } from '../utils/objects'; import { extendedRegExp, stringLength } from '../utils/strings'; import { TextDocument, ASTNode, ObjectASTNode, ArrayASTNode, BooleanASTNode, NumberASTNode, StringASTNode, NullASTNode, PropertyASTNode, JSONPath, ErrorCode, Diagnostic, DiagnosticSeverity, Range, SchemaDraft } from '../jsonLanguageTypes'; +import { URI } from 'vscode-uri'; import * as l10n from '@vscode/l10n'; @@ -171,11 +172,33 @@ export enum EnumMatch { Key, Enum } +const httpPrefix = `http://json-schema.org/`; +const httpsPrefix = `https://json-schema.org/`; + +export function normalizeId(id: string): string { + // use the https prefix for the old json-schema.org meta schemas + // See https://github.com/microsoft/vscode/issues/195189 + if (id.startsWith(httpPrefix)) { + id = httpsPrefix + id.substring(httpPrefix.length); + } + // remove trailing '#', normalize drive capitalization + try { + return URI.parse(id).toString(true); + } catch (e) { + return id; + } + +} + +export function getSchemaDraftFromId(schemaId: string): SchemaDraft | undefined { + return schemaDraftFromId[normalizeId(schemaId)] ?? undefined; +} + const schemaDraftFromId: { [id: string]: SchemaDraft } = { - 'http://json-schema.org/draft-03/schema#': SchemaDraft.v3, - 'http://json-schema.org/draft-04/schema#': SchemaDraft.v4, - 'http://json-schema.org/draft-06/schema#': SchemaDraft.v6, - 'http://json-schema.org/draft-07/schema#': SchemaDraft.v7, + 'https://json-schema.org/draft-03/schema': SchemaDraft.v3, + 'https://json-schema.org/draft-04/schema': SchemaDraft.v4, + 'https://json-schema.org/draft-06/schema': SchemaDraft.v6, + 'https://json-schema.org/draft-07/schema': SchemaDraft.v7, 'https://json-schema.org/draft/2019-09/schema': SchemaDraft.v2019_09, 'https://json-schema.org/draft/2020-12/schema': SchemaDraft.v2020_12 }; @@ -378,7 +401,7 @@ export class JSONDocument { function getSchemaDraft(schema: JSONSchema, fallBack = SchemaDraft.v2020_12) { let schemaId = schema.$schema; if (schemaId) { - return schemaDraftFromId[schemaId] ?? fallBack; + return getSchemaDraftFromId(schemaId) ?? fallBack; } return fallBack; } diff --git a/src/services/configuration.ts b/src/services/configuration.ts index c5265143..7ff29daa 100644 --- a/src/services/configuration.ts +++ b/src/services/configuration.ts @@ -11,8 +11,7 @@ export const schemaContributions: ISchemaContributions = { schemaAssociations: [], schemas: { // bundle the schema-schema to include (localized) descriptions - 'http://json-schema.org/draft-04/schema#': { - '$schema': 'http://json-schema.org/draft-04/schema#', + 'https://json-schema.org/draft-04/schema': { 'definitions': { 'schemaArray': { 'type': 'array', @@ -294,7 +293,7 @@ export const schemaContributions: ISchemaContributions = { }, 'default': {} }, - 'http://json-schema.org/draft-07/schema#': { + 'https://json-schema.org/draft-07/schema': { 'definitions': { 'schemaArray': { 'type': 'array', diff --git a/src/services/jsonCompletion.ts b/src/services/jsonCompletion.ts index dfe17b69..1479f2e5 100644 --- a/src/services/jsonCompletion.ts +++ b/src/services/jsonCompletion.ts @@ -740,7 +740,7 @@ export class JSONCompletion { private addDollarSchemaCompletions(separatorAfter: string, collector: CompletionsCollector): void { const schemaIds = this.schemaService.getRegisteredSchemaIds(schema => schema === 'http' || schema === 'https'); schemaIds.forEach(schemaId => { - if (schemaId.startsWith('http://json-schema.org/draft-')) { + if (schemaId.startsWith('https://json-schema.org/draft-')) { schemaId = schemaId + '#'; } collector.add({ diff --git a/src/services/jsonSchemaService.ts b/src/services/jsonSchemaService.ts index dfd2a251..4e99f347 100644 --- a/src/services/jsonSchemaService.ts +++ b/src/services/jsonSchemaService.ts @@ -7,8 +7,8 @@ import * as Json from 'jsonc-parser'; import { JSONSchema, JSONSchemaMap, JSONSchemaRef } from '../jsonSchema'; import { URI } from 'vscode-uri'; import * as Strings from '../utils/strings'; -import * as Parser from '../parser/jsonParser'; -import { SchemaRequestService, WorkspaceContextService, PromiseConstructor, MatchingSchema, TextDocument, SchemaConfiguration } from '../jsonLanguageTypes'; +import { asSchema, getSchemaDraftFromId, JSONDocument, normalizeId } from '../parser/jsonParser'; +import { SchemaRequestService, WorkspaceContextService, PromiseConstructor, MatchingSchema, TextDocument, SchemaConfiguration, SchemaDraft } from '../jsonLanguageTypes'; import * as l10n from '@vscode/l10n'; import { createRegex } from '../utils/glob'; @@ -34,7 +34,7 @@ export interface IJSONSchemaService { /** * Looks up the appropriate schema for the given URI */ - getSchemaForResource(resource: string, document?: Parser.JSONDocument): PromiseLike; + getSchemaForResource(resource: string, document?: JSONDocument): PromiseLike; /** * Returns all registered schema ids @@ -193,9 +193,9 @@ export class ResolvedSchema { public readonly schema: JSONSchema; public readonly errors: string[]; public readonly warnings: string[]; - public readonly schemaDraft: string | undefined; + public readonly schemaDraft: SchemaDraft | undefined; - constructor(schema: JSONSchema, errors: string[] = [], warnings: string[] = [], schemaDraft: string | undefined) { + constructor(schema: JSONSchema, errors: string[] = [], warnings: string[] = [], schemaDraft: SchemaDraft | undefined) { this.schema = schema; this.errors = errors; this.warnings = warnings; @@ -205,7 +205,7 @@ export class ResolvedSchema { public getSection(path: string[]): JSONSchema | undefined { const schemaRef = this.getSectionRecursive(path, this.schema); if (schemaRef) { - return Parser.asSchema(schemaRef); + return asSchema(schemaRef); } return undefined; } @@ -390,9 +390,6 @@ export class JSONSchemaService implements IJSONSchemaService { const errorMessage = l10n.t('Unable to load schema from \'{0}\'. No schema request service available', toDisplayString(url)); return this.promise.resolve(new UnresolvedSchema({}, [errorMessage])); } - if (url.startsWith('http://json-schema.org/')) { - url = 'https' + url.substring(4); // always access json-schema.org with https. See https://github.com/microsoft/vscode/issues/195189 - } return this.requestService(url).then( content => { if (!content) { @@ -433,8 +430,8 @@ export class JSONSchemaService implements IJSONSchemaService { const resolveErrors: string[] = schemaToResolve.errors.slice(0); const schema = schemaToResolve.schema; - let schemaDraft = schema.$schema ? normalizeId(schema.$schema) : undefined; - if (schemaDraft === 'http://json-schema.org/draft-03/schema') { + const schemaDraft = schema.$schema ? getSchemaDraftFromId(schema.$schema) : undefined; + if (schemaDraft === SchemaDraft.v3) { return this.promise.resolve(new ResolvedSchema({}, [l10n.t("Draft-03 schemas are not supported.")], [], schemaDraft)); } @@ -634,7 +631,7 @@ export class JSONSchemaService implements IJSONSchemaService { } }; - private getSchemaFromProperty(resource: string, document: Parser.JSONDocument): string | undefined { + private getSchemaFromProperty(resource: string, document: JSONDocument): string | undefined { if (document.root?.type === 'object') { for (const p of document.root.properties) { if (p.keyNode.value === '$schema' && p.valueNode?.type === 'string') { @@ -666,7 +663,7 @@ export class JSONSchemaService implements IJSONSchemaService { return schemas; } - public getSchemaURIsForResource(resource: string, document?: Parser.JSONDocument): string[] { + public getSchemaURIsForResource(resource: string, document?: JSONDocument): string[] { let schemeId = document && this.getSchemaFromProperty(resource, document); if (schemeId) { return [schemeId]; @@ -674,7 +671,7 @@ export class JSONSchemaService implements IJSONSchemaService { return this.getAssociatedSchemas(resource); } - public getSchemaForResource(resource: string, document?: Parser.JSONDocument): PromiseLike { + public getSchemaForResource(resource: string, document?: JSONDocument): PromiseLike { if (document) { // first use $schema if present let schemeId = this.getSchemaFromProperty(resource, document); @@ -704,7 +701,7 @@ export class JSONSchemaService implements IJSONSchemaService { } } - public getMatchingSchemas(document: TextDocument, jsonDocument: Parser.JSONDocument, schema?: JSONSchema): PromiseLike { + public getMatchingSchemas(document: TextDocument, jsonDocument: JSONDocument, schema?: JSONSchema): PromiseLike { if (schema) { const id = schema.id || ('schemaservice://untitled/matchingSchemas/' + idCounter++); const handle = this.addSchemaHandle(id, schema); @@ -724,16 +721,6 @@ export class JSONSchemaService implements IJSONSchemaService { let idCounter = 0; -function normalizeId(id: string): string { - // remove trailing '#', normalize drive capitalization - try { - return URI.parse(id).toString(true); - } catch (e) { - return id; - } - -} - function normalizeResourceForMatching(resource: string): string { // remove queries and fragments, normalize drive capitalization try { diff --git a/src/test/completion.test.ts b/src/test/completion.test.ts index dc9a825e..6a8c7db9 100644 --- a/src/test/completion.test.ts +++ b/src/test/completion.test.ts @@ -1079,8 +1079,8 @@ suite('JSON Completion', () => { await testCompletionsFor('{ "$schema": | }', schema, { items: [ { label: '"http://myschemastore/test1"', resultText: '{ "$schema": "http://myschemastore/test1" }' }, - { label: '"http://json-schema.org/draft-04/schema#"', resultText: '{ "$schema": "http://json-schema.org/draft-04/schema#" }' }, - { label: '"http://json-schema.org/draft-07/schema#"', resultText: '{ "$schema": "http://json-schema.org/draft-07/schema#" }' } + { label: '"https://json-schema.org/draft-04/schema#"', resultText: '{ "$schema": "https://json-schema.org/draft-04/schema#" }' }, + { label: '"https://json-schema.org/draft-07/schema#"', resultText: '{ "$schema": "https://json-schema.org/draft-07/schema#" }' } ] }); await testCompletionsFor('{ "$schema": "|', schema, { diff --git a/src/test/schema.test.ts b/src/test/schema.test.ts index ba986db8..e4b4492f 100644 --- a/src/test/schema.test.ts +++ b/src/test/schema.test.ts @@ -1831,7 +1831,7 @@ suite('JSON Schema', () => { test('schema resolving severity', async function () { const schema: JSONSchema = { - $schema: 'http://json-schema.org/draft-03/schema', + $schema: 'http://json-schema.org/draft-03/schema#', type: 'string' };