import * as vscode from 'vscode' ; import * as arrays from './util/arrays' ; import { Disposable } from './util/dispose' ; const resolveExtensionResource = ( extension , resourcePath ) : vscode . Uri => { return vscode . Uri . joinPath ( extension . extensionUri , resourcePath ) ; } ; const resolveExtensionResources = ( extension , resourcePaths ) : vscode . Uri [ ] => { const result = [ ] ; if ( Array . isArray ( resourcePaths ) ) { for ( const resource of resourcePaths ) { try { result . push ( resolveExtensionResource ( extension , resource ) ) ; } catch ( e ) { } } } return result ; } ; export interface MarkdownContributions { readonly previewScripts : ReadonlyArray < vscode . Uri > ; readonly previewStyles : ReadonlyArray < vscode . Uri > ; readonly previewResourceRoots : ReadonlyArray < vscode . Uri > ; readonly markdownItPlugins : Map < string , Thenable < ( md : any ) => any > > ; } export namespace MarkdownContributions { export const Empty = { previewScripts : [ ] , previewStyles : [ ] , previewResourceRoots : [ ] , markdownItPlugins : new Map ( ) } ; export function merge ( a , b ) { return { previewScripts : [ ... a . previewScripts , ... b . previewScripts ] , previewStyles : [ ... a . previewStyles , ... b . previewStyles ] , previewResourceRoots : [ ... a . previewResourceRoots , ... b . previewResourceRoots ] , markdownItPlugins : new Map ( [ ... a . markdownItPlugins . entries ( ) , ... b . markdownItPlugins . entries ( ) ] ) , } ; } function uriEqual ( a , b ) { return a . toString ( ) === b . toString ( ) ; } export function equal ( a , b ) { return arrays . equals ( a . previewScripts , b . previewScripts , uriEqual ) && arrays . equals ( a . previewStyles , b . previewStyles , uriEqual ) && arrays . equals ( a . previewResourceRoots , b . previewResourceRoots , uriEqual ) && arrays . equals ( Array . from ( a . markdownItPlugins . keys ( ) ) , Array . from ( b . markdownItPlugins . keys ( ) ) ) ; } export function fromExtension ( extension ) { const contributions = extension . packageJSON && extension . packageJSON . contributes ; if ( ! contributions ) { return MarkdownContributions . Empty ; } const previewStyles = getContributedStyles ( contributions , extension ) ; const previewScripts = getContributedScripts ( contributions , extension ) ; const previewResourceRoots = previewStyles . length || previewScripts . length ? [ extension . extensionUri ] : [ ] ; const markdownItPlugins = getContributedMarkdownItPlugins ( contributions , extension ) ; return { previewScripts , previewStyles , previewResourceRoots , markdownItPlugins } ; } function getContributedMarkdownItPlugins ( contributes , extension ) { const map = new Map < string , Thenable < ( md : any ) => any > > ( ) ; if ( contributes [ 'markdown.markdownItPlugins' ] ) { map . set ( extension . id , extension . activate ( ) . then ( ( ) => { if ( extension . exports && extension . exports . extendMarkdownIt ) { return ( md ) => extension . exports . extendMarkdownIt ( md ) ; } return ( md ) => md ; } ) ) ; } return map ; } function getContributedScripts ( contributes , extension ) { return resolveExtensionResources ( extension , contributes [ 'preview.previewScripts' ] ) ; } function getContributedStyles ( contributes , extension ) { return resolveExtensionResources ( extension , contributes [ 'preview.previewStyles' ] ) ; } } export interface MarkdownContributionProvider { readonly extensionUri : vscode . Uri ; readonly contributions : MarkdownContributions ; readonly onContributionsChanged : vscode . Event < this > ; dispose ( ) : void ; } class VSCodeExtensionMarkdownContributionProvider extends Disposable implements MarkdownContributionProvider { private _contributions ? : MarkdownContributions ; public constructor ( private readonly _extensionContext ) { super ( ) ; vscode . extensions . onDidChange ( ( ) => { const currentContributions = this . getCurrentContributions ( ) ; const existingContributions = this . _contributions || MarkdownContributions . Empty ; if ( ! MarkdownContributions . equal ( existingContributions , currentContributions ) ) { this . _contributions = currentContributions ; this . _onContributionsChanged . fire ( this ) ; } } , undefined , this . _disposables ) ; } public get extensionUri ( ) { return this . _extensionContext . extensionUri ; } private readonly _onContributionsChanged = this . _register ( new vscode . EventEmitter < this > ( ) ) ; public readonly onContributionsChanged = this . _onContributionsChanged . event ; public get contributions ( ) : MarkdownContributions { if ( ! this . _contributions ) { this . _contributions = this . getCurrentContributions ( ) ; } return this . _contributions ; } private getCurrentContributions ( ) { return vscode . extensions . all . map ( MarkdownContributions . fromExtension ) . reduce ( MarkdownContributions . merge , MarkdownContributions . Empty ) ; } } export function getMarkdownExtensionContributions ( context ) { return new VSCodeExtensionMarkdownContributionProvider ( context ) ; }