<commit_before>const styleToLeaflet = require('./styleToLeaflet')

class Sublayer {
  constructor (master, options) {
    this.master = master
    this.options = options

    this.visibleFeatures = {}
    this.shownFeatures = {} // features which are forcibly shown
    this.shownFeatureOptions = {}
    this.lastZoom = null
  }

  addTo (map) {
    this.map = map
  }

  startAdding () {
    this.currentRequestFeatures = {}
  }

  add (ob) {
    this.currentRequestFeatures[ob.id] = true

    if (!(ob.id in this.visibleFeatures)) {
      var data = {
        object: ob,
        isShown: false
      }

      if (ob.id in this.shownFeatures) {
        data = this.shownFeatures[ob.id]
      } else {
        this._processObject(data)

        this._show(data)
      }

      this.visibleFeatures[ob.id] = data

      if (this.master.layerList) {
        this.master.layerList.addObject(data)
      }
      if (this.master.onAppear) {
        this.master.onAppear(data)
      }
    }
  }

  finishAdding () {
    for (var k in this.visibleFeatures) {
      if (!(k in this.currentRequestFeatures)) {
        if (!(k in this.shownFeatures)) {
          this._hide(this.visibleFeatures[k])
        }

        if (this.master.layerList) {
          this.master.layerList.delObject(this.visibleFeatures[k])
        }
        if (this.master.onDisappear) {
          this.master.onDisappear(this.visibleFeatures[k])
        }

        delete this.visibleFeatures[k]
      }
    }
  }

  hideAll (force) {
    for (let k in this.visibleFeatures) {
      let ob = this.visibleFeatures[k]

      if (this.master.layerList) {
        this.master.layerList.delObject(ob)
      }
      if (this.master.onDisappear) {
        this.master.onDisappear(ob)
      }

      if (force || !(ob.id in this.shownFeatures)) {
        this._hide(ob)
      }
    }

    this.visibleFeatures = {}
  }

  // Hide loaded but non-visible objects
  hideNonVisible (bounds) {
    for (let k in this.visibleFeatures) {
      let ob = this.visibleFeatures[k]

      if (!ob.object.intersects(bounds)) {
        if (this.master.layerList) {
          this.master.layerList.delObject(ob)
        }
        if (this.master.onDisappear) {
          this.master.onDisappear(ob)
        }

        if (!(ob.id in this.shownFeatures)) {
          this._hide(ob)
        }

        delete this.visibleFeatures[k]
      }
    }
  }

  get (id) {
    if (id in this.visibleFeatures) {
      return this.visibleFeatures[id]
    }

    if (id in this.shownFeatures) {
      return this.shownFeatures[id]
    }
  }

  show (ob, options) {
    if (typeof ob === 'string') {
      return this.master.get(ob, (err, ob) => this.show.bind(this, ob, options))
    }

    let id = ob.id
    let data

    if (id in this.visibleFeatures) {
      data = this.shownFeatures[id] = this.visibleFeatures[id]
      if (!(id in this.shownFeatureOptions)) {
        this.shownFeatureOptions[id] = []
      }
    }

    if (id in this.shownFeatures) {
      data = this.shownFeatures[id]
      this.shownFeatureOptions[id].push(options)
    } else {
      data = {
        object: ob,
        isShown: true
      }
      this.shownFeatures[id] = data

      this.shownFeatureOptions[id] = [ options ]
    }

    this._processObject(this.shownFeatures[id])

    this._show(this.shownFeatures[id])

    return {
      id,
      options,
      data,
      hide: () => {
        if (id in this.shownFeatures) {
          var i = this.shownFeatureOptions[id].indexOf(options)
          if (i !== -1) {
            this.shownFeatureOptions[id].splice(i, 1)
          }

          if (this.shownFeatureOptions[id].length === 0) {
            this.hide(data)
          } else {
            this._processObject(this.shownFeatures[id])
          }
        }
      }
    }
  }

  hide (id) {
    if (typeof id === 'object') {
      id = id.id
    }

    if (id in this.shownFeatures) {
      let data = this.shownFeatures[id]
      delete this.shownFeatures[id]
      delete this.shownFeatureOptions[id]

      if (id in this.visibleFeatures) {
        this._processObject(data)
      } else {
        this._hide(data)
      }
    }
  }

  zoomChange () {
    this.recalc()

    for (let k in this.visibleFeatures) {
      if (this.master.onZoomChange) {
        this.master.onZoomChange(this.visibleFeatures[k])
      }
    }

    this.lastZoom = this.map.getZoom()
  }

  recalc () {
    for (var k in this.visibleFeatures) {
      this._processObject(this.visibleFeatures[k])
    }
  }

  _processObject (data) {
    var k
    var ob = data.object
    var showOptions = {
      styles: []
    }

    delete this.master._scheduledReprocesses[data.id]

    if (ob.id in this.shownFeatureOptions) {
      this.shownFeatureOptions[ob.id].forEach(function (opt) {
        if ('styles' in opt) {
          showOptions.styles = showOptions.styles.concat(opt.styles)
        }
      })
    }

    var objectData = this.evaluate(data)

    for (k in objectData) {
      var m = k.match(/^style(|:(.*))$/)
      if (m) {
        var styleId = typeof m[2] === 'undefined' ? 'default' : m[2]
        var style = styleToLeaflet(objectData[k])

        if (data.features[styleId]) {
          data.features[styleId].setStyle(style)
        } else {
          data.features[styleId] = ob.leafletFeature(style)
        }

        if ('text' in style && 'setText' in data.features[styleId]) {
          data.features[styleId].setText(null)
          data.features[styleId].setText(style.text, {
            repeat: style.textRepeat,
            offset: style.textOffset,
            below: style.textBelow,
            attributes: {
              'fill': style.textFill,
              'fill-opacity': style.textFillOpacity,
              'font-weight': style.textFontWeight,
              'font-size': style.textFontSize,
              'letter-spacing': style.textLetterSpacing
            }
          })
        }

        if ('offset' in style && 'setOffset' in data.features[styleId]) {
          data.features[styleId].setOffset(style.offset)
        }
      }
    }

    if ('styles' in showOptions) {
      objectData.styles = objectData.styles.concat(showOptions.styles)
    }

    objectData.marker = {
      html: '',
      iconAnchor: [ 0, 0 ],
      iconSize: [ 0, 0 ],
      signAnchor: [ 0, 0 ],
      popupAnchor: [ 0, 0 ]
    }
    if (objectData.markerSymbol) {
      objectData.marker.html += objectData.markerSymbol

      var div = document.createElement('div')
      div.innerHTML = objectData.markerSymbol

      if (div.firstChild) {
        var c = div.firstChild

        objectData.marker.iconSize = [ c.offsetWidth, c.offsetHeight ]
        if (c.hasAttribute('width')) {
          objectData.marker.iconSize[0] = parseFloat(c.getAttribute('width'))
        }
        if (c.hasAttribute('height')) {
          objectData.marker.iconSize[1] = parseFloat(c.getAttribute('height'))
        }

        objectData.marker.iconAnchor = [ objectData.marker.iconSize[0] / 2, objectData.marker.iconSize[1] / 2 ]
        if (c.hasAttribute('anchorx')) {
          objectData.marker.iconAnchor[0] = parseFloat(c.getAttribute('anchorx'))
        }
        if (c.hasAttribute('anchory')) {
          objectData.marker.iconAnchor[1] = parseFloat(c.getAttribute('anchory'))
        }

        if (c.hasAttribute('signanchorx')) {
          objectData.marker.signAnchor[0] = parseFloat(c.getAttribute('signanchorx'))
        }
        if (c.hasAttribute('signanchory')) {
          objectData.marker.signAnchor[1] = parseFloat(c.getAttribute('signanchory'))
        }

        if (c.hasAttribute('popupanchory')) {
          objectData.marker.popupAnchor[0] = parseFloat(c.getAttribute('popupanchorx'))
        }
        if (c.hasAttribute('popupanchory')) {
          objectData.marker.popupAnchor[1] = parseFloat(c.getAttribute('popupanchory'))
        }
      }
    }

    if (objectData.markerSign) {
      let x = objectData.marker.iconAnchor[0] + objectData.marker.signAnchor[0]
      let y = -objectData.marker.iconSize[1] + objectData.marker.iconAnchor[1] + objectData.marker.signAnchor[1]
      objectData.marker.html += '
' + objectData.markerSign + '
'
    }

    if (objectData.marker.html) {
      objectData.marker.className = 'overpass-layer-icon'
      var icon = L.divIcon(objectData.marker)

      if (data.featureMarker) {
        data.featureMarker.setIcon(icon)
        if (data.featureMarker._icon) {
          this.updateAssets(data.featureMarker._icon)
        }
      } else {
        data.featureMarker = L.marker(ob.center, { icon: icon })
      }
    }

    if (data.isShown) {
      for (k in data.features) {
        if (objectData.styles && objectData.styles.indexOf(k) !== -1 && data.styles && data.styles.indexOf(k) === -1) {
          data.features[k].addTo(this.map)
        }
        if (objectData.styles && objectData.styles.indexOf(k) === -1 && data.styles && data.styles.indexOf(k) !== -1) {
          this.map.removeLayer(data.features[k])
        }
      }
    }
    data.styles = objectData.styles

    data.feature = data.styles.length
      ? data.features[data.styles[0]]
      : null

    var popupContent = ''
    popupContent += '
' + objectData.title + '
'
    popupContent += objectData.body

    if ('updateAssets' in this.options) {
      let div = document.createElement('div')
      div.innerHTML = popupContent
      this.updateAssets(div, objectData)
      popupContent = div.innerHTML
    }

    if (data.popup) {
      if (data.popup._contentNode) {
        data.popup._contentNode.innerHTML = popupContent
      } else {
        data.popup = data.popup.setContent(popupContent)
      }
    } else {
      data.popup = L.popup().setContent(popupContent)
      data.popup.object = data

      for (k in data.features) {
        if (this._shallBindPopupToStyle(k)) {
          data.features[k].bindPopup(data.popup)
        }
      }

      if (data.featureMarker) {
        data.featureMarker.bindPopup(data.popup)
      }
    }

    data.id = ob.id
    data.layer_id = this.options.id
    data.data = objectData

    if (this.master.layerList) {
      this.master.layerList.updateObject(data)
    }
    if (this.master.onUpdate) {
      this.master.onUpdate(data)
    }
  }

  evaluate (data) {
    var k
    var ob = data.object

    var twigData = this.twigData(ob)

    var objectData = {}
    for (k in this.options.feature) {
      if (typeof this.options.feature[k] === 'function') {
        objectData[k] = this.options.feature[k](twigData)
      } else {
        objectData[k] = this.options.feature[k]
      }
    }

    var styleIds = []
    for (k in objectData) {
      var m = k.match(/^style(|:(.*))$/)
      if (m) {
        var style = objectData[k]
        var styleId = typeof m[2] === 'undefined' ? 'default' : m[2]

        if (typeof style === 'string' || 'twig_markup' in style) {
          objectData[k] = strToStyle(style)
        }

        if (this.options.stylesNoAutoShow.indexOf(styleId) === -1) {
          styleIds.push(styleId)
        }
      }
    }

    if (!('features' in data)) {
      data.features = {}
    }

    objectData.styles =
      'styles' in objectData ? objectData.styles
        : 'styles' in this.options ? this.options.styles
          : styleIds
    if (typeof objectData.styles === 'string' || 'twig_markup' in objectData.styles) {
      var styles = objectData.styles.trim()
      if (styles === '') {
        objectData.styles = []
      } else {
        objectData.styles = styles.split(/,/)
      }
    }

    return objectData
  }

  twigData (ob) {
    var result = {
      id: ob.id,
      layer_id: this.options.id,
      osm_id: ob.osm_id,
      type: ob.type,
      tags: ob.tags,
      meta: ob.meta,
      'const': this.options.const
    }

    if (this.map) {
      result.map = {
        zoom: this.map.getZoom()
      }
    }

    return result
  }

  _shallBindPopupToStyle (styleId) {
    return this.options.styleNoBindPopup.indexOf(styleId) === -1
  }

  _show (data) {
    if (!this.map) {
      return
    }

    for (var i = 0; i < data.styles.length; i++) {
      var k = data.styles[i]
      if (k in data.features) {
        data.features[k].addTo(this.map)
      }
    }

    data.feature = data.styles.length
      ? data.features[data.styles[0]]
      : null

    if (data.featureMarker) {
      data.featureMarker.addTo(this.map)
      this.updateAssets(data.featureMarker._icon)
    }

    data.isShown = true
  }

  _hide (data) {
    for (var k in data.features) {
      this.map.removeLayer(data.features[k])
    }

    if (data.featureMarker) {
      this.map.removeLayer(data.featureMarker)
    }

    data.isShown = false
  }

  scheduleReprocess (id) {
    if (!(id in this._scheduledReprocesses)) {
      this._scheduledReprocesses[id] = window.setTimeout(this._processObject.bind(this, this.visibleFeatures[id]), 0)
    }
  }

  updateAssets (div, objectData) {
    if (!this.options.updateAssets) {
      return div
    }

    this.options.updateAssets(div, objectData, this)
  }
}

module.exports = Sublayer
<commit_msg>Include twigData in object data<commit_after>const styleToLeaflet = require('./styleToLeaflet')

class Sublayer {
  constructor (master, options) {
    this.master = master
    this.options = options

    this.visibleFeatures = {}
    this.shownFeatures = {} // features which are forcibly shown
    this.shownFeatureOptions = {}
    this.lastZoom = null
  }

  addTo (map) {
    this.map = map
  }

  startAdding () {
    this.currentRequestFeatures = {}
  }

  add (ob) {
    this.currentRequestFeatures[ob.id] = true

    if (!(ob.id in this.visibleFeatures)) {
      var data = {
        object: ob,
        isShown: false
      }

      if (ob.id in this.shownFeatures) {
        data = this.shownFeatures[ob.id]
      } else {
        this._processObject(data)

        this._show(data)
      }

      this.visibleFeatures[ob.id] = data

      if (this.master.layerList) {
        this.master.layerList.addObject(data)
      }
      if (this.master.onAppear) {
        this.master.onAppear(data)
      }
    }
  }

  finishAdding () {
    for (var k in this.visibleFeatures) {
      if (!(k in this.currentRequestFeatures)) {
        if (!(k in this.shownFeatures)) {
          this._hide(this.visibleFeatures[k])
        }

        if (this.master.layerList) {
          this.master.layerList.delObject(this.visibleFeatures[k])
        }
        if (this.master.onDisappear) {
          this.master.onDisappear(this.visibleFeatures[k])
        }

        delete this.visibleFeatures[k]
      }
    }
  }

  hideAll (force) {
    for (let k in this.visibleFeatures) {
      let ob = this.visibleFeatures[k]

      if (this.master.layerList) {
        this.master.layerList.delObject(ob)
      }
      if (this.master.onDisappear) {
        this.master.onDisappear(ob)
      }

      if (force || !(ob.id in this.shownFeatures)) {
        this._hide(ob)
      }
    }

    this.visibleFeatures = {}
  }

  // Hide loaded but non-visible objects
  hideNonVisible (bounds) {
    for (let k in this.visibleFeatures) {
      let ob = this.visibleFeatures[k]

      if (!ob.object.intersects(bounds)) {
        if (this.master.layerList) {
          this.master.layerList.delObject(ob)
        }
        if (this.master.onDisappear) {
          this.master.onDisappear(ob)
        }

        if (!(ob.id in this.shownFeatures)) {
          this._hide(ob)
        }

        delete this.visibleFeatures[k]
      }
    }
  }

  get (id) {
    if (id in this.visibleFeatures) {
      return this.visibleFeatures[id]
    }

    if (id in this.shownFeatures) {
      return this.shownFeatures[id]
    }
  }

  show (ob, options) {
    if (typeof ob === 'string') {
      return this.master.get(ob, (err, ob) => this.show.bind(this, ob, options))
    }

    let id = ob.id
    let data

    if (id in this.visibleFeatures) {
      data = this.shownFeatures[id] = this.visibleFeatures[id]
      if (!(id in this.shownFeatureOptions)) {
        this.shownFeatureOptions[id] = []
      }
    }

    if (id in this.shownFeatures) {
      data = this.shownFeatures[id]
      this.shownFeatureOptions[id].push(options)
    } else {
      data = {
        object: ob,
        isShown: true
      }
      this.shownFeatures[id] = data

      this.shownFeatureOptions[id] = [ options ]
    }

    this._processObject(this.shownFeatures[id])

    this._show(this.shownFeatures[id])

    return {
      id,
      options,
      data,
      hide: () => {
        if (id in this.shownFeatures) {
          var i = this.shownFeatureOptions[id].indexOf(options)
          if (i !== -1) {
            this.shownFeatureOptions[id].splice(i, 1)
          }

          if (this.shownFeatureOptions[id].length === 0) {
            this.hide(data)
          } else {
            this._processObject(this.shownFeatures[id])
          }
        }
      }
    }
  }

  hide (id) {
    if (typeof id === 'object') {
      id = id.id
    }

    if (id in this.shownFeatures) {
      let data = this.shownFeatures[id]
      delete this.shownFeatures[id]
      delete this.shownFeatureOptions[id]

      if (id in this.visibleFeatures) {
        this._processObject(data)
      } else {
        this._hide(data)
      }
    }
  }

  zoomChange () {
    this.recalc()

    for (let k in this.visibleFeatures) {
      if (this.master.onZoomChange) {
        this.master.onZoomChange(this.visibleFeatures[k])
      }
    }

    this.lastZoom = this.map.getZoom()
  }

  recalc () {
    for (var k in this.visibleFeatures) {
      this._processObject(this.visibleFeatures[k])
    }
  }

  _processObject (data) {
    var k
    var ob = data.object
    var showOptions = {
      styles: []
    }

    delete this.master._scheduledReprocesses[data.id]

    if (ob.id in this.shownFeatureOptions) {
      this.shownFeatureOptions[ob.id].forEach(function (opt) {
        if ('styles' in opt) {
          showOptions.styles = showOptions.styles.concat(opt.styles)
        }
      })
    }

    var objectData = this.evaluate(data)

    for (k in objectData) {
      var m = k.match(/^style(|:(.*))$/)
      if (m) {
        var styleId = typeof m[2] === 'undefined' ? 'default' : m[2]
        var style = styleToLeaflet(objectData[k])

        if (data.features[styleId]) {
          data.features[styleId].setStyle(style)
        } else {
          data.features[styleId] = ob.leafletFeature(style)
        }

        if ('text' in style && 'setText' in data.features[styleId]) {
          data.features[styleId].setText(null)
          data.features[styleId].setText(style.text, {
            repeat: style.textRepeat,
            offset: style.textOffset,
            below: style.textBelow,
            attributes: {
              'fill': style.textFill,
              'fill-opacity': style.textFillOpacity,
              'font-weight': style.textFontWeight,
              'font-size': style.textFontSize,
              'letter-spacing': style.textLetterSpacing
            }
          })
        }

        if ('offset' in style && 'setOffset' in data.features[styleId]) {
          data.features[styleId].setOffset(style.offset)
        }
      }
    }

    if ('styles' in showOptions) {
      objectData.styles = objectData.styles.concat(showOptions.styles)
    }

    objectData.marker = {
      html: '',
      iconAnchor: [ 0, 0 ],
      iconSize: [ 0, 0 ],
      signAnchor: [ 0, 0 ],
      popupAnchor: [ 0, 0 ]
    }
    if (objectData.markerSymbol) {
      objectData.marker.html += objectData.markerSymbol

      var div = document.createElement('div')
      div.innerHTML = objectData.markerSymbol

      if (div.firstChild) {
        var c = div.firstChild

        objectData.marker.iconSize = [ c.offsetWidth, c.offsetHeight ]
        if (c.hasAttribute('width')) {
          objectData.marker.iconSize[0] = parseFloat(c.getAttribute('width'))
        }
        if (c.hasAttribute('height')) {
          objectData.marker.iconSize[1] = parseFloat(c.getAttribute('height'))
        }

        objectData.marker.iconAnchor = [ objectData.marker.iconSize[0] / 2, objectData.marker.iconSize[1] / 2 ]
        if (c.hasAttribute('anchorx')) {
          objectData.marker.iconAnchor[0] = parseFloat(c.getAttribute('anchorx'))
        }
        if (c.hasAttribute('anchory')) {
          objectData.marker.iconAnchor[1] = parseFloat(c.getAttribute('anchory'))
        }

        if (c.hasAttribute('signanchorx')) {
          objectData.marker.signAnchor[0] = parseFloat(c.getAttribute('signanchorx'))
        }
        if (c.hasAttribute('signanchory')) {
          objectData.marker.signAnchor[1] = parseFloat(c.getAttribute('signanchory'))
        }

        if (c.hasAttribute('popupanchory')) {
          objectData.marker.popupAnchor[0] = parseFloat(c.getAttribute('popupanchorx'))
        }
        if (c.hasAttribute('popupanchory')) {
          objectData.marker.popupAnchor[1] = parseFloat(c.getAttribute('popupanchory'))
        }
      }
    }

    if (objectData.markerSign) {
      let x = objectData.marker.iconAnchor[0] + objectData.marker.signAnchor[0]
      let y = -objectData.marker.iconSize[1] + objectData.marker.iconAnchor[1] + objectData.marker.signAnchor[1]
      objectData.marker.html += '
' + objectData.markerSign + '
'
    }

    if (objectData.marker.html) {
      objectData.marker.className = 'overpass-layer-icon'
      var icon = L.divIcon(objectData.marker)

      if (data.featureMarker) {
        data.featureMarker.setIcon(icon)
        if (data.featureMarker._icon) {
          this.updateAssets(data.featureMarker._icon)
        }
      } else {
        data.featureMarker = L.marker(ob.center, { icon: icon })
      }
    }

    if (data.isShown) {
      for (k in data.features) {
        if (objectData.styles && objectData.styles.indexOf(k) !== -1 && data.styles && data.styles.indexOf(k) === -1) {
          data.features[k].addTo(this.map)
        }
        if (objectData.styles && objectData.styles.indexOf(k) === -1 && data.styles && data.styles.indexOf(k) !== -1) {
          this.map.removeLayer(data.features[k])
        }
      }
    }
    data.styles = objectData.styles

    data.feature = data.styles.length
      ? data.features[data.styles[0]]
      : null

    var popupContent = ''
    popupContent += '
' + objectData.title + '
'
    popupContent += objectData.body

    if ('updateAssets' in this.options) {
      let div = document.createElement('div')
      div.innerHTML = popupContent
      this.updateAssets(div, objectData)
      popupContent = div.innerHTML
    }

    if (data.popup) {
      if (data.popup._contentNode) {
        data.popup._contentNode.innerHTML = popupContent
      } else {
        data.popup = data.popup.setContent(popupContent)
      }
    } else {
      data.popup = L.popup().setContent(popupContent)
      data.popup.object = data

      for (k in data.features) {
        if (this._shallBindPopupToStyle(k)) {
          data.features[k].bindPopup(data.popup)
        }
      }

      if (data.featureMarker) {
        data.featureMarker.bindPopup(data.popup)
      }
    }

    data.id = ob.id
    data.layer_id = this.options.id
    data.data = objectData

    if (this.master.layerList) {
      this.master.layerList.updateObject(data)
    }
    if (this.master.onUpdate) {
      this.master.onUpdate(data)
    }
  }

  evaluate (data) {
    var k
    var ob = data.object

    data.twigData = this.twigData(ob)

    var objectData = {}
    for (k in this.options.feature) {
      if (typeof this.options.feature[k] === 'function') {
        objectData[k] = this.options.feature[k](data.twigData)
      } else {
        objectData[k] = this.options.feature[k]
      }
    }

    var styleIds = []
    for (k in objectData) {
      var m = k.match(/^style(|:(.*))$/)
      if (m) {
        var style = objectData[k]
        var styleId = typeof m[2] === 'undefined' ? 'default' : m[2]

        if (typeof style === 'string' || 'twig_markup' in style) {
          objectData[k] = strToStyle(style)
        }

        if (this.options.stylesNoAutoShow.indexOf(styleId) === -1) {
          styleIds.push(styleId)
        }
      }
    }

    if (!('features' in data)) {
      data.features = {}
    }

    objectData.styles =
      'styles' in objectData ? objectData.styles
        : 'styles' in this.options ? this.options.styles
          : styleIds
    if (typeof objectData.styles === 'string' || 'twig_markup' in objectData.styles) {
      var styles = objectData.styles.trim()
      if (styles === '') {
        objectData.styles = []
      } else {
        objectData.styles = styles.split(/,/)
      }
    }

    return objectData
  }

  twigData (ob) {
    var result = {
      id: ob.id,
      layer_id: this.options.id,
      osm_id: ob.osm_id,
      type: ob.type,
      tags: ob.tags,
      meta: ob.meta,
      'const': this.options.const
    }

    if (this.map) {
      result.map = {
        zoom: this.map.getZoom()
      }
    }

    return result
  }

  _shallBindPopupToStyle (styleId) {
    return this.options.styleNoBindPopup.indexOf(styleId) === -1
  }

  _show (data) {
    if (!this.map) {
      return
    }

    for (var i = 0; i < data.styles.length; i++) {
      var k = data.styles[i]
      if (k in data.features) {
        data.features[k].addTo(this.map)
      }
    }

    data.feature = data.styles.length
      ? data.features[data.styles[0]]
      : null

    if (data.featureMarker) {
      data.featureMarker.addTo(this.map)
      this.updateAssets(data.featureMarker._icon)
    }

    data.isShown = true
  }

  _hide (data) {
    for (var k in data.features) {
      this.map.removeLayer(data.features[k])
    }

    if (data.featureMarker) {
      this.map.removeLayer(data.featureMarker)
    }

    data.isShown = false
  }

  scheduleReprocess (id) {
    if (!(id in this._scheduledReprocesses)) {
      this._scheduledReprocesses[id] = window.setTimeout(this._processObject.bind(this, this.visibleFeatures[id]), 0)
    }
  }

  updateAssets (div, objectData) {
    if (!this.options.updateAssets) {
      return div
    }

    this.options.updateAssets(div, objectData, this)
  }
}

module.exports = Sublayer
<|endoftext|>


<commit_before>'use strict';

angular.module('app')
    .controller('rgiDocumentTableCtrl', function (
        _,
        $scope,
        $rootScope,
        rgiDialogFactory,
        rgiAssessmentSrvc,
        rgiDocumentSrvc,
        rgiHttpResponseProcessorSrvc,
        rgiIdentitySrvc,
        rgiNotifier
    ) {
        var limit = 100,
            currentPage = 0,
            totalPages = 0;

        $scope.current_user = rgiIdentitySrvc.currentUser;
        $scope.busy = false;

        $scope.assessment_filter_options = [
            {value: 'all', text: 'Show all documents'}
            // {value: 'type', text: 'Sort by document type'},
            // {value: 'assessments', text: 'Sort by attached assessments'}
        ];

        $scope.assessment_filter = $scope.assessment_filter_options[0].value;

        rgiAssessmentSrvc.query({}, function (assessments) {
            if(assessments.reason) {
                rgiNotifier.error('No assessments');
            } else {
                assessments.forEach(function(assessment) {
                    console.log(assessment);
                    $scope.assessment_filter_options.push({
                        value: assessment.assessment_ID,
                        text: assessment.country + ' ' + assessment.year + ' ' + assessment.version
                    });
                });
            }
        });

        rgiDocumentSrvc.query({skip: currentPage, limit: limit}, function (response) {
            if(response.reason) {
                rgiNotifier.error('Load document data failure');
            } else {
                $scope.count = response.count;
                $scope.documents = response.data;
                totalPages = Math.ceil(response.count / limit);
                currentPage = currentPage + 1;
            }
        }, rgiHttpResponseProcessorSrvc.getDefaultHandler('Load document data failure'));

        $scope.loadMoreDocs = function() {
            if ($scope.busy) {
                return;
            }

            $scope.busy = true;

            if(currentPage < totalPages) {
                rgiDocumentSrvc.query({skip: currentPage, limit: limit}, function (response) {
                    if(response.reason) {
                        rgiNotifier.error('Documents loading failure');
                    } else {
                        $scope.documents = _.union($scope.documents, response.data);
                        currentPage = currentPage + 1;
                        $scope.busy = false;
                    }
                }, rgiHttpResponseProcessorSrvc.getDefaultHandler('Load document data failure'));
            }
        };

        $scope.deleteDocument = function(doc) {
            rgiDialogFactory.deleteDocument($scope, doc);
        };
    });
<commit_msg>fix the 'Document Table' directive controller<commit_after>'use strict';

angular.module('app')
    .controller('rgiDocumentTableCtrl', function (
        _,
        $scope,
        $rootScope,
        rgiDialogFactory,
        rgiAssessmentSrvc,
        rgiDocumentSrvc,
        rgiHttpResponseProcessorSrvc,
        rgiNotifier
    ) {
        var currentPage, totalPages, limit = 100;

        $scope.busy = false;
        $scope.assessment_filter_options = [];
        $scope.assessment_filter = '';

        rgiAssessmentSrvc.query({}, function (assessments) {
            if(assessments.reason) {
                rgiNotifier.error('No assessments');
            } else {
                assessments.forEach(function(assessment) {
                    $scope.assessment_filter_options.push({
                        value: assessment.assessment_ID,
                        text: assessment.country + ' ' + assessment.year + ' ' + assessment.version
                    });
                });
            }
        });

        $scope.$watch('assessment_filter', function(assessment) {
            currentPage = 0;
            totalPages = 0;
            var searchOptions = {skip: currentPage, limit: limit};

            if(assessment) {
                searchOptions.assessments = assessment;
            }

            rgiDocumentSrvc.queryCached(searchOptions, function (response) {
                if(response.reason) {
                    rgiNotifier.error('Load document data failure');
                } else {
                    $scope.count = response.count;
                    $scope.documents = response.data;

                    if($scope.documents.length === 0) {
                        rgiNotifier.error('No documents uploaded');
                    }

                    totalPages = Math.ceil(response.count / limit);
                    currentPage = 1;
                }
            }, rgiHttpResponseProcessorSrvc.getDefaultHandler('Load document data failure'));
        });

        $scope.loadMoreDocs = function() {
            if ($scope.busy) {
                return;
            }

            $scope.busy = true;

            if(currentPage < totalPages) {
                var searchOptions = {skip: currentPage, limit: limit};

                if($scope.assessment_filter) {
                    searchOptions.assessments = $scope.assessment_filter;
                }

                rgiDocumentSrvc.query(searchOptions, function (response) {
                    if(response.reason) {
                        rgiNotifier.error('Documents loading failure');
                    } else {
                        $scope.documents = _.union($scope.documents, response.data);
                        currentPage = currentPage + 1;
                        $scope.busy = false;
                    }
                }, rgiHttpResponseProcessorSrvc.getDefaultHandler('Load document data failure'));
            }
        };

        $scope.deleteDocument = function(doc) {
            rgiDialogFactory.deleteDocument($scope, doc);
        };
    });
<|endoftext|>


<commit_before>// IMPORTANT: Replace below with your Firebase app URL
var firebaseUrl = "https://my-firebase-app.firebaseio.com/";

var converter = new Showdown.converter();

var Comment = React.createClass({
  render: function() {
    var rawMarkup = converter.makeHtml(this.props.children.toString());
    return (

{this.props.author}

    );
  }
});

var CommentList = React.createClass({
  render: function() {
    var commentNodes = this.props.data.map(function (comment, index) {
      return <Comment key={index} author={comment.author}>{comment.text}</Comment>;
    });
    return
{commentNodes}
;
  }
});

var CommentForm = React.createClass({
  handleSubmit: function() {
    event.preventDefault();
    var author = this.refs.author.getDOMNode().value.trim();
    var text = this.refs.text.getDOMNode().value.trim();
    this.props.onCommentSubmit({author: author, text: text});
    this.refs.author.getDOMNode().value = '';
    this.refs.text.getDOMNode().value = '';
    return false;
  },

  render: function() {
    return (
      <form className="commentForm" onSubmit={this.handleSubmit}>
        <input type="text" placeholder="Your name" ref="author" />
        <input type="text" placeholder="Say something..." ref="text" />
        <input type="submit" value="Post" />
      </form>
    );
  }
});

var CommentBox = React.createClass({
  mixins: [ReactFireMixin],

  handleCommentSubmit: function(comment) {
    // Here we push the update out to Firebase and let ReactFire update this.state.data
    this.firebaseRefs["data"].push(comment);
  },

  getInitialState: function() {
    return {
      data: []
    };
  },

  componentWillMount: function() {
    // Here we bind the component to Firebase and it handles all data updates,
    // no need to poll as in the React example.
    this.bindAsArray(new Firebase(firebaseUrl + "commentBox"), "data");
  },

  render: function() {
    return (

Comments

        <CommentList data={this.state.data} />
        <CommentForm onCommentSubmit={this.handleCommentSubmit} />

    );
  }
});

React.render(
  <CommentBox />,
  document.getElementById('content')
);
<commit_msg>Update app.js<commit_after>// IMPORTANT: Replace below with your Firebase app URL
var firebaseUrl = "https://my-firebase-app.firebaseio.com/";

var converter = new Showdown.converter();

var Comment = React.createClass({
  render: function() {
    var rawMarkup = converter.makeHtml(this.props.children.toString());
    return (

{this.props.author}

    );
  }
});

var CommentList = React.createClass({
  render: function() {
    var commentNodes = this.props.data.map(function (comment, index) {
      return <Comment key={index} author={comment.author}>{comment.text}</Comment>;
    });
    return
{commentNodes}
;
  }
});

var CommentForm = React.createClass({
  handleSubmit: function(e) {
    e.preventDefault();
    var author = this.refs.author.getDOMNode().value.trim();
    var text = this.refs.text.getDOMNode().value.trim();
    this.props.onCommentSubmit({author: author, text: text});
    this.refs.author.getDOMNode().value = '';
    this.refs.text.getDOMNode().value = '';
    return false;
  },

  render: function() {
    return (
      <form className="commentForm" onSubmit={this.handleSubmit}>
        <input type="text" placeholder="Your name" ref="author" />
        <input type="text" placeholder="Say something..." ref="text" />
        <input type="submit" value="Post" />
      </form>
    );
  }
});

var CommentBox = React.createClass({
  mixins: [ReactFireMixin],

  handleCommentSubmit: function(comment) {
    // Here we push the update out to Firebase and let ReactFire update this.state.data
    this.firebaseRefs["data"].push(comment);
  },

  getInitialState: function() {
    return {
      data: []
    };
  },

  componentWillMount: function() {
    // Here we bind the component to Firebase and it handles all data updates,
    // no need to poll as in the React example.
    this.bindAsArray(new Firebase(firebaseUrl + "commentBox"), "data");
  },

  render: function() {
    return (

Comments

        <CommentList data={this.state.data} />
        <CommentForm onCommentSubmit={this.handleCommentSubmit} />

    );
  }
});

React.render(
  <CommentBox />,
  document.getElementById('content')
);
<|endoftext|>


<commit_before>import * as utils from 'base/utils';
import Class from 'base/class';

export default Class.extend({

  init: function(context) {
    this.context = context;
  },

  toggle: function(arg) {
    var _this = this.context;

    if(arg) {
      _this._trails.create();
      _this._trails.run(["resize", "recolor", "findVisible", "reveal"]);
    } else {
      _this._trails.run("remove");
      _this.model.entities.select.forEach(function(d) {
        d.trailStartTime = null;
      });
    }
  },

  create: function(selection) {
    var _this = this.context;
    var KEY = _this.KEY;

    //quit if the function is called accidentally
    if(!_this.model.time.trails || !_this.model.entities.select.length) return;

    var start = +_this.timeFormatter(_this.model.time.start);
    var end = +_this.timeFormatter(_this.model.time.end);
    var step = _this.model.time.step;
    var timePoints = [];
    for(var time = start; time <= end; time += step) timePoints.push(time);

    //work with entities.select (all selected entities), if no particular selection is specified
    selection = selection == null ? _this.model.entities.select : [selection];
    selection.forEach(function(d) {

      var trailSegmentData = timePoints.map(function(m) {
        return {
          t: _this.timeFormatter.parse("" + m)
        }
      });

      if(_this.cached[d[KEY]] == null) _this.cached[d[KEY]] = {};

      _this.cached[d[KEY]].maxMinValues = {
        valueXmax: null,
        valueXmin: null,
        valueYmax: null,
        valueYmin: null,
        valueSmax: null
      };

      var maxmin = _this.cached[d[KEY]].maxMinValues;

      var trail = _this.entityTrails
        .filter(function(f) {
          return f[KEY] == "trail-" + d[KEY]
        })
        .selectAll("g")
        .data(trailSegmentData);

      trail.exit().remove();

      trail.enter().append("g")
        .attr("class", "vzb-bc-trailsegment")
        .on("mousemove", function(segment, index) {
          if(utils.isTouchDevice()) return;
          var _key = d3.select(this.parentNode).data()[0][KEY];

          var pointer = {};
          pointer[KEY] = _key.replace("trail-", "");
          pointer.time = segment.t;

          _this._axisProjections(pointer);
          _this._setTooltip(_this.timeFormatter(segment.t));
          _this.entityLabels
            .filter(function(f) {
              return f[KEY] == _key
            })
            .classed("vzb-highlighted", true);
        })
        .on("mouseout", function(segment, index) {
          if(utils.isTouchDevice()) return;
          _this._axisProjections();
          _this._setTooltip();
          _this.entityLabels.classed("vzb-highlighted", false);
        })
        .each(function(segment, index) {
          var view = d3.select(this);
          view.append("circle");
          view.append("line");
        });

      trail.each(function(segment, index) {
        //update segment data (maybe for new indicators)
        var pointer = {};
        pointer[KEY] = d[KEY];
        pointer.time = segment.t;

        segment.valueY = _this.model.marker.axis_y.getValue(pointer);
        segment.valueX = _this.model.marker.axis_x.getValue(pointer);
        segment.valueS = _this.model.marker.size.getValue(pointer);
        segment.valueC = _this.model.marker.color.getValue(pointer);

        //update min max frame: needed to zoom in on the trail
        if(segment.valueX > maxmin.valueXmax || maxmin.valueXmax == null) maxmin.valueXmax = segment.valueX;
        if(segment.valueX < maxmin.valueXmin || maxmin.valueXmin == null) maxmin.valueXmin = segment.valueX;
        if(segment.valueY > maxmin.valueYmax || maxmin.valueYmax == null) maxmin.valueYmax = segment.valueY;
        if(segment.valueY < maxmin.valueYmin || maxmin.valueYmin == null) maxmin.valueYmin = segment.valueY;
        if(segment.valueS > maxmin.valueSmax || maxmin.valueSmax == null) maxmin.valueSmax = segment.valueS;
      });

    });
  },

  run: function(actions, selection, duration) {
    var _this = this.context;
    var KEY = _this.KEY;

    //quit if function is called accidentally
    if((!_this.model.time.trails || !_this.model.entities.select.length) && actions != "remove") return;
    if(!duration) duration = 0;

    actions = [].concat(actions);

    //work with entities.select (all selected entities), if no particular selection is specified
    selection = selection == null ? _this.model.entities.select : [selection];
    selection.forEach(function(d) {

      var trail = _this.entityTrails
        .filter(function(f) {
          return f[KEY] == "trail-" + d[KEY]
        })
        .selectAll("g")

      //do all the actions over "trail"
      actions.forEach(function(action) {
        _this._trails["_" + action](trail, duration, d);
      })

    });
  },

  _remove: function(trail, duration, d) {
    trail.remove();
  },

  _resize: function(trail, duration, d) {
    var _this = this.context;

    trail.each(function(segment, index) {

      var view = d3.select(this);
      view.select("circle")
        //.transition().duration(duration).ease("linear")
        .attr("cy", _this.yScale(segment.valueY))
        .attr("cx", _this.xScale(segment.valueX))
        .attr("r", utils.areaToRadius(_this.sScale(segment.valueS)));

      var next = this.parentNode.childNodes[(index + 1)];
      if(next == null) return;
      next = next.__data__;

      view.select("line")
        //.transition().duration(duration).ease("linear")
        .attr("x1", _this.xScale(next.valueX))
        .attr("y1", _this.yScale(next.valueY))
        .attr("x2", _this.xScale(segment.valueX))
        .attr("y2", _this.yScale(segment.valueY));
    });
  },

  _recolor: function(trail, duration, d) {
    var _this = this.context;

    trail.each(function(segment, index) {

      var view = d3.select(this);

      view.select("circle")
        //.transition().duration(duration).ease("linear")
        .style("fill", _this.cScale(segment.valueC));
      view.select("line")
        //.transition().duration(duration).ease("linear")
        .style("stroke", _this.cScale(segment.valueC));
    });
  },

  _findVisible: function(trail, duration, d) {
    var _this = this.context;
    var KEY = _this.KEY;

    var firstVisible = true;
    var trailStartTime = _this.timeFormatter.parse("" + d.trailStartTime);

    trail.each(function(segment, index) {

      // segment is transparent if it is after current time or before trail StartTime
      segment.transparent = (segment.t - _this.time >= 0) || (trailStartTime - segment.t > 0)
        //no trail segment should be visible if leading bubble is shifted backwards
        || (d.trailStartTime - _this.timeFormatter(_this.time) >= 0);

      if(firstVisible && !segment.transparent) {
        _this.cached[d[KEY]].labelX0 = segment.valueX;
        _this.cached[d[KEY]].labelY0 = segment.valueY;
        _this.cached[d[KEY]].scaledS0 = utils.areaToRadius(_this.sScale(segment.valueS));
        firstVisible = false;
      }
    });
  },

  _reveal: function(trail, duration, d) {
    var _this = this.context;
    var KEY = _this.KEY;

    trail.each(function(segment, index) {

      var view = d3.select(this);

      view.classed("vzb-invisible", segment.transparent);

      if(segment.transparent) return;

      var next = this.parentNode.childNodes[(index + 1)];
      if(next == null) return;
      next = next.__data__;

      if(segment.t - _this.time <= 0 && _this.time - next.t <= 0) {
        next = _this.cached[d[KEY]];

        view.select("line")
          .attr("x2", _this.xScale(segment.valueX))
          .attr("y2", _this.yScale(segment.valueY))
          .attr("x1", _this.xScale(segment.valueX))
          .attr("y1", _this.yScale(segment.valueY))
          //.transition().duration(duration).ease("linear")
          .attr("x1", _this.xScale(next.valueX))
          .attr("y1", _this.yScale(next.valueY));
      } else {
        view.select("line")
          .attr("x2", _this.xScale(segment.valueX))
          .attr("y2", _this.yScale(segment.valueY))
          .attr("x1", _this.xScale(next.valueX))
          .attr("y1", _this.yScale(next.valueY));
      }
    });

  },

});<commit_msg>Re/position the Hover trail label, which is under mouse #853<commit_after>import * as utils from 'base/utils';
import Class from 'base/class';

export default Class.extend({

  init: function(context) {
    this.context = context;
  },

  toggle: function(arg) {
    var _this = this.context;

    if(arg) {
      _this._trails.create();
      _this._trails.run(["resize", "recolor", "findVisible", "reveal"]);
    } else {
      _this._trails.run("remove");
      _this.model.entities.select.forEach(function(d) {
        d.trailStartTime = null;
      });
    }
  },

  create: function(selection) {
    var _this = this.context;
    var KEY = _this.KEY;

    //quit if the function is called accidentally
    if(!_this.model.time.trails || !_this.model.entities.select.length) return;

    var start = +_this.timeFormatter(_this.model.time.start);
    var end = +_this.timeFormatter(_this.model.time.end);
    var step = _this.model.time.step;
    var timePoints = [];
    for(var time = start; time <= end; time += step) timePoints.push(time);

    //work with entities.select (all selected entities), if no particular selection is specified
    selection = selection == null ? _this.model.entities.select : [selection];
    selection.forEach(function(d) {

      var trailSegmentData = timePoints.map(function(m) {
        return {
          t: _this.timeFormatter.parse("" + m)
        }
      });

      if(_this.cached[d[KEY]] == null) _this.cached[d[KEY]] = {};

      _this.cached[d[KEY]].maxMinValues = {
        valueXmax: null,
        valueXmin: null,
        valueYmax: null,
        valueYmin: null,
        valueSmax: null
      };

      var maxmin = _this.cached[d[KEY]].maxMinValues;

      var trail = _this.entityTrails
        .filter(function(f) {
          return f[KEY] == "trail-" + d[KEY]
        })
        .selectAll("g")
        .data(trailSegmentData);

      trail.exit().remove();

      trail.enter().append("g")
        .attr("class", "vzb-bc-trailsegment")
        .on("mousemove", function(segment, index) {
          if(utils.isTouchDevice()) return;
          var _key = d3.select(this.parentNode).data()[0][KEY];

          var pointer = {};
          pointer[KEY] = _key.replace("trail-", "");
          pointer.time = segment.t;

          _this._axisProjections(pointer);
          var x = _this.xScale(_this.model.marker.axis_x.getValue(pointer));
          var y = _this.yScale(_this.model.marker.axis_y.getValue(pointer));
          var s = utils.areaToRadius(_this.sScale(_this.model.marker.size.getValue(pointer)));
          _this._setTooltip(_this.timeFormatter(segment.t), x, y, s);
          _this.entityLabels
            .filter(function(f) {
              return f[KEY] == _key
            })
            .classed("vzb-highlighted", true);
        })
        .on("mouseout", function(segment, index) {
          if(utils.isTouchDevice()) return;
          _this._axisProjections();
          _this._setTooltip();
          _this.entityLabels.classed("vzb-highlighted", false);
        })
        .each(function(segment, index) {
          var view = d3.select(this);
          view.append("circle");
          view.append("line");
        });

      trail.each(function(segment, index) {
        //update segment data (maybe for new indicators)
        var pointer = {};
        pointer[KEY] = d[KEY];
        pointer.time = segment.t;

        segment.valueY = _this.model.marker.axis_y.getValue(pointer);
        segment.valueX = _this.model.marker.axis_x.getValue(pointer);
        segment.valueS = _this.model.marker.size.getValue(pointer);
        segment.valueC = _this.model.marker.color.getValue(pointer);

        //update min max frame: needed to zoom in on the trail
        if(segment.valueX > maxmin.valueXmax || maxmin.valueXmax == null) maxmin.valueXmax = segment.valueX;
        if(segment.valueX < maxmin.valueXmin || maxmin.valueXmin == null) maxmin.valueXmin = segment.valueX;
        if(segment.valueY > maxmin.valueYmax || maxmin.valueYmax == null) maxmin.valueYmax = segment.valueY;
        if(segment.valueY < maxmin.valueYmin || maxmin.valueYmin == null) maxmin.valueYmin = segment.valueY;
        if(segment.valueS > maxmin.valueSmax || maxmin.valueSmax == null) maxmin.valueSmax = segment.valueS;
      });

    });
  },

  run: function(actions, selection, duration) {
    var _this = this.context;
    var KEY = _this.KEY;

    //quit if function is called accidentally
    if((!_this.model.time.trails || !_this.model.entities.select.length) && actions != "remove") return;
    if(!duration) duration = 0;

    actions = [].concat(actions);

    //work with entities.select (all selected entities), if no particular selection is specified
    selection = selection == null ? _this.model.entities.select : [selection];
    selection.forEach(function(d) {

      var trail = _this.entityTrails
        .filter(function(f) {
          return f[KEY] == "trail-" + d[KEY]
        })
        .selectAll("g")

      //do all the actions over "trail"
      actions.forEach(function(action) {
        _this._trails["_" + action](trail, duration, d);
      })

    });
  },

  _remove: function(trail, duration, d) {
    trail.remove();
  },

  _resize: function(trail, duration, d) {
    var _this = this.context;

    trail.each(function(segment, index) {

      var view = d3.select(this);
      view.select("circle")
        //.transition().duration(duration).ease("linear")
        .attr("cy", _this.yScale(segment.valueY))
        .attr("cx", _this.xScale(segment.valueX))
        .attr("r", utils.areaToRadius(_this.sScale(segment.valueS)));

      var next = this.parentNode.childNodes[(index + 1)];
      if(next == null) return;
      next = next.__data__;

      view.select("line")
        //.transition().duration(duration).ease("linear")
        .attr("x1", _this.xScale(next.valueX))
        .attr("y1", _this.yScale(next.valueY))
        .attr("x2", _this.xScale(segment.valueX))
        .attr("y2", _this.yScale(segment.valueY));
    });
  },

  _recolor: function(trail, duration, d) {
    var _this = this.context;

    trail.each(function(segment, index) {

      var view = d3.select(this);

      view.select("circle")
        //.transition().duration(duration).ease("linear")
        .style("fill", _this.cScale(segment.valueC));
      view.select("line")
        //.transition().duration(duration).ease("linear")
        .style("stroke", _this.cScale(segment.valueC));
    });
  },

  _findVisible: function(trail, duration, d) {
    var _this = this.context;
    var KEY = _this.KEY;

    var firstVisible = true;
    var trailStartTime = _this.timeFormatter.parse("" + d.trailStartTime);

    trail.each(function(segment, index) {

      // segment is transparent if it is after current time or before trail StartTime
      segment.transparent = (segment.t - _this.time >= 0) || (trailStartTime - segment.t > 0)
        //no trail segment should be visible if leading bubble is shifted backwards
        || (d.trailStartTime - _this.timeFormatter(_this.time) >= 0);

      if(firstVisible && !segment.transparent) {
        _this.cached[d[KEY]].labelX0 = segment.valueX;
        _this.cached[d[KEY]].labelY0 = segment.valueY;
        _this.cached[d[KEY]].scaledS0 = utils.areaToRadius(_this.sScale(segment.valueS));
        firstVisible = false;
      }
    });
  },

  _reveal: function(trail, duration, d) {
    var _this = this.context;
    var KEY = _this.KEY;

    trail.each(function(segment, index) {

      var view = d3.select(this);

      view.classed("vzb-invisible", segment.transparent);

      if(segment.transparent) return;

      var next = this.parentNode.childNodes[(index + 1)];
      if(next == null) return;
      next = next.__data__;

      if(segment.t - _this.time <= 0 && _this.time - next.t <= 0) {
        next = _this.cached[d[KEY]];

        view.select("line")
          .attr("x2", _this.xScale(segment.valueX))
          .attr("y2", _this.yScale(segment.valueY))
          .attr("x1", _this.xScale(segment.valueX))
          .attr("y1", _this.yScale(segment.valueY))
          //.transition().duration(duration).ease("linear")
          .attr("x1", _this.xScale(next.valueX))
          .attr("y1", _this.yScale(next.valueY));
      } else {
        view.select("line")
          .attr("x2", _this.xScale(segment.valueX))
          .attr("y2", _this.yScale(segment.valueY))
          .attr("x1", _this.xScale(next.valueX))
          .attr("y1", _this.yScale(next.valueY));
      }
    });

  },

});<|endoftext|>


<commit_before>angular.module('gettext').directive('translate', function (gettextCatalog, $parse, $animate, $compile, $window) {
    // Trim polyfill for old browsers (instead of jQuery)
    // Based on AngularJS-v1.2.2 (angular.js#620)
    var trim = (function () {
        if (!String.prototype.trim) {
            return function (value) {
                return (typeof value === 'string') ? value.replace(/^\s*/, '').replace(/\s*$/, '') : value;
            };
        }
        return function (value) {
            return (typeof value === 'string') ? value.trim() : value;
        };
    })();

    function assert(condition, missing, found) {
        if (!condition) {
            throw new Error('You should add a ' + missing + ' attribute whenever you add a ' + found + ' attribute.');
        }
    }

    var msie = parseInt((/msie (\d+)/.exec(angular.lowercase($window.navigator.userAgent)) || [])[1], 10);

    return {
        restrict: 'AE',
        terminal: true,
        compile: function compile(element, attrs) {
            // Validate attributes
            assert(!attrs.translatePlural || attrs.translateN, 'translate-n', 'translate-plural');
            assert(!attrs.translateN || attrs.translatePlural, 'translate-plural', 'translate-n');

            var msgid = trim(element.html());
            var translatePlural = attrs.translatePlural;
            var translateContext = attrs.translateContext;

            if (msie <= 8) {
                // Workaround fix relating to angular adding a comment node to
                // anchors. angular/angular.js/#1949 / angular/angular.js/#2013
                if (msgid.slice(-13) === '') {
                    msgid = msgid.slice(0, -13);
                }
            }

            return {
                post: function (scope, element, attrs) {
                    var countFn = $parse(attrs.translateN);
                    var pluralScope = null;
                    var linking = true;

                    function update() {
                        // Fetch correct translated string.
                        var translated;
                        if (translatePlural) {
                            scope = pluralScope || (pluralScope = scope.$new());
                            scope.$count = countFn(scope);
                            translated = gettextCatalog.getPlural(scope.$count, msgid, translatePlural, null, translateContext);
                        } else {
                            translated = gettextCatalog.getString(msgid,  null, translateContext);
                        }

                        var oldContents = element.contents();

                        // Avoid redundant swaps
                        if (translated === oldContents.html()){
                            // Take care of unlinked content
                            if (linking){
                                $compile(oldContents)(scope);
                            }
                            return;
                        }

                        // Swap in the translation
                        var newWrapper = angular.element('' + translated + '');
                        $compile(newWrapper.contents())(scope);
                        var newContents = newWrapper.contents();

                        $animate.enter(newContents, element);
                        $animate.leave(oldContents);
                    }

                    if (attrs.translateN) {
                        scope.$watch(attrs.translateN, update);
                    }

                    scope.$on('gettextLanguageChanged', update);

                    update();
                    linking = false;
                }
            };
        }
    };
});
<commit_msg>Trim strings before compare<commit_after>angular.module('gettext').directive('translate', function (gettextCatalog, $parse, $animate, $compile, $window) {
    // Trim polyfill for old browsers (instead of jQuery)
    // Based on AngularJS-v1.2.2 (angular.js#620)
    var trim = (function () {
        if (!String.prototype.trim) {
            return function (value) {
                return (typeof value === 'string') ? value.replace(/^\s*/, '').replace(/\s*$/, '') : value;
            };
        }
        return function (value) {
            return (typeof value === 'string') ? value.trim() : value;
        };
    })();

    function assert(condition, missing, found) {
        if (!condition) {
            throw new Error('You should add a ' + missing + ' attribute whenever you add a ' + found + ' attribute.');
        }
    }

    var msie = parseInt((/msie (\d+)/.exec(angular.lowercase($window.navigator.userAgent)) || [])[1], 10);

    return {
        restrict: 'AE',
        terminal: true,
        compile: function compile(element, attrs) {
            // Validate attributes
            assert(!attrs.translatePlural || attrs.translateN, 'translate-n', 'translate-plural');
            assert(!attrs.translateN || attrs.translatePlural, 'translate-plural', 'translate-n');

            var msgid = trim(element.html());
            var translatePlural = attrs.translatePlural;
            var translateContext = attrs.translateContext;

            if (msie <= 8) {
                // Workaround fix relating to angular adding a comment node to
                // anchors. angular/angular.js/#1949 / angular/angular.js/#2013
                if (msgid.slice(-13) === '') {
                    msgid = msgid.slice(0, -13);
                }
            }

            return {
                post: function (scope, element, attrs) {
                    var countFn = $parse(attrs.translateN);
                    var pluralScope = null;
                    var linking = true;

                    function update() {
                        // Fetch correct translated string.
                        var translated;
                        if (translatePlural) {
                            scope = pluralScope || (pluralScope = scope.$new());
                            scope.$count = countFn(scope);
                            translated = gettextCatalog.getPlural(scope.$count, msgid, translatePlural, null, translateContext);
                        } else {
                            translated = gettextCatalog.getString(msgid,  null, translateContext);
                        }

                        var oldContents = element.contents();

                        // Avoid redundant swaps
                        if (translated === trim(oldContents.html())){
                            // Take care of unlinked content
                            if (linking){
                                $compile(oldContents)(scope);
                            }
                            return;
                        }

                        // Swap in the translation
                        var newWrapper = angular.element('' + translated + '');
                        $compile(newWrapper.contents())(scope);
                        var newContents = newWrapper.contents();

                        $animate.enter(newContents, element);
                        $animate.leave(oldContents);
                    }

                    if (attrs.translateN) {
                        scope.$watch(attrs.translateN, update);
                    }

                    scope.$on('gettextLanguageChanged', update);

                    update();
                    linking = false;
                }
            };
        }
    };
});
<|endoftext|>


<commit_before>const childProcess = require('child_process')
const fs = require('fs')
const path = require('path')
const electronLink = require('electron-link')
const CONFIG = require('../config')
const vm = require('vm')

module.exports = function (packagedAppPath) {
  const snapshotScriptPath = path.join(CONFIG.buildOutputPath, 'startup.js')
  const coreModules = new Set(['electron', 'atom', 'shell', 'WNdb', 'lapack', 'remote'])
  const baseDirPath = path.join(CONFIG.intermediateAppPath, 'static')
  let processedFiles = 0

  return electronLink({
    baseDirPath,
    mainPath: path.resolve(baseDirPath, '..', 'src', 'initialize-application-window.js'),
    cachePath: path.join(CONFIG.atomHomeDirPath, 'snapshot-cache'),
    auxiliaryData: CONFIG.snapshotAuxiliaryData,
    shouldExcludeModule: (modulePath) => {
      if (processedFiles > 0) {
        process.stdout.write('\r')
      }
      process.stdout.write(`Generating snapshot script at "${snapshotScriptPath}" (${++processedFiles})`)

      const relativePath = path.relative(baseDirPath, modulePath)
      return (
        modulePath.endsWith('.node') ||
        coreModules.has(modulePath) ||
        (relativePath.startsWith(path.join('..', 'src')) && relativePath.endsWith('-element.js')) ||
        relativePath.startsWith(path.join('..', 'node_modules', 'dugite')) ||
        relativePath === path.join('..', 'exports', 'atom.js') ||
        relativePath === path.join('..', 'src', 'electron-shims.js') ||
        relativePath === path.join('..', 'src', 'safe-clipboard.js') ||
        relativePath === path.join('..', 'node_modules', 'atom-keymap', 'lib', 'command-event.js') ||
        relativePath === path.join('..', 'node_modules', 'babel-core', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'cached-run-in-this-context', 'lib', 'main.js') ||
        relativePath === path.join('..', 'node_modules', 'coffee-script', 'lib', 'coffee-script', 'register.js') ||
        relativePath === path.join('..', 'node_modules', 'cson-parser', 'node_modules', 'coffee-script', 'lib', 'coffee-script', 'register.js') ||
        relativePath === path.join('..', 'node_modules', 'decompress-zip', 'lib', 'decompress-zip.js') ||
        relativePath === path.join('..', 'node_modules', 'debug', 'node.js') ||
        relativePath === path.join('..', 'node_modules', 'fs-extra', 'lib', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'github', 'node_modules', 'fs-extra', 'lib', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'git-utils', 'lib', 'git.js') ||
        relativePath === path.join('..', 'node_modules', 'glob', 'glob.js') ||
        relativePath === path.join('..', 'node_modules', 'graceful-fs', 'graceful-fs.js') ||
        relativePath === path.join('..', 'node_modules', 'htmlparser2', 'lib', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'markdown-preview', 'node_modules', 'htmlparser2', 'lib', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'roaster', 'node_modules', 'htmlparser2', 'lib', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'task-lists', 'node_modules', 'htmlparser2', 'lib', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'iconv-lite', 'lib', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'less', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'less', 'lib', 'less', 'fs.js') ||
        relativePath === path.join('..', 'node_modules', 'less', 'lib', 'less-node', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'less', 'node_modules', 'graceful-fs', 'graceful-fs.js') ||
        relativePath === path.join('..', 'node_modules', 'minimatch', 'minimatch.js') ||
        relativePath === path.join('..', 'node_modules', 'node-fetch', 'lib', 'fetch-error.js') ||
        relativePath === path.join('..', 'node_modules', 'nsfw', 'node_modules', 'fs-extra', 'lib', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'superstring', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'oniguruma', 'src', 'oniguruma.js') ||
        relativePath === path.join('..', 'node_modules', 'request', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'resolve', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'resolve', 'lib', 'core.js') ||
        relativePath === path.join('..', 'node_modules', 'scandal', 'node_modules', 'minimatch', 'minimatch.js') ||
        relativePath === path.join('..', 'node_modules', 'settings-view', 'node_modules', 'glob', 'glob.js') ||
        relativePath === path.join('..', 'node_modules', 'settings-view', 'node_modules', 'minimatch', 'minimatch.js') ||
        relativePath === path.join('..', 'node_modules', 'spellchecker', 'lib', 'spellchecker.js') ||
        relativePath === path.join('..', 'node_modules', 'spelling-manager', 'node_modules', 'natural', 'lib', 'natural', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'tar', 'tar.js') ||
        relativePath === path.join('..', 'node_modules', 'temp', 'lib', 'temp.js') ||
        relativePath === path.join('..', 'node_modules', 'tmp', 'lib', 'tmp.js') ||
        relativePath === path.join('..', 'node_modules', 'tree-view', 'node_modules', 'minimatch', 'minimatch.js')
      )
    }
  }).then((snapshotScript) => {
    fs.writeFileSync(snapshotScriptPath, snapshotScript)
    process.stdout.write('\n')

    console.log('Verifying if snapshot can be executed via `mksnapshot`')
    const verifySnapshotScriptPath = path.join(CONFIG.repositoryRootPath, 'script', 'verify-snapshot-script')
    let nodeBundledInElectronPath
    if (process.platform === 'darwin') {
      nodeBundledInElectronPath = path.join(packagedAppPath, 'Contents', 'MacOS', 'Atom')
    } else if (process.platform === 'win32') {
      nodeBundledInElectronPath = path.join(packagedAppPath, 'atom.exe')
    } else {
      nodeBundledInElectronPath = path.join(packagedAppPath, 'atom')
    }
    childProcess.execFileSync(
      nodeBundledInElectronPath,
      [verifySnapshotScriptPath, snapshotScriptPath],
      {env: Object.assign({}, process.env, {ELECTRON_RUN_AS_NODE: 1})}
    )

    const generatedStartupBlobPath = path.join(CONFIG.buildOutputPath, 'snapshot_blob.bin')
    console.log(`Generating startup blob at "${generatedStartupBlobPath}"`)
    childProcess.execFileSync(
      path.join(CONFIG.repositoryRootPath, 'script', 'node_modules', 'electron-mksnapshot', 'bin', 'mksnapshot'),
      [snapshotScriptPath, '--startup_blob', generatedStartupBlobPath]
    )

    let startupBlobDestinationPath
    if (process.platform === 'darwin') {
      startupBlobDestinationPath = `${packagedAppPath}/Contents/Frameworks/Electron Framework.framework/Resources/snapshot_blob.bin`
    } else {
      startupBlobDestinationPath = path.join(packagedAppPath, 'snapshot_blob.bin')
    }

    console.log(`Moving generated startup blob into "${startupBlobDestinationPath}"`)
    fs.unlinkSync(startupBlobDestinationPath)
    fs.renameSync(generatedStartupBlobPath, startupBlobDestinationPath)
  })
}
<commit_msg>:fire: Delete unused require<commit_after>const childProcess = require('child_process')
const fs = require('fs')
const path = require('path')
const electronLink = require('electron-link')
const CONFIG = require('../config')

module.exports = function (packagedAppPath) {
  const snapshotScriptPath = path.join(CONFIG.buildOutputPath, 'startup.js')
  const coreModules = new Set(['electron', 'atom', 'shell', 'WNdb', 'lapack', 'remote'])
  const baseDirPath = path.join(CONFIG.intermediateAppPath, 'static')
  let processedFiles = 0

  return electronLink({
    baseDirPath,
    mainPath: path.resolve(baseDirPath, '..', 'src', 'initialize-application-window.js'),
    cachePath: path.join(CONFIG.atomHomeDirPath, 'snapshot-cache'),
    auxiliaryData: CONFIG.snapshotAuxiliaryData,
    shouldExcludeModule: (modulePath) => {
      if (processedFiles > 0) {
        process.stdout.write('\r')
      }
      process.stdout.write(`Generating snapshot script at "${snapshotScriptPath}" (${++processedFiles})`)

      const relativePath = path.relative(baseDirPath, modulePath)
      return (
        modulePath.endsWith('.node') ||
        coreModules.has(modulePath) ||
        (relativePath.startsWith(path.join('..', 'src')) && relativePath.endsWith('-element.js')) ||
        relativePath.startsWith(path.join('..', 'node_modules', 'dugite')) ||
        relativePath === path.join('..', 'exports', 'atom.js') ||
        relativePath === path.join('..', 'src', 'electron-shims.js') ||
        relativePath === path.join('..', 'src', 'safe-clipboard.js') ||
        relativePath === path.join('..', 'node_modules', 'atom-keymap', 'lib', 'command-event.js') ||
        relativePath === path.join('..', 'node_modules', 'babel-core', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'cached-run-in-this-context', 'lib', 'main.js') ||
        relativePath === path.join('..', 'node_modules', 'coffee-script', 'lib', 'coffee-script', 'register.js') ||
        relativePath === path.join('..', 'node_modules', 'cson-parser', 'node_modules', 'coffee-script', 'lib', 'coffee-script', 'register.js') ||
        relativePath === path.join('..', 'node_modules', 'decompress-zip', 'lib', 'decompress-zip.js') ||
        relativePath === path.join('..', 'node_modules', 'debug', 'node.js') ||
        relativePath === path.join('..', 'node_modules', 'fs-extra', 'lib', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'github', 'node_modules', 'fs-extra', 'lib', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'git-utils', 'lib', 'git.js') ||
        relativePath === path.join('..', 'node_modules', 'glob', 'glob.js') ||
        relativePath === path.join('..', 'node_modules', 'graceful-fs', 'graceful-fs.js') ||
        relativePath === path.join('..', 'node_modules', 'htmlparser2', 'lib', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'markdown-preview', 'node_modules', 'htmlparser2', 'lib', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'roaster', 'node_modules', 'htmlparser2', 'lib', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'task-lists', 'node_modules', 'htmlparser2', 'lib', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'iconv-lite', 'lib', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'less', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'less', 'lib', 'less', 'fs.js') ||
        relativePath === path.join('..', 'node_modules', 'less', 'lib', 'less-node', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'less', 'node_modules', 'graceful-fs', 'graceful-fs.js') ||
        relativePath === path.join('..', 'node_modules', 'minimatch', 'minimatch.js') ||
        relativePath === path.join('..', 'node_modules', 'node-fetch', 'lib', 'fetch-error.js') ||
        relativePath === path.join('..', 'node_modules', 'nsfw', 'node_modules', 'fs-extra', 'lib', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'superstring', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'oniguruma', 'src', 'oniguruma.js') ||
        relativePath === path.join('..', 'node_modules', 'request', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'resolve', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'resolve', 'lib', 'core.js') ||
        relativePath === path.join('..', 'node_modules', 'scandal', 'node_modules', 'minimatch', 'minimatch.js') ||
        relativePath === path.join('..', 'node_modules', 'settings-view', 'node_modules', 'glob', 'glob.js') ||
        relativePath === path.join('..', 'node_modules', 'settings-view', 'node_modules', 'minimatch', 'minimatch.js') ||
        relativePath === path.join('..', 'node_modules', 'spellchecker', 'lib', 'spellchecker.js') ||
        relativePath === path.join('..', 'node_modules', 'spelling-manager', 'node_modules', 'natural', 'lib', 'natural', 'index.js') ||
        relativePath === path.join('..', 'node_modules', 'tar', 'tar.js') ||
        relativePath === path.join('..', 'node_modules', 'temp', 'lib', 'temp.js') ||
        relativePath === path.join('..', 'node_modules', 'tmp', 'lib', 'tmp.js') ||
        relativePath === path.join('..', 'node_modules', 'tree-view', 'node_modules', 'minimatch', 'minimatch.js')
      )
    }
  }).then((snapshotScript) => {
    fs.writeFileSync(snapshotScriptPath, snapshotScript)
    process.stdout.write('\n')

    console.log('Verifying if snapshot can be executed via `mksnapshot`')
    const verifySnapshotScriptPath = path.join(CONFIG.repositoryRootPath, 'script', 'verify-snapshot-script')
    let nodeBundledInElectronPath
    if (process.platform === 'darwin') {
      nodeBundledInElectronPath = path.join(packagedAppPath, 'Contents', 'MacOS', 'Atom')
    } else if (process.platform === 'win32') {
      nodeBundledInElectronPath = path.join(packagedAppPath, 'atom.exe')
    } else {
      nodeBundledInElectronPath = path.join(packagedAppPath, 'atom')
    }
    childProcess.execFileSync(
      nodeBundledInElectronPath,
      [verifySnapshotScriptPath, snapshotScriptPath],
      {env: Object.assign({}, process.env, {ELECTRON_RUN_AS_NODE: 1})}
    )

    const generatedStartupBlobPath = path.join(CONFIG.buildOutputPath, 'snapshot_blob.bin')
    console.log(`Generating startup blob at "${generatedStartupBlobPath}"`)
    childProcess.execFileSync(
      path.join(CONFIG.repositoryRootPath, 'script', 'node_modules', 'electron-mksnapshot', 'bin', 'mksnapshot'),
      [snapshotScriptPath, '--startup_blob', generatedStartupBlobPath]
    )

    let startupBlobDestinationPath
    if (process.platform === 'darwin') {
      startupBlobDestinationPath = `${packagedAppPath}/Contents/Frameworks/Electron Framework.framework/Resources/snapshot_blob.bin`
    } else {
      startupBlobDestinationPath = path.join(packagedAppPath, 'snapshot_blob.bin')
    }

    console.log(`Moving generated startup blob into "${startupBlobDestinationPath}"`)
    fs.unlinkSync(startupBlobDestinationPath)
    fs.renameSync(generatedStartupBlobPath, startupBlobDestinationPath)
  })
}
<|endoftext|>


<commit_before>const { exec: execCP } = require('child_process');
const { promisify } = require('util');
const { readFile: readFileFS } = require('fs');
const semver = require('semver');
const commandLineArgs = require('command-line-args');
const commandLineUsage = require('command-line-usage');

const exec = promisify(execCP);
const readFile = promisify(readFileFS);

const optionDefinitions = [
  {
    name: 'help',
    description: 'Show this help',
    type: Boolean,
    alias: 'h',
  },
  {
    name: 'debug',
    description: 'Enable debug information',
    type: Boolean,
    alias: 'd',
    defaultValue: false,
  },
  {
    name: 'no-include-dev',
    description: "Don't include development packages when checking whether a "
      + 'peerDependency has been satisfied',
    defaultValue: false,
  },
  {
    name: 'include-resolutions',
    description: 'Check for resolutions section of package.json when checking whether a peerDependency has been satisfied',
    defaultValue: false,
  },
  {
    name: 'max-retries',
    description: 'Specify how many retries are allowed for [underline]{npm} commands',
    type: Number,
    typeLabel: '[underline]{retries}',
    defaultValue: 2,
  },
  {
    name: 'directory',
    description: 'The directory to check peerDependencies within. Defaults '
      + 'to the current directory.',
    type: String,
    typeLabel: '[underline]{directory}',
    defaultValue: process.cwd(),
  },
];

const usageSections = [
  {
    header: 'check-peer-deps',
    content: 'Verifies that the peerDependency requirements of all top level '
      + 'dependencies are satisfied.',
  },
  {
    header: 'Options',
    optionList: optionDefinitions,
  },
];

let options;

// Internal vars
const deps = new Map();
const npmVers = new Map();
const peerDeps = new Map();
const resolutions = new Map();

const log = (value) => {
  if (options.debug) {
    console.log(value);
  }
};

const addDeps = (dependencies) => {
  if (!dependencies) {
    return;
  }
  Object.entries(dependencies).forEach((entry) => {
    const [name, range] = entry;
    deps.set(name, range);
  });
};

const addResolutions = (res) => {
  if (!res) {
    return;
  }
  Object.entries(res).forEach((entry) => {
    const [name, range] = entry;
    resolutions.set(name, range);
  });
};

const readPackageConfig = async (path) => {
  let packageConfig = {};
  try {
    const contents = await readFile(path, { encoding: 'utf8' });
    packageConfig = JSON.parse(contents);
  } catch (e) {
    console.error(e.message);
  }
  return packageConfig;
};

const npmView = async (name, keys) => {
  const opts = ['view', '--json', name].concat(keys);
  const command = ['npm'].concat(opts).join(' ');
  log(`Running '${command}'`);
  let remainingTries = options['max-retries'];
  let output;
  do {
    try {
      // eslint-disable-next-line no-await-in-loop
      ({ stdout: output } = await exec(command));
    } catch (e) {
      log(`'${command}' failed with error ${e}, retrying...`);
      // Do nothing when it fails...
    }
    remainingTries -= 1;
  } while (remainingTries > 0 && !output);
  if (!output) {
    console.error(`To many retries of '${command}' without success, exiting!`);
    process.exit(1);
  }
  return JSON.parse(output);
};

const gatherNpmVer = async (range, name) => {
  log(`Getting versions for ${name}@${range}...`);
  const versions = await npmView(name, 'versions');
  const ranges = {
    versions,
    minimum: semver.minSatisfying(versions, range),
    maximum: semver.maxSatisfying(versions, range),
  };
  log(`${name}@${range}: '${ranges.minimum}' to '${ranges.maximum}'`);
  npmVers.set(name, ranges);
};

const getNpmVersions = async () => {
  // Gather the unique package names
  const toCheck = new Set();
  peerDeps.forEach((peerDependencies) => {
    peerDependencies.forEach((range, name) => {
      toCheck.add(name);
    });
  });

  // Grab the versions from NPM
  return Promise.all(Array.from(toCheck.values()).map(async (name) => {
    if (deps.has(name) && !npmVers.has(name)) {
      await gatherNpmVer(deps.get(name), name);
    }
  }));
};

const addPeerDeps = (name, peerDependencies) => {
  if (!peerDeps.has(name)) {
    peerDeps.set(name, new Map());
  }
  const currDeps = peerDeps.get(name);
  Object.entries(peerDependencies).forEach((entry) => {
    const [depName, depRange] = entry;
    log(`${name} peerDependency: ${depName}@${depRange}`);
    currDeps.set(depName, depRange);
  });
};

// Get the peerDependencies
const getNpmPeerDep = async (range, name) => {
  log(`Getting NPM peerDependencies for ${name}`);
  const npmPeerDeps = await npmView(name, 'peerDependencies');
  addPeerDeps(name, npmPeerDeps);
};

const getPeerDep = async (range, name) => {
  log(`Getting peerDependencies for ${name}`);
  // Hacktown, USA.
  const packagePath = `${options.directory}/node_modules/${name}/package.json`;
  const packageInfo = await readPackageConfig(packagePath);
  if (!packageInfo.peerDependencies) {
    return;
  }

  if (!npmVers.has(name)) {
    await gatherNpmVer(range, name);
  }
  if (semver.lt(packageInfo.version, npmVers.get(name).maximum)) {
    // The installed version isn't the highest allowed, check the latest from NPM
    log(`${name}: Installed version lower than allowed version. Using NPM to determine peerDependencies.`);
    await getNpmPeerDep(range, name);
  } else {
    log(`${name}: Using local package.json's to determine peerDependencies.`);
    addPeerDeps(name, packageInfo.peerDependencies);
  }
};

const getPeerDeps = async () => {
  const promises = [];
  deps.forEach((range, name) => {
    promises.push(getPeerDep(range, name));
  });
  return Promise.all(promises);
};

// peerDependencies checks
const checkPeerDependencies = async (peerDependencies, name) => {
  Promise.all(Array.from(peerDependencies.entries()).map(async (entry) => {
    const [peerDepName, peerDepRange] = entry;
    log(`Checking ${name}'s peerDependency of '${peerDepName}@${peerDepRange}'`);
    let found = false;
    if (deps.has(peerDepName)) {
      // Verify that the minimum allowed version still satisfies the peerDep
      const minAllowedVer = npmVers.get(peerDepName).minimum;
      if (semver.satisfies(minAllowedVer, peerDepRange)) {
        found = true;
      }
    }

    if (resolutions.has(`${name}/${peerDepName}`)) {
      const minAllowedVer = resolutions.get(`${name}/${peerDepName}`);
      if (semver.satisfies(minAllowedVer, peerDepRange)) {
        found = true;
      }
    }

    if (!found) {
      console.error(`A dependency satisfying ${name}'s peerDependency of '${peerDepName}@${peerDepRange}' was not found!`);

      if (deps.has(peerDepName)) {
        console.log(`Current: ${peerDepName}@${deps.get(peerDepName)}`);
        const { versions } = npmVers.get(peerDepName);
        const maxUsable = semver.maxSatisfying(versions, peerDepRange);
        console.log(`Package dependencies can satisfy the peerDependency? ${maxUsable ? 'Yes' : 'No'}`);
      }
    }
  }));
};

const checkAllPeerDeps = async () => {
  const promises = [];
  peerDeps.forEach((peerDependencies, name) => {
    promises.push(checkPeerDependencies(peerDependencies, name));
  });
  return Promise.all(promises);
};

const findDependencies = async () => {
  const packageConfig = await readPackageConfig(`${options.directory}/package.json`);

  // Get the dependencies to process
  addDeps(packageConfig.dependencies);

  if (options['include-resolutions'] && packageConfig.resolutions) {
    addResolutions(packageConfig.resolutions);
  }

  if (!options['no-include-dev'] && packageConfig.devDependencies) {
    addDeps(packageConfig.devDependencies);
  }
};

// Main function
async function checkPeerDeps() {
  let shouldExit = false;
  options = commandLineArgs(optionDefinitions);

  if (options.help) {
    console.log(commandLineUsage(usageSections));
    shouldExit = true;
  }

  if (!shouldExit) {
    await findDependencies();

    if (deps.size < 1) {
      console.error('No dependencies in the current package!');
      shouldExit = true;
    }
  }

  if (!shouldExit) {
    log('Dependencies:');
    deps.forEach((range, name) => { log(`${name}: ${range}`); });

    log('');

    log('Determining peerDependencies...');
    await getPeerDeps();
    log('Done.');

    log('');

    // Get the NPM versions required to check the peerDependencies
    log('Determining peerDependency version ranges from NPM...');
    await getNpmVersions();
    log('Done.');

    log('');

    log('Checking versions...');
    await checkAllPeerDeps();
    log('Done.');
  }
}

module.exports = checkPeerDeps;
<commit_msg>fix: checkPeerDependencies isn't actually async<commit_after>const { exec: execCP } = require('child_process');
const { promisify } = require('util');
const { readFile: readFileFS } = require('fs');
const semver = require('semver');
const commandLineArgs = require('command-line-args');
const commandLineUsage = require('command-line-usage');

const exec = promisify(execCP);
const readFile = promisify(readFileFS);

const optionDefinitions = [
  {
    name: 'help',
    description: 'Show this help',
    type: Boolean,
    alias: 'h',
  },
  {
    name: 'debug',
    description: 'Enable debug information',
    type: Boolean,
    alias: 'd',
    defaultValue: false,
  },
  {
    name: 'no-include-dev',
    description: "Don't include development packages when checking whether a "
      + 'peerDependency has been satisfied',
    defaultValue: false,
  },
  {
    name: 'include-resolutions',
    description: 'Check for resolutions section of package.json when checking whether a peerDependency has been satisfied',
    defaultValue: false,
  },
  {
    name: 'max-retries',
    description: 'Specify how many retries are allowed for [underline]{npm} commands',
    type: Number,
    typeLabel: '[underline]{retries}',
    defaultValue: 2,
  },
  {
    name: 'directory',
    description: 'The directory to check peerDependencies within. Defaults '
      + 'to the current directory.',
    type: String,
    typeLabel: '[underline]{directory}',
    defaultValue: process.cwd(),
  },
];

const usageSections = [
  {
    header: 'check-peer-deps',
    content: 'Verifies that the peerDependency requirements of all top level '
      + 'dependencies are satisfied.',
  },
  {
    header: 'Options',
    optionList: optionDefinitions,
  },
];

let options;

// Internal vars
const deps = new Map();
const npmVers = new Map();
const peerDeps = new Map();
const resolutions = new Map();

const log = (value) => {
  if (options.debug) {
    console.log(value);
  }
};

const addDeps = (dependencies) => {
  if (!dependencies) {
    return;
  }
  Object.entries(dependencies).forEach((entry) => {
    const [name, range] = entry;
    deps.set(name, range);
  });
};

const addResolutions = (res) => {
  if (!res) {
    return;
  }
  Object.entries(res).forEach((entry) => {
    const [name, range] = entry;
    resolutions.set(name, range);
  });
};

const readPackageConfig = async (path) => {
  let packageConfig = {};
  try {
    const contents = await readFile(path, { encoding: 'utf8' });
    packageConfig = JSON.parse(contents);
  } catch (e) {
    console.error(e.message);
  }
  return packageConfig;
};

const npmView = async (name, keys) => {
  const opts = ['view', '--json', name].concat(keys);
  const command = ['npm'].concat(opts).join(' ');
  log(`Running '${command}'`);
  let remainingTries = options['max-retries'];
  let output;
  do {
    try {
      // eslint-disable-next-line no-await-in-loop
      ({ stdout: output } = await exec(command));
    } catch (e) {
      log(`'${command}' failed with error ${e}, retrying...`);
      // Do nothing when it fails...
    }
    remainingTries -= 1;
  } while (remainingTries > 0 && !output);
  if (!output) {
    console.error(`To many retries of '${command}' without success, exiting!`);
    process.exit(1);
  }
  return JSON.parse(output);
};

const gatherNpmVer = async (range, name) => {
  log(`Getting versions for ${name}@${range}...`);
  const versions = await npmView(name, 'versions');
  const ranges = {
    versions,
    minimum: semver.minSatisfying(versions, range),
    maximum: semver.maxSatisfying(versions, range),
  };
  log(`${name}@${range}: '${ranges.minimum}' to '${ranges.maximum}'`);
  npmVers.set(name, ranges);
};

const getNpmVersions = async () => {
  // Gather the unique package names
  const toCheck = new Set();
  peerDeps.forEach((peerDependencies) => {
    peerDependencies.forEach((range, name) => {
      toCheck.add(name);
    });
  });

  // Grab the versions from NPM
  return Promise.all(Array.from(toCheck.values()).map(async (name) => {
    if (deps.has(name) && !npmVers.has(name)) {
      await gatherNpmVer(deps.get(name), name);
    }
  }));
};

const addPeerDeps = (name, peerDependencies) => {
  if (!peerDeps.has(name)) {
    peerDeps.set(name, new Map());
  }
  const currDeps = peerDeps.get(name);
  Object.entries(peerDependencies).forEach((entry) => {
    const [depName, depRange] = entry;
    log(`${name} peerDependency: ${depName}@${depRange}`);
    currDeps.set(depName, depRange);
  });
};

// Get the peerDependencies
const getNpmPeerDep = async (range, name) => {
  log(`Getting NPM peerDependencies for ${name}`);
  const npmPeerDeps = await npmView(name, 'peerDependencies');
  addPeerDeps(name, npmPeerDeps);
};

const getPeerDep = async (range, name) => {
  log(`Getting peerDependencies for ${name}`);
  // Hacktown, USA.
  const packagePath = `${options.directory}/node_modules/${name}/package.json`;
  const packageInfo = await readPackageConfig(packagePath);
  if (!packageInfo.peerDependencies) {
    return;
  }

  if (!npmVers.has(name)) {
    await gatherNpmVer(range, name);
  }
  if (semver.lt(packageInfo.version, npmVers.get(name).maximum)) {
    // The installed version isn't the highest allowed, check the latest from NPM
    log(`${name}: Installed version lower than allowed version. Using NPM to determine peerDependencies.`);
    await getNpmPeerDep(range, name);
  } else {
    log(`${name}: Using local package.json's to determine peerDependencies.`);
    addPeerDeps(name, packageInfo.peerDependencies);
  }
};

const getPeerDeps = async () => {
  const promises = [];
  deps.forEach((range, name) => {
    promises.push(getPeerDep(range, name));
  });
  return Promise.all(promises);
};

// peerDependencies checks
const checkPeerDependencies = (peerDependencies, name) => {
  peerDependencies.forEach((peerDepRange, peerDepName) => {
    log(`Checking ${name}'s peerDependency of '${peerDepName}@${peerDepRange}'`);
    let found = false;
    if (deps.has(peerDepName)) {
      // Verify that the minimum allowed version still satisfies the peerDep
      const minAllowedVer = npmVers.get(peerDepName).minimum;
      if (semver.satisfies(minAllowedVer, peerDepRange)) {
        found = true;
      }
    }

    if (resolutions.has(`${name}/${peerDepName}`)) {
      const minAllowedVer = resolutions.get(`${name}/${peerDepName}`);
      if (semver.satisfies(minAllowedVer, peerDepRange)) {
        found = true;
      }
    }

    if (!found) {
      console.error(`A dependency satisfying ${name}'s peerDependency of '${peerDepName}@${peerDepRange}' was not found!`);

      if (deps.has(peerDepName)) {
        console.log(`Current: ${peerDepName}@${deps.get(peerDepName)}`);
        const { versions } = npmVers.get(peerDepName);
        const maxUsable = semver.maxSatisfying(versions, peerDepRange);
        console.log(`Package dependencies can satisfy the peerDependency? ${maxUsable ? 'Yes' : 'No'}`);
      }
    }
  });
};

const checkAllPeerDeps = () => {
  peerDeps.forEach(checkPeerDependencies);
};

const findDependencies = async () => {
  const packageConfig = await readPackageConfig(`${options.directory}/package.json`);

  // Get the dependencies to process
  addDeps(packageConfig.dependencies);

  if (options['include-resolutions'] && packageConfig.resolutions) {
    addResolutions(packageConfig.resolutions);
  }

  if (!options['no-include-dev'] && packageConfig.devDependencies) {
    addDeps(packageConfig.devDependencies);
  }
};

// Main function
async function checkPeerDeps() {
  let shouldExit = false;
  options = commandLineArgs(optionDefinitions);

  if (options.help) {
    console.log(commandLineUsage(usageSections));
    shouldExit = true;
  }

  if (!shouldExit) {
    await findDependencies();

    if (deps.size < 1) {
      console.error('No dependencies in the current package!');
      shouldExit = true;
    }
  }

  if (!shouldExit) {
    log('Dependencies:');
    deps.forEach((range, name) => { log(`${name}: ${range}`); });

    log('');

    log('Determining peerDependencies...');
    await getPeerDeps();
    log('Done.');

    log('');

    // Get the NPM versions required to check the peerDependencies
    log('Determining peerDependency version ranges from NPM...');
    await getNpmVersions();
    log('Done.');

    log('');

    log('Checking versions...');
    checkAllPeerDeps();
    log('Done.');
  }
}

module.exports = checkPeerDeps;
<|endoftext|>


<commit_before>import path from 'path';
import fs from 'fs';
import assert from 'assert';
import { transformFileSync } from 'babel-core';
import plugin from '../src';

function trim(str) {
  return str.replace(/^\s+|\s+$/, '');
}

describe('Add propType doc to react classes', () => {
  const fixturesDir = path.join(__dirname, 'fixtures');
  fs.readdirSync(fixturesDir).map((caseName) => {
    it(`should ${caseName.split('-').join(' ')}`, () => {
      const fixtureDir = path.join(fixturesDir, caseName);
      const actualPath = path.join(fixtureDir, 'actual.js');
      const options = {
        presets: [
          "react",
          "es2015",
        ],
        plugins: [
          plugin
        ],
        babelrc: false
      };
      const actual = transformFileSync(actualPath, options).code;
      const expected = fs.readFileSync(
          path.join(fixtureDir, 'expected.js')
      ).toString();

      assert.equal(trim(actual), trim(expected));
    });
  });
});
<commit_msg>fixed test runner<commit_after>import path from 'path';
import fs from 'fs';
import assert from 'assert';
import { transformFileSync } from 'babel-core';
import plugin from '../src';

function trim(str) {
  return str.replace(/^\s+|\s+$/, '');
}

describe('Add propType doc to react classes', () => {
  const fixturesDir = path.join(__dirname, 'fixtures');
  fs.readdirSync(fixturesDir).map((caseName) => {
    it(`should ${caseName.split('-').join(' ')}`, () => {
      const fixtureDir = path.join(fixturesDir, caseName);
      const actualPath = path.join(fixtureDir, 'actual.js');
      const options = {
        presets: [
          "react",
          "es2015",
        ],
        plugins: [
          [plugin, {
            "DOC_GEN_GLOBAL": "STORYBOOK_REACT_CLASSES"
          }]
        ],
        babelrc: false
      };
      const actual = transformFileSync(actualPath, options).code;
      //fs.writeFileSync(path.join(fixtureDir, 'actual-output.js'), actual);
      const expected = fs.readFileSync(
          path.join(fixtureDir, 'expected.js')
      ).toString();

      assert.equal(trim(actual), trim(expected));
    });
  });
});
<|endoftext|>