From 8c85d6fd6b90ced123f25b169cd4acdc0c7956e3 Mon Sep 17 00:00:00 2001 From: hexh <250786313@qq.com> Date: Wed, 20 Mar 2024 21:07:29 +0800 Subject: [PATCH] fix(markdown): incorrect list indentation alignment in markdown parser (#4884) * fix(markdown): incorrect markdown list item indent rendering * fix(markdown): ts type error --- src/__tests__/markdown/index.test.ts | 44 +++++++++++++++++++++++++ src/__tests__/markdown/renderer.test.ts | 9 +++-- src/markdown/index.ts | 3 +- src/markdown/renderer.ts | 21 +++++++++++- 4 files changed, 72 insertions(+), 5 deletions(-) diff --git a/src/__tests__/markdown/index.test.ts b/src/__tests__/markdown/index.test.ts index d5d583efbb3..a7fa523f744 100644 --- a/src/__tests__/markdown/index.test.ts +++ b/src/__tests__/markdown/index.test.ts @@ -201,6 +201,50 @@ bar ' * foo', ' * bar', ' * one', ' * two' ]) }) + + it('should render complicated nested list', () => { + let content = ` +- greeting + - hello + - me + you + them + - hi + - me + you + them + - him + her +- bye +- code + + \`\`\`typescript + function foo () { + console.log('foo') + console.log('bar') + } + \`\`\` +` + let res = parseMarkdown(content, {}) + expect(res.lines).toEqual( +` * greeting + * hello + * me + you + them + * hi + * me + you + them + * him + her + * bye + * code + function foo () { + console.log('foo') + console.log('bar') + }`.split('\n')) + }) }) describe('parseDocuments', () => { diff --git a/src/__tests__/markdown/renderer.test.ts b/src/__tests__/markdown/renderer.test.ts index c2f14a83bba..c989c132a21 100644 --- a/src/__tests__/markdown/renderer.test.ts +++ b/src/__tests__/markdown/renderer.test.ts @@ -1,10 +1,11 @@ import { marked } from 'marked' -import Renderer, { bulletPointLine, fixHardReturn, generateTableRow, identify, numberedLine, toSpaces } from '../../markdown/renderer' +import Renderer, { bulletPointLine, fixHardReturn, generateTableRow, identify, numberedLine, toSpaces, toSpecialSpaces } from '../../markdown/renderer' import * as styles from '../../markdown/styles' import { parseAnsiHighlights, AnsiResult } from '../../util/ansiparse' marked.setOptions({ - renderer: new Renderer() + renderer: new Renderer(), + hooks: Renderer.hooks, }) function parse(text: string): AnsiResult { @@ -28,8 +29,10 @@ describe('Renderer of marked', () => { expect(identify(' ', '')).toBe('') expect(fixHardReturn('a\rb', true)).toBe('a\nb') expect(toSpaces('ab')).toBe(' ') + expect(toSpecialSpaces('ab')).toBe('\0\0\0\0\0\0') expect(bulletPointLine(' ', ' * foo')).toBe(' * foo') - expect(bulletPointLine(' ', 'foo')).toBe(' foo') + expect(bulletPointLine(' ', 'foo')).toBe('\0\0\0\0\0\0foo') + expect(bulletPointLine(' ', '\0\0\0foo')).toBe('\0\0\0foo') expect(generateTableRow('')).toEqual([]) expect(numberedLine(' ', 'foo', 1).line).toBe(' foo') }) diff --git a/src/markdown/index.ts b/src/markdown/index.ts index d165b7fd685..445c4652401 100644 --- a/src/markdown/index.ts +++ b/src/markdown/index.ts @@ -157,7 +157,8 @@ export function parseMarkdown(content: string, opts: MarkdownParseOptions): Docu marked.setOptions({ renderer: new Renderer(), gfm: true, - breaks: Is.boolean(opts.breaks) ? opts.breaks : true + breaks: Is.boolean(opts.breaks) ? opts.breaks : true, + hooks: Renderer.hooks, }) let lines: string[] = [] let highlights: HighlightItem[] = [] diff --git a/src/markdown/renderer.ts b/src/markdown/renderer.ts index 7061422ca76..33b5212bbf0 100644 --- a/src/markdown/renderer.ts +++ b/src/markdown/renderer.ts @@ -1,5 +1,6 @@ 'use strict' import { toObject } from '../util/object' +import { MarkedOptions } from 'marked' /** * Renderer for convert markdown to terminal string */ @@ -92,9 +93,21 @@ export function toSpaces(str) { return ' '.repeat(str.length) } +const SPECIAL_SPACE = '\0\0\0' +const SPACE = ' ' +export function toSpecialSpaces(str) { + return SPECIAL_SPACE.repeat(str.length) +} + let BULLET_POINT = '* ' export function bulletPointLine(indent, line) { - return isPointedLine(line, indent) ? line : toSpaces(BULLET_POINT) + line + if (isPointedLine(line, indent)) { + return line + } + if (!line.includes(SPECIAL_SPACE)) { + return toSpecialSpaces(BULLET_POINT) + line + } + return line } function bulletPointLines(lines, indent) { @@ -204,6 +217,12 @@ class Renderer { this.highlightOptions = toObject(highlightOptions) this.transform = this.compose(undoColon, this.unescape) } + public static hooks: MarkedOptions['hooks'] = { + preprocess: str => str, + postprocess: str => { + return str.replace(new RegExp(SPECIAL_SPACE, 'g'), SPACE) + } + } public text(t: string): string { return this.o.text(t)