import { TextDocumentContentProvider , Uri , workspace , window } from 'vscode' ; import { xhr , configure as configureHttpRequests , getErrorStatusDescription , XHRResponse } from 'request-light' ; import { SchemaExtensionAPI } from './schema-extension-api' ; export interface IJSONSchemaCache { getETag ( schemaUri ) : string | undefined ; putSchema ( schemaUri , eTag , schemaContent ) : Promise < void > ; getSchema ( schemaUri ) : Promise < string | undefined > ; } export class JSONSchemaDocumentContentProvider implements TextDocumentContentProvider { constructor ( private readonly schemaCache , private readonly schemaApi ) { } async provideTextDocumentContent ( uri ) { if ( uri . fragment ) { const origUri = uri . fragment ; const schemaUri = Uri . parse ( origUri ) ; if ( origUri . startsWith ( 'http' ) ) { return getJsonSchemaContent ( origUri , this . schemaCache ) ; } else if ( this . schemaApi . hasProvider ( schemaUri . scheme ) ) { let content = this . schemaApi . requestCustomSchemaContent ( origUri ) ; content = await Promise . resolve ( content ) ; if ( content . indexOf ( '\n' ) === - 1 ) { content = JSON . stringify ( JSON . parse ( content ) , null , 2 ) ; } return content ; } else { window . showErrorMessage ( `Cannot Load content for: ${ origUri }. Unknown schema: '${ schemaUri . scheme }'` ) ; return null ; } } else { window . showErrorMessage ( `Cannot Load content for: '${ uri . toString ( ) }' ` ) ; return null ; } } } export async function getJsonSchemaContent ( uri , schemaCache ) { const cachedETag = schemaCache . getETag ( uri ) ; const httpSettings = workspace . getConfiguration ( 'http' ) ; configureHttpRequests ( httpSettings . http && httpSettings . http . proxy , httpSettings . http && httpSettings . http . proxyStrictSSL ) ; const headers = { 'Accept-Encoding' : 'gzip, deflate' } ; if ( cachedETag ) { headers [ 'If-None-Match' ] = cachedETag ; } return xhr ( { url : uri , followRedirects : 5 , headers } ) . then ( async ( response ) => { const etag = response . headers [ 'etag' ] ; if ( typeof etag === 'string' ) { await schemaCache . putSchema ( uri , etag , response . responseText ) ; } return response . responseText ; } ) . then ( ( text ) => { return text ; } ) . catch ( async ( error ) => { if ( error . status === 304 ) { const content = await schemaCache . getSchema ( uri ) ; if ( content === undefined ) { console . error ( `Cannot read cached content for: ${ uri }, trying to load again` ) ; delete headers [ 'If-None-Match' ] ; return xhr ( { url : uri , followRedirects : 5 , headers } ) . then ( ( response ) => { return response . responseText ; } ) . catch ( ( err ) => { return createReject ( err ) ; } ) ; } return content ; } if ( schemaCache . getETag ( uri ) ) { const content = schemaCache . getSchema ( uri ) ; if ( content ) { return content ; } } return createReject ( error ) ; } ) ; } function createReject ( error ) { return Promise . reject ( error . responseText || getErrorStatusDescription ( error . status ) || error . toString ( ) ) ; }