mirror of
https://github.com/jacobinwwey/obsidian-NotEMD.git
synced 2026-07-22 05:48:27 +00:00
1.6.0 mermaid fix a lot
This commit is contained in:
parent
3e2890b9bb
commit
4a095d8cde
5 changed files with 267 additions and 3 deletions
|
|
@ -121,6 +121,10 @@ That's it! Explore the settings to unlock more features like web research, trans
|
|||
- **Comment Integration**: Automatically merges trailing comments (starting with `%`) into the edge label (e.g., `A -- Label --> B; % Comment` becomes `A -- "Label(Comment)" --> B;`).
|
||||
- **Malformed Arrows**: Fixes arrows absorbed into quotes (e.g., `A -- "Label -->" B` becomes `A -- "Label" --> B`).
|
||||
- **Inline Subgraphs**: Converts inline subgraph labels to edge labels.
|
||||
- **Reverse Arrow Fix**: Corrects non-standard `X <-- Y` arrows to `Y --> X`.
|
||||
- **Direction Keyword Fix**: Ensures `direction` keyword is lowercase inside subgraphs (e.g., `Direction TB` -> `direction TB`).
|
||||
- **Comment Conversion**: Converts `//` comments into edge labels (e.g., `A --> B; // Comment` -> `A -- "Comment" --> B;`).
|
||||
- **Duplicate Label Fix**: Simplifies repeated bracketed labels (e.g., `Node["Label"]["Label"]` -> `Node["Label"]`).
|
||||
- **Advanced Fix Mode**: Includes robust fixes for unquoted node labels containing spaces, special characters, or nested brackets (e.g., `Node[Label [Text]]` -> `Node["Label [Text]"]`), ensuring compatibility with complex diagrams like Stellar Evolution paths. Also corrects malformed edge labels (e.g., `--["Label["-->` to `-- "Label" -->`). Additionally converts inline comments (`Consensus --> Adaptive; # Some advanced consensus` to `Consensus -- "Some advanced consensus" --> Adaptive`) and fixes incomplete quotes at line ends (`;"` at the end replaced with `"]`).
|
||||
- **Note Conversion**: Automatically converts `note right/left of` comments into standard Mermaid edge labels (e.g., `note right of A: text` becomes `A -- "text" --> B`), improving graph layout and readability. Now supports both arrow links (`-->`) and solid links (`---`).
|
||||
- **Standardize Pipe Labels**: Automatically fixes and standardizes edge labels containing pipes, ensuring they are properly quoted (e.g., `-->|Text|` becomes `-->|"Text"|` and `-->|Math|^2|` becomes `-->|"Math|^2"|`).
|
||||
|
|
|
|||
|
|
@ -119,6 +119,10 @@ Notemd 通过与各种大型语言模型 (LLM) 集成来增强您的 Obsidian
|
|||
- **注释集成**: 自动将尾随注释(以 `%` 开头)合并到连接线标签中(例如,`A -- Label --> B; % Comment` 变为 `A -- "Label(Comment)" --> B;`)。
|
||||
- **畸形箭头**: 修复被引号吸收的箭头(例如 `A -- "Label -->" B` 修正为 `A -- "Label" --> B`)。
|
||||
- **行内子图**: 将行内子图标签转换为连接线标签。
|
||||
- **反向箭头修复**: 将非标准的 `X <-- Y` 箭头修正为 `Y --> X`。
|
||||
- **方向关键字修复**: 确保子图内的 `direction` 关键字为小写(例如 `Direction TB` -> `direction TB`)。
|
||||
- **注释转换**: 将 `//` 注释转换为连接线标签(例如 `A --> B; // 注释` -> `A -- "注释" --> B;`)。
|
||||
- **重复标签修复**: 简化重复的括号标签(例如 `Node["标签"]["标签"]` -> `Node["标签"]`)。
|
||||
- **高级修复模式**: 包含针对包含空格、特殊字符或嵌套括号的未加引号节点标签的稳健修复(例如,将 `Node[标签 [文本]]` 转换为 `Node["标签 [文本]"]`)。
|
||||
- **注释转换**: 自动将 `note right/left of` 样式的注释转换为标准的 Mermaid 连接线标签(例如,将 `note right of A: text` 转换为 `A -- "text" --> B`),从而改善图表布局和可读性。现在支持箭头连接(`-->`)和实线连接(`---`)。
|
||||
- **标准化管道标签**: 自动修复和标准化包含管道符的连接线标签,确保它们被正确引用(例如,将 `-->|文本|` 转换为 `-->|"文本"|`)。
|
||||
|
|
|
|||
|
|
@ -313,6 +313,9 @@ export function deepDebugMermaid(content: string): string {
|
|||
// 7. Fix Mermaid Comments (Move % comments to label)
|
||||
processed = fixMermaidComments(processed);
|
||||
|
||||
// 17. Fix Double Slash Comments (// -> -- "..." -->) - Apply before general label fixes
|
||||
processed = fixDoubleSlashComments(processed);
|
||||
|
||||
// 8. Fix Unquoted Node Labels (Quote labels with special chars)
|
||||
processed = fixUnquotedNodeLabels(processed);
|
||||
|
||||
|
|
@ -334,6 +337,15 @@ export function deepDebugMermaid(content: string): string {
|
|||
// 14. Enhanced Note Pattern and Semicolon Content Removal
|
||||
processed = enhancedNoteAndSemicolonCleanup(processed);
|
||||
|
||||
// 15. Fix Reverse Arrows (<--)
|
||||
processed = fixReverseArrows(processed);
|
||||
|
||||
// 16. Fix Subgraph Direction (Direction -> direction)
|
||||
processed = fixSubgraphDirection(processed);
|
||||
|
||||
// 18. Fix Duplicate Labels (["..."]["..."] -> ["..."])
|
||||
processed = fixDuplicateLabels(processed);
|
||||
|
||||
return processed;
|
||||
}
|
||||
|
||||
|
|
@ -1032,3 +1044,140 @@ export function fixSmartQuotes(content: string): string {
|
|||
|
||||
return processed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes reverse arrows `A <-- B` to `B --> A`.
|
||||
* Supports optional brackets/quotes on nodes.
|
||||
* Example: `ExSitu["Ex-situ..."] <-- Sample;` -> `Sample --> ExSitu["Ex-situ..."];`
|
||||
*/
|
||||
export function fixReverseArrows(content: string): string {
|
||||
const lines = content.split('\n');
|
||||
const processedLines = lines.map(line => {
|
||||
if (!line.includes('<--')) return line;
|
||||
|
||||
// Regex to capture:
|
||||
// Group 1: Left Node (lazy)
|
||||
// Group 2: <-- (literal)
|
||||
// Group 3: Right Node (lazy)
|
||||
// Group 4: Optional Semicolon
|
||||
const regex = /^(.*?)\s*<--\s*(.*?)(;?)\s*$/;
|
||||
const match = line.match(regex);
|
||||
|
||||
if (match) {
|
||||
const leftNode = match[1].trim();
|
||||
const rightNode = match[2].trim();
|
||||
const semicolon = match[3] || '';
|
||||
|
||||
return `${rightNode} --> ${leftNode}${semicolon}`;
|
||||
}
|
||||
return line;
|
||||
});
|
||||
return processedLines.join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes `Direction` keyword case in subgraphs.
|
||||
* Mermaid is case-sensitive inside subgraphs: `Direction TB` -> `direction TB`.
|
||||
*/
|
||||
export function fixSubgraphDirection(content: string): string {
|
||||
const lines = content.split('\n');
|
||||
let insideSubgraph = false;
|
||||
const processedLines = lines.map(line => {
|
||||
if (line.trim().startsWith('subgraph')) {
|
||||
insideSubgraph = true;
|
||||
} else if (line.trim() === 'end') {
|
||||
insideSubgraph = false;
|
||||
}
|
||||
|
||||
if (insideSubgraph) {
|
||||
// Replace `Direction` with `direction` if followed by TB, BT, LR, RL, TD
|
||||
return line.replace(/^\s*Direction\s+(TB|BT|LR|RL|TD)\b/g, (match) => {
|
||||
return match.replace('Direction', 'direction');
|
||||
});
|
||||
}
|
||||
return line;
|
||||
});
|
||||
return processedLines.join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes comments designated by `//` on arrow lines, converting them to edge labels.
|
||||
* Example: `Thermal --> Optical; // Thermo-optic effect`
|
||||
* Become: `Thermal -- "Thermo-optic effect" --> Optical;`
|
||||
*/
|
||||
export function fixDoubleSlashComments(content: string): string {
|
||||
const lines = content.split('\n');
|
||||
const processedLines = lines.map(line => {
|
||||
if (!line.includes('//') || !line.includes('-->')) return line;
|
||||
|
||||
// Regex to find arrow relation followed by // comment
|
||||
// Handle optional semicolon before //
|
||||
// Group 1: Pre-arrow part
|
||||
// Group 2: Arrow (-->)
|
||||
// Group 3: Post-arrow part (target node)
|
||||
// Group 4: Semicolon (optional)
|
||||
// Group 5: Comment text
|
||||
|
||||
// This regex assumes standard `-->` arrow.
|
||||
// We match `//` specifically.
|
||||
|
||||
const regex = /^(.*?)(\s*-->\s*)(.*?)(;?)\s*\/\/\s*(.*)$/;
|
||||
const match = line.match(regex);
|
||||
|
||||
if (match) {
|
||||
const preArrow = match[1]; // "Thermal"
|
||||
const arrow = match[2]; // " --> "
|
||||
const target = match[3].trim(); // "Optical"
|
||||
const semicolon = match[4]; // ";"
|
||||
const comment = match[5].trim(); // "Thermo-optic effect"
|
||||
|
||||
if (comment) {
|
||||
// Construct: Pre -- "Comment" --> Target;
|
||||
// Note: arrow variable contains " --> ". We change it to " -- "Comment" --> "
|
||||
const newArrow = ` -- "${comment}" --> `;
|
||||
return `${preArrow}${newArrow}${target}${semicolon}`;
|
||||
}
|
||||
}
|
||||
return line;
|
||||
});
|
||||
return processedLines.join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes duplicated bracketed labels.
|
||||
* Example: `Node["Label"]["Label"]` -> `Node["Label"]`
|
||||
* Retains only the last occurrence if they differ, or just collapses them.
|
||||
* The prompt says: "only the final occurrence shall be retained".
|
||||
*/
|
||||
export function fixDuplicateLabels(content: string): string {
|
||||
const lines = content.split('\n');
|
||||
const processedLines = lines.map(line => {
|
||||
// Regex to match consecutive quoted brackets: ["..."]["..."]...
|
||||
// We want to replace the whole sequence with just the last ["..."]
|
||||
|
||||
// Strategy: Find a sequence of 2 or more `["..."]` blocks (allowing optional whitespace)
|
||||
// Replace with the last block.
|
||||
|
||||
// Regex for one block: \[\"[^"]*\"\]
|
||||
const blockRegex = /\["[^"]*"\]/g;
|
||||
|
||||
// We iterate line by line.
|
||||
// If line has multiple blocks adjacent, we check them.
|
||||
|
||||
// Harder to do with single regex replace because of "last occurrence".
|
||||
// Example: `A["1"]["2"]["3"]` -> `A["3"]`
|
||||
|
||||
// Regex: ((\[\"[^"]*\"\]\s*)+)
|
||||
// This captures the whole chain.
|
||||
|
||||
return line.replace(/((?:\["[^"]*"\]\s*){2,})/g, (match) => {
|
||||
// Split match into blocks
|
||||
const blocks = match.match(/\["[^"]*"\]/g);
|
||||
if (blocks && blocks.length > 0) {
|
||||
return blocks[blocks.length - 1];
|
||||
}
|
||||
return match;
|
||||
});
|
||||
});
|
||||
return processedLines.join('\n');
|
||||
}
|
||||
|
|
|
|||
56
src/test.ts
56
src/test.ts
|
|
@ -38,4 +38,58 @@ const input2 = `graph TD
|
|||
Start[Activated Solid Sample] --> SplitSplit Sample for Multiple Tests`;
|
||||
const result2 = deepDebugMermaid(input2);
|
||||
console.log("\nInput 2 Result:\n", result2);
|
||||
console.log("Test 2 Passed:", result2.trim().includes("Start[Activated Solid Sample] --> Split[Split Sample for Multiple Tests]"));
|
||||
console.log("Test 2 Passed:", result2.trim().includes("Start[Activated Solid Sample] --> Split[Split Sample for Multiple Tests]"));
|
||||
|
||||
console.log("\n--- New Tests ---");
|
||||
|
||||
const input3 = `graph TD
|
||||
subgraph "Experimental Setup: Aging at Constant Pressure"
|
||||
PressureSource["Pressure Source Pump/Intensifier"] --> PressureControl["Pressure Controller Regulator/Feedback Loop"];
|
||||
PressureControl --> PressureVessel["High-Pressure Vessel/Chamber"];
|
||||
PressureSensor["Pressure Sensor"] --> PressureControl;
|
||||
|
||||
TempSource["Heating/Cooling System"] --> TempControl["Temperature Controller PID"];
|
||||
TempControl --> PressureVessel;
|
||||
TempSensor["Temperature Sensor"] --> TempControl;
|
||||
|
||||
Sample["Material Sample"] -- Placed Inside --> PressureVessel;
|
||||
Sample -- Interaction --> Environment["Controlled Atmosphere/Fluid"];
|
||||
|
||||
subgraph "Data Acquisition & Monitoring"
|
||||
InSitu["In-situ Measurements Optional, e.g., Strain Gauge, AE Sensor"] -- Attached To/Observing --> Sample;
|
||||
InSitu --> DAQ["Data Acquisition System"];
|
||||
PressureSensor --> DAQ;
|
||||
TempSensor --> DAQ;
|
||||
ExSitu["Ex-situ Characterization Post-test or Interrupted"] <-- Sample;
|
||||
end
|
||||
|
||||
DAQ --> Analysis["Data Analysis & Modeling"];
|
||||
ExSitu --> Analysis;
|
||||
end
|
||||
|
||||
style PressureVessel fill:#f9f,stroke:#333,stroke-width:2px`;
|
||||
|
||||
const result3 = deepDebugMermaid(input3);
|
||||
console.log("\nInput 3 Result (Reverse Arrow):\n", result3);
|
||||
const expected3 = `Sample --> ExSitu["Ex-situ Characterization Post-test or Interrupted"];`;
|
||||
console.log("Test 3 Passed:", result3.includes(expected3));
|
||||
|
||||
const input4 = `Thermal --> Optical; // Thermo-optic effect`;
|
||||
const result4 = deepDebugMermaid(input4);
|
||||
console.log("\nInput 4 Result (Comments):\n", result4);
|
||||
const expected4 = `Thermal -- "Thermo-optic effect" --> Optical;`;
|
||||
console.log("Test 4 Passed:", result4.includes(expected4));
|
||||
|
||||
const input5 = `subgraph test
|
||||
Direction TB
|
||||
end`;
|
||||
const result5 = deepDebugMermaid(input5);
|
||||
console.log("\nInput 5 Result (Direction):\n", result5);
|
||||
const expected5 = `direction TB`;
|
||||
console.log("Test 5 Passed:", result5.includes(expected5));
|
||||
|
||||
const input6 = `D --> E["Label"]["Label"]["Label"];`;
|
||||
const result6 = deepDebugMermaid(input6);
|
||||
console.log("\nInput 6 Result (Duplicate Labels):\n", result6);
|
||||
const expected6 = `D --> E["Label"];`;
|
||||
console.log("Test 6 Passed:", result6.includes(expected6));
|
||||
|
|
|
|||
|
|
@ -1,7 +1,60 @@
|
|||
import { deepDebugMermaid } from '../mermaidProcessor';
|
||||
|
||||
describe('Deep Debug Mermaid Tests', () => {
|
||||
describe('deepDebugMermaid', () => {
|
||||
test('User Example 1: Reverse Arrows', () => {
|
||||
const input = `graph TD
|
||||
subgraph "Experimental Setup: Aging at Constant Pressure"
|
||||
PressureSource["Pressure Source Pump/Intensifier"] --> PressureControl["Pressure Controller Regulator/Feedback Loop"];
|
||||
PressureControl --> PressureVessel["High-Pressure Vessel/Chamber"];
|
||||
PressureSensor["Pressure Sensor"] --> PressureControl;
|
||||
|
||||
TempSource["Heating/Cooling System"] --> TempControl["Temperature Controller PID"];
|
||||
TempControl --> PressureVessel;
|
||||
TempSensor["Temperature Sensor"] --> TempControl;
|
||||
|
||||
Sample["Material Sample"] -- Placed Inside --> PressureVessel;
|
||||
Sample -- Interaction --> Environment["Controlled Atmosphere/Fluid"];
|
||||
|
||||
subgraph "Data Acquisition & Monitoring"
|
||||
InSitu["In-situ Measurements Optional, e.g., Strain Gauge, AE Sensor"] -- Attached To/Observing --> Sample;
|
||||
InSitu --> DAQ["Data Acquisition System"];
|
||||
PressureSensor --> DAQ;
|
||||
TempSensor --> DAQ;
|
||||
ExSitu["Ex-situ Characterization Post-test or Interrupted"] <-- Sample;
|
||||
end
|
||||
|
||||
DAQ --> Analysis["Data Analysis & Modeling"];
|
||||
ExSitu --> Analysis;
|
||||
end
|
||||
|
||||
style PressureVessel fill:#f9f,stroke:#333,stroke-width:2px`;
|
||||
|
||||
const result = deepDebugMermaid(input);
|
||||
const expectedFragment = `Sample --> ExSitu["Ex-situ Characterization Post-test or Interrupted"];`;
|
||||
expect(result).toContain(expectedFragment);
|
||||
});
|
||||
|
||||
test('User Example 2: Comments //', () => {
|
||||
const input = `Thermal --> Optical; // Thermo-optic effect`;
|
||||
const result = deepDebugMermaid(input);
|
||||
const expected = `Thermal -- "Thermo-optic effect" --> Optical;`;
|
||||
expect(result).toContain(expected);
|
||||
});
|
||||
|
||||
test('User Example 3: Subgraph Direction', () => {
|
||||
const input = `subgraph test
|
||||
Direction TB
|
||||
end`;
|
||||
const result = deepDebugMermaid(input);
|
||||
expect(result).toContain(`direction TB`);
|
||||
});
|
||||
|
||||
test('User Example 4: Duplicate Labels', () => {
|
||||
const input = `D --> E["Label"]["Label"]["Label"];`;
|
||||
const result = deepDebugMermaid(input);
|
||||
expect(result).toContain(`D --> E["Label"];`);
|
||||
expect(result).not.toContain(`E["Label"]["Label"]`);
|
||||
});
|
||||
test('should add brackets to nodes missing them after arrow', () => {
|
||||
const content = `\
|
||||
\
|
||||
|
|
@ -500,4 +553,4 @@ style Strehl_Ratio fill:#fcc,stroke:#333`;
|
|||
|
||||
expect(deepDebugMermaid(content).trim()).toBe(expected.trim());
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Reference in a new issue