diff --git a/apps/editor/src/__test__/unit/convertor.spec.ts b/apps/editor/src/__test__/unit/convertor.spec.ts
index 2ed8cdd3ef..babb0c3896 100644
--- a/apps/editor/src/__test__/unit/convertor.spec.ts
+++ b/apps/editor/src/__test__/unit/convertor.spec.ts
@@ -590,7 +590,8 @@ describe('Convertor', () => {
|
|
| |
| - mix**ed**
|
- | - mixed
|
+ | - mix*e*d
|
+ | - mixed
|
| foobaz |
| ![altText](imgUrl) **mixed**- [linkText](linkUrl) mixed
|
`;
@@ -602,8 +603,9 @@ describe('Convertor', () => {
| - ordered
|
| |
| |
- | - mixed
|
- | - mixed
|
+ | - mix**ed**
|
+ | - mix*e*d
|
+ | - mixed
|
| foobaz |
| ![altText](imgUrl) **mixed**- [linkText](linkUrl) mixed
|
`;
@@ -1075,28 +1077,81 @@ describe('Convertor', () => {
});
});
- it('should convert by using HTML tag when delimiter is not preceded an alphanumeric', () => {
- const wwNodeJson = {
- type: 'doc',
- content: [
- {
- type: 'paragraph',
- content: [
- {
- type: 'text',
- marks: [{ type: 'strong' }],
- text: '"test"',
- },
- { type: 'text', text: 'a' },
- ],
- },
- ],
- };
- const wwNode = Node.fromJSON(schema, wwNodeJson);
+ describe('emphasis that starts/ends with punctuation', () => {
+ it('should convert by using HTML tag when not preceded by whitespace or punctuation', () => {
+ const wwNodeJson = {
+ type: 'doc',
+ content: [
+ {
+ type: 'paragraph',
+ content: [
+ { type: 'text', text: 'a' },
+ {
+ type: 'text',
+ marks: [{ type: 'emph' }],
+ text: '"test"',
+ },
+ ],
+ },
+ ],
+ };
+ const wwNode = Node.fromJSON(schema, wwNodeJson);
- const result = convertor.toMarkdownText(wwNode);
+ const result = convertor.toMarkdownText(wwNode);
+
+ expect(result).toBe(`a"test"`);
+ });
+
+ it('should convert by using HTML tag when not succeeded by whitespace or punctuation', () => {
+ const wwNodeJson = {
+ type: 'doc',
+ content: [
+ {
+ type: 'paragraph',
+ content: [
+ {
+ type: 'text',
+ marks: [{ type: 'strong' }],
+ text: '"test"',
+ },
+ { type: 'text', text: 'a' },
+ ],
+ },
+ ],
+ };
+ const wwNode = Node.fromJSON(schema, wwNodeJson);
+
+ const result = convertor.toMarkdownText(wwNode);
- expect(result).toBe(`"test"a`);
+ expect(result).toBe(`"test"a`);
+ });
+
+ it('should not convert by using HTML tag when preceded by whitespace', () => {
+ const markdown =
+ 'test **"test"**';
+ const expected =
+ 'test **"test"**';
+
+ assertConverting(markdown, expected);
+ });
+
+ it('should not convert by using HTML tag when preceded by punctuation', () => {
+ const markdown =
+ 'test,**"test"**';
+ const expected =
+ 'test,**"test"**';
+
+ assertConverting(markdown, expected);
+ });
+
+ it('should not convert by using HTML tag when inside another emphasis', () => {
+ const markdown =
+ '**test*test***';
+ const expected =
+ '**test*test***';
+
+ assertConverting(markdown, expected);
+ });
});
it('should convert empty line between lists of wysiwig to
', () => {
diff --git a/apps/editor/src/convertors/toMarkdown/toMdConvertorState.ts b/apps/editor/src/convertors/toMarkdown/toMdConvertorState.ts
index 86fd701a05..c884493235 100644
--- a/apps/editor/src/convertors/toMarkdown/toMdConvertorState.ts
+++ b/apps/editor/src/convertors/toMarkdown/toMdConvertorState.ts
@@ -1,6 +1,6 @@
import { Node, Mark } from 'prosemirror-model';
-import { includes, escape, last, isEndWithSpace, isStartWithSpace } from '@/utils/common';
+import { includes, escape, last, isStartWithSpaceOrPunct, isEndWithSpaceOrPunct, isStartWithPunct, isEndWithPunct } from '@/utils/common';
import { WwNodeType, WwMarkType } from '@t/wysiwyg';
import {
@@ -10,7 +10,6 @@ import {
FirstDelimFn,
InfoForPosSync,
} from '@t/convertor';
-import { DEFAULT_TEXT_NOT_START_OR_END_WITH_SPACE } from '@/utils/constants';
export default class ToMdConvertorState {
private readonly nodeTypeConvertors: ToMdNodeTypeConvertorMap;
@@ -50,27 +49,23 @@ export default class ToMdConvertorState {
return /(^|\n)$/.test(this.result);
}
- private isBetweenSpaces(parent: Node, index: number) {
+ private isNonSpecEmphasis(parent: Node, index: number) {
const { content } = parent;
- const isFrontNodeEndWithSpace =
- index === 0 ||
- isEndWithSpace(content.child(index - 1).text ?? DEFAULT_TEXT_NOT_START_OR_END_WITH_SPACE);
+ if (index !== 0 && isStartWithPunct(content.child(index).text) && !isEndWithSpaceOrPunct(content.child(index - 1).text) ) return true;
- const isRearNodeStartWithSpace =
- index >= content.childCount - 1 ||
- isStartWithSpace(content.child(index + 1).text ?? DEFAULT_TEXT_NOT_START_OR_END_WITH_SPACE);
+ if (index !== content.childCount - 1 && isEndWithPunct(content.child(index).text) && !isStartWithSpaceOrPunct(content.child(index + 1).text) ) return true;
- return isFrontNodeEndWithSpace && isRearNodeStartWithSpace;
+ return false;
}
private markText(mark: Mark, entering: boolean, parent: Node, index: number) {
const convertor = this.getMarkConvertor(mark);
if (convertor) {
- const betweenSpace = this.isBetweenSpaces(parent, entering ? index : index - 1);
+ const nonSpecEmphasis = this.isNonSpecEmphasis(parent, entering ? index : index - 1);
- const { delim, rawHTML } = convertor({ node: mark, parent, index }, entering, betweenSpace);
+ const { delim, rawHTML } = convertor({ node: mark, parent, index }, entering, nonSpecEmphasis);
return (rawHTML as string) || (delim as string);
}
diff --git a/apps/editor/src/convertors/toMarkdown/toMdConvertors.ts b/apps/editor/src/convertors/toMarkdown/toMdConvertors.ts
index 8f1a190404..e991cdba4d 100644
--- a/apps/editor/src/convertors/toMarkdown/toMdConvertors.ts
+++ b/apps/editor/src/convertors/toMarkdown/toMdConvertors.ts
@@ -208,11 +208,11 @@ export const toMdConvertors: ToMdConvertorMap = {
};
},
- strong({ node }, { entering }, betweenSpace) {
+ strong({ node }, { entering }, nonSpecEmphasis) {
const { rawHTML } = node.attrs;
let delim = '**';
- if (!betweenSpace) {
+ if (nonSpecEmphasis) {
delim = entering ? '' : '';
}
@@ -222,11 +222,11 @@ export const toMdConvertors: ToMdConvertorMap = {
};
},
- emph({ node }, { entering }, betweenSpace) {
+ emph({ node }, { entering }, nonSpecEmphasis) {
const { rawHTML } = node.attrs;
let delim = '*';
- if (!betweenSpace) {
+ if (nonSpecEmphasis) {
delim = entering ? '' : '';
}
@@ -236,11 +236,11 @@ export const toMdConvertors: ToMdConvertorMap = {
};
},
- strike({ node }, { entering }, betweenSpace) {
+ strike({ node }, { entering }, nonSpecEmphasis) {
const { rawHTML } = node.attrs;
let delim = '~~';
- if (!betweenSpace) {
+ if (nonSpecEmphasis) {
delim = entering ? '' : '';
}
@@ -368,7 +368,7 @@ function createMarkTypeConvertors(convertors: ToMdConvertorMap) {
const markTypes = Object.keys(markTypeOptions) as WwMarkType[];
markTypes.forEach((type) => {
- markTypeConvertors[type] = (nodeInfo, entering, betweenSpace) => {
+ markTypeConvertors[type] = (nodeInfo, entering, nonSpecEmphasis) => {
const markOption = markTypeOptions[type];
const convertor = convertors[type];
@@ -378,7 +378,7 @@ function createMarkTypeConvertors(convertors: ToMdConvertorMap) {
// the converter is called without parameters.
const runConvertor = convertor && nodeInfo && !isUndefined(entering);
const params = runConvertor
- ? convertor!(nodeInfo as MarkInfo, { entering }, betweenSpace)
+ ? convertor!(nodeInfo as MarkInfo, { entering }, nonSpecEmphasis)
: {};
return { ...params, ...markOption };
diff --git a/apps/editor/src/utils/common.ts b/apps/editor/src/utils/common.ts
index 3754219237..f4dc66bd03 100644
--- a/apps/editor/src/utils/common.ts
+++ b/apps/editor/src/utils/common.ts
@@ -264,14 +264,35 @@ export function getSortedNumPair(valueA: number, valueB: number) {
return valueA > valueB ? [valueB, valueA] : [valueA, valueB];
}
-export function isStartWithSpace(text: string) {
- const reStartWithSpace = /^\s(\S*)/g;
+const reStartWithSpaceOrPunct = /^[\s\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,\-.\/:;<=>?@\[\]^_`{|}~]/;
- return reStartWithSpace.test(text);
+export function isStartWithSpaceOrPunct(text?: string) {
+ if (!text) return true;
+
+ return reStartWithSpaceOrPunct.test(text);
+}
+
+const reEndWithSpaceOrPunct = /[\s\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,\-.\/:;<=>?@\[\]^_`{|}~]$/;
+
+export function isEndWithSpaceOrPunct(text?: string) {
+ if (!text) return true;
+
+ return reEndWithSpaceOrPunct.test(text);
}
-export function isEndWithSpace(text: string) {
- const reEndWithSpace = /(\S*)\s$/g;
+const reStartWithPunct = /^[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,\-.\/:;<=>?@\[\]^_`{|}~]/;
+
+export function isStartWithPunct(text?: string) {
+ if (!text) return false;
- return reEndWithSpace.test(text);
+ return reStartWithPunct.test(text);
}
+
+const reEndWithPunct = /[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,\-.\/:;<=>?@\[\]^_`{|}~]$/;
+
+export function isEndWithPunct(text?: string) {
+ if (!text) return false;
+
+ return reEndWithPunct.test(text);
+}
+
diff --git a/apps/editor/src/utils/constants.ts b/apps/editor/src/utils/constants.ts
index 78d5adf33f..2d6cd54983 100644
--- a/apps/editor/src/utils/constants.ts
+++ b/apps/editor/src/utils/constants.ts
@@ -20,5 +20,3 @@ export const reBR = /
/i;
export const reHTMLComment = /|/;
export const ALTERNATIVE_TAG_FOR_BR = '';
-
-export const DEFAULT_TEXT_NOT_START_OR_END_WITH_SPACE = 'a';
diff --git a/apps/editor/types/convertor.d.ts b/apps/editor/types/convertor.d.ts
index 718c1c7ade..4013134f27 100644
--- a/apps/editor/types/convertor.d.ts
+++ b/apps/editor/types/convertor.d.ts
@@ -114,7 +114,7 @@ export type ToMdNodeTypeConvertorMap = Partial ToMdConvertorReturnValues & ToMdMarkTypeOption;
export type ToMdMarkTypeConvertorMap = Partial>;
@@ -128,7 +128,7 @@ interface ToMdConvertorContext {
type ToMdConvertor = (
nodeInfo: NodeInfo | MarkInfo,
context: ToMdConvertorContext,
- betweenSpace?: boolean
+ nonSpecEmphasis?: boolean
) => ToMdConvertorReturnValues;
export type ToMdConvertorMap = Partial>;