@ordojs/dev-tools
Version:
Advanced developer tools for OrdoJS with component inspector, AST explorer, and performance profiling
1,671 lines (1,661 loc) • 54.8 kB
JavaScript
import { EventEmitter } from 'events';
var __defProp = Object.defineProperty;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __esm = (fn, res) => function __init() {
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
// src/ast-explorer/index.ts
var ast_explorer_exports = {};
__export(ast_explorer_exports, {
ASTExplorer: () => ASTExplorer
});
var ASTExplorer;
var init_ast_explorer = __esm({
"src/ast-explorer/index.ts"() {
ASTExplorer = class extends EventEmitter {
astNodes;
isRunning;
port;
/**
* Create a new ASTExplorer instance
*
* @param port - WebSocket port for AST explorer
*/
constructor(port = 24681) {
super();
this.astNodes = /* @__PURE__ */ new Map();
this.isRunning = false;
this.port = port;
}
/**
* Start the AST explorer
*/
async start() {
if (this.isRunning) {
console.warn("AST explorer is already running");
return;
}
try {
await this.startWebSocketServer();
this.isRunning = true;
console.log(`AST explorer started on port ${this.port}`);
this.emit("started");
} catch (error) {
console.error("Failed to start AST explorer:", error);
this.emit("error", error);
throw error;
}
}
/**
* Stop the AST explorer
*/
async stop() {
if (!this.isRunning) {
console.warn("AST explorer is not running");
return;
}
try {
await this.stopWebSocketServer();
this.isRunning = false;
console.log("AST explorer stopped");
this.emit("stopped");
} catch (error) {
console.error("Failed to stop AST explorer:", error);
this.emit("error", error);
throw error;
}
}
/**
* Parse source code and create AST
*
* @param sourceCode - Source code to parse
* @param fileName - File name for the AST
* @returns AST root node
*/
parseSourceCode(sourceCode, fileName) {
try {
const astNode = {
type: "Program",
position: {
start: { line: 1, column: 1 },
end: { line: 1, column: sourceCode.length }
},
children: [],
value: sourceCode
};
this.astNodes.set(fileName, astNode);
this.emit("astParsed", { fileName, astNode });
return astNode;
} catch (error) {
console.error("Failed to parse source code:", error);
this.emit("error", error);
throw error;
}
}
/**
* Get AST for a file
*
* @param fileName - File name
* @returns AST node or undefined
*/
getAST(fileName) {
return this.astNodes.get(fileName);
}
/**
* Get all ASTs
*
* @returns Map of all ASTs
*/
getAllASTs() {
return new Map(this.astNodes);
}
/**
* Find nodes by type
*
* @param fileName - File name
* @param nodeType - Node type to search for
* @returns Array of matching nodes
*/
findNodesByType(fileName, nodeType) {
const ast = this.astNodes.get(fileName);
if (!ast) {
return [];
}
return this.findNodesRecursive(ast, nodeType);
}
/**
* Find nodes by value
*
* @param fileName - File name
* @param value - Value to search for
* @returns Array of matching nodes
*/
findNodesByValue(fileName, value) {
const ast = this.astNodes.get(fileName);
if (!ast) {
return [];
}
return this.findNodesByValueRecursive(ast, value);
}
/**
* Get node path from root
*
* @param fileName - File name
* @param targetNode - Target node
* @returns Array of nodes from root to target
*/
getNodePath(fileName, targetNode) {
const ast = this.astNodes.get(fileName);
if (!ast) {
return [];
}
return this.findNodePath(ast, targetNode);
}
/**
* Get AST statistics
*
* @param fileName - File name
* @returns AST statistics
*/
getASTStats(fileName) {
const ast = this.astNodes.get(fileName);
if (!ast) {
return {
totalNodes: 0,
nodeTypes: {},
maxDepth: 0,
averageDepth: 0
};
}
const stats = this.calculateASTStats(ast);
return stats;
}
/**
* Clear all ASTs
*/
clearASTs() {
this.astNodes.clear();
this.emit("astsCleared");
}
/**
* Recursively find nodes by type
*
* @param node - Current node
* @param nodeType - Node type to search for
* @returns Array of matching nodes
*/
findNodesRecursive(node, nodeType) {
const results = [];
if (node.type === nodeType) {
results.push(node);
}
if (node.children) {
for (const child of node.children) {
results.push(...this.findNodesRecursive(child, nodeType));
}
}
return results;
}
/**
* Recursively find nodes by value
*
* @param node - Current node
* @param value - Value to search for
* @returns Array of matching nodes
*/
findNodesByValueRecursive(node, value) {
const results = [];
if (node.value && node.value.includes(value)) {
results.push(node);
}
if (node.children) {
for (const child of node.children) {
results.push(...this.findNodesByValueRecursive(child, value));
}
}
return results;
}
/**
* Find path from root to target node
*
* @param node - Current node
* @param targetNode - Target node
* @param path - Current path
* @returns Path to target node or empty array
*/
findNodePath(node, targetNode, path = []) {
const currentPath = [...path, node];
if (node === targetNode) {
return currentPath;
}
if (node.children) {
for (const child of node.children) {
const result = this.findNodePath(child, targetNode, currentPath);
if (result.length > 0) {
return result;
}
}
}
return [];
}
/**
* Calculate AST statistics
*
* @param node - Root node
* @param depth - Current depth
* @returns AST statistics
*/
calculateASTStats(node, depth = 0) {
let totalNodes = 1;
const nodeTypes = { [node.type]: 1 };
let maxDepth = depth;
let totalDepth = depth;
if (node.children) {
for (const child of node.children) {
const childStats = this.calculateASTStats(child, depth + 1);
totalNodes += childStats.totalNodes;
maxDepth = Math.max(maxDepth, childStats.maxDepth);
totalDepth += childStats.totalNodes * (depth + 1);
for (const [type, count] of Object.entries(childStats.nodeTypes)) {
nodeTypes[type] = (nodeTypes[type] || 0) + count;
}
}
}
return {
totalNodes,
nodeTypes,
maxDepth,
averageDepth: totalDepth / totalNodes
};
}
/**
* Start WebSocket server for AST explorer communication
*/
async startWebSocketServer() {
console.log("Starting WebSocket server for AST explorer...");
}
/**
* Stop WebSocket server
*/
async stopWebSocketServer() {
console.log("Stopping WebSocket server for AST explorer...");
}
};
}
});
// src/bundle-analyzer/index.ts
var bundle_analyzer_exports = {};
__export(bundle_analyzer_exports, {
BundleAnalyzer: () => BundleAnalyzer
});
var BundleAnalyzer;
var init_bundle_analyzer = __esm({
"src/bundle-analyzer/index.ts"() {
BundleAnalyzer = class extends EventEmitter {
analyses;
isRunning;
port;
/**
* Create a new BundleAnalyzer instance
*
* @param port - WebSocket port for bundle analyzer
*/
constructor(port = 24682) {
super();
this.analyses = /* @__PURE__ */ new Map();
this.isRunning = false;
this.port = port;
}
/**
* Start the bundle analyzer
*/
async start() {
if (this.isRunning) {
console.warn("Bundle analyzer is already running");
return;
}
try {
await this.startWebSocketServer();
this.isRunning = true;
console.log(`Bundle analyzer started on port ${this.port}`);
this.emit("started");
} catch (error) {
console.error("Failed to start bundle analyzer:", error);
this.emit("error", error);
throw error;
}
}
/**
* Stop the bundle analyzer
*/
async stop() {
if (!this.isRunning) {
console.warn("Bundle analyzer is not running");
return;
}
try {
await this.stopWebSocketServer();
this.isRunning = false;
console.log("Bundle analyzer stopped");
this.emit("stopped");
} catch (error) {
console.error("Failed to stop bundle analyzer:", error);
this.emit("error", error);
throw error;
}
}
/**
* Analyze a bundle file
*
* @param bundlePath - Path to the bundle file
* @param bundleName - Name for the bundle analysis
* @returns Bundle analysis result
*/
async analyzeBundle(bundlePath, bundleName) {
try {
const analysis = {
size: 0,
gzippedSize: 0,
modules: [],
chunks: [],
dependencies: [],
warnings: [],
errors: []
};
await this.simulateBundleAnalysis(bundlePath, analysis);
this.analyses.set(bundleName, analysis);
this.emit("bundleAnalyzed", { bundleName, analysis });
return analysis;
} catch (error) {
console.error("Failed to analyze bundle:", error);
this.emit("error", error);
throw error;
}
}
/**
* Get bundle analysis by name
*
* @param bundleName - Bundle name
* @returns Bundle analysis or undefined
*/
getAnalysis(bundleName) {
return this.analyses.get(bundleName);
}
/**
* Get all bundle analyses
*
* @returns Array of all bundle analyses
*/
getAllAnalyses() {
return Array.from(this.analyses.values());
}
/**
* Compare two bundle analyses
*
* @param bundleName1 - First bundle name
* @param bundleName2 - Second bundle name
* @returns Comparison result
*/
compareBundles(bundleName1, bundleName2) {
const analysis1 = this.analyses.get(bundleName1);
const analysis2 = this.analyses.get(bundleName2);
if (!analysis1 || !analysis2) {
throw new Error("One or both bundle analyses not found");
}
const sizeDifference = analysis2.size - analysis1.size;
const sizeDifferencePercent = sizeDifference / analysis1.size * 100;
const moduleCountDifference = analysis2.modules.length - analysis1.modules.length;
const dependencyCountDifference = analysis2.dependencies.length - analysis1.dependencies.length;
const modules1 = new Set(analysis1.modules.map((m) => m.name));
const modules2 = new Set(analysis2.modules.map((m) => m.name));
const newModules = analysis2.modules.filter((m) => !modules1.has(m.name)).map((m) => m.name);
const removedModules = analysis1.modules.filter((m) => !modules2.has(m.name)).map((m) => m.name);
const deps1 = new Set(analysis1.dependencies.map((d) => d.name));
const deps2 = new Set(analysis2.dependencies.map((d) => d.name));
const newDependencies = analysis2.dependencies.filter((d) => !deps1.has(d.name)).map((d) => d.name);
const removedDependencies = analysis1.dependencies.filter((d) => !deps2.has(d.name)).map((d) => d.name);
return {
sizeDifference,
sizeDifferencePercent,
moduleCountDifference,
dependencyCountDifference,
newModules,
removedModules,
newDependencies,
removedDependencies
};
}
/**
* Get bundle optimization suggestions
*
* @param bundleName - Bundle name
* @returns Optimization suggestions
*/
getOptimizationSuggestions(bundleName) {
const analysis = this.analyses.get(bundleName);
if (!analysis) {
throw new Error("Bundle analysis not found");
}
const moduleCounts = /* @__PURE__ */ new Map();
for (const module of analysis.modules) {
moduleCounts.set(module.name, (moduleCounts.get(module.name) || 0) + 1);
}
const duplicateModules = Array.from(moduleCounts.entries()).filter(([_, count]) => count > 1).map(([name, _]) => name);
const largeModules = analysis.modules.filter((module) => module.size > 100 * 1024).map((module) => module.name);
const unusedDependencies = [];
const codeSplittingOpportunities = analysis.modules.filter((module) => module.size > 50 * 1024 && !module.name.includes("vendor")).map((module) => module.name);
const compressionOpportunities = analysis.modules.filter((module) => module.size > 10 * 1024).map((module) => module.name);
return {
duplicateModules,
largeModules,
unusedDependencies,
codeSplittingOpportunities,
compressionOpportunities
};
}
/**
* Get bundle statistics
*
* @param bundleName - Bundle name
* @returns Bundle statistics
*/
getBundleStats(bundleName) {
const analysis = this.analyses.get(bundleName);
if (!analysis) {
throw new Error("Bundle analysis not found");
}
const totalSize = analysis.size;
const gzippedSize = analysis.gzippedSize;
const moduleCount = analysis.modules.length;
const dependencyCount = analysis.dependencies.length;
const averageModuleSize = totalSize / moduleCount || 0;
const largestModule = analysis.modules.length > 0 ? analysis.modules.reduce(
(largest, current) => current.size > largest.size ? current : largest
) : null;
const largestModuleSize = largestModule ? largestModule.size : 0;
return {
totalSize,
gzippedSize,
moduleCount,
dependencyCount,
averageModuleSize,
largestModule: largestModule ? largestModule.name : "",
largestModuleSize
};
}
/**
* Clear all bundle analyses
*/
clearAnalyses() {
this.analyses.clear();
this.emit("analysesCleared");
}
/**
* Simulate bundle analysis (placeholder implementation)
*
* @param bundlePath - Path to bundle file
* @param analysis - Analysis object to populate
*/
async simulateBundleAnalysis(bundlePath, analysis) {
const fs = await import('fs/promises');
try {
const stats = await fs.stat(bundlePath);
analysis.size = stats.size;
analysis.gzippedSize = Math.round(analysis.size * 0.3);
analysis.modules = [
{
name: "main.js",
size: Math.round(analysis.size * 0.6),
dependencies: ["react", "react-dom"],
exports: ["App", "main"],
path: bundlePath
},
{
name: "vendor.js",
size: Math.round(analysis.size * 0.4),
dependencies: ["lodash", "moment"],
exports: ["vendor"],
path: bundlePath
}
];
analysis.chunks = [
{
name: "main",
size: analysis.modules[0]?.size || 0,
modules: ["main.js"],
entry: true
},
{
name: "vendor",
size: analysis.modules[1]?.size || 0,
modules: ["vendor.js"],
entry: false
}
];
analysis.dependencies = [
{
name: "react",
version: "18.2.0",
size: 100 * 1024,
type: "production"
},
{
name: "react-dom",
version: "18.2.0",
size: 150 * 1024,
type: "production"
},
{
name: "lodash",
version: "4.17.21",
size: 70 * 1024,
type: "production"
}
];
} catch (error) {
analysis.errors.push(`Failed to analyze bundle: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Start WebSocket server for bundle analyzer communication
*/
async startWebSocketServer() {
console.log("Starting WebSocket server for bundle analyzer...");
}
/**
* Stop WebSocket server
*/
async stopWebSocketServer() {
console.log("Stopping WebSocket server for bundle analyzer...");
}
};
}
});
// src/development-server/index.ts
var development_server_exports = {};
__export(development_server_exports, {
DevelopmentServer: () => DevelopmentServer
});
var DevelopmentServer;
var init_development_server = __esm({
"src/development-server/index.ts"() {
DevelopmentServer = class extends EventEmitter {
config;
isRunning;
server;
// Express server instance
/**
* Create a new DevelopmentServer instance
*
* @param config - Development server configuration
*/
constructor(config) {
super();
this.config = config;
this.isRunning = false;
this.server = null;
}
/**
* Start the development server
*/
async start() {
if (this.isRunning) {
console.warn("Development server is already running");
return;
}
try {
await this.initializeServer();
await this.startServer();
this.isRunning = true;
console.log(`Development server started on http://${this.config.host}:${this.config.port}`);
this.emit("started");
} catch (error) {
console.error("Failed to start development server:", error);
this.emit("error", error);
throw error;
}
}
/**
* Stop the development server
*/
async stop() {
if (!this.isRunning) {
console.warn("Development server is not running");
return;
}
try {
await this.stopServer();
this.isRunning = false;
console.log("Development server stopped");
this.emit("stopped");
} catch (error) {
console.error("Failed to stop development server:", error);
this.emit("error", error);
throw error;
}
}
/**
* Get server status
*
* @returns Server status information
*/
getStatus() {
return {
isRunning: this.isRunning,
port: this.config.port,
host: this.config.host,
config: this.config
};
}
/**
* Update server configuration
*
* @param newConfig - New configuration
*/
updateConfig(newConfig) {
this.config = { ...this.config, ...newConfig };
this.emit("configUpdated", this.config);
}
/**
* Initialize Express server
*/
async initializeServer() {
try {
const express = await import('express');
const cors = await import('cors');
const compression = await import('compression');
const serveStatic = await import('serve-static');
const morgan = await import('morgan');
const helmet = await import('helmet');
const app = express.default();
if (this.config.cors) {
app.use(cors.default());
}
if (this.config.compression) {
app.use(compression.default());
}
app.use(helmet.default());
app.use(morgan.default("combined"));
app.use(serveStatic.default(this.config.staticDir));
this.setupDevToolsRoutes(app);
app.use(this.errorHandler.bind(this));
this.server = app;
} catch (error) {
console.error("Failed to initialize Express server:", error);
throw error;
}
}
/**
* Start the server
*/
async startServer() {
return new Promise((resolve, reject) => {
if (!this.server) {
reject(new Error("Server not initialized"));
return;
}
const server = this.server.listen(this.config.port, this.config.host, () => {
console.log(`Development server listening on http://${this.config.host}:${this.config.port}`);
resolve();
});
server.on("error", (error) => {
console.error("Server error:", error);
reject(error);
});
});
}
/**
* Stop the server
*/
async stopServer() {
return new Promise((resolve, reject) => {
if (!this.server) {
resolve();
return;
}
const server = this.server;
server.close((error) => {
if (error) {
console.error("Error stopping server:", error);
reject(error);
} else {
console.log("Server stopped");
resolve();
}
});
});
}
/**
* Setup dev tools API routes
*
* @param app - Express app instance
*/
setupDevToolsRoutes(app) {
app.get("/api/dev-tools/health", (req, res) => {
res.json({
status: "healthy",
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
config: this.config
});
});
app.get("/api/dev-tools/inspector", (req, res) => {
res.json({
components: [],
stats: {
totalComponents: 0,
totalRenderCount: 0,
averageRenderTime: 0,
peakMemoryUsage: 0
}
});
});
app.get("/api/dev-tools/profiler", (req, res) => {
res.json({
profiles: [],
stats: {
totalProfiles: 0,
activeProfiles: 0,
totalMeasurements: 0,
averageProfileDuration: 0
}
});
});
app.get("/api/dev-tools/ast-explorer", (req, res) => {
res.json({
asts: [],
stats: {
totalASTs: 0,
totalNodes: 0,
averageDepth: 0
}
});
});
app.get("/api/dev-tools/bundle-analyzer", (req, res) => {
res.json({
analyses: [],
stats: {
totalAnalyses: 0,
totalSize: 0,
averageSize: 0
}
});
});
app.get("/api/dev-tools/error-overlay", (req, res) => {
res.json({
errors: [],
stats: {
totalErrors: 0,
errorsByType: {},
errorsByFile: {}
}
});
});
app.get("/api/dev-tools/hmr", (req, res) => {
res.json({
updates: [],
stats: {
totalUpdates: 0,
updatesByType: {},
updatesByFile: {},
averageUpdateTime: 0
}
});
});
}
/**
* Error handling middleware
*
* @param err - Error object
* @param req - Request object
* @param res - Response object
* @param next - Next function
*/
errorHandler(err, req, res, next) {
console.error("Server error:", err);
res.status(500).json({
error: {
message: err.message,
stack: process.env.NODE_ENV === "development" ? err.stack : void 0
}
});
}
};
}
});
// src/error-overlay/index.ts
var error_overlay_exports = {};
__export(error_overlay_exports, {
ErrorOverlay: () => ErrorOverlay
});
var ErrorOverlay;
var init_error_overlay = __esm({
"src/error-overlay/index.ts"() {
ErrorOverlay = class extends EventEmitter {
errors;
isRunning;
port;
/**
* Create a new ErrorOverlay instance
*
* @param port - WebSocket port for error overlay
*/
constructor(port = 24683) {
super();
this.errors = /* @__PURE__ */ new Map();
this.isRunning = false;
this.port = port;
}
/**
* Start the error overlay
*/
async start() {
if (this.isRunning) {
console.warn("Error overlay is already running");
return;
}
try {
await this.startWebSocketServer();
this.isRunning = true;
console.log(`Error overlay started on port ${this.port}`);
this.emit("started");
} catch (error) {
console.error("Failed to start error overlay:", error);
this.emit("error", error);
throw error;
}
}
/**
* Stop the error overlay
*/
async stop() {
if (!this.isRunning) {
console.warn("Error overlay is not running");
return;
}
try {
await this.stopWebSocketServer();
this.isRunning = false;
console.log("Error overlay stopped");
this.emit("stopped");
} catch (error) {
console.error("Failed to stop error overlay:", error);
this.emit("error", error);
throw error;
}
}
/**
* Add an error to the overlay
*
* @param errorId - Unique error identifier
* @param errorInfo - Error information
*/
addError(errorId, errorInfo) {
this.errors.set(errorId, errorInfo);
this.emit("errorAdded", { errorId, errorInfo });
}
/**
* Update an error
*
* @param errorId - Error identifier
* @param updates - Error updates
*/
updateError(errorId, updates) {
const error = this.errors.get(errorId);
if (error) {
const updatedError = { ...error, ...updates };
this.errors.set(errorId, updatedError);
this.emit("errorUpdated", { errorId, errorInfo: updatedError });
}
}
/**
* Remove an error
*
* @param errorId - Error identifier
*/
removeError(errorId) {
const error = this.errors.get(errorId);
if (error) {
this.errors.delete(errorId);
this.emit("errorRemoved", { errorId, errorInfo: error });
}
}
/**
* Get error by ID
*
* @param errorId - Error identifier
* @returns Error information or undefined
*/
getError(errorId) {
return this.errors.get(errorId);
}
/**
* Get all errors
*
* @returns Array of all errors
*/
getAllErrors() {
return Array.from(this.errors.values());
}
/**
* Clear all errors
*/
clearErrors() {
this.errors.clear();
this.emit("errorsCleared");
}
/**
* Get error statistics
*
* @returns Error statistics
*/
getErrorStats() {
const errors = Array.from(this.errors.values());
const errorsByType = {};
const errorsByFile = {};
for (const error of errors) {
const errorType = this.getErrorType(error);
errorsByType[errorType] = (errorsByType[errorType] || 0) + 1;
if (error.filePath) {
errorsByFile[error.filePath] = (errorsByFile[error.filePath] || 0) + 1;
}
}
return {
totalErrors: errors.length,
errorsByType,
errorsByFile
};
}
/**
* Generate error suggestions
*
* @param errorId - Error identifier
* @returns Array of suggestions
*/
generateSuggestions(errorId) {
const error = this.errors.get(errorId);
if (!error) {
return [];
}
const suggestions = [];
if (error.message.includes("Cannot find module")) {
suggestions.push("Check if the module is installed and imported correctly");
suggestions.push("Verify the module path is correct");
suggestions.push("Try running npm install or pnpm install");
}
if (error.message.includes("Unexpected token")) {
suggestions.push("Check for syntax errors in your code");
suggestions.push("Verify all brackets, parentheses, and quotes are properly closed");
suggestions.push("Check for missing semicolons or commas");
}
if (error.message.includes("TypeError")) {
suggestions.push("Check if the variable or property exists");
suggestions.push("Verify the data type is correct");
suggestions.push("Add proper null/undefined checks");
}
if (error.message.includes("ReferenceError")) {
suggestions.push("Check if the variable is declared before use");
suggestions.push("Verify the variable name is spelled correctly");
suggestions.push("Check the scope of the variable");
}
suggestions.push("Check the browser console for more details");
suggestions.push("Try refreshing the page");
suggestions.push("Check the documentation for the correct usage");
return suggestions;
}
/**
* Get error type from error message
*
* @param error - Error information
* @returns Error type
*/
getErrorType(error) {
if (error.message.includes("Cannot find module")) {
return "ModuleNotFound";
}
if (error.message.includes("Unexpected token")) {
return "SyntaxError";
}
if (error.message.includes("TypeError")) {
return "TypeError";
}
if (error.message.includes("ReferenceError")) {
return "ReferenceError";
}
if (error.message.includes("RangeError")) {
return "RangeError";
}
return "Unknown";
}
/**
* Start WebSocket server for error overlay communication
*/
async startWebSocketServer() {
console.log("Starting WebSocket server for error overlay...");
}
/**
* Stop WebSocket server
*/
async stopWebSocketServer() {
console.log("Stopping WebSocket server for error overlay...");
}
};
}
});
// src/hmr/index.ts
var hmr_exports = {};
__export(hmr_exports, {
EnhancedHMR: () => EnhancedHMR
});
var EnhancedHMR;
var init_hmr = __esm({
"src/hmr/index.ts"() {
EnhancedHMR = class extends EventEmitter {
updates;
isRunning;
port;
statePreservation;
/**
* Create a new EnhancedHMR instance
*
* @param port - WebSocket port for enhanced HMR
* @param statePreservation - Enable state preservation
*/
constructor(port = 24684, statePreservation = true) {
super();
this.updates = /* @__PURE__ */ new Map();
this.isRunning = false;
this.port = port;
this.statePreservation = statePreservation;
}
/**
* Start the enhanced HMR
*/
async start() {
if (this.isRunning) {
console.warn("Enhanced HMR is already running");
return;
}
try {
await this.startWebSocketServer();
this.isRunning = true;
console.log(`Enhanced HMR started on port ${this.port}`);
this.emit("started");
} catch (error) {
console.error("Failed to start enhanced HMR:", error);
this.emit("error", error);
throw error;
}
}
/**
* Stop the enhanced HMR
*/
async stop() {
if (!this.isRunning) {
console.warn("Enhanced HMR is not running");
return;
}
try {
await this.stopWebSocketServer();
this.isRunning = false;
console.log("Enhanced HMR stopped");
this.emit("stopped");
} catch (error) {
console.error("Failed to stop enhanced HMR:", error);
this.emit("error", error);
throw error;
}
}
/**
* Send an HMR update
*
* @param update - HMR update information
*/
sendUpdate(update) {
const updateId = this.generateUpdateId(update);
this.updates.set(updateId, update);
this.emit("updateSent", { updateId, update });
}
/**
* Get update by ID
*
* @param updateId - Update identifier
* @returns HMR update or undefined
*/
getUpdate(updateId) {
return this.updates.get(updateId);
}
/**
* Get all updates
*
* @returns Array of all updates
*/
getAllUpdates() {
return Array.from(this.updates.values());
}
/**
* Clear all updates
*/
clearUpdates() {
this.updates.clear();
this.emit("updatesCleared");
}
/**
* Get HMR statistics
*
* @returns HMR statistics
*/
getHMRStats() {
const updates = Array.from(this.updates.values());
const updatesByType = {};
const updatesByFile = {};
let totalUpdateTime = 0;
for (const update of updates) {
updatesByType[update.type] = (updatesByType[update.type] || 0) + 1;
updatesByFile[update.filePath] = (updatesByFile[update.filePath] || 0) + 1;
totalUpdateTime += Date.now() - update.timestamp;
}
const averageUpdateTime = updates.length > 0 ? totalUpdateTime / updates.length : 0;
return {
totalUpdates: updates.length,
updatesByType,
updatesByFile,
averageUpdateTime
};
}
/**
* Enable state preservation
*/
enableStatePreservation() {
this.statePreservation = true;
this.emit("statePreservationEnabled");
}
/**
* Disable state preservation
*/
disableStatePreservation() {
this.statePreservation = false;
this.emit("statePreservationDisabled");
}
/**
* Check if state preservation is enabled
*
* @returns True if state preservation is enabled
*/
isStatePreservationEnabled() {
return this.statePreservation;
}
/**
* Generate update ID
*
* @param update - HMR update
* @returns Update ID
*/
generateUpdateId(update) {
return `${update.type}-${update.filePath}-${update.timestamp}`;
}
/**
* Start WebSocket server for enhanced HMR communication
*/
async startWebSocketServer() {
console.log("Starting WebSocket server for enhanced HMR...");
}
/**
* Stop WebSocket server
*/
async stopWebSocketServer() {
console.log("Stopping WebSocket server for enhanced HMR...");
}
};
}
});
// src/inspector/index.ts
var inspector_exports = {};
__export(inspector_exports, {
ComponentInspector: () => ComponentInspector
});
var ComponentInspector;
var init_inspector = __esm({
"src/inspector/index.ts"() {
ComponentInspector = class extends EventEmitter {
components;
isRunning;
port;
/**
* Create a new ComponentInspector instance
*
* @param port - WebSocket port for inspector
*/
constructor(port = 24679) {
super();
this.components = /* @__PURE__ */ new Map();
this.isRunning = false;
this.port = port;
}
/**
* Start the component inspector
*/
async start() {
if (this.isRunning) {
console.warn("Component inspector is already running");
return;
}
try {
await this.startWebSocketServer();
this.isRunning = true;
console.log(`Component inspector started on port ${this.port}`);
this.emit("started");
} catch (error) {
console.error("Failed to start component inspector:", error);
this.emit("error", error);
throw error;
}
}
/**
* Stop the component inspector
*/
async stop() {
if (!this.isRunning) {
console.warn("Component inspector is not running");
return;
}
try {
await this.stopWebSocketServer();
this.isRunning = false;
console.log("Component inspector stopped");
this.emit("stopped");
} catch (error) {
console.error("Failed to stop component inspector:", error);
this.emit("error", error);
throw error;
}
}
/**
* Register a component for inspection
*
* @param componentInfo - Component information
*/
registerComponent(componentInfo) {
this.components.set(componentInfo.name, componentInfo);
this.emit("componentRegistered", componentInfo);
}
/**
* Update component information
*
* @param componentName - Component name
* @param updates - Component updates
*/
updateComponent(componentName, updates) {
const component = this.components.get(componentName);
if (component) {
const updatedComponent = { ...component, ...updates };
this.components.set(componentName, updatedComponent);
this.emit("componentUpdated", updatedComponent);
}
}
/**
* Get component information
*
* @param componentName - Component name
* @returns Component information or undefined
*/
getComponent(componentName) {
return this.components.get(componentName);
}
/**
* Get all components
*
* @returns Array of all component information
*/
getAllComponents() {
return Array.from(this.components.values());
}
/**
* Get component tree
*
* @returns Component tree structure
*/
getComponentTree() {
const rootComponents = [];
const componentMap = new Map(this.components);
for (const component of componentMap.values()) {
if (!this.hasParent(component, componentMap)) {
rootComponents.push(component);
}
}
return rootComponents;
}
/**
* Clear all components
*/
clearComponents() {
this.components.clear();
this.emit("componentsCleared");
}
/**
* Get inspector statistics
*
* @returns Inspector statistics
*/
getStats() {
const components = Array.from(this.components.values());
const totalRenderCount = components.reduce((sum, comp) => sum + comp.renderCount, 0);
const averageRenderTime = components.reduce((sum, comp) => sum + comp.performance.averageRenderTime, 0) / components.length || 0;
const peakMemoryUsage = Math.max(...components.map((comp) => comp.performance.peakMemoryUsage), 0);
return {
totalComponents: components.length,
totalRenderCount,
averageRenderTime,
peakMemoryUsage
};
}
/**
* Start WebSocket server for inspector communication
*/
async startWebSocketServer() {
console.log("Starting WebSocket server for component inspector...");
}
/**
* Stop WebSocket server
*/
async stopWebSocketServer() {
console.log("Stopping WebSocket server for component inspector...");
}
/**
* Check if component has a parent
*
* @param component - Component to check
* @param componentMap - Map of all components
* @returns True if component has a parent
*/
hasParent(component, componentMap) {
for (const otherComponent of componentMap.values()) {
if (otherComponent.children.some((child) => child.name === component.name)) {
return true;
}
}
return false;
}
};
}
});
// src/profiler/index.ts
var profiler_exports = {};
__export(profiler_exports, {
PerformanceProfiler: () => PerformanceProfiler
});
var PerformanceProfiler;
var init_profiler = __esm({
"src/profiler/index.ts"() {
PerformanceProfiler = class extends EventEmitter {
profiles;
activeProfiles;
measurements;
isRunning;
port;
/**
* Create a new PerformanceProfiler instance
*
* @param port - WebSocket port for profiler
*/
constructor(port = 24680) {
super();
this.profiles = /* @__PURE__ */ new Map();
this.activeProfiles = /* @__PURE__ */ new Map();
this.measurements = /* @__PURE__ */ new Map();
this.isRunning = false;
this.port = port;
}
/**
* Start the performance profiler
*/
async start() {
if (this.isRunning) {
console.warn("Performance profiler is already running");
return;
}
try {
await this.startWebSocketServer();
this.isRunning = true;
console.log(`Performance profiler started on port ${this.port}`);
this.emit("started");
} catch (error) {
console.error("Failed to start performance profiler:", error);
this.emit("error", error);
throw error;
}
}
/**
* Stop the performance profiler
*/
async stop() {
if (!this.isRunning) {
console.warn("Performance profiler is not running");
return;
}
try {
for (const [name, profile] of this.activeProfiles) {
await this.stopProfile(name);
}
await this.stopWebSocketServer();
this.isRunning = false;
console.log("Performance profiler stopped");
this.emit("stopped");
} catch (error) {
console.error("Failed to stop performance profiler:", error);
this.emit("error", error);
throw error;
}
}
/**
* Start a performance profile
*
* @param name - Profile name
* @param metadata - Profile metadata
* @returns Profile instance
*/
startProfile(name, metadata = {}) {
if (this.activeProfiles.has(name)) {
throw new Error(`Profile '${name}' is already active`);
}
const profile = {
name,
startTime: performance.now(),
endTime: 0,
duration: 0,
measurements: [],
metadata
};
this.activeProfiles.set(name, profile);
this.emit("profileStarted", profile);
return profile;
}
/**
* Stop a performance profile
*
* @param name - Profile name
* @returns Completed profile
*/
stopProfile(name) {
const profile = this.activeProfiles.get(name);
if (!profile) {
throw new Error(`Profile '${name}' is not active`);
}
profile.endTime = performance.now();
profile.duration = profile.endTime - profile.startTime;
this.activeProfiles.delete(name);
this.profiles.set(name, profile);
this.emit("profileStopped", profile);
return profile;
}
/**
* Add a performance measurement
*
* @param profileName - Profile name
* @param measurementName - Measurement name
* @param category - Measurement category
* @param metadata - Measurement metadata
* @returns Measurement instance
*/
addMeasurement(profileName, measurementName, category = "general", metadata = {}) {
const profile = this.activeProfiles.get(profileName);
if (!profile) {
throw new Error(`Profile '${profileName}' is not active`);
}
const measurement = {
name: measurementName,
startTime: performance.now(),
endTime: 0,
duration: 0,
category,
metadata
};
if (!this.measurements.has(profileName)) {
this.measurements.set(profileName, []);
}
this.measurements.get(profileName).push(measurement);
profile.measurements.push(measurement);
this.emit("measurementAdded", measurement);
return measurement;
}
/**
* End a performance measurement
*
* @param profileName - Profile name
* @param measurementName - Measurement name
* @returns Completed measurement
*/
endMeasurement(profileName, measurementName) {
const profile = this.activeProfiles.get(profileName);
if (!profile) {
throw new Error(`Profile '${profileName}' is not active`);
}
const measurements = this.measurements.get(profileName);
if (!measurements) {
throw new Error(`No measurements found for profile '${profileName}'`);
}
const measurement = measurements.find((m) => m.name === measurementName);
if (!measurement) {
throw new Error(`Measurement '${measurementName}' not found in profile '${profileName}'`);
}
measurement.endTime = performance.now();
measurement.duration = measurement.endTime - measurement.startTime;
this.emit("measurementEnded", measurement);
return measurement;
}
/**
* Get a profile by name
*
* @param name - Profile name
* @returns Profile or undefined
*/
getProfile(name) {
return this.profiles.get(name) || this.activeProfiles.get(name);
}
/**
* Get all profiles
*
* @returns Array of all profiles
*/
getAllProfiles() {
return Array.from(this.profiles.values());
}
/**
* Get active profiles
*
* @returns Array of active profiles
*/
getActiveProfiles() {
return Array.from(this.activeProfiles.values());
}
/**
* Clear all profiles
*/
clearProfiles() {
this.profiles.clear();
this.activeProfiles.clear();
this.measurements.clear();
this.emit("profilesCleared");
}
/**
* Get profiler statistics
*
* @returns Profiler statistics
*/
getStats() {
const allProfiles = Array.from(this.profiles.values());
const totalMeasurements = allProfiles.reduce((sum, profile) => sum + profile.measurements.length, 0);
const averageProfileDuration = allProfiles.reduce((sum, profile) => sum + profile.duration, 0) / allProfiles.length || 0;
return {
totalProfiles: allProfiles.length,
activeProfiles: this.activeProfiles.size,
totalMeasurements,
averageProfileDuration
};
}
/**
* Start WebSocket server for profiler communication
*/
async startWebSocketServer() {
console.log("Starting WebSocket server for performance profiler...");
}
/**
* Stop WebSocket server
*/
async stopWebSocketServer() {
console.log("Stopping WebSocket server for performance profiler...");
}
};
}
});
// src/index.ts
init_ast_explorer();
init_bundle_analyzer();
init_development_server();
init_error_overlay();
init_hmr();
init_inspector();
init_profiler();
var DevToolsManager = class extends EventEmitter {
config;
isRunning;
tools;
/**
* Create a new DevToolsManager instance
*
* @param config - Dev tools configuration
*/
constructor(config = {}) {
super();
this.config = {
inspector: true,
profiler: true,
astExplorer: true,
bundleAnalyzer: true,
errorOverlay: true,
enhancedHMR: true,
devServer: {
port: 3e3,
host: "localhost",
hmr: true,
https: false,
compression: true,
cors: true,
staticDir: "dist"
},
...config
};
this.isRunning = false;
this.tools = /* @__PURE__ */ new Map();
}
/**
* Start all dev tools
*/
async start() {
if (this.isRunning) {
console.warn("Dev tools are already running");
return;
}