Skip to content

Commit effede9

Browse files
minor diagnostic improvements; breaking changes; removed some whitespace
1 parent 4d6affc commit effede9

File tree

10 files changed

+154
-113
lines changed

10 files changed

+154
-113
lines changed
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
2+
import HTMLKitUtilities
3+
import SwiftDiagnostics
4+
import SwiftSyntax
5+
6+
// MARK: DiagnosticMsg
7+
package struct DiagnosticMsg: DiagnosticMessage, FixItMessage {
8+
package let message:String
9+
package let diagnosticID:MessageID
10+
package let severity:DiagnosticSeverity
11+
package var fixItID: MessageID { diagnosticID }
12+
13+
package init(id: String, message: String, severity: DiagnosticSeverity = .error) {
14+
self.message = message
15+
self.diagnosticID = MessageID(domain: "HTMLKitMacros", id: id)
16+
self.severity = severity
17+
}
18+
}
19+
20+
extension DiagnosticMsg {
21+
// MARK: GA Already Defined
22+
static func globalAttributeAlreadyDefined(context: HTMLExpansionContext, attribute: String, node: some SyntaxProtocol) -> Diagnostic {
23+
Diagnostic(node: node, message: DiagnosticMsg(id: "globalAttributeAlreadyDefined", message: "Global attribute \"" + attribute + "\" is already defined."))
24+
}
25+
26+
// MARK: Unallowed Expression
27+
static func unallowedExpression(context: HTMLExpansionContext, node: some ExprSyntaxProtocol) {
28+
context.diagnose(Diagnostic(node: node, message: DiagnosticMsg(id: "unallowedExpression", message: "String Interpolation is required when encoding runtime values."), fixIts: [
29+
FixIt(message: DiagnosticMsg(id: "useStringInterpolation", message: "Use String Interpolation."), changes: [
30+
FixIt.Change.replace(
31+
oldNode: Syntax(node),
32+
newNode: Syntax(StringLiteralExprSyntax(content: "\\(\(node))"))
33+
)
34+
])
35+
]))
36+
}
37+
38+
// MARK: Something went wrong
39+
static func somethingWentWrong(context: HTMLExpansionContext, node: some SyntaxProtocol, expr: some ExprSyntaxProtocol) {
40+
context.diagnose(Diagnostic(node: node, message: DiagnosticMsg(id: "somethingWentWrong", message: "Something went wrong. (" + expr.debugDescription + ")")))
41+
}
42+
43+
// MARK: Warn Interpolation
44+
static func warnInterpolation(
45+
context: HTMLExpansionContext,
46+
node: some SyntaxProtocol
47+
) {
48+
/*#if canImport(SwiftLexicalLookup)
49+
for t in node.tokens(viewMode: .fixedUp) {
50+
let results = node.lookup(t.identifier)
51+
for result in results {
52+
switch result {
53+
case .lookForMembers(let test):
54+
print("lookForMembers=" + test.debugDescription)
55+
case .lookForImplicitClosureParameters(let test):
56+
print("lookForImplicitClosureParameters=" + test.debugDescription)
57+
default:
58+
print(result.debugDescription)
59+
}
60+
}
61+
}
62+
#endif*/
63+
/*if let fix:String = InterpolationLookup.find(context: context, node) {
64+
let expression:String = "\(node)"
65+
let ranges:[Range<String.Index>] = string.ranges(of: expression)
66+
string.replace(expression, with: fix)
67+
remaining_interpolation -= ranges.count
68+
} else {*/
69+
guard !context.ignoresCompilerWarnings else { return }
70+
context.diagnose(Diagnostic(node: node, message: DiagnosticMsg(id: "unsafeInterpolation", message: "Interpolation may introduce raw HTML.", severity: .warning)))
71+
//}
72+
}
73+
}
74+
75+
// MARK: Expectations
76+
extension DiagnosticMsg {
77+
static func expectedArrayExpr(expr: some ExprSyntaxProtocol) -> Diagnostic {
78+
Diagnostic(node: expr, message: DiagnosticMsg(id: "expectedArrayExpr", message: "Expected array expression; got \(expr.kind)"))
79+
}
80+
static func expectedFunctionCallExpr(expr: some ExprSyntaxProtocol) -> Diagnostic {
81+
Diagnostic(node: expr, message: DiagnosticMsg(id: "expectedFunctionCallExpr", message: "Expected function call expression; got \(expr.kind)"))
82+
}
83+
static func expectedMemberAccessExpr(expr: some ExprSyntaxProtocol) -> Diagnostic {
84+
Diagnostic(node: expr, message: DiagnosticMsg(id: "expectedMemberAccessExpr", message: "Expected member access expression; got \(expr.kind)"))
85+
}
86+
static func expectedFunctionCallOrMemberAccessExpr(expr: some ExprSyntaxProtocol) -> Diagnostic {
87+
Diagnostic(node: expr, message: DiagnosticMsg(id: "expectedFunctionCallOrMemberAccessExpr", message: "Expected function call or member access expression; got \(expr.kind)"))
88+
}
89+
static func expectedStringLiteral(expr: some ExprSyntaxProtocol) -> Diagnostic {
90+
Diagnostic(node: expr, message: DiagnosticMsg(id: "expectedStringLiteral", message: "Expected string literal; got \(expr.kind)"))
91+
}
92+
static func expectedStringLiteralOrMemberAccess(expr: some ExprSyntaxProtocol) -> Diagnostic {
93+
Diagnostic(node: expr, message: DiagnosticMsg(id: "expectedStringLiteralOrMemberAccess", message: "Expected string literal or member access; got \(expr.kind)"))
94+
}
95+
static func stringLiteralContainsIllegalCharacter(expr: some ExprSyntaxProtocol, char: String) -> Diagnostic {
96+
Diagnostic(node: expr, message: DiagnosticMsg(id: "stringLiteralContainsIllegalCharacter", message: "String literal contains illegal character: \"\(char)\""))
97+
}
98+
}

Sources/HTMLKitParse/ExpandHTMLMacro.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ extension HTMLKitUtilities {
6767
private static func hasNoInterpolation(_ context: HTMLExpansionContext, _ node: MacroExpansionExprSyntax, _ string: String) -> Bool {
6868
guard string.firstRange(of: try! Regex("\\((.*)\\)")) == nil else {
6969
if !context.ignoresCompilerWarnings {
70-
context.context.diagnose(Diagnostic(node: node, message: DiagnosticMsg(id: "interpolationNotAllowedForDataType", message: "String Interpolation is not allowed for this data type. Runtime values get converted to raw text, which is not the intended result.")))
70+
context.diagnose(Diagnostic(node: node, message: DiagnosticMsg(id: "interpolationNotAllowedForDataType", message: "String Interpolation is not allowed for this data type. Runtime values get converted to raw text, which is not the intended result.")))
7171
}
7272
return false
7373
}

Sources/HTMLKitParse/InterpolationLookup.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ enum InterpolationLookup {
1818
let parsed = Parser.parse(source: string).statements
1919
cached[file] = parsed
2020
} else {
21-
context.context.diagnose(Diagnostic(node: node, message: DiagnosticMsg(id: "fileNotFound", message: "Could not find file (\(file)) on disk, or was denied disk access (file access is always denied on macOS due to the macro being in a sandbox).", severity: .warning)))
21+
context.diagnose(Diagnostic(node: node, message: DiagnosticMsg(id: "fileNotFound", message: "Could not find file (\(file)) on disk, or was denied disk access (file access is always denied on macOS due to the macro being in a sandbox).", severity: .warning)))
2222
}
2323
}
2424
}

Sources/HTMLKitParse/ParseArguments.swift

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,27 @@ extension HTMLKitUtilities {
2626
context.key = key
2727
switch key {
2828
case "encoding":
29-
context.encoding = parseEncoding(expression: child.expression) ?? .string
29+
context.encoding = parseEncoding(expr: child.expression) ?? .string
3030
case "representation":
3131
context.representation = parseRepresentation(expr: child.expression) ?? .literal
3232
case "lookupFiles":
33-
if let elements = child.expression.array?.elements {
34-
context.lookupFiles = Set(elements.compactMap({ $0.expression.stringLiteral?.string(encoding: context.encoding) }))
33+
guard let array = child.expression.array?.elements else {
34+
context.diagnose(DiagnosticMsg.expectedArrayExpr(expr: child.expression))
35+
break
3536
}
37+
context.lookupFiles = Set(array.compactMap({
38+
guard let string = $0.expression.stringLiteral?.string(encoding: context.encoding) else {
39+
context.diagnose(DiagnosticMsg.expectedStringLiteral(expr: $0.expression))
40+
return nil
41+
}
42+
return string
43+
}))
3644
case "attributes":
37-
if let elements = child.expression.array?.elements {
38-
(globalAttributes, trailingSlash) = parseGlobalAttributes(context: context, array: elements)
45+
guard let array = child.expression.array?.elements else {
46+
context.diagnose(DiagnosticMsg.expectedArrayExpr(expr: child.expression))
47+
break
3948
}
49+
(globalAttributes, trailingSlash) = parseGlobalAttributes(context: context, array: array)
4050
default:
4151
context.key = otherAttributes[key] ?? key
4252
if let test = HTMLAttribute.Extra.parse(context: context, expr: child.expression) {
Lines changed: 12 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,35 @@
11

22
import HTMLElements
33
import HTMLKitUtilities
4-
import SwiftDiagnostics
54
import SwiftSyntax
65

76
extension HTMLKitUtilities {
87
// MARK: Escape HTML
9-
public static func escapeHTML(
10-
context: HTMLExpansionContext
11-
) -> String {
8+
public static func escapeHTML(context: HTMLExpansionContext) -> String {
129
var context = context
1310
return escapeHTML(context: &context)
1411
}
15-
public static func escapeHTML(
16-
context: inout HTMLExpansionContext
17-
) -> String {
12+
public static func escapeHTML(context: inout HTMLExpansionContext) -> String {
1813
context.escape = true
1914
context.escapeAttributes = true
2015
context.elementsRequireEscaping = true
21-
return html(
22-
context: context
23-
)
16+
return html(context: context)
2417
}
2518

2619
// MARK: Raw HTML
27-
public static func rawHTML(
28-
context: HTMLExpansionContext
29-
) -> String {
20+
public static func rawHTML(context: HTMLExpansionContext) -> String {
3021
var context = context
3122
return rawHTML(context: &context)
3223
}
33-
public static func rawHTML(
34-
context: inout HTMLExpansionContext
35-
) -> String {
24+
public static func rawHTML(context: inout HTMLExpansionContext) -> String {
3625
context.escape = false
3726
context.escapeAttributes = false
3827
context.elementsRequireEscaping = false
39-
return html(
40-
context: context
41-
)
28+
return html(context: context)
4229
}
4330

4431
// MARK: HTML
45-
public static func html(
46-
context: HTMLExpansionContext
47-
) -> String {
32+
public static func html(context: HTMLExpansionContext) -> String {
4833
var context = context
4934
let children = context.arguments.children(viewMode: .all)
5035
var innerHTML = ""
@@ -53,7 +38,7 @@ extension HTMLKitUtilities {
5338
guard let child = e.labeled else { continue }
5439
if let key = child.label?.text {
5540
switch key {
56-
case "encoding": context.encoding = parseEncoding(expression: child.expression) ?? .string
41+
case "encoding": context.encoding = parseEncoding(expr: child.expression) ?? .string
5742
case "representation": context.representation = parseRepresentation(expr: child.expression) ?? .literal
5843
case "minify": context.minify = child.expression.boolean(context) ?? false
5944
default: break
@@ -74,12 +59,12 @@ extension HTMLKitUtilities {
7459
}
7560

7661
// MARK: Parse Encoding
77-
public static func parseEncoding(expression: ExprSyntax) -> HTMLEncoding? {
78-
switch expression.kind {
62+
public static func parseEncoding(expr: some ExprSyntaxProtocol) -> HTMLEncoding? {
63+
switch expr.kind {
7964
case .memberAccessExpr:
80-
return HTMLEncoding(rawValue: expression.memberAccess!.declName.baseName.text)
65+
return HTMLEncoding(rawValue: expr.memberAccess!.declName.baseName.text)
8166
case .functionCallExpr:
82-
let function = expression.functionCall!
67+
let function = expr.functionCall!
8368
switch function.calledExpression.memberAccess?.declName.baseName.text {
8469
case "custom":
8570
guard let logic = function.arguments.first?.expression.stringLiteral?.string(encoding: .string) else { return nil }
@@ -160,68 +145,4 @@ extension HTMLKitUtilities {
160145
return nil
161146
}
162147
}
163-
}
164-
165-
extension HTMLKitUtilities {
166-
// MARK: GA Already Defined
167-
static func globalAttributeAlreadyDefined(context: HTMLExpansionContext, attribute: String, node: some SyntaxProtocol) {
168-
context.context.diagnose(Diagnostic(node: node, message: DiagnosticMsg(id: "globalAttributeAlreadyDefined", message: "Global attribute \"" + attribute + "\" is already defined.")))
169-
}
170-
171-
// MARK: Unallowed Expression
172-
static func unallowedExpression(context: HTMLExpansionContext, node: ExprSyntax) {
173-
context.context.diagnose(Diagnostic(node: node, message: DiagnosticMsg(id: "unallowedExpression", message: "String Interpolation is required when encoding runtime values."), fixIts: [
174-
FixIt(message: DiagnosticMsg(id: "useStringInterpolation", message: "Use String Interpolation."), changes: [
175-
FixIt.Change.replace(
176-
oldNode: Syntax(node),
177-
newNode: Syntax(StringLiteralExprSyntax(content: "\\(\(node))"))
178-
)
179-
])
180-
]))
181-
}
182-
183-
// MARK: Warn Interpolation
184-
static func warnInterpolation(
185-
context: HTMLExpansionContext,
186-
node: some SyntaxProtocol
187-
) {
188-
/*#if canImport(SwiftLexicalLookup)
189-
for t in node.tokens(viewMode: .fixedUp) {
190-
let results = node.lookup(t.identifier)
191-
for result in results {
192-
switch result {
193-
case .lookForMembers(let test):
194-
print("lookForMembers=" + test.debugDescription)
195-
case .lookForImplicitClosureParameters(let test):
196-
print("lookForImplicitClosureParameters=" + test.debugDescription)
197-
default:
198-
print(result.debugDescription)
199-
}
200-
}
201-
}
202-
#endif*/
203-
/*if let fix:String = InterpolationLookup.find(context: context, node) {
204-
let expression:String = "\(node)"
205-
let ranges:[Range<String.Index>] = string.ranges(of: expression)
206-
string.replace(expression, with: fix)
207-
remaining_interpolation -= ranges.count
208-
} else {*/
209-
guard !context.ignoresCompilerWarnings else { return }
210-
context.context.diagnose(Diagnostic(node: node, message: DiagnosticMsg(id: "unsafeInterpolation", message: "Interpolation may introduce raw HTML.", severity: .warning)))
211-
//}
212-
}
213-
}
214-
215-
// MARK: DiagnosticMsg
216-
package struct DiagnosticMsg: DiagnosticMessage, FixItMessage {
217-
package let message:String
218-
package let diagnosticID:MessageID
219-
package let severity:DiagnosticSeverity
220-
package var fixItID: MessageID { diagnosticID }
221-
222-
package init(id: String, message: String, severity: DiagnosticSeverity = .error) {
223-
self.message = message
224-
self.diagnosticID = MessageID(domain: "HTMLKitMacros", id: id)
225-
self.severity = severity
226-
}
227148
}

Sources/HTMLKitParse/ParseGlobalAttributes.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ extension HTMLKitUtilities {
1919
c.key = key
2020
c.arguments = function.arguments
2121
if key.contains(" ") {
22-
context.context.diagnose(Diagnostic(node: firstExpression, message: DiagnosticMsg(id: "spacesNotAllowedInAttributeDeclaration", message: "Spaces are not allowed in attribute declaration.")))
22+
//context.diagnose(DiagnosticMsg.stringLiteralContainsIllegalCharacter(expr: firstExpression, char: " "))
23+
context.diagnose(Diagnostic(node: firstExpression, message: DiagnosticMsg(id: "spacesNotAllowedInAttributeDeclaration", message: "Spaces are not allowed in attribute declaration.")))
2324
} else if keys.contains(key) {
24-
globalAttributeAlreadyDefined(context: context, attribute: key, node: firstExpression)
25+
context.diagnose(DiagnosticMsg.globalAttributeAlreadyDefined(context: context, attribute: key, node: firstExpression))
2526
} else if let attr = HTMLAttribute.init(context: c) {
2627
attributes.append(attr)
2728
key = attr.key
@@ -30,7 +31,7 @@ extension HTMLKitUtilities {
3031
}
3132
} else if let member = element.expression.memberAccess?.declName.baseName.text, member == "trailingSlash" {
3233
if keys.contains(member) {
33-
globalAttributeAlreadyDefined(context: context, attribute: member, node: element.expression)
34+
context.diagnose(DiagnosticMsg.globalAttributeAlreadyDefined(context: context, attribute: member, node: element.expression))
3435
} else {
3536
trailingSlash = true
3637
keys.insert(member)

Sources/HTMLKitParse/ParseInnerHTML.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,15 @@ extension HTMLKitUtilities {
2222
case "rawHTML", "anyRawHTML":
2323
return rawHTML(context: &c)
2424
default:
25+
DiagnosticMsg.somethingWentWrong(context: context, node: expr, expr: expansion)
2526
return "" // TODO: fix?
2627
}
2728
} else if let element = parseElement(context: context, expr: expr) {
2829
return element
2930
} else if let literal = parseLiteral(context: context, expr: expr) {
3031
return literal.value(key: "", escape: context.escape, escapeAttributes: context.escapeAttributes)
3132
} else {
32-
unallowedExpression(context: context, node: expr)
33+
DiagnosticMsg.unallowedExpression(context: context, node: expr)
3334
return nil
3435
}
3536
}

0 commit comments

Comments
 (0)