From ccdcb5cfe7c94628e3e6b20102afee8369699527 Mon Sep 17 00:00:00 2001 From: 3y3 <3y3@ya.ru> Date: Fri, 12 Apr 2024 15:28:16 +0300 Subject: [PATCH] feat: Use fence for sandbox data --- src/includer/ui/endpoint.ts | 5 +- src/plugin/plugin.ts | 99 +++++++------------------------------ src/runtime/index.tsx | 5 +- 3 files changed, 22 insertions(+), 87 deletions(-) diff --git a/src/includer/ui/endpoint.ts b/src/includer/ui/endpoint.ts index 15d9b85..8a659a7 100644 --- a/src/includer/ui/endpoint.ts +++ b/src/includer/ui/endpoint.ts @@ -1,5 +1,6 @@ import stringify from 'json-stringify-safe'; import RefsService from '../services/refs'; +import {dump} from 'js-yaml'; import { COOKIES_SECTION_NAME, @@ -114,7 +115,7 @@ function sandbox({ bodyStr = JSON.stringify(prepareSampleObject(requestBody?.schema ?? {}), null, 2); } - const props = JSON.stringify({ + const props = dump({ pathParams, searchParams, headers, @@ -127,7 +128,7 @@ function sandbox({ host: host ?? '', }); - return block(['{% openapi sandbox %}', props, '{% end openapi sandbox %}']); + return block(['```openapi-sandbox\n' + props + '\n```']); } function request(data: Endpoint) { diff --git a/src/plugin/plugin.ts b/src/plugin/plugin.ts index c281260..19a9c28 100644 --- a/src/plugin/plugin.ts +++ b/src/plugin/plugin.ts @@ -1,98 +1,33 @@ -import type StateBlock from 'markdown-it/lib/rules_block/state_block'; import type Token from 'markdown-it/lib/token'; import type {MarkdownItPluginCb} from '@diplodoc/transform/lib/plugins/typings'; -import {escape} from 'html-escaper'; +import {load} from 'js-yaml'; -const startMark = '{% openapi sandbox %}'; -const endMark = '{% end openapi sandbox %}'; - -function parserOpenAPISandboxBlock(state: StateBlock, start: number, end: number, silent: boolean) { - let firstLine, - lastLine, - next, - lastPos, - found = false, - pos = state.bMarks[start] + state.tShift[start], - max = state.eMarks[start]; - - if (pos + startMark.length > max) { - return false; - } - - if (state.src.slice(pos, pos + startMark.length) !== startMark) { - return false; - } - - pos += startMark.length; - firstLine = state.src.slice(pos, max); - - if (silent) { - return true; - } - - if (firstLine.slice(-endMark.length) === endMark) { - firstLine = firstLine.slice(0, -endMark.length); - found = true; - } - - for (next = start; !found; ) { - next++; - - if (next >= end) { - break; - } - - pos = state.bMarks[next] + state.tShift[next]; - max = state.eMarks[next]; - - if (pos < max && state.tShift[next] < state.blkIndent) { - // non-empty line with negative indent should stop the list: - break; - } +function isSandboxBlock(token: Token) { + return token.type === 'fence' && token.info.match(/^\s*openapi-sandbox(\s*|$)/); +} - if (state.src.slice(pos, max).slice(-endMark.length) === endMark) { - lastPos = state.src.slice(0, max).lastIndexOf(endMark); - lastLine = state.src.slice(pos, lastPos); - found = true; - } +function applyTransforms({tokens}: {tokens: Token[]}) { + const blocks = tokens.filter(isSandboxBlock); + + if (blocks.length) { + blocks.forEach((token) => { + token.type = 'openapi_sandbox_block'; + token.tag = 'div'; + token.attrSet('class', 'yfm-openapi-sandbox-js'); + token.attrSet('data-props', encodeURIComponent(JSON.stringify(load(token.content)))); + token.content = ''; + }); } - state.line = next + 1; - - const token = state.push('openapi_sandbox_block', 'openapi_sandbox', 0); - token.block = true; - token.content = - (firstLine ? firstLine + '\n' : '') + - state.getLines(start + 1, next, state.tShift[start], true) + - (lastLine ? lastLine : ''); - token.map = [start, state.line]; - token.markup = startMark; return true; } -const openapiSandboxBlock = (jsonString: string) => { - try { - const props = escape(jsonString); - - return `
`; - } catch (error) { - console.log(error); - return jsonString; - } -}; - -const openapiSandboxRenderer = (tokens: Token[], idx: number) => { - return openapiSandboxBlock(tokens[idx].content); -}; - const openapiSandboxPlugin: MarkdownItPluginCb = (md) => { try { - md.block.ruler.before('meta', 'openapi_sandbox_block', parserOpenAPISandboxBlock); + md.core.ruler.after('fence', 'openapi-sandbox', applyTransforms); } catch (e) { - md.block.ruler.push('openapi_sandbox_block', parserOpenAPISandboxBlock); + md.core.ruler.push('openapi-sandbox', applyTransforms); } - - md.renderer.rules.openapi_sandbox_block = openapiSandboxRenderer; }; export function transform() { diff --git a/src/runtime/index.tsx b/src/runtime/index.tsx index dce035d..735ac28 100644 --- a/src/runtime/index.tsx +++ b/src/runtime/index.tsx @@ -1,6 +1,5 @@ import React, {useEffect, useState} from 'react'; import {createPortal} from 'react-dom'; -import {unescape} from 'html-escaper'; import {Sandbox} from './sandbox'; @@ -34,7 +33,7 @@ export const Runtime: React.FC = () => { }, []); useEffect(() => { - setSandbox(document.querySelector