From de15eaefdf9dbaee233689a0f0ddb6870869dcfa Mon Sep 17 00:00:00 2001 From: Matias Capeletto Date: Tue, 1 Dec 2020 22:08:02 +0100 Subject: [PATCH] fix: port fixes to parseHeader utils from vuepress --- .../node/utils/deeplyParseHeader.spec.ts | 33 +++++++++++ __tests__/node/utils/parseHeader.spec.ts | 38 +++++++++++++ .../utils/removeNonCodeWrappedHTML.spec.ts | 56 +++++++++++++++++++ src/node/utils/parseHeader.ts | 6 +- 4 files changed, 130 insertions(+), 3 deletions(-) create mode 100644 __tests__/node/utils/deeplyParseHeader.spec.ts create mode 100644 __tests__/node/utils/parseHeader.spec.ts create mode 100644 __tests__/node/utils/removeNonCodeWrappedHTML.spec.ts diff --git a/__tests__/node/utils/deeplyParseHeader.spec.ts b/__tests__/node/utils/deeplyParseHeader.spec.ts new file mode 100644 index 000000000000..ded20eacd523 --- /dev/null +++ b/__tests__/node/utils/deeplyParseHeader.spec.ts @@ -0,0 +1,33 @@ +import { deeplyParseHeader } from 'node/utils/parseHeader' + +test('deeplyParseHeader', () => { + const asserts: Record = { + // Remove tail html + '# `H1` ': '# H1', + '# *H1* ': '# H1', + + // Reserve code-wrapped tail html + '# `H1` ``': '# H1 ', + '# *H1* ``': '# H1 ', + + // Remove leading html + '# `H1`': '# H1', + '# *H1*': '# H1', + + // Reserve code-wrapped leading html + '# `` `H1`': '# H1', + '# `` *H1*': '# H1', + + // Remove middle html + '# `H1` `H2`': '# H1 H2', + '# `H1` `H2`': '# H1 H2', + + // Reserve middle html + '# `H1` `` `H2`': '# H1 H2', + '# `H1` `` `H2`': '# H1 H2' + } + + Object.keys(asserts).forEach((input) => { + expect(deeplyParseHeader(input)).toBe(asserts[input]) + }) +}) diff --git a/__tests__/node/utils/parseHeader.spec.ts b/__tests__/node/utils/parseHeader.spec.ts new file mode 100644 index 000000000000..a150cff0f09e --- /dev/null +++ b/__tests__/node/utils/parseHeader.spec.ts @@ -0,0 +1,38 @@ +import { parseHeader } from 'node/utils/parseHeader' + +describe('parseHeader', () => { + test('should unescape html', () => { + const input = `<div :id="'app'">` + expect(parseHeader(input)).toBe(`
`) + }) + + test('should remove markdown tokens correctly', () => { + const asserts: Record = { + // vuepress #238 + '[vue](vuejs.org)': 'vue', + '`vue`': 'vue', + '*vue*': 'vue', + '**vue**': 'vue', + '***vue***': 'vue', + _vue_: 'vue', + '\\_vue\\_': '_vue_', + '\\*vue\\*': '*vue*', + '\\!vue\\!': '!vue!', + + // vuepress #2688 + '[vue](vuejs.org) / [vue](vuejs.org)': 'vue / vue', + '[\\](vuejs.org)': '', + + // vuepress #564 For multiple markdown tokens + '`a` and `b`': 'a and b', + '***bold and italic***': 'bold and italic', + '**bold** and *italic*': 'bold and italic', + + // escaping \$ + '\\$vue': '$vue' + } + Object.keys(asserts).forEach((input) => { + expect(parseHeader(input)).toBe(asserts[input]) + }) + }) +}) diff --git a/__tests__/node/utils/removeNonCodeWrappedHTML.spec.ts b/__tests__/node/utils/removeNonCodeWrappedHTML.spec.ts new file mode 100644 index 000000000000..d5481ad8447f --- /dev/null +++ b/__tests__/node/utils/removeNonCodeWrappedHTML.spec.ts @@ -0,0 +1,56 @@ +import { removeNonCodeWrappedHTML } from 'node/utils/parseHeader' + +test('removeNonCodeWrappedHTML', () => { + const asserts: Record = { + // Remove tail html + '# H1 ': '# H1 ', + '# H1': '# H1', + '# H1 ': '# H1 ', + '# H1': '# H1', + '# H1 ': '# H1 ', + '# H1': '# H1', + '# H1 ': '# H1 ', + '# H1': '# H1', + + // Reserve code-wrapped tail html + '# H1 ``': '# H1 ``', + '# H1 ``': '# H1 ``', + '# H1 ``': '# H1 ``', + '# H1 ``': '# H1 ``', + + // Remove leading html + '# H1': '# H1', + '# H1': '# H1', + '# H1': '# H1', + '# H1': '# H1', + '# H1': '# H1', + '# H1': '# H1', + '# H1': '# H1', + '# H1': '# H1', + + // Reserve code-wrapped leading html + '# `` H1': '# `` H1', + '# `` H1': '# `` H1', + '# `` H1': '# `` H1', + '# `` H1': '# `` H1', + + // Remove middle html + '# H1 H2': '# H1 H2', + '# H1 H2': '# H1 H2', + '# H1 H2': '# H1 H2', + '# H1 H2': '# H1 H2', + + // Reserve code-wrapped middle html + '# H1 `` H2': '# H1 `` H2', + '# H1 `` H2': '# H1 `` H2', + '# H1 `` H2': '# H1 `` H2', + '# H1 `` H2': '# H1 `` H2', + + // vuepress #2688 + '# \\': '# \\' + } + + Object.keys(asserts).forEach((input) => { + expect(removeNonCodeWrappedHTML(input)).toBe(asserts[input]) + }) +}) diff --git a/src/node/utils/parseHeader.ts b/src/node/utils/parseHeader.ts index 87271c5fdea1..47ad2b5f9093 100644 --- a/src/node/utils/parseHeader.ts +++ b/src/node/utils/parseHeader.ts @@ -28,9 +28,9 @@ const unescapeHtml = (html: string) => const removeMarkdownTokens = (str: string) => String(str) - .replace(/\[(.*)\]\(.*\)/, '$1') // []() + .replace(/(\[(.[^\]]+)\]\((.[^)]+)\))/g, '$2') // []() .replace(/(`|\*{1,3}|_)(.*?[^\\])\1/g, '$2') // `{t}` | *{t}* | **{t}** | ***{t}*** | _{t}_ - .replace(/(\\)(\*|_|`|\!)/g, '$2') // remove escape char '\' + .replace(/(\\)(\*|_|`|\!|<|\$)/g, '$2') // remove escape char '\' const trim = (str: string) => str.trim() @@ -39,7 +39,7 @@ const trim = (str: string) => str.trim() // Input: " b", Output: "b" // Input: "`` b", Output: "`` b" export const removeNonCodeWrappedHTML = (str: string) => { - return String(str).replace(/(^|[^><`])<.*>([^><`]|$)/g, '$1$2') + return String(str).replace(/(^|[^><`\\])<.*>([^><`]|$)/g, '$1$2') } const compose = (...processors: ((str: string) => string)[]) => {