Skip to content

Commit 3189d89

Browse files
authored
Merge pull request #11 from g-Off/swift-5
Swift 5
2 parents edbca5c + fe55e69 commit 3189d89

34 files changed

+315
-256
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
/.build
33
/Packages
44
/*.xcodeproj
5+
.swiftpm

Dockerfile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
FROM swift:4.2.1
2+
COPY Package.swift ./Package.swift
3+
COPY Sources ./Sources
4+
COPY Tests ./Tests
5+
RUN swift test --configuration debug

Makefile

Lines changed: 0 additions & 44 deletions
This file was deleted.

Overrides.xcconfig

Lines changed: 0 additions & 1 deletion
This file was deleted.

Package.resolved

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,26 +24,26 @@
2424
"repositoryURL": "https://github.com/scottrhoyt/SwiftyTextTable.git",
2525
"state": {
2626
"branch": null,
27-
"revision": "7b8661865f0d9590a4b7c146237fecd99f3d8406",
28-
"version": "0.8.2"
27+
"revision": "c6df6cf533d120716bff38f8ff9885e1ce2a4ac3",
28+
"version": "0.9.0"
2929
}
3030
},
3131
{
3232
"package": "XcodeProject",
3333
"repositoryURL": "https://github.com/g-Off/XcodeProject.git",
3434
"state": {
3535
"branch": null,
36-
"revision": "a1e12a8659684039258b79761c65abb9ec98fc94",
37-
"version": "0.4.0"
36+
"revision": "f5095a860de4cd1f0e635957bed7c4b80392dac8",
37+
"version": "0.5.0"
3838
}
3939
},
4040
{
4141
"package": "Yams",
4242
"repositoryURL": "https://github.com/jpsim/Yams.git",
4343
"state": {
4444
"branch": null,
45-
"revision": "26ab35f50ea891e8edefcc9d975db2f6b67e1d68",
46-
"version": "1.0.1"
45+
"revision": "b08dba4bcea978bf1ad37703a384097d3efce5af",
46+
"version": "1.0.2"
4747
}
4848
}
4949
]

Package.swift

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,47 @@
1-
// swift-tools-version:4.2
1+
// swift-tools-version:5.0
22
import PackageDescription
33

44
let package = Package(
55
name: "stringray",
6+
platforms: [
7+
.macOS(.v10_14)
8+
],
9+
products: [
10+
.executable(
11+
name: "stringray",
12+
targets: ["stringray"]
13+
),
14+
.library(
15+
name: "RayGun",
16+
targets: ["RayGun"]
17+
)
18+
],
619
dependencies: [
720
.package(url: "https://github.com/jpsim/Yams.git", from: "1.0.1"),
821
.package(url: "https://github.com/scottrhoyt/SwiftyTextTable.git", from: "0.5.0"),
9-
.package(url: "https://github.com/g-Off/XcodeProject.git", from: "0.4.0"),
10-
.package(url: "https://github.com/g-Off/CommandRegistry.git", .branch("master"))
22+
.package(url: "https://github.com/g-Off/XcodeProject.git", from: "0.5.0-alpha.3"),
23+
.package(url: "https://github.com/g-Off/CommandRegistry.git", from: "0.1.0"),
24+
.package(url: "https://github.com/apple/swift-package-manager.git", from: "0.3.0")
1125
],
1226
targets: [
1327
.target(
1428
name: "stringray",
1529
dependencies: [
16-
"Yams",
30+
"CommandRegistry",
31+
"RayGun",
1732
"SwiftyTextTable",
1833
"XcodeProject",
19-
"CommandRegistry"
34+
"Utility",
35+
"Yams",
36+
]
37+
),
38+
.target(
39+
name: "RayGun",
40+
dependencies: [
2041
]
2142
),
2243
.testTarget(
2344
name: "stringrayTests",
24-
dependencies: ["stringray"]),
45+
dependencies: ["RayGun"]),
2546
]
2647
)

Sources/stringray/Extensions/URL+Extensions.swift renamed to Sources/RayGun/Extensions/URL+Extensions.swift

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77

88
import Foundation
99

10-
extension URL {
11-
var tableName: String? {
10+
extension Foundation.URL {
11+
public var tableName: String? {
1212
var url = self
1313
if ["strings", "stringsdict"].contains(url.pathExtension) {
1414
url.deletePathExtension()
@@ -17,7 +17,7 @@ extension URL {
1717
return nil
1818
}
1919

20-
var locale: Locale? {
20+
public var locale: Locale? {
2121
var url = self
2222
if ["strings", "stringsdict"].contains(url.pathExtension) {
2323
url.deleteLastPathComponent()
@@ -29,7 +29,7 @@ extension URL {
2929
return nil
3030
}
3131

32-
var resourceDirectory: URL {
32+
public var resourceDirectory: Foundation.URL {
3333
var dir = self
3434
if dir.pathExtension == "strings" || dir.pathExtension == "stringsdict" {
3535
dir.deleteLastPathComponent()
@@ -40,38 +40,38 @@ extension URL {
4040
return dir
4141
}
4242

43-
var lprojURLs: [URL] {
43+
var lprojURLs: [Foundation.URL] {
4444
let directories = try? FileManager.default.contentsOfDirectory(at: self, includingPropertiesForKeys: nil, options: []).filter { (url) -> Bool in
4545
return url.pathExtension == "lproj"
4646
}
4747
return directories ?? []
4848
}
4949

50-
func stringsFiles(tableName: String) -> [URL] {
50+
func stringsFiles(tableName: String) -> [Foundation.URL] {
5151
return files(tableName: tableName, ext: "strings")
5252
}
5353

54-
func stringsDictFiles(tableName: String) -> [URL] {
54+
func stringsDictFiles(tableName: String) -> [Foundation.URL] {
5555
return files(tableName: tableName, ext: "stringsdict")
5656
}
5757

58-
private func files(tableName: String, ext: String) -> [URL] {
58+
private func files(tableName: String, ext: String) -> [Foundation.URL] {
5959
return lprojURLs.compactMap { (lprojURL) in
6060
let url = lprojURL.appendingPathComponent(tableName).appendingPathExtension(ext)
6161
guard let reachable = try? url.checkResourceIsReachable(), reachable == true else { return nil }
6262
return url
6363
}
6464
}
6565

66-
func stringsURL(tableName: String, locale: Locale) throws -> URL {
66+
func stringsURL(tableName: String, locale: Locale) throws -> Foundation.URL {
6767
return try fileURL(tableName: tableName, locale: locale, ext: "strings", create: true)
6868
}
6969

70-
func stringsDictURL(tableName: String, locale: Locale) throws -> URL {
70+
func stringsDictURL(tableName: String, locale: Locale) throws -> Foundation.URL {
7171
return try fileURL(tableName: tableName, locale: locale, ext: "stringsdict", create: true)
7272
}
7373

74-
private func fileURL(tableName: String, locale: Locale, ext: String, create: Bool) throws -> URL {
74+
private func fileURL(tableName: String, locale: Locale, ext: String, create: Bool) throws -> Foundation.URL {
7575
let lprojURL = appendingPathComponent("\(locale.identifier).lproj", isDirectory: true)
7676
if create {
7777
try FileManager.default.createDirectory(at: lprojURL, withIntermediateDirectories: true, attributes: nil)
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//
2+
// LintRule.swift
3+
// stringray
4+
//
5+
// Created by Geoffrey Foster on 2018-11-07.
6+
//
7+
8+
import Foundation
9+
10+
public protocol LintRule {
11+
var info: RuleInfo { get }
12+
func scan(table: StringsTable, url: Foundation.URL, config: Linter.Config.Rule?) throws -> [LintRuleViolation]
13+
}
14+
15+
public struct RuleInfo {
16+
public let identifier: String
17+
public let name: String
18+
public let description: String
19+
public let severity: Severity
20+
}
21+
22+
public enum Severity: String, CustomStringConvertible, Decodable {
23+
case warning
24+
case error
25+
26+
public var description: String {
27+
return rawValue
28+
}
29+
}
30+
31+
public struct LintRuleViolation {
32+
public struct Location: CustomStringConvertible {
33+
public let file: Foundation.URL
34+
public let line: Int?
35+
36+
public var description: String {
37+
var path = file.lastPathComponent
38+
if let line = line {
39+
path.append(":\(line)")
40+
}
41+
return path
42+
}
43+
}
44+
45+
public let locale: Locale
46+
public let location: Location
47+
public let severity: Severity
48+
public let reason: String
49+
50+
public init(locale: Locale, location: Location, severity: Severity, reason: String) {
51+
self.locale = locale
52+
self.location = location
53+
self.severity = severity
54+
self.reason = reason
55+
}
56+
}

Sources/stringray/Lint Rules/Linter.swift renamed to Sources/RayGun/Lint Rules/Linter.swift

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,10 @@
66
//
77

88
import Foundation
9-
import Yams
109

11-
struct Linter {
12-
struct Config: Decodable {
13-
struct Rule: Decodable {
10+
public struct Linter {
11+
public struct Config: Decodable {
12+
public struct Rule: Decodable {
1413
let severity: Severity
1514
}
1615
let included: [String]
@@ -23,57 +22,54 @@ struct Linter {
2322
case rules
2423
}
2524

26-
init() {
25+
public init() {
2726
self.included = []
2827
self.excluded = []
2928
self.rules = [:]
3029
}
3130

32-
init(url: URL) throws {
33-
let string = try String(contentsOf: url, encoding: .utf8)
34-
self = try YAMLDecoder().decode(Config.self, from: string, userInfo: [:])
35-
}
36-
37-
init(from decoder: Decoder) throws {
31+
public init(from decoder: Decoder) throws {
3832
let container = try decoder.container(keyedBy: CodingKeys.self)
3933
self.included = try container.decodeIfPresent([String].self, forKey: .included) ?? []
4034
self.excluded = try container.decodeIfPresent([String].self, forKey: .excluded) ?? []
4135
self.rules = try container.decodeIfPresent([String: Rule].self, forKey: .rules) ?? [:]
4236
}
4337
}
4438

45-
static let fileName = ".stringray.yml"
39+
public static let fileName = ".stringray.yml"
4640

47-
static let allRules: [LintRule] = [
41+
public static let allRules: [LintRule] = [
4842
MissingLocalizationLintRule(),
4943
OrphanedLocalizationLintRule(),
50-
MissingPlaceholderLintRule()
44+
MissingPlaceholderLintRule(),
45+
MissingCommentLintRule()
5146
]
5247

53-
struct Error: LocalizedError {
54-
var violations: [LintRuleViolation]
55-
init(_ violations: [LintRuleViolation]) {
48+
public struct Error: LocalizedError {
49+
public private(set) var violations: [LintRuleViolation]
50+
51+
public init(_ violations: [LintRuleViolation]) {
5652
self.violations = violations
5753
}
5854

59-
var errorDescription: String? {
55+
public var errorDescription: String? {
6056
let errorCount = violations.filter { $0.severity == .error }.count
6157
let warningCount = violations.filter { $0.severity == .warning }.count
6258
return "Encountered \(errorCount) errors and \(warningCount) warnings."
6359
}
6460
}
6561

66-
let rules: [LintRule]
62+
public let rules: [LintRule]
6763
private let reporter: Reporter
6864
private let config: Config
6965

70-
init(rules: [LintRule] = Linter.allRules, reporter: Reporter = ConsoleReporter(), config: Config = Config()) {
66+
public init(rules: [LintRule] = Linter.allRules, reporter: Reporter, config: Config = Config()) {
7167
self.rules = rules
7268
self.reporter = reporter
7369
self.config = config
7470
}
7571

76-
private func run(on table: StringsTable, url: URL) throws -> [LintRuleViolation] {
72+
private func run(on table: StringsTable, url: Foundation.URL) throws -> [LintRuleViolation] {
7773
var runnableRules = self.rules
7874

7975
let includedRules = Set(config.included)
@@ -93,7 +89,7 @@ struct Linter {
9389
}
9490
}
9591

96-
func report(on table: StringsTable, url: URL) throws {
92+
public func report(on table: StringsTable, url: Foundation.URL) throws {
9793
let violations = try run(on: table, url: url)
9894
var outputStream = LinterOutputStream(fileHandle: FileHandle.standardOutput)
9995
reporter.generateReport(for: violations, to: &outputStream)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//
2+
// MissingCommentLintRule.swift
3+
// RayGun
4+
//
5+
// Created by Geoffrey Foster on 2019-06-02.
6+
//
7+
8+
import Foundation
9+
10+
struct MissingCommentLintRule: LintRule {
11+
let info: RuleInfo = RuleInfo(identifier: "missing_comment", name: "Missing Comment", description: "", severity: .error)
12+
13+
func scan(table: StringsTable, url: Foundation.URL, config: Linter.Config.Rule?) throws -> [LintRuleViolation] {
14+
var violations: [LintRuleViolation] = []
15+
let file = Foundation.URL(fileURLWithPath: "\(table.base.identifier).lproj/\(table.name).strings", relativeTo: url)
16+
for entry in table.baseEntries where entry.comment == nil {
17+
let line = entry.location?.line
18+
let location = LintRuleViolation.Location(file: file, line: line)
19+
let reason = "Mismatched placeholders \(entry.key)"
20+
let violation = LintRuleViolation(locale: table.base, location: location, severity: config?.severity ?? info.severity, reason: reason)
21+
violations.append(violation)
22+
}
23+
return violations
24+
}
25+
}

0 commit comments

Comments
 (0)