Skip to content

Commit cf5b893

Browse files
committed
Refactor and greatly improve AXHelper
1 parent bd0d328 commit cf5b893

File tree

8 files changed

+962
-1164
lines changed

8 files changed

+962
-1164
lines changed

ax/Package.swift

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,31 @@
1-
// swift-tools-version: 6.1
1+
// swift-tools-version:6.1
22
// The swift-tools-version declares the minimum version of Swift required to build this package.
33

44
import PackageDescription
55

66
let package = Package(
7-
name: "x",
7+
name: "ax", // Package name
88
platforms: [
9-
.macOS(.v11)
9+
.macOS(.v11) // macOS 11.0 or later
10+
],
11+
products: [ // EXPLICITLY DEFINE THE EXECUTABLE PRODUCT
12+
.executable(name: "ax", targets: ["ax"])
1013
],
1114
targets: [
1215
// Targets are the basic building blocks of a package, defining a module or a test suite.
1316
// Targets can depend on other targets in this package and products from dependencies.
1417
.executableTarget(
15-
name: "ax",
16-
swiftSettings: [
17-
.unsafeFlags(["-framework", "ApplicationServices", "-framework", "AppKit"])
18+
name: "ax", // Target name, product will be 'ax'
19+
path: "Sources/AXHelper", // Specify the path to the source files
20+
sources: [ // Explicitly list all source files
21+
"AXTool.swift",
22+
"AXConstants.swift",
23+
"AXLogging.swift",
24+
"AXModels.swift",
25+
"AXSearch.swift",
26+
"AXUtils.swift"
1827
]
28+
// swiftSettings for framework linking removed, relying on Swift imports.
1929
),
2030
]
2131
)

ax/Sources/AXHelper/AXConstants.swift

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// AXConstants.swift - Defines global constants used throughout AXHelper
2+
3+
import Foundation
4+
5+
// Standard Accessibility Attributes
6+
public let kAXRoleAttribute = "AXRole"
7+
public let kAXSubroleAttribute = "AXSubrole"
8+
public let kAXRoleDescriptionAttribute = "AXRoleDescription"
9+
public let kAXTitleAttribute = "AXTitle"
10+
public let kAXValueAttribute = "AXValue"
11+
public let kAXDescriptionAttribute = "AXDescription"
12+
public let kAXHelpAttribute = "AXHelp"
13+
public let kAXIdentifierAttribute = "AXIdentifier"
14+
public let kAXPlaceholderValueAttribute = "AXPlaceholderValue"
15+
public let kAXLabelUIElementAttribute = "AXLabelUIElement"
16+
public let kAXTitleUIElementAttribute = "AXTitleUIElement"
17+
public let kAXLabelValueAttribute = "AXLabelValue"
18+
19+
public let kAXChildrenAttribute = "AXChildren"
20+
public let kAXParentAttribute = "AXParent"
21+
public let kAXWindowsAttribute = "AXWindows"
22+
public let kAXMainWindowAttribute = "AXMainWindow"
23+
public let kAXFocusedWindowAttribute = "AXFocusedWindow"
24+
public let kAXFocusedUIElementAttribute = "AXFocusedUIElement"
25+
26+
public let kAXEnabledAttribute = "AXEnabled"
27+
public let kAXFocusedAttribute = "AXFocused"
28+
public let kAXMainAttribute = "AXMain"
29+
30+
public let kAXPositionAttribute = "AXPosition"
31+
public let kAXSizeAttribute = "AXSize"
32+
33+
// Actions
34+
public let kAXActionsAttribute = "AXActions"
35+
public let kAXActionNamesAttribute = "AXActionNames"
36+
public let kAXPressAction = "AXPress"
37+
public let kAXShowMenuAction = "AXShowMenu"
38+
39+
// Attributes for web content and tables/lists
40+
public let kAXVisibleChildrenAttribute = "AXVisibleChildren"
41+
public let kAXTabsAttribute = "AXTabs"
42+
public let kAXSelectedChildrenAttribute = "AXSelectedChildren"
43+
public let kAXRowsAttribute = "AXRows"
44+
public let kAXColumnsAttribute = "AXColumns"
45+
46+
// DOM specific attributes (often strings or arrays of strings)
47+
public let kAXDOMIdentifierAttribute = "AXDOMIdentifier" // Example, might not be standard AX
48+
public let kAXDOMClassListAttribute = "AXDOMClassList" // Example, might not be standard AX
49+
public let kAXARIADOMResourceAttribute = "AXARIADOMResource" // Example
50+
public let kAXARIADOMFunctionAttribute = "AXARIADOM-función" // Corrected identifier, kept original string value.
51+
52+
// Configuration Constants
53+
public let MAX_COLLECT_ALL_HITS = 100000
54+
public let AX_BINARY_VERSION = "1.1.3" // Updated version

ax/Sources/AXHelper/AXLogging.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// AXLogging.swift - Manages debug logging
2+
3+
import Foundation
4+
5+
// More advanced logging setup
6+
public let GLOBAL_DEBUG_ENABLED = true // Consistent with previous advanced setup
7+
@MainActor public var commandSpecificDebugLoggingEnabled = false
8+
@MainActor public var collectedDebugLogs: [String] = []
9+
10+
@MainActor // Functions calling this might be on main actor, good to keep it consistent.
11+
public func debug(_ message: String) {
12+
// AX_BINARY_VERSION is in AXConstants.swift
13+
let logMessage = "DEBUG: AX Binary Version: \(AX_BINARY_VERSION) - \(message)"
14+
if commandSpecificDebugLoggingEnabled {
15+
collectedDebugLogs.append(logMessage)
16+
}
17+
if GLOBAL_DEBUG_ENABLED {
18+
fputs(logMessage + "\n", stderr)
19+
}
20+
}

ax/Sources/AXHelper/AXModels.swift

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// AXModels.swift - Contains Codable data models for the AXHelper utility
2+
3+
import Foundation
4+
5+
// Original models from the older main.swift version, made public
6+
public struct CommandEnvelope: Codable {
7+
public enum Verb: String, Codable { case query, perform }
8+
public let cmd: Verb
9+
public let locator: Locator
10+
public let attributes: [String]? // for query
11+
public let action: String? // for perform
12+
public let multi: Bool? // NEW in that version
13+
public let requireAction: String? // NEW in that version
14+
// Added new fields from more recent versions
15+
public let debug_logging: Bool?
16+
public let max_elements: Int?
17+
public let output_format: String?
18+
}
19+
20+
public struct Locator: Codable {
21+
public let app : String
22+
public let role : String
23+
public let match : [String:String]
24+
public let pathHint : [String]?
25+
}
26+
27+
public struct QueryResponse: Codable {
28+
public let attributes: [String: AnyCodable]
29+
public var debug_logs: [String]? // Added
30+
31+
public init(attributes: [String: Any], debug_logs: [String]? = nil) { // Updated init
32+
self.attributes = attributes.mapValues(AnyCodable.init)
33+
self.debug_logs = debug_logs
34+
}
35+
}
36+
37+
public struct MultiQueryResponse: Codable {
38+
public let elements: [[String: AnyCodable]]
39+
public var debug_logs: [String]? // Added
40+
41+
public init(elements: [[String: Any]], debug_logs: [String]? = nil) { // Updated init
42+
self.elements = elements.map { element in
43+
element.mapValues(AnyCodable.init)
44+
}
45+
self.debug_logs = debug_logs
46+
}
47+
}
48+
49+
public struct PerformResponse: Codable {
50+
public let status: String
51+
public var debug_logs: [String]? // Added
52+
}
53+
54+
public struct ErrorResponse: Codable {
55+
public let error: String
56+
public var debug_logs: [String]? // Added
57+
}
58+
59+
// Added new response type from more recent versions
60+
public struct TextContentResponse: Codable {
61+
public let text_content: String
62+
public var debug_logs: [String]?
63+
}
64+
65+
// AnyCodable wrapper type for JSON encoding of Any values
66+
public struct AnyCodable: Codable {
67+
public let value: Any
68+
69+
public init(_ value: Any) {
70+
self.value = value
71+
}
72+
73+
public init(from decoder: Decoder) throws {
74+
let container = try decoder.singleValueContainer()
75+
76+
if container.decodeNil() {
77+
self.value = NSNull()
78+
} else if let bool = try? container.decode(Bool.self) {
79+
self.value = bool
80+
} else if let int = try? container.decode(Int.self) {
81+
self.value = int
82+
} else if let double = try? container.decode(Double.self) {
83+
self.value = double
84+
} else if let string = try? container.decode(String.self) {
85+
self.value = string
86+
} else if let array = try? container.decode([AnyCodable].self) {
87+
self.value = array.map { $0.value }
88+
} else if let dict = try? container.decode([String: AnyCodable].self) {
89+
self.value = dict.mapValues { $0.value }
90+
} else {
91+
throw DecodingError.dataCorruptedError(
92+
in: container,
93+
debugDescription: "AnyCodable cannot decode value"
94+
)
95+
}
96+
}
97+
98+
public func encode(to encoder: Encoder) throws {
99+
var container = encoder.singleValueContainer()
100+
101+
switch value {
102+
case is NSNull:
103+
try container.encodeNil()
104+
case let bool as Bool:
105+
try container.encode(bool)
106+
case let int as Int:
107+
try container.encode(int)
108+
case let double as Double:
109+
try container.encode(double)
110+
case let string as String:
111+
try container.encode(string)
112+
case let array as [Any]:
113+
try container.encode(array.map(AnyCodable.init))
114+
case let dict as [String: Any]:
115+
try container.encode(dict.mapValues(AnyCodable.init))
116+
default:
117+
try container.encode(String(describing: value))
118+
}
119+
}
120+
}
121+
122+
public typealias ElementAttributes = [String: Any]

0 commit comments

Comments
 (0)