@patternfly/quickstarts 6.2.0-prerelease.4 → 6.2.0-prerelease.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patternfly/quickstarts",
3
- "version": "6.2.0-prerelease.4",
3
+ "version": "6.2.0-prerelease.6",
4
4
  "description": "PatternFly quick starts",
5
5
  "files": [
6
6
  "src",
@@ -48,7 +48,7 @@
48
48
  "@patternfly/react-core": "^6.0.0",
49
49
  "react": ">=18.0.0",
50
50
  "react-dom": ">=18.0.0",
51
- "showdown": ">=2.1.0"
51
+ "marked": "^15.0.6"
52
52
  },
53
53
  "dependencies": {
54
54
  "dompurify": "^3.1.3",
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { css } from '@patternfly/react-styles';
3
- import { Converter } from 'showdown';
3
+ import { marked } from 'marked';
4
4
  import { useForceRender } from '@console/shared';
5
5
  import { QuickStartContext, QuickStartContextValues } from '../../utils/quick-start-context';
6
6
 
@@ -15,18 +15,7 @@ interface ShowdownExtension {
15
15
  replace?: (...args: any[]) => string;
16
16
  }
17
17
 
18
- export const markdownConvert = (markdown, extensions?: ShowdownExtension[]) => {
19
- const converter = new Converter({
20
- tables: true,
21
- openLinksInNewWindow: true,
22
- strikethrough: true,
23
- emoji: false,
24
- });
25
-
26
- if (extensions) {
27
- converter.addExtension(extensions);
28
- }
29
-
18
+ export const markdownConvert = async (markdown: string, extensions?: ShowdownExtension[]) => {
30
19
  DOMPurify.addHook('beforeSanitizeElements', function (node) {
31
20
  // nodeType 1 = element type
32
21
 
@@ -82,12 +71,38 @@ export const markdownConvert = (markdown, extensions?: ShowdownExtension[]) => {
82
71
  }
83
72
  });
84
73
 
85
- return DOMPurify.sanitize(converter.makeHtml(markdown), {
86
- USE_PROFILES: {
87
- html: true,
88
- svg: true,
89
- },
90
- });
74
+ const reverseString = (str: string) => str.split('').reverse().join('');
75
+
76
+ // replace code fences that end in a double curly brace (which are used by our custom md extensions) with non
77
+ // markdown formatting related tokens so that marked doesn't try to parse them as code spans
78
+ //
79
+ // we want to reverse the string before we do the substitution so that we only match the opening code fence which
80
+ // corresponds to the closing code fence with the double curly brace
81
+ const reversedMarkdown = reverseString(markdown);
82
+ const reverseMarkdownWithSubstitutedCodeFences = reversedMarkdown.replace(
83
+ /{{```((.|\n)*?)```/g,
84
+ '{{@@@$1@@@',
85
+ );
86
+ const markdownWithSubstitutedCodeFences = reverseString(reverseMarkdownWithSubstitutedCodeFences);
87
+
88
+ const parsedMarkdown = await marked.parse(markdownWithSubstitutedCodeFences);
89
+ // Swap the temporary tokens back to code fences before we run the extensions
90
+ let md = parsedMarkdown.replace(/@@@/g, '```');
91
+
92
+ if (extensions) {
93
+ // Convert code spans back to md format before we run the custom extension regexes
94
+ md = md.replace(/<code>(.*)<\/code>/g, '`$1`');
95
+
96
+ extensions.forEach(({ regex, replace }) => {
97
+ if (regex) {
98
+ md = md.replace(regex, replace);
99
+ }
100
+ });
101
+
102
+ // Convert any remaining backticks back into code spans
103
+ md = md.replace(/`(.*)`/g, '<code>$1</code>');
104
+ }
105
+ return DOMPurify.sanitize(md);
91
106
  };
92
107
 
93
108
  interface SyncMarkdownProps {
@@ -116,10 +131,18 @@ export const SyncMarkdownView: React.FC<SyncMarkdownProps> = ({
116
131
  className,
117
132
  }) => {
118
133
  const { getResource } = React.useContext<QuickStartContextValues>(QuickStartContext);
119
- const markup = React.useMemo(
120
- () => markdownConvert(content || emptyMsg || getResource('Not available'), extensions),
121
- [content, emptyMsg, extensions, getResource],
122
- );
134
+ const [markup, setMarkup] = React.useState<string>('');
135
+
136
+ React.useEffect(() => {
137
+ async function getMd() {
138
+ const md = await markdownConvert(
139
+ content || emptyMsg || getResource('Not available'),
140
+ extensions,
141
+ );
142
+ setMarkup(md);
143
+ }
144
+ getMd();
145
+ }, [content, emptyMsg, getResource, extensions]);
123
146
  const innerProps: InnerSyncMarkdownProps = {
124
147
  renderExtension: extensions?.length > 0 ? renderExtension : undefined,
125
148
  exactHeight,