Skip to content

Commit

Permalink
Merge pull request #52 from curvetips/htmlparser
Browse files Browse the repository at this point in the history
Use htmlparser2 to parse JSX
  • Loading branch information
cheton committed Nov 7, 2017
2 parents f97c328 + ca44678 commit 4cfff1f
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 43 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@
],
"dependencies": {
"esprima": "^4.0.0",
"htmlparser2": "^3.9.2",
"lodash": "^4.17.4",
"parse5": "^3.0.2",
"parse5": "^3.0.3",
"sortobject": "^1.1.1",
"through2": "^2.0.3",
"vinyl": "^2.1.0",
Expand Down
95 changes: 54 additions & 41 deletions src/jsx-parser.js
Original file line number Diff line number Diff line change
@@ -1,52 +1,65 @@
import parse5 from 'parse5'
import htmlparser from 'htmlparser2';

const jsExpr = /(.*?)({+[^]+?}+)(.*)/

function transform(node) {
let output = []
delete node.parentNode
if (node.nodeName === '#text') {
let text = node.value
let m = jsExpr.exec(node.value)
if (!m) {
return node
}
while ((m = jsExpr.exec(text))) {
if (m[1]) {
output.push({

export function parseJSX(fragment) {
const ast = {
nodeName: '#root',
childNodes: []
}
const stack = [ ast ]

const handler = {
onopentag: (name) => {
const node = {
nodeName: name,
childNodes: []
}
stack[0].childNodes.push(node)
stack.unshift(node)
},

onclosetag: () => {
stack.shift()
},

ontext: (text) => {
let txt = text
let m = jsExpr.exec(txt)
if (m) {
while ((m = jsExpr.exec(txt))) {
if (m[1]) {
stack[0].childNodes.push({
nodeName: '#text',
value: m[1],
childNodes: []
})
}
stack[0].childNodes.push({
nodeName: '#expression',
value: m[2],
childNodes: []
})
txt = m[3]
}
}
if (txt!=='') {
stack[0].childNodes.push({
nodeName: '#text',
value: m[1],
parentNode: node.parentNode
value: txt,
childNodes: []
})
}
output.push({
nodeName: '#expression',
value: m[2],
parentNode: node.parentNode
})
text = m[3]
}
if (text) {
output.push({
nodeName: '#text',
value: text,
parentNode: node.parentNode
})
}
} else {
node.childNodes = Array.prototype.concat.apply(
[],
node.childNodes.map(transform)
)
output.push(node)
}
return output
}

};

export function parseJSX(fragment) {
const ast = parse5.parseFragment(fragment)
return transform(ast)[0].childNodes
const parser = new htmlparser.Parser(handler, {
xmlMode: true,
decodeEntities: true
})
parser.write(fragment)
return stack[0].childNodes
}


Expand Down
17 changes: 16 additions & 1 deletion test/jsx-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,23 @@ test('JSX Nested expression', (t) => {
});


test('JSX child node', (t) => {
const ast = parseJSX('I agree to the <Link>terms</Link>.')
t.same(ast.length, 3)
t.same(ast[0].nodeName, '#text')
t.same(ast[1].nodeName, 'Link')
t.same(ast[1].childNodes.length, 1)
t.same(ast[1].childNodes[0].nodeName, '#text')
t.same(ast[1].childNodes[0].value, 'terms')
t.same(ast[2].nodeName, '#text')
t.same(ast[2].value, '.')
t.end();
});

test('JSX to i18next', (t) => {
t.same(jsxToText('Basic text'), 'Basic text')
t.same(jsxToText('Hello, {{name}}'), 'Hello, <1>{{name}}</1>')
t.same(jsxToText('I agree to the <Link>terms</Link>.'), 'I agree to the <1>terms</1>.')
t.same(jsxToText('One &amp; two'), 'One & two')
t.end()
})
})

0 comments on commit 4cfff1f

Please sign in to comment.