<commit_before>/**
 * Copyright (c) 2017-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

const React = require('react');

const CompLibrary = require('../../core/CompLibrary.js');

const MarkdownBlock = CompLibrary.MarkdownBlock; /* Used to read markdown */
const Container = CompLibrary.Container;
const GridBlock = CompLibrary.GridBlock;

class HomeSplash extends React.Component {
    render() {
        const {siteConfig, language = ''} = this.props;
        const {baseUrl, docsUrl} = siteConfig;
        const docsPart = `${docsUrl ? `${docsUrl}/` : ''}`;
        const langPart = `${language ? `${language}/` : ''}`;
        const docUrl = doc => `${baseUrl}${docsPart}${langPart}${doc}`;

        const SplashContainer = props => (

{props.children}

        );

        const ProjectTitle = () => (

                {siteConfig.title}
                {siteConfig.tagline}

        );

        const PromoSection = props => (

                        {props.children}

        );

        const Button = props => (

                    {props.children}

        );

        return (
            <SplashContainer>

                    <ProjectTitle siteConfig={siteConfig}/>

                    <PromoSection>
                        <Button href='./docs'>Get Started</Button>
                        <Button href="https://github.com/wvlet/airframe/">GitHub</Button>

                        Star
                    </PromoSection>

            </SplashContainer>
        );
    }
}

class Index extends React.Component {
    render() {
        const {config: siteConfig, language = ''} = this.props;
        const {baseUrl} = siteConfig;

        const Logo = props => (

        );

        const Block = props => (
            <Container
                padding={['bottom', 'top']}
                id={props.id}
                background={props.background}>
                <GridBlock
                    align="center"
                    contents={props.children}
                    layout={props.layout}
                />
            </Container>
        );

        const FeatureCallout = () => (
            <Container
                padding={['bottom', 'top']}
                background="light"
                className="twoColumn">

                    <img width='200px' src={`${baseUrl}img/logos/airframe-logo-tr.png`} alt="Project Logo"/>

            </Container>
        );

        const Features = ({background = 'light'}) => (
            <Block layout="threeColumn">
                {[
                    {
                        content: 'Airframe can be a replacement of commonly-used Java libraries, such as Jackson, Google Guava, Guice, slf4j, log4j, etc. To minimize the dependency hell, almost all components are written from scratch in Scala. Airframe supports Scala 2.11, 2.12, 2.13, and Scala.js.  ',
                        image: `${baseUrl}img/features/scala-logo-red-spiral-dark.png`,
                        imageAlign: 'top',
                        title: 'Designed for Scala',
                    },
                    {
                        content:
                            'Airframe uses [MessagePack-based schema-on-read codec](docs/airframe-codec) for fast and compact object serialization. It can be used for efficient HTTP server-client communication, and automatically resolves differences between data types (e.g., integers and strings.). Serialization with [JSON](docs/airframe-json) is also supported. ',
                        image: `${baseUrl}img/features/msgpack.png`,
                        imageAlign: 'top',
                        title: 'MessagePack Serialization',
                    },
                    {
                        content: 'With [dependency injection (DI)](docs/airframe) of Airframe, building services with hundreds of module classes becomes easy an manageable. Airframe DI will build complex objects on your behalf by following [your custom design](docs/airframe-di#design) and properly [start and shutdown your services in FILO order](docs/airframe#life-cycle).',
                        image: `${baseUrl}img/features/di.png`,
                        imageAlign: 'top',
                        title: 'Dependency Injection'
                    },
                    {
                        content: 'Logging is an essential tool for debugging applications. [airframe-log](docs/airframe-log) helps displaying logs with fancy ANSI colors enriched with the source code locations.',
                        image: `${baseUrl}img/airframe-log/demo.png`,
                        imageAlign: 'top',
                        title: 'Colorful Source Code Logging',
                    },
                    {
                        content: '[airframe-config](docs/airframe-config) supports YAML-based application configurations and provides immutable config objects that can be injected through DI. Partially overriding configutations is also supported.',
                        image: `${baseUrl}img/immutable_config.png`,
                        imageAlign: 'top',
                        title: 'Application Config Flow',
                    },
                    {
                        content: 'Need a way to parse command line options? [airframe-launcher](docs/airframe-launcher) is a handy command line parser that can be used to call Scala functions from the command line arguments.',
                        image: `${baseUrl}/img/features/launcher.png`,
                        imageAlign: 'top',
                        title: 'Command-Line Parser'
                    },
                    {
                        content: '[AirSpec](docs/airspec) is a simple unit testing framework for Scala and Scala.js. You can uses public functions in your classes as test cases. No need to remember complex DSLs to start writing tests in Scala.',
                        image: `${baseUrl}/img/features/airspec.png`,
                        imageAlign: 'top',
                        title: 'Simple Testing Framework'
                    },
                    {
                        content: 'Retrying HTTP requests for API calls is an essential technique for connecting microservices. [airframe-control](docs/airframe-control) provides essential tools for making your requests reliable with exponential backoff retry, jitter, circuit-breaker, rate control, etc.',
                        image: `${baseUrl}/img/features/undraw_process_e90d.svg`,
                        imageAlign: 'top',
                        title: 'Retry, Rate Control'
                    },
                    {
                        content: "[airframe-http](docs/airframe-http) allows building web services by using Scala as an IDL (Interface Definition Language). Airframe provides a ready-to use web server implementation based on [Twitter Finagle](https://twitter.github.io/finagle/guide/) and built-in JSON/MessagePack-based REST API call mapping to support building microservice API servers and clients at ease",
                        image: `${baseUrl}/img/features/finagle.png`,
                        imageAlign: 'top',
                        title: 'Web Service IDL in Scala'
                    },
                    {
                        content: "Developing web applications needs efficient HTTP clients and mock servers even if the network is disconnected. With [airframe-http-recorder](docs/airframe-http-recorder) you can record real server responses and replay them for running unit tests even if the servers are offline.",
                        image: `${baseUrl}/img/features/undraw_server_down_s4lk.svg`,
                        imageAlign: 'top',
                        title: 'HTTP Client and Recorders',
                    },
                    {
                        content: `[airframe-fluentd](docs/airframe-fluentd) supports logging your metrics to fluentd. Collecting metrics is much easier with the type-safe logging of airframe-fluentd.`,
                        image: `${baseUrl}/img/features/Fluentd_square.svg`,
                        imageAlign: 'top',
                        title: 'Fluentd Logging',
                    },
                    {
                        content: "[airframe-metrics](docs/airframe-metrics) provides human-friendly time range selectors (e.g., -1d, -1w) and data units for measuring elapsed time (e.g., 0.1s, 1.5h) and data sizes (e.g., GB, PB.)",
                        image: `${baseUrl}/img/features//undraw_time_management_30iu.svg`,
                        imageAlign: 'top',
                        title: 'Time Series Data Management',
                    },
                ]}
            </Block>
        );

        return (

                <HomeSplash siteConfig={siteConfig} language={language}/>

                    <Features/>

        );
    }
}

module.exports = Index;
<commit_msg>Fix link<commit_after>/**
 * Copyright (c) 2017-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

const React = require('react');

const CompLibrary = require('../../core/CompLibrary.js');

const MarkdownBlock = CompLibrary.MarkdownBlock; /* Used to read markdown */
const Container = CompLibrary.Container;
const GridBlock = CompLibrary.GridBlock;

class HomeSplash extends React.Component {
    render() {
        const {siteConfig, language = ''} = this.props;
        const {baseUrl, docsUrl} = siteConfig;
        const docsPart = `${docsUrl ? `${docsUrl}/` : ''}`;
        const langPart = `${language ? `${language}/` : ''}`;
        const docUrl = doc => `${baseUrl}${docsPart}${langPart}${doc}`;

        const SplashContainer = props => (

{props.children}

        );

        const ProjectTitle = () => (

                {siteConfig.title}
                {siteConfig.tagline}

        );

        const PromoSection = props => (

                        {props.children}

        );

        const Button = props => (

                    {props.children}

        );

        return (
            <SplashContainer>

                    <ProjectTitle siteConfig={siteConfig}/>

                    <PromoSection>
                        <Button href='./docs'>Get Started</Button>
                        <Button href="https://github.com/wvlet/airframe/">GitHub</Button>

                        Star
                    </PromoSection>

            </SplashContainer>
        );
    }
}

class Index extends React.Component {
    render() {
        const {config: siteConfig, language = ''} = this.props;
        const {baseUrl} = siteConfig;

        const Logo = props => (

        );

        const Block = props => (
            <Container
                padding={['bottom', 'top']}
                id={props.id}
                background={props.background}>
                <GridBlock
                    align="center"
                    contents={props.children}
                    layout={props.layout}
                />
            </Container>
        );

        const FeatureCallout = () => (
            <Container
                padding={['bottom', 'top']}
                background="light"
                className="twoColumn">

                    <img width='200px' src={`${baseUrl}img/logos/airframe-logo-tr.png`} alt="Project Logo"/>

            </Container>
        );

        const Features = ({background = 'light'}) => (
            <Block layout="threeColumn">
                {[
                    {
                        content: 'Airframe can be a replacement of commonly-used Java libraries, such as Jackson, Google Guava, Guice, slf4j, log4j, etc. To minimize the dependency hell, almost all components are written from scratch in Scala. Airframe supports Scala 2.11, 2.12, 2.13, and Scala.js.  ',
                        image: `${baseUrl}img/features/scala-logo-red-spiral-dark.png`,
                        imageAlign: 'top',
                        title: 'Designed for Scala',
                    },
                    {
                        content:
                            'Airframe uses [MessagePack-based schema-on-read codec](docs/airframe-codec) for fast and compact object serialization. It can be used for efficient HTTP server-client communication, and automatically resolves differences between data types (e.g., integers and strings.). Serialization with [JSON](docs/airframe-json) is also supported. ',
                        image: `${baseUrl}img/features/msgpack.png`,
                        imageAlign: 'top',
                        title: 'MessagePack Serialization',
                    },
                    {
                        content: 'With [dependency injection (DI)](docs/airframe) of Airframe, building services with hundreds of module classes becomes easy an manageable. Airframe DI will build complex objects on your behalf by following [your custom design](docs/airframe#design) and properly [start and shutdown your services in FILO order](docs/airframe#life-cycle).',
                        image: `${baseUrl}img/features/di.png`,
                        imageAlign: 'top',
                        title: 'Dependency Injection'
                    },
                    {
                        content: 'Logging is an essential tool for debugging applications. [airframe-log](docs/airframe-log) helps displaying logs with fancy ANSI colors enriched with the source code locations.',
                        image: `${baseUrl}img/airframe-log/demo.png`,
                        imageAlign: 'top',
                        title: 'Colorful Source Code Logging',
                    },
                    {
                        content: '[airframe-config](docs/airframe-config) supports YAML-based application configurations and provides immutable config objects that can be injected through DI. Partially overriding configutations is also supported.',
                        image: `${baseUrl}img/immutable_config.png`,
                        imageAlign: 'top',
                        title: 'Application Config Flow',
                    },
                    {
                        content: 'Need a way to parse command line options? [airframe-launcher](docs/airframe-launcher) is a handy command line parser that can be used to call Scala functions from the command line arguments.',
                        image: `${baseUrl}/img/features/launcher.png`,
                        imageAlign: 'top',
                        title: 'Command-Line Parser'
                    },
                    {
                        content: '[AirSpec](docs/airspec) is a simple unit testing framework for Scala and Scala.js. You can uses public functions in your classes as test cases. No need to remember complex DSLs to start writing tests in Scala.',
                        image: `${baseUrl}/img/features/airspec.png`,
                        imageAlign: 'top',
                        title: 'Simple Testing Framework'
                    },
                    {
                        content: 'Retrying HTTP requests for API calls is an essential technique for connecting microservices. [airframe-control](docs/airframe-control) provides essential tools for making your requests reliable with exponential backoff retry, jitter, circuit-breaker, rate control, etc.',
                        image: `${baseUrl}/img/features/undraw_process_e90d.svg`,
                        imageAlign: 'top',
                        title: 'Retry, Rate Control'
                    },
                    {
                        content: "[airframe-http](docs/airframe-http) allows building web services by using Scala as an IDL (Interface Definition Language). Airframe provides a ready-to use web server implementation based on [Twitter Finagle](https://twitter.github.io/finagle/guide/) and built-in JSON/MessagePack-based REST API call mapping to support building microservice API servers and clients at ease",
                        image: `${baseUrl}/img/features/finagle.png`,
                        imageAlign: 'top',
                        title: 'Web Service IDL in Scala'
                    },
                    {
                        content: "Developing web applications needs efficient HTTP clients and mock servers even if the network is disconnected. With [airframe-http-recorder](docs/airframe-http-recorder) you can record real server responses and replay them for running unit tests even if the servers are offline.",
                        image: `${baseUrl}/img/features/undraw_server_down_s4lk.svg`,
                        imageAlign: 'top',
                        title: 'HTTP Client and Recorders',
                    },
                    {
                        content: `[airframe-fluentd](docs/airframe-fluentd) supports logging your metrics to fluentd. Collecting metrics is much easier with the type-safe logging of airframe-fluentd.`,
                        image: `${baseUrl}/img/features/Fluentd_square.svg`,
                        imageAlign: 'top',
                        title: 'Fluentd Logging',
                    },
                    {
                        content: "[airframe-metrics](docs/airframe-metrics) provides human-friendly time range selectors (e.g., -1d, -1w) and data units for measuring elapsed time (e.g., 0.1s, 1.5h) and data sizes (e.g., GB, PB.)",
                        image: `${baseUrl}/img/features//undraw_time_management_30iu.svg`,
                        imageAlign: 'top',
                        title: 'Time Series Data Management',
                    },
                ]}
            </Block>
        );

        return (

                <HomeSplash siteConfig={siteConfig} language={language}/>

                    <Features/>

        );
    }
}

module.exports = Index;
<|endoftext|>


<commit_before>import Utils from './utils/utils';
import JSZip from 'jszip';

export class SceneBundle {

    constructor(url, path) {
        this.url = url;
        this.path = path || Utils.pathForURL(this.url);
    }

    load() {
        return Utils.loadResource(this.url);
    }

    urlFor(url) {
        return Utils.addBaseURL(url, this.path);
    }

}

export class ZipSceneBundle extends SceneBundle {

    constructor(url, path) {
        super(url, path);
        this.zip = null;
        this.files = {};
        this.urls = {};

        // Make root file name by substituting or .yaml extension to .zip file name
        this.root = url.split('/').pop().split('.zip').shift() + '.yaml';
    }

    load() {
        this.zip = new JSZip();

        if (typeof this.url === 'string') {
            return Utils.io(this.url, 60000, 'arraybuffer')
                .then(body => this.zip.loadAsync(body))
                .then(() => this.parseZipFiles())
                .then(() => {
                    let url = this.urlForZipFile(this.root);
                    return Utils.loadResource(url);
                })
                .catch(e => { throw e; });
        } else {
            return Promise.resolve(this);
        }
    }

    urlFor(url) {
        if (Utils.isRelativeURL(url)) {
            return this.urlForZipFile(url);
        }
        return Utils.addBaseURL(url, this.path);
    }

    parseZipFiles() {
        let paths = [];
        let queue = [];
        this.zip.forEach((path, file) => {
            if (!file.dir) {
                paths.push(path);
                queue.push(file.async('arraybuffer'));
            }
        });

        return Promise.all(queue).then(data => {
            for (let i=0; i < data.length; i++) {
                this.files[paths[i]] = { data: data[i] };
            }
        });
    }

    urlForZipFile(file) {
        if (this.files[file]) {
            if (!this.files[file].url) {
                this.files[file].url = Utils.createObjectURL(new Blob([this.files[file].data]));
            }

            return this.files[file].url;
        }
    }

}

export function createSceneBundle(url, path) {
    if (typeof url === 'string' && Utils.extensionForURL(url) === 'zip') {
        return new ZipSceneBundle(url, path);
    }
    return new SceneBundle(url, path);
}
<commit_msg>zip bundles: trying smarter logic for finding scene root: either a single scene YAML file at the root level, OR a scene YAML at root level w/same name as the bundle name, e.g. scene.zip -> scene.yaml<commit_after>import Utils from './utils/utils';
import JSZip from 'jszip';

export class SceneBundle {

    constructor(url, path) {
        this.url = url;
        this.path = path || Utils.pathForURL(this.url);
    }

    load() {
        return Utils.loadResource(this.url);
    }

    urlFor(url) {
        return Utils.addBaseURL(url, this.path);
    }

}

export class ZipSceneBundle extends SceneBundle {

    constructor(url, path) {
        super(url, path);
        this.zip = null;
        this.files = {};
        this.urls = {};
        this.root = null;
    }

    load() {
        this.zip = new JSZip();

        if (typeof this.url === 'string') {
            return Utils.io(this.url, 60000, 'arraybuffer')
                .then(body => this.zip.loadAsync(body))
                .then(() => this.parseZipFiles())
                .then(() => this.loadRoot())
                .catch(e => Promise.reject(e));
        } else {
            return Promise.resolve(this);
        }
    }

    urlFor(url) {
        if (Utils.isRelativeURL(url)) {
            return this.urlForZipFile(url);
        }
        return Utils.addBaseURL(url, this.path);
    }

    loadRoot() {
        return this.findRoot()
            .then(() => Utils.loadResource(this.urlForZipFile(this.root)));
    }

    findRoot() {
        // Must be a single YAML at top level of zip
        let bundle_yaml = this.url.split('/').pop().split('.zip').shift() + '.yaml';
        let root = Object.keys(this.files)
            .filter(path => this.files[path].depth === 0)
            .filter(path => Utils.extensionForURL(path) === 'yaml');

        if (root.length === 1) {
            this.root = root[0];
        }
        else if (root.length > 1) {
            // check for name of bundle w/YAML extension
            let index = root.indexOf(bundle_yaml);
            if (index > -1) {
                this.root = root[index];
            }
        }

        if (!this.root) {
            let msg = `Could not find root scene for bundle '${this.url}': `;
            msg += `there must be either a single scene YAML file at the root level of the zip archive, `;
            msg += `or a scene YAML file with the same name as the archive file, e.g. '${bundle_yaml}'. `;
            if (root.length > 0) {
                msg += `Found these YAML files at the root level: ${root.map(r => '\'' + r + '\'' )}.`;
            }
            else {
                msg += `Found NO YAML files at the root level.`;
            }
            return Promise.reject(Error(msg));
        }
        return Promise.resolve();
    }

    parseZipFiles() {
        let paths = [];
        let queue = [];
        this.zip.forEach((path, file) => {
            if (!file.dir) {
                paths.push(path);
                queue.push(file.async('arraybuffer'));
            }
        });

        return Promise.all(queue).then(data => {
            for (let i=0; i < data.length; i++) {
                let path = paths[i];
                let depth = path.split('/').length - 1;
                this.files[path] = { data: data[i], depth };
            }
        });
    }

    urlForZipFile(file) {
        if (this.files[file]) {
            if (!this.files[file].url) {
                this.files[file].url = Utils.createObjectURL(new Blob([this.files[file].data]));
            }

            return this.files[file].url;
        }
    }

}

export function createSceneBundle(url, path) {
    if (typeof url === 'string' && Utils.extensionForURL(url) === 'zip') {
        return new ZipSceneBundle(url, path);
    }
    return new SceneBundle(url, path);
}
<|endoftext|>


<commit_before>/*jslint sloppy: true */
/*globals Arcadia, LevelSelectScene, localStorage, sona */

var TitleScene = function () {
    Arcadia.Scene.apply(this);

    Arcadia.cycleBackground();

    var titleLabel,
        startButton;

    titleLabel = new Arcadia.Label({
        text: 'Shikaku\nMadness',
        font: '64px monospace',
        position: {
            x: 0,
            y: -100
        }
    });

    this.add(titleLabel);

    startButton = new Arcadia.Button({
        position: { x: 0, y: 200 },
        size: { width: 180, height: 50 },
        color: null,
        border: '3px white',
        text: 'start',
        font: '36px monospace',
        action: function () {
            sona.play('button');
            Arcadia.changeScene(LevelSelectScene);
        }
    });
    this.add(startButton);
};

TitleScene.prototype = new Arcadia.Scene();
<commit_msg>Add buttons for editor/rules<commit_after>/*jslint sloppy: true */
/*globals Arcadia, LevelSelectScene, localStorage, sona */

var TitleScene = function () {
    Arcadia.Scene.apply(this);

    Arcadia.cycleBackground();

    var titleLabel,
        startButton,
        rulesButton,
        editorButton,
        padding = 10;

    titleLabel = new Arcadia.Label({
        text: 'Shikaku\nMadness',
        font: '64px monospace',
        position: {
            x: 0,
            y: -100
        }
    });

    this.add(titleLabel);

    startButton = new Arcadia.Button({
        position: { x: 0, y: 150 },
        size: { width: 180, height: 50 },
        color: null,
        border: '3px white',
        text: 'start',
        font: '36px monospace',
        action: function () {
            sona.play('button');
            Arcadia.changeScene(LevelSelectScene);
        }
    });
    this.add(startButton);

    rulesButton = new Arcadia.Button({
        position: { x: 0, y: startButton.position.y + startButton.size.height + padding },
        size: { width: 180, height: 50 },
        color: null,
        border: '3px white',
        text: 'rules',
        font: '36px monospace',
        action: function () {
            sona.play('button');
            Arcadia.changeScene(RulesScene);
        }
    });
    this.add(rulesButton);

    editorButton = new Arcadia.Button({
        position: { x: 0, y: rulesButton.position.y + rulesButton.size.height + padding },
        size: { width: 180, height: 50 },
        color: null,
        border: '3px white',
        text: 'editor',
        font: '36px monospace',
        action: function () {
            sona.play('button');
            Arcadia.changeScene(EditorScene);
        }
    });
    this.add(editorButton);
};

TitleScene.prototype = new Arcadia.Scene();
<|endoftext|>


<commit_before>
import Schema from '../models/schema'
import Text from '../models/text'
import { List } from 'immutable'

/**
 * Options object with normalize set to `false`.
 *
 * @type {Object}
 */

const OPTS = { normalize: false }

/**
 * Define the core schema rules, order-sensitive.
 *
 * @type {Array}
 */

const rules = [

  /**
   * Only allow block nodes in documents.
   *
   * @type {Object}
   */

  {
    match: (node) => {
      return node.kind == 'document'
    },
    validate: (document) => {
      const invalids = document.nodes.filter(n => n.kind != 'block')
      return invalids.size ? invalids : null
    },
    normalize: (transform, document, invalids) => {
      invalids.forEach((node) => {
        transform.removeNodeByKey(node.key, OPTS)
      })
    }
  },

  /**
   * Only allow block, inline and text nodes in blocks.
   *
   * @type {Object}
   */

  {
    match: (node) => {
      return node.kind == 'block'
    },
    validate: (block) => {
      const invalids = block.nodes.filter((n) => {
        return n.kind != 'block' && n.kind != 'inline' && n.kind != 'text'
      })

      return invalids.size ? invalids : null
    },
    normalize: (transform, block, invalids) => {
      invalids.forEach((node) => {
        transform.removeNodeByKey(node.key, OPTS)
      })
    }
  },

  /**
   * Only allow inline and text nodes in inlines.
   *
   * @type {Object}
   */

  {
    match: (object) => {
      return object.kind == 'inline'
    },
    validate: (inline) => {
      const invalids = inline.nodes.filter(n => n.kind != 'inline' && n.kind != 'text')
      return invalids.size ? invalids : null
    },
    normalize: (transform, inline, invalids) => {
      invalids.forEach((node) => {
        transform.removeNodeByKey(node.key, OPTS)
      })
    }
  },

  /**
   * Ensure that block and inline nodes have at least one text child.
   *
   * @type {Object}
   */

  {
    match: (object) => {
      return object.kind == 'block' || object.kind == 'inline'
    },
    validate: (node) => {
      return node.nodes.size == 0
    },
    normalize: (transform, node) => {
      const text = Text.create()
      transform.insertNodeByKey(node.key, 0, text, OPTS)
    }
  },

  /**
   * Ensure that void nodes contain a text node with a single space of text.
   *
   * @type {Object}
   */

  {
    match: (object) => {
      return (
        (object.kind == 'inline' || object.kind == 'block') &&
        (object.isVoid)
      )
    },
    validate: (node) => {
      return node.text !== ' ' || node.nodes.size !== 1
    },
    normalize: (transform, node, result) => {
      const text = Text.createFromString(' ')
      const index = node.nodes.size

      transform.insertNodeByKey(node.key, index, text, OPTS)

      node.nodes.forEach(child => {
        transform.removeNodeByKey(child.key, OPTS)
      })
    }
  },

  /**
   * Ensure that inline nodes are never empty.
   *
   * This rule is applied to all blocks, because when they contain an empty
   * inline, we need to remove the inline from that parent block. If `validate`
   * was to be memoized, it should be against the parent node, not the inline
   * themselves.
   *
   * @type {Object}
   */

  {
    match: (object) => {
      return object.kind == 'block'
    },
    validate: (block) => {
      const invalids = block.nodes.filter(n => n.kind == 'inline' && n.text == '')
      return invalids.size ? invalids : null
    },
    normalize: (transform, block, invalids) => {
      // If all of the block's nodes are invalid, insert an empty text node so
      // that the selection will be preserved when they are all removed.
      if (block.nodes.size == invalids.size) {
        const text = Text.create()
        transform.insertNodeByKey(block.key, 1, text, OPTS)
      }

      invalids.forEach((node) => {
        transform.removeNodeByKey(node.key, OPTS)
      })
    }
  },

  /**
   * Ensure that inline void nodes are surrounded by text nodes, by adding extra
   * blank text nodes if necessary.
   *
   * @type {Object}
   */

  {
    match: (object) => {
      return object.kind == 'block' || object.kind == 'inline'
    },
    validate: (node) => {
      const invalids = node.nodes.reduce((list, child, index) => {
        if (child.kind == 'block') return list
        if (!child.isVoid) return list

        const prev = index > 0 ? node.nodes.get(index - 1) : null
        const next = node.nodes.get(index + 1)
        const insertBefore = !prev
        const insertAfter = !next || (next.kind == 'inline')

        if (insertAfter || insertBefore) {
          list = list.push({ insertAfter, insertBefore, index })
        }

        return list
      }, new List())

      return invalids.size ? invalids : null
    },
    normalize: (transform, block, invalids) => {
      // Shift for every text node inserted previously.
      let shift = 0

      invalids.forEach(({ index, insertAfter, insertBefore }) => {
        if (insertBefore) {
          transform.insertNodeByKey(block.key, shift + index, Text.create(), OPTS)
          shift++
        }

        if (insertAfter) {
          transform.insertNodeByKey(block.key, shift + index + 1, Text.create(), OPTS)
          shift++
        }
      })
    }
  },

  /**
   * Join adjacent text nodes.
   *
   * @type {Object}
   */

  {
    match: (object) => {
      return object.kind == 'block' || object.kind == 'inline'
    },
    validate: (node) => {
      const invalids = node.nodes
        .map((child, i) => {
          const next = node.nodes.get(i + 1)
          if (child.kind != 'text') return
          if (!next || next.kind != 'text') return
          return [child, next]
        })
        .filter(Boolean)

      return invalids.size ? invalids : null
    },
    normalize: (transform, node, pairs) => {
      // We reverse the list to handle consecutive joins, since the earlier nodes
      // will always exist after each join.
      pairs.reverse().forEach((pair) => {
        const [ first, second ] = pair
        return transform.joinNodeByKey(second.key, first.key, OPTS)
      })
    }
  },

  /**
   * Prevent extra empty text nodes, except when adjacent to inline void nodes.
   *
   * @type {Object}
   */

  {
    match: (object) => {
      return object.kind == 'block' || object.kind == 'inline'
    },
    validate: (node) => {
      const { nodes } = node
      if (nodes.size <= 1) return

      const invalids = nodes.filter((desc, i) => {
        if (desc.kind != 'text') return
        if (desc.length > 0) return

        const prev = i > 0 ? nodes.get(i - 1) : null
        const next = nodes.get(i + 1)

        // If it's the first node, and the next is a void, preserve it.
        if (!prev && next.kind == 'inline') return

        // It it's the last node, and the previous is an inline, preserve it.
        if (!next && prev.kind == 'inline') return

        // If it's surrounded by inlines, preserve it.
        if (next && prev && next.kind == 'inline' && prev.kind == 'inline') return

        // Otherwise, remove it.
        return true
      })

      return invalids.size ? invalids : null
    },
    normalize: (transform, node, invalids) => {
      invalids.forEach((text) => {
        transform.removeNodeByKey(text.key, OPTS)
      })
    }
  }

]

/**
 * Create the core schema.
 *
 * @type {Schema}
 */

const SCHEMA = Schema.create({ rules })

/**
 * Export.
 *
 * @type {Schema}
 */

export default SCHEMA
<commit_msg>Fix condition in core rule to add test around all inlines<commit_after>
import Schema from '../models/schema'
import Text from '../models/text'
import { List } from 'immutable'

/**
 * Options object with normalize set to `false`.
 *
 * @type {Object}
 */

const OPTS = { normalize: false }

/**
 * Define the core schema rules, order-sensitive.
 *
 * @type {Array}
 */

const rules = [

  /**
   * Only allow block nodes in documents.
   *
   * @type {Object}
   */

  {
    match: (node) => {
      return node.kind == 'document'
    },
    validate: (document) => {
      const invalids = document.nodes.filter(n => n.kind != 'block')
      return invalids.size ? invalids : null
    },
    normalize: (transform, document, invalids) => {
      invalids.forEach((node) => {
        transform.removeNodeByKey(node.key, OPTS)
      })
    }
  },

  /**
   * Only allow block, inline and text nodes in blocks.
   *
   * @type {Object}
   */

  {
    match: (node) => {
      return node.kind == 'block'
    },
    validate: (block) => {
      const invalids = block.nodes.filter((n) => {
        return n.kind != 'block' && n.kind != 'inline' && n.kind != 'text'
      })

      return invalids.size ? invalids : null
    },
    normalize: (transform, block, invalids) => {
      invalids.forEach((node) => {
        transform.removeNodeByKey(node.key, OPTS)
      })
    }
  },

  /**
   * Only allow inline and text nodes in inlines.
   *
   * @type {Object}
   */

  {
    match: (object) => {
      return object.kind == 'inline'
    },
    validate: (inline) => {
      const invalids = inline.nodes.filter(n => n.kind != 'inline' && n.kind != 'text')
      return invalids.size ? invalids : null
    },
    normalize: (transform, inline, invalids) => {
      invalids.forEach((node) => {
        transform.removeNodeByKey(node.key, OPTS)
      })
    }
  },

  /**
   * Ensure that block and inline nodes have at least one text child.
   *
   * @type {Object}
   */

  {
    match: (object) => {
      return object.kind == 'block' || object.kind == 'inline'
    },
    validate: (node) => {
      return node.nodes.size == 0
    },
    normalize: (transform, node) => {
      const text = Text.create()
      transform.insertNodeByKey(node.key, 0, text, OPTS)
    }
  },

  /**
   * Ensure that void nodes contain a text node with a single space of text.
   *
   * @type {Object}
   */

  {
    match: (object) => {
      return (
        (object.kind == 'inline' || object.kind == 'block') &&
        (object.isVoid)
      )
    },
    validate: (node) => {
      return node.text !== ' ' || node.nodes.size !== 1
    },
    normalize: (transform, node, result) => {
      const text = Text.createFromString(' ')
      const index = node.nodes.size

      transform.insertNodeByKey(node.key, index, text, OPTS)

      node.nodes.forEach(child => {
        transform.removeNodeByKey(child.key, OPTS)
      })
    }
  },

  /**
   * Ensure that inline nodes are never empty.
   *
   * This rule is applied to all blocks, because when they contain an empty
   * inline, we need to remove the inline from that parent block. If `validate`
   * was to be memoized, it should be against the parent node, not the inline
   * themselves.
   *
   * @type {Object}
   */

  {
    match: (object) => {
      return object.kind == 'block'
    },
    validate: (block) => {
      const invalids = block.nodes.filter(n => n.kind == 'inline' && n.text == '')
      return invalids.size ? invalids : null
    },
    normalize: (transform, block, invalids) => {
      // If all of the block's nodes are invalid, insert an empty text node so
      // that the selection will be preserved when they are all removed.
      if (block.nodes.size == invalids.size) {
        const text = Text.create()
        transform.insertNodeByKey(block.key, 1, text, OPTS)
      }

      invalids.forEach((node) => {
        transform.removeNodeByKey(node.key, OPTS)
      })
    }
  },

  /**
   * Ensure that inline void nodes are surrounded by text nodes, by adding extra
   * blank text nodes if necessary.
   *
   * @type {Object}
   */

  {
    match: (object) => {
      return object.kind == 'block' || object.kind == 'inline'
    },
    validate: (node) => {
      const invalids = node.nodes.reduce((list, child, index) => {
        if (child.kind !== 'inline') return list

        const prev = index > 0 ? node.nodes.get(index - 1) : null
        const next = node.nodes.get(index + 1)
        // We don't test if "prev" is inline, since it has already been processed in the loop
        const insertBefore = !prev
        const insertAfter = !next || (next.kind == 'inline')

        if (insertAfter || insertBefore) {
          list = list.push({ insertAfter, insertBefore, index })
        }

        return list
      }, new List())

      return invalids.size ? invalids : null
    },
    normalize: (transform, block, invalids) => {
      // Shift for every text node inserted previously.
      let shift = 0

      invalids.forEach(({ index, insertAfter, insertBefore }) => {
        if (insertBefore) {
          transform.insertNodeByKey(block.key, shift + index, Text.create(), OPTS)
          shift++
        }

        if (insertAfter) {
          transform.insertNodeByKey(block.key, shift + index + 1, Text.create(), OPTS)
          shift++
        }
      })
    }
  },

  /**
   * Join adjacent text nodes.
   *
   * @type {Object}
   */

  {
    match: (object) => {
      return object.kind == 'block' || object.kind == 'inline'
    },
    validate: (node) => {
      const invalids = node.nodes
        .map((child, i) => {
          const next = node.nodes.get(i + 1)
          if (child.kind != 'text') return
          if (!next || next.kind != 'text') return
          return [child, next]
        })
        .filter(Boolean)

      return invalids.size ? invalids : null
    },
    normalize: (transform, node, pairs) => {
      // We reverse the list to handle consecutive joins, since the earlier nodes
      // will always exist after each join.
      pairs.reverse().forEach((pair) => {
        const [ first, second ] = pair
        return transform.joinNodeByKey(second.key, first.key, OPTS)
      })
    }
  },

  /**
   * Prevent extra empty text nodes, except when adjacent to inline void nodes.
   *
   * @type {Object}
   */

  {
    match: (object) => {
      return object.kind == 'block' || object.kind == 'inline'
    },
    validate: (node) => {
      const { nodes } = node
      if (nodes.size <= 1) return

      const invalids = nodes.filter((desc, i) => {
        if (desc.kind != 'text') return
        if (desc.length > 0) return

        const prev = i > 0 ? nodes.get(i - 1) : null
        const next = nodes.get(i + 1)

        // If it's the first node, and the next is a void, preserve it.
        if (!prev && next.kind == 'inline') return

        // It it's the last node, and the previous is an inline, preserve it.
        if (!next && prev.kind == 'inline') return

        // If it's surrounded by inlines, preserve it.
        if (next && prev && next.kind == 'inline' && prev.kind == 'inline') return

        // Otherwise, remove it.
        return true
      })

      return invalids.size ? invalids : null
    },
    normalize: (transform, node, invalids) => {
      invalids.forEach((text) => {
        transform.removeNodeByKey(text.key, OPTS)
      })
    }
  }

]

/**
 * Create the core schema.
 *
 * @type {Schema}
 */

const SCHEMA = Schema.create({ rules })

/**
 * Export.
 *
 * @type {Schema}
 */

export default SCHEMA
<|endoftext|>


<commit_before>// Modules
var Type = require('type-of-is')

// Constants
var DRAFT = 'http://json-schema.org/draft-04/schema#'

function getPropertyFormat(value) {
  var type = Type.string(value).toLowerCase()

  if (type === 'date') return 'date-time'

  return null
}

function getPropertyType(value) {
  var type = Type.string(value).toLowerCase()

  if (type === 'number') return Number.isInteger(value) ? 'integer' : type
  if (type === 'date') return 'string'
  if (type === 'regexp') return 'string'
  if (type === 'function') return 'string'

  return type
}

function getUniqueKeys(a, b, c) {
  a = Object.keys(a)
  b = Object.keys(b)
  c = c || []

  var value
  var cIndex
  var aIndex

  for (var keyIndex = 0, keyLength = b.length; keyIndex < keyLength; keyIndex++) {
    value = b[keyIndex]
    aIndex = a.indexOf(value)
    cIndex = c.indexOf(value)

    if (aIndex === -1) {
      if (cIndex !== -1) {
        // Value is optional, it doesn't exist in A but exists in B(n)
        c.splice(cIndex, 1)
      }
    } else if (cIndex === -1) {
      // Value is required, it exists in both B and A, and is not yet present in C
      c.push(value)
    }
  }

  return c
}

function processArray(array, output, nested) {
  var format
  var oneOf
  var type

  if (nested && output) {
    output = { items: output }
  } else {
    output = output || {}
    output.type = getPropertyType(array)
    output.items = output.items || {}
    type = output.items.type || null
  }

  // Determine whether each item is different
  for (var arrIndex = 0, arrLength = array.length; arrIndex < arrLength; arrIndex++) {
    var elementType = getPropertyType(array[arrIndex])
    var elementFormat = getPropertyFormat(array[arrIndex])

    if (type && elementType !== type) {
      output.items.oneOf = []
      oneOf = true
      break
    } else {
      type = elementType
      format = elementFormat
    }
  }

  // Setup type otherwise
  if (!oneOf && type) {
    output.items.type = type
    if (format) {
      output.items.format = format
    }
  } else if (oneOf && type !== 'object') {
    output.items = {
      oneOf: [{ type: type }],
      required: output.items.required
    }
  }

  // Process each item depending
  if (typeof output.items.oneOf !== 'undefined' || type === 'object') {
    for (var itemIndex = 0, itemLength = array.length; itemIndex < itemLength; itemIndex++) {
      var value = array[itemIndex]
      var itemType = getPropertyType(value)
      var itemFormat = getPropertyFormat(value)
      var arrayItem
      if (itemType === 'object') {
        if (output.items.properties) {
          output.items.required = getUniqueKeys(output.items.properties, value, output.items.required)
        }
        arrayItem = processObject(value, oneOf ? {} : output.items.properties, true)
      } else if (itemType === 'array') {
        arrayItem = processArray(value, oneOf ? {} : output.items.properties, true)
      } else {
        arrayItem = {}
        arrayItem.type = itemType
        if (itemFormat) {
          arrayItem.format = itemFormat
        }
      }
      if (oneOf) {
        var childType = Type.string(value).toLowerCase()
        var tempObj = {}
        if (!arrayItem.type && childType === 'object') {
          tempObj.properties = arrayItem
          tempObj.type = 'object'
          arrayItem = tempObj
        }
        output.items.oneOf.push(arrayItem)
      } else {
        if (output.items.type !== 'object') {
          continue;
        }
        output.items.properties = arrayItem
      }
    }
  }
  return nested ? output.items : output
}

function processObject(object, output, nested) {
  if (nested && output) {
    output = { properties: output }
  } else {
    output = output || {}
    output.type = getPropertyType(object)
    output.properties = output.properties || {}
    output.required = Object.keys(object)
  }

  for (var key in object) {
    var value = object[key]
    var type = getPropertyType(value)
    var format = getPropertyFormat(value)

    type = type === 'undefined' ? 'null' : type

    if (type === 'object') {
      output.properties[key] = processObject(value, output.properties[key])
      continue
    }

    if (type === 'array') {
      output.properties[key] = processArray(value, output.properties[key])
      continue
    }

    if (output.properties[key]) {
      var entry = output.properties[key]
      var hasTypeArray = Array.isArray(entry.type)

      // When an array already exists, we check the existing
      // type array to see if it contains our current property
      // type, if not, we add it to the array and continue
      if (hasTypeArray && entry.type.indexOf(type) < 0) {
        entry.type.push(type)
      }

      // When multiple fields of differing types occur,
      // json schema states that the field must specify the
      // primitive types the field allows in array format.
      if (!hasTypeArray && entry.type !== type) {
        entry.type = [entry.type, type]
      }

      continue
    }

    output.properties[key] = {}
    output.properties[key].type = type

    if (format) {
      output.properties[key].format = format
    }
  }

  return nested ? output.properties : output
}

module.exports = function Process (title, object) {
  var processOutput
  var output = {
    $schema: DRAFT
  }

  // Determine title exists
  if (typeof title !== 'string') {
    object = title
    title = undefined
  } else {
    output.title = title
  }

  // Set initial object type
  output.type = Type.string(object).toLowerCase()

  // Process object
  if (output.type === 'object') {
    processOutput = processObject(object)
    output.type = processOutput.type
    output.properties = processOutput.properties
    output.required = Object.keys(object).filter(function (key) {
      return ['$schema'].includes(key)
    })
  }

  if (output.type === 'array') {
    processOutput = processArray(object)
    output.type = processOutput.type
    output.items = processOutput.items

    if (output.title) {
      output.items.title = output.title
      output.title += ' Set'
    }
  }

  // Output
  return output
}
<commit_msg>Update json.js<commit_after>// Modules
var Type = require('type-of-is')

// Constants
var DRAFT = 'http://json-schema.org/draft-04/schema#'

function getPropertyFormat(value) {
  var type = Type.string(value).toLowerCase()

  if (type === 'date') return 'date-time'

  return null
}

function getPropertyType(value) {
  var type = Type.string(value).toLowerCase()

  if (type === 'number') return Number.isInteger(value) ? 'integer' : type
  if (type === 'date') return 'string'
  if (type === 'regexp') return 'string'
  if (type === 'function') return 'string'

  return type
}

function getUniqueKeys(a, b, c) {
  a = Object.keys(a)
  b = Object.keys(b)
  c = c || []

  var value
  var cIndex
  var aIndex

  for (var keyIndex = 0, keyLength = b.length; keyIndex < keyLength; keyIndex++) {
    value = b[keyIndex]
    aIndex = a.indexOf(value)
    cIndex = c.indexOf(value)

    if (aIndex === -1) {
      if (cIndex !== -1) {
        // Value is optional, it doesn't exist in A but exists in B(n)
        c.splice(cIndex, 1)
      }
    } else if (cIndex === -1) {
      // Value is required, it exists in both B and A, and is not yet present in C
      c.push(value)
    }
  }

  return c
}

function processArray(array, output, nested) {
  var format
  var oneOf
  var type

  if (nested && output) {
    output = { items: output }
  } else {
    output = output || {}
    output.type = getPropertyType(array)
    output.items = output.items || {}
    type = output.items.type || null
  }

  // Determine whether each item is different
  for (var arrIndex = 0, arrLength = array.length; arrIndex < arrLength; arrIndex++) {
    var elementType = getPropertyType(array[arrIndex])
    var elementFormat = getPropertyFormat(array[arrIndex])

    if (type && elementType !== type) {
      output.items.oneOf = []
      oneOf = true
      break
    } else {
      type = elementType
      format = elementFormat
    }
  }

  // Setup type otherwise
  if (!oneOf && type) {
    output.items.type = type
    if (format) {
      output.items.format = format
    }
  } else if (oneOf && type !== 'object') {
    output.items = {
      oneOf: [{ type: type }],
      required: output.items.required
    }
  }

  // Process each item depending
  if (typeof output.items.oneOf !== 'undefined' || type === 'object') {
    for (var itemIndex = 0, itemLength = array.length; itemIndex < itemLength; itemIndex++) {
      var value = array[itemIndex]
      var itemType = getPropertyType(value)
      var itemFormat = getPropertyFormat(value)
      var arrayItem
      if (itemType === 'object') {
        if (output.items.properties) {
          output.items.required = getUniqueKeys(output.items.properties, value, output.items.required)
        }
        arrayItem = processObject(value, oneOf ? {} : output.items.properties, true)
      } else if (itemType === 'array') {
        arrayItem = processArray(value, oneOf ? {} : output.items.properties, true)
      } else {
        arrayItem = {}
        arrayItem.type = itemType
        if (itemFormat) {
          arrayItem.format = itemFormat
        }
      }
      if (oneOf) {
        var childType = Type.string(value).toLowerCase()
        var tempObj = {}
        if (!arrayItem.type && childType === 'object') {
          tempObj.properties = arrayItem
          tempObj.type = 'object'
          arrayItem = tempObj
        }
        output.items.oneOf.push(arrayItem)
      } else {
        if (output.items.type !== 'object') {
          continue;
        }
        output.items.properties = arrayItem
      }
    }
  }
  return nested ? output.items : output
}

function processObject(object, output, nested) {
  if (nested && output) {
    output = { properties: output }
  } else {
    output = output || {}
    output.type = getPropertyType(object)
    output.properties = output.properties || {}
    output.required = Object.keys(object)
  }

  for (var key in object) {
    var value = object[key]
    var type = getPropertyType(value)
    var format = getPropertyFormat(value)

    type = type === 'undefined' ? 'null' : type

    if (type === 'object') {
      output.properties[key] = processObject(value, output.properties[key])
      continue
    }

    if (type === 'array') {
      output.properties[key] = processArray(value, output.properties[key])
      continue
    }

    if (output.properties[key]) {
      var entry = output.properties[key]
      var hasTypeArray = Array.isArray(entry.type)

      // When an array already exists, we check the existing
      // type array to see if it contains our current property
      // type, if not, we add it to the array and continue
      if (hasTypeArray && entry.type.indexOf(type) < 0) {
        entry.type.push(type)
      }

      // When multiple fields of differing types occur,
      // json schema states that the field must specify the
      // primitive types the field allows in array format.
      if (!hasTypeArray && entry.type !== type) {
        entry.type = [entry.type, type]
      }

      continue
    }

    output.properties[key] = {}
    output.properties[key].type = type

    if (format) {
      output.properties[key].format = format
    }
  }

  return nested ? output.properties : output
}

module.exports = function Process (title, object) {
  var processOutput
  var output = {
    $schema: DRAFT
  }

  // Determine title exists
  if (typeof title !== 'string') {
    object = title
    title = undefined
  } else {
    output.title = title
  }

  // Set initial object type
  output.type = Type.string(object).toLowerCase()

  // Process object
  if (output.type === 'object') {
    processOutput = processObject(object)
    output.type = processOutput.type
    output.properties = processOutput.properties
    output.required = Object.keys(object).filter(function (key) {
      return !['$schema'].includes(key)
    })
  }

  if (output.type === 'array') {
    processOutput = processArray(object)
    output.type = processOutput.type
    output.items = processOutput.items

    if (output.title) {
      output.items.title = output.title
      output.title += ' Set'
    }
  }

  // Output
  return output
}
<|endoftext|>


<commit_before>/**
 * @namespace ajax
 * @summary module to make ajax requests
 */
var ajax = (function() {
    "use strict";
    /**
     * @summary loader HTML element injected into loaderTarget when ajax is running
     * @private
     * @type {Element}
     */
    var loader = document.createElement("div");
    loader.className = "ajax-loader";

    /**
     * @memberof ajax
     * @summary injects the loader element into loaderTarget
     * @private
     * @param target {Element}
     */
    function startLoader(target) {
        target.appendChild(loader);
    }

    /**
     * @memberof ajax
     * @summary removes the loader from loaderTarget
     * @private
     * @param target {Element}
     */
    function stopLoader(target) {
        target.removeChild(loader);
    }

    /**
     * @memberof ajax
     * @summary executes the XMLHttpRequest
     * @private
     * @param c {object} request configuration hash
     */
    function sendRequest(c) {
        var req = new XMLHttpRequest();

        if (c.loaderTarget) {
            startLoader(c.loaderTarget);
        }

        // start XMLHttpRequest
        req.open(c.method, c.url, c.async);
        setRequestHeaders(req, c.setHeaders);

        // request now going through
        req.onreadystatechange = function() {
            // Headers & status are received
            if (req.readyState === 2) {
                if (c.onHeaders) {
                    c.onHeaders(req.getAllResponseHeaders());
                }
            }

            // request is complete and successful
            if (req.readyState === 4) {
                // loader needs to be removed BEFORE callbacks
                if (c.loaderTarget) {
                    stopLoader(c.loaderTarget);
                }

                // process success or failure callbacks
                if (req.status.toString().charAt(0) === "2" && c.onSuccess) {
                    c.onSuccess({
                        response: getResponse(req, c),
                        status: req.status,
                        getHeader: function(name) {
                            return req.getResponseHeader.call(req, name);
                        }
                    });
                } else if (c.onFailure) {
                    c.onFailure({
                        response: getResponse(req, c),
                        status: req.status,
                        getHeader: function(name) {
                            return req.getResponseHeader.call(req, name);
                        }
                    });
                }
            }
        };
        req.send(c.data);
    }

    /**
     * @memberof ajax
     * @summary sets basic headers for the request and sets the additional ones provided by the configuration
     * @private
     * @param req {object} XMLHttpRequest object
     * @param headers {object} additional headers to be injected
     */
    function setRequestHeaders(req, headers) {
        // set default values
        if (!headers["Content-Type"]) {
            headers["Content-Type"] = "application/json;charset=utf-8";
        }

        if (!headers.Accept) {
            headers.Accept = "application/json";
        }

        if (!headers["X-Requested-With"]) {
            headers["X-Requested-With"] = "XMLHttpRequest";
        }

        // get all object (t) keys from own properties
        // inject them as request headers
        Object.keys(headers).forEach(function(header) {
            req.setRequestHeader(header, headers[header]);
        });

        // xhr2 spec
        if (req.responseType) {
            req.responseType = c.responseType; // "arraybuffer", "blob", "document", "json", "text"
        }
    }

    /**
     * @memberof ajax
     * @summary parses the response data based on provided responseType
     * @private
     * @param req {object} XMLHttpRequest object
     * @param c {object} configuration hash
     * @returns the parsed data
     */
    function getResponse(req, c) {
        var r = req.response;

        if (c.responseType && c.responseType === "json" && r !== "") {
            r = JSON.parse(r);
        }

        return r;
    }

    /**
     * @memberof ajax
     * @private
     * @summary verifies content provided by configuration object
     * @param c {object} configuration hash
     * @returns {boolean} result of validation (true|false)
     */
    function validateConfig(c) {
        if (Object.prototype.toString.call(c.url) !== "[object String]") {
            throw new TypeError("ajax: requires a URL string");
        }

        if (c.loaderTarget && c.loaderTarget.nodeType !== 1) {
            throw new TypeError("ajax: 'loaderTarget' is not an HTML element");
        }

        if (Object.prototype.toString.call(c.method) === "[object String]") {
            c.method = c.method.toUpperCase();
            if (!["GET","POST","PUT","DELETE"].some(function(method) {
                return method === c.method;
            })) {
                throw new TypeError("ajax: 'method' must have one of the following values:\nGET\nPOST\nPUT\nDelete");
            }
        } else {
            throw Error("ajax: query 'method' is required");
        }

        if (c.setHeaders && Object.prototype.toString.call(c.setHeaders) !== "[object Object]") {
            throw new TypeError("ajax: 'setHeaders' is not an object");
        }

        if (c.onFailure && Object.prototype.toString.call(c.onFailure) !== "[object Function]") {
            throw new TypeError("ajax: onFailure must be a function");
        }
        if (c.onSuccess && Object.prototype.toString.call(c.onSuccess) !== "[object Function]") {
            throw new TypeError("ajax: onFailure must be a function");
        }
        if (c.onHeaders && Object.prototype.toString.call(c.onHEaders) !== "[object Function]") {
            throw new TypeError("ajax: onFailure must be a function");
        }

        if (c.responseType) {
            if (!["json","text","arraybuffer","document","blob"].some(function(value) {
                    return value === c.responseType;
                })) {
                throw new Error("ajax: responseType must have one of the following value:\njson\ntext\ndocument\nblob\narraybuffer");
            }
        }

        return true;
    }

    /**
     * @memberof ajax
     * @private
     * @summary builds the final request configuration object
     * @param c {object} configuration hash
     * @returns {
     *  {
     *   async: boolean,
     *   data: (object|null),
     *   setHeaders: (object|{}),
     *   method: string,
     *   onFailure: (function|null),
     *   onHeaders: (function|null),
     *   onSuccess: (function|null),
     *   responseType: (string),
     *   url: string,
     *   loaderTarget: (Element|null)
     *   }
     *  }
     */
    function finalizeConfig(c) {
        return {
            async: !!c.async,
            data: c.data || null,
            setHeaders: c.setHeaders || {},
            method: c.method,
            onFailure: c.onFailure || null,
            onHeaders: c.onHeaders || null,
            onSuccess: c.onSuccess || null,
            responseType: c.responseType || "text",
            url: encodeURI(c.url).replace(/%5B/g, "[").replace(/%5D/g, "]"),
            loaderTarget: c.loadTarget || null
        };
    }

    function query(c) {
        if (validateConfig(c)) {
            sendRequest(finalizeConfig(c));
        }
    }

    return query;
}());
<commit_msg>all requests are now asynchronous by default was double casting to boolean...<commit_after>/**
 * @namespace ajax
 * @summary module to make ajax requests
 */
var ajax = (function() {
    "use strict";
    /**
     * @summary loader HTML element injected into loaderTarget when ajax is running
     * @private
     * @type {Element}
     */
    var loader = document.createElement("div");
    loader.className = "ajax-loader";

    /**
     * @memberof ajax
     * @summary injects the loader element into loaderTarget
     * @private
     * @param target {Element}
     */
    function startLoader(target) {
        target.appendChild(loader);
    }

    /**
     * @memberof ajax
     * @summary removes the loader from loaderTarget
     * @private
     * @param target {Element}
     */
    function stopLoader(target) {
        target.removeChild(loader);
    }

    /**
     * @memberof ajax
     * @summary executes the XMLHttpRequest
     * @private
     * @param c {object} request configuration hash
     */
    function sendRequest(c) {
        var req = new XMLHttpRequest();

        if (c.loaderTarget) {
            startLoader(c.loaderTarget);
        }

        // start XMLHttpRequest
        req.open(c.method, c.url, c.async);
        setRequestHeaders(req, c.setHeaders);

        // request now going through
        req.onreadystatechange = function() {
            // Headers & status are received
            if (req.readyState === 2) {
                if (c.onHeaders) {
                    c.onHeaders(req.getAllResponseHeaders());
                }
            }

            // request is complete and successful
            if (req.readyState === 4) {
                // loader needs to be removed BEFORE callbacks
                if (c.loaderTarget) {
                    stopLoader(c.loaderTarget);
                }

                // process success or failure callbacks
                if (req.status.toString().charAt(0) === "2" && c.onSuccess) {
                    c.onSuccess({
                        response: getResponse(req, c),
                        status: req.status,
                        getHeader: function(name) {
                            return req.getResponseHeader.call(req, name);
                        }
                    });
                } else if (c.onFailure) {
                    c.onFailure({
                        response: getResponse(req, c),
                        status: req.status,
                        getHeader: function(name) {
                            return req.getResponseHeader.call(req, name);
                        }
                    });
                }
            }
        };
        req.send(c.data);
    }

    /**
     * @memberof ajax
     * @summary sets basic headers for the request and sets the additional ones provided by the configuration
     * @private
     * @param req {object} XMLHttpRequest object
     * @param headers {object} additional headers to be injected
     */
    function setRequestHeaders(req, headers) {
        // set default values
        if (!headers["Content-Type"]) {
            headers["Content-Type"] = "application/json;charset=utf-8";
        }

        if (!headers.Accept) {
            headers.Accept = "application/json";
        }

        if (!headers["X-Requested-With"]) {
            headers["X-Requested-With"] = "XMLHttpRequest";
        }

        // get all object (t) keys from own properties
        // inject them as request headers
        Object.keys(headers).forEach(function(header) {
            req.setRequestHeader(header, headers[header]);
        });

        // xhr2 spec
        if (req.responseType) {
            req.responseType = c.responseType; // "arraybuffer", "blob", "document", "json", "text"
        }
    }

    /**
     * @memberof ajax
     * @summary parses the response data based on provided responseType
     * @private
     * @param req {object} XMLHttpRequest object
     * @param c {object} configuration hash
     * @returns the parsed data
     */
    function getResponse(req, c) {
        var r = req.response;

        if (c.responseType && c.responseType === "json" && r !== "") {
            r = JSON.parse(r);
        }

        return r;
    }

    /**
     * @memberof ajax
     * @private
     * @summary verifies content provided by configuration object
     * @param c {object} configuration hash
     * @returns {boolean} result of validation (true|false)
     */
    function validateConfig(c) {
        if (Object.prototype.toString.call(c.url) !== "[object String]") {
            throw new TypeError("ajax: requires a URL string");
        }

        if (c.loaderTarget && c.loaderTarget.nodeType !== 1) {
            throw new TypeError("ajax: 'loaderTarget' is not an HTML element");
        }

        if (Object.prototype.toString.call(c.method) === "[object String]") {
            c.method = c.method.toUpperCase();
            if (!["GET","POST","PUT","DELETE"].some(function(method) {
                return method === c.method;
            })) {
                throw new TypeError("ajax: 'method' must have one of the following values:\nGET\nPOST\nPUT\nDelete");
            }
        } else {
            throw Error("ajax: query 'method' is required");
        }

        if (c.setHeaders && Object.prototype.toString.call(c.setHeaders) !== "[object Object]") {
            throw new TypeError("ajax: 'setHeaders' is not an object");
        }

        if (c.onFailure && Object.prototype.toString.call(c.onFailure) !== "[object Function]") {
            throw new TypeError("ajax: onFailure must be a function");
        }
        if (c.onSuccess && Object.prototype.toString.call(c.onSuccess) !== "[object Function]") {
            throw new TypeError("ajax: onFailure must be a function");
        }
        if (c.onHeaders && Object.prototype.toString.call(c.onHEaders) !== "[object Function]") {
            throw new TypeError("ajax: onFailure must be a function");
        }

        if (c.responseType) {
            if (!["json","text","arraybuffer","document","blob"].some(function(value) {
                    return value === c.responseType;
                })) {
                throw new Error("ajax: responseType must have one of the following value:\njson\ntext\ndocument\nblob\narraybuffer");
            }
        }

        return true;
    }

    /**
     * @memberof ajax
     * @private
     * @summary builds the final request configuration object
     * @param c {object} configuration hash
     * @returns {
     *  {
     *   async: boolean,
     *   data: (object|null),
     *   setHeaders: (object|{}),
     *   method: string,
     *   onFailure: (function|null),
     *   onHeaders: (function|null),
     *   onSuccess: (function|null),
     *   responseType: (string),
     *   url: string,
     *   loaderTarget: (Element|null)
     *   }
     *  }
     */
    function finalizeConfig(c) {
        return {
            async: c.async !== false,
            data: c.data || null,
            setHeaders: c.setHeaders || {},
            method: c.method,
            onFailure: c.onFailure || null,
            onHeaders: c.onHeaders || null,
            onSuccess: c.onSuccess || null,
            responseType: c.responseType || "text",
            url: encodeURI(c.url).replace(/%5B/g, "[").replace(/%5D/g, "]"),
            loaderTarget: c.loadTarget || null
        };
    }

    function query(c) {
        if (validateConfig(c)) {
            sendRequest(finalizeConfig(c));
        }
    }

    return query;
}());
<|endoftext|>


<commit_before>var browser = chrome || browser;

// define matches methode according to browser
var elementProto = Element.prototype;
var matchesFn = ['webkit', 'ms', 'moz', 'o'].reduce((func, prefix) => {
  var prefixedFuncName = `${prefix}MatchesSelector`;
  if (elementProto.hasOwnProperty(prefixedFuncName)) {
    return elementProto[prefixedFuncName];
  }

  return func;
}, elementProto.matches);

// find node in terms of selector
function passedThrough(evt, selector) {
  var currentNode = evt.target;
  var stopAt = evt.currentTarget;

  while (true) {
    if (matchesFn.call(currentNode, selector)) {
      return currentNode;
    } else if (currentNode !== stopAt && currentNode !== document.body) {
      currentNode = currentNode.parentNode;
    } else {
      return false;
    }
  }
}

function isRightButton(e) {
  var e = e || window.event;
  if (e.which == null) {
    return e.button >= 2 && e.button !== 4; // 4 is the middle button
  }

  return e.which > 2;
}

// sendMessage callback
var callback = function(url) {
  return function(resp) {
    if (resp) {
      console.log('Opened URL: ', url, ' in a new incognito window.');
    } else {
      console.error('Failed to open the URL: ', url);
    }
  }
}

document.addEventListener('click', (evt) => {
  if (!isRightButton(evt)) {
    var found = passedThrough(evt, 'a[target="linkognito"]');

    if (found) {
      evt.preventDefault();
      let url = found.getAttribute('href')
      if (!url.startsWith('http')) {
        if (url.startsWith('/')){
          url = `${window.location.origin}${url}`
        } else {
          url = `${window.location.href}/${url}`
        }
      }

      browser.runtime.sendMessage({ url: url }, callback(url));
    }
  }
});<commit_msg>Select link by classname instead of target<commit_after>var browser = chrome || browser;

// define matches methode according to browser
var elementProto = Element.prototype;
var matchesFn = ['webkit', 'ms', 'moz', 'o'].reduce((func, prefix) => {
  var prefixedFuncName = `${prefix}MatchesSelector`;
  if (elementProto.hasOwnProperty(prefixedFuncName)) {
    return elementProto[prefixedFuncName];
  }

  return func;
}, elementProto.matches);

// find node in terms of selector
function passedThrough(evt, selector) {
  var currentNode = evt.target;
  var stopAt = evt.currentTarget;

  while (true) {
    if (matchesFn.call(currentNode, selector)) {
      return currentNode;
    } else if (currentNode !== stopAt && currentNode !== document.body) {
      currentNode = currentNode.parentNode;
    } else {
      return false;
    }
  }
}

function isRightButton(e) {
  var e = e || window.event;
  if (e.which == null) {
    return e.button >= 2 && e.button !== 4; // 4 is the middle button
  }

  return e.which > 2;
}

// sendMessage callback
var callback = function(url) {
  return function(resp) {
    if (resp) {
      console.log('Opened URL: ', url, ' in a new incognito window.');
    } else {
      console.error('Failed to open the URL: ', url);
    }
  }
}

document.addEventListener('click', (evt) => {
  if (!isRightButton(evt)) {
    var found = passedThrough(evt, 'a.linkognito');

    if (found) {
      evt.preventDefault();
      let url = found.getAttribute('href')
      if (!url.startsWith('http')) {
        if (url.startsWith('/')){
          url = `${window.location.origin}${url}`
        } else {
          url = `${window.location.href}/${url}`
        }
      }

      browser.runtime.sendMessage({ url: url }, callback(url));
    }
  }
});<|endoftext|>


<commit_before>(function() {
    let currentService, currentPlatform;

    const serviceLinks = $$('.service-select a');
    const platformLinks = $$('.platform-select a');

    let initialSetup = function (links, type) {
      for (let i = links.length - 1; i >= 0; i--) {
        links[i].addEventListener('click', function (e) {
          e.preventDefault();
          if(type === 'service') currentService = e.currentTarget.getAttribute(`data-${type}`);
          if(type === 'platform') currentPlatform = e.currentTarget.getAttribute(`data-${type}`);
          nextStep();
        });
      }
    }

    initialSetup(serviceLinks, 'service');
    initialSetup(platformLinks, 'platform');

    let getDocs = function(servicePath, platformPath) {
      return new Promise(function(resolve, reject) {
        let serviceDoc, platformDoc;
        let gotADoc = function () {
          if(serviceDoc != undefined && platformDoc != undefined) resolve({service: serviceDoc, platform: platformDoc});
        }

        fetch(`/docs/${servicePath}`)
          .then(response => response.text())
          .then(body => {
            serviceDoc = body;
            gotADoc()
          })

        fetch(`/docs/${platformPath}`)
          .then(response => response.text())
          .then(body => {
            platformDoc = body;
            gotADoc()
          })
      })
    }

    let nextStep = function () {
      if(currentService != undefined && currentPlatform === undefined) {
        // show platform
        $('.service-select').setAttribute('style', 'display: none;')
        $('.platform-select').removeAttribute('style')
        $('.install').setAttribute('style', 'display: none;')
      } else if(currentService != undefined && currentPlatform != undefined) {
        // show docs
        $('.service-select').setAttribute('style', 'display: none;')
        $('.platform-select').setAttribute('style', 'display: none;')
        $('.install').removeAttribute('style')

        getDocs(`service/${currentService}`, `platform/${currentPlatform}`)
          .then(docs => {
            $('.install').innerHTML = `${docs.service}\n${docs.platform}`
          })

      }
    }

})();<commit_msg>Add steps<commit_after>(function() {
    let currentService, currentPlatform;

    const serviceLinks = $$('.service-select a');
    const platformLinks = $$('.platform-select a');

    let initialSetup = function (links, type) {
      for (let i = links.length - 1; i >= 0; i--) {
        links[i].addEventListener('click', function (e) {
          e.preventDefault();
          if(type === 'service') currentService = e.currentTarget.getAttribute(`data-${type}`);
          if(type === 'platform') currentPlatform = e.currentTarget.getAttribute(`data-${type}`);
          nextStep();
        });
      }
    }

    initialSetup(serviceLinks, 'service');
    initialSetup(platformLinks, 'platform');

    let getDocs = function(servicePath, platformPath) {
      return new Promise(function(resolve, reject) {
        let serviceDoc, platformDoc;
        let gotADoc = function () {
          if(serviceDoc != undefined && platformDoc != undefined) resolve({service: serviceDoc, platform: platformDoc});
        }

        fetch(`/docs/${servicePath}`)
          .then(response => response.text())
          .then(body => {
            serviceDoc = body;
            gotADoc()
          })

        fetch(`/docs/${platformPath}`)
          .then(response => response.text())
          .then(body => {
            platformDoc = body;
            gotADoc()
          })
      })
    }

    let nextStep = function () {
      if(currentService != undefined && currentPlatform === undefined) {
        // show platform
        $('.service-select').setAttribute('style', 'display: none;')
        $('.platform-select').removeAttribute('style')
        $('.install').setAttribute('style', 'display: none;')

        $('.step1').addClassName('step-inactive')
        $('.step2').removeClassName('step-inactive')
      } else if(currentService != undefined && currentPlatform != undefined) {
        // show docs
        $('.service-select').setAttribute('style', 'display: none;')
        $('.platform-select').setAttribute('style', 'display: none;')
        $('.install').removeAttribute('style')

        $('.step2').addClassName('step-inactive')
        $('.step3').removeClassName('step-inactive')

        getDocs(`service/${currentService}`, `platform/${currentPlatform}`)
          .then(docs => {
            $('.install').innerHTML = `${docs.service}\n${docs.platform}`
          })

      }
    }

})();

Element.prototype.hasClassName = function(name) {
  return new RegExp("(?:^|\\s+)" + name + "(?:\\s+|$)").test(this.className);
};

Element.prototype.addClassName = function(name) {
  if (!this.hasClassName(name)) {
    this.className = this.className ? [this.className, name].join(' ') : name;
  }
};

Element.prototype.removeClassName = function(name) {
  if (this.hasClassName(name)) {
    var c = this.className;
    this.className = c.replace(new RegExp("(?:^|\\s+)" + name + "(?:\\s+|$)", "g"), "");
  }
};<|endoftext|>


<commit_before>/* eslint no-console:0 */
'use strict';

/**
 * Requirements
 * @ignore
 */
const Base = require('../Base.js').Base;
const columnify = require('columnify');
const chalk = require('chalk');
const strip = require('strip-ansi');
const shorten = require('../utils/string.js').shortenLeft;
const isPlainObject = require('lodash.isplainobject');
const util = require('util');
require('date-format-lite');

/**
 * Levels:
 *     0 - all
 *     1 - no debug
 *     2 - no info, no options
 *
 * @memberOf cli
 * @extends Base
 */
class CliLogger extends Base
{
    /**
     * @param {Context} context
     */
    constructor(prefix, options)
    {
        super();

        const opts = options || {};
        this._prefix = prefix || '';
        this._state = new Map();
        this._showTimestamp = opts.showTimestamp || true;
        this._showPrefix = opts.showPrefix || true;
        this._prefixLength = opts.prefixLength || 20;
        this._lineLength = process.stdout.columns || 80;
        this._muted = opts.muted || false;
        this._level = opts.level || 0;
        this._id = 0;
    }

    /**
     * @inheritDoc
     */
    static get injections()
    {
        /* istanbul ignore next */
        return { 'parameters': ['cli/CliLogger.prefix', 'cli/CliLogger.options'] };
    }

    /**
     * @inheritDocs
     */
    static get className()
    {
        return 'cli/CliLogger';
    }

    /**
     * @property {bool}
     */
    get muted()
    {
        return this._muted;
    }

    /**
     */
    set muted(value)
    {
        this._muted = value || false;
    }

    /**
     * @param {*} ...
     * @returns {void}
     */
    write()
    {
        if (this._muted)
        {
            return;
        }

        // Message
        const message = Array.from(arguments).join(' ');
        let prepend = '';

        // Timestamp
        if (this._showTimestamp)
        {
            const now = new Date();
            prepend+= chalk.bgBlack(chalk.gray('[' + now.format('hh:mm:ss') + '] '));
        }

        // Prefix
        if (this._showPrefix && this._prefix)
        {
            const prefix = shorten(this._prefix, this._prefixLength);
            prepend+= chalk.gray(prefix + ' '.repeat(Math.max(0, this._prefixLength - prefix.length)) + ' ');
        }

        // Output
        console.log(chalk.bgBlack(prepend) + ' ' + message);
    }

    /**
     * @protected
     * @param {string} message
     * @returns {string}
     */
    formatMessage(message)
    {
        message = message.replace(/<([^>]+)>/g, chalk.styles.cyan.open + '$1' + chalk.styles.cyan.close);
        return message;
    }

    /**
     * @protected
     * @param {string} message
     * @returns {string}
     */
    formatElapsed(date)
    {
        const elapsed = Date.now() - date;
        return chalk.yellow(' (' + elapsed + 'ms)');
    }

    /**
     * @protected
     * @param {string} message
     * @returns {string}
     */
    formatSection(message, isDone, hasError)
    {
        const dashes = '-'.repeat(Math.max(0, 80 - strip(message).replace(/\<|\>/g, '').length));
        let prefix = '○ ';
        if (isDone)
        {
            prefix = hasError ? '✕ ' : '✓ ';
        }
        return chalk.yellow(prefix + this.formatMessage(message)) + ' ' + chalk.dim(dashes);
    }

    /**
     * @protected
     * @param {string} message
     * @returns {string}
     */
    formatWork(message, hasError)
    {
        const prefix = hasError ? '✕ ' : '✓ ';
        let text = '  ' + prefix + this.formatMessage(message);
        if (hasError)
        {
            text = chalk.red(text);
        }
        else
        {
            text = chalk.green(text);
        }
        return text;
    }

    /**
     * @param {string} name
     * @returns {string}
     */
    section()
    {
        const message = Array.from(arguments).join(' ');
        const state =
        {
            id: this._id++,
            type: 'section',
            message: message,
            started: Date.now()
        };
        this._state.set(state.id, state);
        this.write(this.formatSection(message));
        return state.id;
    }

    /**
     * @param {string} name
     * @returns {string}
     */
    work()
    {
        const message = Array.from(arguments).join(' ');
        const state =
        {
            id: this._id++,
            type: 'work',
            message: message,
            started: Date.now()
        };
        this._state.set(state.id, state);
        return state.id;
    }

    /**
     * @param {string} name
     * @returns {string}
     */
    end(id, error, overrideMessage)
    {
        if (!this._state.has(id))
        {
            return;
        }
        const state = this._state.get(id);
        this._state.delete(id);

        let message = '';
        if (state.type === 'section')
        {
            message = this.formatSection(overrideMessage || state.message, true, Boolean(error));
        }
        if (state.type === 'work')
        {
            message = this.formatWork(overrideMessage || state.message, Boolean(error));
        }

        if (error)
        {
            this.write(chalk.red(message));
            if (typeof error === 'string')
            {
                this.write('    ' + chalk.red(error));
            }
        }
        else
        {
            this.write(message + this.formatElapsed(state.started));
        }
    }

    /**
     * @param {string} name
     * @returns {string}
     */
    options(values)
    {
        if (this._level > 2)
        {
            return;
        }
        this.write('  Options');
        for (const key in values)
        {
            if (isPlainObject(values[key]))
            {
                const lines = util.inspect(values[key]).split('\n');
                this.write('    ' + key + ': ' + chalk.cyan(lines.shift()));
                while(lines.length)
                {
                    this.write('        ' + chalk.cyan(lines.shift()));
                }
            }
            else
            {
                this.write('    ' + key + ': ' + chalk.cyan(values[key]));
            }
        }
    }

    /**
     * @param {string} name
     * @returns {string}
     */
    debug()
    {
        if (this._level > 3)
        {
            return;
        }
        const message = Array.from(arguments).join(' ');
        this.write(chalk.dim('  ' + this.formatMessage(message)));
    }

    /**
     * @param {string} name
     * @returns {string}
     */
    info()
    {
        if (this._level > 2)
        {
            return;
        }
        const message = Array.from(arguments).join(' ');
        this.write(chalk.white('  ' + this.formatMessage(message)));
    }

    /**
     * @param {array} data
     * @returns {void}
     */
    error()
    {
        const args = Array.from(arguments);
        let messages = [];
        if (args[0] instanceof Error)
        {
            messages = messages.concat(args[0].stack.split('\n'));
        }
        else
        {
            messages = messages.concat(args.join(' ').split('\n'));
        }
        for (const message of messages)
        {
            this.write(chalk.red('  ' + this.formatMessage(message)));
        }
    }

    /**
     * @param {array} data
     * @returns {void}
     */
    table(data, options)
    {
        const opts = options || {};
        opts.preserveNewLines = true;
        opts.showHeaders = false;
        opts.columnSplitter = '  ';
        const table = columnify(data, opts);
        const lines = table.split('\n');
        for (const line of lines)
        {
            this.write(this.formatMessage(line));
        }
    }

    /**
     * @param {array} data
     * @returns {void}
     */
    createPrefixed(prefix)
    {
        const options =
        {
            showTimestamp: this._showTimestamp,
            showPrefix: this._showPrefix,
            prefixLength: this._prefixLength,
            muted: this._muted,
            level: this._level
        };
        return new CliLogger(prefix, options);
    }
}

/**
 * Exports
 * @ignore
 */
module.exports.CliLogger = CliLogger;
<commit_msg>style(cli.CliLogger): removes unneccesary regex escapes<commit_after>/* eslint no-console:0 */
'use strict';

/**
 * Requirements
 * @ignore
 */
const Base = require('../Base.js').Base;
const columnify = require('columnify');
const chalk = require('chalk');
const strip = require('strip-ansi');
const shorten = require('../utils/string.js').shortenLeft;
const isPlainObject = require('lodash.isplainobject');
const util = require('util');
require('date-format-lite');

/**
 * Levels:
 *     0 - all
 *     1 - no debug
 *     2 - no info, no options
 *
 * @memberOf cli
 * @extends Base
 */
class CliLogger extends Base
{
    /**
     * @param {Context} context
     */
    constructor(prefix, options)
    {
        super();

        const opts = options || {};
        this._prefix = prefix || '';
        this._state = new Map();
        this._showTimestamp = opts.showTimestamp || true;
        this._showPrefix = opts.showPrefix || true;
        this._prefixLength = opts.prefixLength || 20;
        this._lineLength = process.stdout.columns || 80;
        this._muted = opts.muted || false;
        this._level = opts.level || 0;
        this._id = 0;
    }

    /**
     * @inheritDoc
     */
    static get injections()
    {
        /* istanbul ignore next */
        return { 'parameters': ['cli/CliLogger.prefix', 'cli/CliLogger.options'] };
    }

    /**
     * @inheritDocs
     */
    static get className()
    {
        return 'cli/CliLogger';
    }

    /**
     * @property {bool}
     */
    get muted()
    {
        return this._muted;
    }

    /**
     */
    set muted(value)
    {
        this._muted = value || false;
    }

    /**
     * @param {*} ...
     * @returns {void}
     */
    write()
    {
        if (this._muted)
        {
            return;
        }

        // Message
        const message = Array.from(arguments).join(' ');
        let prepend = '';

        // Timestamp
        if (this._showTimestamp)
        {
            const now = new Date();
            prepend+= chalk.bgBlack(chalk.gray('[' + now.format('hh:mm:ss') + '] '));
        }

        // Prefix
        if (this._showPrefix && this._prefix)
        {
            const prefix = shorten(this._prefix, this._prefixLength);
            prepend+= chalk.gray(prefix + ' '.repeat(Math.max(0, this._prefixLength - prefix.length)) + ' ');
        }

        // Output
        console.log(chalk.bgBlack(prepend) + ' ' + message);
    }

    /**
     * @protected
     * @param {string} message
     * @returns {string}
     */
    formatMessage(message)
    {
        message = message.replace(/<([^>]+)>/g, chalk.styles.cyan.open + '$1' + chalk.styles.cyan.close);
        return message;
    }

    /**
     * @protected
     * @param {string} message
     * @returns {string}
     */
    formatElapsed(date)
    {
        const elapsed = Date.now() - date;
        return chalk.yellow(' (' + elapsed + 'ms)');
    }

    /**
     * @protected
     * @param {string} message
     * @returns {string}
     */
    formatSection(message, isDone, hasError)
    {
        const dashes = '-'.repeat(Math.max(0, 80 - strip(message).replace(/<|>/g, '').length));
        let prefix = '○ ';
        if (isDone)
        {
            prefix = hasError ? '✕ ' : '✓ ';
        }
        return chalk.yellow(prefix + this.formatMessage(message)) + ' ' + chalk.dim(dashes);
    }

    /**
     * @protected
     * @param {string} message
     * @returns {string}
     */
    formatWork(message, hasError)
    {
        const prefix = hasError ? '✕ ' : '✓ ';
        let text = '  ' + prefix + this.formatMessage(message);
        if (hasError)
        {
            text = chalk.red(text);
        }
        else
        {
            text = chalk.green(text);
        }
        return text;
    }

    /**
     * @param {string} name
     * @returns {string}
     */
    section()
    {
        const message = Array.from(arguments).join(' ');
        const state =
        {
            id: this._id++,
            type: 'section',
            message: message,
            started: Date.now()
        };
        this._state.set(state.id, state);
        this.write(this.formatSection(message));
        return state.id;
    }

    /**
     * @param {string} name
     * @returns {string}
     */
    work()
    {
        const message = Array.from(arguments).join(' ');
        const state =
        {
            id: this._id++,
            type: 'work',
            message: message,
            started: Date.now()
        };
        this._state.set(state.id, state);
        return state.id;
    }

    /**
     * @param {string} name
     * @returns {string}
     */
    end(id, error, overrideMessage)
    {
        if (!this._state.has(id))
        {
            return;
        }
        const state = this._state.get(id);
        this._state.delete(id);

        let message = '';
        if (state.type === 'section')
        {
            message = this.formatSection(overrideMessage || state.message, true, Boolean(error));
        }
        if (state.type === 'work')
        {
            message = this.formatWork(overrideMessage || state.message, Boolean(error));
        }

        if (error)
        {
            this.write(chalk.red(message));
            if (typeof error === 'string')
            {
                this.write('    ' + chalk.red(error));
            }
        }
        else
        {
            this.write(message + this.formatElapsed(state.started));
        }
    }

    /**
     * @param {string} name
     * @returns {string}
     */
    options(values)
    {
        if (this._level > 2)
        {
            return;
        }
        this.write('  Options');
        for (const key in values)
        {
            if (isPlainObject(values[key]))
            {
                const lines = util.inspect(values[key]).split('\n');
                this.write('    ' + key + ': ' + chalk.cyan(lines.shift()));
                while(lines.length)
                {
                    this.write('        ' + chalk.cyan(lines.shift()));
                }
            }
            else
            {
                this.write('    ' + key + ': ' + chalk.cyan(values[key]));
            }
        }
    }

    /**
     * @param {string} name
     * @returns {string}
     */
    debug()
    {
        if (this._level > 3)
        {
            return;
        }
        const message = Array.from(arguments).join(' ');
        this.write(chalk.dim('  ' + this.formatMessage(message)));
    }

    /**
     * @param {string} name
     * @returns {string}
     */
    info()
    {
        if (this._level > 2)
        {
            return;
        }
        const message = Array.from(arguments).join(' ');
        this.write(chalk.white('  ' + this.formatMessage(message)));
    }

    /**
     * @param {array} data
     * @returns {void}
     */
    error()
    {
        const args = Array.from(arguments);
        let messages = [];
        if (args[0] instanceof Error)
        {
            messages = messages.concat(args[0].stack.split('\n'));
        }
        else
        {
            messages = messages.concat(args.join(' ').split('\n'));
        }
        for (const message of messages)
        {
            this.write(chalk.red('  ' + this.formatMessage(message)));
        }
    }

    /**
     * @param {array} data
     * @returns {void}
     */
    table(data, options)
    {
        const opts = options || {};
        opts.preserveNewLines = true;
        opts.showHeaders = false;
        opts.columnSplitter = '  ';
        const table = columnify(data, opts);
        const lines = table.split('\n');
        for (const line of lines)
        {
            this.write(this.formatMessage(line));
        }
    }

    /**
     * @param {array} data
     * @returns {void}
     */
    createPrefixed(prefix)
    {
        const options =
        {
            showTimestamp: this._showTimestamp,
            showPrefix: this._showPrefix,
            prefixLength: this._prefixLength,
            muted: this._muted,
            level: this._level
        };
        return new CliLogger(prefix, options);
    }
}

/**
 * Exports
 * @ignore
 */
module.exports.CliLogger = CliLogger;
<|endoftext|>