diff --git a/extensions/json-language-features/client/src/jsonClient.ts b/extensions/json-language-features/client/src/jsonClient.ts index fa1c6d1020992..10b577f7abdb1 100644 --- a/extensions/json-language-features/client/src/jsonClient.ts +++ b/extensions/json-language-features/client/src/jsonClient.ts @@ -391,8 +391,7 @@ async function startClientWithParticipants(_context: ExtensionContext, languageP const schemaDocuments: { [uri: string]: boolean } = {}; - // handle content request - client.onRequest(VSCodeContentRequest.type, async (uriPath: string) => { + async function getSchemaContent(uriPath: string, allowKnownSchemaAssociations = true): Promise { const uri = Uri.parse(uriPath); const uriString = uri.toString(true); if (uri.scheme === 'untitled') { @@ -419,7 +418,7 @@ async function startClientWithParticipants(_context: ExtensionContext, languageP if (!workspace.isTrusted) { throw new ResponseError(SchemaRequestServiceErrors.UntrustedWorkspaceError, l10n.t('Downloading schemas is disabled in untrusted workspaces')); } - if (!await isTrusted(uri)) { + if (!await isTrusted(uri, allowKnownSchemaAssociations)) { throw new ResponseError(SchemaRequestServiceErrors.UntrustedSchemaError, l10n.t('Location {0} is untrusted', uriString)); } if (runtime.telemetry && uri.authority === 'schema.management.azure.com') { @@ -440,7 +439,10 @@ async function startClientWithParticipants(_context: ExtensionContext, languageP } else { throw new ResponseError(SchemaRequestServiceErrors.HTTPDisabledError, l10n.t('Downloading schemas is disabled through setting \'{0}\'', SettingIds.enableSchemaDownload)); } - }); + } + + // handle content request + client.onRequest(VSCodeContentRequest.type, uriPath => getSchemaContent(uriPath)); await client.start(); @@ -564,7 +566,7 @@ async function startClientWithParticipants(_context: ExtensionContext, languageP const registryWatchers = new Map(); const updateRegistryWatchers = () => { - const registryUris = new Set(getSchemaRegistryUris().map(uri => uri.toString())); + const registryUris = new Set(getSchemaRegistryUris().filter(isWatchableRegistryUri).map(uri => uri.toString())); for (const [uri, watcher] of registryWatchers) { if (!registryUris.has(uri)) { watcher.dispose(); @@ -598,15 +600,20 @@ async function startClientWithParticipants(_context: ExtensionContext, languageP updateFormatterRegistration(); } else if (e.affectsConfiguration(SettingIds.enableSchemaDownload)) { schemaDownloadEnabled = !!workspace.getConfiguration().get(SettingIds.enableSchemaDownload); + refreshSchemaAssociations(); triggerValidation(); } else if (e.affectsConfiguration(SettingIds.editorFoldingMaximumRegions) || e.affectsConfiguration(SettingIds.editorColorDecoratorsLimit)) { client.sendNotification(DidChangeConfigurationNotification.type, { settings: getSettings(true) }); } else if (e.affectsConfiguration(SettingIds.trustedDomains)) { trustedDomains = workspace.getConfiguration().get>(SettingIds.trustedDomains, {}); + refreshSchemaAssociations(); triggerValidation(); } })); - toDispose.push(workspace.onDidGrantWorkspaceTrust(() => triggerValidation())); + toDispose.push(workspace.onDidGrantWorkspaceTrust(() => { + refreshSchemaAssociations(); + triggerValidation(); + })); toDispose.push(createLanguageStatusItem(documentSelector, (uri: string) => client.sendRequest(LanguageStatusRequest.type, uri))); @@ -684,12 +691,12 @@ async function startClientWithParticipants(_context: ExtensionContext, languageP async function getSchemaAssociations(forceRefresh: boolean): Promise { if (!schemaAssociationsCache || forceRefresh) { - schemaAssociationsCache = computeSchemaAssociations(); + schemaAssociationsCache = computeSchemaAssociations(uri => getSchemaContent(uri, false)); } return schemaAssociationsCache; } - async function isTrusted(uri: Uri): Promise { + async function isTrusted(uri: Uri, allowKnownSchemaAssociations = true): Promise { if (uri.scheme !== 'http' && uri.scheme !== 'https') { return true; } @@ -700,10 +707,12 @@ async function startClientWithParticipants(_context: ExtensionContext, languageP return true; } - const knownAssociations = await getSchemaAssociations(false); - for (const association of knownAssociations) { - if (association.uri === uriString) { - return true; + if (allowKnownSchemaAssociations) { + const knownAssociations = await getSchemaAssociations(false); + for (const association of knownAssociations) { + if (association.uri === uriString) { + return true; + } } } const settingsCache = getSettings(false); @@ -800,9 +809,9 @@ async function startClientWithParticipants(_context: ExtensionContext, languageP }; } -async function computeSchemaAssociations(): Promise { +async function computeSchemaAssociations(getRegistryContent: (uri: string) => Promise): Promise { const extensionAssociations = getSchemaExtensionAssociations(); - return extensionAssociations.concat(await getSchemaRegistryAssociations()); + return extensionAssociations.concat(await getSchemaRegistryAssociations(getRegistryContent)); } function resolveExtensionResource(extensionUri: Uri, resource: string): Uri { @@ -860,12 +869,17 @@ function getSchemaRegistryUris(): Uri[] { return result; } -async function getSchemaRegistryAssociations(): Promise { +function isWatchableRegistryUri(uri: Uri): boolean { + return uri.scheme !== 'http' && uri.scheme !== 'https'; +} + +async function getSchemaRegistryAssociations(getRegistryContent: (uri: string) => Promise): Promise { const result: ISchemaAssociation[] = []; for (const registryUri of getSchemaRegistryUris()) { try { - const data = await workspace.fs.readFile(registryUri); - const rawStr = new TextDecoder().decode(data); + const rawStr = isWatchableRegistryUri(registryUri) + ? new TextDecoder().decode(await workspace.fs.readFile(registryUri)) + : await getRegistryContent(registryUri.toString(true)); const registry = <{ schemas?: { url?: string; fileMatch?: string[] }[] }>JSON.parse(rawStr); if (Array.isArray(registry.schemas)) { for (const schema of registry.schemas) { @@ -996,4 +1010,3 @@ export namespace ErrorCodes { export function isSchemaResolveError(d: Diagnostic) { return typeof d.code === 'number' && d.code >= ErrorCodes.SchemaResolveError; } - diff --git a/extensions/json-language-features/package.json b/extensions/json-language-features/package.json index cf3e0d5ecc691..4fa10ef714794 100644 --- a/extensions/json-language-features/package.json +++ b/extensions/json-language-features/package.json @@ -177,6 +177,9 @@ "jsonValidationRegistry": [ { "url": "vscode://schemas-associations/schemas-associations.json" + }, + { + "url": "https://www.schemastore.org/api/json/catalog.json" } ], "commands": [