refactor: sanitize schema customize

This commit is contained in:
Rongjian Zhang 2020-07-21 18:31:52 +08:00
parent 535d536742
commit b1e1a5aeb6
13 changed files with 27 additions and 45 deletions

View File

@ -15,10 +15,8 @@
],
"dependencies": {
"@types/codemirror": "^0.0.96",
"@types/lodash-es": "^4.17.3",
"@types/lodash.debounce": "^4.0.6",
"codemirror": "^5.55.0",
"deepmerge": "^4.2.2",
"lodash.debounce": "^4.0.8",
"rehype-raw": "^4.0.1",
"rehype-sanitize": "^3.0.1",

View File

@ -3,12 +3,12 @@ import * as bytemd from 'bytemd';
export interface ViewerProps extends bytemd.ViewerProps {}
export const Viewer: FC<ViewerProps> = ({ value, plugins }) => {
export const Viewer: FC<ViewerProps> = ({ value, sanitize, plugins }) => {
const el = useRef<HTMLDivElement>(null);
const html = useMemo(() => bytemd.processMarkdown({ value, plugins }), [
value,
plugins,
]);
const html = useMemo(
() => bytemd.processMarkdown({ value, sanitize, plugins }),
[value, sanitize, plugins]
);
useEffect(() => {
const $ = el.current;

View File

@ -11,6 +11,7 @@
export let value = '';
export let plugins = [];
export let sanitize = null;
export let mode = 'split';
export let previewDebounce = 300;
@ -82,7 +83,7 @@
<div
class="bytemd-preview"
style={mode === 'tab' && activeTab === 0 ? 'display:none' : undefined}>
<Viewer value={viewerValue} {plugins} />
<Viewer value={viewerValue} {plugins} {sanitize} />
</div>
</div>
</div>

View File

@ -27,7 +27,6 @@ export interface BytemdPlugin {
* https://github.com/rehypejs/rehype/blob/main/doc/plugins.md
*/
rehype?: UnifiedProcessor;
sanitizeSchema?: any;
/**
* Side effect for editor, triggers when plugin list changes
*/
@ -82,4 +81,12 @@ export interface ViewerProps {
* ByteMD plugin list
*/
plugins?: BytemdPlugin[];
/**
* An option to change the default sanitize schema.
*
* Defaults to GitHub style sanitation except that the `class` attribute is allowed
*
* https://github.com/syntax-tree/hast-util-sanitize/blob/main/lib/github.json
*/
sanitize?: (schema: any) => any;
}

View File

@ -7,12 +7,15 @@ import rehypeRaw from 'rehype-raw';
// @ts-ignore
import rehypeSanitize from 'rehype-sanitize';
import stringify from 'rehype-stringify';
import merge from 'deepmerge';
// @ts-ignore
import ghSchema from 'hast-util-sanitize/lib/github.json';
import { ViewerProps } from '.';
export function processMarkdown({ value, plugins = [] }: ViewerProps) {
export function processMarkdown({
value,
sanitize,
plugins = [],
}: ViewerProps) {
let parser = unified().use(remarkParse);
plugins.forEach(({ remark }) => {
@ -24,9 +27,8 @@ export function processMarkdown({ value, plugins = [] }: ViewerProps) {
.use(rehypeRaw);
let schema = ghSchema;
plugins.forEach(({ sanitizeSchema: markdownSanitizeSchema }) => {
if (markdownSanitizeSchema) schema = merge(schema, markdownSanitizeSchema);
});
schema.attributes['*'].push('className'); // Add className
if (sanitize) schema = sanitize(schema);
parser = parser.use(rehypeSanitize, schema);

View File

@ -9,6 +9,7 @@
export let value = '';
export let plugins = [];
export let sanitize = null;
let el;
const id = Date.now();
@ -23,7 +24,7 @@
}
onDestroy(off);
$: html = processMarkdown({ value, plugins });
$: html = processMarkdown({ value, plugins, sanitize });
$: if (html != null && plugins) {
off();
tick().then(() => {

View File

@ -6,7 +6,7 @@
import * as bytemd from 'bytemd';
export default {
props: ['value', 'plugins', 'mode', 'previewDebounce'],
props: ['value', 'plugins', 'sanitize', 'mode', 'previewDebounce'],
mounted() {
const editor = new bytemd.Editor({
target: this.$el,

View File

@ -6,13 +6,13 @@
import { processMarkdown } from 'bytemd';
export default {
props: ['value', 'plugins'],
props: ['value', 'plugins', 'sanitize'],
computed: {
html() {
return processMarkdown(this.$props);
},
needUpdate() {
return [this.html, this.plugins];
return [this.html, this.plugins, this.sanitize];
},
},
watch: {

View File

@ -7,11 +7,5 @@ export default function footnotes(options?: {
}): BytemdPlugin {
return {
remark: (u) => u.use(remarkFootnotes, options),
sanitizeSchema: {
attributes: {
div: ['className'],
a: ['className'],
},
},
};
}

View File

@ -17,10 +17,5 @@ export default function highlight({
}: HighlightOptions = {}): BytemdPlugin {
return {
rehype: (u) => u.use(rehypeHighlight, { subset, ignoreMissing, ...rest }),
sanitizeSchema: {
attributes: {
code: ['className'],
},
},
};
}

View File

@ -16,11 +16,5 @@ export default function math(options: Options = {}): BytemdPlugin {
return {
remark: (u) => u.use(remarkMath, options.math),
rehype: (u) => u.use(rehypeKatex, options.katex),
sanitizeSchema: {
attributes: {
div: ['className'],
span: ['className'],
},
},
};
}

View File

@ -3,11 +3,6 @@ import mermaidAPI from 'mermaid/mermaidAPI';
export default function mermaid(options?: mermaidAPI.Config): BytemdPlugin {
return {
sanitizeSchema: {
attributes: {
code: ['className'],
},
},
viewerEffect(el) {
const els = el.querySelectorAll<HTMLElement>('pre>code.language-mermaid');
if (els.length === 0) return;

View File

@ -2,11 +2,6 @@ import { BytemdPlugin } from 'bytemd';
export default function vega(): BytemdPlugin {
return {
sanitizeSchema: {
attributes: {
code: ['className'],
},
},
viewerEffect(el) {
const els = el.querySelectorAll<HTMLElement>('pre>code.language-vega');
if (els.length === 0) return;