Skip to content

Commit

Permalink
Remove HandySwift dependency
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeehut committed Mar 18, 2020
1 parent c2f3175 commit 1310a8b
Show file tree
Hide file tree
Showing 13 changed files with 265 additions and 23 deletions.
9 changes: 0 additions & 9 deletions Package.resolved
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
{
"object": {
"pins": [
{
"package": "HandySwift",
"repositoryURL": "https://github.com/Flinesoft/HandySwift.git",
"state": {
"branch": null,
"revision": "083707d9f9da65bd57b756294653ee0fc50d8662",
"version": "3.1.0"
}
},
{
"package": "Rainbow",
"repositoryURL": "https://github.com/onevcat/Rainbow.git",
Expand Down
7 changes: 3 additions & 4 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,29 @@ let package = Package(
.executable(name: "anylint", targets: ["AnyLintCLI"]),
],
dependencies: [
.package(url: "https://github.com/Flinesoft/HandySwift.git", from: "3.1.0"),
.package(url: "https://github.com/onevcat/Rainbow.git", from: "3.1.5"),
.package(url: "https://github.com/jakeheis/SwiftCLI.git", from: "6.0.1"),
],
targets: [
.target(
name: "AnyLint",
dependencies: ["HandySwift", "Utility"]
dependencies: ["Utility"]
),
.testTarget(
name: "AnyLintTests",
dependencies: ["AnyLint"]
),
.target(
name: "AnyLintCLI",
dependencies: ["HandySwift", "Rainbow", "SwiftCLI", "Utility"]
dependencies: ["Rainbow", "SwiftCLI", "Utility"]
),
.testTarget(
name: "AnyLintCLITests",
dependencies: ["AnyLintCLI"]
),
.target(
name: "Utility",
dependencies: ["HandySwift", "Rainbow"]
dependencies: ["Rainbow"]
),
.testTarget(
name: "UtilityTests",
Expand Down
1 change: 0 additions & 1 deletion Sources/AnyLint/CheckInfo.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Foundation
import HandySwift
import Utility

/// Provides some basic information needed in each lint check.
Expand Down
1 change: 0 additions & 1 deletion Sources/AnyLint/Checkers/FileContentsChecker.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Foundation
import HandySwift
import Utility

struct FileContentsChecker {
Expand Down
1 change: 0 additions & 1 deletion Sources/AnyLint/Checkers/FilePathsChecker.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Foundation
import HandySwift
import Utility

struct FilePathsChecker {
Expand Down
1 change: 0 additions & 1 deletion Sources/AnyLint/FilesSearch.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Foundation
import HandySwift
import Utility

/// Helper to search for files and filter using Regexes.
Expand Down
1 change: 0 additions & 1 deletion Sources/AnyLint/Lint.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Foundation
import HandySwift
import Utility

/// The linter type providing APIs for checking anything using regular expressions.
Expand Down
1 change: 0 additions & 1 deletion Sources/AnyLint/Violation.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Foundation
import HandySwift
import Utility

/// A violation found in a check.
Expand Down
1 change: 0 additions & 1 deletion Sources/Utility/Extensions/RegexExt.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Foundation
import HandySwift

extension Regex: ExpressibleByStringLiteral {
public init(stringLiteral value: String) {
Expand Down
262 changes: 262 additions & 0 deletions Sources/Utility/Regex.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
// Originally from: https://github.com/sharplet/Regex & https://github.com/Flinesoft/HandySwift (modified).

import Foundation

/// `Regex` is a swifty regex engine built on top of the NSRegularExpression api.
public struct Regex {
// MARK: - Properties
private let regularExpression: NSRegularExpression

// MARK: - Initializers
/// Create a `Regex` based on a pattern string.
///
/// If `pattern` is not a valid regular expression, an error is thrown
/// describing the failure.
///
/// - parameters:
/// - pattern: A pattern string describing the regex.
/// - options: Configure regular expression matching options.
/// For details, see `Regex.Options`.
///
/// - throws: A value of `ErrorType` describing the invalid regular expression.
public init(_ pattern: String, options: Options = []) throws {
regularExpression = try NSRegularExpression(
pattern: pattern,
options: options.toNSRegularExpressionOptions
)
}

// MARK: - Methods: Matching
/// Returns `true` if the regex matches `string`, otherwise returns `false`.
///
/// - parameter string: The string to test.
///
/// - returns: `true` if the regular expression matches, otherwise `false`.
public func matches(_ string: String) -> Bool {
firstMatch(in: string) != nil
}

/// If the regex matches `string`, returns a `Match` describing the
/// first matched string and any captures. If there are no matches, returns
/// `nil`.
///
/// - parameter string: The string to match against.
///
/// - returns: An optional `Match` describing the first match, or `nil`.
public func firstMatch(in string: String) -> Match? {
let firstMatch = regularExpression
.firstMatch(in: string, options: [], range: NSRange(location: 0, length: string.utf16.count))
.map { Match(result: $0, in: string) }
return firstMatch
}

/// If the regex matches `string`, returns an array of `Match`, describing
/// every match inside `string`. If there are no matches, returns an empty
/// array.
///
/// - parameter string: The string to match against.
///
/// - returns: An array of `Match` describing every match in `string`.
public func matches(in string: String) -> [Match] {
let matches = regularExpression
.matches(in: string, options: [], range: NSRange(location: 0, length: string.utf16.count))
.map { Match(result: $0, in: string) }
return matches
}

// MARK: Replacing
/// Returns a new string where each substring matched by `regex` is replaced
/// with `template`.
///
/// The template string may be a literal string, or include template variables:
/// the variable `$0` will be replaced with the entire matched substring, `$1`
/// with the first capture group, etc.
///
/// For example, to include the literal string "$1" in the replacement string,
/// you must escape the "$": `\$1`.
///
/// - parameters:
/// - regex: A regular expression to match against `self`.
/// - template: A template string used to replace matches.
/// - count: The maximum count of matches to replace, beginning with the first match.
///
/// - returns: A string with all matches of `regex` replaced by `template`.
public func replacingMatches(in input: String, with template: String, count: Int? = nil) -> String {
var output = input
let matches = self.matches(in: input)
let rangedMatches = Array(matches[0 ..< min(matches.count, count ?? .max)])
for match in rangedMatches.reversed() {
let replacement = match.string(applyingTemplate: template)
output.replaceSubrange(match.range, with: replacement)
}

return output
}
}

// MARK: - CustomStringConvertible
extension Regex: CustomStringConvertible {
/// Returns a string describing the regex using its pattern string.
public var description: String {
"Regex<\"\(regularExpression.pattern)\">"
}
}

// MARK: - Equatable
extension Regex: Equatable {
/// Determines the equality of to `Regex`` instances.
/// Two `Regex` are considered equal, if both the pattern string and the options
/// passed on initialization are equal.
public static func == (lhs: Regex, rhs: Regex) -> Bool {
lhs.regularExpression.pattern == rhs.regularExpression.pattern &&
lhs.regularExpression.options == rhs.regularExpression.options
}
}

// MARK: - Hashable
extension Regex: Hashable {
/// Manages hashing of the `Regex` instance.
public func hash(into hasher: inout Hasher) {
hasher.combine(regularExpression)
}
}

// MARK: - Options
extension Regex {
/// `Options` defines alternate behaviours of regular expressions when matching.
public struct Options: OptionSet {
// MARK: - Properties
/// Ignores the case of letters when matching.
public static let ignoreCase = Options(rawValue: 1)

/// Ignore any metacharacters in the pattern, treating every character as
/// a literal.
public static let ignoreMetacharacters = Options(rawValue: 1 << 1)

/// By default, "^" matches the beginning of the string and "$" matches the
/// end of the string, ignoring any newlines. With this option, "^" will
/// the beginning of each line, and "$" will match the end of each line.
public static let anchorsMatchLines = Options(rawValue: 1 << 2)

/// Usually, "." matches all characters except newlines (\n). Using this,
/// options will allow "." to match newLines
public static let dotMatchesLineSeparators = Options(rawValue: 1 << 3)

/// The raw value of the `OptionSet`
public let rawValue: Int

/// Transform an instance of `Regex.Options` into the equivalent `NSRegularExpression.Options`.
///
/// - returns: The equivalent `NSRegularExpression.Options`.
var toNSRegularExpressionOptions: NSRegularExpression.Options {
var options = NSRegularExpression.Options()
if contains(.ignoreCase) { options.insert(.caseInsensitive) }
if contains(.ignoreMetacharacters) { options.insert(.ignoreMetacharacters) }
if contains(.anchorsMatchLines) { options.insert(.anchorsMatchLines) }
if contains(.dotMatchesLineSeparators) { options.insert(.dotMatchesLineSeparators) }
return options
}

// MARK: - Initializers
/// The raw value init for the `OptionSet`
public init(rawValue: Int) {
self.rawValue = rawValue
}
}
}

// MARK: - Match
extension Regex {
/// A `Match` encapsulates the result of a single match in a string,
/// providing access to the matched string, as well as any capture groups within
/// that string.
public class Match: CustomStringConvertible {
// MARK: Properties
/// The entire matched string.
public lazy var string: String = {
String(describing: self.baseString[self.range])
}()

/// The range of the matched string.
public lazy var range: Range<String.Index> = {
Range(self.result.range, in: self.baseString)!
}()

/// The matching string for each capture group in the regular expression
/// (if any).
///
/// **Note:** Usually if the match was successful, the captures will by
/// definition be non-nil. However if a given capture group is optional, the
/// captured string may also be nil, depending on the particular string that
/// is being matched against.
///
/// Example:
///
/// let regex = Regex("(a)?(b)")
///
/// regex.matches(in: "ab")first?.captures // [Optional("a"), Optional("b")]
/// regex.matches(in: "b").first?.captures // [nil, Optional("b")]
public lazy var captures: [String?] = {
let captureRanges = stride(from: 0, to: result.numberOfRanges, by: 1)
.map(result.range)
.dropFirst()
.map { [unowned self] in
Range($0, in: self.baseString)
}

return captureRanges.map { [unowned self] captureRange in
if let captureRange = captureRange {
return String(describing: self.baseString[captureRange])
}

return nil
}
}()

private let result: NSTextCheckingResult

private let baseString: String

// MARK: - Initializers
internal init(result: NSTextCheckingResult, in string: String) {
precondition(
result.regularExpression != nil,
"NSTextCheckingResult must originate from regular expression parsing."
)

self.result = result
self.baseString = string
}

// MARK: - Methods
/// Returns a new string where the matched string is replaced according to the `template`.
///
/// The template string may be a literal string, or include template variables:
/// the variable `$0` will be replaced with the entire matched substring, `$1`
/// with the first capture group, etc.
///
/// For example, to include the literal string "$1" in the replacement string,
/// you must escape the "$": `\$1`.
///
/// - parameters:
/// - template: The template string used to replace matches.
///
/// - returns: A string with `template` applied to the matched string.
public func string(applyingTemplate template: String) -> String {
let replacement = result.regularExpression!.replacementString(
for: result,
in: baseString,
offset: 0,
template: template
)

return replacement
}

// MARK: - CustomStringConvertible
/// Returns a string describing the match.
public var description: String {
"Match<\"\(string)\">"
}
}
}
1 change: 0 additions & 1 deletion Tests/AnyLintTests/FilesSearchTests.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
@testable import AnyLint
import HandySwift
@testable import Utility
import XCTest

Expand Down
1 change: 0 additions & 1 deletion Tests/AnyLintTests/LintTests.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
@testable import AnyLint
import HandySwift
@testable import Utility
import XCTest

Expand Down
1 change: 0 additions & 1 deletion Tests/UtilityTests/Extensions/RegexExtTests.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import HandySwift
@testable import Utility
import XCTest

Expand Down

0 comments on commit 1310a8b

Please sign in to comment.