Skip to content

Commit

Permalink
added doctype
Browse files Browse the repository at this point in the history
  • Loading branch information
shahrul committed Oct 13, 2024
1 parent ae93bd6 commit b6647ae
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 17 deletions.
6 changes: 3 additions & 3 deletions .rockspec
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package = "luax"
version = "1.0.2-1"
version = "1.0.3-1"

source = {
url = "https://github.com/syarul/luax/archive/refs/tags/v1.0.2.tar.gz",
dir = "luax-1.0.2"
url = "https://github.com/syarul/luax/archive/refs/tags/v1.0.3.tar.gz",
dir = "luax-1.0.3"
}
description = {
summary = "HTML parse in Lua",
Expand Down
13 changes: 9 additions & 4 deletions h.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ local function createElement(tag, atts, children)
}
end

local function isAtts(tbl)
local function isAtts(tbl, tag)
if tag:lower() == "doctype" then
return true
end
for k, v in pairs(tbl) do
if type(k) ~= "string" or type(v) == "table" then
return false
Expand All @@ -36,11 +39,11 @@ setmetatable(_G, {
return function(...)
local atts
local children = { ... }
if type(children[1]) == "table" and isAtts(children[1]) and #children ~= 1 then
if type(children[1]) == "table" and isAtts(children[1], tag) and #children ~= 1 then
atts = children[1]
children = { select(2, ...) }
end
if atts == nil and isAtts(children[1]) then
if atts == nil and isAtts(children[1], tag) then
atts = children[1]
children = { select(2, children) }
end
Expand Down Expand Up @@ -74,7 +77,9 @@ local function h(element)
children = children .. child
end
end
if isVoidTag(element.tag) then
if element.tag:lower() == "doctype" then
return "<!" .. element.tag:lower() .. " " .. table.concat(element.atts, " ") .. ">" .. children
elseif isVoidTag(element.tag) then
return "<" .. element.tag .. atts .. ">"
else
return "<" .. element.tag .. atts .. ">" .. children .. "</" .. element.tag .. ">"
Expand Down
58 changes: 52 additions & 6 deletions luax.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ local originalRequire = require

local function resetTable(store, data)
for key, value in pairs(data) do
-- ignore output and pos
if key ~= "output" and key ~= "pos" then
-- ignore output, pos and doctype
if key ~= "output" and key ~= "pos" and key ~= "docType" then
store[key] = value
end
end
Expand All @@ -17,6 +17,7 @@ State.__index = State
function State:new()
return setmetatable({
output = "",
docType = nil,
pos = 1,
deepNode = 0,
deepString = false,
Expand Down Expand Up @@ -50,23 +51,59 @@ function State:toggle(key, bool)
if bool ~= nil then self[key] = bool else self[key] = not self[key] end
end

local function formatDocTypeParams(input)
local result = {}
local cw = ""
local inQuotes = false
for i = 1, #input do
local char = input:sub(i, i)
if char == '"' then
inQuotes = not inQuotes
if cw ~= "" then
table.insert(result, '"\\"' .. cw .. '\\""')
cw = ""
end
elseif char == ' ' and not inQuotes then
if cw ~= "" then
table.insert(result, '"' .. cw .. '"')
cw = ""
end
else
cw = cw .. char
end
end
if cw ~= "" then
table.insert(result, '"' .. cw .. '"')
end
return table.concat(result, ', ')
end

local function decentParserAST(input)
local var = false
local s = State:new()
local resetStore = {}
resetTable(resetStore, s)
local varStore = {}
local docTypeStartPos = 0

while s.pos <= #input do
local tok = input:sub(s.pos, s.pos)
-- simple decent parser
-- escape " ' encapsulation
-- opening tag
if tok == "<" and s:notStr() then
local nextSpacingPos = input:find("%s", s.pos)

local nextSpacingPos = input:find("%s", s.pos) or input:find("%>", s.pos)
local tagRange = input:sub(s.pos, nextSpacingPos)
local tagName = tagRange:match("<(%w+)", 0)
local tagNameEnd = tagRange:match("</(%w+)>", 0)
local tagDocType = tagRange:match("<(%!%w+)", 0)
if tagDocType then
tagName = tagDocType:sub(2)
s.docType = true
docTypeStartPos = s.pos + #tagDocType + 2
s:inc()
end
if tagName then s:incDeepNode() end
s:inc()

Expand Down Expand Up @@ -129,6 +166,13 @@ local function decentParserAST(input)
s:decDeepNode()
s:conc("})")
end

if s.docType then
s.docType = not s.docType
local docTypeParams = s.output:sub(docTypeStartPos, s.pos - 1)
local output = formatDocTypeParams(docTypeParams)
s.output = s.output:sub(0, docTypeStartPos-1) .. output .. s.output:sub(s.pos)
end
s:inc()
elseif tok == "/" and input:sub(s.pos + 1, s.pos + 1) == ">" and s:notStr() then
s:decDeepNode()
Expand Down Expand Up @@ -156,7 +200,7 @@ local function decentParserAST(input)
s:inc()
elseif s:xml() and s:notStr() then
if tok:match("%s") then
if not var and s.isTag and s.output:sub(-1) ~= "{" and s.output:sub(-1) == "\"" or
if not s.docType and not var and s.isTag and s.output:sub(-1) ~= "{" and s.output:sub(-1) == "\"" or
s.isTag and input:sub(s.pos - 1, s.pos - 1) == "}" then
s:conc(",")
end
Expand Down Expand Up @@ -187,14 +231,16 @@ local function decentParserAST(input)
s:conc(tok, 1)
end
end
-- this to add [] bracket to table attributes
s.output = s.output:gsub('([%w%-_]+)%=([^%s]+)', '["%1"]=%2')
-- encapsulate output if doctype exist
if s.docType ~= nil then s:conc(")") end
return s.output
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("===================")
-- print(transformedCode)
-- print("===================")
Expand Down
2 changes: 1 addition & 1 deletion package.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
return {
name = "syarul/luax",
version = "1.0.2",
version = "1.0.3",
description = "LuaX is Lua + XML Syntax extension with builtin decent parse. In retrospect it's akin to React JSX.",
tags = { "lua", "module", "react", "jsx" },
license = "MIT",
Expand Down
1 change: 1 addition & 0 deletions test/19_doctype_setter.luax
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
return <!DOCTYPE html><html><head></head><body></body></html>
1 change: 1 addition & 0 deletions test/20_doctype_setter_comp.luax
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
return <!doctype HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head></head><body></body></html>
8 changes: 8 additions & 0 deletions test/test_ast.lua
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,12 @@ h(table.Filter(filters))
local f = require('test.18_filter')
h(f(filters))

local doc_type = require('test.19_doctype_setter')

h(doc_type)

local doc_type_comp = require('test.20_doctype_setter_comp')

h(doc_type_comp)


21 changes: 18 additions & 3 deletions test/test_spec.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
-- luacheck: globals describe it div p span
-- luacheck: globals DOCTYPE doctype html head body describe it div p span
local function GetDir()
local handle
local result
Expand Down Expand Up @@ -36,9 +36,24 @@ describe("LuaX", function()
h(el))
end)

it("should return type HTML doctype", function()
local el = DOCTYPE({ "html" }, html({}, head({}), body({})))
assert.is.equal("<!doctype html><html><head></head><body></body></html>", h(el))
end)

it("should return type HTML doctype", function()
local el = DOCTYPE({ "HTML", "PUBLIC", "\"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\"" })
assert.is.equal([[<!doctype HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">]], h(el))
end)

it("should return type HTML doctype", function()
local doc_type = require('test.19_doctype_setter')
assert.is.equal('<!doctype html><html><head></head><body></body></html>', h(doc_type))
end)

it("should return a HTML string when given JSX like syntax", function()
local el = require("test.1_div")
assert.is.equal('<div></div>', h(el))
local doc_type_comp = require('test.20_doctype_setter_comp')
assert.is.equal('<!doctype HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head></head><body></body></html>', h(doc_type_comp))
end)

it("should return a HTML string when given JSX like syntax", function()
Expand Down

0 comments on commit b6647ae

Please sign in to comment.