mindnet_obsidian/src/mapping/updateMappingBlocks.ts

159 lines
5.3 KiB
TypeScript
Raw Normal View History

/**
* Update mapping blocks for specific links without prompting for all links.
* Used when user changes specific links (single-link, selection-links, create-link).
*/
import { App, TFile } from "obsidian";
import type { MindnetSettings } from "../settings";
import { splitIntoSections, type NoteSection } from "./sectionParser";
import { parseEdgesFromCallouts } from "../parser/parseEdgesFromCallouts";
import {
extractExistingMappings,
removeWrapperBlock,
type SectionMappingState,
} from "./mappingExtractor";
import {
buildMappingBlock,
insertMappingBlock,
type MappingBuilderOptions,
} from "./mappingBuilder";
import { convertRelLinksToEdges } from "../parser/parseRelLinks";
/**
* Update mapping blocks for sections containing rel: links, without prompting.
* Only processes links that are already in [[rel:type|link]] format.
*/
export async function updateMappingBlocksForRelLinks(
app: App,
file: TFile,
settings: MindnetSettings
): Promise<void> {
let content = await app.vault.read(file);
const lines = content.split(/\r?\n/);
// Convert [[rel:type|link]] links to normal [[link]] and extract edge mappings
const { convertedContent, edgeMappings: relLinkMappings } = convertRelLinksToEdges(content);
content = convertedContent;
if (relLinkMappings.size === 0) {
// No rel: links to process
return;
}
console.log(`[UpdateMappingBlocks] Converting ${relLinkMappings.size} rel: links to edge mappings`);
// Split into sections
const sections = splitIntoSections(content);
// Process sections in reverse order (to preserve line indices when modifying)
const modifiedSections: Array<{ section: NoteSection; newContent: string }> = [];
for (const section of sections) {
if (section.links.length === 0) {
// No links, skip
modifiedSections.push({
section,
newContent: section.content,
});
continue;
}
// Extract existing mappings
const mappingState = extractExistingMappings(
section.content,
settings.mappingWrapperCalloutType,
settings.mappingWrapperTitle
);
// Merge rel: link mappings (from [[rel:type|link]] format) into existing mappings
// These take precedence over file content mappings (update even if already mapped)
for (const [linkBasename, edgeType] of relLinkMappings.entries()) {
// Check if this link exists in this section
const normalizedBasename = linkBasename.split("|")[0]?.split("#")[0]?.trim() || linkBasename;
if (section.links.some(link => {
const normalizedLink = link.split("|")[0]?.split("#")[0]?.trim() || link;
return normalizedLink === normalizedBasename || link === normalizedBasename;
})) {
// Always update rel: link mappings (they represent user's explicit choice)
mappingState.existingMappings.set(normalizedBasename, edgeType);
console.log(`[UpdateMappingBlocks] Updated rel: link mapping: ${normalizedBasename} -> ${edgeType}`);
}
}
// Remove wrapper block if exists
let sectionContentWithoutWrapper = section.content;
if (mappingState.wrapperBlockStartLine !== null && mappingState.wrapperBlockEndLine !== null) {
sectionContentWithoutWrapper = removeWrapperBlock(
section.content,
mappingState.wrapperBlockStartLine,
mappingState.wrapperBlockEndLine
);
}
// Build mapping block with updated mappings
const mappingOptions: MappingBuilderOptions = {
wrapperCalloutType: settings.mappingWrapperCalloutType,
wrapperTitle: settings.mappingWrapperTitle,
wrapperFolded: settings.mappingWrapperFolded,
defaultEdgeType: settings.defaultEdgeType,
assignUnmapped: "none", // Don't assign unmapped links, just use existing mappings
};
const mappingBlock = buildMappingBlock(
section.links,
mappingState.existingMappings,
mappingOptions
);
if (mappingBlock) {
const newContent = insertMappingBlock(sectionContentWithoutWrapper, mappingBlock);
modifiedSections.push({
section,
newContent,
});
} else {
// No mapping block needed
modifiedSections.push({
section,
newContent: sectionContentWithoutWrapper,
});
}
}
// Reconstruct file content with modified sections
let newContent = "";
let currentLine = 0;
for (let i = 0; i < modifiedSections.length; i++) {
const { section, newContent: sectionNewContent } = modifiedSections[i]!;
// Add lines before this section
if (currentLine < section.startLine) {
newContent += lines.slice(currentLine, section.startLine).join("\n");
if (currentLine < section.startLine) {
newContent += "\n";
}
}
// Add modified section content
newContent += sectionNewContent;
currentLine = section.endLine;
// Add newline between sections (except for last section)
if (i < modifiedSections.length - 1) {
newContent += "\n";
}
}
// Add remaining lines after last section
if (currentLine < lines.length) {
newContent += "\n" + lines.slice(currentLine).join("\n");
}
// Write back to file
await app.vault.modify(file, newContent);
console.log(`[UpdateMappingBlocks] Updated mapping blocks for ${modifiedSections.length} sections`);
}