<commit_before>/* global HAS_REACT_18 */
const React = require(`react`)
const path = require(`path`)
const {
  renderToString,
  renderToStaticMarkup,
  renderToPipeableStream,
} = require(`react-dom/server`)
const { ServerLocation, Router, isRedirect } = require(`@gatsbyjs/reach-router`)
const merge = require(`deepmerge`)
const { StaticQueryContext } = require(`gatsby`)
const fs = require(`fs`)
const { WritableAsPromise } = require(`./server-utils/writable-as-promise`)

const { RouteAnnouncerProps } = require(`./route-announcer-props`)
const { apiRunner, apiRunnerAsync } = require(`./api-runner-ssr`)
const asyncRequires = require(`$virtual/async-requires`)
const { version: gatsbyVersion } = require(`gatsby/package.json`)
const { grabMatchParams } = require(`./find-path`)
const { headHandlerForSSR } = require(`./head/head-export-handler-for-ssr`)
const {
  SlicesResultsContext,
  SlicesContext,
  SlicesMapContext,
  SlicesPropsContext,
} = require(`./slice/context`)
const { ServerSliceRenderer } = require(`./slice/server-slice-renderer`)

// we want to force posix-style joins, so Windows doesn't produce backslashes for urls
const { join } = path.posix

// const testRequireError = require("./test-require-error")
// For some extremely mysterious reason, webpack adds the above module *after*
// this module so that when this code runs, testRequireError is undefined.
// So in the meantime, we'll just inline it.
const testRequireError = (moduleName, err) => {
  const regex = new RegExp(`Error: Cannot find module\\s.${moduleName}`)
  const firstLine = err.toString().split(`\n`)[0]
  return regex.test(firstLine)
}

let Html
try {
  Html = require(`../src/html`)
} catch (err) {
  if (testRequireError(`../src/html`, err)) {
    Html = require(`./default-html`)
  } else {
    throw err
  }
}

Html = Html && Html.__esModule ? Html.default : Html

const getPageDataPath = path => {
  const fixedPagePath = path === `/` ? `index` : path
  return join(`page-data`, fixedPagePath, `page-data.json`)
}

const createElement = React.createElement

export const sanitizeComponents = components => {
  const componentsArray = [].concat(components).flat(Infinity).filter(Boolean)

  return componentsArray.map(component => {
    // Ensure manifest is always loaded from content server
    // And not asset server when an assetPrefix is used
    if (__ASSET_PREFIX__ && component.props.rel === `manifest`) {
      return React.cloneElement(component, {
        href: component.props.href.replace(__ASSET_PREFIX__, ``),
      })
    }
    return component
  })
}

function deepMerge(a, b) {
  const combineMerge = (target, source, options) => {
    const destination = target.slice()

    source.forEach((item, index) => {
      if (typeof destination[index] === `undefined`) {
        destination[index] = options.cloneUnlessOtherwiseSpecified(
          item,
          options
        )
      } else if (options.isMergeableObject(item)) {
        destination[index] = merge(target[index], item, options)
      } else if (target.indexOf(item) === -1) {
        destination.push(item)
      }
    })
    return destination
  }

  return merge(a, b, { arrayMerge: combineMerge })
}

/**
Reorder headComponents so meta tags are always at the top and aren't missed by crawlers by being pushed down by large inline styles, etc.
@see https://github.com/gatsbyjs/gatsby/issues/22206
*/
export const reorderHeadComponents = headComponents => {
  const sorted = headComponents.sort((a, b) => {
    if (a.type && a.type === `meta` && !(b.type && b.type === `meta`)) {
      return -1
    }
    return 0
  })

  return sorted
}

const DEFAULT_CONTEXT = {
  // whether or not we're building the site now
  // usage in determining original build or engines
  isDuringBuild: false,
}

export default async function staticPage({
  pagePath,
  pageData,
  staticQueryContext,
  styles,
  scripts,
  reversedStyles,
  reversedScripts,
  inlinePageData = false,
  context = {},
  webpackCompilationHash,
  sliceData,
}) {
  const renderContext = Object.assign(DEFAULT_CONTEXT, context)

  // for this to work we need this function to be sync or at least ensure there is single execution of it at a time
  global.unsafeBuiltinUsage = []

  try {
    let bodyHtml = ``
    let headComponents = [
      <meta
        name="generator"
        content={`Gatsby ${gatsbyVersion}`}
        key={`generator-${gatsbyVersion}`}
      />,
    ]
    let htmlAttributes = {}
    let bodyAttributes = {}
    let preBodyComponents = []
    let postBodyComponents = []
    let bodyProps = {}

    function loadPageDataSync(_pagePath) {
      if (_pagePath === pagePath) {
        // no need to use fs if we are asking for pageData of current page
        return pageData
      }

      const pageDataPath = getPageDataPath(_pagePath)
      const pageDataFile = join(process.cwd(), `public`, pageDataPath)
      try {
        // deprecation notice
        const myErrorHolder = {
          name: `Usage of loadPageDataSync for page other than currently generated page disables incremental html generation in future builds`,
        }
        Error.captureStackTrace(myErrorHolder, loadPageDataSync)
        global.unsafeBuiltinUsage.push(myErrorHolder.stack)
        const pageDataJson = fs.readFileSync(pageDataFile)
        return JSON.parse(pageDataJson)
      } catch (error) {
        // not an error if file is not found. There's just no page data
        return null
      }
    }

    const replaceBodyHTMLString = body => {
      bodyHtml = body
    }

    const setHeadComponents = components => {
      headComponents = headComponents.concat(sanitizeComponents(components))
    }

    const setHtmlAttributes = attributes => {
      // TODO - we should remove deep merges
      htmlAttributes = deepMerge(htmlAttributes, attributes)
    }

    const setBodyAttributes = attributes => {
      // TODO - we should remove deep merges
      bodyAttributes = deepMerge(bodyAttributes, attributes)
    }

    const setPreBodyComponents = components => {
      preBodyComponents = preBodyComponents.concat(
        sanitizeComponents(components)
      )
    }

    const setPostBodyComponents = components => {
      postBodyComponents = postBodyComponents.concat(
        sanitizeComponents(components)
      )
    }

    const setBodyProps = props => {
      // TODO - we should remove deep merges
      bodyProps = deepMerge({}, bodyProps, props)
    }

    const getHeadComponents = () => headComponents

    const replaceHeadComponents = components => {
      headComponents = sanitizeComponents(components)
    }

    const getPreBodyComponents = () => preBodyComponents

    const replacePreBodyComponents = components => {
      preBodyComponents = sanitizeComponents(components)
    }

    const getPostBodyComponents = () => postBodyComponents

    const replacePostBodyComponents = components => {
      postBodyComponents = sanitizeComponents(components)
    }

    const { componentChunkName, slicesMap } = pageData
    const pageComponent = await asyncRequires.components[componentChunkName]()

    headHandlerForSSR({
      pageComponent,
      setHeadComponents,
      staticQueryContext,
      pageData,
      pagePath,
    })

    class RouteHandler extends React.Component {
      render() {
        const props = {
          ...this.props,
          ...pageData.result,
          params: {
            ...grabMatchParams(this.props.location.pathname),
            ...(pageData.result?.pageContext?.__params || {}),
          },
        }

        const pageElement = createElement(pageComponent.default, props)

        const wrappedPage = apiRunner(
          `wrapPageElement`,
          { element: pageElement, props },
          pageElement,
          ({ result }) => {
            return { element: result, props }
          }
        ).pop()

        return wrappedPage
      }
    }

    const routerElement = (
      <ServerLocation url={`${__BASE_PATH__}${pagePath}`}>
        <Router id="gatsby-focus-wrapper" baseuri={__BASE_PATH__}>
          <RouteHandler path="/*" />
        </Router>
        <div {...RouteAnnouncerProps} />
      </ServerLocation>
    )

    const sliceProps = {}

    let body = apiRunner(
      `wrapRootElement`,
      { element: routerElement, pathname: pagePath },
      routerElement,
      ({ result }) => {
        return { element: result, pathname: pagePath }
      }
    ).pop()

    if (process.env.GATSBY_SLICES) {
      const slicesContext = {
        // if we're in build now, we know we're on the server
        // otherwise we're in an engine
        renderEnvironment: renderContext.isDuringBuild ? `server` : `engines`,
      }
      // if we're running in an engine, we need to manually wrap body with
      // the results context to pass the map of slice name to component/data/context
      if (slicesContext.renderEnvironment === `engines`) {
        // this is the same name used in the browser
        // since this immitates behavior
        const slicesDb = new Map()

        for (const sliceName of Object.values(slicesMap)) {
          const slice = sliceData[sliceName]
          const { default: SliceComponent } = await getPageChunk(slice)

          const sliceObject = {
            component: SliceComponent,
            sliceContext: slice.result.sliceContext,
            data: slice.result.data,
          }

          slicesDb.set(sliceName, sliceObject)
        }

        body = (
          <SlicesResultsContext.Provider value={slicesDb}>
            {body}
          </SlicesResultsContext.Provider>
        )
      }

      body = (
        <SlicesContext.Provider value={slicesContext}>
          <SlicesPropsContext.Provider value={sliceProps}>
            <SlicesMapContext.Provider value={slicesMap}>
              {body}
            </SlicesMapContext.Provider>
          </SlicesPropsContext.Provider>
        </SlicesContext.Provider>
      )
    }

    const bodyComponent = (
      <StaticQueryContext.Provider value={staticQueryContext}>
        {body}
      </StaticQueryContext.Provider>
    )

    // Let the site or plugin render the page component.
    await apiRunnerAsync(`replaceRenderer`, {
      bodyComponent,
      replaceBodyHTMLString,
      setHeadComponents,
      setHtmlAttributes,
      setBodyAttributes,
      setPreBodyComponents,
      setPostBodyComponents,
      setBodyProps,
      pathname: pagePath,
      pathPrefix: __PATH_PREFIX__,
    })

    // If no one stepped up, we'll handle it.
    if (!bodyHtml) {
      try {
        // react 18 enabled
        if (HAS_REACT_18) {
          const writableStream = new WritableAsPromise()
          const { pipe } = renderToPipeableStream(bodyComponent, {
            onAllReady() {
              pipe(writableStream)
            },
            onError(error) {
              writableStream.destroy(error)
            },
          })

          bodyHtml = await writableStream
        } else {
          bodyHtml = renderToString(bodyComponent)
        }
      } catch (e) {
        // ignore @reach/router redirect errors
        if (!isRedirect(e)) throw e
      }
    }

    apiRunner(`onRenderBody`, {
      setHeadComponents,
      setHtmlAttributes,
      setBodyAttributes,
      setPreBodyComponents,
      setPostBodyComponents,
      setBodyProps,
      pathname: pagePath,
      loadPageDataSync,
      bodyHtml,
      scripts,
      styles,
      pathPrefix: __PATH_PREFIX__,
    })

    reversedScripts.forEach(script => {
      // Add preload/prefetch <link>s magic comments
      if (script.shouldGenerateLink) {
        headComponents.push(
          <link
            as="script"
            rel={script.rel}
            key={script.name}
            href={`${__PATH_PREFIX__}/${script.name}`}
          />
        )
      }
    })

    reversedStyles.forEach(style => {
      // Add <link>s for styles that should be prefetched
      // otherwise, inline as a <style> tag

      if (style.rel === `prefetch`) {
        headComponents.push(
          <link
            as="style"
            rel={style.rel}
            key={style.name}
            href={`${__PATH_PREFIX__}/${style.name}`}
          />
        )
      } else {
        headComponents.unshift(
          <style
            data-href={`${__PATH_PREFIX__}/${style.name}`}
            data-identity={`gatsby-global-css`}
            dangerouslySetInnerHTML={{
              __html: style.content,
            }}
          />
        )
      }
    })

    // Add page metadata for the current page
    const windowPageData = `/*<![CDATA[*/window.pagePath="${pagePath}";${
      process.env.GATSBY_SLICES
        ? ``
        : `window.___webpackCompilationHash="${webpackCompilationHash}";`
    }${
      inlinePageData ? `window.pageData=${JSON.stringify(pageData)};` : ``
    }/*]]>*/`

    postBodyComponents.push(
      <script
        key={`script-loader`}
        id={`gatsby-script-loader`}
        dangerouslySetInnerHTML={{
          __html: windowPageData,
        }}
      />
    )

    if (process.env.GATSBY_SLICES) {
      postBodyComponents.push(
        createElement(ServerSliceRenderer, {
          sliceId: `_gatsby-scripts`,
        })
      )
    } else {
      const chunkMapping = require(`../public/chunk-map.json`)
      // restore the old behavior
      // Add chunk mapping metadata
      const scriptChunkMapping = `/*<![CDATA[*/window.___chunkMapping=${JSON.stringify(
        chunkMapping
      )};/*]]>*/`

      postBodyComponents.push(
        <script
          key={`chunk-mapping`}
          id={`gatsby-chunk-mapping`}
          dangerouslySetInnerHTML={{
            __html: scriptChunkMapping,
          }}
        />
      )

      let bodyScripts = []
      if (chunkMapping[`polyfill`]) {
        chunkMapping[`polyfill`].forEach(script => {
          const scriptPath = `${__PATH_PREFIX__}${script}`
          bodyScripts.push(
            <script key={scriptPath} src={scriptPath} noModule={true} />
          )
        })
      }

      // Filter out prefetched bundles as adding them as a script tag
      // would force high priority fetching.
      bodyScripts = bodyScripts.concat(
        scripts
          .filter(s => s.rel !== `prefetch`)
          .map(s => {
            const scriptPath = `${__PATH_PREFIX__}/${JSON.stringify(
              s.name
            ).slice(1, -1)}`
            return <script key={scriptPath} src={scriptPath} async />
          })
      )

      postBodyComponents.push(...bodyScripts)
    }

    headComponents = reorderHeadComponents(headComponents)

    apiRunner(`onPreRenderHTML`, {
      getHeadComponents,
      replaceHeadComponents,
      getPreBodyComponents,
      replacePreBodyComponents,
      getPostBodyComponents,
      replacePostBodyComponents,
      pathname: pagePath,
      pathPrefix: __PATH_PREFIX__,
    })

    const html = `<!DOCTYPE html>${renderToStaticMarkup(
      <Html
        {...bodyProps}
        headComponents={headComponents}
        htmlAttributes={htmlAttributes}
        bodyAttributes={bodyAttributes}
        preBodyComponents={preBodyComponents}
        postBodyComponents={postBodyComponents}
        body={bodyHtml}
        path={pagePath}
      />
    )}`

    return {
      html,
      unsafeBuiltinsUsage: global.unsafeBuiltinUsage,
      sliceData: sliceProps,
    }
  } catch (e) {
    e.unsafeBuiltinsUsage = global.unsafeBuiltinUsage
    throw e
  }
}

export function getPageChunk({ componentChunkName }) {
  return asyncRequires.components[componentChunkName]()
}

export { renderToPipeableStream } from "react-server-dom-webpack/writer.node.server"
export { StaticQueryContext, React }

export async function renderSlice({ slice, staticQueryContext, props = {} }) {
  const { default: SliceComponent } = await getPageChunk(slice)

  const sliceElement = (
    <StaticQueryContext.Provider value={staticQueryContext}>
      <SliceComponent sliceContext={slice.context} {...props} />
    </StaticQueryContext.Provider>
  )
  const sliceWrappedWithWrapRootElement = apiRunner(
    `wrapRootElement`,
    { element: sliceElement },
    sliceElement,
    ({ result }) => {
      return { element: result }
    }
  ).pop()

  const writableStream = new WritableAsPromise()
  const { pipe } = renderToPipeableStream(sliceWrappedWithWrapRootElement, {
    onAllReady() {
      pipe(writableStream)
    },
    onError(error) {
      writableStream.destroy(error)
    },
  })

  return await writableStream
}
<commit_msg>chore: provide slice rendering context to <HTML> (#36799)<commit_after>/* global HAS_REACT_18 */
const React = require(`react`)
const path = require(`path`)
const {
  renderToString,
  renderToStaticMarkup,
  renderToPipeableStream,
} = require(`react-dom/server`)
const { ServerLocation, Router, isRedirect } = require(`@gatsbyjs/reach-router`)
const merge = require(`deepmerge`)
const { StaticQueryContext } = require(`gatsby`)
const fs = require(`fs`)
const { WritableAsPromise } = require(`./server-utils/writable-as-promise`)

const { RouteAnnouncerProps } = require(`./route-announcer-props`)
const { apiRunner, apiRunnerAsync } = require(`./api-runner-ssr`)
const asyncRequires = require(`$virtual/async-requires`)
const { version: gatsbyVersion } = require(`gatsby/package.json`)
const { grabMatchParams } = require(`./find-path`)
const { headHandlerForSSR } = require(`./head/head-export-handler-for-ssr`)
const {
  SlicesResultsContext,
  SlicesContext,
  SlicesMapContext,
  SlicesPropsContext,
} = require(`./slice/context`)
const { ServerSliceRenderer } = require(`./slice/server-slice-renderer`)

// we want to force posix-style joins, so Windows doesn't produce backslashes for urls
const { join } = path.posix

// const testRequireError = require("./test-require-error")
// For some extremely mysterious reason, webpack adds the above module *after*
// this module so that when this code runs, testRequireError is undefined.
// So in the meantime, we'll just inline it.
const testRequireError = (moduleName, err) => {
  const regex = new RegExp(`Error: Cannot find module\\s.${moduleName}`)
  const firstLine = err.toString().split(`\n`)[0]
  return regex.test(firstLine)
}

let Html
try {
  Html = require(`../src/html`)
} catch (err) {
  if (testRequireError(`../src/html`, err)) {
    Html = require(`./default-html`)
  } else {
    throw err
  }
}

Html = Html && Html.__esModule ? Html.default : Html

const getPageDataPath = path => {
  const fixedPagePath = path === `/` ? `index` : path
  return join(`page-data`, fixedPagePath, `page-data.json`)
}

const createElement = React.createElement

export const sanitizeComponents = components => {
  const componentsArray = [].concat(components).flat(Infinity).filter(Boolean)

  return componentsArray.map(component => {
    // Ensure manifest is always loaded from content server
    // And not asset server when an assetPrefix is used
    if (__ASSET_PREFIX__ && component.props.rel === `manifest`) {
      return React.cloneElement(component, {
        href: component.props.href.replace(__ASSET_PREFIX__, ``),
      })
    }
    return component
  })
}

function deepMerge(a, b) {
  const combineMerge = (target, source, options) => {
    const destination = target.slice()

    source.forEach((item, index) => {
      if (typeof destination[index] === `undefined`) {
        destination[index] = options.cloneUnlessOtherwiseSpecified(
          item,
          options
        )
      } else if (options.isMergeableObject(item)) {
        destination[index] = merge(target[index], item, options)
      } else if (target.indexOf(item) === -1) {
        destination.push(item)
      }
    })
    return destination
  }

  return merge(a, b, { arrayMerge: combineMerge })
}

/**
Reorder headComponents so meta tags are always at the top and aren't missed by crawlers by being pushed down by large inline styles, etc.
@see https://github.com/gatsbyjs/gatsby/issues/22206
*/
export const reorderHeadComponents = headComponents => {
  const sorted = headComponents.sort((a, b) => {
    if (a.type && a.type === `meta` && !(b.type && b.type === `meta`)) {
      return -1
    }
    return 0
  })

  return sorted
}

const DEFAULT_CONTEXT = {
  // whether or not we're building the site now
  // usage in determining original build or engines
  isDuringBuild: false,
}

export default async function staticPage({
  pagePath,
  pageData,
  staticQueryContext,
  styles,
  scripts,
  reversedStyles,
  reversedScripts,
  inlinePageData = false,
  context = {},
  webpackCompilationHash,
  sliceData,
}) {
  const renderContext = Object.assign(DEFAULT_CONTEXT, context)

  // for this to work we need this function to be sync or at least ensure there is single execution of it at a time
  global.unsafeBuiltinUsage = []

  try {
    let bodyHtml = ``
    let headComponents = [
      <meta
        name="generator"
        content={`Gatsby ${gatsbyVersion}`}
        key={`generator-${gatsbyVersion}`}
      />,
    ]
    let htmlAttributes = {}
    let bodyAttributes = {}
    let preBodyComponents = []
    let postBodyComponents = []
    let bodyProps = {}

    function loadPageDataSync(_pagePath) {
      if (_pagePath === pagePath) {
        // no need to use fs if we are asking for pageData of current page
        return pageData
      }

      const pageDataPath = getPageDataPath(_pagePath)
      const pageDataFile = join(process.cwd(), `public`, pageDataPath)
      try {
        // deprecation notice
        const myErrorHolder = {
          name: `Usage of loadPageDataSync for page other than currently generated page disables incremental html generation in future builds`,
        }
        Error.captureStackTrace(myErrorHolder, loadPageDataSync)
        global.unsafeBuiltinUsage.push(myErrorHolder.stack)
        const pageDataJson = fs.readFileSync(pageDataFile)
        return JSON.parse(pageDataJson)
      } catch (error) {
        // not an error if file is not found. There's just no page data
        return null
      }
    }

    const replaceBodyHTMLString = body => {
      bodyHtml = body
    }

    const setHeadComponents = components => {
      headComponents = headComponents.concat(sanitizeComponents(components))
    }

    const setHtmlAttributes = attributes => {
      // TODO - we should remove deep merges
      htmlAttributes = deepMerge(htmlAttributes, attributes)
    }

    const setBodyAttributes = attributes => {
      // TODO - we should remove deep merges
      bodyAttributes = deepMerge(bodyAttributes, attributes)
    }

    const setPreBodyComponents = components => {
      preBodyComponents = preBodyComponents.concat(
        sanitizeComponents(components)
      )
    }

    const setPostBodyComponents = components => {
      postBodyComponents = postBodyComponents.concat(
        sanitizeComponents(components)
      )
    }

    const setBodyProps = props => {
      // TODO - we should remove deep merges
      bodyProps = deepMerge({}, bodyProps, props)
    }

    const getHeadComponents = () => headComponents

    const replaceHeadComponents = components => {
      headComponents = sanitizeComponents(components)
    }

    const getPreBodyComponents = () => preBodyComponents

    const replacePreBodyComponents = components => {
      preBodyComponents = sanitizeComponents(components)
    }

    const getPostBodyComponents = () => postBodyComponents

    const replacePostBodyComponents = components => {
      postBodyComponents = sanitizeComponents(components)
    }

    const { componentChunkName, slicesMap } = pageData
    const pageComponent = await asyncRequires.components[componentChunkName]()

    headHandlerForSSR({
      pageComponent,
      setHeadComponents,
      staticQueryContext,
      pageData,
      pagePath,
    })

    class RouteHandler extends React.Component {
      render() {
        const props = {
          ...this.props,
          ...pageData.result,
          params: {
            ...grabMatchParams(this.props.location.pathname),
            ...(pageData.result?.pageContext?.__params || {}),
          },
        }

        const pageElement = createElement(pageComponent.default, props)

        const wrappedPage = apiRunner(
          `wrapPageElement`,
          { element: pageElement, props },
          pageElement,
          ({ result }) => {
            return { element: result, props }
          }
        ).pop()

        return wrappedPage
      }
    }

    const routerElement = (
      <ServerLocation url={`${__BASE_PATH__}${pagePath}`}>
        <Router id="gatsby-focus-wrapper" baseuri={__BASE_PATH__}>
          <RouteHandler path="/*" />
        </Router>
        <div {...RouteAnnouncerProps} />
      </ServerLocation>
    )

    const sliceProps = {}

    let body = apiRunner(
      `wrapRootElement`,
      { element: routerElement, pathname: pagePath },
      routerElement,
      ({ result }) => {
        return { element: result, pathname: pagePath }
      }
    ).pop()

    const slicesContext = {
      // if we're in build now, we know we're on the server
      // otherwise we're in an engine
      renderEnvironment: renderContext.isDuringBuild ? `server` : `engines`,
    }
    if (process.env.GATSBY_SLICES) {
      // if we're running in an engine, we need to manually wrap body with
      // the results context to pass the map of slice name to component/data/context
      if (slicesContext.renderEnvironment === `engines`) {
        // this is the same name used in the browser
        // since this immitates behavior
        const slicesDb = new Map()

        for (const sliceName of Object.values(slicesMap)) {
          const slice = sliceData[sliceName]
          const { default: SliceComponent } = await getPageChunk(slice)

          const sliceObject = {
            component: SliceComponent,
            sliceContext: slice.result.sliceContext,
            data: slice.result.data,
          }

          slicesDb.set(sliceName, sliceObject)
        }

        body = (
          <SlicesResultsContext.Provider value={slicesDb}>
            {body}
          </SlicesResultsContext.Provider>
        )
      }

      body = (
        <SlicesContext.Provider value={slicesContext}>
          <SlicesPropsContext.Provider value={sliceProps}>
            <SlicesMapContext.Provider value={slicesMap}>
              {body}
            </SlicesMapContext.Provider>
          </SlicesPropsContext.Provider>
        </SlicesContext.Provider>
      )
    }

    const bodyComponent = (
      <StaticQueryContext.Provider value={staticQueryContext}>
        {body}
      </StaticQueryContext.Provider>
    )

    // Let the site or plugin render the page component.
    await apiRunnerAsync(`replaceRenderer`, {
      bodyComponent,
      replaceBodyHTMLString,
      setHeadComponents,
      setHtmlAttributes,
      setBodyAttributes,
      setPreBodyComponents,
      setPostBodyComponents,
      setBodyProps,
      pathname: pagePath,
      pathPrefix: __PATH_PREFIX__,
    })

    // If no one stepped up, we'll handle it.
    if (!bodyHtml) {
      try {
        // react 18 enabled
        if (HAS_REACT_18) {
          const writableStream = new WritableAsPromise()
          const { pipe } = renderToPipeableStream(bodyComponent, {
            onAllReady() {
              pipe(writableStream)
            },
            onError(error) {
              writableStream.destroy(error)
            },
          })

          bodyHtml = await writableStream
        } else {
          bodyHtml = renderToString(bodyComponent)
        }
      } catch (e) {
        // ignore @reach/router redirect errors
        if (!isRedirect(e)) throw e
      }
    }

    apiRunner(`onRenderBody`, {
      setHeadComponents,
      setHtmlAttributes,
      setBodyAttributes,
      setPreBodyComponents,
      setPostBodyComponents,
      setBodyProps,
      pathname: pagePath,
      loadPageDataSync,
      bodyHtml,
      scripts,
      styles,
      pathPrefix: __PATH_PREFIX__,
    })

    reversedScripts.forEach(script => {
      // Add preload/prefetch <link>s magic comments
      if (script.shouldGenerateLink) {
        headComponents.push(
          <link
            as="script"
            rel={script.rel}
            key={script.name}
            href={`${__PATH_PREFIX__}/${script.name}`}
          />
        )
      }
    })

    reversedStyles.forEach(style => {
      // Add <link>s for styles that should be prefetched
      // otherwise, inline as a <style> tag

      if (style.rel === `prefetch`) {
        headComponents.push(
          <link
            as="style"
            rel={style.rel}
            key={style.name}
            href={`${__PATH_PREFIX__}/${style.name}`}
          />
        )
      } else {
        headComponents.unshift(
          <style
            data-href={`${__PATH_PREFIX__}/${style.name}`}
            data-identity={`gatsby-global-css`}
            dangerouslySetInnerHTML={{
              __html: style.content,
            }}
          />
        )
      }
    })

    // Add page metadata for the current page
    const windowPageData = `/*<![CDATA[*/window.pagePath="${pagePath}";${
      process.env.GATSBY_SLICES
        ? ``
        : `window.___webpackCompilationHash="${webpackCompilationHash}";`
    }${
      inlinePageData ? `window.pageData=${JSON.stringify(pageData)};` : ``
    }/*]]>*/`

    postBodyComponents.push(
      <script
        key={`script-loader`}
        id={`gatsby-script-loader`}
        dangerouslySetInnerHTML={{
          __html: windowPageData,
        }}
      />
    )

    if (process.env.GATSBY_SLICES) {
      postBodyComponents.push(
        createElement(ServerSliceRenderer, {
          sliceId: `_gatsby-scripts`,
        })
      )
    } else {
      const chunkMapping = require(`../public/chunk-map.json`)
      // restore the old behavior
      // Add chunk mapping metadata
      const scriptChunkMapping = `/*<![CDATA[*/window.___chunkMapping=${JSON.stringify(
        chunkMapping
      )};/*]]>*/`

      postBodyComponents.push(
        <script
          key={`chunk-mapping`}
          id={`gatsby-chunk-mapping`}
          dangerouslySetInnerHTML={{
            __html: scriptChunkMapping,
          }}
        />
      )

      let bodyScripts = []
      if (chunkMapping[`polyfill`]) {
        chunkMapping[`polyfill`].forEach(script => {
          const scriptPath = `${__PATH_PREFIX__}${script}`
          bodyScripts.push(
            <script key={scriptPath} src={scriptPath} noModule={true} />
          )
        })
      }

      // Filter out prefetched bundles as adding them as a script tag
      // would force high priority fetching.
      bodyScripts = bodyScripts.concat(
        scripts
          .filter(s => s.rel !== `prefetch`)
          .map(s => {
            const scriptPath = `${__PATH_PREFIX__}/${JSON.stringify(
              s.name
            ).slice(1, -1)}`
            return <script key={scriptPath} src={scriptPath} async />
          })
      )

      postBodyComponents.push(...bodyScripts)
    }

    headComponents = reorderHeadComponents(headComponents)

    apiRunner(`onPreRenderHTML`, {
      getHeadComponents,
      replaceHeadComponents,
      getPreBodyComponents,
      replacePreBodyComponents,
      getPostBodyComponents,
      replacePostBodyComponents,
      pathname: pagePath,
      pathPrefix: __PATH_PREFIX__,
    })

    let htmlElement = (
      <Html
        {...bodyProps}
        headComponents={headComponents}
        htmlAttributes={htmlAttributes}
        bodyAttributes={bodyAttributes}
        preBodyComponents={preBodyComponents}
        postBodyComponents={postBodyComponents}
        body={bodyHtml}
        path={pagePath}
      />
    )

    if (process.env.GATSBY_SLICES) {
      htmlElement = (
        <SlicesContext.Provider value={slicesContext}>
          {htmlElement}
        </SlicesContext.Provider>
      )
    }

    const html = `<!DOCTYPE html>${renderToStaticMarkup(htmlElement)}`

    return {
      html,
      unsafeBuiltinsUsage: global.unsafeBuiltinUsage,
      sliceData: sliceProps,
    }
  } catch (e) {
    e.unsafeBuiltinsUsage = global.unsafeBuiltinUsage
    throw e
  }
}

export function getPageChunk({ componentChunkName }) {
  return asyncRequires.components[componentChunkName]()
}

export { renderToPipeableStream } from "react-server-dom-webpack/writer.node.server"
export { StaticQueryContext, React }

export async function renderSlice({ slice, staticQueryContext, props = {} }) {
  const { default: SliceComponent } = await getPageChunk(slice)

  const sliceElement = (
    <StaticQueryContext.Provider value={staticQueryContext}>
      <SliceComponent sliceContext={slice.context} {...props} />
    </StaticQueryContext.Provider>
  )
  const sliceWrappedWithWrapRootElement = apiRunner(
    `wrapRootElement`,
    { element: sliceElement },
    sliceElement,
    ({ result }) => {
      return { element: result }
    }
  ).pop()

  const writableStream = new WritableAsPromise()
  const { pipe } = renderToPipeableStream(sliceWrappedWithWrapRootElement, {
    onAllReady() {
      pipe(writableStream)
    },
    onError(error) {
      writableStream.destroy(error)
    },
  })

  return await writableStream
}
<|endoftext|>


<commit_before>#!/usr/bin/env node

// Dependencies
var BibleJS = require("bible.js")
  , Couleurs = require("couleurs")()
  , Debug = require("bug-killer")
  , RegexParser = require("regex-parser")
  , Ul = require("ul")
  , Yargs = require("yargs")
  , OS = require("os")
  , LeTable = require("le-table")
  , Fs = require("fs")
  , config = null
  ;

// Help output
const HELP = require("./docs/help")
    , SAMPLE_CONFIGURATION = require("./docs/sample-conf")
    , CONFIG_FILE_PATH = Ul.USER_DIR + "/.bible-config.json"
    , SUBMODULES_DIR = Ul.USER_DIR + "/.bible"
    ;

// CLI args parser
Yargs = Yargs.usage(HELP);
var Argv = Yargs.argv
  , language = Argv.lang || Argv.language
  , search = Argv.s || Argv.search
  , searchResultColor = null
  ;

// Set log level
Debug.config.logLevel = 3;

// Read the configuration file
try {
    config = require(CONFIG_FILE_PATH);
} catch (e) {
    if (e.code === "MODULE_NOT_FOUND") {
        Debug.log(
            "No configuration file was found. Initing the configuration file."
          , "warn"
        );
        Fs.writeFileSync(CONFIG_FILE_PATH, JSON.stringify(
            SAMPLE_CONFIGURATION, null, 4
        ));
        Debug.log(
            "The configuration file created successfully at the following location: "
          + CONFIG_FILE_PATH
          , "warn"
        );
        config = require(CONFIG_FILE_PATH);
    } else {
        Debug.log(
            "Cannot read the configuration file. Reason: " + e.code
          , "warn"
        );
    }
}

// Show the version
if (Argv.v || Argv.version) {
    return console.log(
        "Bible " + require("./package").version
      + "Bible.JS " + require("./package").dependencies["bible.js"]
    );
}

// Show help
var references = Argv._;
if (Argv.help ||  (!language && !references.length && !search)) {
    return console.log(Yargs.help());
}

// Try to get options from config as well
language = language || config.language;
searchResultColor = (
    Argv.rc || Argv.resultColor || config.resultColor
).split(/[ ,]+/)
config.searchLimit = config.searchLimit || 10;

// Table defaults
LeTable.defaults.marks = {
    nw: "┌"
  , n:  "─"
  , ne: "┐"
  , e:  "│"
  , se: "┘"
  , s:  "─"
  , sw: "└"
  , w:  "│"
  , b: " "
  , mt: "┬"
  , ml: "├"
  , mr: "┤"
  , mb: "┴"
  , mm: "┼"
};

// Parse result color
for (var i = 0; i < 3; ++i) {

    if (!searchResultColor[i]) {
        return console.log(
            "Invalid result color. Please provide a string in this format:"
          + "'r, g, b'. Example: --resultColor '255, 0, 0'"
        );
    }

    searchResultColor[i] = parseInt(searchResultColor[i])
}

/**
 * printOutput
 * This function is called when the response from the
 * search or get request comes
 *
 * @param {Error} err An error that ocured while fetching the verses.
 * @param {Array} verses The verses array that was returned by bible.js module.
 * @return {undefined} Returns undefined
 */
function printOutput (err, verses) {

    // Handle error
    if (err) {
        console.log("Error: ", err);
        return;
    }

    // No verses
    if (!verses || !verses.length) {
        console.log("Verses not found");
    }

    var tbl = new LeTable();

    // Output each verse
    for (var i in verses) {

        // get the current verse and its reference
        var cVerse = verses[i]
          , cVerseRef = cVerse.bookname + " " + cVerse.chapter + ":" + cVerse.verse
          ;

        if (search) {

            // Highlight search results
            var re = typeof search === "string" ? RegexParser(search) : search
              , match = cVerse.text.match(re) || []
              ;

            for (var ii = 0; ii < match.length; ++ii) {
                cVerse.text = cVerse.text.replace (
                    new RegExp(match[ii])
                  , Couleurs.fg(match[ii], searchResultColor)
                );
            }
        }

        if (Argv.onlyVerses) {
            console.log(cVerse.text);
        } else {
            tbl.addRow([
                {text: cVerseRef, data: {hAlign: "right"}}
              , {
                    text: cVerse.text.match(/.{1,80}(\s|$)|\S+?(\s|$)/g).join("\n")
                  , data: {hAlign: "left"}
                }
            ]);
        }

        // Search limit
        if (search && --config.searchLimit <= 0) {
            break;
        }
    }

    // Output
    if (!Argv.onlyVerses) {
        console.log(tbl.toString());
    }
}

// Check if the ~/.bible dir exists
if (!Fs.existsSync(SUBMODULES_DIR)) {
    Debug.log("~/.bible directory was not found. Downloading packages. This may take a while.", "info");
}

// Init submodules
BibleJS.init(config, function (err) {

    if (err) { throw err; }

    // Create Bible instance
    var bibleIns = new BibleJS({language: language});

    // Get the verses
    if (references.length) {
        for (var i = 0; i < references.length; ++i) {
            (function (cR) {
                if (!Argv.onlyVerses) {
                    console.log("Reference: " + cR);
                }
                bibleIns.get(cR, printOutput);
            })(references[i]);
        }
    }

    // Search verses
    if (search) {
        if (!Argv.onlyVerses) {
            console.log("Results for search: " + search);
        }
        bibleIns.search(search, printOutput);
    }
});
<commit_msg>New line<commit_after>#!/usr/bin/env node

// Dependencies
var BibleJS = require("bible.js")
  , Couleurs = require("couleurs")()
  , Debug = require("bug-killer")
  , RegexParser = require("regex-parser")
  , Ul = require("ul")
  , Yargs = require("yargs")
  , OS = require("os")
  , LeTable = require("le-table")
  , Fs = require("fs")
  , config = null
  ;

// Help output
const HELP = require("./docs/help")
    , SAMPLE_CONFIGURATION = require("./docs/sample-conf")
    , CONFIG_FILE_PATH = Ul.USER_DIR + "/.bible-config.json"
    , SUBMODULES_DIR = Ul.USER_DIR + "/.bible"
    ;

// CLI args parser
Yargs = Yargs.usage(HELP);
var Argv = Yargs.argv
  , language = Argv.lang || Argv.language
  , search = Argv.s || Argv.search
  , searchResultColor = null
  ;

// Set log level
Debug.config.logLevel = 3;

// Read the configuration file
try {
    config = require(CONFIG_FILE_PATH);
} catch (e) {
    if (e.code === "MODULE_NOT_FOUND") {
        Debug.log(
            "No configuration file was found. Initing the configuration file."
          , "warn"
        );
        Fs.writeFileSync(CONFIG_FILE_PATH, JSON.stringify(
            SAMPLE_CONFIGURATION, null, 4
        ));
        Debug.log(
            "The configuration file created successfully at the following location: "
          + CONFIG_FILE_PATH
          , "warn"
        );
        config = require(CONFIG_FILE_PATH);
    } else {
        Debug.log(
            "Cannot read the configuration file. Reason: " + e.code
          , "warn"
        );
    }
}

// Show the version
if (Argv.v || Argv.version) {
    return console.log(
        "Bible " + require("./package").version
    + "\nBible.JS " + require("./package").dependencies["bible.js"]
    );
}

// Show help
var references = Argv._;
if (Argv.help ||  (!language && !references.length && !search)) {
    return console.log(Yargs.help());
}

// Try to get options from config as well
language = language || config.language;
searchResultColor = (
    Argv.rc || Argv.resultColor || config.resultColor
).split(/[ ,]+/)
config.searchLimit = config.searchLimit || 10;

// Table defaults
LeTable.defaults.marks = {
    nw: "┌"
  , n:  "─"
  , ne: "┐"
  , e:  "│"
  , se: "┘"
  , s:  "─"
  , sw: "└"
  , w:  "│"
  , b: " "
  , mt: "┬"
  , ml: "├"
  , mr: "┤"
  , mb: "┴"
  , mm: "┼"
};

// Parse result color
for (var i = 0; i < 3; ++i) {

    if (!searchResultColor[i]) {
        return console.log(
            "Invalid result color. Please provide a string in this format:"
          + "'r, g, b'. Example: --resultColor '255, 0, 0'"
        );
    }

    searchResultColor[i] = parseInt(searchResultColor[i])
}

/**
 * printOutput
 * This function is called when the response from the
 * search or get request comes
 *
 * @param {Error} err An error that ocured while fetching the verses.
 * @param {Array} verses The verses array that was returned by bible.js module.
 * @return {undefined} Returns undefined
 */
function printOutput (err, verses) {

    // Handle error
    if (err) {
        console.log("Error: ", err);
        return;
    }

    // No verses
    if (!verses || !verses.length) {
        console.log("Verses not found");
    }

    var tbl = new LeTable();

    // Output each verse
    for (var i in verses) {

        // get the current verse and its reference
        var cVerse = verses[i]
          , cVerseRef = cVerse.bookname + " " + cVerse.chapter + ":" + cVerse.verse
          ;

        if (search) {

            // Highlight search results
            var re = typeof search === "string" ? RegexParser(search) : search
              , match = cVerse.text.match(re) || []
              ;

            for (var ii = 0; ii < match.length; ++ii) {
                cVerse.text = cVerse.text.replace (
                    new RegExp(match[ii])
                  , Couleurs.fg(match[ii], searchResultColor)
                );
            }
        }

        if (Argv.onlyVerses) {
            console.log(cVerse.text);
        } else {
            tbl.addRow([
                {text: cVerseRef, data: {hAlign: "right"}}
              , {
                    text: cVerse.text.match(/.{1,80}(\s|$)|\S+?(\s|$)/g).join("\n")
                  , data: {hAlign: "left"}
                }
            ]);
        }

        // Search limit
        if (search && --config.searchLimit <= 0) {
            break;
        }
    }

    // Output
    if (!Argv.onlyVerses) {
        console.log(tbl.toString());
    }
}

// Check if the ~/.bible dir exists
if (!Fs.existsSync(SUBMODULES_DIR)) {
    Debug.log("~/.bible directory was not found. Downloading packages. This may take a while.", "info");
}

// Init submodules
BibleJS.init(config, function (err) {

    if (err) { throw err; }

    // Create Bible instance
    var bibleIns = new BibleJS({language: language});

    // Get the verses
    if (references.length) {
        for (var i = 0; i < references.length; ++i) {
            (function (cR) {
                if (!Argv.onlyVerses) {
                    console.log("Reference: " + cR);
                }
                bibleIns.get(cR, printOutput);
            })(references[i]);
        }
    }

    // Search verses
    if (search) {
        if (!Argv.onlyVerses) {
            console.log("Results for search: " + search);
        }
        bibleIns.search(search, printOutput);
    }
});
<|endoftext|>


<commit_before>var bb = (function(){'use strict';
return {
	get: function(arg){
		this.el = this.$element = (typeof arg === 'string') ? document.querySelector(arg) : arg;
		if(this.$element && !this.$element.id){	this.$element.id = this.uuid(); }

		return this.el;
	},
	exec: function(name, args){ var action = function(e){$this[name].call($this, e||args)}; return action; }
	objVal: function(value){ //ensure that null value isn't passed for the object
		return value || {};
	},
	strVal: function(value){
		return value || "";
	},
	replace: function(str, search, replacement){ return str.split(search).join(replacement); },
	create: function(elType, options){
		var element = document.createElement(elType);

		options = this.objVal(options);

		element.className = this.strVal(options['class']);
		element.id = this.strVal(options.id);
		/*
		for(var prop in options){
			if(prop){ element[prop] = options[prop]; }
		}
*/
		return element;
	},
	uuid: function(){
		return 'mxxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
			var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
			return v.toString(16);
		});
	},
	stringToBoolean: function(string){
		if(!string) return null;
		switch(string.toLowerCase()){
			case "true": case "yes": case "1": return true;
			default: return false;
		}
	},
	isString: function(s) {
		return typeof(s) === 'string' || s instanceof String;
	},
	format: function(number, n, x, s, c) {
		var re = '\\d(?=(\\d{' + (x || 3) + '})+' + (n > 0 ? '\\D' : '$') + ')',
			num = number.toFixed(Math.max(0, ~~n));

		return (c ? num.replace('.', c) : num).replace(new RegExp(re, 'g'), '$&' + (s || ','));
	},
	applyMask: function(value, mascara) {
		var boleanoMascara,
			exp = /\-|\.|\/|\(|\)| /g,
			campoSoNumeros = value.toString().replace(exp, ""),

			posicaoCampo = 0,
			valor = "",
			tamanhoMascara = campoSoNumeros.length;

		for(var i = 0; i <= tamanhoMascara; i++) {
			boleanoMascara  = ((mascara.charAt(i) == "-") || (mascara.charAt(i) == ".")
										|| (mascara.charAt(i) == "/"));
			boleanoMascara  = boleanoMascara || ((mascara.charAt(i) == "(")
										|| (mascara.charAt(i) == ")") || (mascara.charAt(i) == " "));
			if (boleanoMascara) {
				valor += mascara.charAt(i);
				tamanhoMascara++;
			} else {
				valor += campoSoNumeros.charAt(posicaoCampo);
				posicaoCampo++;
			}
		}

		return valor;
	},
	formatDate: function(date, showTime){
		var miliseconds = Date.parse(date);
		if(miliseconds){
			var d = new Date(miliseconds);

			return d.getDate() + '/' + (d.getMonth()+1) + '/' + d.getFullYear()
			+ ((showTime)? ' '+d.getHours()+':'+d.getMinutes() :'');
		} else {
			var bound = date.indexOf(' ') || date.indexOf('T'),
				splitDate = date.slice(0, bound).split('/'),
				splitTime = date.slice(bound+1, -1).split(':');

			return splitDate[0] + '/' + splitDate[1] + '/' + splitDate[2]
			+ ((showTime)? ' '+splitTime[0]+':'+splitTime[1] :'');
		}
	},
	getChildIndex: function(child){
		var i = 0;
		while( (child = child.previousSibling) !== null ) i++;
		return i;
	},
	hasTouch: function(){
		var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0));
		return isTouch;
	},
	getParentElement: function(element, tagName){
		tagName = tagName.toUpperCase();
		do{
			if(element.tagName === tagName){ return element; }
			element = element.parentNode;
		} while(element !== null);

		return null;
	},
	plugin: function(name, f){
		this[name] = function(){ return f.apply(f, arguments); };
	},
	extend: function(_class){

	},
	noop: function(){},
	each: function(list, action){
		for(var i in list){
			action(list[i], i);
		}
	},
	alias: function(a, action){ action(a); },
	createAudioPool: function(){
		var Pool = function(){
			this.audioList = new Array();
		};

		Pool.prototype = {
			add: function(id, fileName){
				var audio = new Audio(fileName);
				audio.load();
				this.audioList[id] = audio;
			},
			remove: function(id){
				if(!this.audioList[id]){ throw Error("Audio Not Found"); }
				delete this.audioList[id];
			},
			pause: function(id){
				if(!this.audioList[id]){ throw Error("Audio Not Found"); }
				this.audioList[id].pause();
			},
			stop: function(id){
				this.pause(id);
				this.audioList[id].currentTime = 0;
			},
			play: function(id){
				if(!this.audioList[id]){ throw Error("Audio Not Found"); }
				this.audioList[id].play();
			},
			get: function(id){
				if(!this.audioList[id]){ throw Error("Audio Not Found"); }
				return this.audioList[id];
			}
		};
	}
};

})();
<commit_msg>Queue function<commit_after>var bb = (function(){'use strict';
return {
	get: function(arg){
		this.el = this.$element = (typeof arg === 'string') ? document.querySelector(arg) : arg;
		if(this.$element && !this.$element.id){	this.$element.id = this.uuid(); }

		return this.el;
	},
	queue: {
		init: function(){ this.list = {} },
		add: function(func){ this.list.push(func); },
		run: function(){ this.list.reverse(); while(this.list.length){ this.list.pop()(); }; },
		clear: function(){ while(this.list.length){ this.list.pop(); }; }
	},
	exec: function(name, args){ var action = function(e){$this[name].call($this, e||args)}; return action; }
	objVal: function(value){ //ensure that null value isn't passed for the object
		return value || {};
	},
	strVal: function(value){
		return value || "";
	},
	replace: function(str, search, replacement){ return str.split(search).join(replacement); },
	create: function(elType, options){
		var element = document.createElement(elType);

		options = this.objVal(options);

		element.className = this.strVal(options['class']);
		element.id = this.strVal(options.id);
		/*
		for(var prop in options){
			if(prop){ element[prop] = options[prop]; }
		}
*/
		return element;
	},
	uuid: function(){
		return 'mxxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
			var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
			return v.toString(16);
		});
	},
	stringToBoolean: function(string){
		if(!string) return null;
		switch(string.toLowerCase()){
			case "true": case "yes": case "1": return true;
			default: return false;
		}
	},
	isString: function(s) {
		return typeof(s) === 'string' || s instanceof String;
	},
	format: function(number, n, x, s, c) {
		var re = '\\d(?=(\\d{' + (x || 3) + '})+' + (n > 0 ? '\\D' : '$') + ')',
			num = number.toFixed(Math.max(0, ~~n));

		return (c ? num.replace('.', c) : num).replace(new RegExp(re, 'g'), '$&' + (s || ','));
	},
	applyMask: function(value, mascara) {
		var boleanoMascara,
			exp = /\-|\.|\/|\(|\)| /g,
			campoSoNumeros = value.toString().replace(exp, ""),

			posicaoCampo = 0,
			valor = "",
			tamanhoMascara = campoSoNumeros.length;

		for(var i = 0; i <= tamanhoMascara; i++) {
			boleanoMascara  = ((mascara.charAt(i) == "-") || (mascara.charAt(i) == ".")
										|| (mascara.charAt(i) == "/"));
			boleanoMascara  = boleanoMascara || ((mascara.charAt(i) == "(")
										|| (mascara.charAt(i) == ")") || (mascara.charAt(i) == " "));
			if (boleanoMascara) {
				valor += mascara.charAt(i);
				tamanhoMascara++;
			} else {
				valor += campoSoNumeros.charAt(posicaoCampo);
				posicaoCampo++;
			}
		}

		return valor;
	},
	formatDate: function(date, showTime){
		var miliseconds = Date.parse(date);
		if(miliseconds){
			var d = new Date(miliseconds);

			return d.getDate() + '/' + (d.getMonth()+1) + '/' + d.getFullYear()
			+ ((showTime)? ' '+d.getHours()+':'+d.getMinutes() :'');
		} else {
			var bound = date.indexOf(' ') || date.indexOf('T'),
				splitDate = date.slice(0, bound).split('/'),
				splitTime = date.slice(bound+1, -1).split(':');

			return splitDate[0] + '/' + splitDate[1] + '/' + splitDate[2]
			+ ((showTime)? ' '+splitTime[0]+':'+splitTime[1] :'');
		}
	},
	getChildIndex: function(child){
		var i = 0;
		while( (child = child.previousSibling) !== null ) i++;
		return i;
	},
	hasTouch: function(){
		var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0));
		return isTouch;
	},
	getParentElement: function(element, tagName){
		tagName = tagName.toUpperCase();
		do{
			if(element.tagName === tagName){ return element; }
			element = element.parentNode;
		} while(element !== null);

		return null;
	},
	plugin: function(name, f){
		this[name] = function(){ return f.apply(f, arguments); };
	},
	extend: function(_class){

	},
	noop: function(){},
	each: function(list, action){
		for(var i in list){
			action(list[i], i);
		}
	},
	alias: function(a, action){ action(a); },
	createAudioPool: function(){
		var Pool = function(){
			this.audioList = new Array();
		};

		Pool.prototype = {
			add: function(id, fileName){
				var audio = new Audio(fileName);
				audio.load();
				this.audioList[id] = audio;
			},
			remove: function(id){
				if(!this.audioList[id]){ throw Error("Audio Not Found"); }
				delete this.audioList[id];
			},
			pause: function(id){
				if(!this.audioList[id]){ throw Error("Audio Not Found"); }
				this.audioList[id].pause();
			},
			stop: function(id){
				this.pause(id);
				this.audioList[id].currentTime = 0;
			},
			play: function(id){
				if(!this.audioList[id]){ throw Error("Audio Not Found"); }
				this.audioList[id].play();
			},
			get: function(id){
				if(!this.audioList[id]){ throw Error("Audio Not Found"); }
				return this.audioList[id];
			}
		};
	}
};

})();
<|endoftext|>


<commit_before>"use strict";

/**
* Represents an command framework command
* @prop {Object} subcommands Object mapping subcommand labels to Command objects
*/
class Command {
    /**
    * Register a command
    * @arg {String} label The command label
    * @arg {Function | String | Array<Function | String>} generator A response string, array of functions or strings, or function that generates a string or array of strings when called.
    * If a function is passed, the function will be passed a Message object and an array of command arguments. The Message object will have an additional property `prefix`, which is the prefix used in the command.
    *
generator(msg, args)

    * @arg {Object} [options] Command options
    * @arg {Array<String>} [options.aliases] An array of command aliases
    * @arg {Boolean} [options.caseInsensitive=false] Whether the command label (and aliases) is case insensitive or not
    * @arg {Boolean} [options.deleteCommand=false] Whether to delete the user command message or not
    * @arg {Boolean} [options.guildOnly=false] Whether to prevent the command from being used in Direct Messages or not
    * @arg {Boolean} [options.dmOnly=false] Whether to prevent the command from being used in guilds or not
    * @arg {String} [options.description="No description"] A short description of the command to show in the default help command
    * @arg {String} [options.fullDescription="No full description"] A detailed description of the command to show in the default help command
    * @arg {String} [options.usage] Details on how to call the command to show in the default help command
    * @arg {Object} [options.requirements] A set of factors that limit who can call the command
    * @arg {Array<String>} [options.requirements.userIDs] An array of user IDs representing users that can call the command
    * @arg {Object} [options.requirements.permissions] An object containing permission keys the user must match to use the command
    * i.e.:
    * ```
    * {
    *   "administrator": false,
    *   "manageMessages": true
    * }```
    * In the above example, the user must not have administrator permissions, but must have manageMessages to use the command
    * @arg {Array<String>} [options.requirements.roleIDs] An array of role IDs that would allow a user to use the command
    * @arg {Array<String>} [options.requirements.roleNames] An array of role names that would allow a user to use the command
    * @arg {Number} [cooldown] The cooldown between command usage in milliseconds
    */
    constructor(label, generator, options) {
        this.label = label;
        this.description = options.description || "No description";
        this.fullDescription = options.fullDescription || "No full description";
        this.usage = options.usage || "";
        this.aliases = options.aliases || [];
        this.caseInsensitive = !!options.caseInsensitive;
        this.requirements = options.requirements || {};
        if(!this.requirements.userIDs) {
            this.requirements.userIDs = [];
        }
        if(!this.requirements.permissions) {
            this.requirements.permissions = {};
        }
        if(!this.requirements.roleIDs) {
            this.requirements.roleIDs = [];
        }
        if(!this.requirements.roleNames) {
            this.requirements.roleNames = [];
        }
        this.deleteCommand = !!options.deleteCommand;
        this.guildOnly = !!options.guildOnly;
        this.dmOnly = !!options.dmOnly;
        this.cooldown = options.cooldown || 0;
        if(this.cooldown !== 0) {
            this.usersOnCooldown = new Set();
        }
        if(typeof generator === "string") {
            this.response = generator;
            this.execute = () => this.response;
        } else if(Array.isArray(generator)) {
            this.responses = generator.map((item, index) => {
                if(typeof generator === "string") {
                    return () => generator;
                } else if(typeof generator === "function") {
                    return generator;
                } else {
                    throw new Error("Invalid command response generator (index " + index + ")");
                }
            });
            this.execute = () => this.responses[Math.floor(Math.random() * this.responses.length)];
        } else if(typeof generator === "function") {
            this.execute = generator;
        } else {
            throw new Error("Invalid command response generator");
        }

        this.subcommands = {};
        this.subcommandAliases = {};
    }

    permissionCheck(msg) {
        var req = false;
        if(this.requirements.userIDs.length > 0) {
            req = true;
            if(~this.requirements.userIDs.indexOf(msg.author.id)) {
                return true;
            }
        }
        if(!msg.channel.guild) {
            return !this.guildOnly && !req;
        } else if(this.dmOnly) {
            return false;
        }
        var keys = Object.keys(this.requirements.permissions);
        if(keys.length > 0) {
            req = true;
            var permissions = msg.channel.permissionsOf(msg.author.id).json;
            for(var key of keys) {
                if(this.requirements.permissions[key] !== permissions[key]) {
                    req = false;
                    break;
                }
            }
            if(req) {
                return true;
            }
            req = true;
        }
        var roles = msg.channel.guild.members.get(msg.author.id).roles;
        if(roles.length > 0) {
            if(this.requirements.roleIDs.length > 0) {
                req = true;
                for(var roleID of this.requirements.roleIDs) {
                    if(~roles.indexOf(roleID)) {
                        return true;
                    }
                }
            }
            if(this.requirements.roleNames.length > 0) {
                req = true;
                roles = roles.map((roleID) => msg.channel.guild.roles.get(roleID).name);
                for(var roleName of this.requirements.roleNames) {
                    if(~roles.indexOf(roleName)) {
                        return true;
                    }
                }
            }
        }
        return !req;
    }

    cooldownCheck(userID) {
        if(this.usersOnCooldown.has(userID)) {
            return false;
        }
        this.usersOnCooldown.add(userID);
        setTimeout(() => {
            this.usersOnCooldown.delete(userID);
        }, this.cooldown);
        return true;
    }

    process(args, msg) {
        if(!this.permissionCheck(msg)) {
            return;
        }
        if(args.length === 0) {
            if(this.cooldown !== 0 && !this.cooldownCheck(msg.author.id)) {
                return;
            }
            return this.execute(msg, args);
        }
        var label = this.subcommandAliases[args[0]] || args[0];
        var subcommand;
        if((subcommand = this.subcommands[label]) !== undefined || ((subcommand = this.subcommands[label.toLowerCase()]) !== undefined && subcommand.caseInsensitive)) {
            return subcommand.process(args.slice(1), msg);
        } else {
            if(this.cooldown !== 0 && !this.cooldownCheck(msg.author.id)) {
                return;
            }
            return this.execute(msg, args);
        }
    }

    /**
    * Register an alias for a subcommand
    * @arg {String} alias The alias
    * @arg {String} label The original subcommand label
    */
    registerSubcommandAlias(alias, label) {
        if(!this.subcommands[label]) {
            throw new Error("No subcommand registered for " + label);
        }
        if(this.subcommandAliases[alias]) {
            throw new Error(`Alias ${label} already registered`);
        }
        this.subcommandAliases[alias] = label;
        this.subcommands[label].aliases.push(alias);
    }

    /**
    * Register a subcommand
    * @arg {String} label The subcommand label
    * @arg {Function | String | Array<Function | String>} generator A response string, array of functions or strings, or function that generates a string or array of strings when called.
    * If a function is passed, the function will be passed a Message object and an array of subcommand arguments. The Message object will have an additional property `prefix`, which is the prefix used in the subcommand.
    *
generator(msg, args)

    * @arg {Object} [options] Command options
    * @arg {Array<String>} [options.aliases] An array of subcommand aliases
    * @arg {Boolean} [options.caseInsensitive=false] Whether the subcommand label (and aliases) is case insensitive or not
    * @arg {Boolean} [options.deleteCommand=false] Whether to delete the user subcommand message or not
    * @arg {Boolean} [options.guildOnly=false] Whether to prevent the subcommand from being used in Direct Messages or not
    * @arg {Boolean} [options.dmOnly=false] Whether to prevent the subcommand from being used in guilds or not
    * @arg {String} [options.description="No description"] A short description of the subcommand to show in the default help subcommand
    * @arg {String} [options.fullDescription="No full description"] A detailed description of the subcommand to show in the default help subcommand
    * @arg {String} [options.usage] Details on how to call the subcommand to show in the default help subcommand
    * @arg {Object} [options.requirements] A set of factors that limit who can call the subcommand
    * @arg {Array<String>} [options.requirements.userIDs] An array of user IDs representing users that can call the subcommand
    * @arg {Object} [options.requirements.permissions] An object containing permission keys the user must match to use the subcommand
    * i.e.:
    * ```
    * {
    *   "administrator": false,
    *   "manageMessages": true
    * }```
    * In the above example, the user must not have administrator permissions, but must have manageMessages to use the subcommand
    * @arg {Array<String>} [options.requirements.roleIDs] An array of role IDs that would allow a user to use the subcommand
    * @arg {Array<String>} [options.requirements.roleNames] An array of role names that would allow a user to use the subcommand
    * @arg {Number} [cooldown] The cooldown between command usage in milliseconds
    * @returns {Command}
    */
    registerSubcommand(label, generator, options) {
        if(label.includes(" ")) {
            throw new Error("Subcommand label may not have spaces");
        }
        if(this.subcommands[label]) {
            throw new Error("You have already registered a subcommand for " + label);
        }
        options = options || {};
        this.subcommands[label] = new Command(label, generator, options);
        if(options.aliases) {
            options.aliases.forEach((alias) => {
                this.subcommandAliases[alias] = label;
            });
        }
        return this.subcommands[label];
    }

    /**
    * Unregister a subcommand
    * @arg {String} label The subcommand label
    */
    unregisterSubcommand(label) {
        var original = this.subcommandAliases[label];
        if(original) {
            this.subcommands[original].aliases.splice(this.subcommands[original].aliases.indexOf(label), 1);
            this.subcommandAliases[label] = undefined;
        } else {
            this.subcommands[label] = undefined;
        }
    }
}

module.exports = Command;
<commit_msg>Fix for webhook crash in permission check (#107)<commit_after>"use strict";

/**
* Represents an command framework command
* @prop {Object} subcommands Object mapping subcommand labels to Command objects
*/
class Command {
    /**
    * Register a command
    * @arg {String} label The command label
    * @arg {Function | String | Array<Function | String>} generator A response string, array of functions or strings, or function that generates a string or array of strings when called.
    * If a function is passed, the function will be passed a Message object and an array of command arguments. The Message object will have an additional property `prefix`, which is the prefix used in the command.
    *
generator(msg, args)

    * @arg {Object} [options] Command options
    * @arg {Array<String>} [options.aliases] An array of command aliases
    * @arg {Boolean} [options.caseInsensitive=false] Whether the command label (and aliases) is case insensitive or not
    * @arg {Boolean} [options.deleteCommand=false] Whether to delete the user command message or not
    * @arg {Boolean} [options.guildOnly=false] Whether to prevent the command from being used in Direct Messages or not
    * @arg {Boolean} [options.dmOnly=false] Whether to prevent the command from being used in guilds or not
    * @arg {String} [options.description="No description"] A short description of the command to show in the default help command
    * @arg {String} [options.fullDescription="No full description"] A detailed description of the command to show in the default help command
    * @arg {String} [options.usage] Details on how to call the command to show in the default help command
    * @arg {Object} [options.requirements] A set of factors that limit who can call the command
    * @arg {Array<String>} [options.requirements.userIDs] An array of user IDs representing users that can call the command
    * @arg {Object} [options.requirements.permissions] An object containing permission keys the user must match to use the command
    * i.e.:
    * ```
    * {
    *   "administrator": false,
    *   "manageMessages": true
    * }```
    * In the above example, the user must not have administrator permissions, but must have manageMessages to use the command
    * @arg {Array<String>} [options.requirements.roleIDs] An array of role IDs that would allow a user to use the command
    * @arg {Array<String>} [options.requirements.roleNames] An array of role names that would allow a user to use the command
    * @arg {Number} [cooldown] The cooldown between command usage in milliseconds
    */
    constructor(label, generator, options) {
        this.label = label;
        this.description = options.description || "No description";
        this.fullDescription = options.fullDescription || "No full description";
        this.usage = options.usage || "";
        this.aliases = options.aliases || [];
        this.caseInsensitive = !!options.caseInsensitive;
        this.requirements = options.requirements || {};
        if(!this.requirements.userIDs) {
            this.requirements.userIDs = [];
        }
        if(!this.requirements.permissions) {
            this.requirements.permissions = {};
        }
        if(!this.requirements.roleIDs) {
            this.requirements.roleIDs = [];
        }
        if(!this.requirements.roleNames) {
            this.requirements.roleNames = [];
        }
        this.deleteCommand = !!options.deleteCommand;
        this.guildOnly = !!options.guildOnly;
        this.dmOnly = !!options.dmOnly;
        this.cooldown = options.cooldown || 0;
        if(this.cooldown !== 0) {
            this.usersOnCooldown = new Set();
        }
        if(typeof generator === "string") {
            this.response = generator;
            this.execute = () => this.response;
        } else if(Array.isArray(generator)) {
            this.responses = generator.map((item, index) => {
                if(typeof generator === "string") {
                    return () => generator;
                } else if(typeof generator === "function") {
                    return generator;
                } else {
                    throw new Error("Invalid command response generator (index " + index + ")");
                }
            });
            this.execute = () => this.responses[Math.floor(Math.random() * this.responses.length)];
        } else if(typeof generator === "function") {
            this.execute = generator;
        } else {
            throw new Error("Invalid command response generator");
        }

        this.subcommands = {};
        this.subcommandAliases = {};
    }

    permissionCheck(msg) {
        var req = false;
        if(this.requirements.userIDs.length > 0) {
            req = true;
            if(~this.requirements.userIDs.indexOf(msg.author.id)) {
                return true;
            }
        }
        if(!msg.channel.guild) {
            return !this.guildOnly && !req;
        } else if(this.dmOnly) {
            return false;
        }
        var keys = Object.keys(this.requirements.permissions);
        if(keys.length > 0) {
            req = true;
            var permissions = msg.channel.permissionsOf(msg.author.id).json;
            for(var key of keys) {
                if(this.requirements.permissions[key] !== permissions[key]) {
                    req = false;
                    break;
                }
            }
            if(req) {
                return true;
            }
            req = true;
        }
        if(msg.member && msg.member.roles.length > 0) {
            var roles = msg.member.roles;
            if(this.requirements.roleIDs.length > 0) {
                req = true;
                for(var roleID of this.requirements.roleIDs) {
                    if(~roles.indexOf(roleID)) {
                        return true;
                    }
                }
            }
            if(this.requirements.roleNames.length > 0) {
                req = true;
                roles = roles.map((roleID) => msg.channel.guild.roles.get(roleID).name);
                for(var roleName of this.requirements.roleNames) {
                    if(~roles.indexOf(roleName)) {
                        return true;
                    }
                }
            }
        }
        return !req;
    }

    cooldownCheck(userID) {
        if(this.usersOnCooldown.has(userID)) {
            return false;
        }
        this.usersOnCooldown.add(userID);
        setTimeout(() => {
            this.usersOnCooldown.delete(userID);
        }, this.cooldown);
        return true;
    }

    process(args, msg) {
        if(!this.permissionCheck(msg)) {
            return;
        }
        if(args.length === 0) {
            if(this.cooldown !== 0 && !this.cooldownCheck(msg.author.id)) {
                return;
            }
            return this.execute(msg, args);
        }
        var label = this.subcommandAliases[args[0]] || args[0];
        var subcommand;
        if((subcommand = this.subcommands[label]) !== undefined || ((subcommand = this.subcommands[label.toLowerCase()]) !== undefined && subcommand.caseInsensitive)) {
            return subcommand.process(args.slice(1), msg);
        } else {
            if(this.cooldown !== 0 && !this.cooldownCheck(msg.author.id)) {
                return;
            }
            return this.execute(msg, args);
        }
    }

    /**
    * Register an alias for a subcommand
    * @arg {String} alias The alias
    * @arg {String} label The original subcommand label
    */
    registerSubcommandAlias(alias, label) {
        if(!this.subcommands[label]) {
            throw new Error("No subcommand registered for " + label);
        }
        if(this.subcommandAliases[alias]) {
            throw new Error(`Alias ${label} already registered`);
        }
        this.subcommandAliases[alias] = label;
        this.subcommands[label].aliases.push(alias);
    }

    /**
    * Register a subcommand
    * @arg {String} label The subcommand label
    * @arg {Function | String | Array<Function | String>} generator A response string, array of functions or strings, or function that generates a string or array of strings when called.
    * If a function is passed, the function will be passed a Message object and an array of subcommand arguments. The Message object will have an additional property `prefix`, which is the prefix used in the subcommand.
    *
generator(msg, args)

    * @arg {Object} [options] Command options
    * @arg {Array<String>} [options.aliases] An array of subcommand aliases
    * @arg {Boolean} [options.caseInsensitive=false] Whether the subcommand label (and aliases) is case insensitive or not
    * @arg {Boolean} [options.deleteCommand=false] Whether to delete the user subcommand message or not
    * @arg {Boolean} [options.guildOnly=false] Whether to prevent the subcommand from being used in Direct Messages or not
    * @arg {Boolean} [options.dmOnly=false] Whether to prevent the subcommand from being used in guilds or not
    * @arg {String} [options.description="No description"] A short description of the subcommand to show in the default help subcommand
    * @arg {String} [options.fullDescription="No full description"] A detailed description of the subcommand to show in the default help subcommand
    * @arg {String} [options.usage] Details on how to call the subcommand to show in the default help subcommand
    * @arg {Object} [options.requirements] A set of factors that limit who can call the subcommand
    * @arg {Array<String>} [options.requirements.userIDs] An array of user IDs representing users that can call the subcommand
    * @arg {Object} [options.requirements.permissions] An object containing permission keys the user must match to use the subcommand
    * i.e.:
    * ```
    * {
    *   "administrator": false,
    *   "manageMessages": true
    * }```
    * In the above example, the user must not have administrator permissions, but must have manageMessages to use the subcommand
    * @arg {Array<String>} [options.requirements.roleIDs] An array of role IDs that would allow a user to use the subcommand
    * @arg {Array<String>} [options.requirements.roleNames] An array of role names that would allow a user to use the subcommand
    * @arg {Number} [cooldown] The cooldown between command usage in milliseconds
    * @returns {Command}
    */
    registerSubcommand(label, generator, options) {
        if(label.includes(" ")) {
            throw new Error("Subcommand label may not have spaces");
        }
        if(this.subcommands[label]) {
            throw new Error("You have already registered a subcommand for " + label);
        }
        options = options || {};
        this.subcommands[label] = new Command(label, generator, options);
        if(options.aliases) {
            options.aliases.forEach((alias) => {
                this.subcommandAliases[alias] = label;
            });
        }
        return this.subcommands[label];
    }

    /**
    * Unregister a subcommand
    * @arg {String} label The subcommand label
    */
    unregisterSubcommand(label) {
        var original = this.subcommandAliases[label];
        if(original) {
            this.subcommands[original].aliases.splice(this.subcommands[original].aliases.indexOf(label), 1);
            this.subcommandAliases[label] = undefined;
        } else {
            this.subcommands[label] = undefined;
        }
    }
}

module.exports = Command;
<|endoftext|>


<commit_before>'use strict';

var adduser     = module.exports = {};
var inquirer    = require('inquirer');
var lang        = require('../util/lang');

var REGEX_IS_EMAIL = /^(?:[a-z0-9!#$%&'*+\/=?^_`{|}~-]\.?){0,63}[a-z0-9!#$%&'*+\/=?^_`{|}~-]@(?:(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)*[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\])$/i;

var PROMPT_SCHEMAS = [{
        name: 'username',
        type: 'input',
        message: 'username',
        validate: function (username) {
            var done = this.async();

            if ( username.toLowerCase() !== username ) {
                return done('username must be lowercase.');
            }

            if ( ~ encodeURIComponent(username).indexOf("%") ) {
                return done('username cannot contain any non-urlsafe characters.')
            }

            done(true);
        }
    }, {
        name: 'password',
        type: 'password',
        message: 'password',
        validate: function (password) {
            var done = this.async();

            if ( !password ) {
                return done('password is required');
            }

            done(true);
        }
    }, {
        name: 'email',
        type: 'input',
        message: 'email',
        validate: function (email) {
            var done = this.async();

            if ( !email ) {
                return done('email is required');
            }

            if ( !REGEX_IS_EMAIL.test(email) ) {
                return done('invalid email.')
            }

            done(true);
        }
    }
];

function simple_clone (obj) {
    var ret = {};
    var key;

    for (key in obj) {
        ret[key] = obj[key];
    }

    return ret;
}

// 1. new user
// username:
// password:

// 2. change password
// password:

// @param {Object} options
// - username: {string=}
// - password: {string=}
adduser.run = function (options, callback) {

    // If the command 'adduser' is called from the restful service, username and password must be specified
    if ( options._http ) {
        if ( !options.username || !options.password ) {
            return callback('username or password is not specified.');
        }
    }

    var schemas = [];
    var defaults = {};
    var profile = adduser.context.profile;

    PROMPT_SCHEMAS.forEach(function (schema) {
        var key = schema.name;

        // If process.argv already contains a certain key, skip it
        if ( options[key] ) {
            defaults[key] = options[key];
            return;
        }

        schema = simple_clone(schema);

        var saved = profile.get(key);

        if ( saved ) {
            schema.default = saved;
        }

        schemas.push(schema);
    });

    inquirer.prompt(schemas, function (result) {
        // if the username to add is different from the current username, `signup`
        if ( options.signup || result.username !== profile.get('username') ) {
            result.signup = true;
        }

        adduser.add(lang.mix(result, defaults), callback);
    });
};

// @param {Object} options
// - username
// - email
// - password
// - signup
adduser.add = function (options, callback) {
    var neuropil = adduser.context.neuropil;

    adduser.logger.info('{{cyan Add user}} ...');
    neuropil.adduser(options, function (err, res, json) {
        if ( err ) {
            return callback(err, res, json);
        }

        var profile = adduser.context.profile;
        PROMPT_SCHEMAS.forEach(function (schema) {
            var key = schema.name;
            profile.set(key, options[key]);
        });

        profile.saveConfig();
        callback(err, res, json);
    });
};<commit_msg>fixes #129: fix adduser<commit_after>'use strict';

var adduser     = module.exports = {};
var inquirer    = require('inquirer');
var lang        = require('../util/lang');

var REGEX_IS_EMAIL = /^(?:[a-z0-9!#$%&'*+\/=?^_`{|}~-]\.?){0,63}[a-z0-9!#$%&'*+\/=?^_`{|}~-]@(?:(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)*[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\])$/i;

var PROMPT_SCHEMAS = [{
        name: 'username',
        type: 'input',
        message: 'username',
        validate: function (username) {
            var done = this.async();

            if ( username.toLowerCase() !== username ) {
                return done('username must be lowercase.');
            }

            if ( ~ encodeURIComponent(username).indexOf("%") ) {
                return done('username cannot contain any non-urlsafe characters.')
            }

            done(true);
        }
    }, {
        name: 'password',
        type: 'password',
        message: 'password',
        validate: function (password) {
            var done = this.async();

            if ( !password ) {
                return done('password is required');
            }

            done(true);
        }
    }, {
        name: 'email',
        type: 'input',
        message: 'email',
        validate: function (email) {
            var done = this.async();

            if ( !email ) {
                return done('email is required');
            }

            if ( !REGEX_IS_EMAIL.test(email) ) {
                return done('invalid email.')
            }

            done(true);
        }
    }
];

function simple_clone (obj) {
    var ret = {};
    var key;

    for (key in obj) {
        ret[key] = obj[key];
    }

    return ret;
}

// 1. new user
// username:
// password:

// 2. change password
// password:

// @param {Object} options
// - username: {string=}
// - password: {string=}
adduser.run = function (options, callback) {

    // If the command 'adduser' is called from the restful service, username and password must be specified
    if ( options._http ) {
        if ( !options.username || !options.password ) {
            return callback('username or password is not specified.');
        }
    }

    var schemas = [];
    var defaults = {};
    var profile = adduser.context.profile;

    PROMPT_SCHEMAS.forEach(function (schema) {
        var key = schema.name;

        // If process.argv already contains a certain key, skip it
        if ( options[key] ) {
            defaults[key] = options[key];
            return;
        }

        schema = simple_clone(schema);

        var saved = profile.get(key);

        if ( saved ) {
            schema.default = saved;
        }

        schemas.push(schema);
    });

    inquirer.prompt(schemas, function (result) {
        // if the username to add is different from the current username, `signup`
        if (
            options.signup ||
            result.username !== defaults.username ||
            result.password !== defaults.password
        ) {
            result.signup = true;
        }

        adduser.add(lang.mix(result, defaults, false), callback);
    });
};

// @param {Object} options
// - username
// - email
// - password
// - signup
adduser.add = function (options, callback) {
    var neuropil = adduser.context.neuropil;

    adduser.logger.info('{{cyan Add user}} ...');
    neuropil.adduser(options, function (err, res, json) {
        if ( err ) {
            return callback(err, res, json);
        }

        var profile = adduser.context.profile;
        PROMPT_SCHEMAS.forEach(function (schema) {
            var key = schema.name;
            profile.set(key, options[key]);
        });

        profile.saveConfig();
        callback(err, res, json);
    });
};<|endoftext|>


<commit_before>'use strict';

var publish   = exports;

var node_path = require('path');
var node_url  = require('url');
var node_zlib = require('zlib');
var fs        = require('fs');
var util      = require('util');

var async     = require('async');
var expand    = require('fs-expand');
var fse       = require('fs-extra');
var fstream   = require('fstream');
var tar       = require('tar');
var semver    = require('semver');
var spawns    = require('spawns');

var lang      = require('../util/lang');
var cortex_json   = require('read-cortex-json');
var pf        = require('cortex-package-files');

// have no fault tolerance, overload and clean your parameters ahead of time
// @param {Object} options
// - cwd: {node_path=} at least one of cwd and tar must not be undefined
// - force: {boolean=} force to publishing, default to false
// - tar: {node_path=} tar file, if not undefined, must exists
publish.run = function(options, callback) {
  this.MESSAGE = this.locale.require('command-publish');

  var force = options.force;
  var self = this;

  // prepare tgz file and package.json
  // @param {Object} opts
  // - pkg {Object} package json data
  // - tar {node_path} tar file
  this.prepare(options, function(err, data) {
    if (err) {
      return callback(err);
    }

    // @param {Object} options
    // - tar: {string} tar file path
    // - pkg: {Object} the object of package.json
    // - force: {boolean} force publishing
    self.neuropil.publish({
      tar: data.tar,
      pkg: data.pkg,
      force: options.force

    }, function(err, res, json) {

      // TODO
      // standardize callback parameters
      return callback(err);
    });
  });
};

// santitize arguments
// prepare tar file and json data
publish.prepare = function(options, callback) {
  // file = '/Users/Kael/.npm/neuronjs/2.0.1/package.tgz';
  options.temp_dir = this.profile.get('temp_dir');
  options.temp_package = node_path.join(options.temp_dir, 'package');

  var self = this;

  function finish (err) {
    if (err) {
      return callback(err);
    }

    callback(null, {
      tar: options.tar,
      pkg: options.pkg
    });
  }

  async.series([
    function (done) {
      self.read_cortex_json('read', options, done);
    },
    function (done) {
      self.run_prepublish_script(options, done);
    },
    function (done) {
      self.read_cortex_json('enhanced', options, done);
    },
    function (done) {
      self.pack(options, done);
    },
    function (done) {
      self.deal_prerelease_version(options, done);
    }
  ], finish);
};

publish.read_cortex_json = function (type, options, callback) {
  var self = this;
  cortex_json[type](options.cwd, function(err, data) {
    if (err) {
      return callback(err);
    }
    options.pkg = data;
    callback(null);
  });
};

publish.run_prepublish_script = function(options, callback) {
  var pkg = options.pkg;
  var script = lang.makeArray(
    pkg.scripts && (
      pkg.scripts.prepublish ||

      // if prepublish is not defined, try to use prebuild
      pkg.scripts.prebuild
    )
  )
  // skip empty scripts
  .filter(Boolean);

  if (!script.length) {
    return callback(null);
  }

  var self = this;

  this.logger.info('{{cyan run}} "scripts.prepublish" ...');

  spawns(script, {
    cwd: options.cwd,
    stdio: 'inherit'

  }).on('spawn', function(command) {
    self.logger.info('{{cyan exec}} "' + command + '" ...');

  }).on('close', function(code, signal) {
    if (code) {
      callback({
        code: 'PREPUBLISH_FAILS',
        message: 'build step "scripts.prepublish" executes as a failure. exit code: ' + code,
        data: {
          code: code,
          signal: signal
        }
      });
    } else {
      callback(null);
    }

  }).on('error', function(err) {
    self.logger.warn('"scripts.prepublish" let out an error: ' + err);
  });
};

publish.pack = function(options, callback) {
  var temp_package = options.temp_package;
  var file = options.tar = node_path.join(options.temp_dir, 'package.tgz');
  var self = this;
  var cwd = options.cwd;

  pf({
    cwd: cwd,
    pkg: options.pkg,
    more: true

  }, function (err, files) {
    if (err) {
      return callback(err);
    }

    async.series([
      function (done) {
        self.copy(files, cwd, temp_package, done);
      },
      function (done) {
        fse.writeJSON(
          node_path.join(temp_package, 'cortex.json'),
          options.pkg,
          done
        );
      },
      function (done) {
        // We validate the temp_package which is filtered and
        // is about to be published to the registry.
        // Make sure it is ok
        cortex_json.validate(temp_package, options.pkg, done);
      },
      function (done) {
        self.logger.info(self.logger.template(self.MESSAGE.COMPRESS_TARBALL, {
          dir: cwd,
          file: file
        }));
        self._pack(temp_package, file, done);
      }

    ], callback);
  });
};

publish.copy = function(paths, from, to, callback) {
  async.each(paths, function(path, done) {
    var src = node_path.join(from, path);

    fs.stat(src, function(err, stats) {
      if (err || !stats.isFile()) {
        // if error, skip copying
        return done(null);
      }

      var dest = node_path.join(to, path);
      fse.copy(src, dest, done);
    });
  }, callback);
};

publish._pack = function(dir, file, callback) {
  fstream.Reader({
    path: dir,
    type: 'Directory'
  })
  .pipe(tar.Pack())
  .pipe(
    node_zlib.createGzip({
      level: 6,
      memLevel: 6
    })
  )
  .pipe(fstream.Writer(file))
  .on('close', callback);
};

publish.deal_prerelease_version = function(options, callback) {
  var pkg = options.pkg;
  var sv = semver.parse(pkg.version);
  var prerelease = sv.prerelease;

  if (options.prerelease) {
    if (prerelease.length === 0) {
      prerelease.push(options.prerelease);

      pkg.version = sv.format();

    } else {
      this.logger.info(this.MESSAGE.HAS_PRERELEASE + '\n');
    }
  }

  callback(null);
};
<commit_msg>command/publish: removes unnecessary fs-expand; #362<commit_after>'use strict';

var publish   = exports;

var node_path = require('path');
var node_url  = require('url');
var node_zlib = require('zlib');
var fs        = require('fs');
var util      = require('util');

var async     = require('async');
var fse       = require('fs-extra');
var fstream   = require('fstream');
var tar       = require('tar');
var semver    = require('semver');
var spawns    = require('spawns');

var lang      = require('../util/lang');
var cortex_json   = require('read-cortex-json');
var pf        = require('cortex-package-files');

// have no fault tolerance, overload and clean your parameters ahead of time
// @param {Object} options
// - cwd: {node_path=} at least one of cwd and tar must not be undefined
// - force: {boolean=} force to publishing, default to false
// - tar: {node_path=} tar file, if not undefined, must exists
publish.run = function(options, callback) {
  this.MESSAGE = this.locale.require('command-publish');

  var force = options.force;
  var self = this;

  // prepare tgz file and package.json
  // @param {Object} opts
  // - pkg {Object} package json data
  // - tar {node_path} tar file
  this.prepare(options, function(err, data) {
    if (err) {
      return callback(err);
    }

    // @param {Object} options
    // - tar: {string} tar file path
    // - pkg: {Object} the object of package.json
    // - force: {boolean} force publishing
    self.neuropil.publish({
      tar: data.tar,
      pkg: data.pkg,
      force: options.force

    }, function(err, res, json) {

      // TODO
      // standardize callback parameters
      return callback(err);
    });
  });
};

// santitize arguments
// prepare tar file and json data
publish.prepare = function(options, callback) {
  // file = '/Users/Kael/.npm/neuronjs/2.0.1/package.tgz';
  options.temp_dir = this.profile.get('temp_dir');
  options.temp_package = node_path.join(options.temp_dir, 'package');

  var self = this;

  function finish (err) {
    if (err) {
      return callback(err);
    }

    callback(null, {
      tar: options.tar,
      pkg: options.pkg
    });
  }

  async.series([
    function (done) {
      self.read_cortex_json('read', options, done);
    },
    function (done) {
      self.run_prepublish_script(options, done);
    },
    function (done) {
      self.read_cortex_json('enhanced', options, done);
    },
    function (done) {
      self.pack(options, done);
    },
    function (done) {
      self.deal_prerelease_version(options, done);
    }
  ], finish);
};

publish.read_cortex_json = function (type, options, callback) {
  var self = this;
  cortex_json[type](options.cwd, function(err, data) {
    if (err) {
      return callback(err);
    }
    options.pkg = data;
    callback(null);
  });
};

publish.run_prepublish_script = function(options, callback) {
  var pkg = options.pkg;
  var script = lang.makeArray(
    pkg.scripts && (
      pkg.scripts.prepublish ||

      // if prepublish is not defined, try to use prebuild
      pkg.scripts.prebuild
    )
  )
  // skip empty scripts
  .filter(Boolean);

  if (!script.length) {
    return callback(null);
  }

  var self = this;

  this.logger.info('{{cyan run}} "scripts.prepublish" ...');

  spawns(script, {
    cwd: options.cwd,
    stdio: 'inherit'

  }).on('spawn', function(command) {
    self.logger.info('{{cyan exec}} "' + command + '" ...');

  }).on('close', function(code, signal) {
    if (code) {
      callback({
        code: 'PREPUBLISH_FAILS',
        message: 'build step "scripts.prepublish" executes as a failure. exit code: ' + code,
        data: {
          code: code,
          signal: signal
        }
      });
    } else {
      callback(null);
    }

  }).on('error', function(err) {
    self.logger.warn('"scripts.prepublish" let out an error: ' + err);
  });
};

publish.pack = function(options, callback) {
  var temp_package = options.temp_package;
  var file = options.tar = node_path.join(options.temp_dir, 'package.tgz');
  var self = this;
  var cwd = options.cwd;

  pf({
    cwd: cwd,
    pkg: options.pkg,
    more: true

  }, function (err, files) {
    if (err) {
      return callback(err);
    }

    async.series([
      function (done) {
        self.copy(files, cwd, temp_package, done);
      },
      function (done) {
        fse.writeJSON(
          node_path.join(temp_package, 'cortex.json'),
          options.pkg,
          done
        );
      },
      function (done) {
        // We validate the temp_package which is filtered and
        // is about to be published to the registry.
        // Make sure it is ok
        cortex_json.validate(temp_package, options.pkg, done);
      },
      function (done) {
        self.logger.info(self.logger.template(self.MESSAGE.COMPRESS_TARBALL, {
          dir: cwd,
          file: file
        }));
        self._pack(temp_package, file, done);
      }

    ], callback);
  });
};

publish.copy = function(paths, from, to, callback) {
  async.each(paths, function(path, done) {
    var src = node_path.join(from, path);

    fs.stat(src, function(err, stats) {
      if (err || !stats.isFile()) {
        // if error, skip copying
        return done(null);
      }

      var dest = node_path.join(to, path);
      fse.copy(src, dest, done);
    });
  }, callback);
};

publish._pack = function(dir, file, callback) {
  fstream.Reader({
    path: dir,
    type: 'Directory'
  })
  .pipe(tar.Pack())
  .pipe(
    node_zlib.createGzip({
      level: 6,
      memLevel: 6
    })
  )
  .pipe(fstream.Writer(file))
  .on('close', callback);
};

publish.deal_prerelease_version = function(options, callback) {
  var pkg = options.pkg;
  var sv = semver.parse(pkg.version);
  var prerelease = sv.prerelease;

  if (options.prerelease) {
    if (prerelease.length === 0) {
      prerelease.push(options.prerelease);

      pkg.version = sv.format();

    } else {
      this.logger.info(this.MESSAGE.HAS_PRERELEASE + '\n');
    }
  }

  callback(null);
};
<|endoftext|>