Skip to content

Commit 491482d

Browse files
committed
.
0 parents  commit 491482d

File tree

11 files changed

+1508
-0
lines changed

11 files changed

+1508
-0
lines changed

.editorconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
root = true
2+
3+
[*]
4+
indent_style = space
5+
indent_size = 2
6+
end_of_line = lf
7+
charset = utf-8
8+
trim_trailing_whitespace = true
9+
insert_final_newline = true

.github/workflows/main.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: main
2+
on:
3+
- pull_request
4+
- push
5+
jobs:
6+
main:
7+
name: '${{ matrix.node }}'
8+
runs-on: ubuntu-latest
9+
steps:
10+
- uses: actions/checkout@v2
11+
- uses: dcodeIO/setup-node-nvm@master
12+
with:
13+
node-version: ${{ matrix.node }}
14+
- run: npm install
15+
- run: npm test
16+
- uses: codecov/codecov-action@v1
17+
strategy:
18+
matrix:
19+
node:
20+
- lts/dubnium
21+
- node

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.DS_Store
2+
*.log
3+
.nyc_output/
4+
coverage/
5+
node_modules/
6+
yarn.lock

.npmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package-lock=false

.prettierignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
coverage/
2+
*.json
3+
*.md

funding.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
github: wooorm

index.js

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
'use strict'
2+
3+
module.exports = buildJsx
4+
5+
var walk = require('estree-walker').walk
6+
var isIdentifierName = require('estree-util-is-identifier-name').name
7+
8+
function buildJsx(tree, options) {
9+
var settings = options || {}
10+
var pragma = settings.pragma
11+
var pragmaFrag = settings.pragmaFrag
12+
13+
walk(tree, {enter: enter, leave: leave})
14+
15+
return tree
16+
17+
// When entering the program, check all comments, and prefer comments over
18+
// config.
19+
function enter(node) {
20+
var comments
21+
var index
22+
var match
23+
24+
if (node.type === 'Program') {
25+
comments = node.comments || []
26+
index = -1
27+
28+
while (++index < comments.length) {
29+
if ((match = /@jsx\s+(\S+)/.exec(comments[index].value))) {
30+
pragma = match[1]
31+
}
32+
33+
if ((match = /@jsxFrag\s+(\S+)/.exec(comments[index].value))) {
34+
pragmaFrag = match[1]
35+
}
36+
}
37+
}
38+
}
39+
40+
// Transform JSX.
41+
// eslint-disable-next-line complexity
42+
function leave(node) {
43+
var parameters
44+
var fields
45+
var objects
46+
var index
47+
var child
48+
var name
49+
var props
50+
var attributes
51+
52+
if (node.type !== 'JSXElement' && node.type !== 'JSXFragment') {
53+
return
54+
}
55+
56+
parameters = []
57+
index = -1
58+
59+
// Figure out `children`.
60+
while (++index < node.children.length) {
61+
child = node.children[index]
62+
63+
if (child.type === 'JSXExpressionContainer') {
64+
child = child.expression
65+
66+
// Ignore empty expressions.
67+
if (child.type === 'JSXEmptyExpression') continue
68+
} else if (child.type === 'JSXText') {
69+
child = create(child, {
70+
type: 'Literal',
71+
value: child.value
72+
// Replace tabs w/ spaces.
73+
.replace(/\t/g, ' ')
74+
// Use line feeds, drop spaces around them.
75+
.replace(/ *(\r?\n|\r) */g, '\n')
76+
// Collapse multiple line feeds.
77+
.replace(/\n+/g, '\n')
78+
// Drop final line feeds.
79+
.replace(/\n+$/, '')
80+
// Replace line feeds with spaces.
81+
.replace(/\n/g, ' ')
82+
})
83+
84+
// Ignore collapsible text.
85+
if (!child.value) continue
86+
}
87+
// Otherwise, this is an already compiled call.
88+
89+
parameters.push(child)
90+
}
91+
92+
// Do the stuff needed for elements.
93+
if (node.openingElement) {
94+
name = toIdentifier(node.openingElement.name)
95+
96+
// If the name could be an identifier, but start with something other than
97+
// a lowercase letter, it’s not a component.
98+
if (name.type === 'Identifier' && /^[a-z]/.test(name.name)) {
99+
name = create(name, {type: 'Literal', value: name.name})
100+
}
101+
102+
attributes = node.openingElement.attributes
103+
objects = []
104+
fields = []
105+
index = -1
106+
107+
// Place props in the right order, because we might have duplicates
108+
// in them and what’s spread in.
109+
while (++index < attributes.length) {
110+
if (attributes[index].type === 'JSXSpreadAttribute') {
111+
if (fields.length) {
112+
objects.push({type: 'ObjectExpression', properties: fields})
113+
fields = []
114+
}
115+
116+
objects.push(attributes[index].argument)
117+
} else {
118+
fields.push(toProperty(attributes[index]))
119+
}
120+
}
121+
122+
if (fields.length) {
123+
objects.push({type: 'ObjectExpression', properties: fields})
124+
}
125+
126+
if (objects.length > 1) {
127+
// Don’t mutate the first object, shallow clone instead.
128+
if (objects[0].type !== 'ObjectExpression') {
129+
objects.unshift({type: 'ObjectExpression', properties: []})
130+
}
131+
132+
props = {
133+
type: 'CallExpression',
134+
callee: toMemberExpression('Object.assign'),
135+
arguments: objects
136+
}
137+
} else if (objects.length) {
138+
props = objects[0]
139+
}
140+
}
141+
// …and fragments.
142+
else {
143+
name = toMemberExpression(pragmaFrag || 'React.Fragment')
144+
}
145+
146+
// There are props or children.
147+
if (props || parameters.length) {
148+
parameters.unshift(props || {type: 'Literal', value: null})
149+
}
150+
151+
parameters.unshift(name)
152+
153+
this.replace(
154+
create(node, {
155+
type: 'CallExpression',
156+
callee: toMemberExpression(pragma || 'React.createElement'),
157+
arguments: parameters
158+
})
159+
)
160+
}
161+
}
162+
163+
function toProperty(node) {
164+
var value
165+
166+
if (node.value) {
167+
if (node.value.type === 'JSXExpressionContainer') {
168+
value = node.value.expression
169+
}
170+
// Could be an element, fragment, or string.
171+
else {
172+
value = node.value
173+
// Remove `raw` so we don’t get character references in strings.
174+
delete value.raw
175+
}
176+
}
177+
// Boolean prop.
178+
else {
179+
value = {type: 'Literal', value: true}
180+
}
181+
182+
return create(node, {
183+
type: 'Property',
184+
key: toIdentifier(node.name),
185+
value: value,
186+
kind: 'init'
187+
})
188+
}
189+
190+
function toIdentifier(node) {
191+
return create(
192+
node,
193+
node.type === 'JSXMemberExpression'
194+
? {
195+
type: 'MemberExpression',
196+
object: toIdentifier(node.object),
197+
property: toIdentifier(node.property)
198+
}
199+
: node.type === 'JSXNamespacedName'
200+
? {type: 'Literal', value: node.namespace.name + ':' + node.name.name}
201+
: // Must be `JSXIdentifier`.
202+
isIdentifierName(node.name)
203+
? {type: 'Identifier', name: node.name}
204+
: {type: 'Literal', value: node.name}
205+
)
206+
}
207+
208+
function toMemberExpression(id) {
209+
var identifiers = id.split('.')
210+
var index = -1
211+
var result
212+
var prop
213+
214+
while (++index < identifiers.length) {
215+
prop = {type: 'Identifier', name: identifiers[index]}
216+
result = index
217+
? {type: 'MemberExpression', object: result, property: prop}
218+
: prop
219+
}
220+
221+
return result
222+
}
223+
224+
function create(template, node) {
225+
var fields = ['start', 'end', 'loc', 'range', 'comments']
226+
var index = -1
227+
var field
228+
229+
while (++index < fields.length) {
230+
field = fields[index]
231+
if (field in template) {
232+
node[field] = template[field]
233+
}
234+
}
235+
236+
return node
237+
}

license

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
(The MIT License)
2+
3+
Copyright (c) 2020 Titus Wormer <tituswormer@gmail.com>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining
6+
a copy of this software and associated documentation files (the
7+
'Software'), to deal in the Software without restriction, including
8+
without limitation the rights to use, copy, modify, merge, publish,
9+
distribute, sublicense, and/or sell copies of the Software, and to
10+
permit persons to whom the Software is furnished to do so, subject to
11+
the following conditions:
12+
13+
The above copyright notice and this permission notice shall be
14+
included in all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

package.json

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
{
2+
"name": "estree-util-build-jsx",
3+
"version": "0.0.0",
4+
"description": "Transform JSX in estrees to function calls (for react, preact, and most hyperscript interfaces)",
5+
"license": "MIT",
6+
"keywords": [
7+
"estree",
8+
"ast",
9+
"ecmascript",
10+
"javascript",
11+
"tree",
12+
"jsx",
13+
"xml",
14+
"build",
15+
"hyperscript",
16+
"compile",
17+
"call",
18+
"acorn",
19+
"espree",
20+
"recast",
21+
"react",
22+
"preact"
23+
],
24+
"repository": "wooorm/estree-util-build-jsx",
25+
"bugs": "https://github.com/wooorm/estree-util-build-jsx/issues",
26+
"funding": {
27+
"type": "github",
28+
"url": "https://github.com/sponsors/wooorm"
29+
},
30+
"author": "Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)",
31+
"contributors": [
32+
"Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)"
33+
],
34+
"files": [
35+
"index.js"
36+
],
37+
"dependencies": {
38+
"estree-util-is-identifier-name": "^1.0.0",
39+
"estree-walker": "^2.0.0"
40+
},
41+
"devDependencies": {
42+
"acorn": "^8.0.0",
43+
"acorn-jsx": "^5.0.0",
44+
"astring": "^1.0.0",
45+
"escodegen": "^2.0.0",
46+
"nyc": "^15.0.0",
47+
"prettier": "^2.0.0",
48+
"recast": "^0.20.0",
49+
"remark-cli": "^9.0.0",
50+
"remark-preset-wooorm": "^8.0.0",
51+
"tape": "^5.0.0",
52+
"xo": "^0.36.0"
53+
},
54+
"scripts": {
55+
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix",
56+
"test-api": "node test",
57+
"test-coverage": "nyc --reporter lcov tape test.js",
58+
"test": "npm run format && npm run test-coverage"
59+
},
60+
"prettier": {
61+
"tabWidth": 2,
62+
"useTabs": false,
63+
"singleQuote": true,
64+
"bracketSpacing": false,
65+
"semi": false,
66+
"trailingComma": "none"
67+
},
68+
"xo": {
69+
"prettier": true,
70+
"esnext": false,
71+
"rules": {
72+
"guard-for-in": "off",
73+
"max-depth": "off",
74+
"unicorn/explicit-length-check": "off",
75+
"unicorn/prefer-number-properties": "off"
76+
}
77+
},
78+
"nyc": {
79+
"check-coverage": true,
80+
"lines": 100,
81+
"functions": 100,
82+
"branches": 100
83+
},
84+
"remarkConfig": {
85+
"plugins": [
86+
"preset-wooorm"
87+
]
88+
}
89+
}

0 commit comments

Comments
 (0)