mirror of
				https://github.com/explosion/spaCy.git
				synced 2025-11-04 01:48:04 +03:00 
			
		
		
		
	Add plugin for custom attributes on Markdown elements
This commit is contained in:
		
							parent
							
								
									343c0054f2
								
							
						
					
					
						commit
						4340a9a248
					
				| 
						 | 
					@ -1,6 +1,8 @@
 | 
				
			||||||
 | 
					import remarkCustomAttrs from './remarkCustomAttrs.mjs'
 | 
				
			||||||
import remarkWrapSections from './remarkWrapSections.mjs'
 | 
					import remarkWrapSections from './remarkWrapSections.mjs'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const remarkPlugins = [
 | 
					const remarkPlugins = [
 | 
				
			||||||
 | 
					    remarkCustomAttrs,
 | 
				
			||||||
    remarkWrapSections,
 | 
					    remarkWrapSections,
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,55 +1,71 @@
 | 
				
			||||||
/**
 | 
					const parseAttribute = (expression) => {
 | 
				
			||||||
 * Simplified implementation of remark-attr that allows custom attributes on
 | 
					    if (expression.type !== 'AssignmentExpression' || !expression.left || !expression.right) {
 | 
				
			||||||
 * nodes *inline* via the following syntax: {#some-id key="value"}. Extracting
 | 
					        return
 | 
				
			||||||
 * them inline is slightly hackier (at least in this implementation), but it
 | 
					 | 
				
			||||||
 * makes the resulting markup valid and compatible with formatters like
 | 
					 | 
				
			||||||
 * Prettier, which do not allow additional content right below headlines.
 | 
					 | 
				
			||||||
 * Based on: https://github.com/arobase-che/remark-attr
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const visit = require('unist-util-visit')
 | 
					 | 
				
			||||||
const parseAttr = require('md-attr-parser')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const defaultOptions = {
 | 
					 | 
				
			||||||
    elements: ['heading', 'link'],
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function remarkCustomAttrs(userOptions = {}) {
 | 
					    const { left, right } = expression
 | 
				
			||||||
    const options = Object.assign({}, defaultOptions, userOptions)
 | 
					
 | 
				
			||||||
    function transformer(tree) {
 | 
					    if (left.type !== 'Identifier' || right.type !== 'Literal' || !left.name || !right.value) {
 | 
				
			||||||
        visit(tree, null, (node) => {
 | 
					        return
 | 
				
			||||||
            if (options.elements.includes(node.type)) {
 | 
					 | 
				
			||||||
                if (
 | 
					 | 
				
			||||||
                    node.children &&
 | 
					 | 
				
			||||||
                    node.children.length &&
 | 
					 | 
				
			||||||
                    node.children[0].type === 'text' &&
 | 
					 | 
				
			||||||
                    node.children[0].value
 | 
					 | 
				
			||||||
                ) {
 | 
					 | 
				
			||||||
                    if (
 | 
					 | 
				
			||||||
                        node.children.length > 1 &&
 | 
					 | 
				
			||||||
                        node.children.every((el) => el.type === 'text')
 | 
					 | 
				
			||||||
                    ) {
 | 
					 | 
				
			||||||
                        // If headlines contain escaped characters, e.g.
 | 
					 | 
				
			||||||
                        // Doc.\_\_init\_\_, it will be split into several nodes
 | 
					 | 
				
			||||||
                        const mergedText = node.children.map((el) => el.value).join('')
 | 
					 | 
				
			||||||
                        node.children[0].value = mergedText
 | 
					 | 
				
			||||||
                        node.children = [node.children[0]]
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
                    const parsed = node.children[0].value.split(/\{(.*?)\}/)
 | 
					
 | 
				
			||||||
                    if (parsed.length >= 2 && parsed[1]) {
 | 
					    return { type: 'mdxJsxAttribute', name: left.name, value: right.value }
 | 
				
			||||||
                        const text = parsed[0].trim()
 | 
					}
 | 
				
			||||||
                        const { prop } = parseAttr(parsed[1])
 | 
					
 | 
				
			||||||
                        const data = node.data || (node.data = {})
 | 
					const handleNode = (node) => {
 | 
				
			||||||
                        const hProps = data.hProperties || (data.hProperties = {})
 | 
					    if (node.type === 'section' && node.children) {
 | 
				
			||||||
                        node.data.hProperties = Object.assign({}, hProps, prop)
 | 
					        return {
 | 
				
			||||||
                        node.children[0].value = text
 | 
					            ...node,
 | 
				
			||||||
 | 
					            children: node.children.map(handleNode),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (node.type !== 'heading' || !node.children || node.children < 2) {
 | 
				
			||||||
 | 
					        return node
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const indexLast = node.children.length - 1
 | 
				
			||||||
 | 
					    const lastNode = node.children[indexLast]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (lastNode.type !== 'mdxTextExpression' || !lastNode.data || !lastNode.data.estree) {
 | 
				
			||||||
 | 
					        return node
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { estree } = lastNode.data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (estree.type !== 'Program' || !estree.body || estree.body.length <= 0 || !estree.body[0]) {
 | 
				
			||||||
 | 
					        return node
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const estreeBodyFirstNode = estree.body[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (estreeBodyFirstNode.type !== 'ExpressionStatement' || !estreeBodyFirstNode.expression) {
 | 
				
			||||||
 | 
					        return node
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const statement = estreeBodyFirstNode.expression
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const attributeExpressions = [
 | 
				
			||||||
 | 
					        ...(statement.type === 'SequenceExpression' && statement.expressions
 | 
				
			||||||
 | 
					            ? statement.expressions
 | 
				
			||||||
 | 
					            : []),
 | 
				
			||||||
 | 
					        ...(statement.type === 'AssignmentExpression' ? [statement] : []),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // This replaces the markdown heading with a JSX element
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					        type: 'mdxJsxFlowElement',
 | 
				
			||||||
 | 
					        name: `h${node.depth}`,
 | 
				
			||||||
 | 
					        attributes: attributeExpressions.map(parseAttribute),
 | 
				
			||||||
 | 
					        children: [node.children[0]],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const parseAstTree = (markdownAST) => ({
 | 
				
			||||||
 | 
					    ...markdownAST,
 | 
				
			||||||
 | 
					    children: markdownAST.children.map(handleNode),
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
        return tree
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return transformer
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports = remarkCustomAttrs
 | 
					const remarkCustomAttrs = () => parseAstTree
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default remarkCustomAttrs
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user