Просмотр исходного кода

impl lsx rehype plugin to resolve relative prefix

Yuki Takei 3 лет назад
Родитель
Сommit
00c543c80d

+ 54 - 0
packages/app/src/services/renderer/growi-plugins/lsx.ts

@@ -1,11 +1,18 @@
+import assert from 'assert';
+
+import { pathUtils } from '@growi/core';
 import { RemarkGrowiPluginType } from '@growi/remark-growi-plugin';
 import { RemarkGrowiPluginType } from '@growi/remark-growi-plugin';
 import { Schema as SanitizeOption } from 'hast-util-sanitize';
 import { Schema as SanitizeOption } from 'hast-util-sanitize';
+import { selectAll, HastNode } from 'hast-util-select';
 import { Plugin } from 'unified';
 import { Plugin } from 'unified';
 import { visit } from 'unist-util-visit';
 import { visit } from 'unist-util-visit';
 
 
+import { IHrefResolver } from '../rehype-plugins/relative-links';
+
 const NODE_NAME_PATTERN = new RegExp(/ls|lsx/);
 const NODE_NAME_PATTERN = new RegExp(/ls|lsx/);
 const SUPPORTED_ATTRIBUTES = ['prefix', 'num', 'depth', 'sort', 'reverse', 'filter'];
 const SUPPORTED_ATTRIBUTES = ['prefix', 'num', 'depth', 'sort', 'reverse', 'filter'];
 
 
+const { hasHeadingSlash } = pathUtils;
 
 
 type DirectiveAttributes = Record<string, string>
 type DirectiveAttributes = Record<string, string>
 
 
@@ -48,6 +55,53 @@ export const remarkPlugin: Plugin = function() {
   };
   };
 };
 };
 
 
+export type LsxRehypePluginParams = {
+  pagePath?: string,
+}
+
+const pathResolver: IHrefResolver = (relativeHref, basePath) => {
+  // generate relative pathname
+  const baseUrl = new URL(pathUtils.addTrailingSlash(basePath), 'https://example.com');
+  const relativeUrl = new URL(relativeHref, baseUrl);
+
+  return relativeUrl.pathname;
+};
+
+export const rehypePlugin: Plugin<[LsxRehypePluginParams]> = (options = {}) => {
+  assert.notStrictEqual(options.pagePath, null, 'lsx rehype plugin requires \'pagePath\' option');
+
+  return (tree) => {
+    if (options.pagePath == null) {
+      return;
+    }
+
+    const basePagePath = options.pagePath;
+    const elements = selectAll('lsx', tree as HastNode);
+
+    elements.forEach((lsxElem) => {
+      if (lsxElem.properties == null) {
+        return;
+      }
+
+      const prefix = lsxElem.properties.prefix;
+
+      // set basePagePath when prefix is undefined or invalid
+      if (prefix == null || typeof prefix !== 'string') {
+        lsxElem.properties.prefix = basePagePath;
+        return;
+      }
+
+      // return when prefix is already determined and aboslute path
+      if (hasHeadingSlash(prefix)) {
+        return;
+      }
+
+      // resolve relative path
+      lsxElem.properties.prefix = pathResolver(prefix, basePagePath);
+    });
+  };
+};
+
 export const sanitizeOption: SanitizeOption = {
 export const sanitizeOption: SanitizeOption = {
   tagNames: ['lsx'],
   tagNames: ['lsx'],
   attributes: {
   attributes: {

+ 1 - 0
packages/app/src/services/renderer/renderer.ts

@@ -335,6 +335,7 @@ export const generateViewOptions = (
         return false; // not show toc in body
         return false; // not show toc in body
       },
       },
     }],
     }],
+    [lsxGrowiPlugin.rehypePlugin, { pagePath }],
     // [autoLinkHeadings, {
     // [autoLinkHeadings, {
     //   behavior: 'append',
     //   behavior: 'append',
     // }]
     // }]