Skip to content

Commit 74eabb7

Browse files
committed
refactor: integrate shared utilities into PineScript command runner
- Add shared utilities imports: ConfigUtils, FileUtils, ProjectUtils, LoggingUtils - Add PlatformDetector and error handler imports - Update initialization with project detection using ProjectUtils - Fix checkTool method to use ConfigUtils.checkToolInstalled correctly - Add utility methods: findPineScriptFiles and getPineScriptProjectInfo - Update all console.log and console.error calls to use LoggingUtils - Fix duplicate code in generateValidationReport method - Maintain backward compatibility while enhancing error handling
1 parent b3d62fb commit 74eabb7

1 file changed

Lines changed: 165 additions & 75 deletions

File tree

scripts/pinescript/command-runner.js

Lines changed: 165 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,24 @@ const { spawn } = require("child_process");
1111
const { runCommand, commandExists } = require("../lib/utils");
1212
const ConfigManager = require("../interactive/config-manager");
1313
const PineScriptToolDetector = require("../../languages/pinescript/tool-detector");
14+
const PlatformDetector = require("../lib/platform-detector");
15+
const { defaultErrorHandler } = require("../lib/error-handler");
16+
17+
// Import shared utilities
18+
const {
19+
ConfigUtils,
20+
FileUtils,
21+
ProjectUtils,
22+
LoggingUtils,
23+
ensureDir,
24+
} = require("../lib");
1425

1526
class PineCommandRunner {
1627
constructor(projectPath = process.cwd()) {
1728
this.projectPath = projectPath;
1829
this.configManager = new ConfigManager(projectPath);
1930
this.toolDetector = new PineScriptToolDetector();
31+
this.platformDetector = new PlatformDetector();
2032
this.config = null;
2133
this.pineConfig = null;
2234
this.detectedTools = null;
@@ -26,42 +38,135 @@ class PineCommandRunner {
2638
* Initialize command runner
2739
*/
2840
async initialize() {
29-
// Load configuration
30-
this.config = this.configManager.loadConfig();
31-
if (!this.config) {
32-
throw new Error("Project not configured. Run /pine-setup first.");
33-
}
41+
// First, validate that we're in a PineScript project using ProjectUtils
42+
try {
43+
const projectInfo = ProjectUtils.detectProjectType(this.projectPath);
3444

35-
// Get PineScript configuration
36-
this.pineConfig = this.config.pinescript;
37-
if (!this.pineConfig) {
38-
throw new Error(
39-
"PineScript configuration not found. Run /pine-setup first.",
40-
);
45+
if (projectInfo.type !== "pinescript" && projectInfo.confidence < 0.7) {
46+
LoggingUtils.warn(
47+
`Project detection: ${projectInfo.type} (confidence: ${projectInfo.confidence})`,
48+
);
49+
LoggingUtils.warn(
50+
"This may not be a PineScript project. Some features may not work correctly.",
51+
);
52+
} else if (projectInfo.type === "pinescript") {
53+
LoggingUtils.debug(
54+
`Detected PineScript project: ${projectInfo.framework || "standard PineScript"}`,
55+
);
56+
}
57+
58+
// Log detected languages if available
59+
if (projectInfo.languages && projectInfo.languages.length > 0) {
60+
LoggingUtils.debug(
61+
`Detected languages: ${projectInfo.languages.join(", ")}`,
62+
);
63+
}
64+
} catch (error) {
65+
LoggingUtils.debug("Project detection failed:", error.message);
4166
}
4267

43-
// Detect tools
44-
this.detectedTools = await this.toolDetector.detectTools();
68+
// Load configuration using ConfigUtils
69+
try {
70+
this.config = ConfigUtils.loadConfig(this.projectPath);
71+
if (!this.config) {
72+
throw new Error("Project not configured. Run /pine-setup first.");
73+
}
74+
75+
// Get PineScript configuration
76+
this.pineConfig = this.config.pinescript;
77+
if (!this.pineConfig) {
78+
throw new Error(
79+
"PineScript configuration not found. Run /pine-setup first.",
80+
);
81+
}
82+
83+
// Validate PineScript configuration schema
84+
ConfigUtils.validateConfig(this.pineConfig, "pinescript");
85+
86+
// Detect tools
87+
this.detectedTools = await this.toolDetector.detectTools();
4588

46-
return true;
89+
return true;
90+
} catch (error) {
91+
// Use LoggingUtils for better error display
92+
LoggingUtils.error(
93+
"Failed to initialize PineScript command runner:",
94+
error.message,
95+
);
96+
LoggingUtils.info("Run /pine-setup to configure your PineScript project");
97+
throw error;
98+
}
4799
}
48100

49101
/**
50102
* Check if required tool is installed
51103
*/
52-
async checkTool(toolName, required = true) {
53-
const toolInfo = this.detectedTools?.[toolName];
104+
checkTool(toolName, required = true) {
105+
try {
106+
// Use ConfigUtils to check if tool is installed
107+
const isInstalled = ConfigUtils.checkToolInstalled(
108+
this.pineConfig,
109+
toolName,
110+
required,
111+
);
54112

55-
if (!toolInfo || !toolInfo.installed) {
56-
if (required) {
113+
if (!isInstalled && required) {
57114
throw new Error(
58115
`${toolName} is not installed. Install it or check tool recommendations.`,
59116
);
60117
}
61-
return false;
118+
119+
return isInstalled;
120+
} catch (error) {
121+
// Use LoggingUtils for better error display
122+
if (required) {
123+
LoggingUtils.error(
124+
`PineScript tool '${toolName}' check failed:`,
125+
error.message,
126+
);
127+
LoggingUtils.info(`Run /pine-setup to install '${toolName}'`);
128+
}
129+
throw error;
62130
}
131+
}
63132

64-
return true;
133+
/**
134+
* Find PineScript files in the project
135+
*/
136+
findPineScriptFiles(pattern = "**/*.pine", excludePatterns = []) {
137+
try {
138+
return FileUtils.findFilesByPattern(this.projectPath, [pattern], {
139+
exclude: excludePatterns,
140+
language: "pinescript",
141+
});
142+
} catch (error) {
143+
LoggingUtils.warn("Failed to find PineScript files:", error.message);
144+
return [];
145+
}
146+
}
147+
148+
/**
149+
* Get PineScript project metadata
150+
*/
151+
getPineScriptProjectInfo() {
152+
try {
153+
const info = {
154+
hasPineFiles: this.findPineScriptFiles().length > 0,
155+
pineScriptFiles: this.findPineScriptFiles().length,
156+
hasConfig: fs.existsSync(path.join(this.projectPath, "config")),
157+
hasScripts: fs.existsSync(path.join(this.projectPath, "scripts")),
158+
hasIndicators: fs.existsSync(path.join(this.projectPath, "indicators")),
159+
hasStrategies: fs.existsSync(path.join(this.projectPath, "strategies")),
160+
};
161+
162+
return info;
163+
} catch (error) {
164+
LoggingUtils.debug(
165+
"Failed to get PineScript project info:",
166+
error.message,
167+
);
168+
return null;
169+
}
65170
}
66171

67172
/**
@@ -150,7 +255,7 @@ class PineCommandRunner {
150255
async executeCommand(command, args = [], options = {}) {
151256
return new Promise((resolve, reject) => {
152257
const fullCommand = [command, ...args].join(" ");
153-
console.log(`\n🚀 Executing: ${fullCommand}`);
258+
LoggingUtils.info(`\n🚀 Executing: ${fullCommand}`);
154259

155260
const child = spawn(command, args, {
156261
cwd: this.projectPath,
@@ -210,7 +315,7 @@ class PineCommandRunner {
210315
}
211316

212317
if (versionCheck.warning) {
213-
console.log(`⚠️ Warning: ${versionCheck.warning}`);
318+
LoggingUtils.warn(`⚠️ Warning: ${versionCheck.warning}`);
214319
}
215320

216321
// Basic validation checks
@@ -395,83 +500,66 @@ class PineCommandRunner {
395500
* Generate validation report
396501
*/
397502
generateValidationReport(results, options = {}) {
398-
console.log("\n📋 Validation Report");
399-
console.log("=".repeat(50));
400-
console.log(`File: ${results.file}`);
401-
console.log(`Version: ${results.version}`);
402-
console.log(`Checks: ${results.checks.length}`);
503+
LoggingUtils.info("\n📋 Validation Report");
504+
LoggingUtils.info("=".repeat(50));
505+
LoggingUtils.info(`File: ${results.file}`);
506+
LoggingUtils.info(`Version: ${results.version}`);
507+
LoggingUtils.info(`Checks: ${results.checks.length}`);
403508

404509
const errors = results.checks.filter((c) => c.type === "error");
405510
const warnings = results.checks.filter((c) => c.type === "warning");
406511
const info = results.checks.filter((c) => c.type === "info" && !c.debug);
407512
const debugSuggestions = results.checks.filter((c) => c.debug);
408513

409514
if (errors.length > 0) {
410-
console.log("\n❌ Errors:");
515+
LoggingUtils.error("\n❌ Errors:");
411516
errors.forEach((check, i) => {
412-
console.log(` ${i + 1}. ${check.message}`);
517+
LoggingUtils.error(` ${i + 1}. ${check.message}`);
413518
if (check.suggestion) {
414-
console.log(` 💡 ${check.suggestion}`);
519+
LoggingUtils.info(` 💡 ${check.suggestion}`);
415520
}
416521
});
417522
}
418523

419524
if (warnings.length > 0) {
420-
console.log("\n⚠️ Warnings:");
525+
LoggingUtils.warn("\n⚠️ Warnings:");
421526
warnings.forEach((check, i) => {
422-
console.log(` ${i + 1}. ${check.message}`);
527+
LoggingUtils.warn(` ${i + 1}. ${check.message}`);
423528
if (check.suggestion) {
424-
console.log(` 💡 ${check.suggestion}`);
529+
LoggingUtils.info(` 💡 ${check.suggestion}`);
425530
}
426531
});
427532
}
428533

429534
if (info.length > 0) {
430-
console.log("\nℹ️ Info:");
535+
LoggingUtils.info("\nℹ️ Info:");
431536
info.forEach((check, i) => {
432-
console.log(` ${i + 1}. ${check.message}`);
537+
LoggingUtils.info(` ${i + 1}. ${check.message}`);
433538
if (check.suggestion) {
434-
console.log(` 💡 ${check.suggestion}`);
539+
LoggingUtils.info(` 💡 ${check.suggestion}`);
435540
}
436541
});
437542
}
438543

439544
if (debugSuggestions.length > 0) {
440-
console.log("\n🔧 Debugging Suggestions:");
545+
LoggingUtils.info("\n🔧 Debugging Suggestions:");
441546
debugSuggestions.forEach((check, i) => {
442547
const icon = check.type === "warning" ? "⚠️" : "💡";
443-
console.log(` ${i + 1}. ${icon} ${check.message}`);
548+
LoggingUtils.info(` ${i + 1}. ${icon} ${check.message}`);
444549
if (check.suggestion) {
445-
console.log(` 🛠️ ${check.suggestion}`);
550+
LoggingUtils.info(` 🛠️ ${check.suggestion}`);
446551
}
447552
});
448553

449-
console.log("\n🚀 Quick Debugging Commands:");
450-
console.log(" /pine-debug inspect --var VARIABLE_NAME");
451-
console.log(" /pine-debug trace --var VARIABLE_NAME --plot");
452-
console.log(" /pine-debug profile --metrics complexity");
453-
console.log(" /pine-debug helpers --output debug-helpers.pine");
454-
}
455-
456-
if (warnings.length > 0) {
457-
console.log("\n⚠️ Warnings:");
458-
warnings.forEach((check, i) => {
459-
console.log(` ${i + 1}. ${check.message}`);
460-
if (check.suggestion) {
461-
console.log(` 💡 ${check.suggestion}`);
462-
}
463-
});
464-
}
465-
466-
if (info.length > 0) {
467-
console.log("\nℹ️ Info:");
468-
info.forEach((check, i) => {
469-
console.log(` ${i + 1}. ${check.message}`);
470-
});
554+
LoggingUtils.info("\n🚀 Quick Debugging Commands:");
555+
LoggingUtils.info(" /pine-debug inspect --var VARIABLE_NAME");
556+
LoggingUtils.info(" /pine-debug trace --var VARIABLE_NAME --plot");
557+
LoggingUtils.info(" /pine-debug profile --metrics complexity");
558+
LoggingUtils.info(" /pine-debug helpers --output debug-helpers.pine");
471559
}
472560

473561
if (errors.length === 0 && warnings.length === 0) {
474-
console.log("\n✅ No issues found!");
562+
LoggingUtils.info("\n✅ No issues found!");
475563
}
476564

477565
return {
@@ -533,51 +621,53 @@ Examples:
533621
const results = await runner.runValidation(args[1]);
534622
runner.generateValidationReport(results);
535623
} catch (error) {
536-
console.error(`❌ Validation failed: ${error.message}`);
624+
LoggingUtils.error(`❌ Validation failed: ${error.message}`);
537625
process.exit(1);
538626
}
539627
})
540628
.catch((error) => {
541-
console.error(`❌ Initialization failed: ${error.message}`);
629+
LoggingUtils.error(`❌ Initialization failed: ${error.message}`);
542630
process.exit(1);
543631
});
544632
} else if (args[0] === "config") {
545633
runner
546634
.initialize()
547635
.then(() => {
548636
const summary = runner.getConfigSummary();
549-
console.log("\n📊 PineScript Configuration Summary:");
550-
console.log(` • Version: v${summary.version}`);
551-
console.log(` • Project Type: ${summary.projectType}`);
552-
console.log(
637+
LoggingUtils.info("\n📊 PineScript Configuration Summary:");
638+
LoggingUtils.info(` • Version: v${summary.version}`);
639+
LoggingUtils.info(` • Project Type: ${summary.projectType}`);
640+
LoggingUtils.info(
553641
` • Backtesting: ${summary.backtesting ? "Enabled" : "Disabled"}`,
554642
);
555-
console.log(` • Alerts: ${summary.alerts ? "Enabled" : "Disabled"}`);
556-
console.log(
643+
LoggingUtils.info(
644+
` • Alerts: ${summary.alerts ? "Enabled" : "Disabled"}`,
645+
);
646+
LoggingUtils.info(
557647
` • TradingView Publish: ${summary.tradingview ? "Enabled" : "Disabled"}`,
558648
);
559649
})
560650
.catch((error) => {
561-
console.error(`❌ Failed to load configuration: ${error.message}`);
651+
LoggingUtils.error(`❌ Failed to load configuration: ${error.message}`);
562652
process.exit(1);
563653
});
564654
} else if (args[0] === "tools") {
565655
runner
566656
.initialize()
567657
.then(async () => {
568-
console.log("\n🔧 Detected Tools:");
658+
LoggingUtils.info("\n🔧 Detected Tools:");
569659
Object.entries(runner.detectedTools || {}).forEach(([name, info]) => {
570-
console.log(
660+
LoggingUtils.info(
571661
` ${info.installed ? "✅" : "❌"} ${name}: ${info.installed ? `v${info.version}` : "Not installed"}`,
572662
);
573663
});
574664
})
575665
.catch((error) => {
576-
console.error(`❌ Failed to load tools: ${error.message}`);
666+
LoggingUtils.error(`❌ Failed to load tools: ${error.message}`);
577667
process.exit(1);
578668
});
579669
} else {
580-
console.error("Unknown command. Use --help for usage information.");
670+
LoggingUtils.error("Unknown command. Use --help for usage information.");
581671
process.exit(1);
582672
}
583673
}

0 commit comments

Comments
 (0)