Skip to content

Commit

Permalink
handle deep nodes, linebreaks
Browse files Browse the repository at this point in the history
  • Loading branch information
shahrul committed Oct 10, 2024
1 parent fead59f commit 6627906
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 114 deletions.
2 changes: 0 additions & 2 deletions h.lua
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ function printTable(t, indent)
end
end



local voidTags = {
"area", "base", "basefont", "br", "col",
"frame", "hr", "img", "input", "link",
Expand Down
164 changes: 100 additions & 64 deletions luax.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,96 +3,129 @@ local h = require('h')
local originalRequire = require

local function decentParserAST(input)
local pos = 1
local output = ""
local isTag = 0
local isTextNode = 0
local pos = 1
local deepNode = 0
local deepString = false
local deepStringApos = false
local isTag = false
local textNode = false
local textNodeStart = false
local var = false

while pos <= #input do
local char = input:sub(pos, pos)
local tok = input:sub(pos, pos)
-- simple decent parser
-- escape " ' encapsulation
-- opening tag
if char == "<" then
local tagName = input:match("<(%w+)", pos)
local tagNameEnd = input:match("</(%w+)>", pos)
if isTag == 2 and tagName ~= nil then
-- children tag
output = output .. ", "
end
if tagName then
deepNode = deepNode + 1
isTag = 1
output = output .. tagName .. "({"
pos = pos + #tagName + 1
elseif tagNameEnd then
deepNode = deepNode - 1
if deepNode == 0 then
isTag = 0
if tok == "<" and not deepString and not deepStringApos then
local nextSpacingPos = input:find('%s',pos)
local tagRange = input:sub(pos, nextSpacingPos)
local tagName = tagRange:match("<(%w+)", 0)
local tagNameEnd = tagRange:match("</(%w+)>", 0)
if tagName then deepNode = deepNode + 1 end
if tagNameEnd then deepNode = deepNode - 1 end
pos = pos + 1

if tagName and not deepString then
isTag = true
textNode = false
if deepNode > 1 then
output = output .. ", " .. tagName .. "({"
else
output = output .. tagName .. "({"
end
if isTextNode == 2 then
isTextNode = 0
local step = 1
-- enclose attributes if it empty
if tagRange:sub(#tagRange-1, #tagRange):gsub("[\r\n]", ""):match("^%s*(.-)$") == '>' then step = 0 end
pos = pos + #tagName + step
elseif tagNameEnd then
if isTag and not textNode then
isTag = not isTag
local trail = input:sub(0, pos-2):gsub("[%s\r\n]", "")
if trail:sub(#trail-1, #trail-1) == '/' then
output = output .. ")"
else
output = output .. "})"
end
elseif isTag and textNode then
output = output .. "]])"
else
output = output .. ")"
if textNodeStart then
textNodeStart = not textNodeStart
output = output .. "]])"
else
output = output .. ")"
end
end
pos = pos + #tagNameEnd + 2
else
output = output .. tok
pos = pos + 1
end
elseif char == ">" then
if isTag == 1 then
output = output .. " }"
isTag = 2
elseif tok == '"' and deepNode > 0 then
deepString = not deepString
output = output .. tok
pos = pos + 1
elseif tok == "'" and deepNode > 0 then
deepStringApos = not deepStringApos
output = output .. tok
pos = pos + 1
elseif tok == ">" and deepNode > 0 and not deepString and not deepStringApos then
if not textNode and isTag and input:sub(pos-1, pos-1) ~= "/" then
isTag = not isTag
textNode = not textNode
output = output .. '}'
else
isTag = not isTag
-- textNode = not textNode
output = output .. '})'
end
pos = pos + 1
elseif char == "/" then
elseif tok == "/" and input:sub(pos+1, pos+1) == '>' and not deepString and not deepStringApos then
deepNode = deepNode - 1
-- self closing tag
if deepNode == 0 then
isTag = 0
output = output .. '})'
pos = pos + 2
elseif tok == '{' and deepNode > 0 and not deepString and not deepStringApos then
var = not var
if not isTag then
output = output .. ','
end
output = output .. " })"
pos = pos + 1
else
local skip = false
if char and isTag == 2 then
isTextNode = 1
isTag = 3
output = output .. ", "
elseif isTag == 1 then
-- attributes
if char:match("%s") then
if output:sub(-1) ~= "{" and output:sub(-1) == "\"" then
output = output .. ","
elseif input:sub(pos -1, pos -1) == "}" then
output = output .. ","
end
skip = false
elseif char == "{" or char == "}" then
skip = true
elseif tok == '}' and deepNode > 0 and not deepString and not deepStringApos then
var = not var
pos = pos + 1
elseif deepNode > 0 and not deepString and not deepStringApos then
if tok:match("%s") then
if isTag and output:sub(-1) ~= "{" and output:sub(-1) == "\"" or
isTag and input:sub(pos -1, pos -1) == "}" then
output = output .. ","
end
end

if isTag ~= 0 then
-- add bracket to all attributes key
if isTextNode == 1 and char == "{" or char == "}" then
skip = true
isTextNode = 3
elseif isTextNode == 1 then
isTextNode = 2
if char ~= '\n' then
output = output .. "[["
end
if textNode and not textNodeStart then
local subNode = input:match("%s*<(%w+)", pos)
if not isTag and not subNode and not var then
textNodeStart = not textNodeStart
output = output .. ", [["
end
end

if skip == false then
output = output .. char
end
if char:match("%=") then
output = output:gsub('([%w%-_]+)%=', '["%1"]=')
output = output .. tok
pos = pos + 1
else
if not textNode and not deepString and not deepStringApos then
textNode = not textNode
if textNode then
local subNode = input:match("%s*<(%w+)", pos)
if isTag and not subNode then
output = output .. "}, [["
elseif deepNode > 0 and not subNode then
output = output .. "[["
end
end
end
output = output .. tok
pos = pos + 1
end
end
Expand All @@ -102,6 +135,9 @@ end
local function preprocessLuaFile(inputFile)
local inputCode = io.open(inputFile, "r"):read("*all")
local transformedCode = decentParserAST(inputCode)
-- this to add [] bracket to table attributes
transformedCode = transformedCode:gsub('([%w%-_]+)%=([^%s]+)', '["%1"]=%2')
-- print(transformedCode)
return transformedCode
end

Expand Down
5 changes: 5 additions & 0 deletions test/props.luax
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
return <div
id="foo"
style="color;red">
test
</div>
31 changes: 0 additions & 31 deletions test/test.lua

This file was deleted.

30 changes: 30 additions & 0 deletions test/test.luax
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
local id = '1'
local class = "test"
local val = "todo A"
local val2 = "todo A Label"
local val3 = "todo A Value"
local val4 = "install Destroy"
local val5 = "install TodoDblclick"
return <li id={id} class={class} _="on destroy my.querySelector('button').click()">
<div class="view">
{val}
<label
hx-trigger="dblclick"
hx-patch="/edit-todo?id="..{id}.."&foo="..{class}
hx-target="next input"
hx-swap="outerHTML"
_="install TodoDblclick"
>
{val2}
</label>
<button
class="destroy"
hx-delete="/remove-todo?id="..{id}
hx-trigger="click"
hx-target="closest <li/>"
hx-swap="outerHTML"
_={val4}
/>
</div>
{val3}
</li>
28 changes: 19 additions & 9 deletions test/test_ast.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,36 +22,46 @@ local h = require('luax')

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

print(h(div))
h(div)

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

print(h(node_value))
h(node_value)

local element = require('test.element')

print(h(element))
h(element)

local varin = require('test.varin')

print(h(varin))
h(varin)

local foo = require('test.foo')

print(h(foo))
h(foo)

local content = require('test.content')

print(h(content))
h(content)

local input = require('test.input')

print(h(input))
h(input)

local input_with_con = require('test.input_with_con')

print(h(input_with_con))
h(input_with_con)

local props = require('test.props')

h(props)

local linebreak = require('test.line_break')

print(h(linebreak))
h(linebreak)
print("========================")

local test = require('test.test')

h(test)

Loading

0 comments on commit 6627906

Please sign in to comment.