function defineParser(sourceCode, config) {
  config = config || {}

  const exceptions = config.exceptions || []

  /**
   * Get a open decoration string from comment contents.
   * @param {string} contents comment contents
   * @returns {string} decoration string
   */
  function getOpenDecoration(contents) {
    let decoration = ''
    for (const exception of exceptions) {
      const length = exception.length
      let index = 0
      while (contents.startsWith(exception, index)) {
        index += length
      }
      const exceptionLength = index
      if (decoration.length < exceptionLength) {
        decoration = contents.slice(0, exceptionLength)
      }
    }
    return decoration
  }

  /**
   * Get a close decoration string from comment contents.
   * @param {string} contents comment contents
   * @returns {string} decoration string
   */
  function getCloseDecoration(contents) {
    let decoration = ''
    for (const exception of exceptions) {
      const length = exception.length
      let index = contents.length
      while (contents.endsWith(exception, index)) {
        index -= length
      }
      const exceptionLength = contents.length - index
      if (decoration.length < exceptionLength) {
        decoration = contents.slice(index)
      }
    }
    return decoration
  }

  /**
   * Parse HTMLComment.
   * @param {Token} node a comment token
   * @returns {ParsedHTMLComment | null} the result of HTMLComment tokens.
   */
  return function parseHTMLComment(node) {
    if (node.type !== 'HTMLComment') {
      // Is not HTMLComment
      return null
    }

    const htmlCommentText = sourceCode.getText(node)

    if (
      !htmlCommentText.startsWith('<!--') ||
      !htmlCommentText.endsWith('-->')
    ) {
      // Is not normal HTML Comment
      // e.g. Error Code: "abrupt-closing-of-empty-comment", "incorrectly-closed-comment"
      return null
    }

    let valueText = htmlCommentText.slice(4, -3)
    const openDecorationText = getOpenDecoration(valueText)
    valueText = valueText.slice(openDecorationText.length)
    const firstCharIndex = valueText.search(/\S/)
    const beforeSpace =
      firstCharIndex >= 0 ? valueText.slice(0, firstCharIndex) : valueText
    valueText = valueText.slice(beforeSpace.length)

    const closeDecorationText = getCloseDecoration(valueText)
    if (closeDecorationText) {
      valueText = valueText.slice(0, -closeDecorationText.length)
    }
    const lastCharIndex = valueText.search(/\S\s*$/)
    const afterSpace =
      lastCharIndex >= 0 ? valueText.slice(lastCharIndex + 1) : valueText
    if (afterSpace) {
      valueText = valueText.slice(0, -afterSpace.length)
    }

    let tokenIndex = node.range[0]
    /**
     * @param {string} type
     * @param {string} value
     * @returns {any}
     */
    const createToken = (type, value) => {
      /** @type {Range} */
      const range = [tokenIndex, tokenIndex + value.length]
      tokenIndex = range[1]
      /** @type {SourceLocation} */
      let loc
      return {
        type,
        value,
        range,
        get loc() {
          if (loc) {
            return loc
          }
          return (loc = {
            start: sourceCode.getLocFromIndex(range[0]),
            end: sourceCode.getLocFromIndex(range[1])
          })
        }
      }
    }

    /** @type {HTMLCommentOpen} */
    const open = createToken(TYPE_HTML_COMMENT_OPEN, '<!--')
    /** @type {HTMLCommentOpenDecoration | null} */
    const openDecoration = openDecorationText
      ? createToken(TYPE_HTML_COMMENT_OPEN_DECORATION, openDecorationText)
      : null
    tokenIndex += beforeSpace.length
    /** @type {HTMLCommentValue | null} */
    const value = valueText
      ? createToken(TYPE_HTML_COMMENT_VALUE, valueText)
      : null
    tokenIndex += afterSpace.length
    /** @type {HTMLCommentCloseDecoration | null} */
    const closeDecoration = closeDecorationText
      ? createToken(TYPE_HTML_COMMENT_CLOSE_DECORATION, closeDecorationText)
      : null
    /** @type {HTMLCommentClose} */
    const close = createToken(TYPE_HTML_COMMENT_CLOSE, '-->')

    return {
      /** HTML comment open (`<!--`) */
      open,
      /** decoration of the start of HTML comments. (`*****` when `<!--*****`) */
      openDecoration,
      /** value of HTML comment. whitespaces and other tokens are not included. */
      value,
      /** decoration of the end of HTML comments.  (`*****` when `*****-->`) */
      closeDecoration,
      /** HTML comment close (`-->`) */
      close
    }
  }
}
Define HTML comment parser

@param {SourceCode} sourceCode The source code instance.
@param {CommentParserConfig | null} config The config.
@returns { (node: Token) => (ParsedHTMLComment | null) } HTML comment parser.