66//
77
88// generate the html element files using the following command:
9- //
10- // swiftc main.swift -D GENERATE_ELEMENTS && ./main
9+ /*
10+ swiftc main.swift ../HTMLKitUtilities/HTMLEncoding.swift \
11+ ../HTMLKitUtilities/attributes/HTMLElementAttribute.swift \
12+ ../HTMLKitUtilities/attributes/HTMLElementAttributeExtra.swift \
13+ ../HTMLKitUtilities/attributes/HTMX.swift \
14+ ../HTMLKitUtilities/attributes/HTMXAttributes.swift \
15+ -D GENERATE_ELEMENTS && ./main
16+ */
1117
1218#if canImport(Foundation) && GENERATE_ELEMENTS
1319
14- // We do we do it this way?
20+ // Why do we do it this way?
1521// - The documentation doesn't link correctly if we generate from a macro
1622
1723import Foundation
@@ -22,31 +28,36 @@ writeTo = "/home/paradigm/Desktop/GitProjects" + suffix
2228#elseif os(macOS)
2329writeTo = " /Users/randomhashtags/GitProjects " + suffix
2430#else
25- #errorget ("no write path declared for platform")
31+ #error ("no write path declared for platform")
2632#endif
2733
28- let now : Date = Date ( )
34+ let now : String = Date . now . formatted ( date : . abbreviated , time : . complete )
2935let template : String = """
3036//
3137// %elementName%.swift
3238//
3339//
34- // Generated on \( now) .
40+ // Generated \( now) .
3541//
3642
3743import SwiftSyntax
3844
39- /// The `%tagName%` HTML element.%elementDocumentation%
45+ /// The `%tagName%`%aliases% HTML element.%elementDocumentation%
4046public struct %elementName% : HTMLElement {%variables%
4147}
48+
49+ public extension %elementName% {
50+ enum AttributeKeys {%customAttributeCases%
51+ }
52+ }
4253"""
4354let defaultVariables : [ HTMLElementVariable ] = [
44- . init ( public: true , mutable: true , name: " trailingSlash " , valueType: . bool, defaultValue: " false " ) ,
45- . init ( public: true , mutable: true , name: " escaped " , valueType: . bool, defaultValue: " false " ) ,
46- . init ( public: false , mutable: true , name: " fromMacro " , valueType: . bool, defaultValue: " false " ) ,
47- . init ( public: false , mutable: true , name: " encoding " , valueType: . custom( " HTMLEncoding " ) , defaultValue: " .string " ) ,
48- . init ( public: true , mutable: true , name: " innerHTML " , valueType: . array( of: . custom( " CustomStringConvertible " ) ) ) ,
49- . init ( public: true , mutable: true , name: " attributes " , valueType: . array( of: . custom( " HTMLElementAttribute " ) ) ) ,
55+ get ( public: true , mutable: true , name: " trailingSlash " , valueType: . bool, defaultValue: " false " ) ,
56+ get ( public: true , mutable: true , name: " escaped " , valueType: . bool, defaultValue: " false " ) ,
57+ get ( public: false , mutable: true , name: " fromMacro " , valueType: . bool, defaultValue: " false " ) ,
58+ get ( public: false , mutable: true , name: " encoding " , valueType: . custom( " HTMLEncoding " ) , defaultValue: " .string " ) ,
59+ get ( public: true , mutable: true , name: " innerHTML " , valueType: . array( of: . custom( " CustomStringConvertible " ) ) ) ,
60+ get ( public: true , mutable: true , name: " attributes " , valueType: . array( of: . custom( " HTMLElementAttribute " ) ) ) ,
5061]
5162
5263let indent1 : String = " \n "
@@ -56,44 +67,25 @@ for (elementType, customAttributes) in attributes().filter({ $0.key == .a }) {
5667 var variablesString : String = " "
5768
5869 var variables : [ HTMLElementVariable ] = defaultVariables
59- variables. append ( . init ( public: true , mutable: false , name: " tag " , valueType: . string, defaultValue: " \" %tagName% \" " ) )
60- variables. append ( . init ( public: true , mutable: false , name: " isVoid " , valueType: . bool, defaultValue: " \( elementType. isVoid) " ) )
70+ variables. append ( get ( public: true , mutable: false , name: " tag " , valueType: . string, defaultValue: " \" %tagName% \" " ) )
71+ variables. append ( get ( public: true , mutable: false , name: " isVoid " , valueType: . bool, defaultValue: " \( elementType. isVoid) " ) )
6172 for attribute in customAttributes {
6273 variables. append ( attribute)
6374 }
64-
65- let booleans : [ HTMLElementVariable ] = variables. filter ( { $0. valueType. isBool } )
66- for bool in booleans {
67- variablesString += indent1 + bool. description
68- }
69-
70- let integers : [ HTMLElementVariable ] = variables. filter ( { $0. valueType == . int } )
71- for int in integers {
72- variablesString += indent1 + int. description
73- }
74-
75- let floats : [ HTMLElementVariable ] = variables. filter ( { $0. valueType == . float } )
76- for float in floats {
77- variablesString += indent1 + float. description
78- }
79-
80- let attributes : [ HTMLElementVariable ] = variables. filter ( { $0. valueType. isAttribute } )
81- for attribute in attributes {
82- variablesString += indent1 + attribute. description
83- }
84-
85- let strings : [ HTMLElementVariable ] = variables. filter ( { $0. valueType == . string } )
86- for string in strings {
87- variablesString += indent1 + string. description
88- }
89-
90- let arrays : [ HTMLElementVariable ] = variables. filter ( { $0. valueType. isArray } )
91- for array in arrays {
92- variablesString += indent1 + array. description
75+
76+ for variable in variables. sorted ( by: {
77+ guard $0. memoryLayoutAlignment == $1. memoryLayoutAlignment else { return $0. memoryLayoutAlignment > $1. memoryLayoutAlignment }
78+ guard $0. memoryLayoutSize == $1. memoryLayoutSize else { return $0. memoryLayoutSize > $1. memoryLayoutSize }
79+ guard $0. memoryLayoutStride == $1. memoryLayoutStride else { return $0. memoryLayoutStride > $1. memoryLayoutStride }
80+ return $0. name < $1. name
81+ } ) {
82+ variablesString += indent1 + variable. description
9383 }
9484
9585 variables = variables. sorted ( by: { $0. name <= $1. name } )
86+ var customAttributeCases : String = " "
9687 for variable in variables {
88+ customAttributeCases += indent2 + " case " + variable. name + " ( " + variable. valueType. annotation ( variableName: variable. name) + " = " + variable. valueType. defaultOptionalValue + " ) "
9789 }
9890
9991 var code : String = template
@@ -103,7 +95,11 @@ for (elementType, customAttributes) in attributes().filter({ $0.key == .a }) {
10395 let elementDocumentationString : String = " \n /// \n " + elementDocumentation. map ( { " /// " + $0 } ) . joined ( separator: " \n " )
10496 code. replace ( " %elementDocumentation% " , with: elementDocumentationString)
10597 code. replace ( " %tagName% " , with: elementType. tagName)
98+
99+ let aliases : String = elementType. aliases. isEmpty ? " " : " ( " + elementType. aliases. map ( { " _ " + $0 + " _ " } ) . joined ( separator: " , " ) + " ) "
100+ code. replace ( " %aliases% " , with: aliases)
106101 code. replace ( " %elementName% " , with: elementType. rawValue)
102+ code. replace ( " %customAttributeCases% " , with: customAttributeCases)
107103 print ( code)
108104
109105 /*let fileName:String = elementType.rawValue + ".swift"
@@ -112,17 +108,33 @@ for (elementType, customAttributes) in attributes().filter({ $0.key == .a }) {
112108 try FileManager.default.removeItem(atPath: filePath)
113109 }*/
114110}
111+ extension Array where Element == HTMLElementVariable {
112+ func filterAndSort( _ predicate: ( Element ) -> Bool ) -> [ Element ] {
113+ return filter ( predicate) . sorted ( by: { $0. mutable == $1. mutable ? $0. public == $1. public ? $0. name < $1. name : !$0. public : !$0. mutable } )
114+ }
115+ }
115116
116117// MARK: HTMLElementVariable
117- struct HTMLElementVariable {
118+ struct HTMLElementVariable : Hashable {
118119 let name : String
119120 let documentation : [ String ]
120121 let defaultValue : String ?
121122 let `public` : Bool
122123 let mutable : Bool
123124 let valueType : HTMLElementValueType
125+ let memoryLayoutAlignment : Int
126+ let memoryLayoutSize : Int
127+ let memoryLayoutStride : Int
124128
125- init ( public: Bool , mutable: Bool , name: String , documentation: [ String ] = [ ] , valueType: HTMLElementValueType , defaultValue: String ? = nil ) {
129+ init (
130+ public: Bool ,
131+ mutable: Bool ,
132+ name: String ,
133+ documentation: [ String ] = [ ] ,
134+ valueType: HTMLElementValueType ,
135+ defaultValue: String ? = nil ,
136+ memoryLayout: ( alignment: Int , size: Int , stride: Int )
137+ ) {
126138 switch name {
127139 case " for " , " default " , " defer " , " as " :
128140 self . name = " ` " + name + " ` "
@@ -134,12 +146,16 @@ struct HTMLElementVariable {
134146 self . public = `public`
135147 self . mutable = mutable
136148 self . valueType = valueType
149+ ( memoryLayoutAlignment, memoryLayoutSize, memoryLayoutStride) = ( memoryLayout. alignment, memoryLayout. size, memoryLayout. stride)
137150 }
138151
139152 var description : String {
140153 var string : String = " "
141154 for documentation in documentation {
142- string += " /// " + documentation
155+ string += indent1 + " /// " + documentation
156+ }
157+ if !string. isEmpty {
158+ string += indent1
143159 }
144160 string += ( `public` ? " public " : " private " ) + " " + ( mutable ? " var " : " let " ) + " " + name + " : " + valueType. annotation ( variableName: name) + ( defaultValue != nil ? " = " + defaultValue! : " " )
145161 return string
@@ -294,6 +310,15 @@ enum HTMLElementType : String, CaseIterable {
294310 default : return rawValue
295311 }
296312 }
313+
314+ var aliases : [ String ] {
315+ var aliases : Set < String >
316+ switch self {
317+ case . a: aliases = [ " anchor " ]
318+ default : aliases = [ ]
319+ }
320+ return aliases. sorted ( by: { $0 <= $1 } )
321+ }
297322
298323 var documentation : [ String ] {
299324 switch self {
@@ -357,8 +382,7 @@ enum HTMLElementValueType : Hashable {
357382
358383 var isAttribute : Bool {
359384 switch self {
360- case . attribute: return true
361- case . otherAttribute( _) : return true
385+ case . attribute, . otherAttribute( _) : return true
362386 case . optional( let item) : return item. isAttribute
363387 default : return false
364388 }
@@ -369,9 +393,73 @@ enum HTMLElementValueType : Hashable {
369393 }
370394}
371395
372-
373- func get( _ variableName: String , _ valueType: HTMLElementValueType , _ documentation: HTMLElementVariableDocumentation ? = nil ) -> HTMLElementVariable {
374- return HTMLElementVariable ( public: true , mutable: true , name: variableName, documentation: documentation? . value ?? [ ] , valueType: . optional( valueType) , defaultValue: valueType. defaultOptionalValue)
396+ // MARK: Get
397+ func get(
398+ _ variableName: String ,
399+ _ valueType: HTMLElementValueType ,
400+ _ documentation: HTMLElementVariableDocumentation ? = nil
401+ ) -> HTMLElementVariable {
402+ return get ( public: true , mutable: true , name: variableName, documentation: documentation? . value ?? [ ] , valueType: . optional( valueType) )
403+ }
404+ func get(
405+ public: Bool ,
406+ mutable: Bool ,
407+ name: String ,
408+ documentation: [ String ] = [ ] ,
409+ valueType: HTMLElementValueType ,
410+ defaultValue: String ? = nil
411+ ) -> HTMLElementVariable {
412+ func get< T> ( _ dude: T . Type ) -> ( Int , Int , Int ) {
413+ return ( MemoryLayout < T > . alignment, MemoryLayout< T> . size, MemoryLayout< T> . stride)
414+ }
415+ var ( alignment, size, stride) : ( Int , Int , Int ) = ( - 1 , - 1 , - 1 )
416+ func layout( vt: HTMLElementValueType ) -> ( Int , Int , Int ) {
417+ switch vt {
418+ case . bool, . booleanDefaultValue( _) : return get ( Bool . self)
419+ case . string: return get ( String . self)
420+ case . int: return get ( Int . self)
421+ case . float: return get ( Float . self)
422+ case . cssUnit: return get ( HTMLElementAttribute . CSSUnit. self)
423+ case . attribute: return HTMLElementAttribute . Extra. memoryLayout ( for: name. lowercased ( ) ) ?? ( - 1 , - 1 , - 1 )
424+ case . otherAttribute( let item) : return HTMLElementAttribute . Extra. memoryLayout ( for: item. lowercased ( ) ) ?? ( - 1 , - 1 , - 1 )
425+ case . custom( let s) :
426+ switch s {
427+ case " HTMLEncoding " : return get ( HTMLEncoding . self)
428+ default : break
429+ }
430+
431+ default : break
432+ }
433+ return ( - 1 , - 1 , - 1 )
434+ }
435+ switch valueType {
436+ case . bool, . string, . int, . float, . cssUnit, . attribute, . custom( _) : ( alignment, size, stride) = layout ( vt: valueType)
437+ case . optional( let innerVT) :
438+ switch innerVT {
439+ case . bool, . booleanDefaultValue( _) : ( alignment, size, stride) = get ( Bool . self)
440+ case . string: ( alignment, size, stride) = get ( String ? . self)
441+ case . int: ( alignment, size, stride) = get ( Int ? . self)
442+ case . float: ( alignment, size, stride) = get ( Float ? . self)
443+ case . cssUnit: ( alignment, size, stride) = get ( HTMLElementAttribute . CSSUnit? . self)
444+ case . attribute: ( alignment, size, stride) = HTMLElementAttribute . Extra. memoryLayout ( for: name. lowercased ( ) ) ?? ( - 1 , - 1 , - 1 )
445+ case . otherAttribute( let item) : ( alignment, size, stride) = HTMLElementAttribute . Extra. memoryLayout ( for: item. lowercased ( ) ) ?? ( - 1 , - 1 , - 1 )
446+ case . array( _) : ( alignment, size, stride) = ( 8 , 8 , 8 )
447+ default : break
448+ }
449+ case . array( _) : ( alignment, size, stride) = ( 8 , 8 , 8 )
450+ default : break
451+ }
452+ //var documentation:[String] = documentation
453+ //documentation.append(contentsOf: ["- Memory Layout:", " - Alignment: \(alignment)", " - Size: \(size)", " - Stride: \(stride)"])
454+ return HTMLElementVariable (
455+ public: `public`,
456+ mutable: mutable,
457+ name: name,
458+ documentation: documentation,
459+ valueType: valueType,
460+ defaultValue: defaultValue ?? valueType. defaultOptionalValue,
461+ memoryLayout: ( alignment, size, stride)
462+ )
375463}
376464
377465// MARK: Attribute Documentation
@@ -399,7 +487,7 @@ func attributes() -> [HTMLElementType:[HTMLElementVariable]] {
399487 // MARK: A
400488 . a : [
401489 get ( " attributionsrc " , . array( of: . string) ) ,
402- get ( " download " , . attribute) ,
490+ get ( " download " , . attribute, . download ) ,
403491 get ( " href " , . string) ,
404492 get ( " hrefLang " , . string) ,
405493 get ( " ping " , . array( of: . string) ) ,
@@ -413,7 +501,7 @@ func attributes() -> [HTMLElementType:[HTMLElementVariable]] {
413501 . area : [
414502 get ( " alt " , . string) ,
415503 get ( " coords " , . array( of: . int) ) ,
416- get ( " download " , . attribute) ,
504+ get ( " download " , . attribute, . download ) ,
417505 get ( " href " , . string) ,
418506 get ( " shape " , . attribute) ,
419507 get ( " ping " , . array( of: . string) ) ,
0 commit comments