Skip to content

Commit 789b2f8

Browse files
now parses elements and singular enum attributes
1 parent 65e1fb3 commit 789b2f8

File tree

3 files changed

+74
-32
lines changed

3 files changed

+74
-32
lines changed

Sources/HTMLKitMacros/HTMLElement.swift

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ private extension HTMLElementMacro {
8484
children = childs.prefix(childs.count)
8585
}
8686
let (attributes, innerHTML, trailingSlash):(String, String, Bool) = parse_arguments(context: context, elementType: elementType, children: children)
87+
return innerHTML
88+
8789
var string:String = (tag == "html" ? "<!DOCTYPE html>" : "") + "<" + tag + attributes
8890
if trailingSlash {
8991
if isVoid {
@@ -265,6 +267,8 @@ private extension HTMLElementMacro {
265267
string.escapeHTML(escapeAttributes: false)
266268
}
267269
return string
270+
} else if let string:String = parse_element(expr: child.expression) {
271+
return string
268272
} else if var string:String = parse_literal_value(context: context, elementType: elementType, key: "", expression: child.expression, lookupFiles: lookupFiles)?.value {
269273
string.escapeHTML(escapeAttributes: false)
270274
return string
@@ -328,6 +332,16 @@ private extension HTMLElementMacro {
328332
}
329333
return nil
330334
}
335+
// MARK: Parse element
336+
static func parse_element(expr: ExprSyntax) -> String? {
337+
guard let function:FunctionCallExprSyntax = expr.as(FunctionCallExprSyntax.self) else { return nil }
338+
var string:String = "\(function)"
339+
while string.first?.isWhitespace ?? false {
340+
string.removeFirst()
341+
}
342+
guard let element:HTMLElement = parse(rawValue: string) else { return nil }
343+
return element.description
344+
}
331345
// MARK: Parse Literal Value
332346
static func parse_literal_value(
333347
context: some MacroExpansionContext,
@@ -388,9 +402,14 @@ private extension HTMLElementMacro {
388402
if let decl:String = function.calledExpression.as(DeclReferenceExprSyntax.self)?.baseName.text {
389403
switch decl {
390404
case "StaticString":
391-
return (function.arguments.first!.expression.stringLiteral!.string, .string)
405+
var string:String = function.arguments.first!.expression.stringLiteral!.string
406+
return (string, .string)
392407
default:
393-
if let element:HTMLElement = parse(rawValue: "\(function.calledExpression)") {
408+
var string:String = "\(function)"
409+
while string.first?.isWhitespace ?? false {
410+
string.removeFirst()
411+
}
412+
if let element:HTMLElement = parse(rawValue: string) {
394413
let string:String = element.description
395414
return (string, string.contains("\\(") ? .interpolation : .string)
396415
}

Sources/HTMLKitUtilities/HTMLKitUtilities.swift

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -44,40 +44,45 @@ public extension String {
4444
// MARK: CSSUnit
4545
public extension HTMLElementAttribute {
4646
struct CSSUnit {
47+
public let htmlValue:String?
48+
49+
private init(_ value: Float) {
50+
htmlValue = value.description
51+
}
4752
}
4853
}
4954
public extension HTMLElementAttribute.CSSUnit { // https://www.w3schools.com/cssref/css_units.php
5055
// absolute
51-
static func centimeters(_ value: Float) -> Self { Self() }
52-
static func millimeters(_ value: Float) -> Self { Self() }
56+
static func centimeters(_ value: Float) -> Self { Self(value) }
57+
static func millimeters(_ value: Float) -> Self { Self(value) }
5358
/// 1 inch = 96px = 2.54cm
54-
static func inches(_ value: Float) -> Self { Self() }
59+
static func inches(_ value: Float) -> Self { Self(value) }
5560
/// 1 pixel = 1/96th of 1inch
56-
static func pixels(_ value: Float) -> Self { Self() }
61+
static func pixels(_ value: Float) -> Self { Self(value) }
5762
/// 1 point = 1/72 of 1inch
58-
static func points(_ value: Float) -> Self { Self() }
63+
static func points(_ value: Float) -> Self { Self(value) }
5964
/// 1 pica = 12 points
60-
static func picas(_ value: Float) -> Self { Self() }
65+
static func picas(_ value: Float) -> Self { Self(value) }
6166

6267
// relative
6368
/// Relative to the font-size of the element (2em means 2 times the size of the current font)
64-
static func em(_ value: Float) -> Self { Self() }
69+
static func em(_ value: Float) -> Self { Self(value) }
6570
/// Relative to the x-height of the current font (rarely used)
66-
static func ex(_ value: Float) -> Self { Self() }
71+
static func ex(_ value: Float) -> Self { Self(value) }
6772
/// Relative to the width of the "0" (zero)
68-
static func ch(_ value: Float) -> Self { Self() }
73+
static func ch(_ value: Float) -> Self { Self(value) }
6974
/// Relative to font-size of the root element
70-
static func rem(_ value: Float) -> Self { Self() }
75+
static func rem(_ value: Float) -> Self { Self(value) }
7176
/// Relative to 1% of the width of the viewport
72-
static func viewportWidth(_ value: Float) -> Self { Self() }
77+
static func viewportWidth(_ value: Float) -> Self { Self(value) }
7378
/// Relative to 1% of the height of the viewport
74-
static func viewportHeight(_ value: Float) -> Self { Self() }
79+
static func viewportHeight(_ value: Float) -> Self { Self(value) }
7580
/// Relative to 1% of viewport's smaller dimension
76-
static func viewportMin(_ value: Float) -> Self { Self() }
81+
static func viewportMin(_ value: Float) -> Self { Self(value) }
7782
/// Relative to 1% of viewport's larger dimension
78-
static func viewportMax(_ value: Float) -> Self { Self() }
83+
static func viewportMax(_ value: Float) -> Self { Self(value) }
7984
/// Relative to the parent element
80-
static func percent(_ value: Float) -> Self { Self() }
85+
static func percent(_ value: Float) -> Self { Self(value) }
8186
}
8287

8388

@@ -244,16 +249,23 @@ indirect enum HTMLElementValueType {
244249
case cssUnit
245250
case array(of: HTMLElementValueType)
246251

247-
static func consume(_ range: inout Substring, length: Int) -> String {
248-
let slice:Substring = range[range.startIndex..<range.index(range.endIndex, offsetBy: length)]
249-
range = range[range.index(range.startIndex, offsetBy: length)...]
252+
private static func cleanup(_ range: inout Substring) {
250253
while (range.first?.isWhitespace ?? false) || range.first == "," {
251254
range.removeFirst()
252255
}
256+
}
257+
static func consume(_ range: inout Substring, length: Int) -> String {
258+
let slice:Substring = range[range.startIndex..<range.index(range.endIndex, offsetBy: length)]
259+
range = range[range.index(range.startIndex, offsetBy: length)...]
260+
cleanup(&range)
253261
return String(slice)
254262
}
255-
static func cString(_ range: inout Substring) -> String? {
256-
guard range.first == "\"" else { return nil }
263+
static func cString(key: String, _ range: inout Substring) -> String? {
264+
guard range.hasPrefix(key + ":") else { return nil }
265+
range.removeFirst(key.count + 1)
266+
while range.first != "\"" {
267+
range.removeFirst()
268+
}
257269
range.removeFirst()
258270
guard let index:Substring.Index = range.firstIndex(of: "\"") else { return nil }
259271
return consume(&range, length: range.distance(from: range.startIndex, to: index))
@@ -275,11 +287,15 @@ indirect enum HTMLElementValueType {
275287
while (range.first?.isNumber ?? false) || range.first == "." || range.first == "_" {
276288
string.append(range.removeFirst())
277289
}
290+
cleanup(&range)
278291
return Float(string)!
279292
}
280-
static func cAttribute<T: HTMLInitializable>(_ range: inout Substring) -> T? {
281-
guard range.first == "." else { return nil }
282-
range.removeFirst()
293+
static func cAttribute<T: HTMLInitializable>(key: String, _ range: inout Substring) -> T? {
294+
guard range.hasPrefix(key + ":") else { return nil }
295+
range.removeFirst(key.count + 1)
296+
while (range.first?.isWhitespace ?? false) || range.first == "." {
297+
range.removeFirst()
298+
}
283299
var string:String = "", depth:Int = 1
284300
while let char:Character = range.first {
285301
if char == "(" {
@@ -289,11 +305,14 @@ indirect enum HTMLElementValueType {
289305
}
290306
if depth == 0 {
291307
break
308+
} else if depth == 1 && char == "," {
309+
break
292310
}
293311
string.append(range.removeFirst())
294312
}
295-
string += ")"
296-
return T(rawValue: string)
313+
guard let value:T = T(rawValue: string) else { return nil }
314+
cleanup(&range)
315+
return value
297316
}
298317
}
299318

Sources/HTMLKitUtilityMacros/HTMLElements.swift

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,15 @@ enum HTMLElements : DeclarationMacro {
5454
initializers += "self = .init("
5555
attributes.reserveCapacity(test.count)
5656
for element in test {
57-
var key:String = ""
57+
var key:String = "", key_literal:String = ""
5858
let tuple = element.expression.as(TupleExprSyntax.self)!
5959
for attribute_element in tuple.elements {
6060
let label:LabeledExprSyntax = attribute_element
6161
if let key_element = label.expression.as(StringLiteralExprSyntax.self) {
6262
key = "\(key_element)"
6363
key.removeFirst()
6464
key.removeLast()
65+
key_literal = key
6566
switch key {
6667
case "for", "default", "defer", "as":
6768
key = "`\(key)`"
@@ -73,12 +74,12 @@ enum HTMLElements : DeclarationMacro {
7374
let (value_type, default_value):(String, String) = parse_value_type(isArray: &isArray, key: key, label.expression)
7475
let init_type:String
7576
switch value_type {
76-
case "String": init_type = "HTMLElementValueType.cString(&range)"
77+
case "String": init_type = "HTMLElementValueType.cString(key: \"\(key_literal)\", &range)"
7778
case "Bool": init_type = "HTMLElementValueType.cBool(&range)"
7879
case "Float": init_type = "HTMLElementValueType.cFloat(&range)"
7980
default:
8081
if value_type.hasPrefix("HTMLElementAttribute.Extra.") {
81-
init_type = "HTMLElementValueType.cAttribute(&range)"
82+
init_type = "HTMLElementValueType.cAttribute(key: \"\(key_literal)\", &range)"
8283
} else if value_type.first == "[" {
8384
init_type = "[]"
8485
} else {
@@ -140,8 +141,12 @@ enum HTMLElements : DeclarationMacro {
140141
}
141142
attributes_func += ".joined(separator: \"\(separator)\")\n"
142143
attributes_func += "items.append(\"\(key_literal)=\\\"\" + string + \"\\\"\")\n}"
144+
} else if value_type == "String" || value_type == "Int" || value_type == "Float" || value_type == "Double" {
145+
attributes_func += "\n"
146+
attributes_func += #"if let \#(key) { items.append("\#(key_literal)=\\\"\(\#(key))\\\"") }"#
143147
} else {
144-
attributes_func += "\nif let \(key) { items.append(\"\(key_literal)=\\\"\\(\(key))\\\"\") }"
148+
attributes_func += "\n"
149+
attributes_func += #"if let \#(key), let v:String = \#(key).htmlValue { items.append("\#(key_literal)=\\\"\(v)\\\"") }"#
145150
}
146151
}
147152
attributes_func += "\nreturn (items.isEmpty ? \"\" : \" \") + items.joined(separator: \" \")\n}\n"
@@ -151,7 +156,6 @@ enum HTMLElements : DeclarationMacro {
151156
render += "}"
152157

153158
string += render
154-
//string += "\npublic var innerHTML:[HTML] = []\n}"
155159
string += "\n}"
156160
items.append("\(raw: string)")
157161
}

0 commit comments

Comments
 (0)