docs: function matchIndentBase(text, offset, matchedTokens, groups, type) {
      const noTokensMatchedYet = _.isEmpty(matchedTokens)
      const newLines = groups.nl
      const noNewLinesMatchedYet = _.isEmpty(newLines)
      const isFirstLine = noTokensMatchedYet && noNewLinesMatchedYet
      const isStartOfLine =
          // only newlines matched so far
          (noTokensMatchedYet && !noNewLinesMatchedYet) ||
          // Both newlines and other Tokens have been matched AND the last matched Token is a newline
          (!noTokensMatchedYet &&
              !noNewLinesMatchedYet &&
              (!_.isEmpty(newLines) &&
                  !_.isEmpty(matchedTokens) &&
                  _.last(newLines).startOffset) >
                  _.last(matchedTokens).startOffset)
  
      // indentation can only be matched at the start of a line.
      if (isFirstLine || isStartOfLine) {
          let match
          let currIndentLevel = undefined
  
          const wsRegExp = / +/y
          wsRegExp.lastIndex = offset
          match = wsRegExp.exec(text)
          // possible non-empty indentation
          if (match !== null) {
              currIndentLevel = match[0].length
          }
          // "empty" indentation means indentLevel of 0.
          else {
              currIndentLevel = 0
          }
  
          const prevIndentLevel = _.last(indentStack)
          // deeper indentation
          if (currIndentLevel > prevIndentLevel && type === "indent") {
              indentStack.push(currIndentLevel)
              return match
          }
          // shallower indentation
          else if (currIndentLevel < prevIndentLevel && type === "outdent") {
              const matchIndentIndex = _.findLastIndex(
                  indentStack,
                  stackIndentDepth => stackIndentDepth === currIndentLevel
              )
  
              // any outdent must match some previous indentation level.
              if (matchIndentIndex === -1) {
                  throw Error(`invalid outdent at offset: ${offset}`)
              }
  
              const numberOfDedents = indentStack.length - matchIndentIndex - 1
  
              // This is a little tricky
              // 1. If there is no match (0 level indent) than this custom token
              //    matcher would return "null" and so we need to add all the required outdents ourselves.
              // 2. If there was match (> 0 level indent) than we need to add minus one number of outsents
              //    because the lexer would create one due to returning a none null result.
              let iStart = match !== null ? 1 : 0
              for (let i = iStart; i < numberOfDedents; i++) {
                  indentStack.pop()
                  matchedTokens.push(
                      createTokenInstance(
                          Outdent,
                          "",
                          NaN,
                          NaN,
                          NaN,
                          NaN,
                          NaN,
                          NaN
                      )
                  )
              }
  
              // even though we are adding fewer outdents directly we still need to update the indent stack fully.
              if (iStart === 1) {
                  indentStack.pop()
              }
              return match
          } else {
              // same indent, this should be lexed as simple whitespace and ignored
              return null
          }
      } else {
          // indentation cannot be matched under other circumstances
          return null
      }
  }