mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-05-05 23:42:03 +00:00
feat(insight): Implement static insight generation and visualization
- Add HTML template for insights display. - Create JavaScript application logic for rendering insights. - Introduce CSS styles for layout and design. - Develop a test generator for validating the static insight generator. - Define TypeScript interfaces for structured insight data. - Refactor insight command to generate insights and open in browser. - Remove the need for a server process by generating static files directly.
This commit is contained in:
parent
18a21545ea
commit
0e55800941
27 changed files with 1415 additions and 34034 deletions
|
|
@ -0,0 +1,94 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright 2025 Qwen Code
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
import { dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import type { InsightData, StaticInsightTemplateData } from '../types/StaticInsightTypes.js';
|
||||
|
||||
export class TemplateRenderer {
|
||||
private templateDir: string;
|
||||
|
||||
constructor() {
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
this.templateDir = path.join(__dirname, '..', 'templates');
|
||||
}
|
||||
|
||||
// Safe JSON stringification to prevent XSS
|
||||
private safeJsonStringify(data: any): string {
|
||||
return JSON.stringify(data)
|
||||
.replace(/</g, '\\u003c')
|
||||
.replace(/>/g, '\\u003e')
|
||||
.replace(/&/g, '\\u0026');
|
||||
}
|
||||
|
||||
// Load template files
|
||||
private async loadTemplate(): Promise<string> {
|
||||
const templatePath = path.join(this.templateDir, 'insight-template.html');
|
||||
return await fs.readFile(templatePath, 'utf-8');
|
||||
}
|
||||
|
||||
private async loadStyles(): Promise<string> {
|
||||
const stylesPath = path.join(this.templateDir, 'styles', 'base.css');
|
||||
return await fs.readFile(stylesPath, 'utf-8');
|
||||
}
|
||||
|
||||
private async loadScripts(): Promise<string> {
|
||||
const scriptsPath = path.join(this.templateDir, 'scripts', 'insight-app.js');
|
||||
return await fs.readFile(scriptsPath, 'utf-8');
|
||||
}
|
||||
|
||||
// Generate current timestamp
|
||||
private generateTimestamp(): string {
|
||||
return new Date().toLocaleString('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
timeZoneName: 'short',
|
||||
});
|
||||
}
|
||||
|
||||
// Render the complete HTML file
|
||||
async renderInsightHTML(insights: InsightData): Promise<string> {
|
||||
const template = await this.loadTemplate();
|
||||
const styles = await this.loadStyles();
|
||||
const scripts = await this.loadScripts();
|
||||
const generatedTime = this.generateTimestamp();
|
||||
|
||||
// Create empty content placeholder - content will be generated by JavaScript
|
||||
const content = '<!-- Content will be generated by JavaScript -->';
|
||||
|
||||
// Replace all placeholders
|
||||
let html = template;
|
||||
html = html.replace('{{STYLES_PLACEHOLDER}}', styles);
|
||||
html = html.replace('{{CONTENT_PLACEHOLDER}}', content);
|
||||
html = html.replace('{{DATA_PLACEHOLDER}}', this.safeJsonStringify(insights));
|
||||
html = html.replace('{{SCRIPTS_PLACEHOLDER}}', scripts);
|
||||
html = html.replace('{{GENERATED_TIME}}', generatedTime);
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
// Create template data object
|
||||
async createTemplateData(insights: InsightData): Promise<StaticInsightTemplateData> {
|
||||
const styles = await this.loadStyles();
|
||||
const scripts = await this.loadScripts();
|
||||
const generatedTime = this.generateTimestamp();
|
||||
|
||||
return {
|
||||
styles,
|
||||
content: '<!-- Content will be generated by JavaScript -->',
|
||||
data: insights,
|
||||
scripts,
|
||||
generatedTime,
|
||||
};
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue