import * as vscode from 'vscode'; import * as fs from 'fs'; import * as path from 'path'; const BETA_TOOLS_ENABLED_KEY = 'hplToolbox.betaTools.enabled'; interface ToolDefinition { id?: string; command: string; title: string; description: string; beta?: boolean; } const FALLBACK_TOOLS: ToolDefinition[] = [ { command: 'hplToolbox.openPlecUpload', title: 'PLEC Upload', description: 'Upload HTML to internal PLEC server', }, { command: 'hplToolbox.openApplovinUpload', title: 'AppLovin Playable Preview', description: 'Upload to p.applov.in (QR preview)', }, { command: 'hplToolbox.openBase64Scanner', title: 'Base64 Scanner', description: 'Find non-base64 assets in HTML', }, { command: 'hplToolbox.openSendToMobile', title: 'Send To Mobile', description: 'Share HTML to a phone via LAN + QR', }, { command: 'hplToolbox.openMraidChecker', title: 'MRAID Checker', description: 'Check MRAID requirements and best practices', }, { command: 'hplToolbox.openPlayworksConverter', title: 'Playworks Converter', description: 'Convert Playworks HTML to per-network variants', beta: true, }, ]; export class LauncherViewProvider implements vscode.WebviewViewProvider { constructor(private readonly context: vscode.ExtensionContext) { } resolveWebviewView(view: vscode.WebviewView) { view.webview.options = { enableScripts: true }; const version = this.context.extension.packageJSON.version as string; const tools = loadToolDefinitions(this.context.extensionPath); const betaToolsEnabled = this.context.globalState.get(BETA_TOOLS_ENABLED_KEY, false); view.webview.html = getHtml(version, betaToolsEnabled, tools); view.webview.onDidReceiveMessage(async (msg) => { if (msg?.type === 'open' && typeof msg.command === 'string') { vscode.commands.executeCommand(msg.command); } else if (msg?.type === 'openChangelog') { vscode.commands.executeCommand('hplToolbox.openChangelog'); } else if (msg?.type === 'setBetaToolsEnabled' && typeof msg.enabled === 'boolean') { await this.context.globalState.update(BETA_TOOLS_ENABLED_KEY, msg.enabled); view.webview.html = getHtml(version, msg.enabled, tools); } }); } } function loadToolDefinitions(extensionPath: string): ToolDefinition[] { const toolsPath = path.join(extensionPath, 'tools.json'); try { const raw = JSON.parse(fs.readFileSync(toolsPath, 'utf8')); if (!Array.isArray(raw)) return FALLBACK_TOOLS; const tools = raw .filter((tool: any) => tool && typeof tool.command === 'string' && typeof tool.title === 'string') .map((tool: any) => ({ id: typeof tool.id === 'string' ? tool.id : undefined, command: tool.command, title: tool.title, description: typeof tool.description === 'string' ? tool.description : '', beta: Boolean(tool.beta), })); return tools.length ? tools : FALLBACK_TOOLS; } catch { return FALLBACK_TOOLS; } } function getHtml(version: string, betaToolsEnabled: boolean, tools: ToolDefinition[]): string { const visibleTools = sortToolsForDisplay(tools.filter(tool => betaToolsEnabled || !tool.beta)); const toolButtons = visibleTools.map(renderToolButton).join('\n'); return `
${toolButtons}
`; } function sortToolsForDisplay(tools: ToolDefinition[]): ToolDefinition[] { return [...tools].sort((a, b) => Number(Boolean(a.beta)) - Number(Boolean(b.beta))); } function renderToolButton(tool: ToolDefinition): string { return ` `; } function escapeHtml(value: string): string { return value.replace(/[&<>"']/g, ch => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''', }[ch] ?? ch)); }