forked from purescript/purescript-strings
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathInternal.purs
219 lines (190 loc) · 9.17 KB
/
Internal.purs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
module Data.String.NonEmpty.Internal where
import Prelude
import Data.Foldable (class Foldable)
import Data.Foldable as F
import Data.Maybe (Maybe(..), fromJust)
import Data.Semigroup.Foldable (class Foldable1)
import Data.String as String
import Data.String.Pattern (Pattern)
import Data.Symbol (class IsSymbol, reflectSymbol)
import Prim.TypeError as TE
import Unsafe.Coerce (unsafeCoerce)
-- | A string that is known not to be empty.
newtype NonEmptyString = NonEmptyString String
derive newtype instance eqNonEmptyString ∷ Eq NonEmptyString
derive newtype instance ordNonEmptyString ∷ Ord NonEmptyString
derive newtype instance semigroupNonEmptyString ∷ Semigroup NonEmptyString
instance showNonEmptyString :: Show NonEmptyString where
show (NonEmptyString s) = "(NonEmptyString.unsafeFromString " <> show s <> ")"
-- | A helper class for defining non-empty string values at compile time.
-- |
-- | ``` purescript
-- | something :: NonEmptyString
-- | something = nes (Proxy :: Proxy "something")
-- | ```
class MakeNonEmpty (s :: Symbol) where
nes :: forall proxy. proxy s -> NonEmptyString
instance makeNonEmptyBad :: TE.Fail (TE.Text "Cannot create an NonEmptyString from an empty Symbol") => MakeNonEmpty "" where
nes _ = NonEmptyString ""
else instance nonEmptyNonEmpty :: IsSymbol s => MakeNonEmpty s where
nes p = NonEmptyString (reflectSymbol p)
-- | A newtype used in cases to specify a non-empty replacement for a pattern.
newtype NonEmptyReplacement = NonEmptyReplacement NonEmptyString
derive newtype instance eqNonEmptyReplacement :: Eq NonEmptyReplacement
derive newtype instance ordNonEmptyReplacement :: Ord NonEmptyReplacement
derive newtype instance semigroupNonEmptyReplacement ∷ Semigroup NonEmptyReplacement
instance showNonEmptyReplacement :: Show NonEmptyReplacement where
show (NonEmptyReplacement s) = "(NonEmptyReplacement " <> show s <> ")"
-- | Creates a `NonEmptyString` from a `String`, returning `Nothing` if the
-- | input is empty.
-- |
-- | ```purescript
-- | fromString "" = Nothing
-- | fromString "hello" = Just (NES.unsafeFromString "hello")
-- | ```
fromString :: String -> Maybe NonEmptyString
fromString = case _ of
"" -> Nothing
s -> Just (NonEmptyString s)
-- | A partial version of `fromString`.
unsafeFromString :: Partial => String -> NonEmptyString
unsafeFromString = fromJust <<< fromString
-- | Converts a `NonEmptyString` back into a standard `String`.
toString :: NonEmptyString -> String
toString (NonEmptyString s) = s
-- | Appends a string to this non-empty string. Since one of the strings is
-- | non-empty we know the result will be too.
-- |
-- | ```purescript
-- | appendString (NonEmptyString "Hello") " world" == NonEmptyString "Hello world"
-- | appendString (NonEmptyString "Hello") "" == NonEmptyString "Hello"
-- | ```
appendString :: NonEmptyString -> String -> NonEmptyString
appendString (NonEmptyString s1) s2 = NonEmptyString (s1 <> s2)
-- | Prepends a string to this non-empty string. Since one of the strings is
-- | non-empty we know the result will be too.
-- |
-- | ```purescript
-- | prependString "be" (NonEmptyString "fore") == NonEmptyString "before"
-- | prependString "" (NonEmptyString "fore") == NonEmptyString "fore"
-- | ```
prependString :: String -> NonEmptyString -> NonEmptyString
prependString s1 (NonEmptyString s2) = NonEmptyString (s1 <> s2)
-- | If the string starts with the given prefix, return the portion of the
-- | string left after removing it. If the prefix does not match or there is no
-- | remainder, the result will be `Nothing`.
-- |
-- | ```purescript
-- | stripPrefix (Pattern "http:") (NonEmptyString "http://purescript.org") == Just (NonEmptyString "//purescript.org")
-- | stripPrefix (Pattern "http:") (NonEmptyString "https://purescript.org") == Nothing
-- | stripPrefix (Pattern "Hello!") (NonEmptyString "Hello!") == Nothing
-- | ```
stripPrefix :: Pattern -> NonEmptyString -> Maybe NonEmptyString
stripPrefix pat = fromString <=< liftS (String.stripPrefix pat)
-- | If the string ends with the given suffix, return the portion of the
-- | string left after removing it. If the suffix does not match or there is no
-- | remainder, the result will be `Nothing`.
-- |
-- | ```purescript
-- | stripSuffix (Pattern ".exe") (NonEmptyString "purs.exe") == Just (NonEmptyString "purs")
-- | stripSuffix (Pattern ".exe") (NonEmptyString "purs") == Nothing
-- | stripSuffix (Pattern "Hello!") (NonEmptyString "Hello!") == Nothing
-- | ```
stripSuffix :: Pattern -> NonEmptyString -> Maybe NonEmptyString
stripSuffix pat = fromString <=< liftS (String.stripSuffix pat)
-- | Checks whether the pattern appears in the given string.
-- |
-- | ```purescript
-- | contains (Pattern "needle") (NonEmptyString "haystack with needle") == true
-- | contains (Pattern "needle") (NonEmptyString "haystack") == false
-- | ```
contains :: Pattern -> NonEmptyString -> Boolean
contains = liftS <<< String.contains
-- | Compare two strings in a locale-aware fashion. This is in contrast to
-- | the `Ord` instance on `String` which treats strings as arrays of code
-- | units:
-- |
-- | ```purescript
-- | NonEmptyString "ä" `localeCompare` NonEmptyString "b" == LT
-- | NonEmptyString "ä" `compare` NonEmptyString "b" == GT
-- | ```
localeCompare :: NonEmptyString -> NonEmptyString -> Ordering
localeCompare (NonEmptyString a) (NonEmptyString b) = String.localeCompare a b
-- | Replaces the first occurence of the pattern with the replacement string.
-- |
-- | ```purescript
-- | replace (Pattern "<=") (NonEmptyReplacement "≤") (NonEmptyString "a <= b <= c") == NonEmptyString "a ≤ b <= c"
-- | ```
replace :: Pattern -> NonEmptyReplacement -> NonEmptyString -> NonEmptyString
replace pat (NonEmptyReplacement (NonEmptyString rep)) (NonEmptyString s) =
NonEmptyString (String.replace pat (String.Replacement rep) s)
-- | Replaces all occurences of the pattern with the replacement string.
-- |
-- | ```purescript
-- | replaceAll (Pattern "<=") (NonEmptyReplacement "≤") (NonEmptyString "a <= b <= c") == NonEmptyString "a ≤ b ≤ c"
-- | ```
replaceAll :: Pattern -> NonEmptyReplacement -> NonEmptyString -> NonEmptyString
replaceAll pat (NonEmptyReplacement (NonEmptyString rep)) (NonEmptyString s) =
NonEmptyString (String.replaceAll pat (String.Replacement rep) s)
-- | Returns the argument converted to lowercase.
-- |
-- | ```purescript
-- | toLower (NonEmptyString "hElLo") == NonEmptyString "hello"
-- | ```
toLower :: NonEmptyString -> NonEmptyString
toLower (NonEmptyString s) = NonEmptyString (String.toLower s)
-- | Returns the argument converted to uppercase.
-- |
-- | ```purescript
-- | toUpper (NonEmptyString "Hello") == NonEmptyString "HELLO"
-- | ```
toUpper :: NonEmptyString -> NonEmptyString
toUpper (NonEmptyString s) = NonEmptyString (String.toUpper s)
-- | Removes whitespace from the beginning and end of a string, including
-- | [whitespace characters](http://www.ecma-international.org/ecma-262/5.1/#sec-7.2)
-- | and [line terminators](http://www.ecma-international.org/ecma-262/5.1/#sec-7.3).
-- | If the string is entirely made up of whitespace the result will be Nothing.
-- |
-- | ```purescript
-- | trim (NonEmptyString " Hello \n World\n\t ") == Just (NonEmptyString "Hello \n World")
-- | trim (NonEmptyString " \n") == Nothing
-- | ```
trim :: NonEmptyString -> Maybe NonEmptyString
trim (NonEmptyString s) = fromString (String.trim s)
-- | Joins the strings in a container together as a new string, inserting the
-- | first argument as separator between them. The result is not guaranteed to
-- | be non-empty.
-- |
-- | ```purescript
-- | joinWith ", " [NonEmptyString "apple", NonEmptyString "banana"] == "apple, banana"
-- | joinWith ", " [] == ""
-- | ```
joinWith :: forall f. Foldable f => String -> f NonEmptyString -> String
joinWith splice = F.intercalate splice <<< coe
where
coe :: f NonEmptyString -> f String
coe = unsafeCoerce
-- | Joins non-empty strings in a non-empty container together as a new
-- | non-empty string, inserting a possibly empty string as separator between
-- | them. The result is guaranteed to be non-empty.
-- |
-- | ```purescript
-- | -- array syntax is used for demonstration here, it would need to be a real `Foldable1`
-- | join1With ", " [NonEmptyString "apple", NonEmptyString "banana"] == NonEmptyString "apple, banana"
-- | join1With "" [NonEmptyString "apple", NonEmptyString "banana"] == NonEmptyString "applebanana"
-- | ```
join1With :: forall f. Foldable1 f => String -> f NonEmptyString -> NonEmptyString
join1With splice = NonEmptyString <<< joinWith splice
-- | Joins possibly empty strings in a non-empty container together as a new
-- | non-empty string, inserting a non-empty string as a separator between them.
-- | The result is guaranteed to be non-empty.
-- |
-- | ```purescript
-- | -- array syntax is used for demonstration here, it would need to be a real `Foldable1`
-- | joinWith1 (NonEmptyString ", ") ["apple", "banana"] == NonEmptyString "apple, banana"
-- | joinWith1 (NonEmptyString "/") ["a", "b", "", "c", ""] == NonEmptyString "a/b//c/"
-- | ```
joinWith1 :: forall f. Foldable1 f => NonEmptyString -> f String -> NonEmptyString
joinWith1 (NonEmptyString splice) = NonEmptyString <<< F.intercalate splice
liftS :: forall r. (String -> r) -> NonEmptyString -> r
liftS f (NonEmptyString s) = f s