diff --git a/.storybook/main.js b/.storybook/main.js index 01f68736..43d87ece 100644 --- a/.storybook/main.js +++ b/.storybook/main.js @@ -1,9 +1,10 @@ +const path = require('path'); + module.exports = { features: { previewCsfV3: true, }, stories: ['../stories/**/*.stories.@(js|ts|mdx)', '../src/**/*.stories.@(js|ts|mdx)'], - addons: ['@storybook/addon-essentials', '@storybook/addon-a11y'], babel: async (options) => { @@ -15,4 +16,19 @@ module.exports = { }); return options; }, + + webpackFinal: async (config) => { + config.module.rules.push({ + test: /\.js$/, + include: [path.resolve(__dirname, '../node_modules/marked')], + use: { + loader: require.resolve('babel-loader'), + options: { + presets: [require.resolve('@babel/preset-env')], + }, + }, + }); + + return config; + }, }; diff --git a/package.json b/package.json index 5c032db0..c65b6f98 100644 --- a/package.json +++ b/package.json @@ -117,6 +117,7 @@ "lint-staged": "12.5.0", "lit-html": "2.6.1", "markdown-it": "12.3.2", + "marked": "15.0.12", "node-static": "0.7.11", "nodemon": "2.0.21", "pascal-case": "3.1.2", diff --git a/src/lib/text-format.js b/src/lib/text-format.js index b37a2ebf..ea9e6453 100644 --- a/src/lib/text-format.js +++ b/src/lib/text-format.js @@ -15,6 +15,7 @@ */ import DOMPurify from 'dompurify'; +import { marked } from 'marked'; export async function loadAsciiDoctor() { let _gvAsciidoctor = window._gvAsciidoctor; @@ -34,44 +35,40 @@ export async function loadAsciiDoctor() { return _gvAsciidoctor; } -export function toDom(text, type = 'adoc', small = false) { - return loadAsciiDoctor().then((asciidoctor) => { - if (text) { - let innerHTML = ''; - if (type === 'adoc') { - const htmlContent = asciidoctor - .convert(text, { - attributes: { - showtitle: true, - 'source-highlighter': 'highlightjs-ext', - }, - }) - // Replace href links to include potential parts of the URL that can be set by Angular router or - // any other routing framework. By default, href will have the following format: - // href="[SERVER_BASE]/#a_link" i.e. href="https://apim-master-portal.cloud.gravitee.io/#a_link" - .replace(/href="#/g, `href="${window.location.href}#`); - // Sanitize HTML content to avoid XSS attacks - innerHTML = DOMPurify.sanitize(htmlContent); - } else { - throw new Error(`Library not found for type : '${type}' | ${text}`); - } +export async function toDom(text, type = 'adoc', small = false) { + if (!text) return; - const element = document.createElement('div'); - element.innerHTML = innerHTML; - element.style.width = '100%'; - element.style.maxWidth = '1000px'; - element.style.margin = '0 auto'; - element.classList.add('markdown-body'); - if (small) { - element.classList.add('small'); - } - const titleElement = element.querySelector('h1'); - let title = ''; - if (titleElement) { - title = titleElement.textContent; - } + let innerHTML = ''; + if (type === 'adoc') { + const asciidoctor = await loadAsciiDoctor(); + const htmlContent = asciidoctor + .convert(text, { + attributes: { + showtitle: true, + 'source-highlighter': 'highlightjs-ext', + }, + }) + .replace(/href="#/g, `href="${window.location.href}#`); + innerHTML = DOMPurify.sanitize(htmlContent); + } else if (type === 'md' || type === 'markdown') { + const htmlContent = marked.parse(text).replace(/href="#/g, `href="${window.location.href}#`); + innerHTML = DOMPurify.sanitize(htmlContent); + } else { + throw new Error(`Unsupported documentation type: '${type}'`); + } + + const element = document.createElement('div'); + element.innerHTML = innerHTML; + element.style.width = '100%'; + element.style.maxWidth = '1000px'; + element.style.margin = '5px auto'; + element.classList.add('markdown-body'); + if (small) { + element.classList.add('small'); + } + + const titleElement = element.querySelector('h1'); + const title = titleElement ? titleElement.textContent : ''; - return { title, element }; - } - }); + return { title, element }; } diff --git a/src/organisms/gv-documentation/gv-documentation.js b/src/organisms/gv-documentation/gv-documentation.js index 788f6483..0f2db176 100644 --- a/src/organisms/gv-documentation/gv-documentation.js +++ b/src/organisms/gv-documentation/gv-documentation.js @@ -142,7 +142,9 @@ export class GvDocumentation extends LitElement { constructor() { super(); - this.type = 'adoc'; + if (!this.type) { + this.type = 'adoc'; + } } _onCloseDocumentation() { diff --git a/src/organisms/gv-documentation/gv-documentation.stories.js b/src/organisms/gv-documentation/gv-documentation.stories.js index dab4fc8e..51173da8 100644 --- a/src/organisms/gv-documentation/gv-documentation.stories.js +++ b/src/organisms/gv-documentation/gv-documentation.stories.js @@ -16,6 +16,7 @@ import './gv-documentation'; import { policyMockReadme } from '../../../testing/resources/adoc/policy-mock-readme'; import { makeStory, storyWait } from '../../../testing/lib/make-story'; +import { policyCalloutReadme } from '../../../testing/resources/md/policy-mock-readme'; export default { title: 'Organisms/gv-documentation', @@ -66,6 +67,10 @@ export const Async = makeStory(conf, { ], }); +export const MarkdownDoc = makeStory(conf, { + items: [{ text: policyCalloutReadme, type: 'md' }], +}); + const maliciousAsciidoc = '```test">'; export const SanitizedMaliciousDoc = makeStory(conf, { items: [{ text: maliciousAsciidoc }], diff --git a/src/policy-studio/gv-design/gv-design.js b/src/policy-studio/gv-design/gv-design.js index 070027f8..32bd4968 100644 --- a/src/policy-studio/gv-design/gv-design.js +++ b/src/policy-studio/gv-design/gv-design.js @@ -888,6 +888,7 @@ export class GvDesign extends KeyboardElement(LitElement) { @@ -897,6 +898,7 @@ export class GvDesign extends KeyboardElement(LitElement) { return html``; diff --git a/testing/resources/md/policy-mock-readme.js b/testing/resources/md/policy-mock-readme.js new file mode 100644 index 00000000..5bb076cb --- /dev/null +++ b/testing/resources/md/policy-mock-readme.js @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2021 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* eslint-disable no-useless-escape */ +export const policyCalloutReadme = `= Callout Policy +## Overview +You can use the \`callout-http\` policy to invoke an HTTP(S) URL and place a subset or all of the content in +one or more variables of the request execution context. + +This can be useful if you need some data from an external service and want to inject it during request +processing. + +The result of the callout is placed in a variable called \`calloutResponse\` and is only available during policy +execution. If no variable is configured the result of the callout is no longer available. + + + + + +## Errors +You can use the response template feature to override the default response provided by the policy. +These templates are be defined at the API level, in "Entrypoint" section for V4 Apis, or in "Response Templates" for V2 APIs. + +The error keys sent by this policy are as follows: + +| Key | +| --- | +| CALLOUT_EXIT_ON_ERROR | +| CALLOUT_HTTP_ERROR | +`; diff --git a/yarn.lock b/yarn.lock index 2f74d4fa..173ceb1d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4119,6 +4119,7 @@ __metadata: lit: ^2.0.2 lit-html: 2.6.1 markdown-it: 12.3.2 + marked: 15.0.12 node-static: 0.7.11 nodemon: 2.0.21 object-path: ^0.11.8 @@ -17141,6 +17142,15 @@ __metadata: languageName: node linkType: hard +"marked@npm:15.0.12": + version: 15.0.12 + resolution: "marked@npm:15.0.12" + bin: + marked: bin/marked.js + checksum: 2ac72fc0bc7ecb47de246e396c7054d311f55379957e4e01796c12d196cb84480e8d53e54948f957a078f9166692fea8b0309fc597f26f855573e7ba5c1ec7eb + languageName: node + linkType: hard + "marked@npm:^2.0.0": version: 2.1.3 resolution: "marked@npm:2.1.3"