<commit_before># react-inlinesvg
# ===============

# Our dependencies.

React = require 'react'
once = require 'once'
httpplease = require 'httpplease'
ieXDomain = require 'httpplease/lib/plugins/oldiexdomain'

{PropTypes} = React
{span} = React.DOM
http = httpplease.use ieXDomain

# An enum containing all the possible statuses of an isvg component. This is
# accessible via `InlineSVG.Status`.

Status =
  PENDING: 'pending'
  LOADING: 'loading'
  LOADED: 'loaded'
  FAILED: 'failed'
  UNSUPPORTED: 'unsupported'

module.exports = me =
  React.createClass
    statics: {Status}
    displayName: 'InlineSVG'
    propTypes:
      wrapper: PropTypes.func
      src: PropTypes.string.isRequired
      className: PropTypes.string
      preloader: PropTypes.func
      onLoad: PropTypes.func
      onError: PropTypes.func
      supportTest: PropTypes.func
    getDefaultProps: ->
      wrapper: span
      supportTest: isSupportedEnvironment
    getInitialState: ->
      status: Status.PENDING
    componentDidMount: ->
      return unless @state.status is Status.PENDING

      # Either load the SVG or trigger an error, simulating async behavior with
      # `delay` so as not to violate any implicit expectations in the user's
      # code which would be difficult to troubleshoot.
      if @props.supportTest()
        if @props.src then @setState status: Status.LOADING, @load
        else do delay => @fail configurationError 'Missing source'
      else
        do delay => @fail unsupportedBrowserError()
    fail: (error) ->
      console.log error
      status = if error.isUnsupportedBrowserError then Status.UNSUPPORTED else Status.FAILED
      @setState {status}, => @props.onError? error
    handleLoad: (err, res) ->
      return @fail err if err

      # If the component has been unmounted since we started the load, just
      # forget it. (Setting the state of an unmounted component causes an
      # error.)
      return unless @isMounted()

      # Update the state to include the loaded text. This will be rendered to
      # the DOM the next time `render()` runs.
      @setState
        loadedText: res.text
        status: Status.LOADED
        => @props.onLoad?()
    load: -> http.get @props.src, @handleLoad
    getClassName: ->
      # Build a CSS class name based on the current state.
      className = "isvg #{ @state.status }"
      className += " #{ @props.className }" if @props.className
      className
    render: ->
      (@props.wrapper
        className: @getClassName()
        dangerouslySetInnerHTML: __html: @state.loadedText if @state.loadedText
        @renderContents()
      )
    renderContents: ->
      switch @state.status
        when Status.UNSUPPORTED then @props.children
        when Status.PENDING, Status.LOADING
          new @props.preloader if @props.preloader


# Utils
# -----
#
# A test to determine whether the browser supports inline SVGs.

supportsInlineSVG = once ->
  return false unless document
  div = document.createElement 'div'
  div.innerHTML = '<svg />'
  div.firstChild and div.firstChild.namespaceURI is 'http://www.w3.org/2000/svg'

# Wrap a function in a `setTimeout` call. This is used to guarantee async
# behavior, which can avoid unexpected errors.

delay = (fn) ->
  (args...) ->
    newFunc = -> fn args...
    setTimeout newFunc, 0
    return

# Our default support test.

isSupportedEnvironment = once ->
  (window?.XMLHttpRequest or window?.XDomainRequest) and supportsInlineSVG()


# Errors
# ------
#
# A custom error used by the InlineSVG component. For ease of inspection, we have
# one error type with several flags that can be used to get information about the
# error type.

class InlineSVGError extends Error
  name: 'InlineSVGError'
  isSupportedBrowser: true
  isConfigurationError: false<commit_msg>Uniquify IDs in SVG documents<commit_after># react-inlinesvg
# ===============

# Our dependencies.

React = require 'react'
once = require 'once'
httpplease = require 'httpplease'
ieXDomain = require 'httpplease/lib/plugins/oldiexdomain'

{PropTypes} = React
{span} = React.DOM
http = httpplease.use ieXDomain

# An enum containing all the possible statuses of an isvg component. This is
# accessible via `InlineSVG.Status`.

Status =
  PENDING: 'pending'
  LOADING: 'loading'
  LOADED: 'loaded'
  FAILED: 'failed'
  UNSUPPORTED: 'unsupported'

module.exports = me =
  React.createClass
    statics: {Status}
    displayName: 'InlineSVG'
    propTypes:
      wrapper: PropTypes.func
      src: PropTypes.string.isRequired
      className: PropTypes.string
      preloader: PropTypes.func
      onLoad: PropTypes.func
      onError: PropTypes.func
      supportTest: PropTypes.func
      uniquifyIDs: PropTypes.bool
    getDefaultProps: ->
      wrapper: span
      supportTest: isSupportedEnvironment
      uniquifyIDs: true
    getInitialState: ->
      status: Status.PENDING
    componentDidMount: ->
      return unless @state.status is Status.PENDING

      # Either load the SVG or trigger an error, simulating async behavior with
      # `delay` so as not to violate any implicit expectations in the user's
      # code which would be difficult to troubleshoot.
      if @props.supportTest()
        if @props.src then @setState status: Status.LOADING, @load
        else do delay => @fail configurationError 'Missing source'
      else
        do delay => @fail unsupportedBrowserError()
    fail: (error) ->
      console.log error
      status = if error.isUnsupportedBrowserError then Status.UNSUPPORTED else Status.FAILED
      @setState {status}, => @props.onError? error
    handleLoad: (err, res) ->
      return @fail err if err

      # If the component has been unmounted since we started the load, just
      # forget it. (Setting the state of an unmounted component causes an
      # error.)
      return unless @isMounted()

      # Update the state to include the loaded text. This will be rendered to
      # the DOM the next time `render()` runs.
      @setState
        loadedText: res.text
        status: Status.LOADED
        => @props.onLoad?()
    load: -> http.get @props.src, @handleLoad
    getClassName: ->
      # Build a CSS class name based on the current state.
      className = "isvg #{ @state.status }"
      className += " #{ @props.className }" if @props.className
      className
    render: ->
      (@props.wrapper
        className: @getClassName()
        dangerouslySetInnerHTML: __html: @processSVG(@state.loadedText) if @state.loadedText
        @renderContents()
      )
    processSVG: (svgText) ->
      if @props.uniquifyIDs then uniquifyIDs svgText, getComponentID this
      else svgText
    renderContents: ->
      switch @state.status
        when Status.UNSUPPORTED then @props.children
        when Status.PENDING, Status.LOADING
          new @props.preloader if @props.preloader


# Utils
# -----
#
# A test to determine whether the browser supports inline SVGs.

supportsInlineSVG = once ->
  return false unless document
  div = document.createElement 'div'
  div.innerHTML = '<svg />'
  div.firstChild and div.firstChild.namespaceURI is 'http://www.w3.org/2000/svg'

# Wrap a function in a `setTimeout` call. This is used to guarantee async
# behavior, which can avoid unexpected errors.

delay = (fn) ->
  (args...) ->
    newFunc = -> fn args...
    setTimeout newFunc, 0
    return

# Our default support test.

isSupportedEnvironment = once ->
  (window?.XMLHttpRequest or window?.XDomainRequest) and supportsInlineSVG()

# Replaces the IDs in the provided string with document-unique IDs. This is
# obviously very naive, but is intended to provide a good-enough solution
# without adding too much overhead as would, for example, parsing as XML. See
# GH-3.

uniquifyIDs = do ->
  mkAttributePattern = (attr) -> "(?:(?:\\s|\\:)#{ attr })"
  idPattern =
    ///
    (?:                                    # Match ID declarations:
      (
        #{ mkAttributePattern 'id' }       #   The start of an attribute named "id"
      )
      ="
        ([^"]+)                            #   Our attribute value—match anything that isn't a quote.
      "                                    #   The end of the attribute
    )
    |                                      # ...OR...
    (?:                                    # Match IRI references:
      (
        #{ mkAttributePattern 'href' }
        |
        #{ mkAttributePattern 'role' }
        |
        #{ mkAttributePattern 'arcrole' }
      )
      ="                                   #   The start of an attribute
        \#                                 #   A literal # indicating this is an IRI reference
        ([^"]+)                            #   Our attribute value—match anything that isn't a quote.
      "                                    #   The end of the attribute
    )
    |                                      # ...OR...
    (?:                                    # Match FuncIRI references
      ="                                   #   The start of an attribute
        url\(                              #   The beginning of a FuncIRI
          \#                               #   A literal # indicating this is an IRI reference
          ([^\)]+)                         #   The id—match anything that isn't a closing paren
        \)                                 #   The end of the FuncIRI
      "                                    #   The end of the attribute
    )
    ///g
  (svgText, svgID) ->
    uniquifyID = (id) -> "#{ id }___#{ svgID }"
    svgText.replace idPattern, (m, p1, p2, p3, p4, p5) ->
      if p2 then "#{ p1 }=\"#{ uniquifyID p2 }\""
      else if p3 then "=\"url(##{ uniquifyID p3 })\""
      else if p5 then "#{ p4 }=\"##{ uniquifyID p4 }\""

# Gets a unique ID for the given component, for use in the id attribute.

getComponentID = do ->
  clean = (str) -> str.toString().replace /[^a-zA-Z0-9]/g, '_'
  (component) -> "#{ clean component._rootNodeID }__#{ clean component._mountDepth }"


# Errors
# ------
#
# A custom error used by the InlineSVG component. For ease of inspection, we have
# one error type with several flags that can be used to get information about the
# error type.

class InlineSVGError extends Error
  name: 'InlineSVGError'
  isSupportedBrowser: true
  isConfigurationError: false
{'fraction_non_alphanumeric': 0.09847380188587537, 'fraction_numerical': 0.0027218819869738505, 'mean_word_length': 2.2577580747308423, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 50, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 31, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6767266', 'n_tokens_mistral': 2899, 'n_tokens_neox': 2868, 'n_words': 964}