Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 56 additions & 7 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ let package = Package(
targets: ["SwiftJavaConfigurationShared"]
),

.library(
name: "SwiftExtractConfigurationShared",
targets: ["SwiftExtractConfigurationShared"]
),

.library(
name: "JavaUtil",
targets: ["JavaUtil"]
Expand Down Expand Up @@ -108,6 +113,11 @@ let package = Package(
targets: ["SwiftRuntimeFunctions"]
),

.library(
name: "SwiftExtract",
targets: ["SwiftExtract"]
),

.library(
name: "JExtractSwiftLib",
targets: ["JExtractSwiftLib"]
Expand Down Expand Up @@ -271,7 +281,14 @@ let package = Package(
),

.target(
name: "SwiftJavaConfigurationShared"
name: "SwiftJavaConfigurationShared",
dependencies: [
"SwiftExtractConfigurationShared"
]
),

.target(
name: "SwiftExtractConfigurationShared"
),

.target(
Expand Down Expand Up @@ -336,6 +353,33 @@ let package = Package(
]
),

.target(
name: "SwiftExtract",
dependencies: [
.product(name: "SwiftBasicFormat", package: "swift-syntax"),
.product(name: "SwiftIfConfig", package: "swift-syntax"),
.product(name: "SwiftLexicalLookup", package: "swift-syntax"),
.product(name: "SwiftParser", package: "swift-syntax"),
.product(name: "SwiftSyntax", package: "swift-syntax"),
.product(name: "SwiftSyntaxBuilder", package: "swift-syntax"),
.product(name: "Logging", package: "swift-log"),
"SwiftExtractConfigurationShared",
],
path: "Sources/SwiftExtract",
resources: [
// Holds the `dummy.json` placeholder so SwiftPM emits a `Bundle.module`
// for this target. The real `static-build-config.json` is generated at
// build time by the `_StaticBuildConfigPlugin` build tool below.
.process("Resources")
],
swiftSettings: [
.swiftLanguageMode(.v5)
],
plugins: [
.plugin(name: "_StaticBuildConfigPlugin")
]
),

.target(
name: "JExtractSwiftLib",
dependencies: [
Expand All @@ -347,19 +391,14 @@ let package = Package(
.product(name: "ArgumentParser", package: "swift-argument-parser"),
.product(name: "OrderedCollections", package: "swift-collections"),
.product(name: "SwiftJavaJNICore", package: "swift-java-jni-core"),
"SwiftExtract",
"SwiftJavaShared",
"SwiftJavaConfigurationShared",
"CodePrinting",
],
resources: [
.process("Resources")
],
swiftSettings: [
.swiftLanguageMode(.v5),
.enableUpcomingFeature("BareSlashRegexLiterals"),
],
plugins: [
.plugin(name: "_StaticBuildConfigPlugin")
]
),

Expand Down Expand Up @@ -435,13 +474,23 @@ let package = Package(
name: "JExtractSwiftTests",
dependencies: [
"JExtractSwiftLib",
"SwiftExtract",
"CodePrinting",
],
swiftSettings: [
.swiftLanguageMode(.v5)
]
),

.testTarget(
name: "SwiftExtractTests",
dependencies: [
"SwiftExtract",
.product(name: "SwiftSyntax", package: "swift-syntax"),
.product(name: "SwiftParser", package: "swift-syntax"),
]
),

.testTarget(
name: "SwiftRuntimeFunctionsTests",
dependencies: [
Expand Down
1 change: 1 addition & 0 deletions Plugins/PluginsShared/SwiftExtractConfigurationShared
19 changes: 0 additions & 19 deletions Sources/JExtractSwiftLib/AnalysisResult.swift

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
//
//===----------------------------------------------------------------------===//

import SwiftExtract
import SwiftJavaConfigurationShared
import SwiftJavaJNICore

Expand Down
64 changes: 64 additions & 0 deletions Sources/JExtractSwiftLib/Configuration+SwiftExtract.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2024-2026 Apple Inc. and the Swift.org project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of Swift.org project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

import SwiftExtract
import SwiftJavaConfigurationShared

/// Bridges swift-java's `Configuration` onto the language-neutral
/// `SwiftExtractConfiguration` surface consumed by `SwiftExtract`.
///
/// Most members are satisfied directly by `Configuration`'s own properties.
/// `Configuration` shares `AccessLevelMode` with the analyzer (both pull it in
/// from `SwiftExtractConfigurationShared`), so `swiftExtractAccessLevel` is a
/// straight passthrough. Only `swiftExtractLogLevel` needs a mapping from
/// swift-java's `LogLevel` onto the neutral `Logger.Level`.
extension Configuration: SwiftExtractConfiguration {
public var swiftExtractAccessLevel: AccessLevelMode {
effectiveMinimumInputAccessLevelMode
}

public var swiftExtractLogLevel: SwiftExtract.Logger.Level? {
guard let logLevel else { return nil }
switch logLevel {
case .trace: return .trace
case .debug: return .debug
case .info: return .info
case .notice: return .notice
case .warning: return .warning
case .error: return .error
case .critical: return .critical
}
}

// swift-java targets Java, which cannot express Swift operators or
// construct open generic types directly: leave both knobs off
public var extractsOperators: Bool { false }
public var extractsGenericTypeInitializers: Bool { false }
}

extension LogLevel {
/// Bridges from the analysis layer's neutral `Logger.Level` (used by the CLI's
/// `--log-level` option) onto swift-java's own `LogLevel`.
public init(_ level: SwiftExtract.Logger.Level) {
switch level {
case .trace: self = .trace
case .debug: self = .debug
case .info: self = .info
case .notice: self = .notice
case .warning: self = .warning
case .error: self = .error
case .critical: self = .critical
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
//
//===----------------------------------------------------------------------===//

import SwiftExtract
import SwiftJavaJNICore

extension JavaType {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,34 +15,7 @@
import SwiftJavaJNICore

extension String {

var firstCharacterUppercased: String {
guard let f = first else {
return self
}

return "\(f.uppercased())\(String(dropFirst()))"
}

var firstCharacterLowercased: String {
guard let f = first else {
return self
}

return "\(f.lowercased())\(String(dropFirst()))"
}

/// Returns whether the string is of the format `isX`
var hasJavaBooleanNamingConvention: Bool {
guard self.hasPrefix("is"), self.count > 2 else {
return false
}

let thirdCharacterIndex = self.index(self.startIndex, offsetBy: 2)
return self[thirdCharacterIndex].isUppercase
}

/// Returns a version of the string correctly escaped for a JNI
/// Returns a version of the string correctly escaped for a JNI identifier
var escapedJNIIdentifier: String {
self.map {
if $0 == "_" {
Expand All @@ -66,15 +39,6 @@ extension String {
.joined()
}

/// If the string ends with `.swift`, return it without that suffix;
/// otherwise return self unchanged
func dropSwiftFileSuffix() -> String {
if hasSuffix(".swift") {
return String(dropLast(".swift".count))
}
return self
}

/// Looks up self as a SwiftJava wrapped class name and converts it
/// into a `JavaType.class` if it exists in `lookupTable`.
func parseJavaClassFromSwiftJavaName(in lookupTable: [String: String]) -> JavaType? {
Expand All @@ -87,14 +51,6 @@ extension String {

return .class(package: javaPackageName, name: javaClassName)
}

/// Unescapes the name if it is surrounded by backticks.
var unescapedSwiftName: String {
if count >= 2 && hasPrefix("`") && hasSuffix("`") {
return String(dropFirst().dropLast())
}
return self
}
}

extension Array where Element == String {
Expand Down
26 changes: 26 additions & 0 deletions Sources/JExtractSwiftLib/Convenience/String+JavaNaming.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2024-2026 Apple Inc. and the Swift.org project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of Swift.org project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

extension String {
/// Returns whether the string is of the format `isX` (Java Beans boolean
/// property naming convention)
package var hasJavaBooleanNamingConvention: Bool {
guard self.hasPrefix("is"), self.count > 2 else {
return false
}

let thirdCharacterIndex = self.index(self.startIndex, offsetBy: 2)
return self[thirdCharacterIndex].isUppercase
}
}
Loading
Loading