Yuki Takei 2 месяцев назад
Родитель
Сommit
1318950044
2 измененных файлов с 99 добавлено и 28 удалено
  1. 72 0
      packages/editor/src/models/linker.spec.ts
  2. 27 28
      packages/editor/src/models/linker.ts

+ 72 - 0
packages/editor/src/models/linker.spec.ts

@@ -0,0 +1,72 @@
+import { describe, expect, it } from 'vitest';
+
+import { Linker } from './linker';
+
+describe('Linker.fromMarkdownString', () => {
+  describe('pukiwiki link with label', () => {
+    it('should parse [[label>link]] format', () => {
+      const linker = Linker.fromMarkdownString('[[my label>my link]]');
+
+      expect(linker.type).toBe(Linker.types.pukiwikiLink);
+      expect(linker.label).toBe('my label');
+      expect(linker.link).toBe('my link');
+    });
+  });
+
+  describe('pukiwiki link without label', () => {
+    it('should parse [[link]] format and use link as label', () => {
+      const linker = Linker.fromMarkdownString('[[my link]]');
+
+      expect(linker.type).toBe(Linker.types.pukiwikiLink);
+      expect(linker.label).toBe('my link');
+      expect(linker.link).toBe('my link');
+    });
+  });
+
+  describe('markdown link', () => {
+    it('should parse [label](link) format', () => {
+      const linker = Linker.fromMarkdownString(
+        '[my label](https://example.com)',
+      );
+
+      expect(linker.type).toBe(Linker.types.markdownLink);
+      expect(linker.label).toBe('my label');
+      expect(linker.link).toBe('https://example.com');
+    });
+
+    it('should parse [label](link) with empty label and fill label with link', () => {
+      const linker = Linker.fromMarkdownString('[](https://example.com)');
+
+      expect(linker.type).toBe(Linker.types.markdownLink);
+      // label is filled with link when empty (see initWhenMarkdownLink)
+      expect(linker.label).toBe('https://example.com');
+      expect(linker.link).toBe('https://example.com');
+    });
+
+    it('should parse [label](link) with path', () => {
+      const linker = Linker.fromMarkdownString('[page](/path/to/page)');
+
+      expect(linker.type).toBe(Linker.types.markdownLink);
+      expect(linker.label).toBe('page');
+      expect(linker.link).toBe('/path/to/page');
+    });
+  });
+
+  describe('non-matching string', () => {
+    it('should create markdownLink with string as label when no pattern matches', () => {
+      const linker = Linker.fromMarkdownString('plain text');
+
+      expect(linker.type).toBe(Linker.types.markdownLink);
+      expect(linker.label).toBe('plain text');
+      expect(linker.link).toBe('');
+    });
+
+    it('should handle empty string', () => {
+      const linker = Linker.fromMarkdownString('');
+
+      expect(linker.type).toBe(Linker.types.markdownLink);
+      expect(linker.label).toBe('');
+      expect(linker.link).toBe('');
+    });
+  });
+});

+ 27 - 28
packages/editor/src/models/linker.ts

@@ -28,7 +28,6 @@ export class Linker {
   static patterns = {
     pukiwikiLinkWithLabel: /^\[\[(?<label>.+)>(?<link>.+)\]\]$/, // https://regex101.com/r/2fNmUN/2
     pukiwikiLinkWithoutLabel: /^\[\[(?<label>.+)\]\]$/, // https://regex101.com/r/S7w5Xu/1
-    growiLink: /^\[(?<label>\/.+)\]$/, // https://regex101.com/r/DJfkYf/3
     markdownLink: /^\[(?<label>.*)\]\((?<link>.*)\)$/, // https://regex101.com/r/DZCKP3/2
   };
 
@@ -61,33 +60,33 @@ export class Linker {
     let link = '';
     let type = Linker.types.markdownLink;
 
-    // pukiwiki with separator ">".
-    if (str.match(Linker.patterns.pukiwikiLinkWithLabel)) {
-      type = Linker.types.pukiwikiLink;
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      ({ label, link } = str.match(Linker.patterns.pukiwikiLinkWithLabel)!
-        .groups!);
-    }
-    // pukiwiki without separator ">".
-    else if (str.match(Linker.patterns.pukiwikiLinkWithoutLabel)) {
-      type = Linker.types.pukiwikiLink;
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      ({ label } = str.match(Linker.patterns.pukiwikiLinkWithoutLabel)!
-        .groups!);
-      link = label;
-    }
-    // markdown
-    else if (str.match(Linker.patterns.markdownLink)) {
-      type = Linker.types.markdownLink;
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      ({ label, link } = str.match(Linker.patterns.markdownLink)!.groups!);
-    }
-    // growi
-    else if (str.match(Linker.patterns.growiLink)) {
-      type = Linker.types.growiLink;
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      ({ label } = str.match(Linker.patterns.growiLink)!.groups!);
-      link = label;
+    const patterns = [
+      // pukiwiki with separator ">".
+      {
+        type: Linker.types.pukiwikiLink,
+        pattern: Linker.patterns.pukiwikiLinkWithLabel,
+      },
+      // pukiwiki without separator ">".
+      {
+        type: Linker.types.pukiwikiLink,
+        pattern: Linker.patterns.pukiwikiLinkWithoutLabel,
+      },
+      // markdown link.
+      {
+        type: Linker.types.markdownLink,
+        pattern: Linker.patterns.markdownLink,
+      },
+    ];
+
+    // evaluate patterns
+    for (const { type: patternType, pattern } of patterns) {
+      const match = str.match(pattern);
+      if (match?.groups) {
+        type = patternType;
+        label = match.groups.label;
+        link = match.groups.link ?? label;
+        break;
+      }
     }
 
     return new Linker(type, label, link);