Jelajahi Sumber

impl remark plugin and RendererOptions generator

Yuki Takei 3 tahun lalu
induk
melakukan
e7e8a9d47a

+ 27 - 0
packages/app/src/services/renderer/renderer.tsx

@@ -6,6 +6,7 @@ import * as drawioPlugin from '@growi/remark-drawio';
 import growiDirective from '@growi/remark-growi-directive';
 import { Lsx, LsxImmutable } from '@growi/remark-lsx/components';
 import * as lsxGrowiPlugin from '@growi/remark-lsx/services/renderer';
+import * as presentation from '@growi/remark-presentation';
 import type { Schema as SanitizeOption } from 'hast-util-sanitize';
 import type { SpecialComponents } from 'react-markdown/lib/ast-to-react';
 import type { NormalComponents } from 'react-markdown/lib/complex-types';
@@ -293,6 +294,32 @@ export const generateSimpleViewOptions = (
   return options;
 };
 
+export const generatePresentationViewOptions = (
+    config: RendererConfig,
+    pagePath: string,
+): RendererOptions => {
+  const options = generateSimpleViewOptions(config, pagePath);
+
+  options.remarkPlugins.push(
+    presentation.remarkPlugin,
+  );
+
+  // add sanitize option for presentation
+  const sanitizePlugin = options.rehypePlugins.find(rehypePlugin => isSanitizePlugin(rehypePlugin)) as SanitizePlugin | undefined;
+  if (sanitizePlugin != null) {
+    const sanitizeOptions = sanitizePlugin[1];
+    sanitizePlugin[1] = deepmerge(
+      sanitizeOptions,
+      presentation.sanitizeOption,
+    );
+  }
+
+  if (config.isEnabledXssPrevention) {
+    verifySanitizePlugin(options, false);
+  }
+  return options;
+};
+
 export const generateSSRViewOptions = (
     config: RendererConfig,
     pagePath: string,

+ 44 - 0
packages/remark-presentation/src/services/renderer/presentation.ts

@@ -0,0 +1,44 @@
+import type { Schema as SanitizeOption } from 'hast-util-sanitize';
+import type { Plugin } from 'unified';
+import type { Parent } from 'unist';
+import { findAfter } from 'unist-util-find-after';
+import { visitParents } from 'unist-util-visit-parents';
+
+
+export const remarkPlugin: Plugin = function() {
+  return (tree) => {
+    visitParents(
+      tree,
+      node => node.type === 'heading',
+      (node, ancestors) => {
+        const parent = ancestors.slice(-1)[0] as Parent;
+
+        const startElem = node;
+        const endElem = findAfter(parent, startElem, node => node.type === 'heading');
+
+        const startIndex = parent.children.indexOf(startElem);
+        const endIndex = endElem != null ? parent.children.indexOf(endElem) : undefined;
+
+        const between = parent.children.slice(
+          startIndex,
+          endIndex,
+        );
+
+        const section = {
+          type: 'slide',
+          children: between,
+          data: {
+            hName: 'slide',
+          },
+        };
+
+        parent.children.splice(startIndex, section.children.length, section);
+      },
+    );
+  };
+};
+
+
+export const sanitizeOption: SanitizeOption = {
+  tagNames: ['slide'],
+};