<commit_before>import ReactDOMServer from 'react-dom/server'
import React from 'react'
import raf from 'raf'
import Radium from 'radium'

import phash from './lib/phash'
import cloneError from './lib/cloneError'
import hotCache from './mixins/hotCache'
import reportError from './lib/reportError'
import runEvents from './lib/runEvents'
import createElement from './tag/createElement'
import viewOn from './lib/viewOn'

const capitalize = str =>
  str[0].toUpperCase() + str.substring(1)

const pathWithoutProps = path =>
  path.replace(/\.[a-z0-9\-]+$/, '')

let views = {}
let viewErrorDebouncers = {}

export default function createComponent(Flint, Internal, name, view, options = {}) {
  const el = createElement(name)
  let isChanged = options.changed

  if (process.env.production)
    return createViewComponent()

  if (options.changed) {
    views[name] = createViewComponent()
  }

  // once rendered, isChanged is used to prevent
  // unnecessary props hashing, for faster hot reloads
  Flint.on('render:done', () => {
    isChanged = false
  })

  return createProxyComponent()

  // proxy components handle hot reloads
  function createProxyComponent() {
    return React.createClass({

      childContextTypes: {
        path: React.PropTypes.string,
        displayName: React.PropTypes.string
      },

      contextTypes: {
        path: React.PropTypes.string
      },

      getChildContext() {
        return {
          path: this.getPath()
        }
      },

      getPath() {
        if (!this.path) this.setPath()
        return this.path
      },

      getSep() {
        return name == 'Main' ? '' : ','
      },

      setPathKey() {
        const flint = this.props.__flint
        const key = flint && flint.key || '00'
        const index = flint && flint.index || '00'
        const parentPath = this.context.path || ''
        this.pathKey = `${parentPath}${this.getSep()}${name}-${key}/${index}`
      },

      setPath() {
        this.setPathKey()

        if (!isChanged) {
          const prevPath = Internal.paths[this.pathKey]
          if (prevPath) {
            this.path = prevPath
            return
          }
        }

        const propsHash = phash(this.props)
        this.path = `${this.pathKey}.${propsHash}`

        // for faster retrieval hot reloading
        Internal.paths[this.pathKey] = this.path
      },

      onMount(component) {
        const path = this.getPath()
        const lastRendered = component.lastRendered

        Internal.mountedViews[name] = Internal.mountedViews[name] || []
        Internal.mountedViews[name].push(this)
        Internal.viewsAtPath[path] = component

        if (lastRendered)
          Internal.lastWorkingRenders[pathWithoutProps(path)] = lastRendered

        Internal.lastWorkingViews[name] = { component }
      },

      render() {
        const View = views[name]

        let viewProps = Object.assign({}, this.props)

        viewProps.__flint = viewProps.__flint || {}
        viewProps.__flint.onMount = this.onMount
        viewProps.__flint.path = this.getPath()

        return React.createElement(View, viewProps)
      }
    })
  }

  // create view
  function createViewComponent() {
    const component = React.createClass({
      displayName: name,
      name,
      Flint,
      el,

      mixins: [hotCache({ Internal, options, name })],

      // TODO: shouldComponentUpdate based on hot load for perf
      shouldComponentUpdate() {
        return !this.isPaused
      },

      shouldUpdate(fn) {
        if (this.hasShouldUpdate) {
          reportError({ message: `You defined shouldUpdate twice in ${name}, remove one!`, fileName: `view ${name}` })
          return
        }

        this.hasShouldUpdate = true

        const flintShouldUpdate = this.shouldComponentUpdate.bind(this)

        this.shouldComponentUpdate = (nextProps) => {
          if (!flintShouldUpdate()) return false
          return fn(this.props, nextProps)
        }
      },

      // LIFECYCLES

      getInitialState() {
        const fprops = this.props.__flint

        Internal.getInitialStates[fprops ? fprops.path : 'Main'] = () => this.getInitialState()

        let u = null

        this.state = {}
        this.queuedUpdate = false
        this.firstRender = true
        this.isUpdating = true
        this.styles = { _static: {} }
        this.events = { mount: u, unmount: u, change: u, props: u }
        this.path = null

        // scope on() to view
        this.on = viewOn(this)

        // cache Flint view render() (defined below)
        const flintRender = this.render

        this.renders = []

        // setter to capture view render
        this.render = renderFn => {
          this.renders.push(renderFn)
        }

        if (process.env.production)
          view.call(this, this, this.on, this.styles)
        else {
          try {
            view.call(this, this, this.on, this.styles)
            this.recoveryRender = false
          }
          catch(e) {
            Internal.caughtRuntimeErrors++
            reportError(e)
            console.error(e.stack || e)
            this.recoveryRender = true
          }
        }

        // reset original render
        this.render = flintRender

        if (Internal.viewDecorator)
          Internal.viewDecorator(this)

        return null
      },

      runEvents(name, args) {
        runEvents(this.events, name, args)
      },

      componentWillReceiveProps(nextProps) {
        // set timeout becuase otherwise props is mutated before shouldUpdate is run
        setTimeout(() => {
          this.props = nextProps
          this.runEvents('props', [this.props])
        })
      },

      componentWillMount() {
        // run props before mount
        this.runEvents('props', [this.props])
      },

      componentDidMount() {
        this.isRendering = false
        this.mounted = true
        this.isUpdating = false

        this.runEvents('mount')

        if (this.queuedUpdate) {
          this.queuedUpdate = false
          this.update()
        }

        if (name === 'Main')
          Internal.firstRender = false

        if (!process.env.production) {
          this.props.__flint.onMount(this)
          this.setID()
        }
      },

      componentWillUnmount() {
        // fixes unmount errors github.com/flintjs/flint/issues/60
        if (!process.env.production)
          this.render()

        this.runEvents('unmount')
        this.mounted = false
      },

      componentWillUpdate() {
        this.isUpdating = true
        this.runEvents('change')
      },

      setID() {
        if (Internal.isDevTools) return

        // set flintID for state inspect
        const node = ReactDOM.findDOMNode(this)
        if (node) node.__flintID = this.props.__flint.path
      },

      componentDidUpdate() {
        this.isRendering = false
        this.isUpdating = false

        if (this.queuedUpdate) {
          this.queuedUpdate = false
          this.update()
        }

        if (!process.env.production) {
          this.setID()
        }
      },

      // FLINT HELPERS

      // property declarators
      prop(name, defaultValue) {
        return this.props[name] || defaultValue
      },

      clone(el, props) {
        return React.cloneElement(el, props)
      },

      // helpers for controlling re-renders
      pause() { this.isPaused = true },
      resume() { this.isPaused = false },

      // for looping while waiting
      delayUpdate() {
        if (this.queuedUpdate) return
        this.queuedUpdate = true
        this.update()
      },

      // soft = view.set()
      update(soft) {
        // view.set respects paused
        if (soft && this.isPaused)
          return

        let doUpdate = () => {
          // if during a render, wait
          if (this.isRendering || this.isUpdating || !this.mounted || Internal.firstRender) {
            this.queuedUpdate = true
          }
          else {
            // tools run into weird bug where if error in app on initial render, react gets
            // mad that you are trying to re-render tools during app render TODO: strip in prod
            // check for isRendering so it shows if fails to render
            if (!process.env.production && _Flint.firstRender && _Flint.isRendering)
              return setTimeout(this.update)

            this.isUpdating = true
            this.queuedUpdate = false

            // rather than setState because we want to skip shouldUpdate calls
            this.forceUpdate()
          }
        }

        // setTimeout fixes issues with forceUpdate during previous transition in React
        // batch changes at end of setTimeout
        if (this.queuedUpdate) return
        this.queuedUpdate = true
        setTimeout(doUpdate)
      },

      // childContextTypes: {
      //   flintContext: React.PropTypes.object
      // },
      //
      // contextTypes: {
      //   flintContext: React.PropTypes.object
      // },
      //
      // getChildContext() {
      //   console.log(name, 'get', this)
      //   return { flintContext: this._context || null }
      // },
      //
      // // helpers for context
      // setContext(obj) {
      //   if (typeof obj != 'object')
      //     throw new Error('Must pass an object to childContext!')
      //
      //   console.log(this, name, 'set', obj)
      //   this.state = { _context: obj }
      // },

      getWrapper(tags, props, numRenders) {
        const wrapperName = name.toLowerCase()

        let tagProps = Object.assign({
          isWrapper: true
        }, props)

        return this.el(`view.${name}`, tagProps, ...tags)
      },

      getRender() {
        if (this.recoveryRender)
          return this.getLastGoodRender()

        let tags, props
        let addWrapper = true
        const numRenders = this.renders && this.renders.length

        if (!numRenders) {
          tags = []
          props = { yield: true }
        }

        else if (numRenders == 1) {
          tags = this.renders[0].call(this)

          addWrapper = (
            Array.isArray(tags) ||
            !tags.props
          )

          if (!Array.isArray(tags) && tags.props && tags.props.__flint && tags.props.__flint.tagName != name.toLowerCase()) {
            addWrapper = true
            tags = [tags]
          }
        }

        else if (numRenders > 1) {
          tags = this.renders.map(r => r.call(this))
        }

        // if $ = false, unwrap if possible
        // if (this.styles._static && this.styles._static.$ == false && tags.length == 1) {
        //   addWrapper = false
        //   tags = tags[0]
        // }

        // top level tag returned false
        if (!tags)
          addWrapper = true

        const wrappedTags = addWrapper ?
          this.getWrapper(tags, props, numRenders) :
          tags

        const cleanName = name.replace('.', '-')
        const viewClassName = `View${cleanName}`
        const parentClassName = wrappedTags.props.className
        const className = parentClassName
          ? `${viewClassName} ${parentClassName}`
          : viewClassName

        const withClass = React.cloneElement(wrappedTags, { className })

        return withClass
      },

      getLastGoodRender() {
        return Internal.lastWorkingRenders[pathWithoutProps(this.props.__flint.path)]
      },

      render() {
        const self = this

        self.isRendering = true
        self.firstRender = false

        if (process.env.production)
          return self.getRender()
        else {
          clearTimeout(viewErrorDebouncers[self.props.__flint.path])
        }

        // try render
        try {
          const els = self.getRender()
          self.lastRendered = els
          return els
        }
        catch(e) {
          Internal.caughtRuntimeErrors++

          const err = cloneError(e)

          // console warn, with debounce
          viewErrorDebouncers[self.props.__flint.path] = setTimeout(() => {
            console.groupCollapsed(`Render error in view ${name} (${err.message})`)
            console.error(err.stack || err)
            console.groupEnd()
          }, 500)

          reportError(e)

          const lastRender = self.getLastGoodRender()

          try {
            let inner = Error in view {name}

            if (Internal.isDevTools)
              return inner

            if (lastRender) {
              let __html = ReactDOMServer.renderToString(lastRender)
              __html = __html.replace(/\s*data\-react[a-z-]*\=\"[^"]*\"/g, '')
              inner =
            }

            // highlight in red and return last working render
            return (

                {inner}

            )
          }
          catch(e) {
            console.flint("Error rendering last version of view after error")
          }
        }
      }
    })

    return Radium(component)
  }
}
<commit_msg>view.renderToRoot() for portals<commit_after>import ReactDOMServer from 'react-dom/server'
import React from 'react'
import raf from 'raf'
import Radium from 'radium'

import phash from './lib/phash'
import cloneError from './lib/cloneError'
import hotCache from './mixins/hotCache'
import reportError from './lib/reportError'
import runEvents from './lib/runEvents'
import createElement from './tag/createElement'
import viewOn from './lib/viewOn'

const capitalize = str =>
  str[0].toUpperCase() + str.substring(1)

const pathWithoutProps = path =>
  path.replace(/\.[a-z0-9\-]+$/, '')

let views = {}
let viewErrorDebouncers = {}

export default function createComponent(Flint, Internal, name, view, options = {}) {
  const el = createElement(name)
  let isChanged = options.changed

  if (process.env.production)
    return createViewComponent()

  if (options.changed) {
    views[name] = createViewComponent()
  }

  // once rendered, isChanged is used to prevent
  // unnecessary props hashing, for faster hot reloads
  Flint.on('render:done', () => {
    isChanged = false
  })

  return createProxyComponent()

  // proxy components handle hot reloads
  function createProxyComponent() {
    return React.createClass({

      childContextTypes: {
        path: React.PropTypes.string,
        displayName: React.PropTypes.string
      },

      contextTypes: {
        path: React.PropTypes.string
      },

      getChildContext() {
        return {
          path: this.getPath()
        }
      },

      getPath() {
        if (!this.path) this.setPath()
        return this.path
      },

      getSep() {
        return name == 'Main' ? '' : ','
      },

      setPathKey() {
        const flint = this.props.__flint
        const key = flint && flint.key || '00'
        const index = flint && flint.index || '00'
        const parentPath = this.context.path || ''
        this.pathKey = `${parentPath}${this.getSep()}${name}-${key}/${index}`
      },

      setPath() {
        this.setPathKey()

        if (!isChanged) {
          const prevPath = Internal.paths[this.pathKey]
          if (prevPath) {
            this.path = prevPath
            return
          }
        }

        const propsHash = phash(this.props)
        this.path = `${this.pathKey}.${propsHash}`

        // for faster retrieval hot reloading
        Internal.paths[this.pathKey] = this.path
      },

      onMount(component) {
        const path = this.getPath()
        const lastRendered = component.lastRendered

        Internal.mountedViews[name] = Internal.mountedViews[name] || []
        Internal.mountedViews[name].push(this)
        Internal.viewsAtPath[path] = component

        if (lastRendered)
          Internal.lastWorkingRenders[pathWithoutProps(path)] = lastRendered

        Internal.lastWorkingViews[name] = { component }
      },

      render() {
        const View = views[name]

        let viewProps = Object.assign({}, this.props)

        viewProps.__flint = viewProps.__flint || {}
        viewProps.__flint.onMount = this.onMount
        viewProps.__flint.path = this.getPath()

        return React.createElement(View, viewProps)
      }
    })
  }

  // create view
  function createViewComponent() {
    const component = React.createClass({
      displayName: name,
      name,
      Flint,
      el,

      mixins: [hotCache({ Internal, options, name })],

      // TODO: shouldComponentUpdate based on hot load for perf
      shouldComponentUpdate() {
        return !this.isPaused
      },

      shouldUpdate(fn) {
        if (this.hasShouldUpdate) {
          reportError({ message: `You defined shouldUpdate twice in ${name}, remove one!`, fileName: `view ${name}` })
          return
        }

        this.hasShouldUpdate = true

        const flintShouldUpdate = this.shouldComponentUpdate.bind(this)

        this.shouldComponentUpdate = (nextProps) => {
          if (!flintShouldUpdate()) return false
          return fn(this.props, nextProps)
        }
      },

      // LIFECYCLES

      getInitialState() {
        const fprops = this.props.__flint

        Internal.getInitialStates[fprops ? fprops.path : 'Main'] = () => this.getInitialState()

        let u = null

        this.state = {}
        this.queuedUpdate = false
        this.firstRender = true
        this.isUpdating = true
        this.styles = { _static: {} }
        this.events = { mount: u, unmount: u, change: u, props: u }
        this.path = null

        // scope on() to view
        this.on = viewOn(this)

        // cache Flint view render() (defined below)
        const flintRender = this.render

        this.renders = []

        // setter to capture view render
        this.render = renderFn => {
          this.renders.push(renderFn)
        }

        if (process.env.production)
          view.call(this, this, this.on, this.styles)
        else {
          try {
            view.call(this, this, this.on, this.styles)
            this.recoveryRender = false
          }
          catch(e) {
            Internal.caughtRuntimeErrors++
            reportError(e)
            console.error(e.stack || e)
            this.recoveryRender = true
          }
        }

        // reset original render
        this.render = flintRender

        if (Internal.viewDecorator)
          Internal.viewDecorator(this)

        return null
      },

      runEvents(name, args) {
        runEvents(this.events, name, args)
      },

      componentWillReceiveProps(nextProps) {
        // set timeout becuase otherwise props is mutated before shouldUpdate is run
        setTimeout(() => {
          this.props = nextProps
          this.runEvents('props', [this.props])
        })
      },

      componentWillMount() {
        // run props before mount
        this.runEvents('props', [this.props])
      },

      componentDidMount() {
        this.isRendering = false
        this.mounted = true
        this.isUpdating = false

        this.runEvents('mount')

        if (this.queuedUpdate) {
          this.queuedUpdate = false
          this.update()
        }

        if (name === 'Main')
          Internal.firstRender = false

        if (!process.env.production) {
          this.props.__flint.onMount(this)
          this.setID()
        }

        if (this.doRenderToRoot) {
          this.handleRootRender()
        }
      },

      componentWillUnmount() {
        // fixes unmount errors github.com/flintjs/flint/issues/60
        if (!process.env.production)
          this.render()

        this.runEvents('unmount')
        this.mounted = false

        if (this.renderToRoot) {
          ReactDOM.unmountComponentAtNode(this.node)
          this.app.removeChild(this.node)
        }
      },

      componentWillUpdate() {
        this.isUpdating = true
        this.runEvents('change')
      },

      setID() {
        if (Internal.isDevTools) return

        // set flintID for state inspect
        const node = ReactDOM.findDOMNode(this)
        if (node) node.__flintID = this.props.__flint.path
      },

      componentDidUpdate() {
        this.isRendering = false
        this.isUpdating = false

        if (this.queuedUpdate) {
          this.queuedUpdate = false
          this.update()
        }

        if (!process.env.production) {
          this.setID()
        }

        if (this.doRenderToRoot) {
          this.handleRootRender()
        }
      },

      // FLINT HELPERS

      // property declarators
      prop(name, defaultValue) {
        return this.props[name] || defaultValue
      },

      clone(el, props) {
        return React.cloneElement(el, props)
      },

      // helpers for controlling re-renders
      pause() { this.isPaused = true },
      resume() { this.isPaused = false },

      // for looping while waiting
      delayUpdate() {
        if (this.queuedUpdate) return
        this.queuedUpdate = true
        this.update()
      },

      // soft = view.set()
      update(soft) {
        // view.set respects paused
        if (soft && this.isPaused)
          return

        let doUpdate = () => {
          // if during a render, wait
          if (this.isRendering || this.isUpdating || !this.mounted || Internal.firstRender) {
            this.queuedUpdate = true
          }
          else {
            // tools run into weird bug where if error in app on initial render, react gets
            // mad that you are trying to re-render tools during app render TODO: strip in prod
            // check for isRendering so it shows if fails to render
            if (!process.env.production && _Flint.firstRender && _Flint.isRendering)
              return setTimeout(this.update)

            this.isUpdating = true
            this.queuedUpdate = false

            // rather than setState because we want to skip shouldUpdate calls
            this.forceUpdate()
          }
        }

        // setTimeout fixes issues with forceUpdate during previous transition in React
        // batch changes at end of setTimeout
        if (this.queuedUpdate) return
        this.queuedUpdate = true
        setTimeout(doUpdate)
      },

      // childContextTypes: {
      //   flintContext: React.PropTypes.object
      // },
      //
      // contextTypes: {
      //   flintContext: React.PropTypes.object
      // },
      //
      // getChildContext() {
      //   console.log(name, 'get', this)
      //   return { flintContext: this._context || null }
      // },
      //
      // // helpers for context
      // setContext(obj) {
      //   if (typeof obj != 'object')
      //     throw new Error('Must pass an object to childContext!')
      //
      //   console.log(this, name, 'set', obj)
      //   this.state = { _context: obj }
      // },

      // render to a "portal"
      renderToRoot() {
        this.doRenderToRoot = true

        this.app = document.body
        this.node = document.createElement('div')
        this.node.setAttribute('data-portal', 'true')
        this.app.appendChild(this.node)
      },

      handleRootRender() {
        ReactDOM.render(this.renderResult, this.node)
      },

      getWrapper(tags, props, numRenders) {
        const wrapperName = name.toLowerCase()

        let tagProps = Object.assign({
          isWrapper: true
        }, props)

        return this.el(`view.${name}`, tagProps, ...tags)
      },

      getRender() {
        if (this.recoveryRender)
          return this.getLastGoodRender()

        let tags, props
        let addWrapper = true
        const numRenders = this.renders && this.renders.length

        if (!numRenders) {
          tags = []
          props = { yield: true }
        }

        else if (numRenders == 1) {
          tags = this.renders[0].call(this)

          addWrapper = (
            Array.isArray(tags) ||
            !tags.props
          )

          if (!Array.isArray(tags) && tags.props && tags.props.__flint && tags.props.__flint.tagName != name.toLowerCase()) {
            addWrapper = true
            tags = [tags]
          }
        }

        else if (numRenders > 1) {
          tags = this.renders.map(r => r.call(this))
        }

        // if $ = false, unwrap if possible
        // if (this.styles._static && this.styles._static.$ == false && tags.length == 1) {
        //   addWrapper = false
        //   tags = tags[0]
        // }

        // top level tag returned false
        if (!tags)
          addWrapper = true

        const wrappedTags = addWrapper ?
          this.getWrapper(tags, props, numRenders) :
          tags

        const cleanName = name.replace('.', '-')
        const viewClassName = `View${cleanName}`
        const parentClassName = wrappedTags.props.className
        const className = parentClassName
          ? `${viewClassName} ${parentClassName}`
          : viewClassName

        const withClass = React.cloneElement(wrappedTags, { className })

        return withClass
      },

      getLastGoodRender() {
        return Internal.lastWorkingRenders[pathWithoutProps(this.props.__flint.path)]
      },

      _render() {
        const self = this

        self.isRendering = true
        self.firstRender = false

        if (process.env.production)
          return self.getRender()
        else {
          clearTimeout(viewErrorDebouncers[self.props.__flint.path])
        }

        // try render
        try {
          const els = self.getRender()
          self.lastRendered = els
          return els
        }
        catch(e) {
          Internal.caughtRuntimeErrors++

          const err = cloneError(e)

          // console warn, with debounce
          viewErrorDebouncers[self.props.__flint.path] = setTimeout(() => {
            console.groupCollapsed(`Render error in view ${name} (${err.message})`)
            console.error(err.stack || err)
            console.groupEnd()
          }, 500)

          reportError(e)

          const lastRender = self.getLastGoodRender()

          try {
            let inner = Error in view {name}

            if (Internal.isDevTools)
              return inner

            if (lastRender) {
              let __html = ReactDOMServer.renderToString(lastRender)
              __html = __html.replace(/\s*data\-react[a-z-]*\=\"[^"]*\"/g, '')
              inner =
            }

            // highlight in red and return last working render
            return (

                {inner}

            )
          }
          catch(e) {
            console.flint("Error rendering last version of view after error")
          }
        }
      },

      render() {
        let result = this._render.call(this)

        if (this.doRenderToRoot) {
          this.renderResult = result
          return
        }
        else {
          return result
        }
      }
    })

    return Radium(component)
  }
}
<|endoftext|>


<commit_before>module.exports = [
  'esnextreact',
  'json',
  'css',
  // Enable less and tell webpack that our static asses all live in <project>/assets
  {
    generator: 'less',
    assetsDirectory: 'assets',
    publicPath: './',
  },
  // resolves webfonts urls, assumes they all live in <project>/assets/fonts
  {
    test: /\/fonts\/.*\.(eot|woff|ttf|svg)(\?.+)?$/,
    loader: 'file?emitFile=false&name=fonts/[name].[ext]',
  },
  // resolves images as urls, assumes they all live in <project>/assets/img
  {
    test: /\/img\/.*\.(png|svg|jpe?g|gif|tiff)$/,
    loader: 'file?emitFile=false&name=img/[name].[ext]',
  },
];
<commit_msg>Cache bust icon fonts<commit_after>module.exports = [
  'esnextreact',
  'json',
  'css',
  // Enable less and tell webpack that our static asses all live in <project>/assets
  {
    generator: 'less',
    assetsDirectory: 'assets',
    publicPath: './',
  },
  // resolves webfonts urls, assumes they all live in <project>/assets/fonts
  {
    test: /\/fonts\/.*\.(eot|woff|ttf|svg)(\?.+)?$/,
    loader: 'file?&name=fonts/[name].[hash].[ext]',
  },
  // resolves images as urls, assumes they all live in <project>/assets/img
  {
    test: /\/img\/.*\.(png|svg|jpe?g|gif|tiff)$/,
    loader: 'file?emitFile=false&name=img/[name].[ext]',
  },
];
<|endoftext|>


<commit_before>/**
 * Contentful Management API Client. Contains methods which allow access to
 * any operations that can be performed with a management token.
 * @namespace ContentfulClientAPI
 */

/**
 * Types for meta information found across the different entities in Contentful
 * @namespace Meta
 */

/**
 * System metadata. See Common Resource Attributes for more details.
 * @memberof Meta
 * @typedef Sys
 * @prop {string} type
 * @prop {string} id
 * @prop {Meta.Link} space
 * @prop {string} createdAt
 * @prop {string} updatedAt
 * @prop {number} revision
 */

/**
 * Link to another entity. See Links for more details.
 * @memberof Meta
 * @typedef Link
 * @prop {string} type - type of this entity. Always link.
 * @prop {string} id
 * @prop {string} linkType - type of this link. If defined, either Entry or Asset
 */

/**
 * @memberof ContentfulClientAPI
 * @typedef {Object} ClientAPI
 * @prop {function} getSpace
 * @prop {function} getSpaces
 * @prop {function} createSpace
 */

import errorHandler from './error-handler'
import entities from './entities'

/**
 * Creates API object with methods to access functionality from Contentful's
 * Management API
 * @private
 * @param {Object} params - API initialization params
 * @prop {Object} http - HTTP client instance
 * @prop {Function} shouldLinksResolve - Link resolver preconfigured with global setting
 * @return {ClientAPI}
 */
export default function createClientApi ({ http }) {
  const {wrapSpace, wrapSpaceCollection} = entities.space
  const {wrapOrganizationCollection} = entities.organization

  /**
   * Gets all spaces
   * @memberof ContentfulClientAPI
   * @return {Promise<Space.SpaceCollection>} Promise for a collection of Spaces
   * @example
   * const contentful = require('contentful-management')
   *
   * const client = contentful.createClient({
   *   accessToken: '<content_management_api_key>'
   * })
   *
   * client.getSpaces()
   * .then((response) => console.log(response.items))
   * .catch(console.error)
   */
  function getSpaces () {
    return http.get('')
    .then((response) => wrapSpaceCollection(http, response.data), errorHandler)
  }

  /**
   * Gets a space
   * @memberof ContentfulClientAPI
   * @param {string} id - Space ID
   * @return {Promise<Space.Space>} Promise for a Space
   * @example
   * const contentful = require('contentful-management')
   *
   * const client = contentful.createClient({
   *   accessToken: '<content_management_api_key>'
   * })
   *
   * client.getSpace('<space_id>')
   * .then((space) => console.log(space))
   * .catch(console.error)
   */
  function getSpace (id) {
    return http.get(id)
    .then((response) => wrapSpace(http, response.data), errorHandler)
  }

  /**
   * Creates a space
   * @memberof ContentfulClientAPI
   * @see {Space.Space}
   * @param {object} data - Object representation of the Space to be created
   * @param {string=} organizationId - Organization ID, if the associated token can manage more than one organization.
   * @return {Promise<Space.Space>} Promise for the newly created Space
   * @example
   * const contentful = require('contentful-management')
   *
   * const client = contentful.createClient({
   *   accessToken: '<content_management_api_key>'
   * })
   *
   * client.createSpace({
   *   name: 'Name of new space'
   * })
   * .then((space) => console.log(space))
   * .catch(console.error)
   */
  function createSpace (data, organizationId) {
    return http.post('', data, {
      headers: organizationId ? {'X-Contentful-Organization': organizationId} : {}
    })
    .then((response) => wrapSpace(http, response.data), errorHandler)
  }

  /**
   * Gets a collection of Organizations
   * @memberof ClientAPI
   * @return {Promise<OrganizationCollection>} Promise for a collection of Organizations
   * @example
   * const contentful = require('contentful-management')
   *
   * space.getOrganizations()
   * .then(result => console.log(result.items))
   * .catch(console.error)
   */
  function getOrganizations () {
    const baseURL = http.defaults.baseURL.replace('/spaces/', '/organizations/')
    return http.get('', {
      baseURL
    })
    .then((response) => wrapOrganizationCollection(http, response.data), errorHandler)
  }

  /**
   * Make a custom request to the Contentful management API's /spaces endpoint
   * @memberof ContentfulClientAPI
   * @param {Object} opts - axios request options (https://github.com/mzabriskie/axios)
   * @return {Promise<Object>} Promise for the response data
   * @example
   * const contentful = require('contentful-management')
   *
   * const client = contentful.createClient({
   *   accessToken: '<content_management_api_key>'
   * })
   *
   * client.rawRequest({
   *   method: 'GET',
   *   url: '/custom/path'
   * })
   * .then((responseData) => console.log(responseData))
   * .catch(console.error)
   */
  function rawRequest (opts) {
    return http(opts).then((response) => response.data, errorHandler)
  }

  return {
    getSpaces: getSpaces,
    getSpace: getSpace,
    createSpace: createSpace,
    getOrganizations: getOrganizations,
    rawRequest: rawRequest
  }
}
<commit_msg>fix(contentful-management): Add support for query for spaces (#124)<commit_after>/**
 * Contentful Management API Client. Contains methods which allow access to
 * any operations that can be performed with a management token.
 * @namespace ContentfulClientAPI
 */

/**
 * Types for meta information found across the different entities in Contentful
 * @namespace Meta
 */

/**
 * System metadata. See Common Resource Attributes for more details.
 * @memberof Meta
 * @typedef Sys
 * @prop {string} type
 * @prop {string} id
 * @prop {Meta.Link} space
 * @prop {string} createdAt
 * @prop {string} updatedAt
 * @prop {number} revision
 */

/**
 * Link to another entity. See Links for more details.
 * @memberof Meta
 * @typedef Link
 * @prop {string} type - type of this entity. Always link.
 * @prop {string} id
 * @prop {string} linkType - type of this link. If defined, either Entry or Asset
 */

/**
 * @memberof ContentfulClientAPI
 * @typedef {Object} ClientAPI
 * @prop {function} getSpace
 * @prop {function} getSpaces
 * @prop {function} createSpace
 */

import { createRequestConfig } from 'contentful-sdk-core'
import errorHandler from './error-handler'
import entities from './entities'

/**
 * Creates API object with methods to access functionality from Contentful's
 * Management API
 * @private
 * @param {Object} params - API initialization params
 * @prop {Object} http - HTTP client instance
 * @prop {Function} shouldLinksResolve - Link resolver preconfigured with global setting
 * @return {ClientAPI}
 */
export default function createClientApi ({ http }) {
  const {wrapSpace, wrapSpaceCollection} = entities.space
  const {wrapOrganizationCollection} = entities.organization

  /**
   * Gets all spaces
   * @memberof ContentfulClientAPI
   * @return {Promise<Space.SpaceCollection>} Promise for a collection of Spaces
   * @example
   * const contentful = require('contentful-management')
   *
   * const client = contentful.createClient({
   *   accessToken: '<content_management_api_key>'
   * })
   *
   * client.getSpaces()
   * .then((response) => console.log(response.items))
   * .catch(console.error)
   */
  function getSpaces (query = {}) {
    return http.get('', createRequestConfig({query: query}))
    .then((response) => wrapSpaceCollection(http, response.data), errorHandler)
  }

  /**
   * Gets a space
   * @memberof ContentfulClientAPI
   * @param {string} id - Space ID
   * @return {Promise<Space.Space>} Promise for a Space
   * @example
   * const contentful = require('contentful-management')
   *
   * const client = contentful.createClient({
   *   accessToken: '<content_management_api_key>'
   * })
   *
   * client.getSpace('<space_id>')
   * .then((space) => console.log(space))
   * .catch(console.error)
   */
  function getSpace (id) {
    return http.get(id)
    .then((response) => wrapSpace(http, response.data), errorHandler)
  }

  /**
   * Creates a space
   * @memberof ContentfulClientAPI
   * @see {Space.Space}
   * @param {object} data - Object representation of the Space to be created
   * @param {string=} organizationId - Organization ID, if the associated token can manage more than one organization.
   * @return {Promise<Space.Space>} Promise for the newly created Space
   * @example
   * const contentful = require('contentful-management')
   *
   * const client = contentful.createClient({
   *   accessToken: '<content_management_api_key>'
   * })
   *
   * client.createSpace({
   *   name: 'Name of new space'
   * })
   * .then((space) => console.log(space))
   * .catch(console.error)
   */
  function createSpace (data, organizationId) {
    return http.post('', data, {
      headers: organizationId ? {'X-Contentful-Organization': organizationId} : {}
    })
    .then((response) => wrapSpace(http, response.data), errorHandler)
  }

  /**
   * Gets a collection of Organizations
   * @memberof ClientAPI
   * @return {Promise<OrganizationCollection>} Promise for a collection of Organizations
   * @example
   * const contentful = require('contentful-management')
   *
   * space.getOrganizations()
   * .then(result => console.log(result.items))
   * .catch(console.error)
   */
  function getOrganizations () {
    const baseURL = http.defaults.baseURL.replace('/spaces/', '/organizations/')
    return http.get('', {
      baseURL
    })
    .then((response) => wrapOrganizationCollection(http, response.data), errorHandler)
  }

  /**
   * Make a custom request to the Contentful management API's /spaces endpoint
   * @memberof ContentfulClientAPI
   * @param {Object} opts - axios request options (https://github.com/mzabriskie/axios)
   * @return {Promise<Object>} Promise for the response data
   * @example
   * const contentful = require('contentful-management')
   *
   * const client = contentful.createClient({
   *   accessToken: '<content_management_api_key>'
   * })
   *
   * client.rawRequest({
   *   method: 'GET',
   *   url: '/custom/path'
   * })
   * .then((responseData) => console.log(responseData))
   * .catch(console.error)
   */
  function rawRequest (opts) {
    return http(opts).then((response) => response.data, errorHandler)
  }

  return {
    getSpaces: getSpaces,
    getSpace: getSpace,
    createSpace: createSpace,
    getOrganizations: getOrganizations,
    rawRequest: rawRequest
  }
}
<|endoftext|>


<commit_before>/* Copyright 2015 Teem2 LLC. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
   You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing,
   software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
   either express or implied. See the License for the specific language governing permissions and limitations under the License.*/
// Teem server

define.class(function(require){

	var http = require('http')
	var os = require('os')
	var path = require('path')
	var fs = require('fs')
	var url = require('url')
	var zlib = require('zlib')

	var FileWatcher = require('./filewatcher')
	var ExternalApps = require('./externalapps')
	var NodeWebSocket = require('./nodewebsocket')
	var mimeFromFile = require('./mimefromfile')
	var CompositionServer = require('./compositionserver')

	var BusServer = require('$system/rpc/busserver')

	// Doccumentation
	this.atConstructor = function(args){
		this.compositions = {}

		this.args = args
		var port = this.args['-port'] || process.env.PORT || 2000
		var iface = this.args['-iface'] || process.env.IP || '0.0.0.0'

		this.cache_gzip = define.makeCacheDir('gzip')

		this.server = http.createServer(this.request.bind(this))
		this.server.listen(port, iface)
		this.server.on('upgrade', this.upgrade.bind(this))

		if(iface == '0.0.0.0'){
			var ifaces = os.networkInterfaces()
			var txt = ''
			Object.keys(ifaces).forEach(function(ifname){
				var alias = 0;
				ifaces[ifname].forEach(function(iface){
					if ('IPv4' !== iface.family) return
					var addr = 'http://' + iface.address + ':' + port + '/'
					if(!this.address) this.address = addr
					txt += ' ~~on ~c~'+addr
				}.bind(this))
			}.bind(this))
			console.color('Server running' + txt + '~~ Ready to go!\n')
		}
		else {
			this.address = 'http://' + iface + ':' + port + '/'
			console.color('Server running on ~c~' + this.address + "~~\n")
		}
		// use the browser spawner
		var browser = this.args['-browser']
		if(browser && (!this.args['-delay'] || this.args['-count'] ==0 )){
			ExternalApps.browser(this.address + (browser===true?'':browser), this.args['-devtools'])
		}

		this.watcher = new FileWatcher()
		this.watcher.atChange = function(file){
			// ok lets get the original path
			file=file.replace(/\\/g,"/")
			for(var key in define.paths){
				var match = define.expandVariables(define['$'+key])
				if(file.indexOf(match) === 0){
					file = '/'+key+file.slice(match.length)
					break
				}
			}
			//file = file.slice(define.expandVariables(define.$root).length).replace(/\\/g, "/")
			// ok lets rip off our
			this.broadcast({
				type:'filechange',
				file: file
			})
		}.bind(this)

		this.busserver = new BusServer()

		process.on('SIGHUP', function(){
			if(this.args['-close']) this.broadcast({type:'close'})
			if(this.args['-delay']) this.broadcast({type:'delay'})
		}.bind(this))

		if(this.args['-web']) this.getComposition(this.args['-web'])
	}

	this.COMP_DIR = 'compositions'

	this.broadcast = function(msg){
		this.busserver.broadcast(msg)
		for(var k in this.compositions){
			this.compositions[k].busserver.broadcast(msg)
		}
	}

	this.default_composition = null

	this.getComposition = function(file){

		// lets find the composition either in define.COMPOSITIONS
		if(!this.compositions[file]) this.compositions[file] = new CompositionServer(this.args, file, this)
		return this.compositions[file]
	}

	this.upgrade = function(req, sock, head){
		// lets connect the sockets to the app
		var sock = new NodeWebSocket(req, sock, head)
		sock.url = req.url
		var mypath = req.url.slice(1)
		if(mypath) this.getComposition('$' + mypath).busserver.addWebSocket(sock)
		else this.busserver.addWebSocket(sock)
	}

	// maps an input path into our files
	this.mapPath = function(input){
		var reqparts = input.split(/\//)
		// lets do the filename lookup
		var mypath = define.paths[reqparts[1]]
		if(!mypath) return false

		// combine it
		var file = path.join(define.expandVariables(mypath), reqparts.slice(2).join('/'))
		return file
	}

	this.searchPath = function(basedir, match){
		// lets recur our path
		var dir = fs.readdirSync(define.expandVariables(basedir))
		for(var i = 0; i < dir.length; i++){
			var subitem = basedir + '/' + dir[i]
			if(subitem.toLowerCase().indexOf(match) !== -1) return subitem
			var stat = fs.statSync(define.expandVariables(subitem))
			if(stat.isDirectory()){
				var file = this.searchPath(subitem, match)
				if(file) return file
			}
		}
	}

	this.request = function(req, res){
		// lets delegate to
		var host = req.headers.host
		var requrl = req.url

		// otherwise handle as static file
		if(requrl.indexOf('/proxy?') === 0){
			// lets connect a http request and forward it back!
			var tgt_url = url.parse(decodeURIComponent(requrl.slice(7)))
			var tgtpath = tgt_url.path;
			if (tgt_url.search) {
				tgtpath = tgtpath +tgt_url.search
			}
			var proxy_req = http.request({
				hostname: tgt_url.hostname,
				path: tgtpath,
				headers: {
					accept: req.headers.accept,
					'user-agent': req.headers['user-agent'],
					'accept-encoding': req.headers['accept-encoding'],
					'accept-language': req.headers['accept-language']
				}
			}, function(proxy_res){
				res.writeHead(proxy_res.statusCode, proxy_res.headers)
				proxy_res.pipe(res)
			})

			proxy_req.end()
			return
		}

		if(requrl =='/favicon.ico'){
			res.writeHead(200)
			res.end()
			return
		}

		var reqquery = requrl.split('?')

		// ok if we are a /single fetch
		var file = this.mapPath(reqquery[0])

		if(file === false){ // file is a search
			// what are we looking for
			// a directory named x or file or anything
			// we will just 302 to it
			for(var key in define.paths){
				var mypath = define.paths[key]
				var fwdfile = this.searchPath(mypath, reqquery[0].slice(1))
				if(fwdfile){
					var urlpath = '/'+ key + '/' +define.fileBase(fwdfile.slice(mypath.length))
					res.writeHead(307, {location:urlpath})
					res.end()
					return
				}
			}
			res.writeHead(404)
			res.end("File not found: "+reqquery[0])
			return
		}

		var fileext = define.fileExt(file)
		if(!fileext){
			var composition = this.getComposition('$'+reqquery[0].slice(1))
			if(composition) return composition.request(req, res)
		}

		fs.stat(file, function(err, stat){
			if(err || !stat.isFile()){
				// see if we can find the index.js, otherwise skip it
				file = file.slice(0, file.lastIndexOf('.')) + '/index.js'
				fs.stat(file, function(err, stat){
					if(err || !stat.isFile()){
						res.writeHead(404)
						res.end()
						console.color('~br~Error~y~ ' + file + '~~ File not found, returning 403\n')
						return
					}
					processFile(stat)
				})
			}
			else processFile(stat)
		})

		var processFile = function(stat){
			var header = {
				"Connection":"Close",
				"Cache-control":"max-age=0",
				"Content-Type": mimeFromFile(file),
				"etag": stat.mtime.getTime() + '_' + stat.size,
				"mtime": stat.mtime.getTime()
			}
			this.watcher.watch(file)
			if( req.headers['if-none-match'] == header.etag){
				res.writeHead(304,header)
				res.end()
				return
			}
			// lets add a gzip cache
			var type = header["Content-Type"]
			if(type !== 'image/jpeg' && type !== 'image/png'){
				// see if we accept gzip
				if(req.headers['accept-encoding'] && req.headers['accept-encoding'].toLowerCase().indexOf('gzip') !== -1){
					//header["Content-Type"]+="; utf8"
					header["Content-encoding"] = "gzip"
					header["Transfer-Encoding"] = "gzip"
					var gzip_file = path.join(this.cache_gzip, requrl.replace(/\//g,'_')+header.etag)
					fs.stat(gzip_file, function(err, stat){
						if(err){ // make it
							fs.readFile(file, function(err, data){
								zlib.gzip(data, function(err, compr){
									//header["Content-length"] = compr.length
									//console.log(compr.length)
									res.writeHead(200, header)
									res.write(compr)
									res.end()
									fs.writeFile(gzip_file, compr, function(err){

									})
								})
							})
						}
						else{
							var stream = fs.createReadStream(gzip_file)
							res.writeHead(200, header)
							stream.pipe(res)
						}
					})
				}
				else{
					var stream = fs.createReadStream(file)
					res.writeHead(200, header)
					stream.pipe(res)
				}
			}
			else{
				var stream = fs.createReadStream(file)
				res.writeHead(200, header)
				stream.pipe(res)
			}
			// ok so we get a filechange right?

		}.bind(this)
	}
})<commit_msg>First cut at .dre to JS transformation<commit_after>/* Copyright 2015 Teem2 LLC. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
   You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing,
   software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
   either express or implied. See the License for the specific language governing permissions and limitations under the License.*/
// Teem server

define.class(function(require){

	var http = require('http')
	var os = require('os')
	var path = require('path')
	var fs = require('fs')
	var url = require('url')
	var zlib = require('zlib')

	var FileWatcher = require('./filewatcher')
	var ExternalApps = require('./externalapps')
	var NodeWebSocket = require('./nodewebsocket')
	var mimeFromFile = require('./mimefromfile')
	var HTMLParser = require('$system/parse/htmlparser')
	var CompositionServer = require('./compositionserver')

	var BusServer = require('$system/rpc/busserver')

	// Doccumentation
	this.atConstructor = function(args){
		this.compositions = {}

		this.args = args
		var port = this.args['-port'] || process.env.PORT || 2000
		var iface = this.args['-iface'] || process.env.IP || '0.0.0.0'

		this.cache_gzip = define.makeCacheDir('gzip')

		this.server = http.createServer(this.request.bind(this))
		this.server.listen(port, iface)
		this.server.on('upgrade', this.upgrade.bind(this))

		if(iface == '0.0.0.0'){
			var ifaces = os.networkInterfaces()
			var txt = ''
			Object.keys(ifaces).forEach(function(ifname){
				var alias = 0;
				ifaces[ifname].forEach(function(iface){
					if ('IPv4' !== iface.family) return
					var addr = 'http://' + iface.address + ':' + port + '/'
					if(!this.address) this.address = addr
					txt += ' ~~on ~c~'+addr
				}.bind(this))
			}.bind(this))
			console.color('Server running' + txt + '~~ Ready to go!\n')
		}
		else {
			this.address = 'http://' + iface + ':' + port + '/'
			console.color('Server running on ~c~' + this.address + "~~\n")
		}
		// use the browser spawner
		var browser = this.args['-browser']
		if(browser && (!this.args['-delay'] || this.args['-count'] ==0 )){
			ExternalApps.browser(this.address + (browser===true?'':browser), this.args['-devtools'])
		}

		this.watcher = new FileWatcher()
		this.watcher.atChange = function(file){
			// ok lets get the original path
			file=file.replace(/\\/g,"/")
			for(var key in define.paths){
				var match = define.expandVariables(define['$'+key])
				if(file.indexOf(match) === 0){
					file = '/'+key+file.slice(match.length)
					break
				}
			}
			//file = file.slice(define.expandVariables(define.$root).length).replace(/\\/g, "/")
			// ok lets rip off our
			this.broadcast({
				type:'filechange',
				file: file
			})
		}.bind(this)

		this.busserver = new BusServer()

		process.on('SIGHUP', function(){
			if(this.args['-close']) this.broadcast({type:'close'})
			if(this.args['-delay']) this.broadcast({type:'delay'})
		}.bind(this))

		if(this.args['-web']) this.getComposition(this.args['-web'])
	}

	this.COMP_DIR = 'compositions'

	this.broadcast = function(msg){
		this.busserver.broadcast(msg)
		for(var k in this.compositions){
			this.compositions[k].busserver.broadcast(msg)
		}
	}

	this.default_composition = null

	this.getComposition = function(file){

		// lets find the composition either in define.COMPOSITIONS
		if(!this.compositions[file]) this.compositions[file] = new CompositionServer(this.args, file, this)
		return this.compositions[file]
	}

	this.upgrade = function(req, sock, head){
		// lets connect the sockets to the app
		var sock = new NodeWebSocket(req, sock, head)
		sock.url = req.url
		var mypath = req.url.slice(1)
		if(mypath) this.getComposition('$' + mypath).busserver.addWebSocket(sock)
		else this.busserver.addWebSocket(sock)
	}

	// maps an input path into our files
	this.mapPath = function(input){
		var reqparts = input.split(/\//)
		// lets do the filename lookup
		var mypath = define.paths[reqparts[1]]
		if(!mypath) return false

		// combine it
		var file = path.join(define.expandVariables(mypath), reqparts.slice(2).join('/'))
		return file
	}

	this.searchPath = function(basedir, match){
		// lets recur our path
		var dir = fs.readdirSync(define.expandVariables(basedir))
		for(var i = 0; i < dir.length; i++){
			var subitem = basedir + '/' + dir[i]
			if(subitem.toLowerCase().indexOf(match) !== -1) return subitem
			var stat = fs.statSync(define.expandVariables(subitem))
			if(stat.isDirectory()){
				var file = this.searchPath(subitem, match)
				if(file) return file
			}
		}
	}

	this.request = function(req, res){
		// lets delegate to
		var host = req.headers.host
		var requrl = req.url

		// otherwise handle as static file
		if(requrl.indexOf('/proxy?') === 0){
			// lets connect a http request and forward it back!
			var tgt_url = url.parse(decodeURIComponent(requrl.slice(7)))
			var tgtpath = tgt_url.path;
			if (tgt_url.search) {
				tgtpath = tgtpath +tgt_url.search
			}
			var proxy_req = http.request({
				hostname: tgt_url.hostname,
				path: tgtpath,
				headers: {
					accept: req.headers.accept,
					'user-agent': req.headers['user-agent'],
					'accept-encoding': req.headers['accept-encoding'],
					'accept-language': req.headers['accept-language']
				}
			}, function(proxy_res){
				res.writeHead(proxy_res.statusCode, proxy_res.headers)
				proxy_res.pipe(res)
			})

			proxy_req.end()
			return
		}

		if(requrl =='/favicon.ico'){
			res.writeHead(200)
			res.end()
			return
		}

		var reqquery = requrl.split('?')

		// ok if we are a /single fetch
		var file = this.mapPath(reqquery[0])
		var urlext = define.fileExt(reqquery[0])

		var xmlToJS = function(filepath) {
			var makeSpace = function(indent) {
				var out = '';
				for (var i = 0; i < indent; i++) {
					out += '  ';
				}
				return out;
			}
			var filterSpecial = function(child) {
				return child.tag.indexOf('$') !== 0;
			}
			var tagToFunc = function(child, indent) {
				// console.log('tagToFunc', indent, child, child.tag.indexOf('$'))
				var outputthis = filterSpecial(child);
				var out = '';
				var children = child.child && child.child.filter(filterSpecial);
				if (outputthis) {
					out += makeSpace(indent);
					// name
					out += child.tag + '(';
					// attributes
					out += JSON.stringify(child.attr);
					if (children && children.length) out += ',\n'
				}
				if (children && children.length) {
					indent++;
					for (var i = 0; i < children.length; i++) {
						newchild = children[i];
						if (filterSpecial(newchild)) {
							out += tagToFunc(newchild, indent);
							if (i !== children.length - 1) {
								out += ','
							}
							out += '\n';
						}
					}
					indent--;
				}
				if (outputthis) {
					if (children && children.length) out += makeSpace(indent);
					out += ')';
				}
				return out;
			}
			// transform .dre to .js
			// console.log('parsing .dre file', filepath);
			var parsed = HTMLParser(fs.readFileSync(filepath));
			// console.log('parsed', JSON.stringify(parsed.node));
			var out = 'define.class(function($server$, composition, role, $ui$, screen, view){\n  this.render = function(){ return [\n';
			out += tagToFunc(parsed.node, 1);
			out += '  ];\n};\n});'
			// console.log('result', out)
			// write to .dre.js file and redirect there
			// TODO: warn for overwrites to changed file, e.g. check hash of file versus old version
			return out;
		}
		if (urlext === 'dre') {
			var url = reqquery[0];
			var filepath = define.expandVariables('$root' + url)
			var out = xmlToJS(filepath)
			fs.writeFileSync(filepath + '.js', out);
			res.writeHead(307, {location:url + '.js'})
			res.end()
			return
		}

		if(file === false){ // file is a search
			// what are we looking for
			// a directory named x or file or anything
			// we will just 302 to it
			for(var key in define.paths){
				var mypath = define.paths[key]
				var fwdfile = this.searchPath(mypath, reqquery[0].slice(1))
				if(fwdfile){
					var urlpath = '/'+ key + '/' +define.fileBase(fwdfile.slice(mypath.length))
					res.writeHead(307, {location:urlpath})
					res.end()
					return
				}
			}
			res.writeHead(404)
			res.end("File not found: "+reqquery[0])
			return
		}

		var fileext = define.fileExt(file)
		if(!fileext){
			var composition = this.getComposition('$'+reqquery[0].slice(1))
			if(composition) return composition.request(req, res)
		}

		fs.stat(file, function(err, stat){
			if(err || !stat.isFile()){
				// see if we can find the index.js, otherwise skip it
				file = file.slice(0, file.lastIndexOf('.')) + '/index.js'
				fs.stat(file, function(err, stat){
					if(err || !stat.isFile()){
						res.writeHead(404)
						res.end()
						console.color('~br~Error~y~ ' + file + '~~ File not found, returning 403\n')
						return
					}
					processFile(stat)
				})
			}
			else processFile(stat)
		})

		var processFile = function(stat){
			var header = {
				"Connection":"Close",
				"Cache-control":"max-age=0",
				"Content-Type": mimeFromFile(file),
				"etag": stat.mtime.getTime() + '_' + stat.size,
				"mtime": stat.mtime.getTime()
			}
			this.watcher.watch(file)
			if( req.headers['if-none-match'] == header.etag){
				res.writeHead(304,header)
				res.end()
				return
			}
			// lets add a gzip cache
			var type = header["Content-Type"]
			if(type !== 'image/jpeg' && type !== 'image/png'){
				// see if we accept gzip
				if(req.headers['accept-encoding'] && req.headers['accept-encoding'].toLowerCase().indexOf('gzip') !== -1){
					//header["Content-Type"]+="; utf8"
					header["Content-encoding"] = "gzip"
					header["Transfer-Encoding"] = "gzip"
					var gzip_file = path.join(this.cache_gzip, requrl.replace(/\//g,'_')+header.etag)
					fs.stat(gzip_file, function(err, stat){
						if(err){ // make it
							fs.readFile(file, function(err, data){
								zlib.gzip(data, function(err, compr){
									//header["Content-length"] = compr.length
									//console.log(compr.length)
									res.writeHead(200, header)
									res.write(compr)
									res.end()
									fs.writeFile(gzip_file, compr, function(err){

									})
								})
							})
						}
						else{
							var stream = fs.createReadStream(gzip_file)
							res.writeHead(200, header)
							stream.pipe(res)
						}
					})
				}
				else{
					var stream = fs.createReadStream(file)
					res.writeHead(200, header)
					stream.pipe(res)
				}
			}
			else{
				var stream = fs.createReadStream(file)
				res.writeHead(200, header)
				stream.pipe(res)
			}
			// ok so we get a filechange right?

		}.bind(this)
	}
})<|endoftext|>


<commit_before>'use strict';

var RSVP = require('rsvp');
var prepareUpload = require('../../prepareUpload');
var utils = require('../../utils');
var chalk = require('chalk');
var ProgressBar = require('progress');
var api = require('../../api');
var _ = require('lodash');
var FirebaseError = require('../../error');

module.exports = function(context, options, payload) {
  var local = context.hosting;

  if (!payload.hosting) {
    return RSVP.resolve();
  }

  utils.logBullet('preparing ' + chalk.bold(payload.hosting.public) + ' directory for upload...');
  return prepareUpload(options, payload.hosting).then(function(upload) {
    if (!upload.foundIndex) {
      utils.logWarning(chalk.bold('Warning:') + ' Public directory does not contain index.html');
    }

    if (!upload.manifest.length) {
      return utils.reject('Must have at least one file in public directory to deploy.', {exit: 1});
    }

    _.assign(payload.hosting, {
      version: local.versionId,
      prefix: local.versionId + '/',
      manifest: upload.manifest.map(function(file) {
        return {path: file, object: file};
      })
    });

    return new RSVP.Promise(function(resolve, reject) {
      var lastCount = 0;
      var lastPercent = 0;
      var bar;
      if (!options.nonInteractive && process.stderr) {
        bar = new ProgressBar(chalk.bold('Uploading:') + ' [:bar] :percent', {
          total: upload.manifest.length,
          width: 40,
          complete: chalk.green('='),
          incomplete: ' ',
          clear: true
        });
      } else {
        process.stdout.write(chalk.cyan.bold('\ni') + chalk.bold('  Progress: ['));
      }

      local.versionRef.on('value', function(snap) {
        var status = snap.child('status').val();
        switch (status) {
        case 'deploying':
          var uc = snap.child('uploadedCount').val() || 0;
          var percent = Math.round(100.0 * uc / upload.manifest.length);
          if (bar) {
            bar.tick(uc - lastCount);
          } else {
            process.stdout.write(_.repeat(chalk.green('.'), percent - lastPercent));
            lastPercent = percent;
          }
          lastCount = uc;
          break;
        case 'deployed':
          if (bar) {
            bar.terminate();
          } else {
            process.stdout.write(chalk.bold(']') + '\n\n');
          }
          utils.logSuccess(upload.manifest.length + ' files uploaded successfully');
          local.versionRef.off('value');
          resolve();
          break;
        case 'removed':
          reject(new FirebaseError('Not Implemented', {
            exit: 2,
            context: snap.val()
          }));
          break;
        case null:
          break;
        default:
          var msg = 'File upload failed';
          if (snap.hasChild('statusMessage')) {
            msg += ': ' + snap.child('statusMessage').val();
          }

          reject(new FirebaseError(msg, {
            exit: 2,
            context: snap.val()
          }));
        }
      });

      api.request('PUT', '/v1/hosting/' + options.instance + '/uploads/' + local.versionId, {
        auth: true,
        query: {
          fileCount: upload.manifest.length,
          message: options.message
        },
        files: {
          site: {
            filename: 'site.tar.gz',
            stream: upload.stream,
            contentType: 'application/x-gzip',
            knownLength: upload.size
          }
        },
        origin: api.deployOrigin
      }).catch(reject);
    });
  });
};
<commit_msg>Prefix "hosting:" on hosting-specific deploy status updates (#56)<commit_after>'use strict';

var RSVP = require('rsvp');
var prepareUpload = require('../../prepareUpload');
var utils = require('../../utils');
var chalk = require('chalk');
var ProgressBar = require('progress');
var api = require('../../api');
var _ = require('lodash');
var FirebaseError = require('../../error');

module.exports = function(context, options, payload) {
  var local = context.hosting;

  if (!payload.hosting) {
    return RSVP.resolve();
  }

  utils.logBullet(chalk.bold.cyan('hosting:') + ' preparing ' + chalk.bold(payload.hosting.public) + ' directory for upload...');
  return prepareUpload(options, payload.hosting).then(function(upload) {
    if (!upload.foundIndex) {
      utils.logWarning(chalk.bold('Warning:') + ' Public directory does not contain index.html');
    }

    if (!upload.manifest.length) {
      return utils.reject('Must have at least one file in public directory to deploy.', {exit: 1});
    }

    _.assign(payload.hosting, {
      version: local.versionId,
      prefix: local.versionId + '/',
      manifest: upload.manifest.map(function(file) {
        return {path: file, object: file};
      })
    });

    return new RSVP.Promise(function(resolve, reject) {
      var lastCount = 0;
      var lastPercent = 0;
      var bar;
      if (!options.nonInteractive && process.stderr) {
        bar = new ProgressBar(chalk.bold('Uploading:') + ' [:bar] :percent', {
          total: upload.manifest.length,
          width: 40,
          complete: chalk.green('='),
          incomplete: ' ',
          clear: true
        });
      } else {
        process.stdout.write(chalk.cyan.bold('\ni') + chalk.bold('  Progress: ['));
      }

      local.versionRef.on('value', function(snap) {
        var status = snap.child('status').val();
        switch (status) {
        case 'deploying':
          var uc = snap.child('uploadedCount').val() || 0;
          var percent = Math.round(100.0 * uc / upload.manifest.length);
          if (bar) {
            bar.tick(uc - lastCount);
          } else {
            process.stdout.write(_.repeat(chalk.green('.'), percent - lastPercent));
            lastPercent = percent;
          }
          lastCount = uc;
          break;
        case 'deployed':
          if (bar) {
            bar.terminate();
          } else {
            process.stdout.write(chalk.bold(']') + '\n\n');
          }
          utils.logSuccess(chalk.bold.green('hosting:') + ' ' + upload.manifest.length + ' files uploaded successfully');
          local.versionRef.off('value');
          resolve();
          break;
        case 'removed':
          reject(new FirebaseError('Not Implemented', {
            exit: 2,
            context: snap.val()
          }));
          break;
        case null:
          break;
        default:
          var msg = 'File upload failed';
          if (snap.hasChild('statusMessage')) {
            msg += ': ' + snap.child('statusMessage').val();
          }

          reject(new FirebaseError(msg, {
            exit: 2,
            context: snap.val()
          }));
        }
      });

      api.request('PUT', '/v1/hosting/' + options.instance + '/uploads/' + local.versionId, {
        auth: true,
        query: {
          fileCount: upload.manifest.length,
          message: options.message
        },
        files: {
          site: {
            filename: 'site.tar.gz',
            stream: upload.stream,
            contentType: 'application/x-gzip',
            knownLength: upload.size
          }
        },
        origin: api.deployOrigin
      }).catch(reject);
    });
  });
};
<|endoftext|>


<commit_before>var Utils         = require("../../utils")
  , AbstractQuery = require('../abstract/query')

module.exports = (function() {
  var Query = function(database, sequelize, callee, options) {
    this.database = database
    this.sequelize = sequelize
    this.callee = callee
    this.options = Utils._.extend({
      logging: console.log,
      plain: false,
      raw: false
    }, options || {})

    this.checkLoggingOption()
  }
  Utils.inherit(Query, AbstractQuery)

  Query.prototype.getInsertIdField = function() {
    return 'lastID'
  }

  Query.prototype.run = function(sql) {
    var self = this

    this.sql = sql

    if (this.options.logging !== false) {
      this.options.logging('Executing: ' + this.sql)
    }

    var columnTypes = {}
    this.database.serialize(function() {
      var executeSql = function() {
        self.database[getDatabaseMethod.call(self)](self.sql, function(err, results) {
          // allow clients to listen to sql to do their own logging or whatnot
          self.emit('sql', self.sql)
          this.columnTypes = columnTypes;
          err ? onFailure.call(self, err) : onSuccess.call(self, results, this)
        })
      };

      if ((getDatabaseMethod.call(self) === 'all') && /select\s.*?\sfrom\s+([^ ;]+)/i.test(self.sql)) {
        var tableName = RegExp.$1;

        if (tableName !== 'sqlite_master') {
          // get the column types
          self.database.all("PRAGMA table_info(" + tableName + ")", function(err, results) {
            if (!err) {
              for (var i=0, l=results.length; i<l; i++) {
                columnTypes[results[i].name] = results[i].type
              }
            }
            executeSql()
          });
        } else {
          executeSql()
        }
      } else {
        executeSql()
      }
    })

    return this
  }

  //private

  var getDatabaseMethod = function() {
    if (this.send('isInsertQuery') || this.send('isUpdateQuery') || (this.sql.toLowerCase().indexOf('CREATE TEMPORARY TABLE'.toLowerCase()) !== -1)) {
      return 'run'
    } else {
      return 'all'
    }
  }

  var onSuccess = function(results, metaData) {
    var result = this.callee

    // add the inserted row id to the instance
    if (this.send('isInsertQuery', results, metaData)) {
      this.send('handleInsertQuery', results, metaData)
    }

    if (this.sql.indexOf('sqlite_master') !== -1) {
      result = results.map(function(resultSet) { return resultSet.name })
    } else if (this.send('isSelectQuery')) {
      if(!this.options.raw) {
        results = results.map(function(result) {
          for (var name in result) {
            if (result.hasOwnProperty(name) && metaData.columnTypes[name]) {
              if (metaData.columnTypes[name] === 'DATETIME') {
                // we need to convert the timestamps into actual date objects
                var val = result[name]
                if (val !== null) {
                  result[name] = new Date(val+'Z') // Z means UTC
                }
              } else if (metaData.columnTypes[name].lastIndexOf('BLOB') !== -1) {
                result[name] = new Buffer(result[name])
              }
            }
          }
          return result
        })
      }

      result = this.send('handleSelectQuery', results)
    } else if (this.send('isShowOrDescribeQuery')) {
      result = results
    } else if (this.sql.indexOf('PRAGMA INDEX_LIST') !== -1) {
      // this is the sqlite way of getting the indexes of a table
      result = results.map(function(result) {
        return {
          name:       result.name,
          tableName:  result.name.split('_')[0],
          unique:     (result.unique === 0)
        }
      })
    } else if (this.sql.indexOf('PRAGMA TABLE_INFO') !== -1) {
      // this is the sqlite way of getting the metadata of a table
      result = {}

      results.forEach(function(_result) {
        result[_result.name] = {
          type:         _result.type,
          allowNull:    (_result.notnull === 0),
          defaultValue: _result.dflt_value
        }

        if (result[_result.name].type === 'TINYINT(1)') {
          result[_result.name].defaultValue = { '0': false, '1': true }[result[_result.name].defaultValue]
        }

        if (result[_result.name].defaultValue === undefined) {
          result[_result.name].defaultValue = null
        }

        if (typeof result[_result.name].defaultValue === 'string') {
          result[_result.name].defaultValue = result[_result.name].defaultValue.replace(/'/g, "")
        }
      })
    } else if (this.sql.indexOf('PRAGMA foreign_keys;') !== -1) {
      result = results[0]
    } else if (this.sql.indexOf('PRAGMA foreign_keys') !== -1) {
      result = results
    }

    this.emit('success', result)
  }

  var onFailure = function(err) {
    this.emit('error', err, this.callee)
  }

  return Query
})()
<commit_msg>Stop setting global variable 'columnTypes' on error<commit_after>var Utils         = require("../../utils")
  , AbstractQuery = require('../abstract/query')

module.exports = (function() {
  var Query = function(database, sequelize, callee, options) {
    this.database = database
    this.sequelize = sequelize
    this.callee = callee
    this.options = Utils._.extend({
      logging: console.log,
      plain: false,
      raw: false
    }, options || {})

    this.checkLoggingOption()
  }
  Utils.inherit(Query, AbstractQuery)

  Query.prototype.getInsertIdField = function() {
    return 'lastID'
  }

  Query.prototype.run = function(sql) {
    var self = this

    this.sql = sql

    if (this.options.logging !== false) {
      this.options.logging('Executing: ' + this.sql)
    }

    var columnTypes = {}
    this.database.serialize(function() {
      var executeSql = function() {
        self.database[getDatabaseMethod.call(self)](self.sql, function(err, results) {
          // allow clients to listen to sql to do their own logging or whatnot
          self.emit('sql', self.sql)

          if (err) {
            onFailure.call(self, err)
          } else {
            this.columnTypes = columnTypes
            onSuccess.call(self, results, this)
          }
        })
      };

      if ((getDatabaseMethod.call(self) === 'all') && /select\s.*?\sfrom\s+([^ ;]+)/i.test(self.sql)) {
        var tableName = RegExp.$1;

        if (tableName !== 'sqlite_master') {
          // get the column types
          self.database.all("PRAGMA table_info(" + tableName + ")", function(err, results) {
            if (!err) {
              for (var i=0, l=results.length; i<l; i++) {
                columnTypes[results[i].name] = results[i].type
              }
            }
            executeSql()
          });
        } else {
          executeSql()
        }
      } else {
        executeSql()
      }
    })

    return this
  }

  //private

  var getDatabaseMethod = function() {
    if (this.send('isInsertQuery') || this.send('isUpdateQuery') || (this.sql.toLowerCase().indexOf('CREATE TEMPORARY TABLE'.toLowerCase()) !== -1)) {
      return 'run'
    } else {
      return 'all'
    }
  }

  var onSuccess = function(results, metaData) {
    var result = this.callee

    // add the inserted row id to the instance
    if (this.send('isInsertQuery', results, metaData)) {
      this.send('handleInsertQuery', results, metaData)
    }

    if (this.sql.indexOf('sqlite_master') !== -1) {
      result = results.map(function(resultSet) { return resultSet.name })
    } else if (this.send('isSelectQuery')) {
      if(!this.options.raw) {
        results = results.map(function(result) {
          for (var name in result) {
            if (result.hasOwnProperty(name) && metaData.columnTypes[name]) {
              if (metaData.columnTypes[name] === 'DATETIME') {
                // we need to convert the timestamps into actual date objects
                var val = result[name]
                if (val !== null) {
                  result[name] = new Date(val+'Z') // Z means UTC
                }
              } else if (metaData.columnTypes[name].lastIndexOf('BLOB') !== -1) {
                result[name] = new Buffer(result[name])
              }
            }
          }
          return result
        })
      }

      result = this.send('handleSelectQuery', results)
    } else if (this.send('isShowOrDescribeQuery')) {
      result = results
    } else if (this.sql.indexOf('PRAGMA INDEX_LIST') !== -1) {
      // this is the sqlite way of getting the indexes of a table
      result = results.map(function(result) {
        return {
          name:       result.name,
          tableName:  result.name.split('_')[0],
          unique:     (result.unique === 0)
        }
      })
    } else if (this.sql.indexOf('PRAGMA TABLE_INFO') !== -1) {
      // this is the sqlite way of getting the metadata of a table
      result = {}

      results.forEach(function(_result) {
        result[_result.name] = {
          type:         _result.type,
          allowNull:    (_result.notnull === 0),
          defaultValue: _result.dflt_value
        }

        if (result[_result.name].type === 'TINYINT(1)') {
          result[_result.name].defaultValue = { '0': false, '1': true }[result[_result.name].defaultValue]
        }

        if (result[_result.name].defaultValue === undefined) {
          result[_result.name].defaultValue = null
        }

        if (typeof result[_result.name].defaultValue === 'string') {
          result[_result.name].defaultValue = result[_result.name].defaultValue.replace(/'/g, "")
        }
      })
    } else if (this.sql.indexOf('PRAGMA foreign_keys;') !== -1) {
      result = results[0]
    } else if (this.sql.indexOf('PRAGMA foreign_keys') !== -1) {
      result = results
    }

    this.emit('success', result)
  }

  var onFailure = function(err) {
    this.emit('error', err, this.callee)
  }

  return Query
})()
<|endoftext|>


<commit_before>import Expo from 'expo';
import App from '../../../../App';

Expo.registerRootComponent(App);
<commit_msg>Keep apps from sleeping the screen when they're foregrounded in dev mode.<commit_after>import Expo, {
  Components
} from 'expo';
import App from '../../../../App';
import React from 'react';
import {
  View
} from 'react-native';

// we don't want this to require transformation
class AwakeApp extends React.Component {
  render() {
    return React.createElement(
      View, {
        style: {
          flex: 1,
        }
      },
      React.createElement(App, null),
      React.createElement(Components.KeepAwake, null),
    );
  }
}

Expo.registerRootComponent(AwakeApp);
<|endoftext|>


<commit_before>import 'url-polyfill';

import { getAttributes } from '@carbon/icon-helpers';
import Prism from 'prismjs';
import React, { useState } from 'react';
import ReactDOM from 'react-dom';
import meta from '../../build-info.json';

const GITHUB_ICON_URL =
  'https://github.com/IBM/carbon-elements/tree/master/packages/icons/src/svg';

function App({ meta }) {
  const headers = ['Name', 'Size', 'Preview', 'GitHub', 'Issues', 'Path'];

  return (
    <React.Fragment>

Icons

Usage

              Icons in Carbon are now provided through a set of packages that
              let you use icons in various frameworks. We currently support:

                Vanilla

                  Angular

                React

                Vue

              In order to use icons in alongside these packages, you will need a
              couple of pieces of information, namely the icon size and name.
              For most product UIs, you will want to use the 16x16 icons.

              Note: You can share links to specific icons by clicking on the
              name of an icon in the table below and sharing that URL with a
              collaborator.

              In order to make use of an icon, you should look at the{' '}
              Path header. This header will provide you with
              the path to import the module in code. In general, the structure
              of how to import an icon will follow:

              <code
                className="language-js"
                dangerouslySetInnerHTML={{
                  __html: Prism.highlight(
                    `import IconName from '@carbon/icon-<package>/es/<path-to-icon>/<size>';`,
                    Prism.languages.javascript,
                    'javascript'
                  ),
                }}
              />

              For example, if I wanted to import the add{' '}
              icon in React, it would look like:

              <code
                className="language-js"
                dangerouslySetInnerHTML={{
                  __html: Prism.highlight(
                    `import IconName from '@carbon/icon-react/es/add/16';`,
                    Prism.languages.javascript,
                    'javascript'
                  ),
                }}
              />

              The path information comes from the table below under the{' '}
              Path header. If you would like to use CommonJS or
              UMD modules, you can replace the path value of es{' '}
              with either lib or umd respectively.

              For specific guidance on how to use these icons, checkout each
              package's README to learn more!

                {meta.map(info => {
                  const {
                    basename,
                    descriptor,
                    filename,
                    moduleName,
                    original,
                    outputOptions,
                    prefix,
                    size,
                  } = info;
                  const { attrs } = descriptor;
                  const svg = js2svg(descriptor);
                  const name = original
                    ? prefix.join('/') +
                      '/' +
                      basename +
                      ` (Downsized to ${size})`
                    : prefix.join('/') + '/' + basename;
                  const id = window.encodeURIComponent(name);
                  const source = [GITHUB_ICON_URL, ...prefix, filename].join(
                    '/'
                  );

                  return (

                        <a href={`#${id}`}>{name}

                      {`${attrs.width}x${
                        attrs.height
                      }`}

{svg}

                          Source

                          Create

                          {outputOptions.file}

                  );
                })}

    </React.Fragment>
  );
}

function Table({ children, headers }) {
  return (

          {headers.map(header => (
            {header}
          ))}

{children}

  );
}

function render() {
  ReactDOM.render(<App meta={meta} />, document.getElementById('root'));
}

function js2svg(descriptor) {
  const { elem, attrs = {}, content = [] } = descriptor;
  let attributes = attrs;

  if (elem === 'svg') {
    const { style, ...iconAttributes } = getAttributes(attrs);
    attributes = {
      ...iconAttributes,
      style: style
        .split(';')
        .map(declaration => {
          const [property, value] = declaration
            .split(':')
            .map(string => string.trim());
          return {
            [property]: value,
          };
        })
        .reduce(
          (acc, declaration) => ({
            ...acc,
            ...declaration,
          }),
          {}
        ),
    };
  }

  return React.createElement(elem, format(attributes), ...content.map(js2svg));
}

function format(attrs) {
  const { 'fill-rule': fillRule, ...rest } = attrs;
  return {
    ...rest,
    fillRule,
  };
}

function getBugTemplate(info, source) {
  const url = new URL('https://github.com/IBM/carbon-elements/issues/new');
  const params = new URLSearchParams();
  params.append('title', `🔍 Visual bug for the \`${info.filename}\` icon`);
  params.append(
    'body',
    `

There is an issue for the \`${
      info.basename
    }\` icon when viewing [the elements demo](https://ibm.github.io/carbon-elements/icons/examples/esm/index.html).

The source for this icon is available [here](${source}).

## Detailed description

> Describe in detail the issue you're having.

> Is this a feature request (new component, new icon), a bug, or a general issue?

> Is this issue related to a specific component?

> What did you expect to happen? What happened instead? What would you like to see changed?

> What browser are you working in?

> What version of the Carbon Design System are you using?

> What offering/product do you work on? Any pressing ship or release dates we should be aware of?

## Steps to reproduce the issue

1. Step one
2. Step two
3. Step three
4. etc.

## Additional information

- Screenshots or code
- Notes
`
  );
  url.search = params;
  return url.href;
}

render();

if (module.hot) {
  module.hot.dispose(() => {
    render();
  });
}
<commit_msg>docs(icons): update source & repo links on carbon elements demo page (#4852)<commit_after>import 'url-polyfill';

import { getAttributes } from '@carbon/icon-helpers';
import Prism from 'prismjs';
import React, { useState } from 'react';
import ReactDOM from 'react-dom';
import meta from '../../build-info.json';

const GITHUB_ICON_URL =
  'https://github.com/carbon-design-system/carbon/tree/master/packages/icons/svg';

function App({ meta }) {
  const headers = ['Name', 'Size', 'Preview', 'GitHub', 'Issues', 'Path'];

  return (
    <React.Fragment>

Icons

Usage

              Icons in Carbon are now provided through a set of packages that
              let you use icons in various frameworks. We currently support:

                Vanilla

                  Angular

                React

                Vue

              In order to use icons in alongside these packages, you will need a
              couple of pieces of information, namely the icon size and name.
              For most product UIs, you will want to use the 16x16 icons.

              Note: You can share links to specific icons by clicking on the
              name of an icon in the table below and sharing that URL with a
              collaborator.

              In order to make use of an icon, you should look at the{' '}
              Path header. This header will provide you with
              the path to import the module in code. In general, the structure
              of how to import an icon will follow:

              <code
                className="language-js"
                dangerouslySetInnerHTML={{
                  __html: Prism.highlight(
                    `import IconName from '@carbon/icon-<package>/es/<path-to-icon>/<size>';`,
                    Prism.languages.javascript,
                    'javascript'
                  ),
                }}
              />

              For example, if I wanted to import the add{' '}
              icon in React, it would look like:

              <code
                className="language-js"
                dangerouslySetInnerHTML={{
                  __html: Prism.highlight(
                    `import IconName from '@carbon/icon-react/es/add/16';`,
                    Prism.languages.javascript,
                    'javascript'
                  ),
                }}
              />

              The path information comes from the table below under the{' '}
              Path header. If you would like to use CommonJS or
              UMD modules, you can replace the path value of es{' '}
              with either lib or umd respectively.

              For specific guidance on how to use these icons, checkout each
              package's README to learn more!

                {meta.map(info => {
                  const {
                    basename,
                    descriptor,
                    filename,
                    moduleName,
                    original,
                    outputOptions,
                    prefix,
                    size,
                  } = info;
                  const { attrs } = descriptor;
                  const svg = js2svg(descriptor);
                  const name = original
                    ? prefix.join('/') +
                      '/' +
                      basename +
                      ` (Downsized to ${size})`
                    : prefix.join('/') + '/' + basename;
                  const id = window.encodeURIComponent(name);
                  const source = [GITHUB_ICON_URL, ...prefix, filename].join(
                    '/'
                  );

                  return (

                        <a href={`#${id}`}>{name}

                      {`${attrs.width}x${
                        attrs.height
                      }`}

{svg}

                          Source

                          Create

                          {outputOptions.file}

                  );
                })}

    </React.Fragment>
  );
}

function Table({ children, headers }) {
  return (

          {headers.map(header => (
            {header}
          ))}

{children}

  );
}

function render() {
  ReactDOM.render(<App meta={meta} />, document.getElementById('root'));
}

function js2svg(descriptor) {
  const { elem, attrs = {}, content = [] } = descriptor;
  let attributes = attrs;

  if (elem === 'svg') {
    const { style, ...iconAttributes } = getAttributes(attrs);
    attributes = {
      ...iconAttributes,
      style: style
        .split(';')
        .map(declaration => {
          const [property, value] = declaration
            .split(':')
            .map(string => string.trim());
          return {
            [property]: value,
          };
        })
        .reduce(
          (acc, declaration) => ({
            ...acc,
            ...declaration,
          }),
          {}
        ),
    };
  }

  return React.createElement(elem, format(attributes), ...content.map(js2svg));
}

function format(attrs) {
  const { 'fill-rule': fillRule, ...rest } = attrs;
  return {
    ...rest,
    fillRule,
  };
}

function getBugTemplate(info, source) {
  const url = new URL('https://github.com/carbon-design-system/carbon/issues/new');
  const params = new URLSearchParams();
  params.append('title', `🔍 Visual bug for the \`${info.filename}\` icon`);
  params.append(
    'body',
    `

There is an issue for the \`${
      info.basename
    }\` icon when viewing [the elements demo](https://carbon-elements.netlify.com/icons/examples/preview/).

The source for this icon is available [here](${source}).

## Detailed description

> Describe in detail the issue you're having.

> Is this a feature request (new component, new icon), a bug, or a general issue?

> Is this issue related to a specific component?

> What did you expect to happen? What happened instead? What would you like to see changed?

> What browser are you working in?

> What version of the Carbon Design System are you using?

> What offering/product do you work on? Any pressing ship or release dates we should be aware of?

## Steps to reproduce the issue

1. Step one
2. Step two
3. Step three
4. etc.

## Additional information

- Screenshots or code
- Notes
`
  );
  url.search = params;
  return url.href;
}

render();

if (module.hot) {
  module.hot.dispose(() => {
    render();
  });
}
<|endoftext|>


<commit_before>import React, { useEffect, useState, useRef } from 'react';
import { useTracking } from "./analyticsEvents";
import { hookToHoc } from "./hocUtils";

function useEventListener(eventName, handler, element = window){
  // Create a ref that stores handler
  const savedHandler = useRef();

  // Update ref.current value if handler changes.
  // This allows our effect below to always get latest handler ...
  // ... without us needing to pass it in effect deps array ...
  // ... and potentially cause effect to re-run every render.
  useEffect(() => {
    savedHandler.current = handler;
  }, [handler]);

  useEffect(
    () => {
      // Make sure element supports addEventListener
      // On
      const isSupported = element && element.addEventListener;
      if (!isSupported) console.log("Error: eventListener not available");

      // Create event listener that calls handler function stored in ref
      const eventListener = event => savedHandler.current(event);

      // Add event listener
      element.addEventListener(eventName, eventListener);

      // Remove event listener on cleanup
      return () => {
        element.removeEventListener(eventName, eventListener);
      };
    },
    [eventName, element] // Re-run if eventName or element changes
  );
}

export function useBeforeUnloadTracking() {
  const { captureEvent } = useTracking()
  const trackBeforeUnload = () => captureEvent("beforeUnloadFired")

  useEventListener('beforeunload', trackBeforeUnload)
}

export function usePageVisibility() {
  const { captureEvent } = useTracking()
  const [pageIsVisible, setPageIsVisible] = useState(!document.hidden)
  const [pageVisibilityState, setPageVisibilityState] = useState(document.visibilityState)

  function handleVisibilityChange() {
    setPageIsVisible(!document.hidden)
    setPageVisibilityState(document.visibilityState)
    console.log({isVisible: pageIsVisible, visibilityState: pageVisibilityState});
    captureEvent("pageVisibilityChange", {isVisible: pageIsVisible, visibilityState: pageVisibilityState});
  }

  useEventListener('visibilitychange', handleVisibilityChange)

  return { pageIsVisible, pageVisibilityState }
}

export function useIdleActivityTimer(timeoutInSeconds=60) {
    const { captureEvent } = useTracking("activityDetection")
    const [userIsActive, setUserIsActive] = useState(true)
    const countdownTimer = useRef(null)

    useEventListener("mousemove", reset)
    useEventListener("keypress", reset)
    useEventListener("scroll", reset)

    function inactivityAlert() {
        captureEvent("activityDetection", {state: "inactive"})
        console.log({"activityDetection": {state: "inactive"}})

        setUserIsActive(false)
    }

    function reset() {
        if (!userIsActive) {
            captureEvent("activityDetection", {state: "active"})
          console.log({"activityDetection": {state: "active"}})
        }
        setUserIsActive(true)
        clearTimeout(countdownTimer.current)
        countdownTimer.current = setTimeout(inactivityAlert, timeoutInSeconds*1000) //setTimeout uses milliseconds
    }

    useEffect(() => {
        reset()
        return () => clearTimeout(countdownTimer.current)
    }, [])

    return { userIsActive }
};

export function useCountUpTimer (incrementsInSeconds=[10, 30], switchIncrement=60) {
    const { captureEvent } = useTracking("timerEvent")
    const [seconds, setSeconds] = useState(0)
    const [isActive, setIsActive] = useState(true)
    const [smallIncrementInSeconds, largeIncrementInSeconds] = incrementsInSeconds

    function setTimerState(state) {
        setIsActive(state)
    }

    function reset() {
        setSeconds(0)
        setIsActive(false)
    }

    useEffect(() => {
        let interval = null;
        let increment = smallIncrementInSeconds

        if (isActive) {
            if (seconds < switchIncrement ) {increment = smallIncrementInSeconds}
            else {increment = largeIncrementInSeconds}
            interval = setInterval(() => {
                setSeconds(seconds => seconds + increment)
                captureEvent("timerEvent", {seconds, increment: increment})
            }, increment*1000) //setInterval uses milliseconds
        } else if (!isActive && seconds !== 0) {
            clearInterval(interval)
        }
        return () => clearInterval(interval)
    }, [isActive, seconds])

    return { seconds, isActive, setTimerState, reset }
}

export const withCountUpTimerActive = hookToHoc(useCountUpTimerActive)

export function useCombinedAnalyticsHooks() {
  useBeforeUnloadTracking()
  const { pageIsVisible, pageVisibilityState } = usePageVisibility()
  const { userIsActive } = useIdleActivityTimer(60)
  const { setTimerState } = useCountUpTimer([10, 30], 60)

  useEffect( () => {
    setTimerState(userIsActive && pageIsVisible)
    console.log({combined: {timerActive: userIsActive && pageIsVisible.current, userIsActive, pageIsVisible, pageVisibilityState}})
  }, [pageIsVisible.current, userIsActive,])

}

export const withCombinedAnalyticsHooks = hookToHoc(useCombinedAnalyticsHooks)
<commit_msg>Get the activeOnly timer working properly. - usePageVisibility hook implemented with useState to properly propagate state change - rename userIdleActivity to useIdlenessDetection, change from userIsActive to userIsIdle - countUpTimer logic is improved<commit_after>import React, { useEffect, useState, useRef } from 'react';
import { useTracking } from "./analyticsEvents";
import { hookToHoc } from "./hocUtils";

function useEventListener(eventName, handler, element = window){
  // Create a ref that stores handler
  const savedHandler = useRef();

  // Update ref.current value if handler changes.
  // This allows our effect below to always get latest handler ...
  // ... without us needing to pass it in effect deps array ...
  // ... and potentially cause effect to re-run every render.
  useEffect(() => {
    savedHandler.current = handler;
  }, [handler]);

  useEffect(
    () => {
      // Make sure element supports addEventListener
      // On
      const isSupported = element && element.addEventListener;
      // eslint-disable-next-line no-console
      if (!isSupported) console.log("Error: eventListener not available");

      // Create event listener that calls handler function stored in ref
      const eventListener = event => savedHandler.current(event);

      // Add event listener
      element.addEventListener(eventName, eventListener);

      // Remove event listener on cleanup
      return () => {
        element.removeEventListener(eventName, eventListener);
      };
    },
    [eventName, element] // Re-run if eventName or element changes
  );
}

export function useBeforeUnloadTracking() {
  const { captureEvent } = useTracking()
  const trackBeforeUnload = () => captureEvent("beforeUnloadFired")

  useEventListener('beforeunload', trackBeforeUnload)
}

export function usePageVisibility() {
  const { captureEvent } = useTracking()
  const [pageIsVisible, setPageIsVisible] = useState(!document.hidden)
  const [pageVisibilityState, setPageVisibilityState] = useState(document.visibilityState)

  function handleVisibilityChange() {
    const isVisible = !document.hidden
    const visibilityState = document.visibilityState
    setPageIsVisible(isVisible) //these aren't accessible till re-render or something
    setPageVisibilityState(visibilityState)
    captureEvent("pageVisibilityChange", {isVisible, visibilityState});
  }

  useEventListener('visibilitychange', handleVisibilityChange)

  return { pageIsVisible, pageVisibilityState }
}

export function useIdlenessDetection(timeoutInSeconds=60) {
    const { captureEvent } = useTracking("idlenessDetection")
    const [userIsIdle, setUserIsIdle] = useState(false)
    const countdownTimer = useRef(null)

    useEventListener("mousemove", reset)
    useEventListener("keypress", reset)
    useEventListener("scroll", reset)

    function inactivityAlert() {
        captureEvent("idlenessDetection", {state: "inactive"})
        setUserIsIdle(true)
    }

    function reset() {
      const prevUserIsIdle = userIsIdle //so can do this real quick?
      setUserIsIdle(false)
      clearTimeout(countdownTimer.current)
      countdownTimer.current = setTimeout(inactivityAlert, timeoutInSeconds*1000) //setTimeout uses milliseconds
      if (prevUserIsIdle) captureEvent("idlenessDetection", {state: "active"})
    }

    useEffect(() => {
        reset()
        return () => clearTimeout(countdownTimer.current)
    }, [])

    return { userIsIdle }
}

export function useCountUpTimer (incrementsInSeconds=[10, 30], switchIncrement=60) {
    const { captureEvent } = useTracking("timerEvent")
    const [seconds, setSeconds] = useState(0)
    const [timerIsActive, setTimerIsActive] = useState(true)
    const [smallIncrementInSeconds, largeIncrementInSeconds] = incrementsInSeconds
    const intervalTimer = useRef(null)

    function reset() {
        setSeconds(0)
        setTimerIsActive(false)
    }

    useEffect(() => {
        if (timerIsActive) {
            const  increment = (seconds < switchIncrement ) ? smallIncrementInSeconds : largeIncrementInSeconds
            intervalTimer.current = setInterval(() => {
              setSeconds(seconds + increment)
              captureEvent("timerEvent", {seconds: seconds + increment, increment: increment})
            }, increment*1000) //setInterval uses milliseconds
        } else if (!timerIsActive && seconds !== 0) {
            clearInterval(intervalTimer.current)
        }
        return () => clearInterval(intervalTimer.current)
    }, [timerIsActive, setTimerIsActive, seconds])

    return { seconds, isActive: timerIsActive, setTimerIsActive, reset }
}

export function useCombinedAnalyticsHooks() {
  useBeforeUnloadTracking()
  const { pageIsVisible } = usePageVisibility()
  const { userIsIdle } = useIdlenessDetection(60)
  const { setTimerIsActive } = useCountUpTimer([10, 30], 60)

  useEffect( () => {
    setTimerIsActive(pageIsVisible && !userIsIdle); //disable timer whenever tab hidden or user inactive
  }, [pageIsVisible, userIsIdle])

}

export const withCombinedAnalyticsHooks = hookToHoc(useCombinedAnalyticsHooks)
<|endoftext|>