Skip to content

Commit

Permalink
Improve LinkRule to accept titles and ignore internal markdown (#108)
Browse files Browse the repository at this point in the history
* Add Title support to LinkRule
* Adds support for links like: `[Google](http://www.google.com "custom title")`

Co-authored-by: Edwin Veger <[email protected]>
  • Loading branch information
edwinveger and Edwin Veger authored Jan 6, 2021
1 parent 23eb0f5 commit 0c6f2c1
Show file tree
Hide file tree
Showing 16 changed files with 199 additions and 116 deletions.
6 changes: 3 additions & 3 deletions Example/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
PODS:
- markymark (9.2.1)
- markymark (10.1.1)
- SwiftLint (0.28.1)

DEPENDENCIES:
Expand All @@ -15,9 +15,9 @@ EXTERNAL SOURCES:
:path: "../"

SPEC CHECKSUMS:
markymark: e7fa1cdb7ad51c21a46cda308ad8ef4511fa49f6
markymark: 29adb8789fa6b3db97b04b7585d65f13931b5aa5
SwiftLint: 7f5f7de0da74a649b16616cb5246ae323489656e

PODFILE CHECKSUM: e6179d5e64bda0057471cea1521ff93bf207a88b

COCOAPODS: 1.9.3
COCOAPODS: 1.10.0
61 changes: 0 additions & 61 deletions Example/Tests/Rules/Block/LinkRuleTests.swift

This file was deleted.

144 changes: 144 additions & 0 deletions Example/Tests/Rules/Inline/LinkRuleTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
//
// Created by Maren Osnabrug on 10-05-16.
// Copyright © 2016 M2mobi. All rights reserved.
//

import XCTest
@testable import markymark

class LinkRuleTests: XCTestCase {

var sut: LinkRule!

override func setUp() {
super.setUp()
sut = LinkRule()
}

func testRecognizesLines() {
XCTAssertTrue(sut.recognizesLines(["[Alt text](image.png)"]))
XCTAssertFalse((sut.recognizesLines(["![Alt text](image.png)"])))
XCTAssertTrue(sut.recognizesLines([#"[Alt text](image.png "some title")"#]))
}

func test_DoesNotRecognizeLines_When_PrefixedWithExclamationMark() {
XCTAssertFalse((sut.recognizesLines(["![Alt text](image.png)"])))
XCTAssertFalse((sut.recognizesLines(["! [Alt text](image.png)"])))
XCTAssertFalse((sut.recognizesLines([#"![Alt text](image.png "some title")"#])))
}

func test_GetAllMatchesReturnsZero_When_InvalidInput() {
// Assert
XCTAssert(sut.getAllMatches(["(https://www.google.com)"]).isEmpty)
XCTAssert(sut.getAllMatches(["[Google]"]).isEmpty)
XCTAssert(sut.getAllMatches(["![Google](https://www.google.com)"]).isEmpty)
}

func testCreateMarkDownItemWithLinesCreatesCorrectItem() {
// Act
let markDownItem = sut.createMarkDownItemWithLines(["[Google](http://www.google.com)"])

// Assert
XCTAssert(markDownItem is LinkMarkDownItem)
}

func testCreateMarkDownItemContainsCorrectLink() {
// Act
let markDownItem = sut.createMarkDownItemWithLines(["[Google](http://www.google.com)"])
let markDownItem2 = sut.createMarkDownItemWithLines(["[Youtube](http://www.youtube.com)"])

// Assert
XCTAssertEqual((markDownItem as! LinkMarkDownItem).content, "Google")
XCTAssertEqual((markDownItem as! LinkMarkDownItem).url, "http://www.google.com")
XCTAssertEqual((markDownItem2 as! LinkMarkDownItem).content, "Youtube")
XCTAssertEqual((markDownItem2 as! LinkMarkDownItem).url, "http://www.youtube.com")
}

func testGetAllMatches() {
// Arrange
let expectedMatchesRange = NSRange(location: 0, length: 32)
let expectedMatchesRange2 = NSRange(location: 38, length: 32)

// Act + Assert
XCTAssertEqual(sut.getAllMatches(["[Google]"]).count, 0)
XCTAssertEqual(sut.getAllMatches(["(https://www.google.com)"]).count, 0)
XCTAssertEqual(sut.getAllMatches(["[Google](https://www.google.com)"]), [expectedMatchesRange])
XCTAssertEqual(sut.getAllMatches(["![Google](https://www.google.com)"]).count, 0)
XCTAssertEqual(
sut.getAllMatches(["[Google](https://www.google.com) test [Google](https://www.google.com)"]),
[expectedMatchesRange, expectedMatchesRange2]
)

XCTAssertEqual(
sut.getAllMatches([#"[Google](https://www.google.com) test [Google](https://www.google.com "a11y title")"#]),
[
NSRange(location: 0, length: 32),
NSRange(location: 38, length: 45)
]
)
}

func test_ParsesItem_When_InputMatches() throws {
// Arrange
let cases: [(String, String, String, UInt)] = [
(
#"[Google plain link](https://google.com)"#,
"Google plain link",
"https://google.com",
#line
),
(
#"[Google w/ title](http://www.google.com "with custom title")"#,
"Google w/ title",
"http://www.google.com",
#line
),
(
#"[Simple link](https://google.nl)"#,
"Simple link",
"https://google.nl",
#line
),
(
#"Inside [another link](http://m2mobi.com/) sentence"#,
"another link",
"http://m2mobi.com/",
#line
),
(
#"Inside [another link](http://m2mobi.com/ "with custom title") sentence"#,
"another link",
"http://m2mobi.com/",
#line
),
(
#"[Underscored link](https://google.nl/?param=a_b_c)"#,
"Underscored link",
"https://google.nl/?param=a_b_c",
#line
),
(
#"[Underscored link 2](https://google.nl/?param=a_b_c&d=e)"#,
"Underscored link 2",
"https://google.nl/?param=a_b_c&d=e",
#line
),
(
#"[Underscored link 4](https://google.nl/?param=a_b_c&d=e_f_g)"#,
"Underscored link 4",
"https://google.nl/?param=a_b_c&d=e_f_g",
#line
)
]

for (input, content, url, line) in cases {
// Act
let output = sut.createMarkDownItemWithLines([input])

// Assert
let linkMarkDownItem = try XCTUnwrap(output as? LinkMarkDownItem)
XCTAssertEqual(linkMarkDownItem.content, content, line: line)
XCTAssertEqual(linkMarkDownItem.url, url, line: line)
}
}
}
45 changes: 23 additions & 22 deletions Example/markymark.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -112,13 +112,13 @@
9704F30C7296E4A0EA9A0087 /* Pods-markymark_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-markymark_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-markymark_Example/Pods-markymark_Example.release.xcconfig"; sourceTree = "<group>"; };
99E80ED3FF06693617B60997 /* Pods-TodayExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TodayExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-TodayExtension/Pods-TodayExtension.debug.xcconfig"; sourceTree = "<group>"; };
9A06FCF01CF72B4D0040251D /* AlphabeticListTypeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlphabeticListTypeTests.swift; sourceTree = "<group>"; };
9A8BE0A31CEE0416004593A0 /* BoldRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BoldRuleTests.swift; path = Block/BoldRuleTests.swift; sourceTree = "<group>"; };
9A8BE0A41CEE0416004593A0 /* ImageRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageRuleTests.swift; path = Block/ImageRuleTests.swift; sourceTree = "<group>"; };
9A8BE0A51CEE0416004593A0 /* InlineCodeRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InlineCodeRuleTests.swift; path = Block/InlineCodeRuleTests.swift; sourceTree = "<group>"; };
9A8BE0A61CEE0416004593A0 /* InlineTextRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InlineTextRuleTests.swift; path = Block/InlineTextRuleTests.swift; sourceTree = "<group>"; };
9A8BE0A71CEE0416004593A0 /* ItalicRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ItalicRuleTests.swift; path = Block/ItalicRuleTests.swift; sourceTree = "<group>"; };
9A8BE0A81CEE0416004593A0 /* LinkRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LinkRuleTests.swift; path = Block/LinkRuleTests.swift; sourceTree = "<group>"; };
9A8BE0A91CEE0416004593A0 /* StrikeRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = StrikeRuleTests.swift; path = Block/StrikeRuleTests.swift; sourceTree = "<group>"; };
9A8BE0A31CEE0416004593A0 /* BoldRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoldRuleTests.swift; sourceTree = "<group>"; };
9A8BE0A41CEE0416004593A0 /* ImageRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageRuleTests.swift; sourceTree = "<group>"; };
9A8BE0A51CEE0416004593A0 /* InlineCodeRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InlineCodeRuleTests.swift; sourceTree = "<group>"; };
9A8BE0A61CEE0416004593A0 /* InlineTextRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InlineTextRuleTests.swift; sourceTree = "<group>"; };
9A8BE0A71CEE0416004593A0 /* ItalicRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItalicRuleTests.swift; sourceTree = "<group>"; };
9A8BE0A81CEE0416004593A0 /* LinkRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinkRuleTests.swift; sourceTree = "<group>"; };
9A8BE0A91CEE0416004593A0 /* StrikeRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StrikeRuleTests.swift; sourceTree = "<group>"; };
9A8BE0B21CEE044E004593A0 /* BlockQuoteRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockQuoteRuleTests.swift; sourceTree = "<group>"; };
9A8BE0B31CEE044E004593A0 /* CodeBlockRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CodeBlockRuleTests.swift; sourceTree = "<group>"; };
9A8BE0B71CEE0458004593A0 /* HorizontalLineRuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HorizontalLineRuleTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -168,6 +168,20 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
0C813F5425A4993300F805D0 /* Inline */ = {
isa = PBXGroup;
children = (
9A8BE0A31CEE0416004593A0 /* BoldRuleTests.swift */,
9A8BE0A41CEE0416004593A0 /* ImageRuleTests.swift */,
9A8BE0A51CEE0416004593A0 /* InlineCodeRuleTests.swift */,
9A8BE0A61CEE0416004593A0 /* InlineTextRuleTests.swift */,
9A8BE0A71CEE0416004593A0 /* ItalicRuleTests.swift */,
9A8BE0A81CEE0416004593A0 /* LinkRuleTests.swift */,
9A8BE0A91CEE0416004593A0 /* StrikeRuleTests.swift */,
);
path = Inline;
sourceTree = "<group>";
};
607FACC71AFB9204008FA782 = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -252,8 +266,8 @@
629C42251CEB47F900DA57D8 /* Rules */ = {
isa = PBXGroup;
children = (
9A8BE0A21CEE03EB004593A0 /* Inline */,
629C42261CEB47F900DA57D8 /* Block */,
0C813F5425A4993300F805D0 /* Inline */,
);
path = Rules;
sourceTree = "<group>";
Expand Down Expand Up @@ -315,20 +329,6 @@
name = Pods;
sourceTree = "<group>";
};
9A8BE0A21CEE03EB004593A0 /* Inline */ = {
isa = PBXGroup;
children = (
9A8BE0A31CEE0416004593A0 /* BoldRuleTests.swift */,
9A8BE0A41CEE0416004593A0 /* ImageRuleTests.swift */,
9A8BE0A51CEE0416004593A0 /* InlineCodeRuleTests.swift */,
9A8BE0A61CEE0416004593A0 /* InlineTextRuleTests.swift */,
9A8BE0A71CEE0416004593A0 /* ItalicRuleTests.swift */,
9A8BE0A81CEE0416004593A0 /* LinkRuleTests.swift */,
9A8BE0A91CEE0416004593A0 /* StrikeRuleTests.swift */,
);
name = Inline;
sourceTree = "<group>";
};
F927877321F8BB3D00039986 /* Helpers */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -455,6 +455,7 @@
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
English,
en,
Base,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,16 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "607FACCF1AFB9204008FA782"
BuildableName = "markymark_Example.app"
BlueprintName = "markymark_Example"
ReferencedContainer = "container:markymark.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO">
Expand All @@ -54,23 +62,11 @@
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "607FACCF1AFB9204008FA782"
BuildableName = "markymark_Example.app"
BlueprintName = "markymark_Example"
ReferencedContainer = "container:markymark.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
Expand All @@ -87,8 +83,6 @@
ReferencedContainer = "container:markymark.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
Expand Down
4 changes: 3 additions & 1 deletion Example/markymark/markdown.txt
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,9 @@ Inline image ![Apple logo](appleLogo) Apple logo ![Apple logo](appleLogoSmall)

## Links
[This is a test link](https://m2mobi.com)
Inline links are also possible, click [here](https://m2mobi.com)
Inline links are also possible, click [here](https://m2mobi.com).
Do not worry about [possible markdown inside URLs](https://m2mobi.com?p_q=r_s&t_u), or [URLs with titles](https://m2mobi.com "Custom URL title").

# Code
---

Expand Down
2 changes: 1 addition & 1 deletion markymark.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "markymark"
s.version = "10.1.0"
s.version = "10.1.1"
s.summary = "Markdown parser for iOS"
s.description = <<-DESC
Marky Mark is a parser written in Swift that converts markdown into native views. The way it looks is highly customizable and the supported markdown syntax and tags are easy to extend.
Expand Down
2 changes: 1 addition & 1 deletion markymark/Classes/Flavors/ContentfulFlavor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ open class ContentfulFlavor: Flavor {
open var defaultRule: Rule = ParagraphRule()

open var inlineRules: [InlineRule] = [
LinkRule(),
BoldRule(),
ItalicRule(),
StrikeRule(),
ImageRule(),
LinkRule(),
InlineCodeRule()
]

Expand Down
Loading

0 comments on commit 0c6f2c1

Please sign in to comment.