Skip to content

Commit

Permalink
feat: configurable conversion options
Browse files Browse the repository at this point in the history
  • Loading branch information
davidenke committed Oct 23, 2024
1 parent db22a4a commit fe195df
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 12 deletions.
7 changes: 6 additions & 1 deletion src/components/root/root.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,12 @@ export class Root extends LitElement {
async loadFile({ detail: path }: CustomEvent<string>) {
const remove = await readAndWatchFile(path, async data => {
const workbook = await readMindMap(data);
this.contents = await parse(convertToMarkdown(workbook));
this.contents = await parse(
convertToMarkdown(workbook, {
useHeadlinesUntilLevel: 2,
useListsUntilLevel: Infinity,
}),
);
});
this.#listeners.push(remove);

Expand Down
68 changes: 57 additions & 11 deletions src/utils/conversion.utils.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,66 @@
import type { Sheet, Topic, Workbook } from 'xmind-model';

export type ConversionOptions = {
/**
* Topics until this level will be rendered as headlines.
* Minimum value is 1, default is 2, maximum value is 6.
* @default 2
*/
useHeadlinesUntilLevel: 1 | 2 | 3 | 4 | 5 | 6;

/**
* Topics until this level will be rendered as lists.
* Minimum value is the value of `useHeadlinesUntilLevel`, default is 4 if higher.
* No maximum value.
*
* @default 4 if higher than `useHeadlinesUntilLevel`
*
* Unused right now, as no explicit rendering beyond lists is implemented.
*/
useListsUntilLevel: number;
};

export function conversionOptionsWithDefaults(options: Partial<ConversionOptions> = {}): ConversionOptions {
return {
useHeadlinesUntilLevel: 2,
useListsUntilLevel: Math.max(4, options.useHeadlinesUntilLevel ?? 2),
...options,
};
}

/**
* Convert a given set of sheets into markdown
*/
export function convertToMarkdown(workbook: Workbook): string {
return workbook.getSheets().map(convertSheetToMarkdown).join('\n\n');
export function convertToMarkdown(workbook: Workbook, options?: ConversionOptions): string {
options = conversionOptionsWithDefaults(options);
return workbook
.getSheets()
.map(sheet => convertSheetToMarkdown(sheet, options))
.join('\n\n');
}

/**
* Convert a single given sheet into markdown
*/
export function convertSheetToMarkdown(sheet: Sheet): string {
return convertTopicToMarkdown(sheet.getRootTopic(), 1);
export function convertSheetToMarkdown(sheet: Sheet, options: ConversionOptions): string {
return convertTopicToMarkdown(sheet.getRootTopic(), 1, options);
}

/**
* Convert a single given topic into markdown.
*/
export function convertTopicToMarkdown(topic: Topic, level = 1): string {
export function convertTopicToMarkdown(topic: Topic, level: number, options: ConversionOptions): string {
const { useHeadlinesUntilLevel, useListsUntilLevel } = options;
const title = topic.getTitle();
const text = level > 2 ? renderListItem(title, level - 2) : renderHeadline(title, level);
const text =
level > useHeadlinesUntilLevel
? level > useListsUntilLevel
? renderText(title, level - useListsUntilLevel)
: renderListItem(title, level - useHeadlinesUntilLevel)
: renderHeadline(title, level);
const attachedTopics = topic
.getChildrenByType(['attached'])
.map(child => convertTopicToMarkdown(child, level + 1))
.map(child => convertTopicToMarkdown(child, level + 1, options))
.join('');

return `${text}${attachedTopics}`;
Expand All @@ -33,7 +71,7 @@ export function convertTopicToMarkdown(topic: Topic, level = 1): string {
*/
export function renderHeadline(text: string, level: number): string {
const hN = '#'.repeat(level);
return `${hN} ${sanitizeHeadline(text)}\n`;
return `${hN} ${removeLineBreaks(text)}\n`;
}

/**
Expand All @@ -42,12 +80,20 @@ export function renderHeadline(text: string, level: number): string {
export function renderListItem(text: string, depth: number, ordered = false): string {
const inset = ''.padStart(depth * 2, ' ');
const bullet = ordered ? '1.' : '*';
return `${inset}${bullet} ${sanitizeHeadline(text)}\n`;
return `${inset}${bullet} ${removeLineBreaks(text)}\n`;
}

/**
* Render text node
*/
export function renderText(text: string, depth: number): string {
// TODO implement me
return renderListItem(text, depth, true);
}

/**
* Sanitize a headline by removing newlines
* Removes line breaks from a given string
*/
export function sanitizeHeadline(headline: string): string {
export function removeLineBreaks(headline: string): string {
return headline.replace(/(\r\n|\n|\r)/gm, '');
}

0 comments on commit fe195df

Please sign in to comment.