Skip to content

Commit 19644da

Browse files
authored
Merge pull request #97 from omochi/method-chain-style
パラメータオブジェクトをメソッドチェーンで構築できるようにする
2 parents 07a2438 + 2e8f54d commit 19644da

26 files changed

+7331
-403
lines changed

Codegen/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ DerivedData/
88
.netrc
99
.swiftpm
1010
node_modules
11+
data.json

Codegen/Package.resolved

+9
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@
2727
"version" : "0.3.0"
2828
}
2929
},
30+
{
31+
"identity" : "swift-collections",
32+
"kind" : "remoteSourceControl",
33+
"location" : "https://github.com/apple/swift-collections",
34+
"state" : {
35+
"revision" : "94cf62b3ba8d4bed62680a282d4c25f9c63c2efb",
36+
"version" : "1.1.0"
37+
}
38+
},
3039
{
3140
"identity" : "swift-format",
3241
"kind" : "remoteSourceControl",

Codegen/Package.swift

+2
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@ let package = Package(
1212
)
1313
],
1414
dependencies: [
15+
.package(url: "https://github.com/apple/swift-collections", from: "1.1.0"),
1516
.package(url: "https://github.com/omochi/CodegenKit", from: "1.4.1")
1617
],
1718
targets: [
1819
.target(
1920
name: "SRTCodegen",
2021
dependencies: [
22+
.product(name: "Collections", package: "swift-collections"),
2123
.product(name: "CodegenKit", package: "CodegenKit")
2224
]
2325
),

Codegen/Sources/SRTCodegen/Def.swift

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import Collections
2+
3+
struct Def: Codable {
4+
var tagNames: [String]
5+
var voidElements: [String]
6+
var elementAttributes: [String: [String]]
7+
var eventAttributes: [String]
8+
var cssProperties: [String]
9+
10+
mutating func fix() {
11+
tagNames.removeAll { (tagName) in
12+
voidElements.contains(tagName)
13+
}
14+
15+
self.cssProperties = {
16+
var css: OrderedSet<String> = []
17+
18+
for x in cssProperties {
19+
if !x.hasPrefix("-") {
20+
css.remove("-" + x)
21+
}
22+
23+
css.append(x)
24+
}
25+
26+
return css.elements
27+
}()
28+
}
29+
30+
var allAttributes: [String] {
31+
var attrs: OrderedSet<String> = []
32+
attrs.formUnion(elementAttributes["*"] ?? [])
33+
34+
var dict = elementAttributes
35+
dict["*"] = nil
36+
37+
for key in dict.keys.sorted() {
38+
attrs.formUnion(dict[key] ?? [])
39+
}
40+
41+
return attrs.elements
42+
}
43+
}

Codegen/Sources/SRTCodegen/Keywords.swift

-1
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import Foundation
2+
import CodegenKit
3+
4+
struct AttributesRenderer: Renderer {
5+
var def: Def
6+
7+
func isTarget(file: URL) -> Bool {
8+
file.lastPathComponent == "Attributes.swift"
9+
}
10+
11+
func render(template: inout CodeTemplateModule.CodeTemplate, file: URL, on runner: CodegenKit.CodegenRunner) throws {
12+
let code = def.allAttributes.map { (attribute) in
13+
renderSetter(attribute: attribute)
14+
}.joined(separator: "\n")
15+
16+
template["setters"] = code
17+
}
18+
19+
private func renderSetter(attribute: String) -> String {
20+
let symbol = attribute.kebabToCamel()
21+
22+
return """
23+
public func \(renderIdentifier(symbol))(_ value: String) -> Attributes {
24+
set("\(attribute)", to: value)
25+
}
26+
27+
"""
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import Foundation
2+
import CodegenKit
3+
4+
struct EventListenersRenderer: Renderer {
5+
var def: Def
6+
7+
func isTarget(file: URL) -> Bool {
8+
file.lastPathComponent == "EventListeners.swift"
9+
}
10+
11+
func render(template: inout CodeTemplateModule.CodeTemplate, file: URL, on runner: CodegenKit.CodegenRunner) throws {
12+
let code = def.eventAttributes.map { (attribute) in
13+
renderSetter(attribute: attribute)
14+
}.joined(separator: "\n")
15+
16+
template["setters"] = code
17+
}
18+
19+
private func renderSetter(attribute: String) -> String {
20+
var attribute = attribute
21+
if attribute.hasPrefix("on") {
22+
attribute.removeFirst(2)
23+
}
24+
25+
return """
26+
public func \(renderIdentifier(attribute))(_ value: EventListener) -> EventListeners {
27+
set("\(attribute)", to: value)
28+
}
29+
30+
"""
31+
}
32+
}

Codegen/Sources/SRTCodegen/HTMLTagRenderer.swift Codegen/Sources/SRTCodegen/Renderers/HTMLTagRenderer.swift

+7-13
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ import Foundation
22
import CodegenKit
33

44
struct HTMLTagRenderer: Renderer {
5-
var tags: [String]
6-
5+
var def: Def
6+
77
func isTarget(file: URL) -> Bool {
88
file.lastPathComponent == "HTMLTags.swift"
99
}
1010

1111
func render(template: inout CodeTemplateModule.CodeTemplate, file: URL, on runner: CodegenKit.CodegenRunner) throws {
12-
let code = tags.map { (tag) in
12+
let code = def.tagNames.map { (tag) in
1313
renderTagFunc(tag: tag)
1414
}.joined(separator: "\n")
1515

@@ -21,28 +21,22 @@ struct HTMLTagRenderer: Renderer {
2121
public func \(renderIdentifier(tag))(
2222
key: AnyHashable? = nil,
2323
ref: RefObject<JSHTMLElement>? = nil,
24-
attributes: Attributes = [:],
25-
listeners: EventListeners = [:],
24+
attributes: Attributes? = nil,
25+
style: Style? = nil,
26+
listeners: EventListeners? = nil,
2627
@ChildrenBuilder _ children: () -> [Node] = { [] }
2728
) -> HTMLElement {
2829
HTMLElement(
2930
tagName: "\(tag)",
3031
key: key,
3132
ref: ref,
3233
attributes: attributes,
34+
style: style,
3335
listeners: listeners,
3436
children: children()
3537
)
3638
}
3739
3840
"""
3941
}
40-
41-
private func renderIdentifier(_ text: String) -> String {
42-
var text = text
43-
if keywords.contains(text) {
44-
text = "`\(text)`"
45-
}
46-
return text
47-
}
4842
}

Codegen/Sources/SRTCodegen/HTMLLeafTagRenderer.swift Codegen/Sources/SRTCodegen/Renderers/HTMLVoidTagRenderer.swift

+8-6
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import Foundation
22
import CodegenKit
33

4-
struct HTMLLeafTagRenderer: Renderer {
5-
var tags: [String]
4+
struct HTMLVoidTagRenderer: Renderer {
5+
var def: Def
66

77
func isTarget(file: URL) -> Bool {
8-
file.lastPathComponent == "HTMLLeafTags.swift"
8+
file.lastPathComponent == "HTMLVoidTags.swift"
99
}
1010

1111
func render(template: inout CodeTemplateModule.CodeTemplate, file: URL, on runner: CodegenKit.CodegenRunner) throws {
12-
let code = tags.map { (tag) in
12+
let code = def.voidElements.map { (tag) in
1313
renderTagFunc(tag: tag)
1414
}.joined(separator: "\n")
1515

@@ -21,14 +21,16 @@ struct HTMLLeafTagRenderer: Renderer {
2121
public func \(tag)(
2222
key: AnyHashable? = nil,
2323
ref: RefObject<JSHTMLElement>? = nil,
24-
attributes: Attributes = [:],
25-
listeners: EventListeners = [:]
24+
attributes: Attributes? = nil,
25+
style: Style? = nil,
26+
listeners: EventListeners? = nil
2627
) -> HTMLElement {
2728
HTMLElement(
2829
tagName: "\(tag)",
2930
key: key,
3031
ref: ref,
3132
attributes: attributes,
33+
style: style,
3234
listeners: listeners
3335
)
3436
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import Foundation
2+
import CodegenKit
3+
4+
struct StyleRenderer: Renderer {
5+
var def: Def
6+
7+
func isTarget(file: URL) -> Bool {
8+
file.lastPathComponent == "Style.swift"
9+
}
10+
11+
func render(template: inout CodeTemplateModule.CodeTemplate, file: URL, on runner: CodegenKit.CodegenRunner) throws {
12+
let code = def.cssProperties.map { (attribute) in
13+
renderSetter(attribute: attribute)
14+
}.joined(separator: "\n")
15+
16+
template["setters"] = code
17+
}
18+
19+
private func renderSetter(attribute: String) -> String {
20+
let symbol = attribute.kebabToCamel()
21+
22+
return """
23+
public func \(renderIdentifier(symbol))(_ value: String) -> Style {
24+
set("\(attribute)", to: value)
25+
}
26+
27+
"""
28+
}
29+
}

Codegen/Sources/SRTCodegen/SRTCodegen.swift

+9-9
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,25 @@ public struct SRTCodegen {
66
self.codegenDir = URL(filePath: ".", directoryHint: .isDirectory)
77
self.swiftReactDir = codegenDir.deletingLastPathComponent()
88
self.htmlSourceDir = swiftReactDir.appending(components: "Sources", "React", "HTML", directoryHint: .isDirectory)
9-
let tagsDir = codegenDir.appending(components: "node_modules", "html-tags")
10-
let tagsJSON = try Data(contentsOf: tagsDir.appending(path: "html-tags.json"))
9+
let json = try Data(contentsOf: codegenDir.appending(path: "data.json"))
1110
let decoder = JSONDecoder()
12-
self.tags = try decoder.decode(Array<String>.self, from: tagsJSON)
13-
let leafJSON = try Data(contentsOf: tagsDir.appending(path: "html-tags-void.json"))
14-
self.leafTags = try decoder.decode(Array<String>.self, from: leafJSON)
11+
self.def = try decoder.decode(Def.self, from: json)
12+
def.fix()
1513
}
1614

1715
var codegenDir: URL
1816
var swiftReactDir: URL
1917
var htmlSourceDir: URL
20-
var tags: [String]
21-
var leafTags: [String]
18+
var def: Def
2219

2320
public func run() throws {
2421
let runner = CodegenRunner(
2522
renderers: [
26-
HTMLTagRenderer(tags: tags),
27-
HTMLLeafTagRenderer(tags: leafTags)
23+
HTMLTagRenderer(def: def),
24+
HTMLVoidTagRenderer(def: def),
25+
AttributesRenderer(def: def),
26+
StyleRenderer(def: def),
27+
EventListenersRenderer(def: def)
2828
]
2929
)
3030

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import Foundation
2+
3+
public let keywords = [
4+
"as",
5+
"class",
6+
"continue",
7+
"default",
8+
"defer",
9+
"for",
10+
"is",
11+
"var",
12+
]
13+
14+
func renderIdentifier(_ text: String) -> String {
15+
var text = text
16+
if keywords.contains(text) {
17+
text = "`\(text)`"
18+
}
19+
return text
20+
}
21+
22+
extension String {
23+
func kebabToCamel() -> String {
24+
let strs = self.components(separatedBy: "-")
25+
.filter { !$0.isEmpty }
26+
27+
var result = ""
28+
for (index, str) in strs.enumerated() {
29+
if index == 0 {
30+
result += str.lowercased()
31+
} else {
32+
result += str.capitalized
33+
}
34+
}
35+
36+
return result
37+
}
38+
}

Codegen/index.mjs

+16-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
1-
import htmlTags from "html-tags/index.js";
2-
import htmlLeafTags from "html-tags/void.js";
1+
import { htmlTagNames } from "html-tag-names";
2+
import { htmlVoidElements } from "html-void-elements";
3+
import { htmlElementAttributes } from "html-element-attributes";
4+
import { htmlEventAttributes } from "html-event-attributes";
5+
import * as kcpModule from "known-css-properties";
36

4-
console.log(htmlTags);
5-
console.log(htmlLeafTags);
7+
const json = {
8+
"tagNames": htmlTagNames,
9+
"voidElements": htmlVoidElements,
10+
"elementAttributes": htmlElementAttributes,
11+
"eventAttributes": htmlEventAttributes,
12+
"cssProperties": kcpModule.all
13+
};
14+
15+
const string = JSON.stringify(json, undefined, 2);
16+
17+
console.log(string);

0 commit comments

Comments
 (0)