@probelabs/visor 0.1.71 → 0.1.73
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai-review-service.d.ts +1 -0
- package/dist/ai-review-service.d.ts.map +1 -1
- package/dist/check-execution-engine.d.ts +92 -3
- package/dist/check-execution-engine.d.ts.map +1 -1
- package/dist/cli-main.d.ts.map +1 -1
- package/dist/index.js +3958 -78
- package/dist/output-formatters.d.ts +2 -0
- package/dist/output-formatters.d.ts.map +1 -1
- package/dist/sdk/{check-execution-engine-TBF6LPYH.mjs → check-execution-engine-75SSXUBP.mjs} +2 -2
- package/dist/sdk/{chunk-745RDQD3.mjs → chunk-NINHE4RF.mjs} +304 -35
- package/dist/sdk/chunk-NINHE4RF.mjs.map +1 -0
- package/dist/sdk/sdk.d.mts +99 -60
- package/dist/sdk/sdk.d.ts +99 -60
- package/dist/sdk/sdk.js +302 -33
- package/dist/sdk/sdk.js.map +1 -1
- package/dist/sdk/sdk.mjs +1 -1
- package/package.json +3 -3
- package/dist/sdk/chunk-745RDQD3.mjs.map +0 -1
- /package/dist/sdk/{check-execution-engine-TBF6LPYH.mjs.map → check-execution-engine-75SSXUBP.mjs.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
process.env.VISOR_VERSION = '0.1.
|
|
3
|
-
process.env.PROBE_VERSION = '0.6.0-
|
|
2
|
+
process.env.VISOR_VERSION = '0.1.73';
|
|
3
|
+
process.env.PROBE_VERSION = '0.6.0-rc117';
|
|
4
4
|
/******/ (() => { // webpackBootstrap
|
|
5
5
|
/******/ var __webpack_modules__ = ({
|
|
6
6
|
|
|
@@ -94483,6 +94483,11 @@ ${prInfo.fullDiff ? this.escapeXml(prInfo.fullDiff) : ''}
|
|
|
94483
94483
|
allowEdit: false, // We don't want the agent to modify files
|
|
94484
94484
|
debug: this.config.debug || false,
|
|
94485
94485
|
};
|
|
94486
|
+
// Wire MCP configuration when provided
|
|
94487
|
+
if (this.config.mcpServers && Object.keys(this.config.mcpServers).length > 0) {
|
|
94488
|
+
options.enableMcp = true;
|
|
94489
|
+
options.mcpConfig = { mcpServers: this.config.mcpServers };
|
|
94490
|
+
}
|
|
94486
94491
|
// Add provider-specific options if configured
|
|
94487
94492
|
if (this.config.provider) {
|
|
94488
94493
|
// Map claude-code to anthropic for ProbeAgent compatibility
|
|
@@ -95094,6 +95099,7 @@ class CheckExecutionEngine {
|
|
|
95094
95099
|
config;
|
|
95095
95100
|
webhookContext;
|
|
95096
95101
|
routingSandbox;
|
|
95102
|
+
executionStats = new Map();
|
|
95097
95103
|
constructor(workingDirectory) {
|
|
95098
95104
|
this.workingDirectory = workingDirectory || process.cwd();
|
|
95099
95105
|
this.gitAnalyzer = new git_repository_analyzer_1.GitRepositoryAnalyzer(this.workingDirectory);
|
|
@@ -95655,12 +95661,15 @@ class CheckExecutionEngine {
|
|
|
95655
95661
|
apiCallDetails: reviewSummary.debug.apiCallDetails,
|
|
95656
95662
|
};
|
|
95657
95663
|
}
|
|
95664
|
+
// Build execution statistics
|
|
95665
|
+
const executionStatistics = this.buildExecutionStatistics();
|
|
95658
95666
|
return {
|
|
95659
95667
|
repositoryInfo,
|
|
95660
95668
|
reviewSummary,
|
|
95661
95669
|
executionTime,
|
|
95662
95670
|
timestamp,
|
|
95663
95671
|
checksExecuted: filteredChecks,
|
|
95672
|
+
executionStatistics,
|
|
95664
95673
|
debug: debugInfo,
|
|
95665
95674
|
};
|
|
95666
95675
|
}
|
|
@@ -95856,7 +95865,7 @@ class CheckExecutionEngine {
|
|
|
95856
95865
|
});
|
|
95857
95866
|
}
|
|
95858
95867
|
/**
|
|
95859
|
-
* Execute review checks and return grouped results for new architecture
|
|
95868
|
+
* Execute review checks and return grouped results with statistics for new architecture
|
|
95860
95869
|
*/
|
|
95861
95870
|
async executeGroupedChecks(prInfo, checks, timeout, config, outputFormat, debug, maxParallelism, failFast, tagFilter) {
|
|
95862
95871
|
// Determine where to send log messages based on output format
|
|
@@ -95885,7 +95894,10 @@ class CheckExecutionEngine {
|
|
|
95885
95894
|
// Check if we have any checks left after filtering
|
|
95886
95895
|
if (checks.length === 0) {
|
|
95887
95896
|
logger_1.logger.warn('⚠️ No checks remain after tag filtering');
|
|
95888
|
-
return {
|
|
95897
|
+
return {
|
|
95898
|
+
results: {},
|
|
95899
|
+
statistics: this.buildExecutionStatistics(),
|
|
95900
|
+
};
|
|
95889
95901
|
}
|
|
95890
95902
|
if (!config?.checks) {
|
|
95891
95903
|
throw new Error('Config with check definitions required for grouped execution');
|
|
@@ -95909,10 +95921,16 @@ class CheckExecutionEngine {
|
|
|
95909
95921
|
const checkResult = await this.executeSingleGroupedCheck(prInfo, checks[0], timeout, config, logFn, debug);
|
|
95910
95922
|
const groupedResults = {};
|
|
95911
95923
|
groupedResults[checkResult.group] = [checkResult];
|
|
95912
|
-
return
|
|
95924
|
+
return {
|
|
95925
|
+
results: groupedResults,
|
|
95926
|
+
statistics: this.buildExecutionStatistics(),
|
|
95927
|
+
};
|
|
95913
95928
|
}
|
|
95914
95929
|
// No checks to execute
|
|
95915
|
-
return {
|
|
95930
|
+
return {
|
|
95931
|
+
results: {},
|
|
95932
|
+
statistics: this.buildExecutionStatistics(),
|
|
95933
|
+
};
|
|
95916
95934
|
}
|
|
95917
95935
|
/**
|
|
95918
95936
|
* Execute single check and return grouped result
|
|
@@ -95957,13 +95975,19 @@ class CheckExecutionEngine {
|
|
|
95957
95975
|
};
|
|
95958
95976
|
}
|
|
95959
95977
|
/**
|
|
95960
|
-
* Execute multiple checks with dependency awareness - return grouped results
|
|
95978
|
+
* Execute multiple checks with dependency awareness - return grouped results with statistics
|
|
95961
95979
|
*/
|
|
95962
95980
|
async executeGroupedDependencyAwareChecks(prInfo, checks, timeout, config, logFn, debug, maxParallelism, failFast) {
|
|
95963
95981
|
// Use the existing dependency-aware execution logic
|
|
95964
95982
|
const reviewSummary = await this.executeDependencyAwareChecks(prInfo, checks, timeout, config, logFn, debug, maxParallelism, failFast);
|
|
95983
|
+
// Build execution statistics
|
|
95984
|
+
const executionStatistics = this.buildExecutionStatistics();
|
|
95965
95985
|
// Convert the flat ReviewSummary to grouped CheckResults
|
|
95966
|
-
|
|
95986
|
+
const groupedResults = await this.convertReviewSummaryToGroupedResults(reviewSummary, checks, config, prInfo);
|
|
95987
|
+
return {
|
|
95988
|
+
results: groupedResults,
|
|
95989
|
+
statistics: executionStatistics,
|
|
95990
|
+
};
|
|
95967
95991
|
}
|
|
95968
95992
|
/**
|
|
95969
95993
|
* Convert ReviewSummary to GroupedCheckResults
|
|
@@ -96276,9 +96300,10 @@ class CheckExecutionEngine {
|
|
|
96276
96300
|
let shouldStopExecution = false;
|
|
96277
96301
|
let completedChecksCount = 0;
|
|
96278
96302
|
const totalChecksCount = stats.totalChecks;
|
|
96279
|
-
|
|
96280
|
-
|
|
96281
|
-
|
|
96303
|
+
// Initialize execution statistics for all checks
|
|
96304
|
+
for (const checkName of checks) {
|
|
96305
|
+
this.initializeCheckStats(checkName);
|
|
96306
|
+
}
|
|
96282
96307
|
for (let levelIndex = 0; levelIndex < dependencyGraph.executionOrder.length && !shouldStopExecution; levelIndex++) {
|
|
96283
96308
|
const executionGroup = dependencyGraph.executionOrder[levelIndex];
|
|
96284
96309
|
// Check if any checks in this level require session reuse - if so, force sequential execution
|
|
@@ -96411,9 +96436,13 @@ class CheckExecutionEngine {
|
|
|
96411
96436
|
// Handle forEach dependent execution
|
|
96412
96437
|
let finalResult;
|
|
96413
96438
|
if (isForEachDependent && forEachParentName) {
|
|
96439
|
+
// Record forEach preview items
|
|
96440
|
+
this.recordForEachPreview(checkName, forEachItems);
|
|
96414
96441
|
if (debug) {
|
|
96415
96442
|
log(`🔄 Debug: Check "${checkName}" depends on forEach check "${forEachParentName}", executing ${forEachItems.length} times`);
|
|
96416
96443
|
}
|
|
96444
|
+
// Log forEach processing start
|
|
96445
|
+
logger_1.logger.info(` Processing ${forEachItems.length} items...`);
|
|
96417
96446
|
const allIssues = [];
|
|
96418
96447
|
const allOutputs = [];
|
|
96419
96448
|
const aggregatedContents = [];
|
|
@@ -96474,6 +96503,8 @@ class CheckExecutionEngine {
|
|
|
96474
96503
|
if (debug) {
|
|
96475
96504
|
log(`🔄 Debug: Executing check "${checkName}" for item ${itemIndex + 1}/${forEachItems.length}`);
|
|
96476
96505
|
}
|
|
96506
|
+
// Track iteration start
|
|
96507
|
+
const iterationStart = this.recordIterationStart(checkName);
|
|
96477
96508
|
// Execute with retry/routing semantics per item
|
|
96478
96509
|
const itemResult = await this.executeWithRouting(checkName, checkConfig, provider, providerConfig, prInfo, forEachDependencyResults, sessionInfo, config, dependencyGraph, debug, results,
|
|
96479
96510
|
/*foreachContext*/ {
|
|
@@ -96481,6 +96512,11 @@ class CheckExecutionEngine {
|
|
|
96481
96512
|
total: forEachItems.length,
|
|
96482
96513
|
parent: forEachParentName,
|
|
96483
96514
|
});
|
|
96515
|
+
// Record iteration completion
|
|
96516
|
+
const iterationDuration = (Date.now() - iterationStart) / 1000;
|
|
96517
|
+
this.recordIterationComplete(checkName, iterationStart, true, itemResult.issues || [], itemResult.output);
|
|
96518
|
+
// Log iteration progress
|
|
96519
|
+
logger_1.logger.info(` ✔ ${itemIndex + 1}/${forEachItems.length} (${iterationDuration.toFixed(1)}s)`);
|
|
96484
96520
|
return { index: itemIndex, itemResult };
|
|
96485
96521
|
});
|
|
96486
96522
|
const forEachConcurrency = Math.max(1, Math.min(forEachItems.length, effectiveMaxParallelism));
|
|
@@ -96532,8 +96568,9 @@ class CheckExecutionEngine {
|
|
|
96532
96568
|
if (checkConfig.if) {
|
|
96533
96569
|
const shouldRun = await this.evaluateCheckCondition(checkName, checkConfig.if, prInfo, results, debug);
|
|
96534
96570
|
if (!shouldRun) {
|
|
96535
|
-
|
|
96536
|
-
|
|
96571
|
+
// Record skip with condition
|
|
96572
|
+
this.recordSkip(checkName, 'if_condition', checkConfig.if);
|
|
96573
|
+
logger_1.logger.info(`⏭ Skipped (if: ${this.truncate(checkConfig.if, 40)})`);
|
|
96537
96574
|
return {
|
|
96538
96575
|
checkName,
|
|
96539
96576
|
error: null,
|
|
@@ -96546,6 +96583,8 @@ class CheckExecutionEngine {
|
|
|
96546
96583
|
}
|
|
96547
96584
|
// Execute with retry/routing semantics
|
|
96548
96585
|
finalResult = await this.executeWithRouting(checkName, checkConfig, provider, providerConfig, prInfo, dependencyResults, sessionInfo, config, dependencyGraph, debug, results);
|
|
96586
|
+
// Record normal (non-forEach) execution
|
|
96587
|
+
this.recordIterationComplete(checkName, checkStartTime, true, finalResult.issues || [], finalResult.output);
|
|
96549
96588
|
if (checkConfig.forEach) {
|
|
96550
96589
|
try {
|
|
96551
96590
|
const finalResultWithOutput = finalResult;
|
|
@@ -96576,7 +96615,20 @@ class CheckExecutionEngine {
|
|
|
96576
96615
|
};
|
|
96577
96616
|
const checkDuration = ((Date.now() - checkStartTime) / 1000).toFixed(1);
|
|
96578
96617
|
const issueCount = enrichedIssues.length;
|
|
96579
|
-
|
|
96618
|
+
const checkStats = this.executionStats.get(checkName);
|
|
96619
|
+
// Enhanced completion message with forEach stats
|
|
96620
|
+
if (checkStats && checkStats.totalRuns > 1) {
|
|
96621
|
+
if (issueCount > 0) {
|
|
96622
|
+
logger_1.logger.success(`Check complete: ${checkName} (${checkDuration}s) - ${checkStats.totalRuns} runs, ${issueCount} issue${issueCount === 1 ? '' : 's'}`);
|
|
96623
|
+
}
|
|
96624
|
+
else {
|
|
96625
|
+
logger_1.logger.success(`Check complete: ${checkName} (${checkDuration}s) - ${checkStats.totalRuns} runs`);
|
|
96626
|
+
}
|
|
96627
|
+
}
|
|
96628
|
+
else if (checkStats && checkStats.outputsProduced && checkStats.outputsProduced > 0) {
|
|
96629
|
+
logger_1.logger.success(`Check complete: ${checkName} (${checkDuration}s) - ${checkStats.outputsProduced} items`);
|
|
96630
|
+
}
|
|
96631
|
+
else if (issueCount > 0) {
|
|
96580
96632
|
logger_1.logger.success(`Check complete: ${checkName} (${checkDuration}s) - ${issueCount} issue${issueCount === 1 ? '' : 's'} found`);
|
|
96581
96633
|
}
|
|
96582
96634
|
else {
|
|
@@ -96589,9 +96641,11 @@ class CheckExecutionEngine {
|
|
|
96589
96641
|
};
|
|
96590
96642
|
}
|
|
96591
96643
|
catch (error) {
|
|
96592
|
-
failedChecksCount++;
|
|
96593
96644
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
96594
96645
|
const checkDuration = ((Date.now() - checkStartTime) / 1000).toFixed(1);
|
|
96646
|
+
// Record error in stats
|
|
96647
|
+
this.recordError(checkName, error instanceof Error ? error : new Error(String(error)));
|
|
96648
|
+
this.recordIterationComplete(checkName, checkStartTime, false, [], undefined);
|
|
96595
96649
|
logger_1.logger.error(`✖ Check failed: ${checkName} (${checkDuration}s) - ${errorMessage}`);
|
|
96596
96650
|
if (debug) {
|
|
96597
96651
|
log(`🔧 Debug: Error in check ${checkName}: ${errorMessage}`);
|
|
@@ -96709,20 +96763,18 @@ class CheckExecutionEngine {
|
|
|
96709
96763
|
}
|
|
96710
96764
|
}
|
|
96711
96765
|
}
|
|
96712
|
-
//
|
|
96713
|
-
const
|
|
96714
|
-
|
|
96715
|
-
|
|
96716
|
-
|
|
96717
|
-
|
|
96718
|
-
|
|
96719
|
-
logger_1.logger.info(` ⏭ Skipped: ${skippedChecksCount}`);
|
|
96720
|
-
}
|
|
96721
|
-
if (failedChecksCount > 0) {
|
|
96722
|
-
logger_1.logger.info(` ✖ Failed: ${failedChecksCount}`);
|
|
96766
|
+
// Build and log final execution summary
|
|
96767
|
+
const executionStatistics = this.buildExecutionStatistics();
|
|
96768
|
+
// Show detailed summary table (only if logFn outputs to console)
|
|
96769
|
+
// Skip when output format is JSON/SARIF to avoid polluting structured output
|
|
96770
|
+
// Check if logFn is console.log (not a no-op or console.error)
|
|
96771
|
+
if (logFn === console.log) {
|
|
96772
|
+
this.logExecutionSummary(executionStatistics);
|
|
96723
96773
|
}
|
|
96774
|
+
// Add warning if execution stopped early
|
|
96724
96775
|
if (shouldStopExecution) {
|
|
96725
|
-
logger_1.logger.
|
|
96776
|
+
logger_1.logger.info('');
|
|
96777
|
+
logger_1.logger.warn(`⚠️ Execution stopped early due to fail-fast`);
|
|
96726
96778
|
}
|
|
96727
96779
|
if (debug) {
|
|
96728
96780
|
if (shouldStopExecution) {
|
|
@@ -97661,6 +97713,251 @@ class CheckExecutionEngine {
|
|
|
97661
97713
|
// events, which don't generate PRInfo objects in the first place.
|
|
97662
97714
|
return 'pr_updated';
|
|
97663
97715
|
}
|
|
97716
|
+
/**
|
|
97717
|
+
* Initialize execution statistics for a check
|
|
97718
|
+
*/
|
|
97719
|
+
initializeCheckStats(checkName) {
|
|
97720
|
+
this.executionStats.set(checkName, {
|
|
97721
|
+
checkName,
|
|
97722
|
+
totalRuns: 0,
|
|
97723
|
+
successfulRuns: 0,
|
|
97724
|
+
failedRuns: 0,
|
|
97725
|
+
skipped: false,
|
|
97726
|
+
totalDuration: 0,
|
|
97727
|
+
issuesFound: 0,
|
|
97728
|
+
issuesBySeverity: {
|
|
97729
|
+
critical: 0,
|
|
97730
|
+
error: 0,
|
|
97731
|
+
warning: 0,
|
|
97732
|
+
info: 0,
|
|
97733
|
+
},
|
|
97734
|
+
perIterationDuration: [],
|
|
97735
|
+
});
|
|
97736
|
+
}
|
|
97737
|
+
/**
|
|
97738
|
+
* Record the start of a check iteration
|
|
97739
|
+
* Returns the start timestamp for duration tracking
|
|
97740
|
+
*/
|
|
97741
|
+
recordIterationStart(_checkName) {
|
|
97742
|
+
return Date.now();
|
|
97743
|
+
}
|
|
97744
|
+
/**
|
|
97745
|
+
* Record completion of a check iteration
|
|
97746
|
+
*/
|
|
97747
|
+
recordIterationComplete(checkName, startTime, success, issues, output) {
|
|
97748
|
+
const stats = this.executionStats.get(checkName);
|
|
97749
|
+
if (!stats)
|
|
97750
|
+
return;
|
|
97751
|
+
const duration = Date.now() - startTime;
|
|
97752
|
+
stats.totalRuns++;
|
|
97753
|
+
if (success) {
|
|
97754
|
+
stats.successfulRuns++;
|
|
97755
|
+
}
|
|
97756
|
+
else {
|
|
97757
|
+
stats.failedRuns++;
|
|
97758
|
+
}
|
|
97759
|
+
stats.totalDuration += duration;
|
|
97760
|
+
stats.perIterationDuration.push(duration);
|
|
97761
|
+
// Count issues by severity
|
|
97762
|
+
for (const issue of issues) {
|
|
97763
|
+
stats.issuesFound++;
|
|
97764
|
+
if (issue.severity === 'critical')
|
|
97765
|
+
stats.issuesBySeverity.critical++;
|
|
97766
|
+
else if (issue.severity === 'error')
|
|
97767
|
+
stats.issuesBySeverity.error++;
|
|
97768
|
+
else if (issue.severity === 'warning')
|
|
97769
|
+
stats.issuesBySeverity.warning++;
|
|
97770
|
+
else if (issue.severity === 'info')
|
|
97771
|
+
stats.issuesBySeverity.info++;
|
|
97772
|
+
}
|
|
97773
|
+
// Track outputs produced
|
|
97774
|
+
if (output !== undefined) {
|
|
97775
|
+
stats.outputsProduced = (stats.outputsProduced || 0) + 1;
|
|
97776
|
+
}
|
|
97777
|
+
}
|
|
97778
|
+
/**
|
|
97779
|
+
* Record that a check was skipped
|
|
97780
|
+
*/
|
|
97781
|
+
recordSkip(checkName, reason, condition) {
|
|
97782
|
+
const stats = this.executionStats.get(checkName);
|
|
97783
|
+
if (!stats)
|
|
97784
|
+
return;
|
|
97785
|
+
stats.skipped = true;
|
|
97786
|
+
stats.skipReason = reason;
|
|
97787
|
+
if (condition) {
|
|
97788
|
+
stats.skipCondition = condition;
|
|
97789
|
+
}
|
|
97790
|
+
}
|
|
97791
|
+
/**
|
|
97792
|
+
* Record forEach preview items
|
|
97793
|
+
*/
|
|
97794
|
+
recordForEachPreview(checkName, items) {
|
|
97795
|
+
const stats = this.executionStats.get(checkName);
|
|
97796
|
+
if (!stats || !items.length)
|
|
97797
|
+
return;
|
|
97798
|
+
// Store preview of first 3 items
|
|
97799
|
+
const preview = items.slice(0, 3).map(item => {
|
|
97800
|
+
const str = typeof item === 'string' ? item : JSON.stringify(item);
|
|
97801
|
+
return str.length > 50 ? str.substring(0, 47) + '...' : str;
|
|
97802
|
+
});
|
|
97803
|
+
if (items.length > 3) {
|
|
97804
|
+
preview.push(`...${items.length - 3} more`);
|
|
97805
|
+
}
|
|
97806
|
+
stats.forEachPreview = preview;
|
|
97807
|
+
}
|
|
97808
|
+
/**
|
|
97809
|
+
* Record an error for a check
|
|
97810
|
+
*/
|
|
97811
|
+
recordError(checkName, error) {
|
|
97812
|
+
const stats = this.executionStats.get(checkName);
|
|
97813
|
+
if (!stats)
|
|
97814
|
+
return;
|
|
97815
|
+
stats.errorMessage = error instanceof Error ? error.message : String(error);
|
|
97816
|
+
}
|
|
97817
|
+
/**
|
|
97818
|
+
* Build the final execution statistics object
|
|
97819
|
+
*/
|
|
97820
|
+
buildExecutionStatistics() {
|
|
97821
|
+
const checks = Array.from(this.executionStats.values());
|
|
97822
|
+
const totalExecutions = checks.reduce((sum, s) => sum + s.totalRuns, 0);
|
|
97823
|
+
const successfulExecutions = checks.reduce((sum, s) => sum + s.successfulRuns, 0);
|
|
97824
|
+
const failedExecutions = checks.reduce((sum, s) => sum + s.failedRuns, 0);
|
|
97825
|
+
const skippedChecks = checks.filter(s => s.skipped).length;
|
|
97826
|
+
const totalDuration = checks.reduce((sum, s) => sum + s.totalDuration, 0);
|
|
97827
|
+
return {
|
|
97828
|
+
totalChecksConfigured: checks.length,
|
|
97829
|
+
totalExecutions,
|
|
97830
|
+
successfulExecutions,
|
|
97831
|
+
failedExecutions,
|
|
97832
|
+
skippedChecks,
|
|
97833
|
+
totalDuration,
|
|
97834
|
+
checks,
|
|
97835
|
+
};
|
|
97836
|
+
}
|
|
97837
|
+
/**
|
|
97838
|
+
* Truncate a string to max length with ellipsis
|
|
97839
|
+
*/
|
|
97840
|
+
truncate(str, maxLen) {
|
|
97841
|
+
if (str.length <= maxLen)
|
|
97842
|
+
return str;
|
|
97843
|
+
return str.substring(0, maxLen - 3) + '...';
|
|
97844
|
+
}
|
|
97845
|
+
/**
|
|
97846
|
+
* Format the Status column for execution summary table
|
|
97847
|
+
*/
|
|
97848
|
+
formatStatusColumn(stats) {
|
|
97849
|
+
if (stats.skipped) {
|
|
97850
|
+
if (stats.skipReason === 'if_condition')
|
|
97851
|
+
return '⏭ if';
|
|
97852
|
+
if (stats.skipReason === 'fail_fast')
|
|
97853
|
+
return '⏭ ff';
|
|
97854
|
+
if (stats.skipReason === 'dependency_failed')
|
|
97855
|
+
return '⏭ dep';
|
|
97856
|
+
return '⏭';
|
|
97857
|
+
}
|
|
97858
|
+
if (stats.totalRuns === 0)
|
|
97859
|
+
return '-';
|
|
97860
|
+
const symbol = stats.failedRuns === 0 ? '✔' : stats.successfulRuns === 0 ? '✖' : '✔/✖';
|
|
97861
|
+
// Show iteration count if > 1
|
|
97862
|
+
if (stats.totalRuns > 1) {
|
|
97863
|
+
if (stats.failedRuns > 0 && stats.successfulRuns > 0) {
|
|
97864
|
+
// Partial success
|
|
97865
|
+
return `${symbol} ${stats.successfulRuns}/${stats.totalRuns}`;
|
|
97866
|
+
}
|
|
97867
|
+
else {
|
|
97868
|
+
// All success or all failed
|
|
97869
|
+
return `${symbol} ×${stats.totalRuns}`;
|
|
97870
|
+
}
|
|
97871
|
+
}
|
|
97872
|
+
return symbol;
|
|
97873
|
+
}
|
|
97874
|
+
/**
|
|
97875
|
+
* Format the Details column for execution summary table
|
|
97876
|
+
*/
|
|
97877
|
+
formatDetailsColumn(stats) {
|
|
97878
|
+
const parts = [];
|
|
97879
|
+
// Outputs produced (forEach)
|
|
97880
|
+
if (stats.outputsProduced && stats.outputsProduced > 0) {
|
|
97881
|
+
parts.push(`→${stats.outputsProduced}`);
|
|
97882
|
+
}
|
|
97883
|
+
// Critical issues
|
|
97884
|
+
if (stats.issuesBySeverity.critical > 0) {
|
|
97885
|
+
parts.push(`${stats.issuesBySeverity.critical}🔴`);
|
|
97886
|
+
}
|
|
97887
|
+
// Warnings
|
|
97888
|
+
if (stats.issuesBySeverity.warning > 0) {
|
|
97889
|
+
parts.push(`${stats.issuesBySeverity.warning}⚠️`);
|
|
97890
|
+
}
|
|
97891
|
+
// Info (only if no critical/warnings)
|
|
97892
|
+
if (stats.issuesBySeverity.info > 0 &&
|
|
97893
|
+
stats.issuesBySeverity.critical === 0 &&
|
|
97894
|
+
stats.issuesBySeverity.warning === 0) {
|
|
97895
|
+
parts.push(`${stats.issuesBySeverity.info}💡`);
|
|
97896
|
+
}
|
|
97897
|
+
// Error message or skip condition
|
|
97898
|
+
if (stats.errorMessage) {
|
|
97899
|
+
parts.push(this.truncate(stats.errorMessage, 20));
|
|
97900
|
+
}
|
|
97901
|
+
else if (stats.skipCondition) {
|
|
97902
|
+
parts.push(this.truncate(stats.skipCondition, 20));
|
|
97903
|
+
}
|
|
97904
|
+
return parts.join(' ');
|
|
97905
|
+
}
|
|
97906
|
+
/**
|
|
97907
|
+
* Log the execution summary table
|
|
97908
|
+
*/
|
|
97909
|
+
logExecutionSummary(stats) {
|
|
97910
|
+
const totalIssues = stats.checks.reduce((sum, s) => sum + s.issuesFound, 0);
|
|
97911
|
+
const criticalIssues = stats.checks.reduce((sum, s) => sum + s.issuesBySeverity.critical, 0);
|
|
97912
|
+
const warningIssues = stats.checks.reduce((sum, s) => sum + s.issuesBySeverity.warning, 0);
|
|
97913
|
+
const durationSec = (stats.totalDuration / 1000).toFixed(1);
|
|
97914
|
+
// Summary box
|
|
97915
|
+
const summaryTable = new (__nccwpck_require__(25832))({
|
|
97916
|
+
style: {
|
|
97917
|
+
head: [],
|
|
97918
|
+
border: [],
|
|
97919
|
+
},
|
|
97920
|
+
colWidths: [41],
|
|
97921
|
+
});
|
|
97922
|
+
summaryTable.push([`Execution Complete (${durationSec}s)`], [`Checks: ${stats.totalChecksConfigured} configured → ${stats.totalExecutions} executions`], [
|
|
97923
|
+
`Status: ${stats.successfulExecutions} ✔ │ ${stats.failedExecutions} ✖ │ ${stats.skippedChecks} ⏭`,
|
|
97924
|
+
]);
|
|
97925
|
+
if (totalIssues > 0) {
|
|
97926
|
+
let issuesLine = `Issues: ${totalIssues} total`;
|
|
97927
|
+
if (criticalIssues > 0)
|
|
97928
|
+
issuesLine += ` (${criticalIssues} 🔴`;
|
|
97929
|
+
if (warningIssues > 0)
|
|
97930
|
+
issuesLine += `${criticalIssues > 0 ? ' ' : ' ('}${warningIssues} ⚠️)`;
|
|
97931
|
+
else if (criticalIssues > 0)
|
|
97932
|
+
issuesLine += ')';
|
|
97933
|
+
summaryTable.push([issuesLine]);
|
|
97934
|
+
}
|
|
97935
|
+
logger_1.logger.info('');
|
|
97936
|
+
logger_1.logger.info(summaryTable.toString());
|
|
97937
|
+
// Details table
|
|
97938
|
+
logger_1.logger.info('');
|
|
97939
|
+
logger_1.logger.info('Check Details:');
|
|
97940
|
+
const detailsTable = new (__nccwpck_require__(25832))({
|
|
97941
|
+
head: ['Check', 'Duration', 'Status', 'Details'],
|
|
97942
|
+
colWidths: [21, 10, 10, 21],
|
|
97943
|
+
style: {
|
|
97944
|
+
head: ['cyan'],
|
|
97945
|
+
border: ['grey'],
|
|
97946
|
+
},
|
|
97947
|
+
});
|
|
97948
|
+
for (const checkStats of stats.checks) {
|
|
97949
|
+
const duration = checkStats.skipped
|
|
97950
|
+
? '-'
|
|
97951
|
+
: `${(checkStats.totalDuration / 1000).toFixed(1)}s`;
|
|
97952
|
+
const status = this.formatStatusColumn(checkStats);
|
|
97953
|
+
const details = this.formatDetailsColumn(checkStats);
|
|
97954
|
+
detailsTable.push([checkStats.checkName, duration, status, details]);
|
|
97955
|
+
}
|
|
97956
|
+
logger_1.logger.info(detailsTable.toString());
|
|
97957
|
+
// Legend
|
|
97958
|
+
logger_1.logger.info('');
|
|
97959
|
+
logger_1.logger.info('Legend: ✔=success │ ✖=failed │ ⏭=skipped │ ×N=iterations │ →N=outputs │ N🔴=critical │ N⚠️=warnings');
|
|
97960
|
+
}
|
|
97664
97961
|
}
|
|
97665
97962
|
exports.CheckExecutionEngine = CheckExecutionEngine;
|
|
97666
97963
|
|
|
@@ -97747,7 +98044,15 @@ async function main() {
|
|
|
97747
98044
|
console.log(cli.getVersion());
|
|
97748
98045
|
process.exit(0);
|
|
97749
98046
|
}
|
|
98047
|
+
// Configure logger based on output format and verbosity
|
|
98048
|
+
logger_1.logger.configure({
|
|
98049
|
+
outputFormat: options.output,
|
|
98050
|
+
debug: options.debug,
|
|
98051
|
+
verbose: options.verbose,
|
|
98052
|
+
quiet: options.quiet,
|
|
98053
|
+
});
|
|
97750
98054
|
// Print runtime banner (info level): Visor + Probe versions
|
|
98055
|
+
// Banner is automatically suppressed for JSON/SARIF by logger configuration
|
|
97751
98056
|
try {
|
|
97752
98057
|
const visorVersion = process.env.VISOR_VERSION || ((__nccwpck_require__(8330)/* .version */ .rE) ?? 'dev');
|
|
97753
98058
|
let probeVersion = process.env.PROBE_VERSION || 'unknown';
|
|
@@ -97915,7 +98220,9 @@ async function main() {
|
|
|
97915
98220
|
const prInfoWithContext = prInfo;
|
|
97916
98221
|
prInfoWithContext.includeCodeContext = includeCodeContext;
|
|
97917
98222
|
// Execute checks with proper parameters
|
|
97918
|
-
const
|
|
98223
|
+
const executionResult = await engine.executeGroupedChecks(prInfo, checksToRun, options.timeout, config, options.output, options.debug || false, options.maxParallelism, options.failFast, tagFilter);
|
|
98224
|
+
// Extract results and statistics from the execution result
|
|
98225
|
+
const { results: groupedResults, statistics: executionStatistics } = executionResult;
|
|
97919
98226
|
const shouldFilterResults = explicitChecks && explicitChecks.size > 0 && !explicitChecks.has('all');
|
|
97920
98227
|
const groupedResultsToUse = shouldFilterResults
|
|
97921
98228
|
? Object.fromEntries(Object.entries(groupedResults)
|
|
@@ -97940,7 +98247,8 @@ async function main() {
|
|
|
97940
98247
|
}
|
|
97941
98248
|
}
|
|
97942
98249
|
}
|
|
97943
|
-
|
|
98250
|
+
// Get executed check names
|
|
98251
|
+
const executedCheckNames = Array.from(new Set(Object.entries(groupedResultsToUse).flatMap(([, checks]) => checks.map(check => check.checkName))));
|
|
97944
98252
|
// Format output based on format type
|
|
97945
98253
|
logger_1.logger.step(`Formatting results as ${options.output}`);
|
|
97946
98254
|
let output;
|
|
@@ -97953,12 +98261,14 @@ async function main() {
|
|
|
97953
98261
|
repositoryInfo,
|
|
97954
98262
|
reviewSummary: {
|
|
97955
98263
|
issues: Object.values(groupedResultsToUse)
|
|
97956
|
-
.flatMap(
|
|
98264
|
+
.flatMap(checks => checks.flatMap(check => check.issues || []))
|
|
97957
98265
|
.flat(),
|
|
97958
98266
|
},
|
|
97959
98267
|
executionTime: 0,
|
|
97960
98268
|
timestamp: new Date().toISOString(),
|
|
97961
98269
|
checksExecuted: executedCheckNames,
|
|
98270
|
+
executionStatistics,
|
|
98271
|
+
isCodeReview: includeCodeContext,
|
|
97962
98272
|
};
|
|
97963
98273
|
output = output_formatters_1.OutputFormatters.formatAsSarif(analysisResult);
|
|
97964
98274
|
}
|
|
@@ -97968,12 +98278,14 @@ async function main() {
|
|
|
97968
98278
|
repositoryInfo,
|
|
97969
98279
|
reviewSummary: {
|
|
97970
98280
|
issues: Object.values(groupedResultsToUse)
|
|
97971
|
-
.flatMap(
|
|
98281
|
+
.flatMap(checks => checks.flatMap(check => check.issues || []))
|
|
97972
98282
|
.flat(),
|
|
97973
98283
|
},
|
|
97974
98284
|
executionTime: 0,
|
|
97975
98285
|
timestamp: new Date().toISOString(),
|
|
97976
98286
|
checksExecuted: executedCheckNames,
|
|
98287
|
+
executionStatistics,
|
|
98288
|
+
isCodeReview: includeCodeContext,
|
|
97977
98289
|
};
|
|
97978
98290
|
output = output_formatters_1.OutputFormatters.formatAsMarkdown(analysisResult);
|
|
97979
98291
|
}
|
|
@@ -97983,12 +98295,14 @@ async function main() {
|
|
|
97983
98295
|
repositoryInfo,
|
|
97984
98296
|
reviewSummary: {
|
|
97985
98297
|
issues: Object.values(groupedResultsToUse)
|
|
97986
|
-
.flatMap(
|
|
98298
|
+
.flatMap(checks => checks.flatMap(check => check.issues || []))
|
|
97987
98299
|
.flat(),
|
|
97988
98300
|
},
|
|
97989
98301
|
executionTime: 0,
|
|
97990
98302
|
timestamp: new Date().toISOString(),
|
|
97991
98303
|
checksExecuted: executedCheckNames,
|
|
98304
|
+
executionStatistics,
|
|
98305
|
+
isCodeReview: includeCodeContext,
|
|
97992
98306
|
};
|
|
97993
98307
|
output = output_formatters_1.OutputFormatters.formatAsTable(analysisResult, { showDetails: true });
|
|
97994
98308
|
}
|
|
@@ -98009,7 +98323,7 @@ async function main() {
|
|
|
98009
98323
|
console.log(output);
|
|
98010
98324
|
}
|
|
98011
98325
|
// Summarize execution (stderr only; suppressed in JSON/SARIF unless verbose/debug)
|
|
98012
|
-
const allResults = Object.values(groupedResultsToUse).
|
|
98326
|
+
const allResults = Object.values(groupedResultsToUse).flatMap(checks => checks);
|
|
98013
98327
|
const allIssues = allResults.flatMap((r) => r.issues || []);
|
|
98014
98328
|
const counts = allIssues.reduce((acc, issue) => {
|
|
98015
98329
|
const sev = (issue.severity || 'info').toLowerCase();
|
|
@@ -101532,14 +101846,15 @@ async function handleIssueEvent(octokit, owner, repo, context, inputs, config, c
|
|
|
101532
101846
|
const { CheckExecutionEngine } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(80299)));
|
|
101533
101847
|
const engine = new CheckExecutionEngine();
|
|
101534
101848
|
try {
|
|
101535
|
-
const
|
|
101849
|
+
const executionResult = await engine.executeGroupedChecks(prInfo, checksToRun, undefined, // timeout
|
|
101536
101850
|
config, undefined, // outputFormat
|
|
101537
101851
|
inputs.debug === 'true');
|
|
101852
|
+
const { results } = executionResult;
|
|
101538
101853
|
// Format and post results as a comment on the issue
|
|
101539
|
-
if (Object.keys(
|
|
101854
|
+
if (Object.keys(results).length > 0) {
|
|
101540
101855
|
let commentBody = '';
|
|
101541
101856
|
// Directly use check content without adding extra headers
|
|
101542
|
-
for (const checks of Object.values(
|
|
101857
|
+
for (const checks of Object.values(results)) {
|
|
101543
101858
|
for (const check of checks) {
|
|
101544
101859
|
if (check.content && check.content.trim()) {
|
|
101545
101860
|
commentBody += `${check.content}\n\n`;
|
|
@@ -101798,7 +102113,7 @@ async function handleIssueComment(octokit, owner, repo, context, inputs, actionC
|
|
|
101798
102113
|
console.log('📝 Skipping comment (comment-on-pr is disabled)');
|
|
101799
102114
|
}
|
|
101800
102115
|
// Calculate total check results from grouped results
|
|
101801
|
-
const totalChecks = Object.values(groupedResults).
|
|
102116
|
+
const totalChecks = Object.values(groupedResults).flatMap(checks => checks).length;
|
|
101802
102117
|
(0, core_1.setOutput)('checks-executed', totalChecks.toString());
|
|
101803
102118
|
}
|
|
101804
102119
|
break;
|
|
@@ -102118,7 +102433,7 @@ async function completeGitHubChecks(octokit, owner, repo, checkRunMap, groupedRe
|
|
|
102118
102433
|
*/
|
|
102119
102434
|
function extractIssuesFromGroupedResults(groupedResults) {
|
|
102120
102435
|
const issues = [];
|
|
102121
|
-
for (const
|
|
102436
|
+
for (const checkResults of Object.values(groupedResults)) {
|
|
102122
102437
|
for (const checkResult of checkResults) {
|
|
102123
102438
|
const { checkName, content } = checkResult;
|
|
102124
102439
|
// First, check if structured issues are available
|
|
@@ -102147,7 +102462,7 @@ function extractIssuesFromGroupedResults(groupedResults) {
|
|
|
102147
102462
|
message: message.trim(),
|
|
102148
102463
|
severity,
|
|
102149
102464
|
category: 'logic', // Default category since we can't parse this from content
|
|
102150
|
-
group:
|
|
102465
|
+
group: checkResult.group,
|
|
102151
102466
|
timestamp: Date.now(),
|
|
102152
102467
|
};
|
|
102153
102468
|
issues.push(issue);
|
|
@@ -102711,19 +103026,35 @@ class OutputFormatters {
|
|
|
102711
103026
|
const issues = result.reviewSummary.issues || [];
|
|
102712
103027
|
const totalIssues = issues.length;
|
|
102713
103028
|
const criticalIssues = issues.filter(i => i.severity === 'critical').length;
|
|
102714
|
-
//
|
|
102715
|
-
const
|
|
102716
|
-
|
|
102717
|
-
|
|
102718
|
-
|
|
102719
|
-
|
|
102720
|
-
|
|
102721
|
-
|
|
102722
|
-
|
|
102723
|
-
|
|
102724
|
-
|
|
102725
|
-
|
|
102726
|
-
|
|
103029
|
+
// Check if this is a code review context
|
|
103030
|
+
const isCodeReview = result.isCodeReview || issues.some(i => i.schema === 'code-review');
|
|
103031
|
+
// Only show "Analysis Summary" table for code review contexts or when there are issues
|
|
103032
|
+
// For other contexts, the execution statistics table already provides summary
|
|
103033
|
+
if (isCodeReview || totalIssues > 0) {
|
|
103034
|
+
// Summary table
|
|
103035
|
+
const summaryTable = new cli_table3_1.default({
|
|
103036
|
+
head: ['Metric', 'Value'],
|
|
103037
|
+
colWidths: [25, 30],
|
|
103038
|
+
style: {
|
|
103039
|
+
head: ['cyan', 'bold'],
|
|
103040
|
+
border: ['grey'],
|
|
103041
|
+
},
|
|
103042
|
+
});
|
|
103043
|
+
// Add issue metrics
|
|
103044
|
+
summaryTable.push(['Total Issues', totalIssues.toString()]);
|
|
103045
|
+
if (criticalIssues > 0) {
|
|
103046
|
+
summaryTable.push(['Critical Issues', criticalIssues.toString()]);
|
|
103047
|
+
}
|
|
103048
|
+
// Add code-review specific metrics if in code review context
|
|
103049
|
+
if (isCodeReview && result.repositoryInfo.files.length > 0) {
|
|
103050
|
+
summaryTable.push(['Files Analyzed', result.repositoryInfo.files.length.toString()], ['Total Additions', result.repositoryInfo.totalAdditions.toString()], ['Total Deletions', result.repositoryInfo.totalDeletions.toString()]);
|
|
103051
|
+
}
|
|
103052
|
+
// Always show execution time and checks executed
|
|
103053
|
+
summaryTable.push(['Execution Time', `${result.executionTime}ms`], ['Checks Executed', result.checksExecuted.join(', ')]);
|
|
103054
|
+
output += 'Analysis Summary\n';
|
|
103055
|
+
output += summaryTable.toString() + '\n';
|
|
103056
|
+
output += '\n';
|
|
103057
|
+
}
|
|
102727
103058
|
// Issues by category table
|
|
102728
103059
|
if (issues.length > 0) {
|
|
102729
103060
|
if (groupByCategory) {
|
|
@@ -103963,13 +104294,13 @@ class AICheckProvider extends check_provider_interface_1.CheckProvider {
|
|
|
103963
104294
|
}
|
|
103964
104295
|
// Setup MCP tools if any servers are configured
|
|
103965
104296
|
if (Object.keys(mcpServers).length > 0) {
|
|
104297
|
+
// Pass raw server config to AI service so it can enable MCP in ProbeAgent
|
|
104298
|
+
aiConfig.mcpServers = mcpServers;
|
|
104299
|
+
// Optional: attempt to enumerate tools for debug visibility (not required for functionality)
|
|
103966
104300
|
const mcpConfig = { mcpServers };
|
|
103967
104301
|
const mcpTools = await this.setupMcpTools(mcpConfig);
|
|
103968
|
-
if (
|
|
103969
|
-
|
|
103970
|
-
if (aiConfig.debug) {
|
|
103971
|
-
console.error(`🔧 Debug: AI check configured with ${mcpTools.length} MCP tools from ${Object.keys(mcpServers).length} servers`);
|
|
103972
|
-
}
|
|
104302
|
+
if (aiConfig.debug) {
|
|
104303
|
+
console.error(`🔧 Debug: AI check MCP configured with ${Object.keys(mcpServers).length} servers; discovered ${mcpTools.length} tools`);
|
|
103973
104304
|
}
|
|
103974
104305
|
}
|
|
103975
104306
|
// Process prompt with Liquid templates and file loading
|
|
@@ -106558,8 +106889,8 @@ class PRReviewer {
|
|
|
106558
106889
|
if (config && checks && checks.length > 0) {
|
|
106559
106890
|
const { CheckExecutionEngine } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(80299)));
|
|
106560
106891
|
const engine = new CheckExecutionEngine();
|
|
106561
|
-
const
|
|
106562
|
-
return
|
|
106892
|
+
const { results } = await engine.executeGroupedChecks(prInfo, checks, undefined, config, undefined, debug);
|
|
106893
|
+
return results;
|
|
106563
106894
|
}
|
|
106564
106895
|
throw new Error('No configuration provided. Please create a .visor.yaml file with check definitions. ' +
|
|
106565
106896
|
'Built-in prompts have been removed - all checks must be explicitly configured.');
|
|
@@ -156729,14 +157060,53 @@ var init_probeTool = __esm({
|
|
|
156729
157060
|
if (!targetDir.startsWith(secureBaseDir + import_path7.default.sep) && targetDir !== secureBaseDir) {
|
|
156730
157061
|
throw new Error("Path traversal attempt detected. Access denied.");
|
|
156731
157062
|
}
|
|
157063
|
+
const debug = process.env.DEBUG === "1";
|
|
157064
|
+
if (debug) {
|
|
157065
|
+
console.log(`[DEBUG] Listing files in directory: ${targetDir}`);
|
|
157066
|
+
}
|
|
156732
157067
|
try {
|
|
156733
|
-
const files = await
|
|
156734
|
-
|
|
156735
|
-
|
|
156736
|
-
|
|
156737
|
-
|
|
157068
|
+
const files = await import_fs4.promises.readdir(targetDir, { withFileTypes: true });
|
|
157069
|
+
const formatSize = (size) => {
|
|
157070
|
+
if (size < 1024) return `${size}B`;
|
|
157071
|
+
if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)}K`;
|
|
157072
|
+
if (size < 1024 * 1024 * 1024) return `${(size / (1024 * 1024)).toFixed(1)}M`;
|
|
157073
|
+
return `${(size / (1024 * 1024 * 1024)).toFixed(1)}G`;
|
|
157074
|
+
};
|
|
157075
|
+
const entries = await Promise.all(files.map(async (file) => {
|
|
157076
|
+
const isDirectory = file.isDirectory();
|
|
157077
|
+
const fullPath = import_path7.default.join(targetDir, file.name);
|
|
157078
|
+
let size = 0;
|
|
157079
|
+
try {
|
|
157080
|
+
const stats = await import_fs4.promises.stat(fullPath);
|
|
157081
|
+
size = stats.size;
|
|
157082
|
+
} catch (statError) {
|
|
157083
|
+
if (debug) {
|
|
157084
|
+
console.log(`[DEBUG] Could not stat file ${file.name}:`, statError.message);
|
|
157085
|
+
}
|
|
157086
|
+
}
|
|
157087
|
+
return {
|
|
157088
|
+
name: file.name,
|
|
157089
|
+
isDirectory,
|
|
157090
|
+
size
|
|
157091
|
+
};
|
|
157092
|
+
}));
|
|
157093
|
+
entries.sort((a3, b3) => {
|
|
157094
|
+
if (a3.isDirectory && !b3.isDirectory) return -1;
|
|
157095
|
+
if (!a3.isDirectory && b3.isDirectory) return 1;
|
|
157096
|
+
return a3.name.localeCompare(b3.name);
|
|
156738
157097
|
});
|
|
156739
|
-
|
|
157098
|
+
const formatted = entries.map((entry) => {
|
|
157099
|
+
const type = entry.isDirectory ? "dir " : "file";
|
|
157100
|
+
const sizeStr = formatSize(entry.size).padStart(8);
|
|
157101
|
+
return `${type} ${sizeStr} ${entry.name}`;
|
|
157102
|
+
});
|
|
157103
|
+
if (debug) {
|
|
157104
|
+
console.log(`[DEBUG] Found ${entries.length} files/directories in ${targetDir}`);
|
|
157105
|
+
}
|
|
157106
|
+
const header = `${targetDir}:
|
|
157107
|
+
`;
|
|
157108
|
+
const output = header + formatted.join("\n");
|
|
157109
|
+
return output;
|
|
156740
157110
|
} catch (error2) {
|
|
156741
157111
|
throw new Error(`Failed to list files: ${error2.message}`);
|
|
156742
157112
|
}
|
|
@@ -156754,6 +157124,9 @@ var init_probeTool = __esm({
|
|
|
156754
157124
|
if (!targetDir.startsWith(secureBaseDir + import_path7.default.sep) && targetDir !== secureBaseDir) {
|
|
156755
157125
|
throw new Error("Path traversal attempt detected. Access denied.");
|
|
156756
157126
|
}
|
|
157127
|
+
if (pattern.includes("**/**") || pattern.split("*").length > 10) {
|
|
157128
|
+
throw new Error("Pattern too complex. Please use a simpler glob pattern.");
|
|
157129
|
+
}
|
|
156757
157130
|
try {
|
|
156758
157131
|
const options = {
|
|
156759
157132
|
cwd: targetDir,
|
|
@@ -156763,7 +157136,17 @@ var init_probeTool = __esm({
|
|
|
156763
157136
|
if (!recursive) {
|
|
156764
157137
|
options.deep = 1;
|
|
156765
157138
|
}
|
|
156766
|
-
const
|
|
157139
|
+
const timeoutPromise = new Promise((_2, reject2) => {
|
|
157140
|
+
setTimeout(() => reject2(new Error("Search operation timed out after 10 seconds")), 1e4);
|
|
157141
|
+
});
|
|
157142
|
+
const files = await Promise.race([
|
|
157143
|
+
(0, import_glob.glob)(pattern, options),
|
|
157144
|
+
timeoutPromise
|
|
157145
|
+
]);
|
|
157146
|
+
const maxResults = 1e3;
|
|
157147
|
+
if (files.length > maxResults) {
|
|
157148
|
+
return files.slice(0, maxResults);
|
|
157149
|
+
}
|
|
156767
157150
|
return files;
|
|
156768
157151
|
} catch (error2) {
|
|
156769
157152
|
throw new Error(`Failed to search files: ${error2.message}`);
|
|
@@ -168081,13 +168464,14 @@ function tokenize(text) {
|
|
|
168081
168464
|
const lexResult = MermaidLexer.tokenize(text);
|
|
168082
168465
|
return lexResult;
|
|
168083
168466
|
}
|
|
168084
|
-
var Identifier, NumberLiteral, FlowchartKeyword, GraphKeyword, Direction, SubgraphKeyword, EndKeyword, ClassKeyword, StyleKeyword, ClassDefKeyword, Ampersand, Comma, Semicolon, Colon, TripleColon, BiDirectionalArrow, CircleEndLine, CrossEndLine, DottedArrowRight, DottedArrowLeft, ThickArrowRight, ThickArrowLeft, ArrowRight, ArrowLeft, DottedLine, ThickLine, Line, TwoDashes, InvalidArrow, DoubleSquareOpen, DoubleSquareClose, DoubleRoundOpen, DoubleRoundClose, HexagonOpen, HexagonClose, StadiumOpen, StadiumClose, CylinderOpen, CylinderClose, SquareOpen, SquareClose, RoundOpen, RoundClose, DiamondOpen, DiamondClose, AngleOpen, AngleLess, Pipe, QuotedString, MultilineText, Comment, ColorValue, Text, WhiteSpace, Newline, allTokens, MermaidLexer;
|
|
168467
|
+
var Identifier, NumberLiteral, FlowchartKeyword, GraphKeyword, Direction, SubgraphKeyword, EndKeyword, ClassKeyword, StyleKeyword, ClassDefKeyword, Ampersand, Comma, Semicolon, Colon, TripleColon, BiDirectionalArrow, CircleEndLine, CrossEndLine, DottedArrowRight, DottedArrowLeft, ThickArrowRight, ThickArrowLeft, ArrowRight, ArrowLeft, DottedLine, ThickLine, Line, TwoDashes, InvalidArrow, DoubleSquareOpen, DoubleSquareClose, DoubleRoundOpen, DoubleRoundClose, HexagonOpen, HexagonClose, StadiumOpen, StadiumClose, CylinderOpen, CylinderClose, SquareOpen, SquareClose, RoundOpen, RoundClose, DiamondOpen, DiamondClose, AngleOpen, AngleLess, Pipe, ForwardSlash, Backslash, QuotedString, MultilineText, Comment, ColorValue, Text, WhiteSpace, Newline, allTokens, MermaidLexer;
|
|
168085
168468
|
var init_lexer2 = __esm({
|
|
168086
168469
|
"node_modules/@probelabs/maid/out/diagrams/flowchart/lexer.js"() {
|
|
168087
168470
|
init_api5();
|
|
168088
168471
|
Identifier = createToken({
|
|
168089
168472
|
name: "Identifier",
|
|
168090
|
-
|
|
168473
|
+
// e.g., id-2, _id, A1, but not A-- (that belongs to an arrow token)
|
|
168474
|
+
pattern: /[a-zA-Z_][a-zA-Z0-9_]*(?:-[a-zA-Z0-9_]+)*/
|
|
168091
168475
|
});
|
|
168092
168476
|
NumberLiteral = createToken({
|
|
168093
168477
|
name: "NumberLiteral",
|
|
@@ -168228,6 +168612,8 @@ var init_lexer2 = __esm({
|
|
|
168228
168612
|
AngleOpen = createToken({ name: "AngleOpen", pattern: />/ });
|
|
168229
168613
|
AngleLess = createToken({ name: "AngleLess", pattern: /</ });
|
|
168230
168614
|
Pipe = createToken({ name: "Pipe", pattern: /\|/ });
|
|
168615
|
+
ForwardSlash = createToken({ name: "ForwardSlash", pattern: /\// });
|
|
168616
|
+
Backslash = createToken({ name: "Backslash", pattern: /\\/ });
|
|
168231
168617
|
QuotedString = createToken({
|
|
168232
168618
|
name: "QuotedString",
|
|
168233
168619
|
// Allow escaped characters within quotes (Mermaid accepts \" inside "...")
|
|
@@ -168311,6 +168697,8 @@ var init_lexer2 = __esm({
|
|
|
168311
168697
|
DiamondClose,
|
|
168312
168698
|
AngleOpen,
|
|
168313
168699
|
AngleLess,
|
|
168700
|
+
ForwardSlash,
|
|
168701
|
+
Backslash,
|
|
168314
168702
|
Pipe,
|
|
168315
168703
|
TripleColon,
|
|
168316
168704
|
Ampersand,
|
|
@@ -168503,6 +168891,8 @@ var init_parser2 = __esm({
|
|
|
168503
168891
|
// Allow HTML-like tags (e.g., <br/>) inside labels
|
|
168504
168892
|
{ ALT: () => this.CONSUME(AngleLess) },
|
|
168505
168893
|
{ ALT: () => this.CONSUME(AngleOpen) },
|
|
168894
|
+
{ ALT: () => this.CONSUME(ForwardSlash) },
|
|
168895
|
+
{ ALT: () => this.CONSUME(Backslash) },
|
|
168506
168896
|
{ ALT: () => this.CONSUME(Comma) },
|
|
168507
168897
|
{ ALT: () => this.CONSUME(Colon) },
|
|
168508
168898
|
// HTML entities and ampersands inside labels
|
|
@@ -169551,6 +169941,66 @@ ${br.example}`,
|
|
|
169551
169941
|
length: len
|
|
169552
169942
|
};
|
|
169553
169943
|
}
|
|
169944
|
+
if (inRule("boxBlock") && (err.name === "NoViableAltException" || err.name === "MismatchedTokenException")) {
|
|
169945
|
+
const isMessage = /->|-->>|-->/.test(ltxt);
|
|
169946
|
+
const isNote = /note\s+(left|right|over)/i.test(ltxt);
|
|
169947
|
+
const isActivate = /activate\s+/i.test(ltxt);
|
|
169948
|
+
const isDeactivate = /deactivate\s+/i.test(ltxt);
|
|
169949
|
+
if (isMessage || isNote || isActivate || isDeactivate || tokType === "NoteKeyword" || tokType === "ActivateKeyword" || tokType === "DeactivateKeyword") {
|
|
169950
|
+
const lines2 = text.split(/\r?\n/);
|
|
169951
|
+
const boxLine = Math.max(0, line - 1);
|
|
169952
|
+
let hasEnd = false;
|
|
169953
|
+
let openIdx = -1;
|
|
169954
|
+
for (let i3 = boxLine; i3 >= 0; i3--) {
|
|
169955
|
+
if (/^\s*box\b/.test(lines2[i3] || "")) {
|
|
169956
|
+
openIdx = i3;
|
|
169957
|
+
break;
|
|
169958
|
+
}
|
|
169959
|
+
}
|
|
169960
|
+
if (openIdx !== -1) {
|
|
169961
|
+
for (let i3 = boxLine; i3 < lines2.length; i3++) {
|
|
169962
|
+
if (/^\s*end\s*$/.test(lines2[i3] || "")) {
|
|
169963
|
+
hasEnd = true;
|
|
169964
|
+
break;
|
|
169965
|
+
}
|
|
169966
|
+
if (i3 > boxLine && /^\s*(sequenceDiagram|box|alt|opt|loop|par|rect|critical|break)\b/.test(lines2[i3] || ""))
|
|
169967
|
+
break;
|
|
169968
|
+
}
|
|
169969
|
+
}
|
|
169970
|
+
if (hasEnd) {
|
|
169971
|
+
let hasParticipants = false;
|
|
169972
|
+
for (let i3 = openIdx + 1; i3 < lines2.length; i3++) {
|
|
169973
|
+
const raw = lines2[i3] || "";
|
|
169974
|
+
if (/^\s*end\s*$/.test(raw))
|
|
169975
|
+
break;
|
|
169976
|
+
if (/^\s*(participant|actor)\b/i.test(raw)) {
|
|
169977
|
+
hasParticipants = true;
|
|
169978
|
+
break;
|
|
169979
|
+
}
|
|
169980
|
+
}
|
|
169981
|
+
if (!hasParticipants) {
|
|
169982
|
+
return {
|
|
169983
|
+
line: openIdx + 1,
|
|
169984
|
+
column: 1,
|
|
169985
|
+
severity: "error",
|
|
169986
|
+
code: "SE-BOX-EMPTY",
|
|
169987
|
+
message: "Box block has no participant/actor declarations. Use 'rect' to group messages visually.",
|
|
169988
|
+
hint: "Replace 'box' with 'rect' if you want to group messages:\nrect rgb(240, 240, 255)\n A->>B: Message\n Note over A: Info\nend",
|
|
169989
|
+
length: 3
|
|
169990
|
+
};
|
|
169991
|
+
}
|
|
169992
|
+
return {
|
|
169993
|
+
line,
|
|
169994
|
+
column,
|
|
169995
|
+
severity: "error",
|
|
169996
|
+
code: "SE-BOX-INVALID-CONTENT",
|
|
169997
|
+
message: "Box blocks can only contain participant/actor declarations.",
|
|
169998
|
+
hint: 'Move messages, notes, and other statements outside the box block.\nExample:\nbox "Group"\n participant A\n participant B\nend\nA->>B: Message',
|
|
169999
|
+
length: len
|
|
170000
|
+
};
|
|
170001
|
+
}
|
|
170002
|
+
}
|
|
170003
|
+
}
|
|
169554
170004
|
const blockRules = [
|
|
169555
170005
|
{ rule: "altBlock", label: "alt" },
|
|
169556
170006
|
{ rule: "optBlock", label: "opt" },
|
|
@@ -170450,9 +170900,15 @@ var init_parser4 = __esm({
|
|
|
170450
170900
|
this.CONSUME(BoxKeyword);
|
|
170451
170901
|
this.OPTION(() => this.SUBRULE(this.lineRemainder));
|
|
170452
170902
|
this.AT_LEAST_ONE(() => this.CONSUME(Newline3));
|
|
170453
|
-
this.MANY(() => this.
|
|
170903
|
+
this.MANY(() => this.OR([
|
|
170904
|
+
{ ALT: () => this.SUBRULE(this.participantDecl) },
|
|
170905
|
+
{ ALT: () => this.SUBRULE(this.blankLine) }
|
|
170906
|
+
]));
|
|
170454
170907
|
this.CONSUME(EndKeyword2);
|
|
170455
|
-
this.
|
|
170908
|
+
this.OR2([
|
|
170909
|
+
{ ALT: () => this.AT_LEAST_ONE2(() => this.CONSUME2(Newline3)) },
|
|
170910
|
+
{ ALT: () => this.CONSUME2(EOF) }
|
|
170911
|
+
]);
|
|
170456
170912
|
});
|
|
170457
170913
|
this.lineRemainder = this.RULE("lineRemainder", () => {
|
|
170458
170914
|
this.AT_LEAST_ONE(() => this.OR([
|
|
@@ -172003,6 +172459,69 @@ function computeFixes(text, errors, level = "safe") {
|
|
|
172003
172459
|
edits.push(replaceRange(text, at(e3), e3.length ?? 4, "option"));
|
|
172004
172460
|
continue;
|
|
172005
172461
|
}
|
|
172462
|
+
if (is("SE-BOX-EMPTY", e3)) {
|
|
172463
|
+
const lines = text.split(/\r?\n/);
|
|
172464
|
+
const boxIdx = Math.max(0, e3.line - 1);
|
|
172465
|
+
const boxLine = lines[boxIdx] || "";
|
|
172466
|
+
const labelMatch = /^\s*box\s+(.+)$/.exec(boxLine);
|
|
172467
|
+
if (labelMatch) {
|
|
172468
|
+
const indent = boxLine.match(/^\s*/)?.[0] || "";
|
|
172469
|
+
const newLine = `${indent}rect rgb(240, 240, 255)`;
|
|
172470
|
+
edits.push({ start: { line: e3.line, column: 1 }, end: { line: e3.line, column: boxLine.length + 1 }, newText: newLine });
|
|
172471
|
+
}
|
|
172472
|
+
continue;
|
|
172473
|
+
}
|
|
172474
|
+
if (is("SE-BOX-INVALID-CONTENT", e3)) {
|
|
172475
|
+
const lines = text.split(/\r?\n/);
|
|
172476
|
+
const curIdx = Math.max(0, e3.line - 1);
|
|
172477
|
+
const boxRe = /^(\s*)box\b/;
|
|
172478
|
+
let openIdx = -1;
|
|
172479
|
+
let openIndent = "";
|
|
172480
|
+
for (let i3 = curIdx; i3 >= 0; i3--) {
|
|
172481
|
+
const m3 = boxRe.exec(lines[i3] || "");
|
|
172482
|
+
if (m3) {
|
|
172483
|
+
openIdx = i3;
|
|
172484
|
+
openIndent = m3[1] || "";
|
|
172485
|
+
break;
|
|
172486
|
+
}
|
|
172487
|
+
}
|
|
172488
|
+
if (openIdx !== -1) {
|
|
172489
|
+
let endIdx = -1;
|
|
172490
|
+
for (let i3 = openIdx + 1; i3 < lines.length; i3++) {
|
|
172491
|
+
const trimmed = (lines[i3] || "").trim();
|
|
172492
|
+
if (trimmed === "end") {
|
|
172493
|
+
endIdx = i3;
|
|
172494
|
+
break;
|
|
172495
|
+
}
|
|
172496
|
+
}
|
|
172497
|
+
if (endIdx !== -1) {
|
|
172498
|
+
const invalidLines = [];
|
|
172499
|
+
for (let i3 = openIdx + 1; i3 < endIdx; i3++) {
|
|
172500
|
+
const raw = lines[i3] || "";
|
|
172501
|
+
const trimmed = raw.trim();
|
|
172502
|
+
if (trimmed === "")
|
|
172503
|
+
continue;
|
|
172504
|
+
if (!/^\s*(participant|actor)\b/i.test(raw)) {
|
|
172505
|
+
invalidLines.push(i3);
|
|
172506
|
+
}
|
|
172507
|
+
}
|
|
172508
|
+
if (invalidLines.length > 0) {
|
|
172509
|
+
const endIndent = openIndent;
|
|
172510
|
+
const movedContent = invalidLines.map((i3) => {
|
|
172511
|
+
const line = lines[i3] || "";
|
|
172512
|
+
const trimmed = line.trimStart();
|
|
172513
|
+
return endIndent + trimmed;
|
|
172514
|
+
}).join("\n") + "\n";
|
|
172515
|
+
for (let i3 = invalidLines.length - 1; i3 >= 0; i3--) {
|
|
172516
|
+
const idx = invalidLines[i3];
|
|
172517
|
+
edits.push({ start: { line: idx + 1, column: 1 }, end: { line: idx + 2, column: 1 }, newText: "" });
|
|
172518
|
+
}
|
|
172519
|
+
edits.push(insertAt(text, { line: endIdx + 2, column: 1 }, movedContent));
|
|
172520
|
+
}
|
|
172521
|
+
}
|
|
172522
|
+
}
|
|
172523
|
+
continue;
|
|
172524
|
+
}
|
|
172006
172525
|
if (is("SE-BLOCK-MISSING-END", e3)) {
|
|
172007
172526
|
const lines = text.split(/\r?\n/);
|
|
172008
172527
|
const curIdx = Math.max(0, e3.line - 1);
|
|
@@ -172283,8 +172802,543 @@ var init_fixes = __esm({
|
|
|
172283
172802
|
});
|
|
172284
172803
|
|
|
172285
172804
|
// node_modules/@probelabs/maid/out/renderer/graph-builder.js
|
|
172805
|
+
var GraphBuilder;
|
|
172286
172806
|
var init_graph_builder = __esm({
|
|
172287
172807
|
"node_modules/@probelabs/maid/out/renderer/graph-builder.js"() {
|
|
172808
|
+
GraphBuilder = class {
|
|
172809
|
+
constructor() {
|
|
172810
|
+
this.nodes = /* @__PURE__ */ new Map();
|
|
172811
|
+
this.edges = [];
|
|
172812
|
+
this.nodeCounter = 0;
|
|
172813
|
+
this.edgeCounter = 0;
|
|
172814
|
+
this.subgraphs = [];
|
|
172815
|
+
this.currentSubgraphStack = [];
|
|
172816
|
+
this.classStyles = /* @__PURE__ */ new Map();
|
|
172817
|
+
this.nodeStyles = /* @__PURE__ */ new Map();
|
|
172818
|
+
this.nodeClasses = /* @__PURE__ */ new Map();
|
|
172819
|
+
}
|
|
172820
|
+
build(cst) {
|
|
172821
|
+
this.reset();
|
|
172822
|
+
if (!cst || !cst.children) {
|
|
172823
|
+
return {
|
|
172824
|
+
nodes: [],
|
|
172825
|
+
edges: [],
|
|
172826
|
+
direction: "TD",
|
|
172827
|
+
subgraphs: []
|
|
172828
|
+
};
|
|
172829
|
+
}
|
|
172830
|
+
const direction = this.extractDirection(cst);
|
|
172831
|
+
this.processStatements(cst);
|
|
172832
|
+
return {
|
|
172833
|
+
nodes: Array.from(this.nodes.values()),
|
|
172834
|
+
edges: this.edges,
|
|
172835
|
+
direction,
|
|
172836
|
+
subgraphs: this.subgraphs
|
|
172837
|
+
};
|
|
172838
|
+
}
|
|
172839
|
+
reset() {
|
|
172840
|
+
this.nodes.clear();
|
|
172841
|
+
this.edges = [];
|
|
172842
|
+
this.nodeCounter = 0;
|
|
172843
|
+
this.edgeCounter = 0;
|
|
172844
|
+
this.subgraphs = [];
|
|
172845
|
+
this.currentSubgraphStack = [];
|
|
172846
|
+
this.classStyles.clear();
|
|
172847
|
+
this.nodeStyles.clear();
|
|
172848
|
+
this.nodeClasses.clear();
|
|
172849
|
+
}
|
|
172850
|
+
extractDirection(cst) {
|
|
172851
|
+
const dirToken = cst.children?.Direction?.[0];
|
|
172852
|
+
const dir = dirToken?.image?.toUpperCase();
|
|
172853
|
+
switch (dir) {
|
|
172854
|
+
case "TB":
|
|
172855
|
+
case "TD":
|
|
172856
|
+
return "TD";
|
|
172857
|
+
case "BT":
|
|
172858
|
+
return "BT";
|
|
172859
|
+
case "LR":
|
|
172860
|
+
return "LR";
|
|
172861
|
+
case "RL":
|
|
172862
|
+
return "RL";
|
|
172863
|
+
default:
|
|
172864
|
+
return "TD";
|
|
172865
|
+
}
|
|
172866
|
+
}
|
|
172867
|
+
processStatements(cst) {
|
|
172868
|
+
const statements = cst.children?.statement;
|
|
172869
|
+
if (!statements)
|
|
172870
|
+
return;
|
|
172871
|
+
for (const stmt of statements) {
|
|
172872
|
+
if (stmt.children?.nodeStatement) {
|
|
172873
|
+
this.processNodeStatement(stmt.children.nodeStatement[0]);
|
|
172874
|
+
} else if (stmt.children?.subgraph) {
|
|
172875
|
+
this.processSubgraph(stmt.children.subgraph[0]);
|
|
172876
|
+
} else if (stmt.children?.classDefStatement) {
|
|
172877
|
+
this.processClassDef(stmt.children.classDefStatement[0]);
|
|
172878
|
+
} else if (stmt.children?.classStatement) {
|
|
172879
|
+
this.processClassAssign(stmt.children.classStatement[0]);
|
|
172880
|
+
} else if (stmt.children?.styleStatement) {
|
|
172881
|
+
this.processStyle(stmt.children.styleStatement[0]);
|
|
172882
|
+
}
|
|
172883
|
+
}
|
|
172884
|
+
}
|
|
172885
|
+
processNodeStatement(stmt) {
|
|
172886
|
+
const groups = stmt.children?.nodeOrParallelGroup;
|
|
172887
|
+
const links = stmt.children?.link;
|
|
172888
|
+
if (!groups || groups.length === 0)
|
|
172889
|
+
return;
|
|
172890
|
+
const sourceNodes = this.processNodeGroup(groups[0]);
|
|
172891
|
+
if (groups.length > 1 && links && links.length > 0) {
|
|
172892
|
+
const targetNodes = this.processNodeGroup(groups[1]);
|
|
172893
|
+
const linkInfo = this.extractLinkInfo(links[0]);
|
|
172894
|
+
for (const source of sourceNodes) {
|
|
172895
|
+
for (const target of targetNodes) {
|
|
172896
|
+
this.edges.push({
|
|
172897
|
+
id: `e${this.edgeCounter++}`,
|
|
172898
|
+
source,
|
|
172899
|
+
target,
|
|
172900
|
+
label: linkInfo.label,
|
|
172901
|
+
type: linkInfo.type,
|
|
172902
|
+
markerStart: linkInfo.markerStart,
|
|
172903
|
+
markerEnd: linkInfo.markerEnd
|
|
172904
|
+
});
|
|
172905
|
+
}
|
|
172906
|
+
}
|
|
172907
|
+
for (let i3 = 2; i3 < groups.length; i3++) {
|
|
172908
|
+
const nextNodes = this.processNodeGroup(groups[i3]);
|
|
172909
|
+
const nextLink = links[i3 - 1] ? this.extractLinkInfo(links[i3 - 1]) : linkInfo;
|
|
172910
|
+
for (const source of targetNodes) {
|
|
172911
|
+
for (const target of nextNodes) {
|
|
172912
|
+
this.edges.push({
|
|
172913
|
+
id: `e${this.edgeCounter++}`,
|
|
172914
|
+
source,
|
|
172915
|
+
target,
|
|
172916
|
+
label: nextLink.label,
|
|
172917
|
+
type: nextLink.type,
|
|
172918
|
+
markerStart: nextLink.markerStart,
|
|
172919
|
+
markerEnd: nextLink.markerEnd
|
|
172920
|
+
});
|
|
172921
|
+
}
|
|
172922
|
+
}
|
|
172923
|
+
targetNodes.length = 0;
|
|
172924
|
+
targetNodes.push(...nextNodes);
|
|
172925
|
+
}
|
|
172926
|
+
}
|
|
172927
|
+
}
|
|
172928
|
+
processNodeGroup(group) {
|
|
172929
|
+
const nodes = group.children?.node;
|
|
172930
|
+
if (!nodes)
|
|
172931
|
+
return [];
|
|
172932
|
+
const nodeIds = [];
|
|
172933
|
+
for (const node of nodes) {
|
|
172934
|
+
const nodeInfo = this.extractNodeInfo(node);
|
|
172935
|
+
if (nodeInfo) {
|
|
172936
|
+
const isSubgraph = this.subgraphs.some((sg) => sg.id === nodeInfo.id);
|
|
172937
|
+
if (!isSubgraph) {
|
|
172938
|
+
if (!this.nodes.has(nodeInfo.id)) {
|
|
172939
|
+
nodeInfo.style = this.computeNodeStyle(nodeInfo.id);
|
|
172940
|
+
this.nodes.set(nodeInfo.id, nodeInfo);
|
|
172941
|
+
} else {
|
|
172942
|
+
const existing = this.nodes.get(nodeInfo.id);
|
|
172943
|
+
if (nodeInfo.shape !== "rectangle" || nodeInfo.label !== nodeInfo.id) {
|
|
172944
|
+
if (nodeInfo.label !== nodeInfo.id) {
|
|
172945
|
+
existing.label = nodeInfo.label;
|
|
172946
|
+
}
|
|
172947
|
+
if (nodeInfo.shape !== "rectangle") {
|
|
172948
|
+
existing.shape = nodeInfo.shape;
|
|
172949
|
+
}
|
|
172950
|
+
}
|
|
172951
|
+
const merged = this.computeNodeStyle(nodeInfo.id);
|
|
172952
|
+
if (Object.keys(merged).length) {
|
|
172953
|
+
existing.style = { ...existing.style || {}, ...merged };
|
|
172954
|
+
}
|
|
172955
|
+
}
|
|
172956
|
+
if (this.currentSubgraphStack.length) {
|
|
172957
|
+
for (const sgId of this.currentSubgraphStack) {
|
|
172958
|
+
const subgraph = this.subgraphs.find((s3) => s3.id === sgId);
|
|
172959
|
+
if (subgraph && !subgraph.nodes.includes(nodeInfo.id)) {
|
|
172960
|
+
subgraph.nodes.push(nodeInfo.id);
|
|
172961
|
+
}
|
|
172962
|
+
}
|
|
172963
|
+
}
|
|
172964
|
+
}
|
|
172965
|
+
nodeIds.push(nodeInfo.id);
|
|
172966
|
+
}
|
|
172967
|
+
}
|
|
172968
|
+
return nodeIds;
|
|
172969
|
+
}
|
|
172970
|
+
extractNodeInfo(node) {
|
|
172971
|
+
const children = node.children;
|
|
172972
|
+
if (!children)
|
|
172973
|
+
return null;
|
|
172974
|
+
let id;
|
|
172975
|
+
if (children.nodeId) {
|
|
172976
|
+
id = children.nodeId[0].image;
|
|
172977
|
+
if (children.nodeIdSuffix) {
|
|
172978
|
+
id += children.nodeIdSuffix[0].image;
|
|
172979
|
+
}
|
|
172980
|
+
} else if (children.nodeIdNum) {
|
|
172981
|
+
id = children.nodeIdNum[0].image;
|
|
172982
|
+
} else if (children.Identifier) {
|
|
172983
|
+
id = children.Identifier[0].image;
|
|
172984
|
+
} else {
|
|
172985
|
+
return null;
|
|
172986
|
+
}
|
|
172987
|
+
let shape = "rectangle";
|
|
172988
|
+
let label = id;
|
|
172989
|
+
const shapeNode = children.nodeShape?.[0];
|
|
172990
|
+
if (shapeNode?.children) {
|
|
172991
|
+
const result = this.extractShapeAndLabel(shapeNode);
|
|
172992
|
+
shape = result.shape;
|
|
172993
|
+
if (result.label)
|
|
172994
|
+
label = result.label;
|
|
172995
|
+
}
|
|
172996
|
+
const clsTok = children.nodeClass?.[0];
|
|
172997
|
+
if (clsTok) {
|
|
172998
|
+
const set = this.nodeClasses.get(id) || /* @__PURE__ */ new Set();
|
|
172999
|
+
set.add(clsTok.image);
|
|
173000
|
+
this.nodeClasses.set(id, set);
|
|
173001
|
+
}
|
|
173002
|
+
return { id, label, shape };
|
|
173003
|
+
}
|
|
173004
|
+
extractShapeAndLabel(shapeNode) {
|
|
173005
|
+
const children = shapeNode.children;
|
|
173006
|
+
let shape = "rectangle";
|
|
173007
|
+
let label = "";
|
|
173008
|
+
const contentNodes = children?.nodeContent;
|
|
173009
|
+
if (contentNodes && contentNodes.length > 0) {
|
|
173010
|
+
label = this.extractTextContent(contentNodes[0]);
|
|
173011
|
+
}
|
|
173012
|
+
if (children?.SquareOpen) {
|
|
173013
|
+
shape = "rectangle";
|
|
173014
|
+
const contentNode = children.nodeContent?.[0];
|
|
173015
|
+
if (contentNode) {
|
|
173016
|
+
const c3 = contentNode.children;
|
|
173017
|
+
const tokTypes = ["ForwardSlash", "Backslash", "Identifier", "Text", "NumberLiteral", "RoundOpen", "RoundClose", "AngleLess", "AngleOpen", "Comma", "Colon", "Ampersand", "Semicolon", "TwoDashes", "Line", "ThickLine", "DottedLine"];
|
|
173018
|
+
const toks = [];
|
|
173019
|
+
for (const tt of tokTypes) {
|
|
173020
|
+
const arr = c3[tt];
|
|
173021
|
+
arr?.forEach((t3) => toks.push({ type: tt, t: t3, start: t3.startOffset ?? 0 }));
|
|
173022
|
+
}
|
|
173023
|
+
if (toks.length >= 2) {
|
|
173024
|
+
toks.sort((a3, b3) => a3.start - b3.start);
|
|
173025
|
+
const first2 = toks[0].type;
|
|
173026
|
+
const last2 = toks[toks.length - 1].type;
|
|
173027
|
+
if (first2 === "ForwardSlash" && last2 === "ForwardSlash" || first2 === "Backslash" && last2 === "Backslash") {
|
|
173028
|
+
shape = "parallelogram";
|
|
173029
|
+
} else if (first2 === "ForwardSlash" && last2 === "Backslash") {
|
|
173030
|
+
shape = "trapezoid";
|
|
173031
|
+
} else if (first2 === "Backslash" && last2 === "ForwardSlash") {
|
|
173032
|
+
shape = "trapezoidAlt";
|
|
173033
|
+
}
|
|
173034
|
+
}
|
|
173035
|
+
}
|
|
173036
|
+
} else if (children?.RoundOpen) {
|
|
173037
|
+
shape = "round";
|
|
173038
|
+
} else if (children?.DiamondOpen) {
|
|
173039
|
+
shape = "diamond";
|
|
173040
|
+
} else if (children?.DoubleRoundOpen) {
|
|
173041
|
+
shape = "circle";
|
|
173042
|
+
} else if (children?.StadiumOpen) {
|
|
173043
|
+
shape = "stadium";
|
|
173044
|
+
} else if (children?.HexagonOpen) {
|
|
173045
|
+
shape = "hexagon";
|
|
173046
|
+
} else if (children?.DoubleSquareOpen) {
|
|
173047
|
+
shape = "subroutine";
|
|
173048
|
+
} else if (children?.CylinderOpen) {
|
|
173049
|
+
shape = "cylinder";
|
|
173050
|
+
} else if (children?.TrapezoidOpen) {
|
|
173051
|
+
shape = "trapezoid";
|
|
173052
|
+
} else if (children?.ParallelogramOpen) {
|
|
173053
|
+
shape = "parallelogram";
|
|
173054
|
+
}
|
|
173055
|
+
return { shape, label };
|
|
173056
|
+
}
|
|
173057
|
+
extractTextContent(contentNode) {
|
|
173058
|
+
const children = contentNode.children;
|
|
173059
|
+
if (!children)
|
|
173060
|
+
return "";
|
|
173061
|
+
const tokenTypes = [
|
|
173062
|
+
"Text",
|
|
173063
|
+
"Identifier",
|
|
173064
|
+
"QuotedString",
|
|
173065
|
+
"NumberLiteral",
|
|
173066
|
+
"Ampersand",
|
|
173067
|
+
"Comma",
|
|
173068
|
+
"Colon",
|
|
173069
|
+
"Semicolon",
|
|
173070
|
+
"Dot",
|
|
173071
|
+
"Underscore",
|
|
173072
|
+
"Dash",
|
|
173073
|
+
"ForwardSlash",
|
|
173074
|
+
"Backslash",
|
|
173075
|
+
"AngleLess",
|
|
173076
|
+
"AngleOpen"
|
|
173077
|
+
];
|
|
173078
|
+
const tokenWithPositions = [];
|
|
173079
|
+
for (const type of tokenTypes) {
|
|
173080
|
+
const tokens = children[type];
|
|
173081
|
+
if (tokens) {
|
|
173082
|
+
for (const token of tokens) {
|
|
173083
|
+
let text = token.image;
|
|
173084
|
+
if (type === "QuotedString" && text.startsWith('"') && text.endsWith('"')) {
|
|
173085
|
+
text = text.slice(1, -1);
|
|
173086
|
+
}
|
|
173087
|
+
if ((type === "ForwardSlash" || type === "Backslash") && tokenWithPositions.length === 0) {
|
|
173088
|
+
continue;
|
|
173089
|
+
}
|
|
173090
|
+
tokenWithPositions.push({
|
|
173091
|
+
text,
|
|
173092
|
+
startOffset: token.startOffset ?? 0,
|
|
173093
|
+
type
|
|
173094
|
+
});
|
|
173095
|
+
}
|
|
173096
|
+
}
|
|
173097
|
+
}
|
|
173098
|
+
tokenWithPositions.sort((a3, b3) => a3.startOffset - b3.startOffset);
|
|
173099
|
+
if (tokenWithPositions.length) {
|
|
173100
|
+
const first2 = tokenWithPositions[0];
|
|
173101
|
+
if (first2.type === "ForwardSlash" || first2.type === "Backslash") {
|
|
173102
|
+
tokenWithPositions.shift();
|
|
173103
|
+
}
|
|
173104
|
+
const last2 = tokenWithPositions[tokenWithPositions.length - 1];
|
|
173105
|
+
if (last2.type === "ForwardSlash" || last2.type === "Backslash") {
|
|
173106
|
+
tokenWithPositions.pop();
|
|
173107
|
+
}
|
|
173108
|
+
}
|
|
173109
|
+
const parts = tokenWithPositions.map((t3) => t3.text);
|
|
173110
|
+
if (children.Space) {
|
|
173111
|
+
return parts.join("");
|
|
173112
|
+
}
|
|
173113
|
+
return parts.join(" ").trim();
|
|
173114
|
+
}
|
|
173115
|
+
extractLinkInfo(link) {
|
|
173116
|
+
const children = link.children;
|
|
173117
|
+
let type = "arrow";
|
|
173118
|
+
let label;
|
|
173119
|
+
let markerStart = "none";
|
|
173120
|
+
let markerEnd = "none";
|
|
173121
|
+
if (children.BiDirectionalArrow) {
|
|
173122
|
+
type = "arrow";
|
|
173123
|
+
markerStart = "arrow";
|
|
173124
|
+
markerEnd = "arrow";
|
|
173125
|
+
} else if (children.CircleEndLine) {
|
|
173126
|
+
type = "open";
|
|
173127
|
+
markerStart = "circle";
|
|
173128
|
+
markerEnd = "circle";
|
|
173129
|
+
} else if (children.CrossEndLine) {
|
|
173130
|
+
type = "open";
|
|
173131
|
+
markerStart = "cross";
|
|
173132
|
+
markerEnd = "cross";
|
|
173133
|
+
} else if (children?.ArrowRight) {
|
|
173134
|
+
type = "arrow";
|
|
173135
|
+
markerEnd = "arrow";
|
|
173136
|
+
} else if (children?.ArrowLeft) {
|
|
173137
|
+
type = "arrow";
|
|
173138
|
+
markerStart = "arrow";
|
|
173139
|
+
} else if (children?.DottedArrowRight) {
|
|
173140
|
+
type = "dotted";
|
|
173141
|
+
markerEnd = "arrow";
|
|
173142
|
+
} else if (children?.DottedArrowLeft) {
|
|
173143
|
+
type = "dotted";
|
|
173144
|
+
markerStart = "arrow";
|
|
173145
|
+
} else if (children?.ThickArrowRight) {
|
|
173146
|
+
type = "thick";
|
|
173147
|
+
markerEnd = "arrow";
|
|
173148
|
+
} else if (children?.ThickArrowLeft) {
|
|
173149
|
+
type = "thick";
|
|
173150
|
+
markerStart = "arrow";
|
|
173151
|
+
} else if (children?.LinkRight || children?.LinkLeft || children?.Line || children?.TwoDashes || children?.DottedLine || children?.ThickLine) {
|
|
173152
|
+
if (children?.DottedLine)
|
|
173153
|
+
type = "dotted";
|
|
173154
|
+
else if (children?.ThickLine)
|
|
173155
|
+
type = "thick";
|
|
173156
|
+
else
|
|
173157
|
+
type = "open";
|
|
173158
|
+
} else if (children?.InvisibleLink) {
|
|
173159
|
+
type = "invisible";
|
|
173160
|
+
}
|
|
173161
|
+
if (markerEnd === "none" && (children?.ArrowRight || children.ThickArrowRight || children.DottedArrowRight)) {
|
|
173162
|
+
markerEnd = "arrow";
|
|
173163
|
+
}
|
|
173164
|
+
if (markerStart === "none" && (children?.ArrowLeft || children.ThickArrowLeft || children.DottedArrowLeft)) {
|
|
173165
|
+
markerStart = "arrow";
|
|
173166
|
+
}
|
|
173167
|
+
const textNode = children?.linkText?.[0];
|
|
173168
|
+
if (textNode) {
|
|
173169
|
+
label = this.extractTextContent(textNode);
|
|
173170
|
+
} else if (children.linkTextInline?.[0]) {
|
|
173171
|
+
label = this.extractTextContent(children.linkTextInline[0]);
|
|
173172
|
+
} else if (children.inlineCarrier?.[0]) {
|
|
173173
|
+
const token = children.inlineCarrier[0];
|
|
173174
|
+
const raw = token.image.trim();
|
|
173175
|
+
if (raw.startsWith("-.") && raw.endsWith(".-")) {
|
|
173176
|
+
type = "dotted";
|
|
173177
|
+
} else if (raw.startsWith("==") && raw.endsWith("==")) {
|
|
173178
|
+
type = "thick";
|
|
173179
|
+
} else if (raw.startsWith("--") && raw.endsWith("--")) {
|
|
173180
|
+
}
|
|
173181
|
+
if (children.ArrowRight || children.DottedArrowRight || children.ThickArrowRight) {
|
|
173182
|
+
markerEnd = "arrow";
|
|
173183
|
+
}
|
|
173184
|
+
if (children.ArrowLeft || children.DottedArrowLeft || children.ThickArrowLeft) {
|
|
173185
|
+
markerStart = "arrow";
|
|
173186
|
+
}
|
|
173187
|
+
const strip = (str) => {
|
|
173188
|
+
if (str.startsWith("-.") && str.endsWith(".-") || str.startsWith("==") && str.endsWith("==") || str.startsWith("--") && str.endsWith("--")) {
|
|
173189
|
+
return str.slice(2, -2).trim();
|
|
173190
|
+
}
|
|
173191
|
+
return str;
|
|
173192
|
+
};
|
|
173193
|
+
label = strip(raw);
|
|
173194
|
+
}
|
|
173195
|
+
return { type, label, markerStart, markerEnd };
|
|
173196
|
+
}
|
|
173197
|
+
processSubgraph(subgraph) {
|
|
173198
|
+
const children = subgraph.children;
|
|
173199
|
+
let id = `subgraph_${this.subgraphs.length}`;
|
|
173200
|
+
let label;
|
|
173201
|
+
const idToken = children?.subgraphId?.[0] || children?.Identifier?.[0];
|
|
173202
|
+
if (idToken) {
|
|
173203
|
+
id = idToken.image;
|
|
173204
|
+
}
|
|
173205
|
+
if (children?.SquareOpen && children?.nodeContent) {
|
|
173206
|
+
label = this.extractTextContent(children.nodeContent[0]);
|
|
173207
|
+
} else if (children.subgraphTitleQ?.[0]) {
|
|
173208
|
+
const qt = children.subgraphTitleQ[0];
|
|
173209
|
+
const img = qt.image;
|
|
173210
|
+
label = img && img.length >= 2 && (img.startsWith('"') || img.startsWith("'")) ? img.slice(1, -1) : img;
|
|
173211
|
+
} else if (children?.subgraphLabel) {
|
|
173212
|
+
label = this.extractTextContent(children.subgraphLabel[0]);
|
|
173213
|
+
}
|
|
173214
|
+
if (!label && id !== `subgraph_${this.subgraphs.length}`) {
|
|
173215
|
+
label = id;
|
|
173216
|
+
}
|
|
173217
|
+
const parent = this.currentSubgraphStack.length ? this.currentSubgraphStack[this.currentSubgraphStack.length - 1] : void 0;
|
|
173218
|
+
const sg = { id, label, nodes: [], parent };
|
|
173219
|
+
this.subgraphs.push(sg);
|
|
173220
|
+
this.currentSubgraphStack.push(id);
|
|
173221
|
+
const statements = children?.subgraphStatement;
|
|
173222
|
+
if (statements) {
|
|
173223
|
+
for (const stmt of statements) {
|
|
173224
|
+
if (stmt.children?.nodeStatement) {
|
|
173225
|
+
this.processNodeStatement(stmt.children.nodeStatement[0]);
|
|
173226
|
+
} else if (stmt.children?.subgraph) {
|
|
173227
|
+
this.processSubgraph(stmt.children.subgraph[0]);
|
|
173228
|
+
}
|
|
173229
|
+
}
|
|
173230
|
+
}
|
|
173231
|
+
this.currentSubgraphStack.pop();
|
|
173232
|
+
}
|
|
173233
|
+
// ---- Styling helpers ----
|
|
173234
|
+
processClassDef(cst) {
|
|
173235
|
+
const idTok = cst.children?.Identifier?.[0];
|
|
173236
|
+
if (!idTok)
|
|
173237
|
+
return;
|
|
173238
|
+
const className = idTok.image;
|
|
173239
|
+
const props = this.collectStyleProps(cst, { skipFirstIdentifier: true });
|
|
173240
|
+
if (Object.keys(props).length) {
|
|
173241
|
+
this.classStyles.set(className, props);
|
|
173242
|
+
for (const [nodeId, classes] of this.nodeClasses.entries()) {
|
|
173243
|
+
if (classes.has(className)) {
|
|
173244
|
+
const node = this.nodes.get(nodeId);
|
|
173245
|
+
if (node) {
|
|
173246
|
+
node.style = { ...node.style || {}, ...this.computeNodeStyle(nodeId) };
|
|
173247
|
+
}
|
|
173248
|
+
}
|
|
173249
|
+
}
|
|
173250
|
+
}
|
|
173251
|
+
}
|
|
173252
|
+
processClassAssign(cst) {
|
|
173253
|
+
const ids = cst.children?.Identifier || [];
|
|
173254
|
+
if (!ids.length)
|
|
173255
|
+
return;
|
|
173256
|
+
const classNameTok = cst.children.className?.[0];
|
|
173257
|
+
const className = classNameTok?.image || ids[ids.length - 1].image;
|
|
173258
|
+
const nodeIds = classNameTok ? ids.slice(0, -1) : ids.slice(0, -1);
|
|
173259
|
+
for (const tok of nodeIds) {
|
|
173260
|
+
const id = tok.image;
|
|
173261
|
+
const set = this.nodeClasses.get(id) || /* @__PURE__ */ new Set();
|
|
173262
|
+
set.add(className);
|
|
173263
|
+
this.nodeClasses.set(id, set);
|
|
173264
|
+
const node = this.nodes.get(id);
|
|
173265
|
+
if (node) {
|
|
173266
|
+
node.style = { ...node.style || {}, ...this.computeNodeStyle(id) };
|
|
173267
|
+
}
|
|
173268
|
+
}
|
|
173269
|
+
}
|
|
173270
|
+
processStyle(cst) {
|
|
173271
|
+
const idTok = cst.children?.Identifier?.[0];
|
|
173272
|
+
if (!idTok)
|
|
173273
|
+
return;
|
|
173274
|
+
const nodeId = idTok.image;
|
|
173275
|
+
const props = this.collectStyleProps(cst, { skipFirstIdentifier: true });
|
|
173276
|
+
if (Object.keys(props).length) {
|
|
173277
|
+
this.nodeStyles.set(nodeId, props);
|
|
173278
|
+
const node = this.nodes.get(nodeId);
|
|
173279
|
+
if (node) {
|
|
173280
|
+
node.style = { ...node.style || {}, ...this.computeNodeStyle(nodeId) };
|
|
173281
|
+
}
|
|
173282
|
+
}
|
|
173283
|
+
}
|
|
173284
|
+
collectStyleProps(cst, opts = {}) {
|
|
173285
|
+
const tokens = [];
|
|
173286
|
+
const ch = cst.children || {};
|
|
173287
|
+
const push = (arr, type = "t") => arr?.forEach((t3) => tokens.push({ text: t3.image, startOffset: t3.startOffset ?? 0, type }));
|
|
173288
|
+
push(ch.Text, "Text");
|
|
173289
|
+
push(ch.Identifier, "Identifier");
|
|
173290
|
+
push(ch.ColorValue, "Color");
|
|
173291
|
+
push(ch.Colon, "Colon");
|
|
173292
|
+
push(ch.Comma, "Comma");
|
|
173293
|
+
push(ch.NumberLiteral, "Number");
|
|
173294
|
+
tokens.sort((a3, b3) => a3.startOffset - b3.startOffset);
|
|
173295
|
+
if (opts.skipFirstIdentifier) {
|
|
173296
|
+
const idx = tokens.findIndex((t3) => t3.type === "Identifier");
|
|
173297
|
+
if (idx >= 0)
|
|
173298
|
+
tokens.splice(idx, 1);
|
|
173299
|
+
}
|
|
173300
|
+
const joined = tokens.map((t3) => t3.text).join("");
|
|
173301
|
+
const props = {};
|
|
173302
|
+
for (const seg of joined.split(",").map((s3) => s3.trim()).filter(Boolean)) {
|
|
173303
|
+
const [k3, v3] = seg.split(":");
|
|
173304
|
+
if (k3 && v3)
|
|
173305
|
+
props[k3.trim()] = v3.trim();
|
|
173306
|
+
}
|
|
173307
|
+
return props;
|
|
173308
|
+
}
|
|
173309
|
+
computeNodeStyle(nodeId) {
|
|
173310
|
+
const out = {};
|
|
173311
|
+
const classes = this.nodeClasses.get(nodeId);
|
|
173312
|
+
if (classes) {
|
|
173313
|
+
for (const c3 of classes) {
|
|
173314
|
+
const s3 = this.classStyles.get(c3);
|
|
173315
|
+
if (s3)
|
|
173316
|
+
Object.assign(out, this.normalizeStyle(s3));
|
|
173317
|
+
}
|
|
173318
|
+
}
|
|
173319
|
+
const direct = this.nodeStyles.get(nodeId);
|
|
173320
|
+
if (direct)
|
|
173321
|
+
Object.assign(out, this.normalizeStyle(direct));
|
|
173322
|
+
return out;
|
|
173323
|
+
}
|
|
173324
|
+
normalizeStyle(s3) {
|
|
173325
|
+
const out = {};
|
|
173326
|
+
for (const [kRaw, vRaw] of Object.entries(s3)) {
|
|
173327
|
+
const k3 = kRaw.trim().toLowerCase();
|
|
173328
|
+
const v3 = vRaw.trim();
|
|
173329
|
+
if (k3 === "stroke-width") {
|
|
173330
|
+
const num = parseFloat(v3);
|
|
173331
|
+
if (!Number.isNaN(num))
|
|
173332
|
+
out.strokeWidth = num;
|
|
173333
|
+
} else if (k3 === "stroke") {
|
|
173334
|
+
out.stroke = v3;
|
|
173335
|
+
} else if (k3 === "fill") {
|
|
173336
|
+
out.fill = v3;
|
|
173337
|
+
}
|
|
173338
|
+
}
|
|
173339
|
+
return out;
|
|
173340
|
+
}
|
|
173341
|
+
};
|
|
172288
173342
|
}
|
|
172289
173343
|
});
|
|
172290
173344
|
|
|
@@ -179967,16 +181021,2435 @@ var require_dagre = __commonJS({
|
|
|
179967
181021
|
});
|
|
179968
181022
|
|
|
179969
181023
|
// node_modules/@probelabs/maid/out/renderer/layout.js
|
|
179970
|
-
var import_dagre;
|
|
181024
|
+
var import_dagre, DagreLayoutEngine;
|
|
179971
181025
|
var init_layout = __esm({
|
|
179972
181026
|
"node_modules/@probelabs/maid/out/renderer/layout.js"() {
|
|
179973
181027
|
import_dagre = __toESM(require_dagre(), 1);
|
|
181028
|
+
DagreLayoutEngine = class {
|
|
181029
|
+
constructor() {
|
|
181030
|
+
this.nodeWidth = 120;
|
|
181031
|
+
this.nodeHeight = 50;
|
|
181032
|
+
this.rankSep = 50;
|
|
181033
|
+
this.nodeSep = 50;
|
|
181034
|
+
this.edgeSep = 10;
|
|
181035
|
+
}
|
|
181036
|
+
layout(graph) {
|
|
181037
|
+
const g3 = new import_dagre.default.graphlib.Graph();
|
|
181038
|
+
const hasClusters = !!(graph.subgraphs && graph.subgraphs.length > 0);
|
|
181039
|
+
const dir = this.mapDirection(graph.direction);
|
|
181040
|
+
let ranksep = this.rankSep;
|
|
181041
|
+
let nodesep = this.nodeSep;
|
|
181042
|
+
if (hasClusters) {
|
|
181043
|
+
if (dir === "LR" || dir === "RL") {
|
|
181044
|
+
ranksep += 20;
|
|
181045
|
+
nodesep += 70;
|
|
181046
|
+
} else {
|
|
181047
|
+
ranksep += 70;
|
|
181048
|
+
nodesep += 20;
|
|
181049
|
+
}
|
|
181050
|
+
}
|
|
181051
|
+
const graphConfig = {
|
|
181052
|
+
rankdir: dir,
|
|
181053
|
+
ranksep,
|
|
181054
|
+
nodesep,
|
|
181055
|
+
edgesep: this.edgeSep,
|
|
181056
|
+
marginx: 20,
|
|
181057
|
+
marginy: 20
|
|
181058
|
+
};
|
|
181059
|
+
if (hasClusters && (dir === "LR" || dir === "RL")) {
|
|
181060
|
+
graphConfig.ranker = "longest-path";
|
|
181061
|
+
graphConfig.acyclicer = "greedy";
|
|
181062
|
+
}
|
|
181063
|
+
if (hasClusters) {
|
|
181064
|
+
graphConfig.compound = true;
|
|
181065
|
+
}
|
|
181066
|
+
g3.setGraph(graphConfig);
|
|
181067
|
+
g3.setDefaultEdgeLabel(() => ({}));
|
|
181068
|
+
if (graph.subgraphs && graph.subgraphs.length > 0) {
|
|
181069
|
+
for (const subgraph of graph.subgraphs) {
|
|
181070
|
+
g3.setNode(subgraph.id, { label: subgraph.label || subgraph.id, clusterLabelPos: "top" });
|
|
181071
|
+
}
|
|
181072
|
+
}
|
|
181073
|
+
for (const node of graph.nodes) {
|
|
181074
|
+
const dimensions = this.calculateNodeDimensions(node.label, node.shape);
|
|
181075
|
+
g3.setNode(node.id, {
|
|
181076
|
+
width: dimensions.width,
|
|
181077
|
+
height: dimensions.height,
|
|
181078
|
+
label: node.label,
|
|
181079
|
+
shape: node.shape
|
|
181080
|
+
});
|
|
181081
|
+
}
|
|
181082
|
+
if (graph.subgraphs && graph.subgraphs.length > 0) {
|
|
181083
|
+
for (const subgraph of graph.subgraphs) {
|
|
181084
|
+
for (const nodeId of subgraph.nodes) {
|
|
181085
|
+
if (g3.hasNode(nodeId)) {
|
|
181086
|
+
try {
|
|
181087
|
+
g3.setParent(nodeId, subgraph.id);
|
|
181088
|
+
} catch {
|
|
181089
|
+
}
|
|
181090
|
+
}
|
|
181091
|
+
}
|
|
181092
|
+
if (subgraph.parent && g3.hasNode(subgraph.parent)) {
|
|
181093
|
+
try {
|
|
181094
|
+
g3.setParent(subgraph.id, subgraph.parent);
|
|
181095
|
+
} catch {
|
|
181096
|
+
}
|
|
181097
|
+
}
|
|
181098
|
+
}
|
|
181099
|
+
}
|
|
181100
|
+
for (const edge of graph.edges) {
|
|
181101
|
+
g3.setEdge(edge.source, edge.target, {
|
|
181102
|
+
label: edge.label,
|
|
181103
|
+
width: edge.label ? edge.label.length * 8 : 0,
|
|
181104
|
+
height: edge.label ? 20 : 0
|
|
181105
|
+
});
|
|
181106
|
+
}
|
|
181107
|
+
import_dagre.default.layout(g3);
|
|
181108
|
+
const graphInfo = g3.graph();
|
|
181109
|
+
const layoutNodes = [];
|
|
181110
|
+
const layoutEdges = [];
|
|
181111
|
+
for (const node of graph.nodes) {
|
|
181112
|
+
const nodeLayout = g3.node(node.id);
|
|
181113
|
+
if (nodeLayout) {
|
|
181114
|
+
layoutNodes.push({
|
|
181115
|
+
...node,
|
|
181116
|
+
x: nodeLayout.x - nodeLayout.width / 2,
|
|
181117
|
+
y: nodeLayout.y - nodeLayout.height / 2,
|
|
181118
|
+
width: nodeLayout.width,
|
|
181119
|
+
height: nodeLayout.height
|
|
181120
|
+
});
|
|
181121
|
+
}
|
|
181122
|
+
}
|
|
181123
|
+
const layoutSubgraphs = [];
|
|
181124
|
+
if (graph.subgraphs && graph.subgraphs.length > 0) {
|
|
181125
|
+
for (const sg of graph.subgraphs) {
|
|
181126
|
+
const members = layoutNodes.filter((nd) => sg.nodes.includes(nd.id));
|
|
181127
|
+
if (members.length) {
|
|
181128
|
+
const minX = Math.min(...members.map((m3) => m3.x));
|
|
181129
|
+
const minY = Math.min(...members.map((m3) => m3.y));
|
|
181130
|
+
const maxX = Math.max(...members.map((m3) => m3.x + m3.width));
|
|
181131
|
+
const maxY = Math.max(...members.map((m3) => m3.y + m3.height));
|
|
181132
|
+
const pad = 30;
|
|
181133
|
+
layoutSubgraphs.push({
|
|
181134
|
+
id: sg.id,
|
|
181135
|
+
label: sg.label || sg.id,
|
|
181136
|
+
x: minX - pad,
|
|
181137
|
+
y: minY - pad - 18,
|
|
181138
|
+
// space for title
|
|
181139
|
+
width: maxX - minX + pad * 2,
|
|
181140
|
+
height: maxY - minY + pad * 2 + 18,
|
|
181141
|
+
parent: sg.parent
|
|
181142
|
+
});
|
|
181143
|
+
}
|
|
181144
|
+
}
|
|
181145
|
+
const byId = Object.fromEntries(layoutSubgraphs.map((s3) => [s3.id, s3]));
|
|
181146
|
+
for (const sg of layoutSubgraphs) {
|
|
181147
|
+
if (!sg.parent)
|
|
181148
|
+
continue;
|
|
181149
|
+
const p3 = byId[sg.parent];
|
|
181150
|
+
if (!p3)
|
|
181151
|
+
continue;
|
|
181152
|
+
const minX = Math.min(p3.x, sg.x);
|
|
181153
|
+
const minY = Math.min(p3.y, sg.y);
|
|
181154
|
+
const maxX = Math.max(p3.x + p3.width, sg.x + sg.width);
|
|
181155
|
+
const maxY = Math.max(p3.y + p3.height, sg.y + sg.height);
|
|
181156
|
+
p3.x = minX;
|
|
181157
|
+
p3.y = minY;
|
|
181158
|
+
p3.width = maxX - minX;
|
|
181159
|
+
p3.height = maxY - minY;
|
|
181160
|
+
}
|
|
181161
|
+
}
|
|
181162
|
+
const subgraphById = Object.fromEntries(layoutSubgraphs.map((sg) => [sg.id, sg]));
|
|
181163
|
+
for (const edge of graph.edges) {
|
|
181164
|
+
const edgeLayout = g3.edge(edge.source, edge.target);
|
|
181165
|
+
let pts = edgeLayout && Array.isArray(edgeLayout.points) ? edgeLayout.points.slice() : [];
|
|
181166
|
+
const hasNaN = pts.some((p3) => !Number.isFinite(p3.x) || !Number.isFinite(p3.y));
|
|
181167
|
+
const srcSg = subgraphById[edge.source];
|
|
181168
|
+
const dstSg = subgraphById[edge.target];
|
|
181169
|
+
let synthesized = false;
|
|
181170
|
+
if (!pts.length || hasNaN || srcSg || dstSg) {
|
|
181171
|
+
const rankdir = this.mapDirection(graph.direction);
|
|
181172
|
+
const getNode = (id) => {
|
|
181173
|
+
const n3 = g3.node(id);
|
|
181174
|
+
if (!n3)
|
|
181175
|
+
return void 0;
|
|
181176
|
+
return {
|
|
181177
|
+
id,
|
|
181178
|
+
label: n3.label || id,
|
|
181179
|
+
shape: n3.shape || "rectangle",
|
|
181180
|
+
x: n3.x - n3.width / 2,
|
|
181181
|
+
y: n3.y - n3.height / 2,
|
|
181182
|
+
width: n3.width,
|
|
181183
|
+
height: n3.height,
|
|
181184
|
+
style: {}
|
|
181185
|
+
};
|
|
181186
|
+
};
|
|
181187
|
+
const start = srcSg ? this.clusterAnchor(srcSg, rankdir, "out") : this.nodeAnchor(getNode(edge.source), rankdir, "out");
|
|
181188
|
+
const end = dstSg ? this.clusterAnchor(dstSg, rankdir, "in") : this.nodeAnchor(getNode(edge.target), rankdir, "in");
|
|
181189
|
+
if (start && end) {
|
|
181190
|
+
const PAD = 20;
|
|
181191
|
+
const horizontallyAdjacent = srcSg && dstSg && Math.abs(srcSg.x - dstSg.x) > Math.abs(srcSg.y - dstSg.y);
|
|
181192
|
+
const horizontalSubgraphs = horizontallyAdjacent;
|
|
181193
|
+
if (rankdir === "LR" || rankdir === "RL") {
|
|
181194
|
+
const outX = start.x + (rankdir === "LR" ? PAD : -PAD);
|
|
181195
|
+
const inX = end.x + (rankdir === "LR" ? -PAD : PAD);
|
|
181196
|
+
const startOut = { x: srcSg ? outX : start.x, y: start.y };
|
|
181197
|
+
const endPre = { x: dstSg ? inX : end.x, y: end.y };
|
|
181198
|
+
const alpha = 0.68;
|
|
181199
|
+
const midX = startOut.x + (endPre.x - startOut.x) * alpha;
|
|
181200
|
+
const m1 = { x: midX, y: startOut.y };
|
|
181201
|
+
const m22 = { x: midX, y: endPre.y };
|
|
181202
|
+
pts = dstSg ? [start, startOut, m1, m22, endPre] : [start, startOut, m1, m22, endPre, end];
|
|
181203
|
+
} else {
|
|
181204
|
+
if (horizontalSubgraphs && srcSg && dstSg) {
|
|
181205
|
+
const midY = (srcSg.y + srcSg.height / 2 + dstSg.y + dstSg.height / 2) / 2;
|
|
181206
|
+
if (srcSg.x < dstSg.x) {
|
|
181207
|
+
const startX = srcSg.x + srcSg.width;
|
|
181208
|
+
const endX = dstSg.x;
|
|
181209
|
+
pts = [{ x: startX, y: midY }, { x: endX, y: midY }];
|
|
181210
|
+
} else {
|
|
181211
|
+
const startX = srcSg.x;
|
|
181212
|
+
const endX = dstSg.x + dstSg.width;
|
|
181213
|
+
pts = [{ x: startX, y: midY }, { x: endX, y: midY }];
|
|
181214
|
+
}
|
|
181215
|
+
} else {
|
|
181216
|
+
const outY = start.y + (rankdir === "TD" ? PAD : -PAD);
|
|
181217
|
+
const inY = end.y + (rankdir === "TD" ? -PAD : PAD);
|
|
181218
|
+
const startOut = { x: start.x, y: srcSg ? outY : start.y };
|
|
181219
|
+
const endPre = { x: end.x, y: dstSg ? inY : end.y };
|
|
181220
|
+
const alpha = 0.68;
|
|
181221
|
+
const midY = startOut.y + (endPre.y - startOut.y) * alpha;
|
|
181222
|
+
const m1 = { x: startOut.x, y: midY };
|
|
181223
|
+
const m22 = { x: endPre.x, y: midY };
|
|
181224
|
+
pts = dstSg ? [start, startOut, m1, m22, endPre] : [start, startOut, m1, m22, endPre, end];
|
|
181225
|
+
}
|
|
181226
|
+
}
|
|
181227
|
+
synthesized = true;
|
|
181228
|
+
}
|
|
181229
|
+
}
|
|
181230
|
+
if (pts.length) {
|
|
181231
|
+
layoutEdges.push({ ...edge, points: pts, pathMode: synthesized ? "orthogonal" : "smooth" });
|
|
181232
|
+
}
|
|
181233
|
+
}
|
|
181234
|
+
const rawW = graphInfo.width;
|
|
181235
|
+
const rawH = graphInfo.height;
|
|
181236
|
+
const w3 = Number.isFinite(rawW) && rawW > 0 ? rawW : 800;
|
|
181237
|
+
const h3 = Number.isFinite(rawH) && rawH > 0 ? rawH : 600;
|
|
181238
|
+
return {
|
|
181239
|
+
nodes: layoutNodes,
|
|
181240
|
+
edges: layoutEdges,
|
|
181241
|
+
width: w3,
|
|
181242
|
+
height: h3,
|
|
181243
|
+
subgraphs: layoutSubgraphs
|
|
181244
|
+
};
|
|
181245
|
+
}
|
|
181246
|
+
mapDirection(direction) {
|
|
181247
|
+
switch (direction) {
|
|
181248
|
+
case "TB":
|
|
181249
|
+
case "TD":
|
|
181250
|
+
return "TB";
|
|
181251
|
+
case "BT":
|
|
181252
|
+
return "BT";
|
|
181253
|
+
case "LR":
|
|
181254
|
+
return "LR";
|
|
181255
|
+
case "RL":
|
|
181256
|
+
return "RL";
|
|
181257
|
+
default:
|
|
181258
|
+
return "TB";
|
|
181259
|
+
}
|
|
181260
|
+
}
|
|
181261
|
+
calculateNodeDimensions(label, shape) {
|
|
181262
|
+
const charWidth = 7;
|
|
181263
|
+
const padding = 20;
|
|
181264
|
+
const minWidth = 80;
|
|
181265
|
+
const minHeight = 40;
|
|
181266
|
+
const maxWidth = 240;
|
|
181267
|
+
const lineHeight = 18;
|
|
181268
|
+
const explicitLines = label.split(/<\s*br\s*\/?\s*>/i);
|
|
181269
|
+
const hasExplicitBreaks = explicitLines.length > 1;
|
|
181270
|
+
let width;
|
|
181271
|
+
let lines;
|
|
181272
|
+
if (hasExplicitBreaks) {
|
|
181273
|
+
const maxLineLength = Math.max(...explicitLines.map((line) => line.length));
|
|
181274
|
+
width = Math.min(Math.max(maxLineLength * charWidth + padding * 2, minWidth), maxWidth);
|
|
181275
|
+
lines = explicitLines.length;
|
|
181276
|
+
} else {
|
|
181277
|
+
width = Math.min(Math.max(label.length * charWidth + padding * 2, minWidth), maxWidth);
|
|
181278
|
+
const charsPerLine = Math.max(1, Math.floor((width - padding * 2) / charWidth));
|
|
181279
|
+
lines = Math.ceil(label.length / charsPerLine);
|
|
181280
|
+
}
|
|
181281
|
+
let height = Math.max(lines * lineHeight + padding, minHeight);
|
|
181282
|
+
switch (shape) {
|
|
181283
|
+
case "circle":
|
|
181284
|
+
const size = Math.max(width, height);
|
|
181285
|
+
width = size;
|
|
181286
|
+
height = size;
|
|
181287
|
+
break;
|
|
181288
|
+
case "diamond": {
|
|
181289
|
+
const size2 = Math.max(width, height) * 1.2;
|
|
181290
|
+
width = size2;
|
|
181291
|
+
height = size2;
|
|
181292
|
+
break;
|
|
181293
|
+
}
|
|
181294
|
+
case "hexagon":
|
|
181295
|
+
width *= 1.3;
|
|
181296
|
+
height *= 1.2;
|
|
181297
|
+
break;
|
|
181298
|
+
case "stadium":
|
|
181299
|
+
width *= 1.2;
|
|
181300
|
+
break;
|
|
181301
|
+
case "cylinder":
|
|
181302
|
+
height *= 1.5;
|
|
181303
|
+
break;
|
|
181304
|
+
case "subroutine":
|
|
181305
|
+
case "double":
|
|
181306
|
+
width += 10;
|
|
181307
|
+
height += 10;
|
|
181308
|
+
break;
|
|
181309
|
+
case "parallelogram":
|
|
181310
|
+
case "trapezoid":
|
|
181311
|
+
width *= 1.3;
|
|
181312
|
+
break;
|
|
181313
|
+
}
|
|
181314
|
+
return { width: Math.round(width), height: Math.round(height) };
|
|
181315
|
+
}
|
|
181316
|
+
clusterAnchor(sg, rankdir, mode) {
|
|
181317
|
+
switch (rankdir) {
|
|
181318
|
+
case "LR":
|
|
181319
|
+
return { x: mode === "out" ? sg.x + sg.width : sg.x, y: sg.y + sg.height / 2 };
|
|
181320
|
+
case "RL":
|
|
181321
|
+
return { x: mode === "out" ? sg.x : sg.x + sg.width, y: sg.y + sg.height / 2 };
|
|
181322
|
+
case "BT":
|
|
181323
|
+
return { x: sg.x + sg.width / 2, y: mode === "out" ? sg.y : sg.y + sg.height };
|
|
181324
|
+
case "TB":
|
|
181325
|
+
default:
|
|
181326
|
+
return { x: sg.x + sg.width / 2, y: mode === "out" ? sg.y + sg.height : sg.y };
|
|
181327
|
+
}
|
|
181328
|
+
}
|
|
181329
|
+
nodeAnchor(n3, rankdir, mode) {
|
|
181330
|
+
if (!n3)
|
|
181331
|
+
return { x: 0, y: 0 };
|
|
181332
|
+
switch (rankdir) {
|
|
181333
|
+
case "LR":
|
|
181334
|
+
return { x: mode === "in" ? n3.x : n3.x + n3.width, y: n3.y + n3.height / 2 };
|
|
181335
|
+
case "RL":
|
|
181336
|
+
return { x: mode === "in" ? n3.x + n3.width : n3.x, y: n3.y + n3.height / 2 };
|
|
181337
|
+
case "BT":
|
|
181338
|
+
return { x: n3.x + n3.width / 2, y: mode === "in" ? n3.y + n3.height : n3.y };
|
|
181339
|
+
case "TB":
|
|
181340
|
+
default:
|
|
181341
|
+
return { x: n3.x + n3.width / 2, y: mode === "in" ? n3.y : n3.y + n3.height };
|
|
181342
|
+
}
|
|
181343
|
+
}
|
|
181344
|
+
};
|
|
181345
|
+
}
|
|
181346
|
+
});
|
|
181347
|
+
|
|
181348
|
+
// node_modules/@probelabs/maid/out/renderer/arrow-utils.js
|
|
181349
|
+
function triangleAtEnd(start, end, color = "#333", length = 8, width = 6) {
|
|
181350
|
+
const vx = end.x - start.x;
|
|
181351
|
+
const vy = end.y - start.y;
|
|
181352
|
+
const len = Math.hypot(vx, vy) || 1;
|
|
181353
|
+
const ux = vx / len;
|
|
181354
|
+
const uy = vy / len;
|
|
181355
|
+
const nx = -uy;
|
|
181356
|
+
const ny = ux;
|
|
181357
|
+
const baseX = end.x - ux * length;
|
|
181358
|
+
const baseY = end.y - uy * length;
|
|
181359
|
+
const p2x = baseX + nx * (width / 2), p2y = baseY + ny * (width / 2);
|
|
181360
|
+
const p3x = baseX - nx * (width / 2), p3y = baseY - ny * (width / 2);
|
|
181361
|
+
return `<path d="M${end.x},${end.y} L${p2x},${p2y} L${p3x},${p3y} Z" fill="${color}" />`;
|
|
181362
|
+
}
|
|
181363
|
+
function triangleAtStart(first2, second, color = "#333", length = 8, width = 6) {
|
|
181364
|
+
const vx = second.x - first2.x;
|
|
181365
|
+
const vy = second.y - first2.y;
|
|
181366
|
+
const len = Math.hypot(vx, vy) || 1;
|
|
181367
|
+
const ux = vx / len;
|
|
181368
|
+
const uy = vy / len;
|
|
181369
|
+
const nx = -uy;
|
|
181370
|
+
const ny = ux;
|
|
181371
|
+
const tipX = first2.x - ux * length;
|
|
181372
|
+
const tipY = first2.y - uy * length;
|
|
181373
|
+
const p2x = first2.x + nx * (width / 2), p2y = first2.y + ny * (width / 2);
|
|
181374
|
+
const p3x = first2.x - nx * (width / 2), p3y = first2.y - ny * (width / 2);
|
|
181375
|
+
return `<path d="M${tipX},${tipY} L${p2x},${p2y} L${p3x},${p3y} Z" fill="${color}" />`;
|
|
181376
|
+
}
|
|
181377
|
+
var init_arrow_utils = __esm({
|
|
181378
|
+
"node_modules/@probelabs/maid/out/renderer/arrow-utils.js"() {
|
|
181379
|
+
}
|
|
181380
|
+
});
|
|
181381
|
+
|
|
181382
|
+
// node_modules/@probelabs/maid/out/renderer/styles.js
|
|
181383
|
+
function buildSharedCss(opts = {}) {
|
|
181384
|
+
const fontFamily = opts.fontFamily || "Arial, sans-serif";
|
|
181385
|
+
const fontSize = opts.fontSize ?? 14;
|
|
181386
|
+
const nodeFill = opts.nodeFill || "#eef0ff";
|
|
181387
|
+
const nodeStroke = opts.nodeStroke || "#3f3f3f";
|
|
181388
|
+
const edgeStroke = opts.edgeStroke || "#555555";
|
|
181389
|
+
return `
|
|
181390
|
+
.node-shape { fill: ${nodeFill}; stroke: ${nodeStroke}; stroke-width: 1px; }
|
|
181391
|
+
.node-label { fill: #333; font-family: ${fontFamily}; font-size: ${fontSize}px; }
|
|
181392
|
+
.edge-path { stroke: ${edgeStroke}; stroke-width: 2px; fill: none; }
|
|
181393
|
+
.edge-label-bg { fill: rgba(232,232,232, 0.8); opacity: 0.5; }
|
|
181394
|
+
.edge-label-text { fill: #333; font-family: ${fontFamily}; font-size: ${Math.max(10, fontSize - 2)}px; }
|
|
181395
|
+
|
|
181396
|
+
/* Cluster (flowchart + sequence blocks) */
|
|
181397
|
+
.cluster-bg { fill: #ffffde; }
|
|
181398
|
+
.cluster-border { fill: none; stroke: #aaaa33; stroke-width: 1px; }
|
|
181399
|
+
.cluster-title-bg { fill: rgba(255,255,255,0.8); }
|
|
181400
|
+
.cluster-label-text { fill: #333; font-family: ${fontFamily}; font-size: 12px; }
|
|
181401
|
+
|
|
181402
|
+
/* Notes */
|
|
181403
|
+
.note { fill: #fff5ad; stroke: #aaaa33; stroke-width: 1px; }
|
|
181404
|
+
.note-text { fill: #333; font-family: ${fontFamily}; font-size: 12px; }
|
|
181405
|
+
|
|
181406
|
+
/* Sequence-specific add-ons (safe for flowcharts too) */
|
|
181407
|
+
.actor-rect { fill: #eaeaea; stroke: #666; stroke-width: 1.5px; }
|
|
181408
|
+
.actor-label { fill: #111; font-family: ${fontFamily}; font-size: 16px; }
|
|
181409
|
+
.lifeline { stroke: #999; stroke-width: 0.5px; }
|
|
181410
|
+
.activation { fill: #f4f4f4; stroke: #666; stroke-width: 1px; }
|
|
181411
|
+
.msg-line { stroke: #333; stroke-width: 1.5px; fill: none; }
|
|
181412
|
+
.msg-line.dotted { stroke-dasharray: 2 2; }
|
|
181413
|
+
.msg-line.thick { stroke-width: 3px; }
|
|
181414
|
+
.msg-label { fill: #333; font-family: ${fontFamily}; font-size: 12px; dominant-baseline: middle; }
|
|
181415
|
+
.msg-label-bg { fill: #ffffff; stroke: #cccccc; stroke-width: 1px; rx: 3; }
|
|
181416
|
+
`;
|
|
181417
|
+
}
|
|
181418
|
+
var init_styles = __esm({
|
|
181419
|
+
"node_modules/@probelabs/maid/out/renderer/styles.js"() {
|
|
181420
|
+
}
|
|
181421
|
+
});
|
|
181422
|
+
|
|
181423
|
+
// node_modules/@probelabs/maid/out/renderer/utils.js
|
|
181424
|
+
function escapeXml(text) {
|
|
181425
|
+
return String(text).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/\"/g, """).replace(/'/g, "'");
|
|
181426
|
+
}
|
|
181427
|
+
function measureText(text, fontSize = 12) {
|
|
181428
|
+
const avg = 0.6 * fontSize;
|
|
181429
|
+
return Math.max(0, Math.round(text.length * avg));
|
|
181430
|
+
}
|
|
181431
|
+
function palette(index) {
|
|
181432
|
+
if (index < DEFAULT_PALETTE.length)
|
|
181433
|
+
return DEFAULT_PALETTE[index];
|
|
181434
|
+
const i3 = index - DEFAULT_PALETTE.length;
|
|
181435
|
+
const hue = i3 * 47 % 360;
|
|
181436
|
+
return `hsl(${hue} 60% 55%)`;
|
|
181437
|
+
}
|
|
181438
|
+
function formatNumber(n3) {
|
|
181439
|
+
if (Number.isInteger(n3))
|
|
181440
|
+
return String(n3);
|
|
181441
|
+
return (Math.round(n3 * 100) / 100).toString();
|
|
181442
|
+
}
|
|
181443
|
+
function formatPercent(value, total) {
|
|
181444
|
+
if (!(total > 0))
|
|
181445
|
+
return "0%";
|
|
181446
|
+
const p3 = value / total * 100;
|
|
181447
|
+
return `${Math.round(p3)}%`;
|
|
181448
|
+
}
|
|
181449
|
+
var DEFAULT_PALETTE;
|
|
181450
|
+
var init_utils4 = __esm({
|
|
181451
|
+
"node_modules/@probelabs/maid/out/renderer/utils.js"() {
|
|
181452
|
+
DEFAULT_PALETTE = [
|
|
181453
|
+
"#ECECFF",
|
|
181454
|
+
"#ffffde",
|
|
181455
|
+
"hsl(80, 100%, 56.2745098039%)",
|
|
181456
|
+
"hsl(240, 100%, 86.2745098039%)",
|
|
181457
|
+
"hsl(60, 100%, 63.5294117647%)",
|
|
181458
|
+
"hsl(80, 100%, 76.2745098039%)",
|
|
181459
|
+
"hsl(300, 100%, 76.2745098039%)",
|
|
181460
|
+
"hsl(180, 100%, 56.2745098039%)",
|
|
181461
|
+
"hsl(0, 100%, 56.2745098039%)",
|
|
181462
|
+
"hsl(300, 100%, 56.2745098039%)",
|
|
181463
|
+
"hsl(150, 100%, 56.2745098039%)",
|
|
181464
|
+
"hsl(0, 100%, 66.2745098039%)"
|
|
181465
|
+
];
|
|
181466
|
+
}
|
|
181467
|
+
});
|
|
181468
|
+
|
|
181469
|
+
// node_modules/@probelabs/maid/out/renderer/block-utils.js
|
|
181470
|
+
function blockBackground(x3, y2, width, height, radius = 0) {
|
|
181471
|
+
return `<g class="cluster-bg-layer" transform="translate(${x3},${y2})">
|
|
181472
|
+
<rect class="cluster-bg" x="0" y="0" width="${width}" height="${height}" rx="${radius}"/>
|
|
181473
|
+
</g>`;
|
|
181474
|
+
}
|
|
181475
|
+
function blockOverlay(x3, y2, width, height, title, branchYs = [], titleYOffset = 0, align = "center", branchAlign = "left", radius = 0) {
|
|
181476
|
+
const parts = [];
|
|
181477
|
+
parts.push(`<g class="cluster-overlay" transform="translate(${x3},${y2})">`);
|
|
181478
|
+
parts.push(`<rect class="cluster-border" x="0" y="0" width="${width}" height="${height}" rx="${radius}"/>`);
|
|
181479
|
+
const titleText = title ? escapeXml(title) : "";
|
|
181480
|
+
if (titleText) {
|
|
181481
|
+
const titleW = Math.max(24, measureText(titleText, 12) + 10);
|
|
181482
|
+
const yBg = -2 + titleYOffset;
|
|
181483
|
+
const yText = 11 + titleYOffset;
|
|
181484
|
+
if (align === "left") {
|
|
181485
|
+
const xBg = 6;
|
|
181486
|
+
parts.push(`<rect class="cluster-title-bg" x="${xBg}" y="${yBg}" width="${titleW}" height="18" rx="3"/>`);
|
|
181487
|
+
parts.push(`<text class="cluster-label-text" x="${xBg + 6}" y="${yText}" text-anchor="start">${titleText}</text>`);
|
|
181488
|
+
} else {
|
|
181489
|
+
const xBg = 6;
|
|
181490
|
+
parts.push(`<rect class="cluster-title-bg" x="${xBg}" y="${yBg}" width="${titleW}" height="18" rx="3"/>`);
|
|
181491
|
+
parts.push(`<text class="cluster-label-text" x="${xBg + titleW / 2}" y="${yText}" text-anchor="middle">${titleText}</text>`);
|
|
181492
|
+
}
|
|
181493
|
+
}
|
|
181494
|
+
for (const br of branchYs) {
|
|
181495
|
+
const yRel = br.y - y2;
|
|
181496
|
+
parts.push(`<line x1="0" y1="${yRel}" x2="${width}" y2="${yRel}" class="cluster-border" />`);
|
|
181497
|
+
if (br.title) {
|
|
181498
|
+
const text = escapeXml(br.title);
|
|
181499
|
+
const bw = Math.max(24, measureText(text, 12) + 10);
|
|
181500
|
+
const xBg = 6;
|
|
181501
|
+
parts.push(`<rect class="cluster-title-bg" x="${xBg}" y="${yRel - 10}" width="${bw}" height="18" rx="3"/>`);
|
|
181502
|
+
if (branchAlign === "left") {
|
|
181503
|
+
parts.push(`<text class="cluster-label-text" x="${xBg + 6}" y="${yRel + 1}" text-anchor="start">${text}</text>`);
|
|
181504
|
+
} else {
|
|
181505
|
+
parts.push(`<text class="cluster-label-text" x="${xBg + bw / 2}" y="${yRel + 1}" text-anchor="middle">${text}</text>`);
|
|
181506
|
+
}
|
|
181507
|
+
}
|
|
181508
|
+
}
|
|
181509
|
+
parts.push("</g>");
|
|
181510
|
+
return parts.join("\n");
|
|
181511
|
+
}
|
|
181512
|
+
var init_block_utils = __esm({
|
|
181513
|
+
"node_modules/@probelabs/maid/out/renderer/block-utils.js"() {
|
|
181514
|
+
init_utils4();
|
|
179974
181515
|
}
|
|
179975
181516
|
});
|
|
179976
181517
|
|
|
179977
181518
|
// node_modules/@probelabs/maid/out/renderer/svg-generator.js
|
|
181519
|
+
var SVGRenderer;
|
|
179978
181520
|
var init_svg_generator = __esm({
|
|
179979
181521
|
"node_modules/@probelabs/maid/out/renderer/svg-generator.js"() {
|
|
181522
|
+
init_arrow_utils();
|
|
181523
|
+
init_styles();
|
|
181524
|
+
init_block_utils();
|
|
181525
|
+
SVGRenderer = class {
|
|
181526
|
+
constructor() {
|
|
181527
|
+
this.padding = 20;
|
|
181528
|
+
this.fontSize = 14;
|
|
181529
|
+
this.fontFamily = "Arial, sans-serif";
|
|
181530
|
+
this.defaultStroke = "#3f3f3f";
|
|
181531
|
+
this.defaultFill = "#eef0ff";
|
|
181532
|
+
this.arrowStroke = "#555555";
|
|
181533
|
+
this.arrowMarkerSize = 9;
|
|
181534
|
+
}
|
|
181535
|
+
render(layout) {
|
|
181536
|
+
let minX = Infinity;
|
|
181537
|
+
let minY = Infinity;
|
|
181538
|
+
let maxX = -Infinity;
|
|
181539
|
+
let maxY = -Infinity;
|
|
181540
|
+
for (const n3 of layout.nodes) {
|
|
181541
|
+
minX = Math.min(minX, n3.x);
|
|
181542
|
+
minY = Math.min(minY, n3.y);
|
|
181543
|
+
maxX = Math.max(maxX, n3.x + n3.width);
|
|
181544
|
+
maxY = Math.max(maxY, n3.y + n3.height);
|
|
181545
|
+
}
|
|
181546
|
+
if (layout.subgraphs) {
|
|
181547
|
+
for (const sg of layout.subgraphs) {
|
|
181548
|
+
minX = Math.min(minX, sg.x);
|
|
181549
|
+
minY = Math.min(minY, sg.y);
|
|
181550
|
+
maxX = Math.max(maxX, sg.x + sg.width);
|
|
181551
|
+
maxY = Math.max(maxY, sg.y + sg.height);
|
|
181552
|
+
}
|
|
181553
|
+
}
|
|
181554
|
+
for (const e3 of layout.edges) {
|
|
181555
|
+
if (e3.points)
|
|
181556
|
+
for (const p3 of e3.points) {
|
|
181557
|
+
minX = Math.min(minX, p3.x);
|
|
181558
|
+
minY = Math.min(minY, p3.y);
|
|
181559
|
+
maxX = Math.max(maxX, p3.x);
|
|
181560
|
+
maxY = Math.max(maxY, p3.y);
|
|
181561
|
+
}
|
|
181562
|
+
}
|
|
181563
|
+
if (!isFinite(minX)) {
|
|
181564
|
+
minX = 0;
|
|
181565
|
+
}
|
|
181566
|
+
if (!isFinite(minY)) {
|
|
181567
|
+
minY = 0;
|
|
181568
|
+
}
|
|
181569
|
+
if (!isFinite(maxX)) {
|
|
181570
|
+
maxX = layout.width;
|
|
181571
|
+
}
|
|
181572
|
+
if (!isFinite(maxY)) {
|
|
181573
|
+
maxY = layout.height;
|
|
181574
|
+
}
|
|
181575
|
+
const extraPadX = Math.max(0, -Math.floor(minX) + 1);
|
|
181576
|
+
const extraPadY = Math.max(0, -Math.floor(minY) + 1);
|
|
181577
|
+
const padX = this.padding + extraPadX;
|
|
181578
|
+
const padY = this.padding + extraPadY;
|
|
181579
|
+
const bboxWidth = Math.ceil(maxX) - Math.min(0, Math.floor(minX));
|
|
181580
|
+
const bboxHeight = Math.ceil(maxY) - Math.min(0, Math.floor(minY));
|
|
181581
|
+
const width = bboxWidth + this.padding * 2 + extraPadX;
|
|
181582
|
+
const height = bboxHeight + this.padding * 2 + extraPadY;
|
|
181583
|
+
const elements = [];
|
|
181584
|
+
const overlays = [];
|
|
181585
|
+
elements.push(this.generateDefs());
|
|
181586
|
+
if (layout.subgraphs && layout.subgraphs.length) {
|
|
181587
|
+
const sgs = layout.subgraphs;
|
|
181588
|
+
const order = sgs.slice().sort((a3, b3) => (a3.parent ? 1 : 0) - (b3.parent ? 1 : 0));
|
|
181589
|
+
const map4 = new Map(order.map((o3) => [o3.id, o3]));
|
|
181590
|
+
const depthOf = (sg) => {
|
|
181591
|
+
let d3 = 0;
|
|
181592
|
+
let p3 = sg.parent;
|
|
181593
|
+
while (p3) {
|
|
181594
|
+
d3++;
|
|
181595
|
+
p3 = map4.get(p3)?.parent;
|
|
181596
|
+
}
|
|
181597
|
+
return d3;
|
|
181598
|
+
};
|
|
181599
|
+
const bgs = [];
|
|
181600
|
+
for (const sg of order) {
|
|
181601
|
+
const x3 = sg.x + padX;
|
|
181602
|
+
const y2 = sg.y + padY;
|
|
181603
|
+
bgs.push(blockBackground(x3, y2, sg.width, sg.height, 0));
|
|
181604
|
+
const depth = depthOf(sg);
|
|
181605
|
+
const title = sg.label ? this.escapeXml(sg.label) : void 0;
|
|
181606
|
+
const titleYOffset = 7 + depth * 12;
|
|
181607
|
+
overlays.push(blockOverlay(x3, y2, sg.width, sg.height, title, [], titleYOffset, "center", "left", 0));
|
|
181608
|
+
}
|
|
181609
|
+
elements.push(`<g class="subgraph-bg">${bgs.join("")}</g>`);
|
|
181610
|
+
}
|
|
181611
|
+
const nodeMap = {};
|
|
181612
|
+
for (const n3 of layout.nodes) {
|
|
181613
|
+
nodeMap[n3.id] = { x: n3.x + padX, y: n3.y + padY, width: n3.width, height: n3.height, shape: n3.shape };
|
|
181614
|
+
}
|
|
181615
|
+
if (layout.subgraphs && layout.subgraphs.length) {
|
|
181616
|
+
for (const sg of layout.subgraphs) {
|
|
181617
|
+
nodeMap[sg.id] = { x: sg.x + padX, y: sg.y + padY, width: sg.width, height: sg.height, shape: "rectangle" };
|
|
181618
|
+
}
|
|
181619
|
+
}
|
|
181620
|
+
for (const node of layout.nodes) {
|
|
181621
|
+
elements.push(this.generateNodeWithPad(node, padX, padY));
|
|
181622
|
+
}
|
|
181623
|
+
for (const edge of layout.edges) {
|
|
181624
|
+
const { path: path6, overlay } = this.generateEdge(edge, padX, padY, nodeMap);
|
|
181625
|
+
elements.push(path6);
|
|
181626
|
+
if (overlay)
|
|
181627
|
+
overlays.push(overlay);
|
|
181628
|
+
}
|
|
181629
|
+
const bg = `<rect x="0" y="0" width="${width}" height="${height}" fill="#ffffff" />`;
|
|
181630
|
+
const sharedCss = buildSharedCss({
|
|
181631
|
+
fontFamily: this.fontFamily,
|
|
181632
|
+
fontSize: this.fontSize,
|
|
181633
|
+
nodeFill: this.defaultFill,
|
|
181634
|
+
nodeStroke: this.defaultStroke,
|
|
181635
|
+
edgeStroke: this.arrowStroke
|
|
181636
|
+
});
|
|
181637
|
+
const css = `<style>${sharedCss}</style>`;
|
|
181638
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">
|
|
181639
|
+
${bg}
|
|
181640
|
+
${css}
|
|
181641
|
+
${elements.join("\n ")}
|
|
181642
|
+
${overlays.join("\n ")}
|
|
181643
|
+
</svg>`;
|
|
181644
|
+
}
|
|
181645
|
+
buildNodeStyleAttrs(style) {
|
|
181646
|
+
const decs = [];
|
|
181647
|
+
if (style.fill)
|
|
181648
|
+
decs.push(`fill:${style.fill}`);
|
|
181649
|
+
if (style.stroke)
|
|
181650
|
+
decs.push(`stroke:${style.stroke}`);
|
|
181651
|
+
if (style.strokeWidth != null)
|
|
181652
|
+
decs.push(`stroke-width:${style.strokeWidth}`);
|
|
181653
|
+
return decs.length ? `style="${decs.join(";")}"` : "";
|
|
181654
|
+
}
|
|
181655
|
+
buildNodeStrokeStyle(style) {
|
|
181656
|
+
const decs = [];
|
|
181657
|
+
if (style.stroke)
|
|
181658
|
+
decs.push(`stroke:${style.stroke}`);
|
|
181659
|
+
if (style.strokeWidth != null)
|
|
181660
|
+
decs.push(`stroke-width:${style.strokeWidth}`);
|
|
181661
|
+
return decs.length ? `style="${decs.join(";")}"` : "";
|
|
181662
|
+
}
|
|
181663
|
+
generateDefs() {
|
|
181664
|
+
const aw = Math.max(8, this.arrowMarkerSize + 2);
|
|
181665
|
+
const ah = Math.max(8, this.arrowMarkerSize + 2);
|
|
181666
|
+
const arefX = Math.max(6, aw);
|
|
181667
|
+
const arefY = Math.max(4, Math.round(ah / 2));
|
|
181668
|
+
return `<defs>
|
|
181669
|
+
<marker id="arrow" viewBox="0 0 ${aw} ${ah}" markerWidth="${aw}" markerHeight="${ah}" refX="${arefX}" refY="${arefY}" orient="auto" markerUnits="userSpaceOnUse">
|
|
181670
|
+
<path d="M0,0 L0,${ah} L${aw},${arefY} z" fill="${this.arrowStroke}" />
|
|
181671
|
+
</marker>
|
|
181672
|
+
<marker id="circle-marker" viewBox="0 0 9 9" markerWidth="9" markerHeight="9" refX="4.5" refY="4.5" orient="auto" markerUnits="userSpaceOnUse">
|
|
181673
|
+
<circle cx="4.5" cy="4.5" r="4.5" fill="${this.arrowStroke}" />
|
|
181674
|
+
</marker>
|
|
181675
|
+
<marker id="cross-marker" viewBox="0 0 12 12" markerWidth="12" markerHeight="12" refX="6" refY="6" orient="auto" markerUnits="userSpaceOnUse">
|
|
181676
|
+
<path d="M1.5,1.5 L10.5,10.5 M10.5,1.5 L1.5,10.5" stroke="${this.arrowStroke}" stroke-width="2.25" />
|
|
181677
|
+
</marker>
|
|
181678
|
+
</defs>`;
|
|
181679
|
+
}
|
|
181680
|
+
generateNodeWithPad(node, padX, padY) {
|
|
181681
|
+
const x3 = node.x + padX;
|
|
181682
|
+
const y2 = node.y + padY;
|
|
181683
|
+
const cx = x3 + node.width / 2;
|
|
181684
|
+
const cy = y2 + node.height / 2;
|
|
181685
|
+
let shape = "";
|
|
181686
|
+
let labelCenterY = cy;
|
|
181687
|
+
const strokeWidth = node.style?.strokeWidth ?? void 0;
|
|
181688
|
+
const stroke = node.style?.stroke ?? void 0;
|
|
181689
|
+
const fill = node.style?.fill ?? void 0;
|
|
181690
|
+
const styleAttr = this.buildNodeStyleAttrs({ stroke, strokeWidth, fill });
|
|
181691
|
+
switch (node.shape) {
|
|
181692
|
+
case "rectangle":
|
|
181693
|
+
shape = `<rect class="node-shape" ${styleAttr} x="${x3}" y="${y2}" width="${node.width}" height="${node.height}" rx="0" ry="0" />`;
|
|
181694
|
+
break;
|
|
181695
|
+
case "round":
|
|
181696
|
+
shape = `<rect class="node-shape" ${styleAttr} x="${x3}" y="${y2}" width="${node.width}" height="${node.height}" rx="5" ry="5" />`;
|
|
181697
|
+
break;
|
|
181698
|
+
case "stadium":
|
|
181699
|
+
const radius = node.height / 2;
|
|
181700
|
+
shape = `<rect class="node-shape" ${styleAttr} x="${x3}" y="${y2}" width="${node.width}" height="${node.height}" rx="${radius}" ry="${radius}" />`;
|
|
181701
|
+
break;
|
|
181702
|
+
case "circle":
|
|
181703
|
+
const r3 = Math.min(node.width, node.height) / 2;
|
|
181704
|
+
shape = `<circle class="node-shape" ${styleAttr} cx="${cx}" cy="${cy}" r="${r3}" />`;
|
|
181705
|
+
break;
|
|
181706
|
+
case "diamond": {
|
|
181707
|
+
const points = [
|
|
181708
|
+
`${cx},${y2}`,
|
|
181709
|
+
// top
|
|
181710
|
+
`${x3 + node.width},${cy}`,
|
|
181711
|
+
// right
|
|
181712
|
+
`${cx},${y2 + node.height}`,
|
|
181713
|
+
// bottom
|
|
181714
|
+
`${x3},${cy}`
|
|
181715
|
+
// left
|
|
181716
|
+
].join(" ");
|
|
181717
|
+
shape = `<polygon class="node-shape" ${styleAttr} points="${points}" />`;
|
|
181718
|
+
break;
|
|
181719
|
+
}
|
|
181720
|
+
case "hexagon": {
|
|
181721
|
+
const dx = node.width * 0.25;
|
|
181722
|
+
const points = [
|
|
181723
|
+
`${x3 + dx},${y2}`,
|
|
181724
|
+
// top-left
|
|
181725
|
+
`${x3 + node.width - dx},${y2}`,
|
|
181726
|
+
// top-right
|
|
181727
|
+
`${x3 + node.width},${cy}`,
|
|
181728
|
+
// right
|
|
181729
|
+
`${x3 + node.width - dx},${y2 + node.height}`,
|
|
181730
|
+
// bottom-right
|
|
181731
|
+
`${x3 + dx},${y2 + node.height}`,
|
|
181732
|
+
// bottom-left
|
|
181733
|
+
`${x3},${cy}`
|
|
181734
|
+
// left
|
|
181735
|
+
].join(" ");
|
|
181736
|
+
shape = `<polygon class="node-shape" ${styleAttr} points="${points}" />`;
|
|
181737
|
+
break;
|
|
181738
|
+
}
|
|
181739
|
+
case "parallelogram": {
|
|
181740
|
+
const skew = node.width * 0.15;
|
|
181741
|
+
const points = [
|
|
181742
|
+
`${x3 + skew},${y2}`,
|
|
181743
|
+
// top-left
|
|
181744
|
+
`${x3 + node.width},${y2}`,
|
|
181745
|
+
// top-right
|
|
181746
|
+
`${x3 + node.width - skew},${y2 + node.height}`,
|
|
181747
|
+
// bottom-right
|
|
181748
|
+
`${x3},${y2 + node.height}`
|
|
181749
|
+
// bottom-left
|
|
181750
|
+
].join(" ");
|
|
181751
|
+
shape = `<polygon class="node-shape" ${styleAttr} points="${points}" />`;
|
|
181752
|
+
break;
|
|
181753
|
+
}
|
|
181754
|
+
case "trapezoid": {
|
|
181755
|
+
const inset = node.width * 0.15;
|
|
181756
|
+
const points = [
|
|
181757
|
+
`${x3 + inset},${y2}`,
|
|
181758
|
+
// top-left
|
|
181759
|
+
`${x3 + node.width - inset},${y2}`,
|
|
181760
|
+
// top-right
|
|
181761
|
+
`${x3 + node.width},${y2 + node.height}`,
|
|
181762
|
+
// bottom-right
|
|
181763
|
+
`${x3},${y2 + node.height}`
|
|
181764
|
+
// bottom-left
|
|
181765
|
+
].join(" ");
|
|
181766
|
+
shape = `<polygon class="node-shape" ${styleAttr} points="${points}" />`;
|
|
181767
|
+
break;
|
|
181768
|
+
}
|
|
181769
|
+
case "trapezoidAlt": {
|
|
181770
|
+
const inset = node.width * 0.15;
|
|
181771
|
+
const points = [
|
|
181772
|
+
`${x3},${y2}`,
|
|
181773
|
+
// top-left (full width)
|
|
181774
|
+
`${x3 + node.width},${y2}`,
|
|
181775
|
+
// top-right
|
|
181776
|
+
`${x3 + node.width - inset},${y2 + node.height}`,
|
|
181777
|
+
// bottom-right (narrow)
|
|
181778
|
+
`${x3 + inset},${y2 + node.height}`
|
|
181779
|
+
// bottom-left (narrow)
|
|
181780
|
+
].join(" ");
|
|
181781
|
+
shape = `<polygon class="node-shape" ${styleAttr} points="${points}" />`;
|
|
181782
|
+
break;
|
|
181783
|
+
}
|
|
181784
|
+
case "cylinder": {
|
|
181785
|
+
const rx = Math.max(8, node.width / 2);
|
|
181786
|
+
const ry = Math.max(6, Math.min(node.height * 0.22, node.width * 0.25));
|
|
181787
|
+
const topCY = y2 + ry;
|
|
181788
|
+
const botCY = y2 + node.height - ry;
|
|
181789
|
+
const bodyH = Math.max(0, node.height - ry * 2);
|
|
181790
|
+
const strokeOnly = this.buildNodeStrokeStyle({ stroke, strokeWidth });
|
|
181791
|
+
shape = `<g>
|
|
181792
|
+
<rect class="node-shape" ${styleAttr} x="${x3}" y="${topCY}" width="${node.width}" height="${bodyH}" />
|
|
181793
|
+
<ellipse class="node-shape" ${styleAttr} cx="${cx}" cy="${topCY}" rx="${node.width / 2}" ry="${ry}" />
|
|
181794
|
+
<path class="node-shape" ${strokeOnly} d="M${x3},${topCY} L${x3},${botCY} A${node.width / 2},${ry} 0 0,0 ${x3 + node.width},${botCY} L${x3 + node.width},${topCY}" fill="none" />
|
|
181795
|
+
</g>`;
|
|
181796
|
+
labelCenterY = topCY + bodyH / 2;
|
|
181797
|
+
break;
|
|
181798
|
+
}
|
|
181799
|
+
case "subroutine":
|
|
181800
|
+
const insetX = 5;
|
|
181801
|
+
const strokeOnly2 = this.buildNodeStrokeStyle({ stroke, strokeWidth });
|
|
181802
|
+
shape = `<g>
|
|
181803
|
+
<rect class="node-shape" ${styleAttr} x="${x3}" y="${y2}" width="${node.width}" height="${node.height}" rx="0" ry="0" />
|
|
181804
|
+
<line class="node-shape" ${strokeOnly2} x1="${x3 + insetX}" y1="${y2}" x2="${x3 + insetX}" y2="${y2 + node.height}" />
|
|
181805
|
+
<line class="node-shape" ${strokeOnly2} x1="${x3 + node.width - insetX}" y1="${y2}" x2="${x3 + node.width - insetX}" y2="${y2 + node.height}" />
|
|
181806
|
+
</g>`;
|
|
181807
|
+
break;
|
|
181808
|
+
case "double":
|
|
181809
|
+
const gap = 4;
|
|
181810
|
+
const strokeOnly3 = this.buildNodeStrokeStyle({ stroke, strokeWidth });
|
|
181811
|
+
shape = `<g>
|
|
181812
|
+
<rect class="node-shape" ${styleAttr} x="${x3}" y="${y2}" width="${node.width}" height="${node.height}" rx="0" ry="0" />
|
|
181813
|
+
<rect class="node-shape" ${strokeOnly3} x="${x3 + gap}" y="${y2 + gap}" width="${node.width - gap * 2}" height="${node.height - gap * 2}" rx="0" ry="0" fill="none" />
|
|
181814
|
+
</g>`;
|
|
181815
|
+
break;
|
|
181816
|
+
default:
|
|
181817
|
+
const s3 = this.buildNodeStyleAttrs({ stroke, strokeWidth, fill });
|
|
181818
|
+
shape = `<rect ${s3} x="${x3}" y="${y2}" width="${node.width}" height="${node.height}" rx="0" ry="0" />`;
|
|
181819
|
+
}
|
|
181820
|
+
const text = this.generateWrappedText(node.label, cx, labelCenterY, node.width - 20);
|
|
181821
|
+
return `<g id="${node.id}">
|
|
181822
|
+
${shape}
|
|
181823
|
+
${text}
|
|
181824
|
+
</g>`;
|
|
181825
|
+
}
|
|
181826
|
+
generateWrappedText(text, x3, y2, maxWidth) {
|
|
181827
|
+
if (text.includes("<")) {
|
|
181828
|
+
return this.generateRichText(text, x3, y2, maxWidth);
|
|
181829
|
+
}
|
|
181830
|
+
const charWidth = 7;
|
|
181831
|
+
const maxCharsPerLine = Math.floor(maxWidth / charWidth);
|
|
181832
|
+
if (maxCharsPerLine <= 0 || text.length <= maxCharsPerLine) {
|
|
181833
|
+
const dyOffset = this.fontSize * 0.35;
|
|
181834
|
+
return `<text class="node-label" x="${x3}" y="${y2 + dyOffset}" text-anchor="middle">${this.escapeXml(text)}</text>`;
|
|
181835
|
+
}
|
|
181836
|
+
const words = text.split(" ");
|
|
181837
|
+
const lines = [];
|
|
181838
|
+
let currentLine = "";
|
|
181839
|
+
for (const word of words) {
|
|
181840
|
+
const testLine = currentLine ? `${currentLine} ${word}` : word;
|
|
181841
|
+
if (testLine.length > maxCharsPerLine && currentLine) {
|
|
181842
|
+
lines.push(currentLine);
|
|
181843
|
+
currentLine = word;
|
|
181844
|
+
} else {
|
|
181845
|
+
currentLine = testLine;
|
|
181846
|
+
}
|
|
181847
|
+
}
|
|
181848
|
+
if (currentLine) {
|
|
181849
|
+
lines.push(currentLine);
|
|
181850
|
+
}
|
|
181851
|
+
const lineHeight = 18;
|
|
181852
|
+
const totalHeight = (lines.length - 1) * lineHeight;
|
|
181853
|
+
const startY = y2 - totalHeight / 2 + this.fontSize * 0.35;
|
|
181854
|
+
const tspans = lines.map((line, i3) => {
|
|
181855
|
+
const lineY = startY + i3 * lineHeight;
|
|
181856
|
+
return `<tspan x="${x3}" y="${lineY}" text-anchor="middle">${this.escapeXml(line)}</tspan>`;
|
|
181857
|
+
}).join("\n ");
|
|
181858
|
+
return `<text class="node-label">
|
|
181859
|
+
${tspans}
|
|
181860
|
+
</text>`;
|
|
181861
|
+
}
|
|
181862
|
+
// Basic HTML-aware text renderer supporting <br>, <b>/<strong>, <i>/<em>, <u>
|
|
181863
|
+
generateRichText(html, x3, y2, maxWidth) {
|
|
181864
|
+
html = this.normalizeHtml(html);
|
|
181865
|
+
const segments = [];
|
|
181866
|
+
const re = /<\/?(br|b|strong|i|em|u)\s*\/?\s*>/gi;
|
|
181867
|
+
let lastIndex = 0;
|
|
181868
|
+
const state2 = { bold: false, italic: false, underline: false };
|
|
181869
|
+
const pushText = (t3) => {
|
|
181870
|
+
if (!t3)
|
|
181871
|
+
return;
|
|
181872
|
+
segments.push({ text: this.htmlDecode(t3), bold: state2.bold, italic: state2.italic, underline: state2.underline });
|
|
181873
|
+
};
|
|
181874
|
+
let m3;
|
|
181875
|
+
while (m3 = re.exec(html)) {
|
|
181876
|
+
pushText(html.slice(lastIndex, m3.index));
|
|
181877
|
+
const tag2 = m3[0].toLowerCase();
|
|
181878
|
+
const name14 = m3[1].toLowerCase();
|
|
181879
|
+
const isClose = tag2.startsWith("</");
|
|
181880
|
+
if (name14 === "br") {
|
|
181881
|
+
segments.push({ text: "", br: true });
|
|
181882
|
+
} else if (name14 === "b" || name14 === "strong") {
|
|
181883
|
+
state2.bold = !isClose ? true : false;
|
|
181884
|
+
} else if (name14 === "i" || name14 === "em") {
|
|
181885
|
+
state2.italic = !isClose ? true : false;
|
|
181886
|
+
} else if (name14 === "u") {
|
|
181887
|
+
state2.underline = !isClose ? true : false;
|
|
181888
|
+
}
|
|
181889
|
+
lastIndex = re.lastIndex;
|
|
181890
|
+
}
|
|
181891
|
+
pushText(html.slice(lastIndex));
|
|
181892
|
+
const lines = [];
|
|
181893
|
+
const charWidth = 7;
|
|
181894
|
+
const maxCharsPerLine = Math.max(1, Math.floor(maxWidth / charWidth));
|
|
181895
|
+
let current = [];
|
|
181896
|
+
let currentLen = 0;
|
|
181897
|
+
const flush = () => {
|
|
181898
|
+
if (current.length) {
|
|
181899
|
+
lines.push(current);
|
|
181900
|
+
current = [];
|
|
181901
|
+
currentLen = 0;
|
|
181902
|
+
}
|
|
181903
|
+
};
|
|
181904
|
+
const splitWords = (s3) => {
|
|
181905
|
+
if (!s3.text)
|
|
181906
|
+
return [s3];
|
|
181907
|
+
const words = s3.text.split(/(\s+)/);
|
|
181908
|
+
return words.map((w3) => ({ ...s3, text: w3 }));
|
|
181909
|
+
};
|
|
181910
|
+
for (const seg of segments) {
|
|
181911
|
+
if (seg.br) {
|
|
181912
|
+
flush();
|
|
181913
|
+
continue;
|
|
181914
|
+
}
|
|
181915
|
+
for (const w3 of splitWords(seg)) {
|
|
181916
|
+
const wlen = w3.text.length;
|
|
181917
|
+
if (currentLen + wlen > maxCharsPerLine && currentLen > 0) {
|
|
181918
|
+
flush();
|
|
181919
|
+
}
|
|
181920
|
+
current.push(w3);
|
|
181921
|
+
currentLen += wlen;
|
|
181922
|
+
}
|
|
181923
|
+
}
|
|
181924
|
+
flush();
|
|
181925
|
+
const lineHeight = 18;
|
|
181926
|
+
const totalHeight = (lines.length - 1) * lineHeight;
|
|
181927
|
+
const startY = y2 - totalHeight / 2 + this.fontSize * 0.35;
|
|
181928
|
+
const tspans = [];
|
|
181929
|
+
for (let i3 = 0; i3 < lines.length; i3++) {
|
|
181930
|
+
const lineY = startY + i3 * lineHeight;
|
|
181931
|
+
let acc = "";
|
|
181932
|
+
let cursorX = x3;
|
|
181933
|
+
const inner = [];
|
|
181934
|
+
let buffer = "";
|
|
181935
|
+
let style = { bold: false, italic: false, underline: false };
|
|
181936
|
+
const flushInline = () => {
|
|
181937
|
+
if (!buffer)
|
|
181938
|
+
return;
|
|
181939
|
+
const styleAttr = `${style.bold ? 'font-weight="bold" ' : ""}${style.italic ? 'font-style="italic" ' : ""}${style.underline ? 'text-decoration="underline" ' : ""}`;
|
|
181940
|
+
inner.push(`<tspan ${styleAttr}>${this.escapeXml(buffer)}</tspan>`);
|
|
181941
|
+
buffer = "";
|
|
181942
|
+
};
|
|
181943
|
+
for (const w3 of lines[i3]) {
|
|
181944
|
+
const wStyle = { bold: !!w3.bold, italic: !!w3.italic, underline: !!w3.underline };
|
|
181945
|
+
if (wStyle.bold !== style.bold || wStyle.italic !== style.italic || wStyle.underline !== style.underline) {
|
|
181946
|
+
flushInline();
|
|
181947
|
+
style = wStyle;
|
|
181948
|
+
}
|
|
181949
|
+
buffer += w3.text;
|
|
181950
|
+
}
|
|
181951
|
+
flushInline();
|
|
181952
|
+
tspans.push(`<tspan x="${x3}" y="${lineY}" text-anchor="middle">${inner.join("")}</tspan>`);
|
|
181953
|
+
}
|
|
181954
|
+
return `<text font-family="${this.fontFamily}" font-size="${this.fontSize}" fill="#333">${tspans.join("\n ")}</text>`;
|
|
181955
|
+
}
|
|
181956
|
+
normalizeHtml(s3) {
|
|
181957
|
+
let out = s3.replace(/<\s+/g, "<").replace(/\s+>/g, ">").replace(/<\s*\//g, "</").replace(/\s*\/\s*>/g, "/>").replace(/<\s*(br)\s*>/gi, "<$1/>");
|
|
181958
|
+
return out;
|
|
181959
|
+
}
|
|
181960
|
+
htmlDecode(s3) {
|
|
181961
|
+
return s3.replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&").replace(/"/g, '"').replace(/'/g, "'");
|
|
181962
|
+
}
|
|
181963
|
+
generateEdge(edge, padX, padY, nodeMap) {
|
|
181964
|
+
if (!edge.points || edge.points.length < 2) {
|
|
181965
|
+
return { path: "" };
|
|
181966
|
+
}
|
|
181967
|
+
const points = edge.points.map((p3) => ({ x: p3.x + padX, y: p3.y + padY }));
|
|
181968
|
+
const segData = this.buildSmoothSegments(points);
|
|
181969
|
+
let strokeDasharray = "";
|
|
181970
|
+
let strokeWidth = 1.5;
|
|
181971
|
+
let markerEnd = "";
|
|
181972
|
+
let markerStart = "";
|
|
181973
|
+
switch (edge.type) {
|
|
181974
|
+
case "open":
|
|
181975
|
+
markerEnd = "";
|
|
181976
|
+
break;
|
|
181977
|
+
case "dotted":
|
|
181978
|
+
strokeDasharray = "3,3";
|
|
181979
|
+
break;
|
|
181980
|
+
case "thick":
|
|
181981
|
+
strokeWidth = 3;
|
|
181982
|
+
break;
|
|
181983
|
+
case "invisible":
|
|
181984
|
+
strokeDasharray = "0,100000";
|
|
181985
|
+
markerEnd = "";
|
|
181986
|
+
break;
|
|
181987
|
+
}
|
|
181988
|
+
const mStart = edge.markerStart;
|
|
181989
|
+
const mEnd = edge.markerEnd;
|
|
181990
|
+
const sourceNode = nodeMap[edge.source];
|
|
181991
|
+
const targetNode = nodeMap[edge.target];
|
|
181992
|
+
let boundaryStart = points[0];
|
|
181993
|
+
let boundaryEnd = points[points.length - 1];
|
|
181994
|
+
if (sourceNode && points.length >= 2) {
|
|
181995
|
+
const pseudo = { start: points[0], segs: [{ c1: points[1], c2: points[Math.max(0, points.length - 2)], to: points[points.length - 1] }] };
|
|
181996
|
+
boundaryStart = this.intersectSegmentsStart(pseudo, sourceNode).start;
|
|
181997
|
+
}
|
|
181998
|
+
if (targetNode && points.length >= 2) {
|
|
181999
|
+
const pseudo = { start: points[0], segs: [{ c1: points[1], c2: points[Math.max(0, points.length - 2)], to: points[points.length - 1] }] };
|
|
182000
|
+
const after = this.intersectSegmentsEnd(pseudo, targetNode);
|
|
182001
|
+
boundaryEnd = after.segs.length ? after.segs[after.segs.length - 1].to : boundaryEnd;
|
|
182002
|
+
}
|
|
182003
|
+
const pathParts = [];
|
|
182004
|
+
pathParts.push(`M${boundaryStart.x},${boundaryStart.y}`);
|
|
182005
|
+
let startFlat = points.length >= 2 ? points[1] : boundaryStart;
|
|
182006
|
+
if (points.length >= 2) {
|
|
182007
|
+
const svx = points[1].x - boundaryStart.x;
|
|
182008
|
+
const svy = points[1].y - boundaryStart.y;
|
|
182009
|
+
const slen = Math.hypot(svx, svy) || 1;
|
|
182010
|
+
const SFLAT = Math.min(22, Math.max(10, slen * 0.15));
|
|
182011
|
+
startFlat = { x: boundaryStart.x + svx / slen * SFLAT, y: boundaryStart.y + svy / slen * SFLAT };
|
|
182012
|
+
pathParts.push(`L${startFlat.x},${startFlat.y}`);
|
|
182013
|
+
}
|
|
182014
|
+
const orthogonal = edge.pathMode === "orthogonal";
|
|
182015
|
+
if (points.length >= 4 && !orthogonal) {
|
|
182016
|
+
const pts = [points[0], ...points, points[points.length - 1]];
|
|
182017
|
+
for (let i3 = 1; i3 < pts.length - 3; i3++) {
|
|
182018
|
+
const p0 = pts[i3 - 1];
|
|
182019
|
+
const p1 = pts[i3];
|
|
182020
|
+
const p22 = pts[i3 + 1];
|
|
182021
|
+
const p3 = pts[i3 + 2];
|
|
182022
|
+
const c1x = p1.x + (p22.x - p0.x) / 6;
|
|
182023
|
+
const c1y = p1.y + (p22.y - p0.y) / 6;
|
|
182024
|
+
const c2x = p22.x - (p3.x - p1.x) / 6;
|
|
182025
|
+
const c2y = p22.y - (p3.y - p1.y) / 6;
|
|
182026
|
+
pathParts.push(`C${c1x},${c1y} ${c2x},${c2y} ${p22.x},${p22.y}`);
|
|
182027
|
+
}
|
|
182028
|
+
pathParts.push(`L${boundaryEnd.x},${boundaryEnd.y}`);
|
|
182029
|
+
} else if (points.length === 3 && !orthogonal) {
|
|
182030
|
+
const p0 = boundaryStart, p1 = points[1], p22 = boundaryEnd;
|
|
182031
|
+
const ax = boundaryEnd.x - p1.x;
|
|
182032
|
+
const ay = boundaryEnd.y - p1.y;
|
|
182033
|
+
const alen = Math.hypot(ax, ay) || 1;
|
|
182034
|
+
const FLAT_IN = Math.min(20, Math.max(10, alen * 0.15));
|
|
182035
|
+
const preEnd = { x: boundaryEnd.x - ax / alen * FLAT_IN, y: boundaryEnd.y - ay / alen * FLAT_IN };
|
|
182036
|
+
const sdx = startFlat.x - boundaryStart.x;
|
|
182037
|
+
const sdy = startFlat.y - boundaryStart.y;
|
|
182038
|
+
const sdirx = sdx === 0 && sdy === 0 ? p1.x - p0.x : sdx;
|
|
182039
|
+
const sdiry = sdx === 0 && sdy === 0 ? p1.y - p0.y : sdy;
|
|
182040
|
+
const sdlen = Math.hypot(sdirx, sdiry) || 1;
|
|
182041
|
+
const c1len = Math.min(40, Math.max(12, sdlen * 1.2));
|
|
182042
|
+
const c1x = startFlat.x + sdirx / sdlen * c1len;
|
|
182043
|
+
const c1y = startFlat.y + sdiry / sdlen * c1len;
|
|
182044
|
+
const dirx = (boundaryEnd.x - p1.x) / alen;
|
|
182045
|
+
const diry = (boundaryEnd.y - p1.y) / alen;
|
|
182046
|
+
const c2x = preEnd.x - dirx * (FLAT_IN * 0.6);
|
|
182047
|
+
const c2y = preEnd.y - diry * (FLAT_IN * 0.6);
|
|
182048
|
+
pathParts.push(`C${c1x},${c1y} ${c2x},${c2y} ${preEnd.x},${preEnd.y}`);
|
|
182049
|
+
pathParts.push(`L${boundaryEnd.x},${boundaryEnd.y}`);
|
|
182050
|
+
} else {
|
|
182051
|
+
pathParts.push(`L${boundaryEnd.x},${boundaryEnd.y}`);
|
|
182052
|
+
}
|
|
182053
|
+
if (orthogonal) {
|
|
182054
|
+
pathParts.length = 0;
|
|
182055
|
+
pathParts.push(`M${boundaryStart.x},${boundaryStart.y}`);
|
|
182056
|
+
for (const p3 of points.slice(1, -1))
|
|
182057
|
+
pathParts.push(`L${p3.x},${p3.y}`);
|
|
182058
|
+
pathParts.push(`L${boundaryEnd.x},${boundaryEnd.y}`);
|
|
182059
|
+
}
|
|
182060
|
+
const pathData = pathParts.join(" ");
|
|
182061
|
+
let edgeElement = `<path class="edge-path" d="${pathData}" stroke-linecap="round" stroke-linejoin="round"`;
|
|
182062
|
+
if (strokeDasharray) {
|
|
182063
|
+
edgeElement += ` stroke-dasharray="${strokeDasharray}"`;
|
|
182064
|
+
}
|
|
182065
|
+
const startMarkUrl = mStart === "arrow" ? "url(#arrow)" : mStart === "circle" ? "url(#circle-marker)" : mStart === "cross" ? "url(#cross-marker)" : "";
|
|
182066
|
+
const endMarkUrl = mEnd === "arrow" ? "url(#arrow)" : mEnd === "circle" ? "url(#circle-marker)" : mEnd === "cross" ? "url(#cross-marker)" : markerEnd || "";
|
|
182067
|
+
if (startMarkUrl && mStart !== "arrow")
|
|
182068
|
+
edgeElement += ` marker-start="${startMarkUrl}"`;
|
|
182069
|
+
if (endMarkUrl && mEnd !== "arrow")
|
|
182070
|
+
edgeElement += ` marker-end="${endMarkUrl}"`;
|
|
182071
|
+
edgeElement += " />";
|
|
182072
|
+
if (edge.label) {
|
|
182073
|
+
const pos = this.pointAtRatio(points, 0.55);
|
|
182074
|
+
const text = this.escapeXml(edge.label);
|
|
182075
|
+
const padding = 4;
|
|
182076
|
+
const fontSize = this.fontSize - 3;
|
|
182077
|
+
const width = Math.max(18, Math.min(220, text.length * 6 + padding * 2));
|
|
182078
|
+
const height = 14;
|
|
182079
|
+
const x3 = pos.x - width / 2;
|
|
182080
|
+
const y2 = pos.y - height / 2;
|
|
182081
|
+
const labelBg = `<rect class="edge-label-bg" x="${x3}" y="${y2}" width="${width}" height="${height}" rx="3" />`;
|
|
182082
|
+
const labelText = `<text class="edge-label-text" x="${pos.x}" y="${pos.y}" text-anchor="middle" dominant-baseline="middle">${text}</text>`;
|
|
182083
|
+
let overlay2 = "";
|
|
182084
|
+
const prevEndL = points.length >= 2 ? points[points.length - 2] : boundaryEnd;
|
|
182085
|
+
const vxl = boundaryEnd.x - prevEndL.x;
|
|
182086
|
+
const vyl = boundaryEnd.y - prevEndL.y;
|
|
182087
|
+
const vlenl = Math.hypot(vxl, vyl) || 1;
|
|
182088
|
+
const uxl = vxl / vlenl;
|
|
182089
|
+
const uyl = vyl / vlenl;
|
|
182090
|
+
const nxl = -uyl;
|
|
182091
|
+
const nyl = uxl;
|
|
182092
|
+
const triLenL = 8;
|
|
182093
|
+
const triWL = 6;
|
|
182094
|
+
const p1xL = boundaryEnd.x, p1yL = boundaryEnd.y;
|
|
182095
|
+
const baseXL = boundaryEnd.x - uxl * triLenL;
|
|
182096
|
+
const baseYL = boundaryEnd.y - uyl * triLenL;
|
|
182097
|
+
const p2xL = baseXL + nxl * (triWL / 2), p2yL = baseYL + nyl * (triWL / 2);
|
|
182098
|
+
const p3xL = baseXL - nxl * (triWL / 2), p3yL = baseYL - nyl * (triWL / 2);
|
|
182099
|
+
overlay2 += triangleAtEnd(prevEndL, boundaryEnd, this.arrowStroke);
|
|
182100
|
+
if (mStart === "arrow" && points.length >= 2) {
|
|
182101
|
+
const firstLeg = points[1];
|
|
182102
|
+
const svx = boundaryStart.x - firstLeg.x;
|
|
182103
|
+
const svy = boundaryStart.y - firstLeg.y;
|
|
182104
|
+
const slen = Math.hypot(svx, svy) || 1;
|
|
182105
|
+
const sux = svx / slen;
|
|
182106
|
+
const suy = svy / slen;
|
|
182107
|
+
const snx = -suy;
|
|
182108
|
+
const sny = sux;
|
|
182109
|
+
const sbaseX = boundaryStart.x - sux * triLenL;
|
|
182110
|
+
const sbaseY = boundaryStart.y - suy * triLenL;
|
|
182111
|
+
overlay2 += triangleAtStart(boundaryStart, firstLeg, this.arrowStroke);
|
|
182112
|
+
}
|
|
182113
|
+
const pathGroup = `<g>
|
|
182114
|
+
${edgeElement}
|
|
182115
|
+
${labelBg}
|
|
182116
|
+
${labelText}
|
|
182117
|
+
${overlay2}
|
|
182118
|
+
</g>`;
|
|
182119
|
+
return { path: pathGroup };
|
|
182120
|
+
}
|
|
182121
|
+
let overlay = "";
|
|
182122
|
+
const prevEnd = points.length >= 2 ? points[points.length - 2] : boundaryEnd;
|
|
182123
|
+
const vx = boundaryEnd.x - prevEnd.x;
|
|
182124
|
+
const vy = boundaryEnd.y - prevEnd.y;
|
|
182125
|
+
const vlen = Math.hypot(vx, vy) || 1;
|
|
182126
|
+
const ux = vx / vlen;
|
|
182127
|
+
const uy = vy / vlen;
|
|
182128
|
+
const nx = -uy;
|
|
182129
|
+
const ny = ux;
|
|
182130
|
+
const triLen = 8;
|
|
182131
|
+
const triW = 6;
|
|
182132
|
+
const p1x = boundaryEnd.x, p1y = boundaryEnd.y;
|
|
182133
|
+
const baseX = boundaryEnd.x - ux * triLen;
|
|
182134
|
+
const baseY = boundaryEnd.y - uy * triLen;
|
|
182135
|
+
const p2x = baseX + nx * (triW / 2), p2y = baseY + ny * (triW / 2);
|
|
182136
|
+
const p3x = baseX - nx * (triW / 2), p3y = baseY - ny * (triW / 2);
|
|
182137
|
+
if (mEnd === "arrow")
|
|
182138
|
+
overlay += triangleAtEnd(prevEnd, boundaryEnd, this.arrowStroke);
|
|
182139
|
+
if (mStart === "arrow" && points.length >= 2) {
|
|
182140
|
+
const firstLeg = points[1];
|
|
182141
|
+
const svx = boundaryStart.x - firstLeg.x;
|
|
182142
|
+
const svy = boundaryStart.y - firstLeg.y;
|
|
182143
|
+
const slen = Math.hypot(svx, svy) || 1;
|
|
182144
|
+
const sux = svx / slen;
|
|
182145
|
+
const suy = svy / slen;
|
|
182146
|
+
const snx = -suy;
|
|
182147
|
+
const sny = sux;
|
|
182148
|
+
overlay += triangleAtStart(boundaryStart, firstLeg, this.arrowStroke);
|
|
182149
|
+
}
|
|
182150
|
+
if (overlay) {
|
|
182151
|
+
const grouped = `<g>${edgeElement}
|
|
182152
|
+
${overlay}</g>`;
|
|
182153
|
+
return { path: grouped };
|
|
182154
|
+
}
|
|
182155
|
+
return { path: edgeElement };
|
|
182156
|
+
}
|
|
182157
|
+
// --- helpers ---
|
|
182158
|
+
buildSmoothSegments(points) {
|
|
182159
|
+
if (points.length < 2) {
|
|
182160
|
+
const p3 = points[0] || { x: 0, y: 0 };
|
|
182161
|
+
return { start: p3, segs: [] };
|
|
182162
|
+
}
|
|
182163
|
+
if (points.length === 2) {
|
|
182164
|
+
const p0 = points[0];
|
|
182165
|
+
const p1 = points[1];
|
|
182166
|
+
const c1 = { x: p0.x + (p1.x - p0.x) / 3, y: p0.y + (p1.y - p0.y) / 3 };
|
|
182167
|
+
const c22 = { x: p0.x + 2 * (p1.x - p0.x) / 3, y: p0.y + 2 * (p1.y - p0.y) / 3 };
|
|
182168
|
+
return { start: p0, segs: [{ c1, c2: c22, to: p1 }] };
|
|
182169
|
+
}
|
|
182170
|
+
const pts = [points[0], ...points, points[points.length - 1]];
|
|
182171
|
+
const segs = [];
|
|
182172
|
+
const firstIdx = 1;
|
|
182173
|
+
const lastIdx = pts.length - 3;
|
|
182174
|
+
const midFactor = 1;
|
|
182175
|
+
const endFactor = 0.35;
|
|
182176
|
+
const FLAT_LEN = 28;
|
|
182177
|
+
for (let i3 = 1; i3 < pts.length - 2; i3++) {
|
|
182178
|
+
const p0 = pts[i3 - 1];
|
|
182179
|
+
const p1 = pts[i3];
|
|
182180
|
+
const p22 = pts[i3 + 1];
|
|
182181
|
+
const p3 = pts[i3 + 2];
|
|
182182
|
+
const f1 = i3 === firstIdx ? endFactor : midFactor;
|
|
182183
|
+
const f22 = i3 === lastIdx ? endFactor : midFactor;
|
|
182184
|
+
let c1 = { x: p1.x + (p22.x - p0.x) / 6 * f1, y: p1.y + (p22.y - p0.y) / 6 * f1 };
|
|
182185
|
+
let c22 = { x: p22.x - (p3.x - p1.x) / 6 * f22, y: p22.y - (p3.y - p1.y) / 6 * f22 };
|
|
182186
|
+
if (i3 === firstIdx) {
|
|
182187
|
+
const dx = p22.x - p1.x, dy = p22.y - p1.y;
|
|
182188
|
+
const len = Math.hypot(dx, dy) || 1;
|
|
182189
|
+
const t3 = Math.min(FLAT_LEN, len * 0.5);
|
|
182190
|
+
c1 = { x: p1.x + dx / len * t3, y: p1.y + dy / len * t3 };
|
|
182191
|
+
}
|
|
182192
|
+
if (i3 === lastIdx) {
|
|
182193
|
+
const dx = p22.x - p1.x, dy = p22.y - p1.y;
|
|
182194
|
+
const len = Math.hypot(dx, dy) || 1;
|
|
182195
|
+
const t3 = Math.min(FLAT_LEN, len * 0.5);
|
|
182196
|
+
c22 = { x: p22.x - dx / len * t3, y: p22.y - dy / len * t3 };
|
|
182197
|
+
}
|
|
182198
|
+
segs.push({ c1, c2: c22, to: { x: p22.x, y: p22.y } });
|
|
182199
|
+
}
|
|
182200
|
+
return { start: pts[1], segs };
|
|
182201
|
+
}
|
|
182202
|
+
pathFromSegments(data2) {
|
|
182203
|
+
let d3 = `M${data2.start.x},${data2.start.y}`;
|
|
182204
|
+
for (const s3 of data2.segs) {
|
|
182205
|
+
d3 += ` C${s3.c1.x},${s3.c1.y} ${s3.c2.x},${s3.c2.y} ${s3.to.x},${s3.to.y}`;
|
|
182206
|
+
}
|
|
182207
|
+
return d3;
|
|
182208
|
+
}
|
|
182209
|
+
trimSegmentsEnd(data2, cut) {
|
|
182210
|
+
const segs = data2.segs.slice();
|
|
182211
|
+
if (!segs.length)
|
|
182212
|
+
return data2;
|
|
182213
|
+
const last2 = { ...segs[segs.length - 1] };
|
|
182214
|
+
const vx = last2.to.x - last2.c2.x;
|
|
182215
|
+
const vy = last2.to.y - last2.c2.y;
|
|
182216
|
+
const len = Math.hypot(vx, vy) || 1;
|
|
182217
|
+
const eff = Math.max(0.1, Math.min(cut, Math.max(0, len - 0.2)));
|
|
182218
|
+
const nx = vx / len;
|
|
182219
|
+
const ny = vy / len;
|
|
182220
|
+
const newTo = { x: last2.to.x - nx * eff, y: last2.to.y - ny * eff };
|
|
182221
|
+
last2.to = newTo;
|
|
182222
|
+
segs[segs.length - 1] = last2;
|
|
182223
|
+
return { start: data2.start, segs };
|
|
182224
|
+
}
|
|
182225
|
+
trimSegmentsStart(data2, cut) {
|
|
182226
|
+
const segs = data2.segs.slice();
|
|
182227
|
+
if (!segs.length)
|
|
182228
|
+
return data2;
|
|
182229
|
+
const first2 = { ...segs[0] };
|
|
182230
|
+
const vx = first2.c1.x - data2.start.x;
|
|
182231
|
+
const vy = first2.c1.y - data2.start.y;
|
|
182232
|
+
const len = Math.hypot(vx, vy) || 1;
|
|
182233
|
+
const eff = Math.max(0.1, Math.min(cut, Math.max(0, len - 0.2)));
|
|
182234
|
+
const nx = vx / len;
|
|
182235
|
+
const ny = vy / len;
|
|
182236
|
+
const newStart = { x: data2.start.x + nx * eff, y: data2.start.y + ny * eff };
|
|
182237
|
+
return { start: newStart, segs };
|
|
182238
|
+
}
|
|
182239
|
+
// ---- shape intersections ----
|
|
182240
|
+
intersectSegmentsEnd(data2, node) {
|
|
182241
|
+
if (!data2.segs.length)
|
|
182242
|
+
return data2;
|
|
182243
|
+
const last2 = data2.segs[data2.segs.length - 1];
|
|
182244
|
+
const p1 = last2.c2;
|
|
182245
|
+
const p22 = last2.to;
|
|
182246
|
+
const hit = this.intersectLineWithNode(p1, p22, node);
|
|
182247
|
+
if (hit) {
|
|
182248
|
+
const segs = data2.segs.slice();
|
|
182249
|
+
segs[segs.length - 1] = { ...last2, to: hit };
|
|
182250
|
+
return { start: data2.start, segs };
|
|
182251
|
+
}
|
|
182252
|
+
return data2;
|
|
182253
|
+
}
|
|
182254
|
+
intersectSegmentsStart(data2, node) {
|
|
182255
|
+
if (!data2.segs.length)
|
|
182256
|
+
return data2;
|
|
182257
|
+
const first2 = data2.segs[0];
|
|
182258
|
+
const p1 = data2.start;
|
|
182259
|
+
const p22 = first2.c1;
|
|
182260
|
+
const hit = this.intersectLineWithNode(p1, p22, node);
|
|
182261
|
+
if (hit) {
|
|
182262
|
+
return { start: hit, segs: data2.segs };
|
|
182263
|
+
}
|
|
182264
|
+
return data2;
|
|
182265
|
+
}
|
|
182266
|
+
intersectLineWithNode(p1, p22, node) {
|
|
182267
|
+
const shape = node.shape;
|
|
182268
|
+
const rectPoly = () => [
|
|
182269
|
+
{ x: node.x, y: node.y },
|
|
182270
|
+
{ x: node.x + node.width, y: node.y },
|
|
182271
|
+
{ x: node.x + node.width, y: node.y + node.height },
|
|
182272
|
+
{ x: node.x, y: node.y + node.height }
|
|
182273
|
+
];
|
|
182274
|
+
switch (shape) {
|
|
182275
|
+
case "circle": {
|
|
182276
|
+
const cx = node.x + node.width / 2;
|
|
182277
|
+
const cy = node.y + node.height / 2;
|
|
182278
|
+
const r3 = Math.min(node.width, node.height) / 2;
|
|
182279
|
+
return this.lineCircleIntersection(p1, p22, { cx, cy, r: r3 });
|
|
182280
|
+
}
|
|
182281
|
+
case "diamond": {
|
|
182282
|
+
const cx = node.x + node.width / 2;
|
|
182283
|
+
const cy = node.y + node.height / 2;
|
|
182284
|
+
const poly = [{ x: cx, y: node.y }, { x: node.x + node.width, y: cy }, { x: cx, y: node.y + node.height }, { x: node.x, y: cy }];
|
|
182285
|
+
return this.linePolygonIntersection(p1, p22, poly);
|
|
182286
|
+
}
|
|
182287
|
+
case "hexagon": {
|
|
182288
|
+
const s3 = Math.max(10, node.width * 0.2);
|
|
182289
|
+
const poly = [
|
|
182290
|
+
{ x: node.x + s3, y: node.y },
|
|
182291
|
+
{ x: node.x + node.width - s3, y: node.y },
|
|
182292
|
+
{ x: node.x + node.width, y: node.y + node.height / 2 },
|
|
182293
|
+
{ x: node.x + node.width - s3, y: node.y + node.height },
|
|
182294
|
+
{ x: node.x + s3, y: node.y + node.height },
|
|
182295
|
+
{ x: node.x, y: node.y + node.height / 2 }
|
|
182296
|
+
];
|
|
182297
|
+
return this.linePolygonIntersection(p1, p22, poly);
|
|
182298
|
+
}
|
|
182299
|
+
case "parallelogram": {
|
|
182300
|
+
const o3 = Math.min(node.width * 0.25, node.height * 0.6);
|
|
182301
|
+
const poly = [
|
|
182302
|
+
{ x: node.x + o3, y: node.y },
|
|
182303
|
+
{ x: node.x + node.width, y: node.y },
|
|
182304
|
+
{ x: node.x + node.width - o3, y: node.y + node.height },
|
|
182305
|
+
{ x: node.x, y: node.y + node.height }
|
|
182306
|
+
];
|
|
182307
|
+
return this.linePolygonIntersection(p1, p22, poly);
|
|
182308
|
+
}
|
|
182309
|
+
case "trapezoid": {
|
|
182310
|
+
const o3 = Math.min(node.width * 0.2, node.height * 0.5);
|
|
182311
|
+
const poly = [
|
|
182312
|
+
{ x: node.x + o3, y: node.y },
|
|
182313
|
+
{ x: node.x + node.width - o3, y: node.y },
|
|
182314
|
+
{ x: node.x + node.width, y: node.y + node.height },
|
|
182315
|
+
{ x: node.x, y: node.y + node.height }
|
|
182316
|
+
];
|
|
182317
|
+
return this.linePolygonIntersection(p1, p22, poly);
|
|
182318
|
+
}
|
|
182319
|
+
case "trapezoidAlt": {
|
|
182320
|
+
const o3 = Math.min(node.width * 0.2, node.height * 0.5);
|
|
182321
|
+
const poly = [
|
|
182322
|
+
{ x: node.x, y: node.y },
|
|
182323
|
+
{ x: node.x + node.width, y: node.y },
|
|
182324
|
+
{ x: node.x + node.width - o3, y: node.y + node.height },
|
|
182325
|
+
{ x: node.x + o3, y: node.y + node.height }
|
|
182326
|
+
];
|
|
182327
|
+
return this.linePolygonIntersection(p1, p22, poly);
|
|
182328
|
+
}
|
|
182329
|
+
case "stadium": {
|
|
182330
|
+
const r3 = Math.min(node.height / 2, node.width / 2);
|
|
182331
|
+
const rect = [
|
|
182332
|
+
{ x: node.x + r3, y: node.y },
|
|
182333
|
+
{ x: node.x + node.width - r3, y: node.y },
|
|
182334
|
+
{ x: node.x + node.width - r3, y: node.y + node.height },
|
|
182335
|
+
{ x: node.x + r3, y: node.y + node.height }
|
|
182336
|
+
];
|
|
182337
|
+
const hitRect = this.linePolygonIntersection(p1, p22, rect);
|
|
182338
|
+
if (hitRect)
|
|
182339
|
+
return hitRect;
|
|
182340
|
+
const left = this.lineCircleIntersection(p1, p22, { cx: node.x + r3, cy: node.y + node.height / 2, r: r3 });
|
|
182341
|
+
const right = this.lineCircleIntersection(p1, p22, { cx: node.x + node.width - r3, cy: node.y + node.height / 2, r: r3 });
|
|
182342
|
+
const pick = (...pts) => {
|
|
182343
|
+
let best = null;
|
|
182344
|
+
let bestd = -Infinity;
|
|
182345
|
+
for (const pt of pts)
|
|
182346
|
+
if (pt) {
|
|
182347
|
+
const d3 = -((pt.x - p22.x) ** 2 + (pt.y - p22.y) ** 2);
|
|
182348
|
+
if (d3 > bestd) {
|
|
182349
|
+
bestd = d3;
|
|
182350
|
+
best = pt;
|
|
182351
|
+
}
|
|
182352
|
+
}
|
|
182353
|
+
return best;
|
|
182354
|
+
};
|
|
182355
|
+
return pick(left, right);
|
|
182356
|
+
}
|
|
182357
|
+
default: {
|
|
182358
|
+
return this.linePolygonIntersection(p1, p22, rectPoly());
|
|
182359
|
+
}
|
|
182360
|
+
}
|
|
182361
|
+
}
|
|
182362
|
+
lineCircleIntersection(p1, p22, c3) {
|
|
182363
|
+
const dx = p22.x - p1.x;
|
|
182364
|
+
const dy = p22.y - p1.y;
|
|
182365
|
+
const fx = p1.x - c3.cx;
|
|
182366
|
+
const fy = p1.y - c3.cy;
|
|
182367
|
+
const a3 = dx * dx + dy * dy;
|
|
182368
|
+
const b3 = 2 * (fx * dx + fy * dy);
|
|
182369
|
+
const cc2 = fx * fx + fy * fy - c3.r * c3.r;
|
|
182370
|
+
const disc = b3 * b3 - 4 * a3 * cc2;
|
|
182371
|
+
if (disc < 0)
|
|
182372
|
+
return null;
|
|
182373
|
+
const s3 = Math.sqrt(disc);
|
|
182374
|
+
const t1 = (-b3 - s3) / (2 * a3);
|
|
182375
|
+
const t22 = (-b3 + s3) / (2 * a3);
|
|
182376
|
+
const ts = [t1, t22].filter((t4) => t4 >= 0 && t4 <= 1);
|
|
182377
|
+
if (!ts.length)
|
|
182378
|
+
return null;
|
|
182379
|
+
const t3 = Math.max(...ts);
|
|
182380
|
+
return { x: p1.x + dx * t3, y: p1.y + dy * t3 };
|
|
182381
|
+
}
|
|
182382
|
+
linePolygonIntersection(p1, p22, poly) {
|
|
182383
|
+
let bestT = -Infinity;
|
|
182384
|
+
let best = null;
|
|
182385
|
+
for (let i3 = 0; i3 < poly.length; i3++) {
|
|
182386
|
+
const a3 = poly[i3];
|
|
182387
|
+
const b3 = poly[(i3 + 1) % poly.length];
|
|
182388
|
+
const hit = this.segmentIntersection(p1, p22, a3, b3);
|
|
182389
|
+
if (hit && hit.t >= 0 && hit.t <= 1 && hit.u >= 0 && hit.u <= 1) {
|
|
182390
|
+
if (hit.t > bestT) {
|
|
182391
|
+
bestT = hit.t;
|
|
182392
|
+
best = { x: hit.x, y: hit.y };
|
|
182393
|
+
}
|
|
182394
|
+
}
|
|
182395
|
+
}
|
|
182396
|
+
return best;
|
|
182397
|
+
}
|
|
182398
|
+
segmentIntersection(p3, p22, q3, q22) {
|
|
182399
|
+
const r3 = { x: p22.x - p3.x, y: p22.y - p3.y };
|
|
182400
|
+
const s3 = { x: q22.x - q3.x, y: q22.y - q3.y };
|
|
182401
|
+
const rxs = r3.x * s3.y - r3.y * s3.x;
|
|
182402
|
+
if (Math.abs(rxs) < 1e-6)
|
|
182403
|
+
return null;
|
|
182404
|
+
const q_p = { x: q3.x - p3.x, y: q3.y - p3.y };
|
|
182405
|
+
const t3 = (q_p.x * s3.y - q_p.y * s3.x) / rxs;
|
|
182406
|
+
const u3 = (q_p.x * r3.y - q_p.y * r3.x) / rxs;
|
|
182407
|
+
const x3 = p3.x + t3 * r3.x;
|
|
182408
|
+
const y2 = p3.y + t3 * r3.y;
|
|
182409
|
+
return { x: x3, y: y2, t: t3, u: u3 };
|
|
182410
|
+
}
|
|
182411
|
+
pointAtRatio(points, ratio) {
|
|
182412
|
+
const clampRatio = Math.max(0, Math.min(1, ratio));
|
|
182413
|
+
let total = 0;
|
|
182414
|
+
const segs = [];
|
|
182415
|
+
for (let i3 = 0; i3 < points.length - 1; i3++) {
|
|
182416
|
+
const dx = points[i3 + 1].x - points[i3].x;
|
|
182417
|
+
const dy = points[i3 + 1].y - points[i3].y;
|
|
182418
|
+
const len = Math.hypot(dx, dy);
|
|
182419
|
+
segs.push(len);
|
|
182420
|
+
total += len;
|
|
182421
|
+
}
|
|
182422
|
+
if (total === 0)
|
|
182423
|
+
return points[Math.floor(points.length / 2)];
|
|
182424
|
+
let target = total * clampRatio;
|
|
182425
|
+
for (let i3 = 0; i3 < segs.length; i3++) {
|
|
182426
|
+
if (target <= segs[i3]) {
|
|
182427
|
+
const t3 = segs[i3] === 0 ? 0 : target / segs[i3];
|
|
182428
|
+
return {
|
|
182429
|
+
x: points[i3].x + (points[i3 + 1].x - points[i3].x) * t3,
|
|
182430
|
+
y: points[i3].y + (points[i3 + 1].y - points[i3].y) * t3
|
|
182431
|
+
};
|
|
182432
|
+
}
|
|
182433
|
+
target -= segs[i3];
|
|
182434
|
+
}
|
|
182435
|
+
return points[points.length - 1];
|
|
182436
|
+
}
|
|
182437
|
+
escapeXml(text) {
|
|
182438
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
182439
|
+
}
|
|
182440
|
+
};
|
|
182441
|
+
}
|
|
182442
|
+
});
|
|
182443
|
+
|
|
182444
|
+
// node_modules/@probelabs/maid/out/renderer/pie-builder.js
|
|
182445
|
+
function unquote(s3) {
|
|
182446
|
+
if (!s3)
|
|
182447
|
+
return s3;
|
|
182448
|
+
const first2 = s3.charAt(0);
|
|
182449
|
+
const last2 = s3.charAt(s3.length - 1);
|
|
182450
|
+
if (first2 === '"' && last2 === '"' || first2 === "'" && last2 === "'") {
|
|
182451
|
+
const inner = s3.slice(1, -1);
|
|
182452
|
+
return inner.replace(/\\(["'])/g, "$1");
|
|
182453
|
+
}
|
|
182454
|
+
return s3;
|
|
182455
|
+
}
|
|
182456
|
+
function buildPieModel(text) {
|
|
182457
|
+
const errors = [];
|
|
182458
|
+
const lex = tokenize2(text);
|
|
182459
|
+
for (const e3 of lex.errors) {
|
|
182460
|
+
errors.push({
|
|
182461
|
+
line: e3.line ?? 1,
|
|
182462
|
+
column: e3.column ?? 1,
|
|
182463
|
+
message: e3.message,
|
|
182464
|
+
code: "PIE_LEX",
|
|
182465
|
+
severity: "error"
|
|
182466
|
+
});
|
|
182467
|
+
}
|
|
182468
|
+
parserInstance2.reset();
|
|
182469
|
+
parserInstance2.input = lex.tokens;
|
|
182470
|
+
const cst = parserInstance2.diagram();
|
|
182471
|
+
for (const e3 of parserInstance2.errors) {
|
|
182472
|
+
const t3 = e3.token;
|
|
182473
|
+
errors.push({
|
|
182474
|
+
line: t3?.startLine ?? 1,
|
|
182475
|
+
column: t3?.startColumn ?? 1,
|
|
182476
|
+
message: e3.message,
|
|
182477
|
+
code: "PIE_PARSE",
|
|
182478
|
+
severity: "error"
|
|
182479
|
+
});
|
|
182480
|
+
}
|
|
182481
|
+
const model = { title: void 0, showData: false, slices: [] };
|
|
182482
|
+
if (!cst || !cst.children)
|
|
182483
|
+
return { model, errors };
|
|
182484
|
+
if (cst.children.ShowDataKeyword && cst.children.ShowDataKeyword.length > 0) {
|
|
182485
|
+
model.showData = true;
|
|
182486
|
+
}
|
|
182487
|
+
const statements = cst.children.statement ?? [];
|
|
182488
|
+
for (const st of statements) {
|
|
182489
|
+
if (st.children?.titleStmt) {
|
|
182490
|
+
const tnode = st.children.titleStmt[0];
|
|
182491
|
+
const parts = [];
|
|
182492
|
+
const collect = (k3) => {
|
|
182493
|
+
const arr = tnode.children?.[k3] ?? [];
|
|
182494
|
+
for (const tok of arr)
|
|
182495
|
+
parts.push(unquote(tok.image));
|
|
182496
|
+
};
|
|
182497
|
+
collect("QuotedString");
|
|
182498
|
+
collect("Text");
|
|
182499
|
+
collect("NumberLiteral");
|
|
182500
|
+
const title = parts.join(" ").trim();
|
|
182501
|
+
if (title)
|
|
182502
|
+
model.title = title;
|
|
182503
|
+
} else if (st.children?.sliceStmt) {
|
|
182504
|
+
const snode = st.children.sliceStmt[0];
|
|
182505
|
+
const labelTok = snode.children?.sliceLabel?.[0]?.children?.QuotedString?.[0];
|
|
182506
|
+
const numTok = snode.children?.NumberLiteral?.[0];
|
|
182507
|
+
if (labelTok && numTok) {
|
|
182508
|
+
const label = unquote(labelTok.image).trim();
|
|
182509
|
+
const value = Number(numTok.image);
|
|
182510
|
+
if (!Number.isNaN(value)) {
|
|
182511
|
+
model.slices.push({ label, value });
|
|
182512
|
+
}
|
|
182513
|
+
}
|
|
182514
|
+
}
|
|
182515
|
+
}
|
|
182516
|
+
return { model, errors };
|
|
182517
|
+
}
|
|
182518
|
+
var init_pie_builder = __esm({
|
|
182519
|
+
"node_modules/@probelabs/maid/out/renderer/pie-builder.js"() {
|
|
182520
|
+
init_lexer3();
|
|
182521
|
+
init_parser3();
|
|
182522
|
+
}
|
|
182523
|
+
});
|
|
182524
|
+
|
|
182525
|
+
// node_modules/@probelabs/maid/out/renderer/pie-renderer.js
|
|
182526
|
+
function polarToCartesian(cx, cy, r3, angleRad) {
|
|
182527
|
+
return { x: cx + r3 * Math.cos(angleRad), y: cy + r3 * Math.sin(angleRad) };
|
|
182528
|
+
}
|
|
182529
|
+
function renderPie(model, opts = {}) {
|
|
182530
|
+
let width = Math.max(320, Math.floor(opts.width ?? 640));
|
|
182531
|
+
const height = Math.max(240, Math.floor(opts.height ?? 400));
|
|
182532
|
+
const pad = 24;
|
|
182533
|
+
const titleH = model.title ? 28 : 0;
|
|
182534
|
+
let cx = width / 2;
|
|
182535
|
+
const cy = (height + titleH) / 2 + (model.title ? 8 : 0);
|
|
182536
|
+
const baseRadius = Math.max(40, Math.min(width, height - titleH) / 2 - pad);
|
|
182537
|
+
const slices = model.slices.filter((s3) => Math.max(0, s3.value) > 0);
|
|
182538
|
+
const total = slices.reduce((a3, s3) => a3 + Math.max(0, s3.value), 0);
|
|
182539
|
+
const LEG_SW = 12;
|
|
182540
|
+
const LEG_GAP = 8;
|
|
182541
|
+
const LEG_VSPACE = 18;
|
|
182542
|
+
const legendItems = slices.map((s3) => `${s3.label}${model.showData ? ` ${formatNumber(Number(s3.value))}` : ""}`);
|
|
182543
|
+
const legendTextWidth = legendItems.length ? Math.max(...legendItems.map((t3) => measureText(t3, 12))) : 0;
|
|
182544
|
+
const legendBlockWidth = legendItems.length ? LEG_SW + LEG_GAP + legendTextWidth + pad : 0;
|
|
182545
|
+
if (legendItems.length) {
|
|
182546
|
+
const neededWidth = pad + baseRadius * 2 + legendBlockWidth + pad;
|
|
182547
|
+
if (neededWidth > width)
|
|
182548
|
+
width = Math.ceil(neededWidth);
|
|
182549
|
+
}
|
|
182550
|
+
let radius = baseRadius;
|
|
182551
|
+
if (legendItems.length) {
|
|
182552
|
+
const leftPad = Math.max(pad, (width - legendBlockWidth - radius * 2) / 2);
|
|
182553
|
+
cx = leftPad + radius;
|
|
182554
|
+
}
|
|
182555
|
+
let start = -Math.PI / 2;
|
|
182556
|
+
let svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">`;
|
|
182557
|
+
svg += `
|
|
182558
|
+
<style>
|
|
182559
|
+
.pie-title { font-family: Arial, sans-serif; font-size: 16px; font-weight: 600; fill: #222; }
|
|
182560
|
+
.slice-label { font-family: Arial, sans-serif; font-size: 12px; fill: #222; dominant-baseline: middle; }
|
|
182561
|
+
.leader { stroke: #444; stroke-width: 1; fill: none; }
|
|
182562
|
+
.pieCircle { stroke: black; stroke-width: 2px; opacity: 0.7; }
|
|
182563
|
+
.pieOuterCircle { stroke: black; stroke-width: 2px; fill: none; }
|
|
182564
|
+
</style>`;
|
|
182565
|
+
if (model.title) {
|
|
182566
|
+
svg += `
|
|
182567
|
+
<text class="pie-title" x="${cx}" y="${pad + 8}" text-anchor="middle">${escapeXml(model.title)}</text>`;
|
|
182568
|
+
}
|
|
182569
|
+
svg += `
|
|
182570
|
+
<g class="pie" aria-label="pie">`;
|
|
182571
|
+
const minOutsideAngle = 0.35;
|
|
182572
|
+
slices.forEach((s3, i3) => {
|
|
182573
|
+
const pct = total > 0 ? Math.max(0, s3.value) / total : 0;
|
|
182574
|
+
const angle = 2 * Math.PI * pct;
|
|
182575
|
+
const end = start + angle;
|
|
182576
|
+
const large = angle > Math.PI ? 1 : 0;
|
|
182577
|
+
const c0 = polarToCartesian(cx, cy, radius, start);
|
|
182578
|
+
const c1 = polarToCartesian(cx, cy, radius, end);
|
|
182579
|
+
const d3 = [
|
|
182580
|
+
`M ${cx} ${cy}`,
|
|
182581
|
+
`L ${c0.x.toFixed(2)} ${c0.y.toFixed(2)}`,
|
|
182582
|
+
`A ${radius} ${radius} 0 ${large} 1 ${c1.x.toFixed(2)} ${c1.y.toFixed(2)}`,
|
|
182583
|
+
"Z"
|
|
182584
|
+
].join(" ");
|
|
182585
|
+
const fill = s3.color || palette(i3);
|
|
182586
|
+
svg += `
|
|
182587
|
+
<path d="${d3}" class="pieCircle" fill="${fill}" />`;
|
|
182588
|
+
const mid = (start + end) / 2;
|
|
182589
|
+
const cos = Math.cos(mid);
|
|
182590
|
+
const sin = Math.sin(mid);
|
|
182591
|
+
const percentLabel = escapeXml(formatPercent(s3.value, total));
|
|
182592
|
+
if (angle < minOutsideAngle) {
|
|
182593
|
+
const r1 = radius * 0.9;
|
|
182594
|
+
const r22 = radius * 1.06;
|
|
182595
|
+
const p1 = polarToCartesian(cx, cy, r1, mid);
|
|
182596
|
+
const p22 = polarToCartesian(cx, cy, r22, mid);
|
|
182597
|
+
const hlen = 12;
|
|
182598
|
+
const anchorLeft = cos < 0;
|
|
182599
|
+
const hx = anchorLeft ? p22.x - hlen : p22.x + hlen;
|
|
182600
|
+
const hy = p22.y;
|
|
182601
|
+
svg += `
|
|
182602
|
+
<path class="leader" d="M ${p1.x.toFixed(2)} ${p1.y.toFixed(2)} L ${p22.x.toFixed(2)} ${p22.y.toFixed(2)} L ${hx.toFixed(2)} ${hy.toFixed(2)}" />`;
|
|
182603
|
+
const tx = anchorLeft ? hx - 2 : hx + 2;
|
|
182604
|
+
const tAnchor = anchorLeft ? "end" : "start";
|
|
182605
|
+
svg += `
|
|
182606
|
+
<text class="slice-label" x="${tx.toFixed(2)}" y="${hy.toFixed(2)}" text-anchor="${tAnchor}">${percentLabel}</text>`;
|
|
182607
|
+
} else {
|
|
182608
|
+
const lr = radius * 0.62;
|
|
182609
|
+
const lp = { x: cx + lr * cos, y: cy + lr * sin };
|
|
182610
|
+
const tAnchor = Math.abs(cos) < 0.2 ? "middle" : cos > 0 ? "start" : "end";
|
|
182611
|
+
const avail = lr;
|
|
182612
|
+
const textW = measureText(percentLabel, 12);
|
|
182613
|
+
const anchor = textW > avail * 1.2 ? "middle" : tAnchor;
|
|
182614
|
+
svg += `
|
|
182615
|
+
<text class="slice-label" x="${lp.x.toFixed(2)}" y="${lp.y.toFixed(2)}" text-anchor="${anchor}">${percentLabel}</text>`;
|
|
182616
|
+
}
|
|
182617
|
+
start = end;
|
|
182618
|
+
});
|
|
182619
|
+
const rimStroke = opts.rimStroke || "black";
|
|
182620
|
+
const rimWidth = opts.rimStrokeWidth != null ? String(opts.rimStrokeWidth) : "2px";
|
|
182621
|
+
svg += `
|
|
182622
|
+
</g>
|
|
182623
|
+
<circle class="pie-rim pieOuterCircle" cx="${cx}" cy="${cy}" r="${radius}" stroke="${rimStroke}" stroke-width="${rimWidth}" fill="none" />`;
|
|
182624
|
+
if (legendItems.length) {
|
|
182625
|
+
const legendX = cx + radius + pad / 2;
|
|
182626
|
+
const totalH = legendItems.length * LEG_VSPACE;
|
|
182627
|
+
let legendY = cy - totalH / 2 + 10;
|
|
182628
|
+
svg += `
|
|
182629
|
+
<g class="legend">`;
|
|
182630
|
+
slices.forEach((s3, i3) => {
|
|
182631
|
+
const y2 = legendY + i3 * LEG_VSPACE;
|
|
182632
|
+
const fill = s3.color || palette(i3);
|
|
182633
|
+
const text = escapeXml(`${s3.label}${model.showData ? ` ${formatNumber(Number(s3.value))}` : ""}`);
|
|
182634
|
+
svg += `
|
|
182635
|
+
<rect x="${legendX}" y="${y2 - LEG_SW + 6}" width="${LEG_SW}" height="${LEG_SW}" fill="${fill}" stroke="${fill}" stroke-width="1" />`;
|
|
182636
|
+
svg += `
|
|
182637
|
+
<text class="slice-label legend-text" x="${legendX + LEG_SW + LEG_GAP}" y="${y2}" text-anchor="start">${text}</text>`;
|
|
182638
|
+
});
|
|
182639
|
+
svg += `
|
|
182640
|
+
</g>`;
|
|
182641
|
+
}
|
|
182642
|
+
svg += `
|
|
182643
|
+
</svg>`;
|
|
182644
|
+
return svg;
|
|
182645
|
+
}
|
|
182646
|
+
var init_pie_renderer = __esm({
|
|
182647
|
+
"node_modules/@probelabs/maid/out/renderer/pie-renderer.js"() {
|
|
182648
|
+
init_utils4();
|
|
182649
|
+
}
|
|
182650
|
+
});
|
|
182651
|
+
|
|
182652
|
+
// node_modules/@probelabs/maid/out/renderer/sequence-builder.js
|
|
182653
|
+
function textFromTokens(tokens) {
|
|
182654
|
+
if (!tokens || tokens.length === 0)
|
|
182655
|
+
return "";
|
|
182656
|
+
const parts = [];
|
|
182657
|
+
for (const t3 of tokens) {
|
|
182658
|
+
const img = t3.image;
|
|
182659
|
+
if (!img)
|
|
182660
|
+
continue;
|
|
182661
|
+
if (t3.tokenType && t3.tokenType.name === "QuotedString") {
|
|
182662
|
+
if (img.startsWith('"') && img.endsWith('"'))
|
|
182663
|
+
parts.push(img.slice(1, -1));
|
|
182664
|
+
else if (img.startsWith("'") && img.endsWith("'"))
|
|
182665
|
+
parts.push(img.slice(1, -1));
|
|
182666
|
+
else
|
|
182667
|
+
parts.push(img);
|
|
182668
|
+
} else {
|
|
182669
|
+
parts.push(img);
|
|
182670
|
+
}
|
|
182671
|
+
}
|
|
182672
|
+
return parts.join(" ").replace(/\s+/g, " ").trim();
|
|
182673
|
+
}
|
|
182674
|
+
function actorRefToText(refCst) {
|
|
182675
|
+
const ch = refCst.children || {};
|
|
182676
|
+
const toks = [];
|
|
182677
|
+
["Identifier", "QuotedString", "NumberLiteral", "Text"].forEach((k3) => {
|
|
182678
|
+
const a3 = ch[k3];
|
|
182679
|
+
a3?.forEach((t3) => toks.push(t3));
|
|
182680
|
+
});
|
|
182681
|
+
toks.sort((a3, b3) => (a3.startOffset ?? 0) - (b3.startOffset ?? 0));
|
|
182682
|
+
return textFromTokens(toks);
|
|
182683
|
+
}
|
|
182684
|
+
function lineRemainderToText(lineRem) {
|
|
182685
|
+
if (!lineRem)
|
|
182686
|
+
return void 0;
|
|
182687
|
+
const ch = lineRem.children || {};
|
|
182688
|
+
const toks = [];
|
|
182689
|
+
const order = [
|
|
182690
|
+
"Identifier",
|
|
182691
|
+
"NumberLiteral",
|
|
182692
|
+
"QuotedString",
|
|
182693
|
+
"Text",
|
|
182694
|
+
"Plus",
|
|
182695
|
+
"Minus",
|
|
182696
|
+
"Comma",
|
|
182697
|
+
"Colon",
|
|
182698
|
+
"LParen",
|
|
182699
|
+
"RParen",
|
|
182700
|
+
"AndKeyword",
|
|
182701
|
+
"ElseKeyword",
|
|
182702
|
+
"OptKeyword",
|
|
182703
|
+
"OptionKeyword",
|
|
182704
|
+
"LoopKeyword",
|
|
182705
|
+
"ParKeyword",
|
|
182706
|
+
"RectKeyword",
|
|
182707
|
+
"CriticalKeyword",
|
|
182708
|
+
"BreakKeyword",
|
|
182709
|
+
"BoxKeyword",
|
|
182710
|
+
"EndKeyword",
|
|
182711
|
+
"NoteKeyword",
|
|
182712
|
+
"LeftKeyword",
|
|
182713
|
+
"RightKeyword",
|
|
182714
|
+
"OverKeyword",
|
|
182715
|
+
"OfKeyword",
|
|
182716
|
+
"AutonumberKeyword",
|
|
182717
|
+
"OffKeyword",
|
|
182718
|
+
"LinkKeyword",
|
|
182719
|
+
"LinksKeyword",
|
|
182720
|
+
"CreateKeyword",
|
|
182721
|
+
"DestroyKeyword",
|
|
182722
|
+
"ParticipantKeyword",
|
|
182723
|
+
"ActorKeyword",
|
|
182724
|
+
"ActivateKeyword",
|
|
182725
|
+
"DeactivateKeyword"
|
|
182726
|
+
];
|
|
182727
|
+
for (const k3 of order)
|
|
182728
|
+
ch[k3]?.forEach((t3) => toks.push(t3));
|
|
182729
|
+
toks.sort((a3, b3) => (a3.startOffset ?? 0) - (b3.startOffset ?? 0));
|
|
182730
|
+
return textFromTokens(toks) || void 0;
|
|
182731
|
+
}
|
|
182732
|
+
function canonicalId(raw) {
|
|
182733
|
+
const t3 = raw.trim().replace(/\s+/g, "_");
|
|
182734
|
+
return t3;
|
|
182735
|
+
}
|
|
182736
|
+
function ensureParticipant(map4, byDisplay, idLike, display) {
|
|
182737
|
+
const idGuess = canonicalId(idLike);
|
|
182738
|
+
const existing = map4.get(idGuess) || (byDisplay.get(idLike) ? map4.get(byDisplay.get(idLike)) : void 0);
|
|
182739
|
+
if (existing)
|
|
182740
|
+
return existing;
|
|
182741
|
+
const p3 = { id: idGuess, display: display || idLike };
|
|
182742
|
+
map4.set(p3.id, p3);
|
|
182743
|
+
byDisplay.set(p3.display, p3.id);
|
|
182744
|
+
return p3;
|
|
182745
|
+
}
|
|
182746
|
+
function msgFromArrow(arrowCst) {
|
|
182747
|
+
const ch = arrowCst.children || {};
|
|
182748
|
+
if (ch.BidirAsyncDotted)
|
|
182749
|
+
return { line: "dotted", start: "arrow", end: "arrow", async: true };
|
|
182750
|
+
if (ch.BidirAsync)
|
|
182751
|
+
return { line: "solid", start: "arrow", end: "arrow", async: true };
|
|
182752
|
+
if (ch.DottedAsync)
|
|
182753
|
+
return { line: "dotted", start: "none", end: "arrow", async: true };
|
|
182754
|
+
if (ch.Async)
|
|
182755
|
+
return { line: "solid", start: "none", end: "arrow", async: true };
|
|
182756
|
+
if (ch.Dotted)
|
|
182757
|
+
return { line: "dotted", start: "none", end: "arrow" };
|
|
182758
|
+
if (ch.Solid)
|
|
182759
|
+
return { line: "solid", start: "none", end: "arrow" };
|
|
182760
|
+
if (ch.DottedCross)
|
|
182761
|
+
return { line: "dotted", start: "none", end: "cross" };
|
|
182762
|
+
if (ch.Cross)
|
|
182763
|
+
return { line: "solid", start: "none", end: "cross" };
|
|
182764
|
+
if (ch.DottedOpen)
|
|
182765
|
+
return { line: "dotted", start: "none", end: "open" };
|
|
182766
|
+
if (ch.Open)
|
|
182767
|
+
return { line: "solid", start: "none", end: "open" };
|
|
182768
|
+
return { line: "solid", start: "none", end: "arrow" };
|
|
182769
|
+
}
|
|
182770
|
+
function buildSequenceModel(text) {
|
|
182771
|
+
const { tokens } = tokenize3(text);
|
|
182772
|
+
parserInstance3.input = tokens;
|
|
182773
|
+
const cst = parserInstance3.diagram();
|
|
182774
|
+
const participantsMap = /* @__PURE__ */ new Map();
|
|
182775
|
+
const byDisplay = /* @__PURE__ */ new Map();
|
|
182776
|
+
const events = [];
|
|
182777
|
+
let autonumber = { on: false };
|
|
182778
|
+
const diagramChildren = cst.children || {};
|
|
182779
|
+
const lines = diagramChildren.line || [];
|
|
182780
|
+
const openBlocks = [];
|
|
182781
|
+
function processLineNode(ln) {
|
|
182782
|
+
const ch = ln.children || {};
|
|
182783
|
+
if (ch.participantDecl) {
|
|
182784
|
+
const decl = ch.participantDecl[0];
|
|
182785
|
+
const dch = decl.children || {};
|
|
182786
|
+
const ref1 = dch.actorRef?.[0];
|
|
182787
|
+
const ref2 = dch.actorRef?.[1];
|
|
182788
|
+
const idText = actorRefToText(ref1);
|
|
182789
|
+
const aliasText = ref2 ? actorRefToText(ref2) : void 0;
|
|
182790
|
+
const id = canonicalId(idText);
|
|
182791
|
+
const display = aliasText || idText;
|
|
182792
|
+
const p3 = ensureParticipant(participantsMap, byDisplay, id, display);
|
|
182793
|
+
events.push({ kind: "create", actor: p3.id, display: p3.display });
|
|
182794
|
+
return;
|
|
182795
|
+
}
|
|
182796
|
+
if (ch.autonumberStmt) {
|
|
182797
|
+
const stmt = ch.autonumberStmt[0];
|
|
182798
|
+
const sch = stmt.children || {};
|
|
182799
|
+
autonumber = { on: true };
|
|
182800
|
+
const nums = sch.NumberLiteral || [];
|
|
182801
|
+
if (nums.length >= 1)
|
|
182802
|
+
autonumber.start = Number(nums[0].image);
|
|
182803
|
+
if (nums.length >= 2)
|
|
182804
|
+
autonumber.step = Number(nums[1].image);
|
|
182805
|
+
if (sch.OffKeyword)
|
|
182806
|
+
autonumber = { on: false };
|
|
182807
|
+
return;
|
|
182808
|
+
}
|
|
182809
|
+
if (ch.activateStmt) {
|
|
182810
|
+
const st = ch.activateStmt[0];
|
|
182811
|
+
const sch = st.children || {};
|
|
182812
|
+
const idTxt = actorRefToText(sch.actorRef?.[0]);
|
|
182813
|
+
const p3 = ensureParticipant(participantsMap, byDisplay, idTxt);
|
|
182814
|
+
events.push({ kind: "activate", actor: p3.id });
|
|
182815
|
+
return;
|
|
182816
|
+
}
|
|
182817
|
+
if (ch.deactivateStmt) {
|
|
182818
|
+
const st = ch.deactivateStmt[0];
|
|
182819
|
+
const sch = st.children || {};
|
|
182820
|
+
const idTxt = actorRefToText(sch.actorRef?.[0]);
|
|
182821
|
+
const p3 = ensureParticipant(participantsMap, byDisplay, idTxt);
|
|
182822
|
+
events.push({ kind: "deactivate", actor: p3.id });
|
|
182823
|
+
return;
|
|
182824
|
+
}
|
|
182825
|
+
if (ch.createStmt) {
|
|
182826
|
+
const st = ch.createStmt[0];
|
|
182827
|
+
const sch = st.children || {};
|
|
182828
|
+
const idTxt = actorRefToText(sch.actorRef?.[0]);
|
|
182829
|
+
const alias = sch.lineRemainder ? lineRemainderToText(sch.lineRemainder[0]) : void 0;
|
|
182830
|
+
const p3 = ensureParticipant(participantsMap, byDisplay, idTxt, alias || idTxt);
|
|
182831
|
+
events.push({ kind: "create", actor: p3.id, display: p3.display });
|
|
182832
|
+
return;
|
|
182833
|
+
}
|
|
182834
|
+
if (ch.destroyStmt) {
|
|
182835
|
+
const st = ch.destroyStmt[0];
|
|
182836
|
+
const sch = st.children || {};
|
|
182837
|
+
const idTxt = actorRefToText(sch.actorRef?.[0]);
|
|
182838
|
+
const p3 = ensureParticipant(participantsMap, byDisplay, idTxt);
|
|
182839
|
+
events.push({ kind: "destroy", actor: p3.id });
|
|
182840
|
+
return;
|
|
182841
|
+
}
|
|
182842
|
+
if (ch.noteStmt) {
|
|
182843
|
+
const st = ch.noteStmt[0];
|
|
182844
|
+
const sch = st.children || {};
|
|
182845
|
+
const text2 = lineRemainderToText(sch.lineRemainder?.[0]) || "";
|
|
182846
|
+
if (sch.LeftKeyword || sch.RightKeyword) {
|
|
182847
|
+
const pos = sch.LeftKeyword ? "leftOf" : "rightOf";
|
|
182848
|
+
const actorTxt = actorRefToText(sch.actorRef?.[0]);
|
|
182849
|
+
const p3 = ensureParticipant(participantsMap, byDisplay, actorTxt);
|
|
182850
|
+
const note = { pos, actors: [p3.id], text: text2 };
|
|
182851
|
+
events.push({ kind: "note", note });
|
|
182852
|
+
} else if (sch.OverKeyword) {
|
|
182853
|
+
const a1 = actorRefToText(sch.actorRef?.[0]);
|
|
182854
|
+
const a22 = sch.actorRef?.[1] ? actorRefToText(sch.actorRef?.[1]) : void 0;
|
|
182855
|
+
const p1 = ensureParticipant(participantsMap, byDisplay, a1);
|
|
182856
|
+
const ids = [p1.id];
|
|
182857
|
+
if (a22) {
|
|
182858
|
+
const p22 = ensureParticipant(participantsMap, byDisplay, a22);
|
|
182859
|
+
ids.push(p22.id);
|
|
182860
|
+
}
|
|
182861
|
+
events.push({ kind: "note", note: { pos: "over", actors: ids, text: text2 } });
|
|
182862
|
+
}
|
|
182863
|
+
return;
|
|
182864
|
+
}
|
|
182865
|
+
const blockKinds = [
|
|
182866
|
+
{ key: "altBlock", type: "alt", branchKeys: [{ key: "ElseKeyword", kind: "else" }] },
|
|
182867
|
+
{ key: "optBlock", type: "opt" },
|
|
182868
|
+
{ key: "loopBlock", type: "loop" },
|
|
182869
|
+
{ key: "parBlock", type: "par", branchKeys: [{ key: "AndKeyword", kind: "and" }] },
|
|
182870
|
+
{ key: "criticalBlock", type: "critical", branchKeys: [{ key: "OptionKeyword", kind: "option" }] },
|
|
182871
|
+
{ key: "breakBlock", type: "break" },
|
|
182872
|
+
{ key: "rectBlock", type: "rect" },
|
|
182873
|
+
{ key: "boxBlock", type: "box" }
|
|
182874
|
+
];
|
|
182875
|
+
let handledBlock = false;
|
|
182876
|
+
for (const spec of blockKinds) {
|
|
182877
|
+
if (ch[spec.key]) {
|
|
182878
|
+
handledBlock = true;
|
|
182879
|
+
const bnode = ch[spec.key][0];
|
|
182880
|
+
const bch = bnode.children || {};
|
|
182881
|
+
const title = lineRemainderToText(bch.lineRemainder?.[0]);
|
|
182882
|
+
const block = { type: spec.type, title, branches: spec.branchKeys ? [] : void 0 };
|
|
182883
|
+
openBlocks.push(block);
|
|
182884
|
+
events.push({ kind: "block-start", block });
|
|
182885
|
+
if (spec.branchKeys) {
|
|
182886
|
+
const newlines = bch.Newline || [];
|
|
182887
|
+
const branchKey = spec.branchKeys[0].key;
|
|
182888
|
+
const branchTokArr = bch[branchKey];
|
|
182889
|
+
const lrArr = bch.lineRemainder;
|
|
182890
|
+
if (branchTokArr && branchTokArr.length) {
|
|
182891
|
+
const lr = (lrArr || []).slice(1);
|
|
182892
|
+
for (let i3 = 0; i3 < branchTokArr.length; i3++) {
|
|
182893
|
+
const title2 = lr[i3] ? lineRemainderToText(lr[i3]) : void 0;
|
|
182894
|
+
const br = { kind: spec.branchKeys[0].kind, title: title2 };
|
|
182895
|
+
block.branches.push(br);
|
|
182896
|
+
events.push({ kind: "block-branch", block, branch: br });
|
|
182897
|
+
}
|
|
182898
|
+
}
|
|
182899
|
+
}
|
|
182900
|
+
events.push({ kind: "block-end", block });
|
|
182901
|
+
openBlocks.pop();
|
|
182902
|
+
break;
|
|
182903
|
+
}
|
|
182904
|
+
}
|
|
182905
|
+
if (handledBlock)
|
|
182906
|
+
return;
|
|
182907
|
+
if (ch.messageStmt) {
|
|
182908
|
+
const st = ch.messageStmt[0];
|
|
182909
|
+
const sch = st.children || {};
|
|
182910
|
+
const fromTxt = actorRefToText(sch.actorRef?.[0]);
|
|
182911
|
+
const toTxt = actorRefToText(sch.actorRef?.[1]);
|
|
182912
|
+
const from = ensureParticipant(participantsMap, byDisplay, fromTxt).id;
|
|
182913
|
+
const to = ensureParticipant(participantsMap, byDisplay, toTxt).id;
|
|
182914
|
+
const arrow = msgFromArrow(sch.arrow?.[0]);
|
|
182915
|
+
const text2 = lineRemainderToText(sch.lineRemainder?.[0]);
|
|
182916
|
+
const activateTarget = !!sch.Plus;
|
|
182917
|
+
const deactivateTarget = !!sch.Minus;
|
|
182918
|
+
const msg = { from, to, text: text2, line: arrow.line, startMarker: arrow.start, endMarker: arrow.end, async: arrow.async, activateTarget, deactivateTarget };
|
|
182919
|
+
events.push({ kind: "message", msg });
|
|
182920
|
+
return;
|
|
182921
|
+
}
|
|
182922
|
+
if (ch.linkStmt) {
|
|
182923
|
+
events.push({ kind: "noop" });
|
|
182924
|
+
return;
|
|
182925
|
+
}
|
|
182926
|
+
events.push({ kind: "noop" });
|
|
182927
|
+
}
|
|
182928
|
+
function collectInnerLines(blockNode) {
|
|
182929
|
+
const out = [];
|
|
182930
|
+
const ch = blockNode.children || {};
|
|
182931
|
+
for (const key of Object.keys(ch)) {
|
|
182932
|
+
const arr = ch[key];
|
|
182933
|
+
if (Array.isArray(arr)) {
|
|
182934
|
+
for (const node of arr) {
|
|
182935
|
+
if (node && typeof node === "object" && node.name === "line")
|
|
182936
|
+
out.push(node);
|
|
182937
|
+
}
|
|
182938
|
+
}
|
|
182939
|
+
}
|
|
182940
|
+
return out;
|
|
182941
|
+
}
|
|
182942
|
+
for (const ln of lines) {
|
|
182943
|
+
processLineNode(ln);
|
|
182944
|
+
const ch = ln.children || {};
|
|
182945
|
+
const block = ch.altBlock?.[0] || ch.optBlock?.[0] || ch.loopBlock?.[0] || ch.parBlock?.[0] || ch.criticalBlock?.[0] || ch.breakBlock?.[0] || ch.rectBlock?.[0] || ch.boxBlock?.[0];
|
|
182946
|
+
if (block) {
|
|
182947
|
+
for (const inner of collectInnerLines(block))
|
|
182948
|
+
processLineNode(inner);
|
|
182949
|
+
}
|
|
182950
|
+
}
|
|
182951
|
+
return {
|
|
182952
|
+
participants: Array.from(participantsMap.values()),
|
|
182953
|
+
events,
|
|
182954
|
+
autonumber: autonumber.on === true || autonumber.on === false ? autonumber : { on: false }
|
|
182955
|
+
};
|
|
182956
|
+
}
|
|
182957
|
+
var init_sequence_builder = __esm({
|
|
182958
|
+
"node_modules/@probelabs/maid/out/renderer/sequence-builder.js"() {
|
|
182959
|
+
init_lexer4();
|
|
182960
|
+
init_parser4();
|
|
182961
|
+
}
|
|
182962
|
+
});
|
|
182963
|
+
|
|
182964
|
+
// node_modules/@probelabs/maid/out/renderer/sequence-layout.js
|
|
182965
|
+
function layoutSequence(model) {
|
|
182966
|
+
const order = [];
|
|
182967
|
+
const seen = /* @__PURE__ */ new Set();
|
|
182968
|
+
const partById = new Map(model.participants.map((p3) => [p3.id, p3]));
|
|
182969
|
+
function touch(id) {
|
|
182970
|
+
if (!seen.has(id)) {
|
|
182971
|
+
seen.add(id);
|
|
182972
|
+
order.push(id);
|
|
182973
|
+
}
|
|
182974
|
+
}
|
|
182975
|
+
for (const ev of model.events) {
|
|
182976
|
+
if (ev.kind === "message") {
|
|
182977
|
+
touch(ev.msg.from);
|
|
182978
|
+
touch(ev.msg.to);
|
|
182979
|
+
}
|
|
182980
|
+
if (ev.kind === "note") {
|
|
182981
|
+
ev.note.actors.forEach(touch);
|
|
182982
|
+
}
|
|
182983
|
+
if (ev.kind === "activate" || ev.kind === "deactivate" || ev.kind === "create" || ev.kind === "destroy")
|
|
182984
|
+
touch(ev.actor);
|
|
182985
|
+
}
|
|
182986
|
+
for (const p3 of model.participants)
|
|
182987
|
+
touch(p3.id);
|
|
182988
|
+
const participants = [];
|
|
182989
|
+
let x3 = MARGIN_X;
|
|
182990
|
+
for (const id of order) {
|
|
182991
|
+
const p3 = partById.get(id) || { id, display: id };
|
|
182992
|
+
const w3 = Math.max(COL_MIN, measureText(p3.display, ACTOR_FONT_SIZE) + ACTOR_PAD_X * 2);
|
|
182993
|
+
participants.push({ id, display: p3.display, x: x3, y: MARGIN_Y, width: w3, height: ACTOR_H });
|
|
182994
|
+
x3 += w3 + MARGIN_X;
|
|
182995
|
+
}
|
|
182996
|
+
const width = Math.max(320, x3);
|
|
182997
|
+
const rowIndexForEvent = /* @__PURE__ */ new Map();
|
|
182998
|
+
let row = 0;
|
|
182999
|
+
const openBlocks = [];
|
|
183000
|
+
function consumeRow(idx) {
|
|
183001
|
+
rowIndexForEvent.set(idx, row++);
|
|
183002
|
+
}
|
|
183003
|
+
model.events.forEach((ev, idx) => {
|
|
183004
|
+
switch (ev.kind) {
|
|
183005
|
+
case "message":
|
|
183006
|
+
consumeRow(idx);
|
|
183007
|
+
break;
|
|
183008
|
+
case "note":
|
|
183009
|
+
consumeRow(idx);
|
|
183010
|
+
break;
|
|
183011
|
+
case "block-start":
|
|
183012
|
+
openBlocks.push({ block: ev.block, startRow: row, branches: [] });
|
|
183013
|
+
consumeRow(idx);
|
|
183014
|
+
break;
|
|
183015
|
+
case "block-branch": {
|
|
183016
|
+
const top = openBlocks[openBlocks.length - 1];
|
|
183017
|
+
if (top)
|
|
183018
|
+
top.branches.push({ title: ev.branch.title, row });
|
|
183019
|
+
consumeRow(idx);
|
|
183020
|
+
break;
|
|
183021
|
+
}
|
|
183022
|
+
case "block-end":
|
|
183023
|
+
break;
|
|
183024
|
+
case "activate":
|
|
183025
|
+
case "deactivate":
|
|
183026
|
+
case "create":
|
|
183027
|
+
case "destroy":
|
|
183028
|
+
case "noop":
|
|
183029
|
+
break;
|
|
183030
|
+
}
|
|
183031
|
+
});
|
|
183032
|
+
const lifelineTop = MARGIN_Y + ACTOR_H + LIFELINE_GAP;
|
|
183033
|
+
const contentHeight = row * ROW_H;
|
|
183034
|
+
const height = lifelineTop + contentHeight + MARGIN_Y + ACTOR_H;
|
|
183035
|
+
const lifelines = participants.map((p3) => ({ x: p3.x + p3.width / 2, y1: lifelineTop, y2: height - MARGIN_Y - ACTOR_H }));
|
|
183036
|
+
function yForRow(r3) {
|
|
183037
|
+
return lifelineTop + r3 * ROW_H + ROW_H / 2;
|
|
183038
|
+
}
|
|
183039
|
+
const col = new Map(participants.map((p3) => [p3.id, p3]));
|
|
183040
|
+
const messages = [];
|
|
183041
|
+
const notes = [];
|
|
183042
|
+
const blocks = [];
|
|
183043
|
+
const activations = [];
|
|
183044
|
+
const actStack = /* @__PURE__ */ new Map();
|
|
183045
|
+
const startAct = (actor, r3) => {
|
|
183046
|
+
const arr = actStack.get(actor) || [];
|
|
183047
|
+
arr.push(r3);
|
|
183048
|
+
actStack.set(actor, arr);
|
|
183049
|
+
};
|
|
183050
|
+
const endAct = (actor, r3) => {
|
|
183051
|
+
const arr = actStack.get(actor) || [];
|
|
183052
|
+
const start = arr.pop();
|
|
183053
|
+
if (start != null) {
|
|
183054
|
+
const p3 = col.get(actor);
|
|
183055
|
+
if (p3) {
|
|
183056
|
+
activations.push({ actor, x: p3.x + p3.width / 2 - 4, y: yForRow(start) - ROW_H / 2, width: 8, height: yForRow(r3) - yForRow(start) });
|
|
183057
|
+
}
|
|
183058
|
+
}
|
|
183059
|
+
actStack.set(actor, arr);
|
|
183060
|
+
};
|
|
183061
|
+
const openForLayout = [];
|
|
183062
|
+
model.events.forEach((ev, idx) => {
|
|
183063
|
+
const r3 = rowIndexForEvent.has(idx) ? rowIndexForEvent.get(idx) : null;
|
|
183064
|
+
switch (ev.kind) {
|
|
183065
|
+
case "message": {
|
|
183066
|
+
const p1 = col.get(ev.msg.from), p22 = col.get(ev.msg.to);
|
|
183067
|
+
if (p1 && p22 && r3 != null) {
|
|
183068
|
+
const y2 = yForRow(r3);
|
|
183069
|
+
const x1 = p1.x + p1.width / 2;
|
|
183070
|
+
const x22 = p22.x + p22.width / 2;
|
|
183071
|
+
messages.push({ from: p1.id, to: p22.id, text: ev.msg.text, y: y2, x1, x2: x22, line: ev.msg.line, startMarker: ev.msg.startMarker, endMarker: ev.msg.endMarker, async: ev.msg.async });
|
|
183072
|
+
if (ev.msg.activateTarget)
|
|
183073
|
+
startAct(ev.msg.to, r3);
|
|
183074
|
+
if (ev.msg.deactivateTarget)
|
|
183075
|
+
endAct(ev.msg.to, r3);
|
|
183076
|
+
const top = openForLayout[openForLayout.length - 1];
|
|
183077
|
+
if (top)
|
|
183078
|
+
top.lastRow = r3;
|
|
183079
|
+
}
|
|
183080
|
+
break;
|
|
183081
|
+
}
|
|
183082
|
+
case "note": {
|
|
183083
|
+
if (r3 == null)
|
|
183084
|
+
break;
|
|
183085
|
+
const estLines = (text, width2) => {
|
|
183086
|
+
const charsPerLine = Math.max(8, Math.floor((width2 - NOTE_PAD * 2) / 7));
|
|
183087
|
+
const length = text ? text.length : 0;
|
|
183088
|
+
return Math.max(1, Math.ceil(length / charsPerLine));
|
|
183089
|
+
};
|
|
183090
|
+
const y2 = yForRow(r3) - NOTE_PAD;
|
|
183091
|
+
if (ev.note.pos === "over") {
|
|
183092
|
+
const [a3, b3] = ev.note.actors;
|
|
183093
|
+
const p1 = col.get(a3), p22 = b3 ? col.get(b3) : p1;
|
|
183094
|
+
if (p1 && p22) {
|
|
183095
|
+
const left = Math.min(p1.x + p1.width / 2, p22.x + p22.width / 2);
|
|
183096
|
+
const right = Math.max(p1.x + p1.width / 2, p22.x + p22.width / 2);
|
|
183097
|
+
const w3 = right - left + NOTE_PAD * 2;
|
|
183098
|
+
const lines = estLines(ev.note.text, w3);
|
|
183099
|
+
const h3 = Math.max(ROW_H - NOTE_PAD, lines * 16 + NOTE_PAD);
|
|
183100
|
+
notes.push({ x: left - NOTE_PAD, y: y2, width: w3, height: h3, text: ev.note.text, anchor: "over" });
|
|
183101
|
+
}
|
|
183102
|
+
} else {
|
|
183103
|
+
const actor = ev.note.actors[0];
|
|
183104
|
+
const p3 = col.get(actor);
|
|
183105
|
+
if (p3) {
|
|
183106
|
+
const leftSide = ev.note.pos === "leftOf";
|
|
183107
|
+
const x4 = leftSide ? p3.x - NOTE_W - 10 : p3.x + p3.width + 10;
|
|
183108
|
+
const lines = estLines(ev.note.text, NOTE_W);
|
|
183109
|
+
const h3 = Math.max(ROW_H - NOTE_PAD, lines * 16 + NOTE_PAD);
|
|
183110
|
+
notes.push({ x: x4, y: y2, width: NOTE_W, height: h3, text: ev.note.text, anchor: leftSide ? "left" : "right" });
|
|
183111
|
+
}
|
|
183112
|
+
}
|
|
183113
|
+
const top = openForLayout[openForLayout.length - 1];
|
|
183114
|
+
if (top && r3 != null)
|
|
183115
|
+
top.lastRow = r3;
|
|
183116
|
+
break;
|
|
183117
|
+
}
|
|
183118
|
+
case "activate":
|
|
183119
|
+
if (r3 != null)
|
|
183120
|
+
startAct(ev.actor, r3);
|
|
183121
|
+
break;
|
|
183122
|
+
case "deactivate":
|
|
183123
|
+
if (r3 != null)
|
|
183124
|
+
endAct(ev.actor, r3);
|
|
183125
|
+
break;
|
|
183126
|
+
case "block-start": {
|
|
183127
|
+
const startRow = r3 != null ? r3 : row;
|
|
183128
|
+
openForLayout.push({ block: ev.block, startRow, branches: [] });
|
|
183129
|
+
break;
|
|
183130
|
+
}
|
|
183131
|
+
case "block-branch": {
|
|
183132
|
+
const top = openForLayout[openForLayout.length - 1];
|
|
183133
|
+
if (top && r3 != null) {
|
|
183134
|
+
top.branches.push({ title: ev.branch.title, row: r3 });
|
|
183135
|
+
top.lastRow = r3;
|
|
183136
|
+
}
|
|
183137
|
+
break;
|
|
183138
|
+
}
|
|
183139
|
+
case "block-end": {
|
|
183140
|
+
const top = openForLayout.pop();
|
|
183141
|
+
if (top) {
|
|
183142
|
+
const first2 = participants.length > 0 ? participants[0] : void 0;
|
|
183143
|
+
const last2 = participants.length > 0 ? participants[participants.length - 1] : void 0;
|
|
183144
|
+
const left = first2 ? first2.x : MARGIN_X;
|
|
183145
|
+
const right = last2 ? last2.x + last2.width : left + 200;
|
|
183146
|
+
const yTop = yForRow(top.startRow) - ROW_H / 2 - (BLOCK_PAD + TITLE_EXTRA_TOP);
|
|
183147
|
+
const endRow = top.lastRow != null ? top.lastRow : top.startRow;
|
|
183148
|
+
const yBot = yForRow(endRow) + ROW_H / 2 + BLOCK_PAD;
|
|
183149
|
+
const layout = { type: top.block.type, title: top.block.title, x: left - BLOCK_PAD, y: yTop, width: right - left + BLOCK_PAD * 2, height: yBot - yTop };
|
|
183150
|
+
if (top.branches.length)
|
|
183151
|
+
layout.branches = top.branches.map((b3) => ({ title: b3.title, y: yForRow(b3.row) - ROW_H / 2 }));
|
|
183152
|
+
blocks.push(layout);
|
|
183153
|
+
}
|
|
183154
|
+
break;
|
|
183155
|
+
}
|
|
183156
|
+
default:
|
|
183157
|
+
break;
|
|
183158
|
+
}
|
|
183159
|
+
});
|
|
183160
|
+
const lastRow = row;
|
|
183161
|
+
for (const [actor, arr] of actStack.entries()) {
|
|
183162
|
+
while (arr.length) {
|
|
183163
|
+
const start = arr.pop();
|
|
183164
|
+
const p3 = col.get(actor);
|
|
183165
|
+
if (p3)
|
|
183166
|
+
activations.push({ actor, x: p3.x + p3.width / 2 - 4, y: yForRow(start) - ROW_H / 2, width: 8, height: yForRow(lastRow) - yForRow(start) });
|
|
183167
|
+
}
|
|
183168
|
+
}
|
|
183169
|
+
return { width, height, participants, lifelines, messages, notes, blocks, activations };
|
|
183170
|
+
}
|
|
183171
|
+
var MARGIN_X, MARGIN_Y, ACTOR_FONT_SIZE, ACTOR_H, LIFELINE_GAP, ACTOR_PAD_X, COL_MIN, ROW_H, NOTE_W, NOTE_PAD, BLOCK_PAD, TITLE_EXTRA_TOP;
|
|
183172
|
+
var init_sequence_layout = __esm({
|
|
183173
|
+
"node_modules/@probelabs/maid/out/renderer/sequence-layout.js"() {
|
|
183174
|
+
init_utils4();
|
|
183175
|
+
MARGIN_X = 24;
|
|
183176
|
+
MARGIN_Y = 24;
|
|
183177
|
+
ACTOR_FONT_SIZE = 16;
|
|
183178
|
+
ACTOR_H = 32;
|
|
183179
|
+
LIFELINE_GAP = 4;
|
|
183180
|
+
ACTOR_PAD_X = 12;
|
|
183181
|
+
COL_MIN = 110;
|
|
183182
|
+
ROW_H = 36;
|
|
183183
|
+
NOTE_W = 160;
|
|
183184
|
+
NOTE_PAD = 8;
|
|
183185
|
+
BLOCK_PAD = 8;
|
|
183186
|
+
TITLE_EXTRA_TOP = 12;
|
|
183187
|
+
}
|
|
183188
|
+
});
|
|
183189
|
+
|
|
183190
|
+
// node_modules/@probelabs/maid/out/renderer/sequence-renderer.js
|
|
183191
|
+
function renderSequence(model, opts = {}) {
|
|
183192
|
+
const layout = layoutSequence(model);
|
|
183193
|
+
const svgParts = [];
|
|
183194
|
+
const width = Math.ceil(layout.width);
|
|
183195
|
+
const height = Math.ceil(layout.height);
|
|
183196
|
+
svgParts.push(`<svg xmlns="http://www.w3.org/2000/svg" width="${width + 50}" height="${height + 40}" viewBox="-50 -10 ${width + 50} ${height + 40}">`);
|
|
183197
|
+
const sharedCss = buildSharedCss({
|
|
183198
|
+
fontFamily: "Arial, sans-serif",
|
|
183199
|
+
fontSize: 14,
|
|
183200
|
+
nodeFill: "#eef0ff",
|
|
183201
|
+
nodeStroke: "#3f3f3f",
|
|
183202
|
+
edgeStroke: "#555555"
|
|
183203
|
+
});
|
|
183204
|
+
svgParts.push(` <style>${sharedCss}</style>`);
|
|
183205
|
+
for (const p3 of layout.participants)
|
|
183206
|
+
drawParticipant(svgParts, p3);
|
|
183207
|
+
for (const b3 of layout.blocks)
|
|
183208
|
+
svgParts.push(blockBackground(b3.x, b3.y, b3.width, b3.height, 0));
|
|
183209
|
+
for (const l3 of layout.lifelines)
|
|
183210
|
+
svgParts.push(` <line class="lifeline" x1="${l3.x}" y1="${l3.y1}" x2="${l3.x}" y2="${l3.y2}"/>`);
|
|
183211
|
+
for (const a3 of layout.activations)
|
|
183212
|
+
svgParts.push(` <rect class="activation" x="${a3.x}" y="${a3.y}" width="${a3.width}" height="${a3.height}" />`);
|
|
183213
|
+
let counter = model.autonumber?.on ? model.autonumber.start ?? 1 : void 0;
|
|
183214
|
+
const step = model.autonumber?.on ? model.autonumber.step ?? 1 : void 0;
|
|
183215
|
+
for (const m3 of layout.messages) {
|
|
183216
|
+
drawMessage(svgParts, m3);
|
|
183217
|
+
const label = formatMessageLabel(m3.text, counter);
|
|
183218
|
+
if (label)
|
|
183219
|
+
drawMessageLabel(svgParts, m3, label, counter);
|
|
183220
|
+
if (counter != null)
|
|
183221
|
+
counter += step;
|
|
183222
|
+
}
|
|
183223
|
+
for (const n3 of layout.notes)
|
|
183224
|
+
drawNote(svgParts, n3);
|
|
183225
|
+
for (const b3 of layout.blocks) {
|
|
183226
|
+
const title = b3.title ? `${b3.type}: ${b3.title}` : b3.type;
|
|
183227
|
+
const branches = (b3.branches || []).map((br) => ({ y: br.y, title: br.title }));
|
|
183228
|
+
svgParts.push(blockOverlay(b3.x, b3.y, b3.width, b3.height, title, branches, 0, "left", "left", 0));
|
|
183229
|
+
}
|
|
183230
|
+
for (const p3 of layout.participants)
|
|
183231
|
+
drawParticipantBottom(svgParts, p3, layout);
|
|
183232
|
+
svgParts.push("</svg>");
|
|
183233
|
+
let svg = svgParts.join("\n");
|
|
183234
|
+
if (opts.theme)
|
|
183235
|
+
svg = applySequenceTheme(svg, opts.theme);
|
|
183236
|
+
return svg;
|
|
183237
|
+
}
|
|
183238
|
+
function drawParticipant(out, p3) {
|
|
183239
|
+
out.push(` <g class="actor" transform="translate(${p3.x},${p3.y})">`);
|
|
183240
|
+
out.push(` <rect class="node-shape" width="${p3.width}" height="${p3.height}" rx="0"/>`);
|
|
183241
|
+
out.push(` <text class="node-label" x="${p3.width / 2}" y="${p3.height / 2}" text-anchor="middle" dominant-baseline="middle">${escapeXml(p3.display)}</text>`);
|
|
183242
|
+
out.push(" </g>");
|
|
183243
|
+
}
|
|
183244
|
+
function drawParticipantBottom(out, p3, layout) {
|
|
183245
|
+
const lifeline = layout.lifelines.find((l3) => Math.abs(l3.x - (p3.x + p3.width / 2)) < 1e-3);
|
|
183246
|
+
const y2 = lifeline ? lifeline.y2 : layout.height - 28;
|
|
183247
|
+
out.push(` <g class="actor" transform="translate(${p3.x},${y2})">`);
|
|
183248
|
+
out.push(` <rect class="node-shape" width="${p3.width}" height="${p3.height}" rx="0"/>`);
|
|
183249
|
+
out.push(` <text class="node-label" x="${p3.width / 2}" y="${p3.height / 2}" text-anchor="middle" dominant-baseline="middle">${escapeXml(p3.display)}</text>`);
|
|
183250
|
+
out.push(" </g>");
|
|
183251
|
+
}
|
|
183252
|
+
function drawMessage(out, m3) {
|
|
183253
|
+
const cls = `msg-line ${m3.line}`.trim();
|
|
183254
|
+
const x1 = m3.x1, x22 = m3.x2, y2 = m3.y;
|
|
183255
|
+
out.push(` <path class="${cls}" d="M ${x1} ${y2} L ${x22} ${y2}" />`);
|
|
183256
|
+
const start = { x: x1, y: y2 };
|
|
183257
|
+
const end = { x: x22, y: y2 };
|
|
183258
|
+
if (m3.endMarker === "arrow")
|
|
183259
|
+
out.push(" " + triangleAtEnd(start, end));
|
|
183260
|
+
if (m3.startMarker === "arrow")
|
|
183261
|
+
out.push(" " + triangleAtStart(start, end));
|
|
183262
|
+
if (m3.endMarker === "open")
|
|
183263
|
+
out.push(` <circle class="openhead" cx="${x22}" cy="${y2}" r="4" />`);
|
|
183264
|
+
if (m3.startMarker === "open")
|
|
183265
|
+
out.push(` <circle class="openhead" cx="${x1}" cy="${y2}" r="4" />`);
|
|
183266
|
+
if (m3.endMarker === "cross")
|
|
183267
|
+
out.push(` <g class="crosshead" transform="translate(${x22},${y2})"><path d="M -4 -4 L 4 4"/><path d="M -4 4 L 4 -4"/></g>`);
|
|
183268
|
+
if (m3.startMarker === "cross")
|
|
183269
|
+
out.push(` <g class="crosshead" transform="translate(${x1},${y2})"><path d="M -4 -4 L 4 4"/><path d="M -4 4 L 4 -4"/></g>`);
|
|
183270
|
+
}
|
|
183271
|
+
function formatMessageLabel(text, counter) {
|
|
183272
|
+
if (!text && counter == null)
|
|
183273
|
+
return void 0;
|
|
183274
|
+
if (counter != null && text)
|
|
183275
|
+
return `${counter}: ${text}`;
|
|
183276
|
+
if (counter != null)
|
|
183277
|
+
return String(counter);
|
|
183278
|
+
return text;
|
|
183279
|
+
}
|
|
183280
|
+
function drawMessageLabel(out, m3, label, _counter) {
|
|
183281
|
+
const xMid = (m3.x1 + m3.x2) / 2;
|
|
183282
|
+
const h3 = 16;
|
|
183283
|
+
const w3 = Math.max(20, measureText(label, 12) + 10);
|
|
183284
|
+
const x3 = xMid - w3 / 2;
|
|
183285
|
+
const y2 = m3.y - 10 - h3 / 2;
|
|
183286
|
+
out.push(` <rect class="msg-label-bg" x="${x3}" y="${y2}" width="${w3}" height="${h3}" rx="0"/>`);
|
|
183287
|
+
out.push(` <text class="msg-label" x="${xMid}" y="${y2 + h3 / 2}" text-anchor="middle">${escapeXml(label)}</text>`);
|
|
183288
|
+
}
|
|
183289
|
+
function drawNote(out, n3) {
|
|
183290
|
+
out.push(` <g class="note" transform="translate(${n3.x},${n3.y})">`);
|
|
183291
|
+
out.push(` <rect width="${n3.width}" height="${n3.height}" rx="0"/>`);
|
|
183292
|
+
out.push(` <text class="note-text" x="${n3.width / 2}" y="${n3.height / 2 + 4}" text-anchor="middle">${escapeXml(n3.text)}</text>`);
|
|
183293
|
+
out.push(" </g>");
|
|
183294
|
+
}
|
|
183295
|
+
function applySequenceTheme(svg, theme) {
|
|
183296
|
+
let out = svg;
|
|
183297
|
+
if (theme.actorBkg)
|
|
183298
|
+
out = out.replace(/\.actor-rect\s*\{[^}]*\}/, (m3) => m3.replace(/fill:\s*[^;]+;/, `fill: ${String(theme.actorBkg)};`));
|
|
183299
|
+
if (theme.actorBorder)
|
|
183300
|
+
out = out.replace(/\.actor-rect\s*\{[^}]*\}/, (m3) => m3.replace(/stroke:\s*[^;]+;/, `stroke: ${String(theme.actorBorder)};`));
|
|
183301
|
+
if (theme.actorTextColor)
|
|
183302
|
+
out = out.replace(/\.actor-label\s*\{[^}]*\}/, (m3) => m3.replace(/fill:\s*[^;]+;/, `fill: ${String(theme.actorTextColor)};`));
|
|
183303
|
+
if (theme.lifelineColor)
|
|
183304
|
+
out = out.replace(/\.lifeline\s*\{[^}]*\}/, (m3) => m3.replace(/stroke:\s*[^;]+;/, `stroke: ${String(theme.lifelineColor)};`));
|
|
183305
|
+
if (theme.lineColor)
|
|
183306
|
+
out = out.replace(/\.msg-line\s*\{[^}]*\}/, (m3) => m3.replace(/stroke:\s*[^;]+;/, `stroke: ${String(theme.lineColor)};`));
|
|
183307
|
+
if (theme.arrowheadColor) {
|
|
183308
|
+
out = out.replace(/\.arrowhead\s*\{[^}]*\}/, (m3) => m3.replace(/fill:\s*[^;]+;/, `fill: ${String(theme.arrowheadColor)};`));
|
|
183309
|
+
out = out.replace(/\.openhead\s*\{[^}]*\}/, (m3) => m3.replace(/stroke:\s*[^;]+;/, `stroke: ${String(theme.arrowheadColor)};`));
|
|
183310
|
+
out = out.replace(/\.crosshead\s*\{[^}]*\}/, (m3) => m3.replace(/stroke:\s*[^;]+;/, `stroke: ${String(theme.arrowheadColor)};`));
|
|
183311
|
+
}
|
|
183312
|
+
if (theme.noteBkg)
|
|
183313
|
+
out = out.replace(/\.note\s*\{[^}]*\}/, (m3) => m3.replace(/fill:\s*[^;]+;/, `fill: ${String(theme.noteBkg)};`));
|
|
183314
|
+
if (theme.noteBorder)
|
|
183315
|
+
out = out.replace(/\.note\s*\{[^}]*\}/, (m3) => m3.replace(/stroke:\s*[^;]+;/, `stroke: ${String(theme.noteBorder)};`));
|
|
183316
|
+
if (theme.noteTextColor)
|
|
183317
|
+
out = out.replace(/\.note-text\s*\{[^}]*\}/, (m3) => m3.replace(/fill:\s*[^;]+;/, `fill: ${String(theme.noteTextColor)};`));
|
|
183318
|
+
if (theme.activationBkg)
|
|
183319
|
+
out = out.replace(/\.activation\s*\{[^}]*\}/, (m3) => m3.replace(/fill:\s*[^;]+;/, `fill: ${String(theme.activationBkg)};`));
|
|
183320
|
+
if (theme.activationBorder)
|
|
183321
|
+
out = out.replace(/\.activation\s*\{[^}]*\}/, (m3) => m3.replace(/stroke:\s*[^;]+;/, `stroke: ${String(theme.activationBorder)};`));
|
|
183322
|
+
return out;
|
|
183323
|
+
}
|
|
183324
|
+
var init_sequence_renderer = __esm({
|
|
183325
|
+
"node_modules/@probelabs/maid/out/renderer/sequence-renderer.js"() {
|
|
183326
|
+
init_sequence_layout();
|
|
183327
|
+
init_utils4();
|
|
183328
|
+
init_arrow_utils();
|
|
183329
|
+
init_block_utils();
|
|
183330
|
+
init_styles();
|
|
183331
|
+
}
|
|
183332
|
+
});
|
|
183333
|
+
|
|
183334
|
+
// node_modules/@probelabs/maid/out/core/frontmatter.js
|
|
183335
|
+
function parseFrontmatter(input) {
|
|
183336
|
+
const text = input.startsWith("\uFEFF") ? input.slice(1) : input;
|
|
183337
|
+
const lines = text.split(/\r?\n/);
|
|
183338
|
+
if (lines.length < 3 || lines[0].trim() !== "---")
|
|
183339
|
+
return null;
|
|
183340
|
+
let i3 = 1;
|
|
183341
|
+
const block = [];
|
|
183342
|
+
while (i3 < lines.length && lines[i3].trim() !== "---") {
|
|
183343
|
+
block.push(lines[i3]);
|
|
183344
|
+
i3++;
|
|
183345
|
+
}
|
|
183346
|
+
if (i3 >= lines.length)
|
|
183347
|
+
return null;
|
|
183348
|
+
const body = lines.slice(i3 + 1).join("\n");
|
|
183349
|
+
const raw = block.join("\n");
|
|
183350
|
+
const config = {};
|
|
183351
|
+
const themeVars = {};
|
|
183352
|
+
let themeUnderConfig = false;
|
|
183353
|
+
let ctx = "root";
|
|
183354
|
+
for (const line of block) {
|
|
183355
|
+
if (!line.trim())
|
|
183356
|
+
continue;
|
|
183357
|
+
const indent = line.match(/^\s*/)?.[0].length ?? 0;
|
|
183358
|
+
const mKey = line.match(/^\s*([A-Za-z0-9_\-]+):\s*(.*)$/);
|
|
183359
|
+
if (!mKey)
|
|
183360
|
+
continue;
|
|
183361
|
+
const key = mKey[1];
|
|
183362
|
+
let value = mKey[2] || "";
|
|
183363
|
+
if (indent === 0) {
|
|
183364
|
+
if (key === "config") {
|
|
183365
|
+
ctx = "config";
|
|
183366
|
+
continue;
|
|
183367
|
+
}
|
|
183368
|
+
if (key === "themeVariables") {
|
|
183369
|
+
ctx = "theme";
|
|
183370
|
+
continue;
|
|
183371
|
+
}
|
|
183372
|
+
ctx = "root";
|
|
183373
|
+
continue;
|
|
183374
|
+
}
|
|
183375
|
+
if (ctx === "config") {
|
|
183376
|
+
if (indent <= 2 && key !== "pie" && key !== "themeVariables")
|
|
183377
|
+
continue;
|
|
183378
|
+
if (key === "pie") {
|
|
183379
|
+
ctx = "config.pie";
|
|
183380
|
+
ensure(config, "pie", {});
|
|
183381
|
+
continue;
|
|
183382
|
+
}
|
|
183383
|
+
if (key === "themeVariables") {
|
|
183384
|
+
ctx = "theme";
|
|
183385
|
+
themeUnderConfig = true;
|
|
183386
|
+
continue;
|
|
183387
|
+
}
|
|
183388
|
+
continue;
|
|
183389
|
+
}
|
|
183390
|
+
if (ctx === "config.pie") {
|
|
183391
|
+
if (indent < 4) {
|
|
183392
|
+
if (key === "pie") {
|
|
183393
|
+
ctx = "config.pie";
|
|
183394
|
+
ensure(config, "pie", {});
|
|
183395
|
+
continue;
|
|
183396
|
+
}
|
|
183397
|
+
if (key === "themeVariables") {
|
|
183398
|
+
ctx = "theme";
|
|
183399
|
+
themeUnderConfig = true;
|
|
183400
|
+
continue;
|
|
183401
|
+
}
|
|
183402
|
+
ctx = "config";
|
|
183403
|
+
continue;
|
|
183404
|
+
}
|
|
183405
|
+
setKV(config.pie, key, value);
|
|
183406
|
+
continue;
|
|
183407
|
+
}
|
|
183408
|
+
if (ctx === "theme") {
|
|
183409
|
+
if (indent < 2) {
|
|
183410
|
+
ctx = "root";
|
|
183411
|
+
continue;
|
|
183412
|
+
}
|
|
183413
|
+
setKV(themeVars, key, value);
|
|
183414
|
+
continue;
|
|
183415
|
+
}
|
|
183416
|
+
}
|
|
183417
|
+
if (themeUnderConfig && Object.keys(themeVars).length) {
|
|
183418
|
+
ensure(config, "themeVariables", {});
|
|
183419
|
+
Object.assign(config.themeVariables, themeVars);
|
|
183420
|
+
}
|
|
183421
|
+
return { raw, body, config: Object.keys(config).length ? config : void 0, themeVariables: Object.keys(themeVars).length ? themeVars : void 0 };
|
|
183422
|
+
}
|
|
183423
|
+
function ensure(obj, key, def) {
|
|
183424
|
+
if (obj[key] == null)
|
|
183425
|
+
obj[key] = def;
|
|
183426
|
+
}
|
|
183427
|
+
function unquote2(val) {
|
|
183428
|
+
const v3 = val.trim();
|
|
183429
|
+
if (v3.startsWith('"') && v3.endsWith('"') || v3.startsWith("'") && v3.endsWith("'")) {
|
|
183430
|
+
return v3.slice(1, -1);
|
|
183431
|
+
}
|
|
183432
|
+
return v3;
|
|
183433
|
+
}
|
|
183434
|
+
function setKV(target, key, rawValue) {
|
|
183435
|
+
const v3 = unquote2(rawValue);
|
|
183436
|
+
if (v3 === "") {
|
|
183437
|
+
target[key] = "";
|
|
183438
|
+
return;
|
|
183439
|
+
}
|
|
183440
|
+
const num = Number(v3);
|
|
183441
|
+
if (!Number.isNaN(num) && /^-?[0-9]+(\.[0-9]+)?$/.test(v3)) {
|
|
183442
|
+
target[key] = num;
|
|
183443
|
+
return;
|
|
183444
|
+
}
|
|
183445
|
+
if (/^(true|false)$/i.test(v3)) {
|
|
183446
|
+
target[key] = /^true$/i.test(v3);
|
|
183447
|
+
return;
|
|
183448
|
+
}
|
|
183449
|
+
target[key] = v3;
|
|
183450
|
+
}
|
|
183451
|
+
var init_frontmatter = __esm({
|
|
183452
|
+
"node_modules/@probelabs/maid/out/core/frontmatter.js"() {
|
|
179980
183453
|
}
|
|
179981
183454
|
});
|
|
179982
183455
|
|
|
@@ -179987,6 +183460,102 @@ var init_dot_renderer = __esm({
|
|
|
179987
183460
|
});
|
|
179988
183461
|
|
|
179989
183462
|
// node_modules/@probelabs/maid/out/renderer/index.js
|
|
183463
|
+
function applyPieTheme(svg, theme) {
|
|
183464
|
+
if (!theme)
|
|
183465
|
+
return svg;
|
|
183466
|
+
let out = svg;
|
|
183467
|
+
if (theme.pieOuterStrokeWidth != null || theme.pieStrokeColor) {
|
|
183468
|
+
out = out.replace(/\.pieOuterCircle\s*\{[^}]*\}/, (m3) => {
|
|
183469
|
+
let rule = m3;
|
|
183470
|
+
if (theme.pieStrokeColor)
|
|
183471
|
+
rule = rule.replace(/stroke:\s*[^;]+;/, `stroke: ${String(theme.pieStrokeColor)};`);
|
|
183472
|
+
if (theme.pieOuterStrokeWidth != null)
|
|
183473
|
+
rule = rule.replace(/stroke-width:\s*[^;]+;/, `stroke-width: ${String(theme.pieOuterStrokeWidth)};`);
|
|
183474
|
+
return rule;
|
|
183475
|
+
});
|
|
183476
|
+
if (theme.pieStrokeColor) {
|
|
183477
|
+
out = out.replace(/\.pieCircle\s*\{[^}]*\}/, (m3) => m3.replace(/stroke:\s*[^;]+;/, `stroke: ${String(theme.pieStrokeColor)};`));
|
|
183478
|
+
}
|
|
183479
|
+
}
|
|
183480
|
+
if (theme.pieSectionTextColor) {
|
|
183481
|
+
const c3 = String(theme.pieSectionTextColor);
|
|
183482
|
+
out = out.replace(/\.slice-label \{[^}]*\}/, (m3) => m3.replace(/fill:\s*#[0-9A-Fa-f]{3,8}|fill:\s*rgb\([^)]*\)/, `fill: ${c3}`));
|
|
183483
|
+
out = out.replace(/<text class="slice-label"([^>]*)>/g, `<text class="slice-label"$1 fill="${c3}">`);
|
|
183484
|
+
}
|
|
183485
|
+
if (theme.pieTitleTextColor) {
|
|
183486
|
+
const c3 = String(theme.pieTitleTextColor);
|
|
183487
|
+
out = out.replace(/<text class="pie-title"([^>]*)>/g, `<text class="pie-title"$1 fill="${c3}">`);
|
|
183488
|
+
}
|
|
183489
|
+
if (theme.pieSectionTextSize) {
|
|
183490
|
+
const size = String(theme.pieSectionTextSize);
|
|
183491
|
+
out = out.replace(/<text class="slice-label"([^>]*)>/g, `<text class="slice-label"$1 font-size="${size}">`);
|
|
183492
|
+
}
|
|
183493
|
+
if (theme.pieTitleTextSize) {
|
|
183494
|
+
const size = String(theme.pieTitleTextSize);
|
|
183495
|
+
out = out.replace(/<text class="pie-title"([^>]*)>/g, `<text class="pie-title"$1 font-size="${size}">`);
|
|
183496
|
+
}
|
|
183497
|
+
const colors = [];
|
|
183498
|
+
for (let i3 = 1; i3 <= 24; i3++) {
|
|
183499
|
+
const key = "pie" + i3;
|
|
183500
|
+
if (theme[key])
|
|
183501
|
+
colors.push(String(theme[key]));
|
|
183502
|
+
}
|
|
183503
|
+
if (colors.length) {
|
|
183504
|
+
let idx = 0;
|
|
183505
|
+
out = out.replace(/<path[^>]*class="pieCircle"[^>]*\sfill="([^"]+)"/g, (_m2) => {
|
|
183506
|
+
const color = colors[idx] ?? null;
|
|
183507
|
+
idx++;
|
|
183508
|
+
if (color)
|
|
183509
|
+
return _m2.replace(/fill="([^"]+)"/, `fill="${color}"`);
|
|
183510
|
+
return _m2;
|
|
183511
|
+
});
|
|
183512
|
+
}
|
|
183513
|
+
return out;
|
|
183514
|
+
}
|
|
183515
|
+
function applyFlowchartTheme(svg, theme) {
|
|
183516
|
+
if (!theme)
|
|
183517
|
+
return svg;
|
|
183518
|
+
let out = svg;
|
|
183519
|
+
if (theme.nodeBkg || theme.nodeBorder) {
|
|
183520
|
+
out = out.replace(/\.node-shape\s*\{[^}]*\}/, (m3) => {
|
|
183521
|
+
let rule = m3;
|
|
183522
|
+
if (theme.nodeBkg)
|
|
183523
|
+
rule = rule.replace(/fill:\s*[^;]+;/, `fill: ${String(theme.nodeBkg)};`);
|
|
183524
|
+
if (theme.nodeBorder)
|
|
183525
|
+
rule = rule.replace(/stroke:\s*[^;]+;/, `stroke: ${String(theme.nodeBorder)};`);
|
|
183526
|
+
return rule;
|
|
183527
|
+
});
|
|
183528
|
+
}
|
|
183529
|
+
if (theme.nodeTextColor) {
|
|
183530
|
+
out = out.replace(/\.node-label\s*\{[^}]*\}/, (m3) => m3.replace(/fill:\s*[^;]+;/, `fill: ${String(theme.nodeTextColor)};`));
|
|
183531
|
+
}
|
|
183532
|
+
if (theme.lineColor) {
|
|
183533
|
+
out = out.replace(/\.edge-path\s*\{[^}]*\}/, (m3) => m3.replace(/stroke:\s*[^;]+;/, `stroke: ${String(theme.lineColor)};`));
|
|
183534
|
+
}
|
|
183535
|
+
if (theme.arrowheadColor) {
|
|
183536
|
+
out = out.replace(/(<path d="M0,0 L0,[0-9.]+ L[0-9.]+,[0-9.]+ z"[^>]*)(fill="[^"]*")/g, (_m2, p1) => `${p1}fill="${String(theme.arrowheadColor)}"`);
|
|
183537
|
+
out = out.replace(/(<circle cx="4\.5" cy="4\.5" r="4\.5"[^>]*)(fill="[^"]*")/g, (_m2, p1) => `${p1}fill="${String(theme.arrowheadColor)}"`);
|
|
183538
|
+
}
|
|
183539
|
+
if (theme.clusterBkg) {
|
|
183540
|
+
out = out.replace(/\.cluster-bg\s*\{[^}]*\}/, (m3) => m3.replace(/fill:\s*[^;]+;/, `fill: ${String(theme.clusterBkg)};`));
|
|
183541
|
+
}
|
|
183542
|
+
if (theme.clusterBorder) {
|
|
183543
|
+
out = out.replace(/\.cluster-border\s*\{[^}]*\}/, (m3) => m3.replace(/stroke:\s*[^;]+;/, `stroke: ${String(theme.clusterBorder)};`));
|
|
183544
|
+
}
|
|
183545
|
+
if (theme.clusterTextColor) {
|
|
183546
|
+
out = out.replace(/\.cluster-label-text\s*\{[^}]*\}/, (m3) => m3.replace(/fill:\s*[^;]+;/, `fill: ${String(theme.clusterTextColor)};`));
|
|
183547
|
+
}
|
|
183548
|
+
if (theme.fontFamily)
|
|
183549
|
+
out = out.replace(/\.node-label\s*\{[^}]*\}/, (m3) => m3.replace(/font-family:\s*[^;]+;/, `font-family: ${String(theme.fontFamily)};`));
|
|
183550
|
+
if (theme.fontSize)
|
|
183551
|
+
out = out.replace(/\.node-label\s*\{[^}]*\}/, (m3) => m3.replace(/font-size:\s*[^;]+;/, `font-size: ${String(theme.fontSize)};`));
|
|
183552
|
+
return out;
|
|
183553
|
+
}
|
|
183554
|
+
function renderMermaid(text, options = {}) {
|
|
183555
|
+
const renderer = new MermaidRenderer(options.layoutEngine, options.renderer);
|
|
183556
|
+
return renderer.renderAny(text, options);
|
|
183557
|
+
}
|
|
183558
|
+
var MermaidRenderer;
|
|
179990
183559
|
var init_renderer = __esm({
|
|
179991
183560
|
"node_modules/@probelabs/maid/out/renderer/index.js"() {
|
|
179992
183561
|
init_lexer2();
|
|
@@ -179994,9 +183563,244 @@ var init_renderer = __esm({
|
|
|
179994
183563
|
init_graph_builder();
|
|
179995
183564
|
init_layout();
|
|
179996
183565
|
init_svg_generator();
|
|
183566
|
+
init_pie_builder();
|
|
183567
|
+
init_pie_renderer();
|
|
183568
|
+
init_sequence_builder();
|
|
183569
|
+
init_sequence_renderer();
|
|
183570
|
+
init_frontmatter();
|
|
179997
183571
|
init_layout();
|
|
179998
183572
|
init_svg_generator();
|
|
179999
183573
|
init_dot_renderer();
|
|
183574
|
+
MermaidRenderer = class {
|
|
183575
|
+
constructor(layoutEngine, renderer) {
|
|
183576
|
+
this.graphBuilder = new GraphBuilder();
|
|
183577
|
+
this.layoutEngine = layoutEngine || new DagreLayoutEngine();
|
|
183578
|
+
this.renderer = renderer || new SVGRenderer();
|
|
183579
|
+
}
|
|
183580
|
+
/**
|
|
183581
|
+
* Renders a Mermaid flowchart diagram
|
|
183582
|
+
*/
|
|
183583
|
+
render(text, options = {}) {
|
|
183584
|
+
const errors = [];
|
|
183585
|
+
const layoutEngine = options.layoutEngine || this.layoutEngine;
|
|
183586
|
+
const renderer = options.renderer || this.renderer;
|
|
183587
|
+
try {
|
|
183588
|
+
const lexResult = tokenize(text);
|
|
183589
|
+
if (lexResult.errors && lexResult.errors.length > 0) {
|
|
183590
|
+
for (const error2 of lexResult.errors) {
|
|
183591
|
+
errors.push({
|
|
183592
|
+
line: error2.line || 1,
|
|
183593
|
+
column: error2.column || 1,
|
|
183594
|
+
message: error2.message,
|
|
183595
|
+
severity: "error",
|
|
183596
|
+
code: "LEXER_ERROR"
|
|
183597
|
+
});
|
|
183598
|
+
}
|
|
183599
|
+
}
|
|
183600
|
+
parserInstance.reset();
|
|
183601
|
+
parserInstance.input = lexResult.tokens;
|
|
183602
|
+
const cst = parserInstance.diagram();
|
|
183603
|
+
if (parserInstance.errors && parserInstance.errors.length > 0) {
|
|
183604
|
+
for (const error2 of parserInstance.errors) {
|
|
183605
|
+
const token = error2.token;
|
|
183606
|
+
errors.push({
|
|
183607
|
+
line: token?.startLine || 1,
|
|
183608
|
+
column: token?.startColumn || 1,
|
|
183609
|
+
message: error2.message,
|
|
183610
|
+
severity: "error",
|
|
183611
|
+
code: "PARSER_ERROR"
|
|
183612
|
+
});
|
|
183613
|
+
}
|
|
183614
|
+
}
|
|
183615
|
+
const graph = this.graphBuilder.build(cst);
|
|
183616
|
+
let layout;
|
|
183617
|
+
try {
|
|
183618
|
+
layout = layoutEngine.layout(graph);
|
|
183619
|
+
} catch (layoutError) {
|
|
183620
|
+
errors.push({
|
|
183621
|
+
line: 1,
|
|
183622
|
+
column: 1,
|
|
183623
|
+
message: layoutError.message || "Layout calculation failed",
|
|
183624
|
+
severity: "error",
|
|
183625
|
+
code: "LAYOUT_ERROR"
|
|
183626
|
+
});
|
|
183627
|
+
return {
|
|
183628
|
+
svg: this.generateErrorSvg(layoutError.message || "Layout calculation failed"),
|
|
183629
|
+
graph,
|
|
183630
|
+
errors
|
|
183631
|
+
};
|
|
183632
|
+
}
|
|
183633
|
+
let svg = renderer.render(layout);
|
|
183634
|
+
if (options.showErrors && errors.length > 0) {
|
|
183635
|
+
svg = this.addErrorOverlays(svg, errors);
|
|
183636
|
+
}
|
|
183637
|
+
return {
|
|
183638
|
+
svg,
|
|
183639
|
+
graph,
|
|
183640
|
+
errors
|
|
183641
|
+
};
|
|
183642
|
+
} catch (error2) {
|
|
183643
|
+
const errorSvg = this.generateErrorSvg(error2.message || "Unknown error occurred");
|
|
183644
|
+
errors.push({
|
|
183645
|
+
line: 1,
|
|
183646
|
+
column: 1,
|
|
183647
|
+
message: error2.message || "Unknown error occurred",
|
|
183648
|
+
severity: "error",
|
|
183649
|
+
code: "RENDER_ERROR"
|
|
183650
|
+
});
|
|
183651
|
+
return {
|
|
183652
|
+
svg: errorSvg,
|
|
183653
|
+
graph: { nodes: [], edges: [], direction: "TD" },
|
|
183654
|
+
errors
|
|
183655
|
+
};
|
|
183656
|
+
}
|
|
183657
|
+
}
|
|
183658
|
+
/**
|
|
183659
|
+
* Renders supported diagram types (flowchart + pie for now)
|
|
183660
|
+
*/
|
|
183661
|
+
renderAny(text, options = {}) {
|
|
183662
|
+
let content = text;
|
|
183663
|
+
let theme;
|
|
183664
|
+
if (text.trimStart().startsWith("---")) {
|
|
183665
|
+
const fm = parseFrontmatter(text);
|
|
183666
|
+
if (fm) {
|
|
183667
|
+
content = fm.body;
|
|
183668
|
+
theme = fm.themeVariables || fm.config && fm.config.themeVariables || void 0;
|
|
183669
|
+
}
|
|
183670
|
+
}
|
|
183671
|
+
const firstLine = content.trim().split("\n")[0];
|
|
183672
|
+
if (/^(flowchart|graph)\s+/i.test(firstLine)) {
|
|
183673
|
+
const res = this.render(content, options);
|
|
183674
|
+
const svg2 = theme ? applyFlowchartTheme(res.svg, theme) : res.svg;
|
|
183675
|
+
return { svg: svg2, graph: res.graph, errors: res.errors };
|
|
183676
|
+
}
|
|
183677
|
+
if (/^pie\b/i.test(firstLine)) {
|
|
183678
|
+
try {
|
|
183679
|
+
const { model, errors } = buildPieModel(content);
|
|
183680
|
+
const svg = renderPie(model, {
|
|
183681
|
+
width: options.width,
|
|
183682
|
+
height: options.height,
|
|
183683
|
+
rimStroke: theme?.pieStrokeColor,
|
|
183684
|
+
rimStrokeWidth: theme?.pieOuterStrokeWidth
|
|
183685
|
+
});
|
|
183686
|
+
const themedSvg = applyPieTheme(svg, theme);
|
|
183687
|
+
return { svg: themedSvg, graph: { nodes: [], edges: [], direction: "TD" }, errors };
|
|
183688
|
+
} catch (e3) {
|
|
183689
|
+
const msg = e3?.message || "Pie render error";
|
|
183690
|
+
const err = [{ line: 1, column: 1, message: msg, severity: "error", code: "PIE_RENDER" }];
|
|
183691
|
+
return { svg: this.generateErrorSvg(msg), graph: { nodes: [], edges: [], direction: "TD" }, errors: err };
|
|
183692
|
+
}
|
|
183693
|
+
}
|
|
183694
|
+
if (/^sequenceDiagram\b/.test(firstLine)) {
|
|
183695
|
+
try {
|
|
183696
|
+
const model = buildSequenceModel(content);
|
|
183697
|
+
const svg = renderSequence(model, { theme });
|
|
183698
|
+
return { svg, graph: { nodes: [], edges: [], direction: "TD" }, errors: [] };
|
|
183699
|
+
} catch (e3) {
|
|
183700
|
+
const msg = e3?.message || "Sequence render error";
|
|
183701
|
+
const err = [{ line: 1, column: 1, message: msg, severity: "error", code: "SEQUENCE_RENDER" }];
|
|
183702
|
+
return { svg: this.generateErrorSvg(msg), graph: { nodes: [], edges: [], direction: "TD" }, errors: err };
|
|
183703
|
+
}
|
|
183704
|
+
}
|
|
183705
|
+
const errorSvg = this.generateErrorSvg("Unsupported diagram type. Rendering supports flowchart, pie, and sequence for now.");
|
|
183706
|
+
return {
|
|
183707
|
+
svg: errorSvg,
|
|
183708
|
+
graph: { nodes: [], edges: [], direction: "TD" },
|
|
183709
|
+
errors: [{
|
|
183710
|
+
line: 1,
|
|
183711
|
+
column: 1,
|
|
183712
|
+
message: "Unsupported diagram type",
|
|
183713
|
+
severity: "error",
|
|
183714
|
+
code: "UNSUPPORTED_TYPE"
|
|
183715
|
+
}]
|
|
183716
|
+
};
|
|
183717
|
+
}
|
|
183718
|
+
addErrorOverlays(svg, errors) {
|
|
183719
|
+
const errorStyle = `
|
|
183720
|
+
<style>
|
|
183721
|
+
.error-indicator {
|
|
183722
|
+
fill: #ff0000;
|
|
183723
|
+
opacity: 0.8;
|
|
183724
|
+
}
|
|
183725
|
+
.error-text {
|
|
183726
|
+
fill: white;
|
|
183727
|
+
font-family: Arial, sans-serif;
|
|
183728
|
+
font-size: 12px;
|
|
183729
|
+
font-weight: bold;
|
|
183730
|
+
}
|
|
183731
|
+
</style>`;
|
|
183732
|
+
const errorIndicator = `
|
|
183733
|
+
<g id="errors">
|
|
183734
|
+
<rect x="5" y="5" width="100" height="25" rx="3" class="error-indicator" />
|
|
183735
|
+
<text x="55" y="20" text-anchor="middle" class="error-text">${errors.length} error${errors.length !== 1 ? "s" : ""}</text>
|
|
183736
|
+
</g>`;
|
|
183737
|
+
return svg.replace("</svg>", `${errorStyle}${errorIndicator}</svg>`);
|
|
183738
|
+
}
|
|
183739
|
+
generateErrorSvg(message) {
|
|
183740
|
+
const width = 400;
|
|
183741
|
+
const height = 200;
|
|
183742
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">
|
|
183743
|
+
<rect width="${width}" height="${height}" fill="#fee" stroke="#c00" stroke-width="2" />
|
|
183744
|
+
<text x="${width / 2}" y="${height / 2 - 20}" text-anchor="middle" font-family="Arial, sans-serif" font-size="16" fill="#c00">
|
|
183745
|
+
Render Error
|
|
183746
|
+
</text>
|
|
183747
|
+
<text x="${width / 2}" y="${height / 2 + 10}" text-anchor="middle" font-family="Arial, sans-serif" font-size="12" fill="#666">
|
|
183748
|
+
${this.wrapText(message, 40).map((line, i3) => `<tspan x="${width / 2}" dy="${i3 === 0 ? 0 : 15}">${this.escapeXml(line)}</tspan>`).join("")}
|
|
183749
|
+
</text>
|
|
183750
|
+
</svg>`;
|
|
183751
|
+
}
|
|
183752
|
+
wrapText(text, maxLength) {
|
|
183753
|
+
const words = text.split(" ");
|
|
183754
|
+
const lines = [];
|
|
183755
|
+
let currentLine = "";
|
|
183756
|
+
for (const word of words) {
|
|
183757
|
+
if (currentLine.length + word.length + 1 <= maxLength) {
|
|
183758
|
+
currentLine += (currentLine ? " " : "") + word;
|
|
183759
|
+
} else {
|
|
183760
|
+
if (currentLine)
|
|
183761
|
+
lines.push(currentLine);
|
|
183762
|
+
currentLine = word;
|
|
183763
|
+
}
|
|
183764
|
+
}
|
|
183765
|
+
if (currentLine)
|
|
183766
|
+
lines.push(currentLine);
|
|
183767
|
+
return lines.slice(0, 3);
|
|
183768
|
+
}
|
|
183769
|
+
escapeXml(text) {
|
|
183770
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
183771
|
+
}
|
|
183772
|
+
};
|
|
183773
|
+
}
|
|
183774
|
+
});
|
|
183775
|
+
|
|
183776
|
+
// node_modules/@probelabs/maid/out/mermaid-compat.js
|
|
183777
|
+
function createMermaidAPI() {
|
|
183778
|
+
return {
|
|
183779
|
+
initialize(_config) {
|
|
183780
|
+
},
|
|
183781
|
+
async render(_id, text, options) {
|
|
183782
|
+
try {
|
|
183783
|
+
const result = renderMermaid(text, options);
|
|
183784
|
+
return { svg: result.svg };
|
|
183785
|
+
} catch (error2) {
|
|
183786
|
+
throw new Error(`Maid render failed: ${error2.message || "Unknown error"}`);
|
|
183787
|
+
}
|
|
183788
|
+
},
|
|
183789
|
+
renderSync(_id, text, options) {
|
|
183790
|
+
try {
|
|
183791
|
+
const result = renderMermaid(text, options);
|
|
183792
|
+
return { svg: result.svg };
|
|
183793
|
+
} catch (error2) {
|
|
183794
|
+
throw new Error(`Maid render failed: ${error2.message || "Unknown error"}`);
|
|
183795
|
+
}
|
|
183796
|
+
}
|
|
183797
|
+
};
|
|
183798
|
+
}
|
|
183799
|
+
var maid;
|
|
183800
|
+
var init_mermaid_compat = __esm({
|
|
183801
|
+
"node_modules/@probelabs/maid/out/mermaid-compat.js"() {
|
|
183802
|
+
init_renderer();
|
|
183803
|
+
maid = createMermaidAPI();
|
|
180000
183804
|
}
|
|
180001
183805
|
});
|
|
180002
183806
|
|
|
@@ -180030,6 +183834,7 @@ var init_out = __esm({
|
|
|
180030
183834
|
init_edits();
|
|
180031
183835
|
init_fixes();
|
|
180032
183836
|
init_renderer();
|
|
183837
|
+
init_mermaid_compat();
|
|
180033
183838
|
init_router();
|
|
180034
183839
|
init_fixes();
|
|
180035
183840
|
init_edits();
|
|
@@ -180745,8 +184550,8 @@ When presented with a broken Mermaid diagram, analyze it thoroughly and provide
|
|
|
180745
184550
|
debug: this.options.debug,
|
|
180746
184551
|
tracer: this.options.tracer,
|
|
180747
184552
|
allowEdit: this.options.allowEdit,
|
|
180748
|
-
maxIterations:
|
|
180749
|
-
//
|
|
184553
|
+
maxIterations: 10,
|
|
184554
|
+
// Allow more iterations for mermaid fixing to handle complex diagrams
|
|
180750
184555
|
disableMermaidValidation: true
|
|
180751
184556
|
// CRITICAL: Disable mermaid validation in nested agent to prevent infinite recursion
|
|
180752
184557
|
});
|
|
@@ -181646,6 +185451,18 @@ var init_ProbeAgent = __esm({
|
|
|
181646
185451
|
this.toolImplementations.bash = wrappedTools.bashToolInstance;
|
|
181647
185452
|
}
|
|
181648
185453
|
this.wrappedTools = wrappedTools;
|
|
185454
|
+
if (this.debug) {
|
|
185455
|
+
console.error("\n[DEBUG] ========================================");
|
|
185456
|
+
console.error("[DEBUG] ProbeAgent Tools Initialized");
|
|
185457
|
+
console.error("[DEBUG] Session ID:", this.sessionId);
|
|
185458
|
+
console.error("[DEBUG] Available tools:");
|
|
185459
|
+
for (const toolName of Object.keys(this.toolImplementations)) {
|
|
185460
|
+
console.error(`[DEBUG] - ${toolName}`);
|
|
185461
|
+
}
|
|
185462
|
+
console.error("[DEBUG] Allowed folders:", this.allowedFolders);
|
|
185463
|
+
console.error("[DEBUG] Outline mode:", this.outline);
|
|
185464
|
+
console.error("[DEBUG] ========================================\n");
|
|
185465
|
+
}
|
|
181649
185466
|
}
|
|
181650
185467
|
/**
|
|
181651
185468
|
* Initialize the AI model based on available API keys and forced provider setting
|
|
@@ -182416,12 +186233,28 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
182416
186233
|
const { type } = parsedTool;
|
|
182417
186234
|
if (type === "mcp" && this.mcpBridge && this.mcpBridge.isMcpTool(toolName)) {
|
|
182418
186235
|
try {
|
|
182419
|
-
if (this.debug)
|
|
186236
|
+
if (this.debug) {
|
|
186237
|
+
console.error(`
|
|
186238
|
+
[DEBUG] ========================================`);
|
|
186239
|
+
console.error(`[DEBUG] Executing MCP tool: ${toolName}`);
|
|
186240
|
+
console.error(`[DEBUG] Arguments:`);
|
|
186241
|
+
for (const [key, value] of Object.entries(params)) {
|
|
186242
|
+
const displayValue = typeof value === "string" && value.length > 100 ? value.substring(0, 100) + "..." : value;
|
|
186243
|
+
console.error(`[DEBUG] ${key}: ${JSON.stringify(displayValue)}`);
|
|
186244
|
+
}
|
|
186245
|
+
console.error(`[DEBUG] ========================================
|
|
186246
|
+
`);
|
|
186247
|
+
}
|
|
182420
186248
|
const executionResult = await this.mcpBridge.mcpTools[toolName].execute(params);
|
|
182421
186249
|
const toolResultContent = typeof executionResult === "string" ? executionResult : JSON.stringify(executionResult, null, 2);
|
|
182422
|
-
const preview = createMessagePreview(toolResultContent);
|
|
182423
186250
|
if (this.debug) {
|
|
182424
|
-
|
|
186251
|
+
const preview = toolResultContent.length > 500 ? toolResultContent.substring(0, 500) + "..." : toolResultContent;
|
|
186252
|
+
console.error(`[DEBUG] ========================================`);
|
|
186253
|
+
console.error(`[DEBUG] MCP tool '${toolName}' completed successfully`);
|
|
186254
|
+
console.error(`[DEBUG] Result preview:`);
|
|
186255
|
+
console.error(preview);
|
|
186256
|
+
console.error(`[DEBUG] ========================================
|
|
186257
|
+
`);
|
|
182425
186258
|
}
|
|
182426
186259
|
currentMessages.push({ role: "user", content: `<tool_result>
|
|
182427
186260
|
${toolResultContent}
|
|
@@ -182429,7 +186262,13 @@ ${toolResultContent}
|
|
|
182429
186262
|
} catch (error2) {
|
|
182430
186263
|
console.error(`Error executing MCP tool ${toolName}:`, error2);
|
|
182431
186264
|
const toolResultContent = `Error executing MCP tool ${toolName}: ${error2.message}`;
|
|
182432
|
-
if (this.debug)
|
|
186265
|
+
if (this.debug) {
|
|
186266
|
+
console.error(`[DEBUG] ========================================`);
|
|
186267
|
+
console.error(`[DEBUG] MCP tool '${toolName}' failed with error:`);
|
|
186268
|
+
console.error(`[DEBUG] ${error2.message}`);
|
|
186269
|
+
console.error(`[DEBUG] ========================================
|
|
186270
|
+
`);
|
|
186271
|
+
}
|
|
182433
186272
|
currentMessages.push({ role: "user", content: `<tool_result>
|
|
182434
186273
|
${toolResultContent}
|
|
182435
186274
|
</tool_result>` });
|
|
@@ -182441,6 +186280,18 @@ ${toolResultContent}
|
|
|
182441
186280
|
sessionId: this.sessionId,
|
|
182442
186281
|
workingDirectory: this.allowedFolders && this.allowedFolders[0] || process.cwd()
|
|
182443
186282
|
};
|
|
186283
|
+
if (this.debug) {
|
|
186284
|
+
console.error(`
|
|
186285
|
+
[DEBUG] ========================================`);
|
|
186286
|
+
console.error(`[DEBUG] Executing tool: ${toolName}`);
|
|
186287
|
+
console.error(`[DEBUG] Arguments:`);
|
|
186288
|
+
for (const [key, value] of Object.entries(params)) {
|
|
186289
|
+
const displayValue = typeof value === "string" && value.length > 100 ? value.substring(0, 100) + "..." : value;
|
|
186290
|
+
console.error(`[DEBUG] ${key}: ${JSON.stringify(displayValue)}`);
|
|
186291
|
+
}
|
|
186292
|
+
console.error(`[DEBUG] ========================================
|
|
186293
|
+
`);
|
|
186294
|
+
}
|
|
182444
186295
|
this.events.emit("toolCall", {
|
|
182445
186296
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
182446
186297
|
name: toolName,
|
|
@@ -182482,6 +186333,15 @@ ${toolResultContent}
|
|
|
182482
186333
|
} else {
|
|
182483
186334
|
toolResult = await executeToolCall();
|
|
182484
186335
|
}
|
|
186336
|
+
if (this.debug) {
|
|
186337
|
+
const resultPreview = typeof toolResult === "string" ? toolResult.length > 500 ? toolResult.substring(0, 500) + "..." : toolResult : toolResult ? JSON.stringify(toolResult, null, 2).substring(0, 500) + "..." : "No Result";
|
|
186338
|
+
console.error(`[DEBUG] ========================================`);
|
|
186339
|
+
console.error(`[DEBUG] Tool '${toolName}' completed successfully`);
|
|
186340
|
+
console.error(`[DEBUG] Result preview:`);
|
|
186341
|
+
console.error(resultPreview);
|
|
186342
|
+
console.error(`[DEBUG] ========================================
|
|
186343
|
+
`);
|
|
186344
|
+
}
|
|
182485
186345
|
this.events.emit("toolCall", {
|
|
182486
186346
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
182487
186347
|
name: toolName,
|
|
@@ -182490,6 +186350,13 @@ ${toolResultContent}
|
|
|
182490
186350
|
status: "completed"
|
|
182491
186351
|
});
|
|
182492
186352
|
} catch (toolError) {
|
|
186353
|
+
if (this.debug) {
|
|
186354
|
+
console.error(`[DEBUG] ========================================`);
|
|
186355
|
+
console.error(`[DEBUG] Tool '${toolName}' failed with error:`);
|
|
186356
|
+
console.error(`[DEBUG] ${toolError.message}`);
|
|
186357
|
+
console.error(`[DEBUG] ========================================
|
|
186358
|
+
`);
|
|
186359
|
+
}
|
|
182493
186360
|
this.events.emit("toolCall", {
|
|
182494
186361
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
182495
186362
|
name: toolName,
|
|
@@ -182539,6 +186406,16 @@ Error: Unknown tool '${toolName}'. Available tools: ${allAvailableTools.join(",
|
|
|
182539
186406
|
}
|
|
182540
186407
|
}
|
|
182541
186408
|
} else {
|
|
186409
|
+
const hasMermaidCodeBlock = /```mermaid\s*\n[\s\S]*?\n```/.test(assistantResponseContent);
|
|
186410
|
+
const hasNoSchemaOrTools = !options.schema && validTools.length === 0;
|
|
186411
|
+
if (hasMermaidCodeBlock && hasNoSchemaOrTools) {
|
|
186412
|
+
finalResult = assistantResponseContent;
|
|
186413
|
+
completionAttempted = true;
|
|
186414
|
+
if (this.debug) {
|
|
186415
|
+
console.error(`[DEBUG] Accepting mermaid code block as valid completion (no schema, no tools)`);
|
|
186416
|
+
}
|
|
186417
|
+
break;
|
|
186418
|
+
}
|
|
182542
186419
|
currentMessages.push({ role: "assistant", content: assistantResponseContent });
|
|
182543
186420
|
let reminderContent;
|
|
182544
186421
|
if (options.schema) {
|
|
@@ -183252,12 +187129,14 @@ __export(index_exports, {
|
|
|
183252
187129
|
getBinaryPath: () => getBinaryPath,
|
|
183253
187130
|
initializeSimpleTelemetryFromOptions: () => initializeSimpleTelemetryFromOptions,
|
|
183254
187131
|
listFilesByLevel: () => listFilesByLevel,
|
|
187132
|
+
listFilesToolInstance: () => listFilesToolInstance,
|
|
183255
187133
|
parseXmlToolCall: () => parseXmlToolCall,
|
|
183256
187134
|
query: () => query,
|
|
183257
187135
|
querySchema: () => querySchema,
|
|
183258
187136
|
queryTool: () => queryTool,
|
|
183259
187137
|
queryToolDefinition: () => queryToolDefinition,
|
|
183260
187138
|
search: () => search,
|
|
187139
|
+
searchFilesToolInstance: () => searchFilesToolInstance,
|
|
183261
187140
|
searchSchema: () => searchSchema,
|
|
183262
187141
|
searchTool: () => searchTool,
|
|
183263
187142
|
searchToolDefinition: () => searchToolDefinition,
|
|
@@ -183280,6 +187159,7 @@ var init_index = __esm({
|
|
|
183280
187159
|
init_bash();
|
|
183281
187160
|
init_ProbeAgent();
|
|
183282
187161
|
init_simpleTelemetry();
|
|
187162
|
+
init_probeTool();
|
|
183283
187163
|
}
|
|
183284
187164
|
});
|
|
183285
187165
|
init_index();
|
|
@@ -213361,7 +217241,7 @@ module.exports = /*#__PURE__*/JSON.parse('{"application/1d-interleaved-parityfec
|
|
|
213361
217241
|
/***/ ((module) => {
|
|
213362
217242
|
|
|
213363
217243
|
"use strict";
|
|
213364
|
-
module.exports = {"rE":"0.1.
|
|
217244
|
+
module.exports = {"rE":"0.1.73"};
|
|
213365
217245
|
|
|
213366
217246
|
/***/ })
|
|
213367
217247
|
|