From 94bf52930b20a5d43ffbac5701cdc94113ead0b8 Mon Sep 17 00:00:00 2001 From: Alessandro Calzavara Date: Thu, 19 Sep 2024 17:15:40 +0200 Subject: [PATCH] let disable implicit swiftui matches --- .../Helpers/Parsing.swift | 4 ++ .../SwiftParserConfiguration.swift | 3 ++ .../Parsers/SwiftParser.swift | 10 +++-- StringsLint.xcodeproj/project.pbxproj | 4 ++ .../SwiftParserConfigurationTests.swift | 43 ++++++++++++++++--- .../Parsers/SwiftParserTests.swift | 19 +++++++- 6 files changed, 72 insertions(+), 11 deletions(-) diff --git a/Sources/StringsLintFramework/Helpers/Parsing.swift b/Sources/StringsLintFramework/Helpers/Parsing.swift index 2a79e81..684fbf0 100644 --- a/Sources/StringsLintFramework/Helpers/Parsing.swift +++ b/Sources/StringsLintFramework/Helpers/Parsing.swift @@ -18,3 +18,7 @@ func defaultDictionaryValue(_ dictionary: Any, for key: String) -> Any { return dictionary[key] as Any } + +func defaultBooleanValue(_ object: Any?, `default`: Bool) -> Bool { + object as? Bool ?? `default` +} diff --git a/Sources/StringsLintFramework/Parsers/Configuration/SwiftParserConfiguration.swift b/Sources/StringsLintFramework/Parsers/Configuration/SwiftParserConfiguration.swift index b7e9973..6cf4e6e 100644 --- a/Sources/StringsLintFramework/Parsers/Configuration/SwiftParserConfiguration.swift +++ b/Sources/StringsLintFramework/Parsers/Configuration/SwiftParserConfiguration.swift @@ -12,6 +12,7 @@ public struct SwiftParserConfiguration { private enum Key: String { case macros = "macros" case customRegex = "regex" + case swiftUIImplicitEnabled = "swiftui_implicit" } public var macros: [String] = [ @@ -20,6 +21,7 @@ public struct SwiftParserConfiguration { ] public var customRegex: CustomRegex? + public var swiftUIImplicitEnabled: Bool = true public mutating func apply(_ configuration: Any) throws { @@ -29,6 +31,7 @@ public struct SwiftParserConfiguration { self.macros += defaultStringArray(configuration[Key.macros.rawValue]) self.customRegex = CustomRegex(config: configuration[Key.customRegex.rawValue]) + self.swiftUIImplicitEnabled = defaultBooleanValue(configuration[Key.swiftUIImplicitEnabled.rawValue], default: true) } } diff --git a/Sources/StringsLintFramework/Parsers/SwiftParser.swift b/Sources/StringsLintFramework/Parsers/SwiftParser.swift index bfe301e..9572a5d 100644 --- a/Sources/StringsLintFramework/Parsers/SwiftParser.swift +++ b/Sources/StringsLintFramework/Parsers/SwiftParser.swift @@ -15,6 +15,7 @@ public struct SwiftParser: LocalizableParser { let uiKitPattern: String let swiftUIImplicitPattern: String + let swiftUIImplicitEnabled: Bool let swiftUIExplicitPattern: String let customRegex: CustomRegex? let ignoreThisPattern: String @@ -25,7 +26,7 @@ public struct SwiftParser: LocalizableParser { public init() { let config = SwiftParserConfiguration() - self.init(macros: config.macros, customRegex: config.customRegex) + self.init(macros: config.macros, customRegex: config.customRegex, swiftUIImplicitEnabled: config.swiftUIImplicitEnabled) } public init(configuration: Any) throws { @@ -34,15 +35,16 @@ public struct SwiftParser: LocalizableParser { try config.apply(defaultDictionaryValue(configuration, for: SwiftParser.self.identifier)) } catch {} - self.init(macros: config.macros, customRegex: config.customRegex) + self.init(macros: config.macros, customRegex: config.customRegex, swiftUIImplicitEnabled: config.swiftUIImplicitEnabled) } - public init(macros: [String], customRegex: CustomRegex? = nil) { + public init(macros: [String], customRegex: CustomRegex?, swiftUIImplicitEnabled: Bool) { self.uiKitPattern = "(\(macros.joined(separator: "|")))\\(\"([^\"]+)\", (tableName: \"([^\"]+)\", )?(comment: \"([^\"]*)\")\\)" self.swiftUIExplicitPattern = "Text\\((LocalizedStringKey\\()?\"([^\"]+)\"\\)?, tableName: \"([^\"]+)\"(, comment: \"([^\"]*)\")?\\)" self.swiftUIImplicitPattern = "(Text|Button|LocalizedStringKey)\\(\"([^\"]+)\"\\)" self.ignoreThisPattern = "//stringslint:ignore" self.customRegex = customRegex + self.swiftUIImplicitEnabled = swiftUIImplicitEnabled } public func support(file: File) -> Bool { @@ -124,7 +126,7 @@ public struct SwiftParser: LocalizableParser { } // Swift UI - implicit - if strings.isEmpty { + if strings.isEmpty && self.swiftUIImplicitEnabled { do { let regex = try NSRegularExpression(pattern: self.swiftUIImplicitPattern) let results = regex.matches(in: text, options: [ .reportCompletion ], range: NSRange(text.startIndex..., in: text)) diff --git a/StringsLint.xcodeproj/project.pbxproj b/StringsLint.xcodeproj/project.pbxproj index 3610b2c..5156e78 100644 --- a/StringsLint.xcodeproj/project.pbxproj +++ b/StringsLint.xcodeproj/project.pbxproj @@ -28,6 +28,7 @@ FA77E9EA26DE1C0600D82C5C /* MissingCommentRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA77E9E926DE1C0600D82C5C /* MissingCommentRuleTests.swift */; }; FAA8243D224BDC620091A65C /* StringsdictParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAA8243C224BDC620091A65C /* StringsdictParserTests.swift */; }; FAA8243F224BDDD20091A65C /* StringsdictParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAA8243E224BDDD20091A65C /* StringsdictParser.swift */; }; + FAC5F8972C9C70F40041AE49 /* RegexConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAC5F8962C9C70F40041AE49 /* RegexConfiguration.swift */; }; FAE0FFD3251A07C400E20F84 /* String+Range.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAE0FFC5251A032B00E20F84 /* String+Range.swift */; }; FAF2E3482AB486B000B60C7E /* MissingRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAF2E3472AB486B000B60C7E /* MissingRuleTests.swift */; }; FAF383AD21E7A3C100B24265 /* MissingRuleConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAF383AC21E7A3C100B24265 /* MissingRuleConfiguration.swift */; }; @@ -248,6 +249,7 @@ FA77E9E926DE1C0600D82C5C /* MissingCommentRuleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MissingCommentRuleTests.swift; sourceTree = ""; }; FAA8243C224BDC620091A65C /* StringsdictParserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringsdictParserTests.swift; sourceTree = ""; }; FAA8243E224BDDD20091A65C /* StringsdictParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringsdictParser.swift; sourceTree = ""; }; + FAC5F8962C9C70F40041AE49 /* RegexConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RegexConfiguration.swift; sourceTree = ""; }; FAE0FFC5251A032B00E20F84 /* String+Range.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Range.swift"; sourceTree = ""; }; FAF2E3472AB486B000B60C7E /* MissingRuleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MissingRuleTests.swift; sourceTree = ""; }; FAF383AC21E7A3C100B24265 /* MissingRuleConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MissingRuleConfiguration.swift; sourceTree = ""; }; @@ -633,6 +635,7 @@ OBJ_35 /* LocalizedString.swift */, OBJ_36 /* Location.swift */, OBJ_37 /* MasterRuleList.swift */, + FAC5F8962C9C70F40041AE49 /* RegexConfiguration.swift */, OBJ_38 /* RuleDescription.swift */, OBJ_39 /* RuleList.swift */, OBJ_40 /* Version.swift */, @@ -1198,6 +1201,7 @@ OBJ_229 /* SwiftParser.swift in Sources */, OBJ_230 /* XibParser.swift in Sources */, OBJ_231 /* YamlParser.swift in Sources */, + FAC5F8972C9C70F40041AE49 /* RegexConfiguration.swift in Sources */, OBJ_232 /* Reporter.swift in Sources */, OBJ_233 /* XcodeReporter.swift in Sources */, OBJ_234 /* RuleConfiguration.swift in Sources */, diff --git a/Tests/StringsLintFrameworkTests/Parsers/Configuration/SwiftParserConfigurationTests.swift b/Tests/StringsLintFrameworkTests/Parsers/Configuration/SwiftParserConfigurationTests.swift index ddce1d1..561417e 100644 --- a/Tests/StringsLintFrameworkTests/Parsers/Configuration/SwiftParserConfigurationTests.swift +++ b/Tests/StringsLintFrameworkTests/Parsers/Configuration/SwiftParserConfigurationTests.swift @@ -10,25 +10,58 @@ import XCTest class SwiftParserConfigurationTests: ConfigurationTestCase { - func testImplicitMacros() throws { + func testMacros() throws { let content = """ macros: - ABCString -regex: - pattern: ^\"([^\"]+)\".localized$ - match_index: 2 """ let data = try self.creareConfigFileAsDictionary(with: content) var configuration = SwiftParserConfiguration() - try configuration.apply(data) + // Default values + XCTAssertEqual(configuration.macros.count, 2) + XCTAssertEqual(configuration.macros, [ "NSLocalizedString", "CFLocalizedString" ]) + + try configuration.apply(data) + + // Updated values XCTAssertEqual(configuration.macros.count, 3) XCTAssertEqual(configuration.macros, [ "NSLocalizedString", "CFLocalizedString", "ABCString" ]) + } + + func testRegex() throws { + + let content = """ +regex: + pattern: ^\"([^\"]+)\".localized$ + match_index: 2 +""" + + let data = try self.creareConfigFileAsDictionary(with: content) + + var configuration = SwiftParserConfiguration() + try configuration.apply(data) + XCTAssertEqual(configuration.customRegex?.pattern, "^\"([^\"]+)\".localized$") XCTAssertEqual(configuration.customRegex?.matchIndex, 2) } + func testIgnoreImplicit() throws { + + let content = """ +swiftui_implicit: false +""" + + let data = try self.creareConfigFileAsDictionary(with: content) + + var configuration = SwiftParserConfiguration() + XCTAssertTrue(configuration.swiftUIImplicitEnabled) + + try configuration.apply(data) + + XCTAssertFalse(configuration.swiftUIImplicitEnabled) + } } diff --git a/Tests/StringsLintFrameworkTests/Parsers/SwiftParserTests.swift b/Tests/StringsLintFrameworkTests/Parsers/SwiftParserTests.swift index ec02c67..2f517b4 100644 --- a/Tests/StringsLintFrameworkTests/Parsers/SwiftParserTests.swift +++ b/Tests/StringsLintFrameworkTests/Parsers/SwiftParserTests.swift @@ -106,7 +106,7 @@ ABCLocalizedString(\"abc\", tableName: \"Extras\", comment: \"blabla\") let file = try self.createTempFile("test1.swift", with: content) - let parser = SwiftParser(macros: [ "ABCLocalizedString" ]) + let parser = SwiftParser(macros: [ "ABCLocalizedString" ], customRegex: nil, swiftUIImplicitEnabled: true) let results = try parser.parse(file: file) XCTAssertEqual(results.count, 2) @@ -131,7 +131,7 @@ ABCLocalizedString(\"abc\", tableName: \"Extras\", comment: \"blabla\") let file = try self.createTempFile("test1.swift", with: content) let customRegex = CustomRegex(pattern: "^\"([^\"]+)\".localized$", matchIndex: 1) - let parser = SwiftParser(macros: [], customRegex: customRegex) + let parser = SwiftParser(macros: [], customRegex: customRegex, swiftUIImplicitEnabled: true) let results = try parser.parse(file: file) XCTAssertEqual(results.count, 1) @@ -250,4 +250,19 @@ Button("def") //stringslint:ignore XCTAssertEqual(results[0].locale, .none) XCTAssertEqual(results[0].location, Location(file: file, line: 1)) } + + func testIgnoreImplicit() throws { + + let content = """ +Text("abc") +""" + + let file = try self.createTempFile("test1.swift", with: content) + + let parser = SwiftParser(macros: [], customRegex: nil, swiftUIImplicitEnabled: false) + + let results = try parser.parse(file: file) + + XCTAssertEqual(results.count, 0) + } }