
const group = (pattern: string) => `(?:${pattern})`

const optional = (pattern: string) => group(pattern) + '?'

const all = (pattern: string) => group(pattern) + '*'

const atLeast = (count: number, pattern: string) => group(pattern) + `{${count},}`

const either = (...patterns: string[]) => group(patterns.join('|'))

const whitespace = '[^\\S\\n]'

const lineOf = (pattern: string) => `^` + pattern + all(whitespace) + '$'

const streakOf = (char: string) => lineOf(atLeast(3, char))

const dottedStreakOf = (char: string) => lineOf(optional(' ') + atLeast(2, char + ' ') + char)

const BLANK_LINE = new RegExp(
  lineOf('')
)

// We don't need to check for the start or end of the string, because if a line
// contains a non-whitespace character anywhere in it, it's not blank.
const NON_BLANK_LINE = /\S/

export {
  NON_BLANK_LINE,
  BLANK_LINE,
  either,
  lineOf,
  streakOf,
  dottedStreakOf
}

const group = (pattern: string) => `(?:${pattern})`

const optional = (pattern: string) => pattern + '?'

const all = (pattern: string) => pattern + '*'

const atLeast = (count: number, pattern: string) => pattern + `{${count},}`

const either = (...patterns: string[]) => group(patterns.join('|'))

const whitespace = '[^\\S\\n]'

const lineOf = (pattern: string) => `^` + pattern + all(whitespace) + '$'

const streakOf = (char: string) => lineOf(atLeast(3, char))

const dottedStreakOf = (char: string) => lineOf(optional(' ') + atLeast(2, group(char + ' ')) + char)

const BLANK_LINE = new RegExp(
  lineOf('')
)

// We don't need to check for the start or end of the string, because if a line
// contains a non-whitespace character anywhere in it, it's not blank.
const NON_BLANK_LINE = /\S/

export {
  NON_BLANK_LINE,
  BLANK_LINE,
  either,
  lineOf,
  streakOf,
  dottedStreakOf
}
--- 
+++ 
@@ -1,11 +1,11 @@
 
 const group = (pattern: string) => `(?:${pattern})`
 
-const optional = (pattern: string) => pattern + '?'
+const optional = (pattern: string) => group(pattern) + '?'
 
-const all = (pattern: string) => pattern + '*'
+const all = (pattern: string) => group(pattern) + '*'
 
-const atLeast = (count: number, pattern: string) => pattern + `{${count},}`
+const atLeast = (count: number, pattern: string) => group(pattern) + `{${count},}`
 
 const either = (...patterns: string[]) => group(patterns.join('|'))
 
@@ -15,7 +15,7 @@
 
 const streakOf = (char: string) => lineOf(atLeast(3, char))
 
-const dottedStreakOf = (char: string) => lineOf(optional(' ') + atLeast(2, group(char + ' ')) + char)
+const dottedStreakOf = (char: string) => lineOf(optional(' ') + atLeast(2, char + ' ') + char)
 
 const BLANK_LINE = new RegExp(
   lineOf('')
Make public pattern helpers more robust
