blob: b3839e524fa181d1ad6eaf09a656e6cf1669bed8 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as vscode from 'vscode'
import * as fs from 'fs'
export class SvelteWebviewInitializer {
constructor(private context: vscode.ExtensionContext) {}
initialize(view: string, webView: vscode.Webview): void {
webView.options = this.getWebViewOptions(this.context, view)
webView.html = this.getHtmlContent(this.context, view, webView)
}
// get the HTML content for the webview
private getHtmlContent(
context: vscode.ExtensionContext,
view: string,
webView: vscode.Webview
): string {
const nonce = this.getNonce()
const scriptUri = this.getResourceUri('js', context, (uri) => {
return webView.asWebviewUri(uri)
})
const stylesUri = this.getResourceUri('css', context, (uri) => {
return webView.asWebviewUri(uri)
})
const indexPath = this.getResourceUri('index', context)
let indexHTML = this.injectNonce(
this.getIndexHTML(context),
webView,
nonce,
scriptUri
)!
indexHTML = fs
.readFileSync(indexPath!.fsPath, 'utf-8')
.replace(/src="\.\/index.js"/, `src="${scriptUri.toString()}"`)
.replace(/href="\.\/style.css"/, `href="${stylesUri.toString()}"`)
.replaceAll(/nonce="__nonce__"/g, `nonce="${nonce}""`)
return indexHTML
}
private injectNonce(
html: string,
webView: vscode.Webview,
nonce: string,
scriptsUri: vscode.Uri
) {
let ret = html.replaceAll(
'<head>',
`<head><meta http-equiv="Content-Security-Policy" content="default-src ${webView.cspSource}; font-src ${webView.cspSource}; style-src 'self' 'unsafe-inline' ${webView.cspSource}; img-src ${webView.cspSource}; script-src 'nonce-${nonce}' ${webView.cspSource};">`
)
return ret
}
private getIndexHTML(context: vscode.ExtensionContext) {
const indexFile = vscode.Uri.joinPath(
context.extensionUri,
'dist',
'views',
'dataEditor',
'index.html'
)
const indexContent = fs.readFileSync(indexFile.fsPath).toString()
return indexContent
}
// get a nonce for use in a content security policy
private getNonce(): string {
let text = ''
const possible =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
for (let i = 0; i < 32; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length))
}
return text
}
// get the webview options
private getWebViewOptions(
context: vscode.ExtensionContext,
view: string
): vscode.WebviewPanelOptions & vscode.WebviewOptions {
return {
enableScripts: true,
localResourceRoots: [
this.getSvelteAppDistributionFolderUri(context),
this.getSvelteAppDistributionViewFolderUri(context, view),
],
}
}
// get the svelte app distribution folder uri
private getSvelteAppDistributionFolderUri(
context: vscode.ExtensionContext
): vscode.Uri {
return vscode.Uri.joinPath(context.extensionUri, 'dist')
}
// get the svelte app distribution view folder uri
private getSvelteAppDistributionViewFolderUri(
context: vscode.ExtensionContext,
view: string
): vscode.Uri {
return vscode.Uri.joinPath(context.extensionUri, 'dist', 'views', view)
}
private getResourceUri(
item: 'index' | 'css' | 'js',
context: vscode.ExtensionContext,
uriDecorator?: (uriPath: vscode.Uri) => any
): vscode.Uri
private getResourceUri<R>(
item: 'index' | 'css' | 'js',
context: vscode.ExtensionContext,
uriDecorator: (uriPath: vscode.Uri) => R
): R
private getResourceUri<R>(
item: 'index' | 'css' | 'js',
context: vscode.ExtensionContext,
uriDecorator?: (uriPath: vscode.Uri) => R
): vscode.Uri | R {
let resourceFile = ''
switch (item) {
case 'index':
resourceFile = item + '.html'
break
case 'css':
resourceFile = 'style.css'
break
case 'js':
resourceFile = 'index.js'
break
}
let ret = vscode.Uri.joinPath(
context.extensionUri,
'dist',
'views',
'dataEditor',
resourceFile
)
return uriDecorator ? uriDecorator(ret) : ret
}
}