micro-mdx-parser
Version:
A tiny parser to convert markdown or html into JSON
1,273 lines (1,177 loc) • 31 kB
JavaScript
const { inspect } = require('util')
const { test } = require('uvu')
const assert = require('uvu/assert')
const { parse, stringify, validate } = require('.')
const { getTextBetweenChars } = require('./utils')
function deepLog(objOrLabel, logVal) {
let obj = objOrLabel
if (typeof objOrLabel === 'string') {
obj = logVal
console.log(objOrLabel)
}
console.log(inspect(obj, false, null, true))
}
function replaceTextBetweenChars(str = '', start, end, newStr) {
return str.substring(0, start) + newStr + str.substring(end)
}
test('Exports API', () => {
assert.equal(typeof parse, 'function')
assert.equal(typeof stringify, 'function')
})
const stringExample = `
Hello, world!
Below is an example of markdown in JSX.
<div style={{padding: '1rem', backgroundColor: 'violet'}}>
Try and change the background color to.
</div>
<MyComponent isCool />
<img src="w3schools.jpg" alt="W3Schools-img.com" width="104" height="142" />
`
const moreComplexStringExample = `
Hello, world!
Below is an example of markdown in JSX.
**Bold text** next to *italic text* and an example of <u>underlined text</u> & <mark>highlighting</mark> via html tag.
<div style={{padding: '1rem', backgroundColor: 'violet'}}>
Try and change the background color to.
</div>
<MyComponent isCool />
<img src="w3schools.jpg" alt="W3Schools-img.com" width="104" height="142" />
`
function escapeStringRegexp(string) {
// Escape characters with special meaning either inside or outside character sets.
// Use a simple backslash escape when it’s always valid, and a `\xnn` escape when the simpler form would be disallowed by Unicode patterns’ stricter grammar.
return string.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d')
}
function isInline(match, str) {
const pattern = new RegExp(`(\\s*)${escapeStringRegexp(str)}(\\s*)`)
const found = stringExample.match(pattern)
if (found) {
console.log('found leading/trailing', found)
}
}
test('simple md', () => {
const parsedValue = parse(stringExample)
/*
console.log('parsedValue')
deepLog(parsedValue)
console.log(getTextBetweenChars(stringExample, 189, 267))
process.exit(1)
/** */
const html = stringify(parsedValue)
/*
console.log('html')
console.log(html)
process.exit(1)
/** */
assert.equal(parsedValue, [
{
type: 'text',
content: '\nHello, world!\nBelow is an example of markdown in JSX.\n\n',
position: {
start: { index: 0, line: 1, column: 1 },
end: { index: 56, line: 5, column: 1 }
}
},
{
type: 'element',
tagName: 'div',
tagValue: "<div style={{padding: '1rem', backgroundColor: 'violet'}}>\n" +
' Try and change the background color to.\n' +
'</div>',
props: { style: { padding: '1rem', backgroundColor: 'violet' } },
propsRaw: " style={{padding: '1rem', backgroundColor: 'violet'}}",
children: [
{
type: 'text',
content: '\n Try and change the background color to.\n',
position: {
start: { index: 114, line: 5, column: 58 },
end: { index: 157, line: 7, column: 1 }
}
}
],
position: {
start: { index: 56, line: 5, column: 1 },
end: { index: 163, line: 7, column: 6 }
}
},
{
type: 'text',
content: '\n\n',
position: {
start: { index: 163, line: 7, column: 6 },
end: { index: 165, line: 9, column: 1 }
}
},
{
type: 'component',
tagName: 'MyComponent',
tagValue: '<MyComponent isCool />',
props: { isCool: true },
propsRaw: ' isCool ',
children: [],
isSelfClosing: true,
position: {
start: { index: 165, line: 9, column: 1 },
end: { index: 187, line: 9, column: 22 }
}
},
{
type: 'text',
content: '\n\n',
position: {
start: { index: 187, line: 9, column: 22 },
end: { index: 189, line: 11, column: 1 }
}
},
{
type: 'element',
tagName: 'img',
tagValue: '<img src="w3schools.jpg" alt="W3Schools-img.com" width="104" height="142" />',
props: {
src: 'w3schools.jpg',
alt: 'W3Schools-img.com',
width: '104',
height: '142'
},
propsRaw: ' src="w3schools.jpg" alt="W3Schools-img.com" width="104" height="142" ',
children: [],
isSelfClosing: true,
position: {
start: { index: 189, line: 11, column: 1 },
end: { index: 265, line: 11, column: 76 }
}
},
{
type: 'text',
content: '\n\n',
position: {
start: { index: 265, line: 11, column: 76 },
end: { index: 267, line: 13, column: 1 }
}
}
])
assert.equal(html, stringExample, 'html')
const myComponent = parsedValue.find((section) => section.tagName === 'MyComponent')
//console.log('myComponent', myComponent)
assert.equal(myComponent, {
type: 'component',
tagName: 'MyComponent',
tagValue: '<MyComponent isCool />',
props: { isCool: true },
propsRaw: ' isCool ',
children: [],
isSelfClosing: true,
position: {
start: { index: 165, line: 9, column: 1 },
end: { index: 187, line: 9, column: 22 }
}
}, 'found component is equal')
const componentText = getTextBetweenChars(stringExample, 165, 187)
// console.log('componentText')
// console.log(componentText)
})
const selfClosingTags = `
## Testing images
<MyComponent isCool/>
`
test('verify isSelfClosing set', () => {
const parsedValue = parse(selfClosingTags)
/*
console.log('parsedValue')
deepLog(parsedValue)
console.log(`"${getTextBetweenChars(selfClosingTags, 20, 41)}"`)
console.log(`${replaceTextBetweenChars(selfClosingTags, 20, 41, 'My thing')}`)
// console.log(`"${stringify(parsedValue)}"`)
process.exit(1)
/** */
assert.equal(parsedValue, [
{
type: 'text',
content: '\n## Testing images\n\n',
position: {
start: { index: 0, line: 1, column: 1 },
end: { index: 20, line: 4, column: 1 }
}
},
{
type: 'component',
tagName: 'MyComponent',
tagValue: '<MyComponent isCool/>',
props: { isCool: true },
propsRaw: ' isCool',
children: [],
isSelfClosing: true,
position: {
start: { index: 20, line: 4, column: 1 },
end: { index: 41, line: 4, column: 21 }
}
},
{
type: 'text',
content: '\n',
position: {
start: { index: 41, line: 4, column: 21 },
end: { index: 42, line: 5, column: 1 }
}
}
])
})
const withComments = `
## Hi
There
<!-- hehehhehehe -->
Cool
`
test('withComments', () => {
const parsedValue = parse(withComments)
const commentText = getTextBetweenChars(withComments, 15, 35)
/*
console.log('commentText')
console.log(commentText)
deepLog(parsedValue)
process.exit(1)
/** */
assert.equal(parsedValue, [
{
type: 'text',
content: '\n## Hi\n\nThere\n\n',
position: {
start: { index: 0, line: 1, column: 1 },
end: { index: 15, line: 6, column: 1 }
}
},
{
type: 'comment',
content: ' hehehhehehe ',
position: {
start: { index: 15, line: 6, column: 1 },
end: { index: 35, line: 6, column: 20 }
}
},
{
type: 'text',
content: '\n\nCool\n',
position: {
start: { index: 35, line: 6, column: 20 },
end: { index: 42, line: 9, column: 1 }
}
}
])
})
const invalidImgTag = `
Hello, world!
Below is an example of markdown in JSX.
<img src="cool.jpg" alt="nice-img.com" width="104" height="142" >
<div style={{padding: '1rem', backgroundColor: 'violet'}}>
Try and change the background color to.
</div>
<MyComponent isCool />
<img src="w3schools.jpg" alt="W3Schools-img.com" width="104" height="142" >
`
test('Validate markup', () => {
const parsedValue = parse(invalidImgTag)
const errors = validate(parsedValue)
const errorsViaStr = validate(invalidImgTag)
/*
deepLog(errors)
deepLog(errorsViaStr)
process.exit(1)
/** */
const answer = [
{
message: 'Missing closing "/>" on "element". <img src="cool.jpg" alt="nice-img.com" width="104" height="142" >',
value: '<img src="cool.jpg" alt="nice-img.com" width="104" height="142" >',
position: {
start: { index: 56, line: 5, column: 1 },
end: { index: 121, line: 5, column: 65 }
}
},
{
message: 'Missing closing "/>" on "element". <img src="w3schools.jpg" alt="W3Schools-img.com" width="104" height="142" >',
value: '<img src="w3schools.jpg" alt="W3Schools-img.com" width="104" height="142" >',
position: {
start: { index: 256, line: 13, column: 1 },
end: { index: 331, line: 13, column: 75 }
}
}
]
assert.equal(errors.length, 2)
assert.equal(errorsViaStr.length, 2)
assert.equal(errors, answer)
assert.equal(errorsViaStr, answer, 'errorsViaStr')
})
test('inline <https://www.markdown-link-test.org> links', () => {
const md = `
<div>gfoo</div>
<div> </div>
<https://www.markdownguide.org>
<fake@example.com>
`
const parsedValue = parse(md)
// deepLog(parsedValue)
assert.equal(parsedValue, [
{
type: 'text',
content: '\n',
position: {
start: { index: 0, line: 1, column: 1 },
end: { index: 1, line: 2, column: 1 }
}
},
{
type: 'element',
tagName: 'div',
tagValue: '<div>gfoo</div>',
props: {},
propsRaw: '',
children: [
{
type: 'text',
content: 'gfoo',
position: {
start: { index: 6, line: 2, column: 5 },
end: { index: 10, line: 2, column: 9 }
}
}
],
position: {
start: { index: 1, line: 2, column: 1 },
end: { index: 16, line: 2, column: 15 }
}
},
{
type: 'text',
content: '\n\n ',
position: {
start: { index: 16, line: 2, column: 15 },
end: { index: 20, line: 4, column: 2 }
}
},
{
type: 'element',
tagName: 'div',
tagValue: '<div> </div>',
props: {},
propsRaw: '',
children: [
{
type: 'text',
content: ' ',
position: {
start: { index: 25, line: 4, column: 7 },
end: { index: 26, line: 4, column: 8 }
}
}
],
position: {
start: { index: 20, line: 4, column: 2 },
end: { index: 32, line: 4, column: 14 }
}
},
{
type: 'text',
content: '\n \n <https://www.markdownguide.org>\n <fake@example.com>\n',
position: {
start: { index: 32, line: 4, column: 14 },
end: { index: 91, line: 8, column: 1 }
}
}
])
})
test('Single line react style props', () => {
const singleLineProps = `
<div id="nice" style={{ padding: '1rem', backgroundColor: 'violet' }}>
Try and change the background color to.
</div>
`.trim()
const parsedValue = parse(singleLineProps)
// deepLog(parsedValue)
assert.equal(parsedValue, [
{
type: 'element',
tagName: 'div',
tagValue: `<div id="nice" style={{ padding: '1rem', backgroundColor: 'violet' }}>\n` +
' Try and change the background color to.\n' +
'</div>',
props: {
id: 'nice',
style: { padding: '1rem', backgroundColor: 'violet' }
},
propsRaw: ` id="nice" style={{ padding: '1rem', backgroundColor: 'violet' }}`,
children: [
{
type: 'text',
content: '\n Try and change the background color to.\n',
position: {
start: { index: 70, line: 1, column: 71 },
end: { index: 113, line: 3, column: 1 }
}
}
],
position: {
start: { index: 0, line: 1, column: 1 },
end: { index: 119, line: 3, column: 6 }
}
}
])
const divText = getTextBetweenChars(singleLineProps, parsedValue[0].position.start.index, parsedValue[0].position.end.index)
assert.equal(divText, singleLineProps, 'divText matches position indexes')
})
test('inner component props {()}', () => {
const multiLineProps = `
<div
innerComponent={(
<span>cool</span>
)}
>
Try and change the background color to.
</div>
`
const parsedValue = parse(multiLineProps)
// deepLog(parsedValue)
})
test('Handles inline functions', () => {
const inlineFn = `
<div onClick={() => console.log('hi')}>
click
</div>
`
const parsedValue = parse(inlineFn)
// deepLog(parsedValue)
assert.equal(parsedValue[1].props.onClick, "() => console.log('hi')")
})
test('Handles multiline functions', () => {
const inlineFn = `
<div
onClick={(arg) => {
console.log('hi')
}}
>
click
</div>
`
const parsedValue = parse(inlineFn)
// deepLog(parsedValue)
assert.equal(parsedValue[1].props.onClick, `(arg) => {
console.log('hi')
}`)
})
test('Handles multiline functions two', () => {
const inlineFn = `
<div onClick={
() => {
console.log('hi')
}
}>
click
</div>
`
const parsedValue = parse(inlineFn)
// deepLog(parsedValue)
assert.equal(parsedValue[1].props.onClick, `
() => {
console.log('hi')
}
`)
})
const b = `
<div onClick={() => console.log('hi')}>
click
</div>
<div onClick={
() => {
console.log('hi')
}
}>
click
</div>
`
test('inner component props {()}', () => {
const broken = `
<Nested
customElement={(
<div>Custom div</div>
)}
htmlContent={(
<span style={{ color: 'red' }} color="b'lue">This should be red too</span>
)}
>
check it
</Nested>
`
const parsedValue = parse(broken)
// deepLog(parsedValue)
assert.equal(parsedValue[1].props, {
customElement: '\n <div>Custom div</div>\n ',
htmlContent: '\n' +
` <span style={{ color: 'red' }} color="b'lue">This should be red too</span>\n` +
' '
},
'props match'
)
assert.equal(parsedValue[1].propsRaw, '\n' +
' customElement={(\n' +
' <div>Custom div</div>\n' +
' )}\n' +
' htmlContent={(\n' +
` <span style={{ color: 'red' }} color="b'lue">This should be red too</span>\n` +
' )}\n',
'propsRaw match'
)
})
test.skip('inner component props {{}}', () => {
const broken = `
<Nested buttonText={{<span>Nice. dudeee</span>}}>\n check it\n</Nested>
`
const parsedValue = parse(broken)
deepLog(parsedValue)
})
test('Handles multiline components with inner html props', () => {
const broken = `
<Nested
customElement={(
<div>Custom div</div>
)}
htmlContent={(
<span style={{ color: 'red' }}>This should be red too</span>
)}
customElementTwo={(
<div id="foo" style={{ color: 'purple' }}>
This should be purple too
<div style={{ color: 'green' }}>
This should be red too
</div>
</div>
)}
>
check it
</Nested>
`
const parsedValue = parse(broken)
/*
deepLog(parsedValue)
/** */
assert.equal(parsedValue, [
{
type: 'text',
content: '\n',
position: {
start: { index: 0, line: 1, column: 1 },
end: { index: 1, line: 2, column: 1 }
}
},
{
type: 'component',
tagName: 'Nested',
tagValue: '<Nested\n' +
' customElement={(\n' +
' <div>Custom div</div>\n' +
' )}\n' +
' htmlContent={(\n' +
" <span style={{ color: 'red' }}>This should be red too</span>\n" +
' )}\n' +
' customElementTwo={(\n' +
` <div id="foo" style={{ color: 'purple' }}>\n` +
' This should be purple too\n' +
" <div style={{ color: 'green' }}>\n" +
' This should be red too\n' +
' </div>\n' +
' </div>\n' +
' )}\n' +
'>\n' +
' check it\n' +
'</Nested>',
props: {
customElement: '\n <div>Custom div</div>\n ',
htmlContent: "\n <span style={{ color: 'red' }}>This should be red too</span>\n ",
customElementTwo: '\n' +
` <div id="foo" style={{ color: 'purple' }}>\n` +
' This should be purple too\n' +
" <div style={{ color: 'green' }}>\n" +
' This should be red too\n' +
' </div>\n' +
' </div>\n' +
' '
},
propsRaw: '\n' +
' customElement={(\n' +
' <div>Custom div</div>\n' +
' )}\n' +
' htmlContent={(\n' +
" <span style={{ color: 'red' }}>This should be red too</span>\n" +
' )}\n' +
' customElementTwo={(\n' +
` <div id="foo" style={{ color: 'purple' }}>\n` +
' This should be purple too\n' +
" <div style={{ color: 'green' }}>\n" +
' This should be red too\n' +
' </div>\n' +
' </div>\n' +
' )}\n',
children: [
{
type: 'text',
content: '\n check it\n',
position: {
start: { index: 347, line: 17, column: 1 },
end: { index: 359, line: 19, column: 1 }
}
}
],
position: {
start: { index: 1, line: 2, column: 1 },
end: { index: 368, line: 19, column: 9 }
}
},
{
type: 'text',
content: '\n',
position: {
start: { index: 368, line: 19, column: 9 },
end: { index: 369, line: 20, column: 1 }
}
}
])
})
test('Multiline props', () => {
const multiLineProps = `
Hello, world!
<div
style={{
padding: '1rem',
backgroundColor: 'violet'
}}
>
Try and change the background color to.
</div>
`
const parsedValue = parse(multiLineProps)
// deepLog(parsedValue)
// console.log(getTextBetweenChars(multiLineProps, 16, 133))
assert.equal(parsedValue, [
{
type: 'text',
content: '\nHello, world!\n\n',
position: {
start: { index: 0, line: 1, column: 1 },
end: { index: 16, line: 4, column: 1 }
}
},
{
type: 'element',
tagName: 'div',
tagValue: '<div \n' +
' style={{\n' +
" padding: '1rem', \n" +
" backgroundColor: 'violet'\n" +
' }}\n' +
'>\n' +
' Try and change the background color to.\n' +
'</div>',
props: { style: { padding: '1rem', backgroundColor: 'violet' } },
propsRaw: ' \n' +
' style={{\n' +
" padding: '1rem', \n" +
" backgroundColor: 'violet'\n" +
' }}\n',
children: [
{
type: 'text',
content: '\n Try and change the background color to.\n',
position: {
start: { index: 94, line: 9, column: 1 },
end: { index: 137, line: 11, column: 1 }
}
}
],
position: {
start: { index: 16, line: 4, column: 1 },
end: { index: 143, line: 11, column: 6 }
}
},
{
type: 'text',
content: '\n',
position: {
start: { index: 143, line: 11, column: 6 },
end: { index: 144, line: 12, column: 1 }
}
}
])
})
test('Multiline props two', () => {
const multiLineProps = `
Hello, world!
<div style={{
padding: '1rem',
backgroundColor: 'violet'
}}>
Try and change the background color to.
</div>
<MyComponent isCool={\`
multi
line
\`} />
<MyComponentTwoIndents isCool={\`
multi
line
\`} />
xyz
`
const parsedValue = parse(multiLineProps)
// deepLog(parsedValue)
assert.equal(parsedValue, [
{
type: 'text',
content: '\nHello, world!\n\n',
position: {
start: { index: 0, line: 1, column: 1 },
end: { index: 16, line: 4, column: 1 }
}
},
{
type: 'element',
tagName: 'div',
tagValue: '<div style={{\n' +
" padding: '1rem', \n" +
" backgroundColor: 'violet'\n" +
'}}>\n' +
' Try and change the background color to.\n' +
'</div>',
props: { style: { padding: '1rem', backgroundColor: 'violet' } },
propsRaw: " style={{\n padding: '1rem', \n backgroundColor: 'violet'\n}}",
children: [
{
type: 'text',
content: '\n Try and change the background color to.\n',
position: {
start: { index: 81, line: 7, column: 3 },
end: { index: 124, line: 9, column: 1 }
}
}
],
position: {
start: { index: 16, line: 4, column: 1 },
end: { index: 130, line: 9, column: 6 }
}
},
{
type: 'text',
content: '\n\n',
position: {
start: { index: 130, line: 9, column: 6 },
end: { index: 132, line: 11, column: 1 }
}
},
{
type: 'component',
tagName: 'MyComponent',
tagValue: '<MyComponent isCool={`\nmulti\nline\n`} />',
props: { isCool: '\nmulti\nline\n' },
propsRaw: ' isCool={`\nmulti\nline\n`} ',
children: [],
isSelfClosing: true,
position: {
start: { index: 132, line: 11, column: 1 },
end: { index: 171, line: 14, column: 5 }
}
},
{
type: 'text',
content: '\n\n',
position: {
start: { index: 171, line: 14, column: 5 },
end: { index: 173, line: 16, column: 1 }
}
},
{
type: 'component',
tagName: 'MyComponentTwoIndents',
tagValue: '<MyComponentTwoIndents isCool={`\n multi\n line\n`} />',
props: { isCool: '\n multi\n line\n' },
propsRaw: ' isCool={`\n multi\n line\n`} ',
children: [],
isSelfClosing: true,
position: {
start: { index: 173, line: 16, column: 1 },
end: { index: 226, line: 19, column: 5 }
}
},
{
type: 'text',
content: '\n\nxyz\n',
position: {
start: { index: 226, line: 19, column: 5 },
end: { index: 232, line: 22, column: 1 }
}
}
])
})
test('Innner jsx props', () => {
const inlineComponentProp = `
<Nested buttonText={\`<span>Niceeee</span>\`}>
check it
</Nested>
`
const inlineComponentPropTwo = `
<Nested buttonText={<span>Niceeee</span>}>
check it
</Nested>
`
const parsedValue = parse(inlineComponentPropTwo)
// deepLog(parsedValue)
// process.exit(1)
assert.equal(parsedValue, [
{
type: 'text',
content: '\n ',
position: {
start: { index: 0, line: 1, column: 1 },
end: { index: 3, line: 2, column: 2 }
}
},
{
type: 'component',
tagName: 'Nested',
tagValue: '<Nested buttonText={<span>Niceeee</span>}>\n check it\n </Nested>',
props: { buttonText: '<span>Niceeee</span>' },
propsRaw: ' buttonText={<span>Niceeee</span>}',
children: [
{
type: 'text',
content: '\n check it\n ',
position: {
start: { index: 45, line: 2, column: 44 },
end: { index: 61, line: 4, column: 2 }
}
}
],
position: {
start: { index: 3, line: 2, column: 2 },
end: { index: 70, line: 4, column: 11 }
}
},
{
type: 'text',
content: '\n ',
position: {
start: { index: 70, line: 4, column: 11 },
end: { index: 73, line: 5, column: 2 }
}
}
])
})
const HTML_WITH_NESTED_COMPONENTS = `
Now
<button>xcool</button>
I can authorxxx with stuff brokjen
<Builder
components={[{
type: "content",
content: "Content here...\n\n<Builder\n components={[{ type: \"content\", content: \"Content here... woah\" }]}\n/>"
}]}
/>
<Builder beans=true>cool</Builder>
<OBuilder
components={[{
type: "content",
content: "Content here...\n\n<Builder\n components={[{\n type: \"content\",\n content: \"Content here... woah nice\\n\\n<Builder\\n components={[{ type: \\\"content\\\", content: \\\"Content here... deeeeep\\\" }]}\\n/>\"\n }]}\n/>"
}]}
/>
<MyComponent isCool={\`
multi
line
\`} />
<MyComponentTwoIndents isCool={\`
multi
line
\`} more pros=true />
<img src="w3schools.jpg" alt="W3Schools-img.com" width="104" height="142" />
<Bool>cool</Bool>
`
test('HTML_WITH_NESTED_COMPONENTS', () => {
const parsedValue = parse(HTML_WITH_NESTED_COMPONENTS)
/*
deepLog('nested', parsedValue)
/** */
assert.equal(parsedValue, [
{
type: 'text',
content: '\nNow\n\n',
position: {
start: { index: 0, line: 1, column: 1 },
end: { index: 6, line: 4, column: 1 }
}
},
{
type: 'element',
tagName: 'button',
tagValue: '<button>xcool</button>',
props: {},
propsRaw: '',
children: [
{
type: 'text',
content: 'xcool',
position: {
start: { index: 14, line: 4, column: 8 },
end: { index: 19, line: 4, column: 13 }
}
}
],
position: {
start: { index: 6, line: 4, column: 1 },
end: { index: 28, line: 4, column: 22 }
}
},
{
type: 'text',
content: '\n\nI can authorxxx with stuff brokjen\n\n',
position: {
start: { index: 28, line: 4, column: 22 },
end: { index: 66, line: 8, column: 1 }
}
},
{
type: 'component',
tagName: 'Builder',
tagValue: '<Builder\n' +
' components={[{\n' +
' type: "content",\n' +
' content: "Content here...\n' +
'\n' +
'<Builder\n' +
' components={[{ type: "content", content: "Content here... woah" }]}\n' +
'/>"\n' +
' }]}\n' +
'/>',
props: {
components: [
{
type: 'content',
content: 'Content here...\n' +
'\n' +
'<Builder\n' +
' components={[{ type: "content", content: "Content here... woah" }]}\n' +
'/>'
}
]
},
propsRaw: '\n' +
' components={[{\n' +
' type: "content",\n' +
' content: "Content here...\n' +
'\n' +
'<Builder\n' +
' components={[{ type: "content", content: "Content here... woah" }]}\n' +
'/>"\n' +
' }]}\n',
children: [],
isSelfClosing: true,
position: {
start: { index: 66, line: 8, column: 1 },
end: { index: 235, line: 17, column: 2 }
}
},
{
type: 'text',
content: '\n\n',
position: {
start: { index: 235, line: 17, column: 2 },
end: { index: 237, line: 19, column: 1 }
}
},
{
type: 'component',
tagName: 'Builder',
tagValue: '<Builder beans=true>cool</Builder>',
props: { beans: true },
propsRaw: ' beans=true',
children: [
{
type: 'text',
content: 'cool',
position: {
start: { index: 257, line: 19, column: 20 },
end: { index: 261, line: 19, column: 24 }
}
}
],
position: {
start: { index: 237, line: 19, column: 1 },
end: { index: 271, line: 19, column: 34 }
}
},
{
type: 'text',
content: '\n\n',
position: {
start: { index: 271, line: 19, column: 34 },
end: { index: 273, line: 21, column: 1 }
}
},
{
type: 'component',
tagName: 'OBuilder',
tagValue: '<OBuilder\n' +
' components={[{\n' +
' type: "content",\n' +
' content: "Content here...\n' +
'\n' +
'<Builder\n' +
' components={[{\n' +
' type: "content",\n' +
' content: "Content here... woah nice\\n\\n<Builder\\n components={[{ type: \\"content\\", content: \\"Content here... deeeeep\\" }]}\\n/>"\n' +
' }]}\n' +
'/>"\n' +
' }]}\n' +
'/>',
props: {
components: [
{
type: 'content',
content: 'Content here...\n' +
'\n' +
'<Builder\n' +
' components={[{\n' +
' type: "content",\n' +
' content: "Content here... woah nice\n' +
'\n' +
'<Builder\n' +
' components={[{ type: "content", content: "Content here... deeeeep" }]}\n' +
'/>"\n' +
' }]}\n' +
'/>'
}
]
},
propsRaw: '\n' +
' components={[{\n' +
' type: "content",\n' +
' content: "Content here...\n' +
'\n' +
'<Builder\n' +
' components={[{\n' +
' type: "content",\n' +
' content: "Content here... woah nice\\n\\n<Builder\\n components={[{ type: \\"content\\", content: \\"Content here... deeeeep\\" }]}\\n/>"\n' +
' }]}\n' +
'/>"\n' +
' }]}\n',
children: [],
isSelfClosing: true,
position: {
start: { index: 273, line: 21, column: 1 },
end: { index: 552, line: 33, column: 2 }
}
},
{
type: 'text',
content: '\n\n',
position: {
start: { index: 552, line: 33, column: 2 },
end: { index: 554, line: 35, column: 1 }
}
},
{
type: 'component',
tagName: 'MyComponent',
tagValue: '<MyComponent isCool={`\nmulti\nline\n`} />',
props: { isCool: '\nmulti\nline\n' },
propsRaw: ' isCool={`\nmulti\nline\n`} ',
children: [],
isSelfClosing: true,
position: {
start: { index: 554, line: 35, column: 1 },
end: { index: 593, line: 38, column: 5 }
}
},
{
type: 'text',
content: '\n\n',
position: {
start: { index: 593, line: 38, column: 5 },
end: { index: 595, line: 40, column: 1 }
}
},
{
type: 'component',
tagName: 'MyComponentTwoIndents',
tagValue: '<MyComponentTwoIndents isCool={`\n multi\n line\n`} more pros=true />',
props: { isCool: '\n multi\n line\n', more: true, pros: true },
propsRaw: ' isCool={`\n multi\n line\n`} more pros=true ',
children: [],
isSelfClosing: true,
position: {
start: { index: 595, line: 40, column: 1 },
end: { index: 663, line: 43, column: 20 }
}
},
{
type: 'text',
content: '\n\n',
position: {
start: { index: 663, line: 43, column: 20 },
end: { index: 665, line: 45, column: 1 }
}
},
{
type: 'element',
tagName: 'img',
tagValue: '<img src="w3schools.jpg" alt="W3Schools-img.com" width="104" height="142" />',
props: {
src: 'w3schools.jpg',
alt: 'W3Schools-img.com',
width: '104',
height: '142'
},
propsRaw: ' src="w3schools.jpg" alt="W3Schools-img.com" width="104" height="142" ',
children: [],
isSelfClosing: true,
position: {
start: { index: 665, line: 45, column: 1 },
end: { index: 741, line: 45, column: 76 }
}
},
{
type: 'text',
content: '\n\n',
position: {
start: { index: 741, line: 45, column: 76 },
end: { index: 743, line: 47, column: 1 }
}
},
{
type: 'component',
tagName: 'Bool',
tagValue: '<Bool>cool</Bool>',
props: {},
propsRaw: '',
children: [
{
type: 'text',
content: 'cool',
position: {
start: { index: 749, line: 47, column: 6 },
end: { index: 753, line: 47, column: 10 }
}
}
],
position: {
start: { index: 743, line: 47, column: 1 },
end: { index: 760, line: 47, column: 17 }
}
},
{
type: 'text',
content: '\n',
position: {
start: { index: 760, line: 47, column: 17 },
end: { index: 761, line: 48, column: 1 }
}
}
],
'props match'
)
})
test.run()