6
6
//
7
7
8
8
// 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
+ */
11
17
12
18
#if canImport(Foundation) && GENERATE_ELEMENTS
13
19
14
- // We do we do it this way?
20
+ // Why do we do it this way?
15
21
// - The documentation doesn't link correctly if we generate from a macro
16
22
17
23
import Foundation
@@ -22,31 +28,36 @@ writeTo = "/home/paradigm/Desktop/GitProjects" + suffix
22
28
#elseif os(macOS)
23
29
writeTo = " /Users/randomhashtags/GitProjects " + suffix
24
30
#else
25
- #errorget ("no write path declared for platform")
31
+ #error ("no write path declared for platform")
26
32
#endif
27
33
28
- let now : Date = Date ( )
34
+ let now : String = Date . now . formatted ( date : . abbreviated , time : . complete )
29
35
let template : String = """
30
36
//
31
37
// %elementName%.swift
32
38
//
33
39
//
34
- // Generated on \( now) .
40
+ // Generated \( now) .
35
41
//
36
42
37
43
import SwiftSyntax
38
44
39
- /// The `%tagName%` HTML element.%elementDocumentation%
45
+ /// The `%tagName%`%aliases% HTML element.%elementDocumentation%
40
46
public struct %elementName% : HTMLElement {%variables%
41
47
}
48
+
49
+ public extension %elementName% {
50
+ enum AttributeKeys {%customAttributeCases%
51
+ }
52
+ }
42
53
"""
43
54
let 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 " ) ) ) ,
50
61
]
51
62
52
63
let indent1 : String = " \n "
@@ -56,44 +67,25 @@ for (elementType, customAttributes) in attributes().filter({ $0.key == .a }) {
56
67
var variablesString : String = " "
57
68
58
69
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) " ) )
61
72
for attribute in customAttributes {
62
73
variables. append ( attribute)
63
74
}
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
93
83
}
94
84
95
85
variables = variables. sorted ( by: { $0. name <= $1. name } )
86
+ var customAttributeCases : String = " "
96
87
for variable in variables {
88
+ customAttributeCases += indent2 + " case " + variable. name + " ( " + variable. valueType. annotation ( variableName: variable. name) + " = " + variable. valueType. defaultOptionalValue + " ) "
97
89
}
98
90
99
91
var code : String = template
@@ -103,7 +95,11 @@ for (elementType, customAttributes) in attributes().filter({ $0.key == .a }) {
103
95
let elementDocumentationString : String = " \n /// \n " + elementDocumentation. map ( { " /// " + $0 } ) . joined ( separator: " \n " )
104
96
code. replace ( " %elementDocumentation% " , with: elementDocumentationString)
105
97
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)
106
101
code. replace ( " %elementName% " , with: elementType. rawValue)
102
+ code. replace ( " %customAttributeCases% " , with: customAttributeCases)
107
103
print ( code)
108
104
109
105
/*let fileName:String = elementType.rawValue + ".swift"
@@ -112,17 +108,33 @@ for (elementType, customAttributes) in attributes().filter({ $0.key == .a }) {
112
108
try FileManager.default.removeItem(atPath: filePath)
113
109
}*/
114
110
}
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
+ }
115
116
116
117
// MARK: HTMLElementVariable
117
- struct HTMLElementVariable {
118
+ struct HTMLElementVariable : Hashable {
118
119
let name : String
119
120
let documentation : [ String ]
120
121
let defaultValue : String ?
121
122
let `public` : Bool
122
123
let mutable : Bool
123
124
let valueType : HTMLElementValueType
125
+ let memoryLayoutAlignment : Int
126
+ let memoryLayoutSize : Int
127
+ let memoryLayoutStride : Int
124
128
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
+ ) {
126
138
switch name {
127
139
case " for " , " default " , " defer " , " as " :
128
140
self . name = " ` " + name + " ` "
@@ -134,12 +146,16 @@ struct HTMLElementVariable {
134
146
self . public = `public`
135
147
self . mutable = mutable
136
148
self . valueType = valueType
149
+ ( memoryLayoutAlignment, memoryLayoutSize, memoryLayoutStride) = ( memoryLayout. alignment, memoryLayout. size, memoryLayout. stride)
137
150
}
138
151
139
152
var description : String {
140
153
var string : String = " "
141
154
for documentation in documentation {
142
- string += " /// " + documentation
155
+ string += indent1 + " /// " + documentation
156
+ }
157
+ if !string. isEmpty {
158
+ string += indent1
143
159
}
144
160
string += ( `public` ? " public " : " private " ) + " " + ( mutable ? " var " : " let " ) + " " + name + " : " + valueType. annotation ( variableName: name) + ( defaultValue != nil ? " = " + defaultValue! : " " )
145
161
return string
@@ -294,6 +310,15 @@ enum HTMLElementType : String, CaseIterable {
294
310
default : return rawValue
295
311
}
296
312
}
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
+ }
297
322
298
323
var documentation : [ String ] {
299
324
switch self {
@@ -357,8 +382,7 @@ enum HTMLElementValueType : Hashable {
357
382
358
383
var isAttribute : Bool {
359
384
switch self {
360
- case . attribute: return true
361
- case . otherAttribute( _) : return true
385
+ case . attribute, . otherAttribute( _) : return true
362
386
case . optional( let item) : return item. isAttribute
363
387
default : return false
364
388
}
@@ -369,9 +393,73 @@ enum HTMLElementValueType : Hashable {
369
393
}
370
394
}
371
395
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
+ )
375
463
}
376
464
377
465
// MARK: Attribute Documentation
@@ -399,7 +487,7 @@ func attributes() -> [HTMLElementType:[HTMLElementVariable]] {
399
487
// MARK: A
400
488
. a : [
401
489
get ( " attributionsrc " , . array( of: . string) ) ,
402
- get ( " download " , . attribute) ,
490
+ get ( " download " , . attribute, . download ) ,
403
491
get ( " href " , . string) ,
404
492
get ( " hrefLang " , . string) ,
405
493
get ( " ping " , . array( of: . string) ) ,
@@ -413,7 +501,7 @@ func attributes() -> [HTMLElementType:[HTMLElementVariable]] {
413
501
. area : [
414
502
get ( " alt " , . string) ,
415
503
get ( " coords " , . array( of: . int) ) ,
416
- get ( " download " , . attribute) ,
504
+ get ( " download " , . attribute, . download ) ,
417
505
get ( " href " , . string) ,
418
506
get ( " shape " , . attribute) ,
419
507
get ( " ping " , . array( of: . string) ) ,
0 commit comments