Skip to content

Commit 6627906

Browse files
author
shahrul
committed
handle deep nodes, linebreaks
1 parent fead59f commit 6627906

File tree

7 files changed

+183
-114
lines changed

7 files changed

+183
-114
lines changed

h.lua

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ function printTable(t, indent)
2323
end
2424
end
2525

26-
27-
2826
local voidTags = {
2927
"area", "base", "basefont", "br", "col",
3028
"frame", "hr", "img", "input", "link",

luax.lua

Lines changed: 100 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -3,96 +3,129 @@ local h = require('h')
33
local originalRequire = require
44

55
local function decentParserAST(input)
6-
local pos = 1
76
local output = ""
8-
local isTag = 0
9-
local isTextNode = 0
7+
local pos = 1
108
local deepNode = 0
9+
local deepString = false
10+
local deepStringApos = false
11+
local isTag = false
12+
local textNode = false
13+
local textNodeStart = false
14+
local var = false
1115

1216
while pos <= #input do
13-
local char = input:sub(pos, pos)
17+
local tok = input:sub(pos, pos)
1418
-- simple decent parser
19+
-- escape " ' encapsulation
1520
-- opening tag
16-
if char == "<" then
17-
local tagName = input:match("<(%w+)", pos)
18-
local tagNameEnd = input:match("</(%w+)>", pos)
19-
if isTag == 2 and tagName ~= nil then
20-
-- children tag
21-
output = output .. ", "
22-
end
23-
if tagName then
24-
deepNode = deepNode + 1
25-
isTag = 1
26-
output = output .. tagName .. "({"
27-
pos = pos + #tagName + 1
28-
elseif tagNameEnd then
29-
deepNode = deepNode - 1
30-
if deepNode == 0 then
31-
isTag = 0
21+
if tok == "<" and not deepString and not deepStringApos then
22+
local nextSpacingPos = input:find('%s',pos)
23+
local tagRange = input:sub(pos, nextSpacingPos)
24+
local tagName = tagRange:match("<(%w+)", 0)
25+
local tagNameEnd = tagRange:match("</(%w+)>", 0)
26+
if tagName then deepNode = deepNode + 1 end
27+
if tagNameEnd then deepNode = deepNode - 1 end
28+
pos = pos + 1
29+
30+
if tagName and not deepString then
31+
isTag = true
32+
textNode = false
33+
if deepNode > 1 then
34+
output = output .. ", " .. tagName .. "({"
35+
else
36+
output = output .. tagName .. "({"
3237
end
33-
if isTextNode == 2 then
34-
isTextNode = 0
38+
local step = 1
39+
-- enclose attributes if it empty
40+
if tagRange:sub(#tagRange-1, #tagRange):gsub("[\r\n]", ""):match("^%s*(.-)$") == '>' then step = 0 end
41+
pos = pos + #tagName + step
42+
elseif tagNameEnd then
43+
if isTag and not textNode then
44+
isTag = not isTag
45+
local trail = input:sub(0, pos-2):gsub("[%s\r\n]", "")
46+
if trail:sub(#trail-1, #trail-1) == '/' then
47+
output = output .. ")"
48+
else
49+
output = output .. "})"
50+
end
51+
elseif isTag and textNode then
3552
output = output .. "]])"
3653
else
37-
output = output .. ")"
54+
if textNodeStart then
55+
textNodeStart = not textNodeStart
56+
output = output .. "]])"
57+
else
58+
output = output .. ")"
59+
end
3860
end
3961
pos = pos + #tagNameEnd + 2
4062
else
63+
output = output .. tok
4164
pos = pos + 1
4265
end
43-
elseif char == ">" then
44-
if isTag == 1 then
45-
output = output .. " }"
46-
isTag = 2
66+
elseif tok == '"' and deepNode > 0 then
67+
deepString = not deepString
68+
output = output .. tok
69+
pos = pos + 1
70+
elseif tok == "'" and deepNode > 0 then
71+
deepStringApos = not deepStringApos
72+
output = output .. tok
73+
pos = pos + 1
74+
elseif tok == ">" and deepNode > 0 and not deepString and not deepStringApos then
75+
if not textNode and isTag and input:sub(pos-1, pos-1) ~= "/" then
76+
isTag = not isTag
77+
textNode = not textNode
78+
output = output .. '}'
79+
else
80+
isTag = not isTag
81+
-- textNode = not textNode
82+
output = output .. '})'
4783
end
4884
pos = pos + 1
49-
elseif char == "/" then
85+
elseif tok == "/" and input:sub(pos+1, pos+1) == '>' and not deepString and not deepStringApos then
5086
deepNode = deepNode - 1
51-
-- self closing tag
52-
if deepNode == 0 then
53-
isTag = 0
87+
output = output .. '})'
88+
pos = pos + 2
89+
elseif tok == '{' and deepNode > 0 and not deepString and not deepStringApos then
90+
var = not var
91+
if not isTag then
92+
output = output .. ','
5493
end
55-
output = output .. " })"
5694
pos = pos + 1
57-
else
58-
local skip = false
59-
if char and isTag == 2 then
60-
isTextNode = 1
61-
isTag = 3
62-
output = output .. ", "
63-
elseif isTag == 1 then
64-
-- attributes
65-
if char:match("%s") then
66-
if output:sub(-1) ~= "{" and output:sub(-1) == "\"" then
67-
output = output .. ","
68-
elseif input:sub(pos -1, pos -1) == "}" then
69-
output = output .. ","
70-
end
71-
skip = false
72-
elseif char == "{" or char == "}" then
73-
skip = true
95+
elseif tok == '}' and deepNode > 0 and not deepString and not deepStringApos then
96+
var = not var
97+
pos = pos + 1
98+
elseif deepNode > 0 and not deepString and not deepStringApos then
99+
if tok:match("%s") then
100+
if isTag and output:sub(-1) ~= "{" and output:sub(-1) == "\"" or
101+
isTag and input:sub(pos -1, pos -1) == "}" then
102+
output = output .. ","
74103
end
75104
end
76105

77-
if isTag ~= 0 then
78-
-- add bracket to all attributes key
79-
if isTextNode == 1 and char == "{" or char == "}" then
80-
skip = true
81-
isTextNode = 3
82-
elseif isTextNode == 1 then
83-
isTextNode = 2
84-
if char ~= '\n' then
85-
output = output .. "[["
86-
end
106+
if textNode and not textNodeStart then
107+
local subNode = input:match("%s*<(%w+)", pos)
108+
if not isTag and not subNode and not var then
109+
textNodeStart = not textNodeStart
110+
output = output .. ", [["
87111
end
88112
end
89113

90-
if skip == false then
91-
output = output .. char
92-
end
93-
if char:match("%=") then
94-
output = output:gsub('([%w%-_]+)%=', '["%1"]=')
114+
output = output .. tok
115+
pos = pos + 1
116+
else
117+
if not textNode and not deepString and not deepStringApos then
118+
textNode = not textNode
119+
if textNode then
120+
local subNode = input:match("%s*<(%w+)", pos)
121+
if isTag and not subNode then
122+
output = output .. "}, [["
123+
elseif deepNode > 0 and not subNode then
124+
output = output .. "[["
125+
end
126+
end
95127
end
128+
output = output .. tok
96129
pos = pos + 1
97130
end
98131
end
@@ -102,6 +135,9 @@ end
102135
local function preprocessLuaFile(inputFile)
103136
local inputCode = io.open(inputFile, "r"):read("*all")
104137
local transformedCode = decentParserAST(inputCode)
138+
-- this to add [] bracket to table attributes
139+
transformedCode = transformedCode:gsub('([%w%-_]+)%=([^%s]+)', '["%1"]=%2')
140+
-- print(transformedCode)
105141
return transformedCode
106142
end
107143

test/props.luax

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
return <div
2+
id="foo"
3+
style="color;red">
4+
test
5+
</div>

test/test.lua

Lines changed: 0 additions & 31 deletions
This file was deleted.

test/test.luax

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
local id = '1'
2+
local class = "test"
3+
local val = "todo A"
4+
local val2 = "todo A Label"
5+
local val3 = "todo A Value"
6+
local val4 = "install Destroy"
7+
local val5 = "install TodoDblclick"
8+
return <li id={id} class={class} _="on destroy my.querySelector('button').click()">
9+
<div class="view">
10+
{val}
11+
<label
12+
hx-trigger="dblclick"
13+
hx-patch="/edit-todo?id="..{id}.."&foo="..{class}
14+
hx-target="next input"
15+
hx-swap="outerHTML"
16+
_="install TodoDblclick"
17+
>
18+
{val2}
19+
</label>
20+
<button
21+
class="destroy"
22+
hx-delete="/remove-todo?id="..{id}
23+
hx-trigger="click"
24+
hx-target="closest <li/>"
25+
hx-swap="outerHTML"
26+
_={val4}
27+
/>
28+
</div>
29+
{val3}
30+
</li>

test/test_ast.lua

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,36 +22,46 @@ local h = require('luax')
2222

2323
local div = require('test.1_div')
2424

25-
print(h(div))
25+
h(div)
2626

2727
local node_value = require('test.2_node_value')
2828

29-
print(h(node_value))
29+
h(node_value)
3030

3131
local element = require('test.element')
3232

33-
print(h(element))
33+
h(element)
3434

3535
local varin = require('test.varin')
3636

37-
print(h(varin))
37+
h(varin)
3838

3939
local foo = require('test.foo')
4040

41-
print(h(foo))
41+
h(foo)
4242

4343
local content = require('test.content')
4444

45-
print(h(content))
45+
h(content)
4646

4747
local input = require('test.input')
4848

49-
print(h(input))
49+
h(input)
5050

5151
local input_with_con = require('test.input_with_con')
5252

53-
print(h(input_with_con))
53+
h(input_with_con)
54+
55+
local props = require('test.props')
56+
57+
h(props)
5458

5559
local linebreak = require('test.line_break')
5660

57-
print(h(linebreak))
61+
h(linebreak)
62+
print("========================")
63+
64+
local test = require('test.test')
65+
66+
h(test)
67+

0 commit comments

Comments
 (0)