<commit_before>var env = process.env.NODE_ENV || 'test';

var expect = require('chai').expect;
var deleteStream = require('level-delete-stream');
var Map = require('es6-map');

var mikey = {
  name: "Mikey",
};

describe("#Graph", function () {
  var leveldb, db;
  var Graph;
  var People, Resources;

  before(function () {
    var level = require('level-test')();
    leveldb = level(env+'.db');
    db = require('levelgraph-jsonld')(
      require('levelgraph')(leveldb)
    , {
      base: "http://open.app/",
    });

    Graph = require('../');

    var types = require('oa-types')();
    var PersonType = types.use({
      id: "Person",
      type: 'object',
      prefixes: {
        "vocab": "http://open.vocab/",
      },
      context: "vocab:Person",
      properties: {
        name: {
          context: "vocab:name",
          type: "string",
        },
        bio: {
          context: "vocab:bio",
          type: "string",
        },
        resources: {
          context: "vocab:hasResource",
          reverse: "owner",
          $ref: "Resource",
        },
      },
    });
    var ResourceType = types.use({
      id: "Resource",
      type: 'object',
      prefixes: {
        "vocab": "http://open.vocab/",
      },
      context: "vocab:Resource",
      properties: {
        name: {
          context: "vocab:name",
          type: "string",
        },
        owner: {
          context: "vocab:isOwner",
          $ref: "Person",
        },
      },
    });
    var graphs = new Map();
    People = new Graph({
      id: "People",
      db: db,
      type: PersonType,
      graphs: graphs,
    });
    Resources = new Graph({
      id: "Resources",
      db: db,
      type: ResourceType,
      graphs: graphs,
    });
  });

  beforeEach(function (done) {
    return leveldb.createKeyStream()
    .pipe(deleteStream(leveldb, done))
  });

  describe("Graph.isGraph()", function () {

    it("of simple graph should be true", function () {
      var graph = new Graph({
        id: "Things",
        db: db,
        type: {
          id: "Thing",
          type: 'object',
          properties: {
            description: {
              type: 'string',
            },
          },
        },
      });
      expect(Graph.isGraph(graph)).to.be.true;
    });
  });

  describe("get", function () {
    var fixture = {
      name: "Mikey",
      bio: "a human from planet earth."
    };
    var id;

    beforeEach(function () {
      return People.create(fixture)
      .then(function (result) {
        id = result['@id'];
      })
      ;
    });

    it("should get with no params", function () {
      return People.get(id)
      .then(function (result) {
        expect(Object.keys(result)).to.have.length(6);
        expect(result).to.have.property('@context');
        expect(result).to.have.property('@id');
        expect(result).to.have.property('@type', "Person");
        expect(result).to.have.property('name', fixture.name);
        expect(result).to.have.property('bio', fixture.bio);
        expect(result.resources).to.deep.equal([]);
      })
      ;
    });

    it("should get with exclude params", function () {
      return People.get(id, {
        exclude: "bio",
      })
      .then(function (result) {
        console.log(result);
        expect(Object.keys(result)).to.have.length(5);
        expect(result).to.have.property('@context');
        expect(result).to.have.property('@id');
        expect(result).to.have.property('@type', "Person");
        expect(result).to.have.property('name', fixture.name);
        expect(result.resources).to.deep.equal([]);
      })
      ;
    });
  });

  describe("find", function () {
    it("should find based on simple query", function () {
      return People.create({
        name: "Mikey",
      })
      .then(function (person) {
        return People.find({
          query: {
            name: "Mikey",
          },
        });
      })
      .then(function (results) {
        expect(Array.isArray(results)).to.be.true;
        expect(results).to.have.length(1);
        expect(results[0]).to.have.property('@type', "Person");
        expect(results[0]).to.have.property('name', "Mikey");
      })
      ;
    });

    it("should implicitly add type to simple query", function () {
      return Resources.create({
        name: "Mikey",
      })
      .then(function () {
        return People.create({
          name: "Mikey",
        })
      })
      .then(function (person) {
        return People.find({
          query: {
            name: "Mikey",
          },
        });
      })
      .then(function (results) {
        expect(Array.isArray(results)).to.be.true;
        expect(results).to.have.length(1);
        expect(results[0]).to.have.property('@type', "Person");
        expect(results[0]).to.have.property('name', "Mikey");
      })
      ;
    });
  });

  describe("relations", function () {

    it("should have hasMany <> belongsTo relation", function () {

      var id;

      // create person
      return People.create({
        name: "Mikey",
      })
      .then(function (person) {
        // save person id
        id = person['@id'];
        // create resource with person as owner
        return Resources.create({
          name: "RepRap Prusa Mendel",
          owner: id,
        });
      })
      .then(function (resource) {
        // get person again
        return People.get(id);
      })
      .then(function (person) {
        expect(person).to.have.property('resources');
        expect(Array.isArray(person.resources)).to.be.true;
        expect(person.resources).to.have.length(1);
        expect(Object.keys(person.resources[0])).to.have.length(5);
        expect(person.resources[0]).to.have.property('@context');
        expect(person.resources[0]).to.have.property('@type', "Resource");
        expect(person.resources[0]).to.have.property('@id');
        expect(person.resources[0]).to.have.property('name', "RepRap Prusa Mendel");
        expect(person.resources[0].owner).to.deep.equal({ '@id': id });
      });
    });
  });
});
<commit_msg>remove unused code<commit_after>var env = process.env.NODE_ENV || 'test';

var expect = require('chai').expect;
var deleteStream = require('level-delete-stream');
var Map = require('es6-map');

describe("#Graph", function () {
  var leveldb, db;
  var Graph;
  var People, Resources;

  before(function () {
    var level = require('level-test')();
    leveldb = level(env+'.db');
    db = require('levelgraph-jsonld')(
      require('levelgraph')(leveldb)
    , {
      base: "http://open.app/",
    });

    Graph = require('../');

    var types = require('oa-types')();
    var PersonType = types.use({
      id: "Person",
      type: 'object',
      prefixes: {
        "vocab": "http://open.vocab/",
      },
      context: "vocab:Person",
      properties: {
        name: {
          context: "vocab:name",
          type: "string",
        },
        bio: {
          context: "vocab:bio",
          type: "string",
        },
        resources: {
          context: "vocab:hasResource",
          reverse: "owner",
          $ref: "Resource",
        },
      },
    });
    var ResourceType = types.use({
      id: "Resource",
      type: 'object',
      prefixes: {
        "vocab": "http://open.vocab/",
      },
      context: "vocab:Resource",
      properties: {
        name: {
          context: "vocab:name",
          type: "string",
        },
        owner: {
          context: "vocab:isOwner",
          $ref: "Person",
        },
      },
    });
    var graphs = new Map();
    People = new Graph({
      id: "People",
      db: db,
      type: PersonType,
      graphs: graphs,
    });
    Resources = new Graph({
      id: "Resources",
      db: db,
      type: ResourceType,
      graphs: graphs,
    });
  });

  beforeEach(function (done) {
    return leveldb.createKeyStream()
    .pipe(deleteStream(leveldb, done))
  });

  describe("Graph.isGraph()", function () {

    it("of simple graph should be true", function () {
      var graph = new Graph({
        id: "Things",
        db: db,
        type: {
          id: "Thing",
          type: 'object',
          properties: {
            description: {
              type: 'string',
            },
          },
        },
      });
      expect(Graph.isGraph(graph)).to.be.true;
    });
  });

  describe("get", function () {
    var fixture = {
      name: "Mikey",
      bio: "a human from planet earth."
    };
    var id;

    beforeEach(function () {
      return People.create(fixture)
      .then(function (result) {
        id = result['@id'];
      })
      ;
    });

    it("should get with no params", function () {
      return People.get(id)
      .then(function (result) {
        expect(Object.keys(result)).to.have.length(6);
        expect(result).to.have.property('@context');
        expect(result).to.have.property('@id');
        expect(result).to.have.property('@type', "Person");
        expect(result).to.have.property('name', fixture.name);
        expect(result).to.have.property('bio', fixture.bio);
        expect(result.resources).to.deep.equal([]);
      })
      ;
    });

    it("should get with exclude params", function () {
      return People.get(id, {
        exclude: "bio",
      })
      .then(function (result) {
        console.log(result);
        expect(Object.keys(result)).to.have.length(5);
        expect(result).to.have.property('@context');
        expect(result).to.have.property('@id');
        expect(result).to.have.property('@type', "Person");
        expect(result).to.have.property('name', fixture.name);
        expect(result.resources).to.deep.equal([]);
      })
      ;
    });
  });

  describe("find", function () {
    it("should find based on simple query", function () {
      return People.create({
        name: "Mikey",
      })
      .then(function (person) {
        return People.find({
          query: {
            name: "Mikey",
          },
        });
      })
      .then(function (results) {
        expect(Array.isArray(results)).to.be.true;
        expect(results).to.have.length(1);
        expect(results[0]).to.have.property('@type', "Person");
        expect(results[0]).to.have.property('name', "Mikey");
      })
      ;
    });

    it("should implicitly add type to simple query", function () {
      return Resources.create({
        name: "Mikey",
      })
      .then(function () {
        return People.create({
          name: "Mikey",
        })
      })
      .then(function (person) {
        return People.find({
          query: {
            name: "Mikey",
          },
        });
      })
      .then(function (results) {
        expect(Array.isArray(results)).to.be.true;
        expect(results).to.have.length(1);
        expect(results[0]).to.have.property('@type', "Person");
        expect(results[0]).to.have.property('name', "Mikey");
      })
      ;
    });
  });

  describe("relations", function () {

    it("should have hasMany <> belongsTo relation", function () {

      var id;

      // create person
      return People.create({
        name: "Mikey",
      })
      .then(function (person) {
        // save person id
        id = person['@id'];
        // create resource with person as owner
        return Resources.create({
          name: "RepRap Prusa Mendel",
          owner: id,
        });
      })
      .then(function (resource) {
        // get person again
        return People.get(id);
      })
      .then(function (person) {
        expect(person).to.have.property('resources');
        expect(Array.isArray(person.resources)).to.be.true;
        expect(person.resources).to.have.length(1);
        expect(Object.keys(person.resources[0])).to.have.length(5);
        expect(person.resources[0]).to.have.property('@context');
        expect(person.resources[0]).to.have.property('@type', "Resource");
        expect(person.resources[0]).to.have.property('@id');
        expect(person.resources[0]).to.have.property('name', "RepRap Prusa Mendel");
        expect(person.resources[0].owner).to.deep.equal({ '@id': id });
      });
    });
  });
});
<|endoftext|>


<commit_before>let assert = require( 'assert' );
let collections = require( '../index' );
let chai = require( 'chai' );
let dirtyChai = require( 'dirty-chai' );
let Metalsmith = require( 'metalsmith' );
let path = require( 'path' );
let rimraf = require( 'rimraf' );

let metalsmithReplacer = require( '../lib/utilities/metalsmithReplacer' );
let saveMetadata = require( '../lib/utilities/saveMetadata' );

chai.use( dirtyChai );
let expect = chai.expect;

describe( 'metalsmith-nested-collections', function() {

    context( 'is a drop-in replacement for `metalsmith-collections`, so this plugin', function() {
        const fixturePath = 'test/collection-fixtures';

        before( function( done ) {
            rimraf( fixturePath + '/*/build', done );
        } );

        it( 'should add collections to metadata', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/basic' );
            metalsmith
                .use( collections( { articles: {} } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 2, m.articles.length );
                    assert.equal( m.collections.articles, m.articles );
                    done();
                } );
        } );

        it( 'should match collections by pattern', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/pattern' );
            metalsmith
                .use( collections( {
                    articles: {
                        pattern: '*.md'
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    assert.equal( 4, metalsmith.metadata().articles.length );
                    done();
                } );
        } );

        it( 'should take a pattern shorthand string', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/pattern' );
            metalsmith
                .use( collections( {
                    articles: '*.md'
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    assert.equal( 4, metalsmith.metadata().articles.length );
                    done();
                } );
        } );

        it( 'should take an array of patterns', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/pattern' );
            metalsmith
                .use( collections( {
                    blogs: [ '*.md', '!one.md', '!two.md', '!four.md' ],
                    pages: { pattern: [ 'four.md' ] }
                } ) )
                .build( function( err, files ) {
                    if ( err ) return done( err );
                    assert.equal( 1, metalsmith.metadata().blogs.length, 'length blogs' );
                    assert.equal( 1, metalsmith.metadata().pages.length, 'length page' );
                    assert.equal( files[ 'three.md' ].collection, 'blogs', 'collection blogs' );
                    assert.equal( files[ 'four.md' ].collection, 'pages', 'collection page' );
                    done();
                } );
        } );

        it( 'should add the collection property to a file', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/pattern' );
            metalsmith
                .use( collections( {
                    articles: '*.md'
                } ) )
                .build( function( err, files ) {
                    if ( err ) return done( err );
                    assert.equal( files[ 'three.md' ].collection, 'articles' );
                    done();
                } );
        } );

        it( 'should accept a "sortBy" option', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/sort' );
            metalsmith
                .use( collections( { articles: { sortBy: 'title' } } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert.equal( 'Alpha', articles[ 0 ].title );
                    assert.equal( 'Beta', articles[ 1 ].title );
                    assert.equal( 'Gamma', articles[ 2 ].title );
                    done();
                } );
        } );

        it( 'should accept a "sortBy" function', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/sort' );
            metalsmith
                .use( collections( { articles: { sortBy: sort } } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert.equal( 'Gamma', articles[ 0 ].title );
                    assert.equal( 'Beta', articles[ 1 ].title );
                    assert.equal( 'Alpha', articles[ 2 ].title );
                    done();
                } );

            function sort( a, b ) {
                a = a.title.slice( 1 );
                b = b.title.slice( 1 );
                return a > b ? 1 : -1;
            }
        } );

        it( 'should accept a "reverse" option', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/sort' );
            metalsmith
                .use( collections( {
                    articles: {
                        sortBy: 'title',
                        reverse: true
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert.equal( 'Alpha', articles[ 2 ].title );
                    assert.equal( 'Beta', articles[ 1 ].title );
                    assert.equal( 'Gamma', articles[ 0 ].title );
                    done();
                } );
        } );

        it( 'should accept a "limit" option', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/limit' ),
                limit = 2;
            metalsmith
                .use( collections( {
                    articles: {
                        limit: limit,
                        sortBy: 'title'
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert.equal( limit, articles.length );
                    assert.equal( 'Alpha', articles[ 0 ].title );
                    assert.equal( 'Beta', articles[ 1 ].title );
                    done();
                } );
        } );

        it( 'should accept a "limit" higher than the collection length', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/limit' );
            metalsmith
                .use( collections( {
                    articles: {
                        sortBy: 'title',
                        limit: 25
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert.equal( 3, articles.length );
                    assert.equal( 'Alpha', articles[ 0 ].title );
                    assert.equal( 'Beta', articles[ 1 ].title );
                    assert.equal( 'Gamma', articles[ 2 ].title );
                    done();
                } );
        } );

        it( 'should add next and previous references', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/references' );
            metalsmith
                .use( collections( { articles: {} } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert( !articles[ 0 ].previous );
                    assert.equal( articles[ 0 ].next, articles[ 1 ] );
                    assert.equal( articles[ 1 ].previous, articles[ 0 ] );
                    assert.equal( articles[ 1 ].next, articles[ 2 ] );
                    debugger;
                    assert.equal( articles[ 2 ].previous, articles[ 1 ] );
                    assert( !articles[ 2 ].next );
                    done();
                } );
        } );

        it( 'should not add references if opts[key].refer === false', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/references-off' );
            metalsmith
                .use( collections( { articles: { refer: false } } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert( !articles[ 0 ].previous );
                    assert( !articles[ 0 ].next );
                    assert( !articles[ 1 ].previous );
                    assert( !articles[ 1 ].next );
                    assert( !articles[ 2 ].previous );
                    assert( !articles[ 2 ].next );
                    done();
                } );
        } );

        it( 'should not fail with empty collections', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/empty' );
            metalsmith
                .use( collections( {
                    articles: {
                        sortBy: 'date',
                        reverse: true
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert.equal( articles.length, 0 );
                    done();
                } );
        } );

        it( 'should add metadata objects to collections', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/basic' );
            metalsmith
                .use( collections( {
                    articles: {
                        metadata: { name: 'Batman' }
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 'Batman', m.articles.metadata.name );
                    done();
                } );
        } );

        it( 'should load collection metadata from a JSON file', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/basic' );
            metalsmith
                .use( collections( {
                    articles: {
                        metadata: fixturePath + '/metadata/metadata.json'
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 'Batman', m.articles.metadata.name );
                    done();
                } );
        } );

        it( 'should load collection metadata from a YAML file', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/basic' );
            metalsmith
                .use( collections( {
                    articles: {
                        metadata: fixturePath + '/metadata/metadata.yaml'
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 'Batman', m.articles.metadata.name );
                    done();
                } );
        } );

        it( 'should allow multiple collections', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/multi' );
            metalsmith
                .use( collections( { articles: {}, posts: {}, drafts: {} } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 2, m.articles.length );
                    assert.equal( 1, m.drafts.length );
                    assert.equal( 1, m.posts.length );
                    assert.equal( m.collections.articles, m.articles );
                    assert.equal( m.collections.drafts, m.drafts );
                    assert.equal( m.collections.posts, m.posts );
                    done();
                } );
        } );

        it( 'should allow collections through metadata alone', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/noconfig' );
            metalsmith
                .use( collections( { movies: {} } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 2, m.books.length );
                    assert.equal( 1, m.movies.length );
                    assert.equal( m.collections.books, m.books );
                    assert.equal( m.collections.movies, m.movies );
                    done();
                } );
        } );

        it( 'should allow collections by pattern and front matter', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/multi' );
            metalsmith
                .use( collections( {
                    articles: {},
                    posts: {},
                    drafts: {},
                    blog: '*.md'
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 3, m.blog.length );
                    assert.equal( 2, m.articles.length );
                    assert.equal( 1, m.drafts.length );
                    assert.equal( 1, m.posts.length );
                    assert.equal( m.collections.blog, m.blog );
                    assert.equal( m.collections.articles, m.articles );
                    assert.equal( m.collections.drafts, m.drafts );
                    assert.equal( m.collections.posts, m.posts );
                    done();
                } );
        } );

        it( 'should add file path', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/sort' );
            metalsmith
                .use( collections( {
                    articles: {
                        sortBy: 'title'
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert( articles[ 0 ].path );
                    assert.equal( articles[ 0 ].path, 'one.md' );
                    done();
                } );
        } );

    } );

    context( 'provides functionality that', function() {
        const fixtureRoot = path.resolve( __dirname, 'nested-fixtures' );
        const collectionsConfig = {
            posts: {
                pattern: 'posts/**/*.md',
                sortBy: 'date',
                reverse: true
            },
            'metalsmith-tutorial': {
                pattern: 'posts/metalsmith-tutorial/*.md',
                sortBy: 'date',
                reverse: true
            },
            'shocking-secret': {
                pattern: 'posts/shocking-secret/*.md',
                sortBy: 'date',
                reverse: true
            }
        };

        before( function( done ) {
            rimraf( fixtureRoot + '/*/build', done );
        } );

        it( 'adds "nextInCollection" and "prevInCollection" to file metadata', function( done ) {
            let fixturePath = path.resolve( fixtureRoot, 'basic' );
            let metalsmith = Metalsmith( fixturePath );
            metalsmith
                .use( collections( collectionsConfig ) )
                .build( function( err, files ) {
                    if ( err ) return done( err );
                    let metadata = metalsmith.metadata();

                    // Save file and collection metadata to JSON files
                    let metadataCollection = {
                        files: files,
                        collections: metadata
                    };
                    saveMetadata( fixturePath, metadataCollection );

                    // Test using the `collections` group in the global metadata
                    let names = Object.keys( metadata.collections );
                    for ( let name of names ) {
                        let collection = metadata[ name ];
                        expect( Array.isArray( collection ) ).to.be.true();
                        collection.forEach( ( file, index, array ) => {
                            if ( index > 0 ) {
                                expect( file ).to.have.ownProperty( 'prevInCollection' );
                            }
                            if ( index < ( array.length - 1 ) ) {
                                expect( file ).to.have.ownProperty( 'nextInCollection' );
                            }
                        } );
                    }

                    done();
                } );
        } );

        it( 'adds links by collection to each file', function( done ) {
            let fixturePath = path.resolve( fixtureRoot, 'basic' );
            let metalsmith = Metalsmith( fixturePath );
            metalsmith
                .use( collections( collectionsConfig ) )
                .build( function( err, files ) {
                    if ( err ) return done( err );
                    let metadata = metalsmith.metadata();

                    // Test using the `collections` group in the global metadata
                    let names = Object.keys( metadata.collections );
                    for ( let name of names ) {
                        let collection = metadata.collections[ name ];
                        expect( Array.isArray( collection ) ).to.be.true();
                        collection.forEach( ( file, index, array ) => {
                            if ( index > 0 ) {
                                let prevLinks = file.prevInCollection;
                                expect( prevLinks ).to.be.ok();
                                expect( prevLinks ).to.have.ownProperty( name );
                            }

                            if ( index < ( array.length - 1) ) {
                                let nextLinks = file.nextInCollection;
                                expect( nextLinks ).to.be.ok();
                                expect( nextLinks ).to.have.ownProperty( name );
                            }
                        } );
                    }

                    done();
                } );
        } );
                    done();
                } );
        } );

    } );

} );
<commit_msg>Add test for correct collection links, with built-in to-do list<commit_after>let assert = require( 'assert' );
let collections = require( '../index' );
let chai = require( 'chai' );
let dirtyChai = require( 'dirty-chai' );
let Metalsmith = require( 'metalsmith' );
let path = require( 'path' );
let rimraf = require( 'rimraf' );

let metalsmithReplacer = require( '../lib/utilities/metalsmithReplacer' );
let saveMetadata = require( '../lib/utilities/saveMetadata' );

chai.use( dirtyChai );
let expect = chai.expect;

describe( 'metalsmith-nested-collections', function() {

    context( 'is a drop-in replacement for `metalsmith-collections`, so this plugin', function() {
        const fixturePath = 'test/collection-fixtures';

        before( function( done ) {
            rimraf( fixturePath + '/*/build', done );
        } );

        it( 'should add collections to metadata', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/basic' );
            metalsmith
                .use( collections( { articles: {} } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 2, m.articles.length );
                    assert.equal( m.collections.articles, m.articles );
                    done();
                } );
        } );

        it( 'should match collections by pattern', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/pattern' );
            metalsmith
                .use( collections( {
                    articles: {
                        pattern: '*.md'
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    assert.equal( 4, metalsmith.metadata().articles.length );
                    done();
                } );
        } );

        it( 'should take a pattern shorthand string', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/pattern' );
            metalsmith
                .use( collections( {
                    articles: '*.md'
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    assert.equal( 4, metalsmith.metadata().articles.length );
                    done();
                } );
        } );

        it( 'should take an array of patterns', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/pattern' );
            metalsmith
                .use( collections( {
                    blogs: [ '*.md', '!one.md', '!two.md', '!four.md' ],
                    pages: { pattern: [ 'four.md' ] }
                } ) )
                .build( function( err, files ) {
                    if ( err ) return done( err );
                    assert.equal( 1, metalsmith.metadata().blogs.length, 'length blogs' );
                    assert.equal( 1, metalsmith.metadata().pages.length, 'length page' );
                    assert.equal( files[ 'three.md' ].collection, 'blogs', 'collection blogs' );
                    assert.equal( files[ 'four.md' ].collection, 'pages', 'collection page' );
                    done();
                } );
        } );

        it( 'should add the collection property to a file', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/pattern' );
            metalsmith
                .use( collections( {
                    articles: '*.md'
                } ) )
                .build( function( err, files ) {
                    if ( err ) return done( err );
                    assert.equal( files[ 'three.md' ].collection, 'articles' );
                    done();
                } );
        } );

        it( 'should accept a "sortBy" option', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/sort' );
            metalsmith
                .use( collections( { articles: { sortBy: 'title' } } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert.equal( 'Alpha', articles[ 0 ].title );
                    assert.equal( 'Beta', articles[ 1 ].title );
                    assert.equal( 'Gamma', articles[ 2 ].title );
                    done();
                } );
        } );

        it( 'should accept a "sortBy" function', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/sort' );
            metalsmith
                .use( collections( { articles: { sortBy: sort } } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert.equal( 'Gamma', articles[ 0 ].title );
                    assert.equal( 'Beta', articles[ 1 ].title );
                    assert.equal( 'Alpha', articles[ 2 ].title );
                    done();
                } );

            function sort( a, b ) {
                a = a.title.slice( 1 );
                b = b.title.slice( 1 );
                return a > b ? 1 : -1;
            }
        } );

        it( 'should accept a "reverse" option', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/sort' );
            metalsmith
                .use( collections( {
                    articles: {
                        sortBy: 'title',
                        reverse: true
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert.equal( 'Alpha', articles[ 2 ].title );
                    assert.equal( 'Beta', articles[ 1 ].title );
                    assert.equal( 'Gamma', articles[ 0 ].title );
                    done();
                } );
        } );

        it( 'should accept a "limit" option', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/limit' ),
                limit = 2;
            metalsmith
                .use( collections( {
                    articles: {
                        limit: limit,
                        sortBy: 'title'
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert.equal( limit, articles.length );
                    assert.equal( 'Alpha', articles[ 0 ].title );
                    assert.equal( 'Beta', articles[ 1 ].title );
                    done();
                } );
        } );

        it( 'should accept a "limit" higher than the collection length', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/limit' );
            metalsmith
                .use( collections( {
                    articles: {
                        sortBy: 'title',
                        limit: 25
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert.equal( 3, articles.length );
                    assert.equal( 'Alpha', articles[ 0 ].title );
                    assert.equal( 'Beta', articles[ 1 ].title );
                    assert.equal( 'Gamma', articles[ 2 ].title );
                    done();
                } );
        } );

        it( 'should add next and previous references', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/references' );
            metalsmith
                .use( collections( { articles: {} } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert( !articles[ 0 ].previous );
                    assert.equal( articles[ 0 ].next, articles[ 1 ] );
                    assert.equal( articles[ 1 ].previous, articles[ 0 ] );
                    assert.equal( articles[ 1 ].next, articles[ 2 ] );
                    debugger;
                    assert.equal( articles[ 2 ].previous, articles[ 1 ] );
                    assert( !articles[ 2 ].next );
                    done();
                } );
        } );

        it( 'should not add references if opts[key].refer === false', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/references-off' );
            metalsmith
                .use( collections( { articles: { refer: false } } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert( !articles[ 0 ].previous );
                    assert( !articles[ 0 ].next );
                    assert( !articles[ 1 ].previous );
                    assert( !articles[ 1 ].next );
                    assert( !articles[ 2 ].previous );
                    assert( !articles[ 2 ].next );
                    done();
                } );
        } );

        it( 'should not fail with empty collections', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/empty' );
            metalsmith
                .use( collections( {
                    articles: {
                        sortBy: 'date',
                        reverse: true
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert.equal( articles.length, 0 );
                    done();
                } );
        } );

        it( 'should add metadata objects to collections', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/basic' );
            metalsmith
                .use( collections( {
                    articles: {
                        metadata: { name: 'Batman' }
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 'Batman', m.articles.metadata.name );
                    done();
                } );
        } );

        it( 'should load collection metadata from a JSON file', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/basic' );
            metalsmith
                .use( collections( {
                    articles: {
                        metadata: fixturePath + '/metadata/metadata.json'
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 'Batman', m.articles.metadata.name );
                    done();
                } );
        } );

        it( 'should load collection metadata from a YAML file', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/basic' );
            metalsmith
                .use( collections( {
                    articles: {
                        metadata: fixturePath + '/metadata/metadata.yaml'
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 'Batman', m.articles.metadata.name );
                    done();
                } );
        } );

        it( 'should allow multiple collections', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/multi' );
            metalsmith
                .use( collections( { articles: {}, posts: {}, drafts: {} } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 2, m.articles.length );
                    assert.equal( 1, m.drafts.length );
                    assert.equal( 1, m.posts.length );
                    assert.equal( m.collections.articles, m.articles );
                    assert.equal( m.collections.drafts, m.drafts );
                    assert.equal( m.collections.posts, m.posts );
                    done();
                } );
        } );

        it( 'should allow collections through metadata alone', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/noconfig' );
            metalsmith
                .use( collections( { movies: {} } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 2, m.books.length );
                    assert.equal( 1, m.movies.length );
                    assert.equal( m.collections.books, m.books );
                    assert.equal( m.collections.movies, m.movies );
                    done();
                } );
        } );

        it( 'should allow collections by pattern and front matter', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/multi' );
            metalsmith
                .use( collections( {
                    articles: {},
                    posts: {},
                    drafts: {},
                    blog: '*.md'
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let m = metalsmith.metadata();
                    assert.equal( 3, m.blog.length );
                    assert.equal( 2, m.articles.length );
                    assert.equal( 1, m.drafts.length );
                    assert.equal( 1, m.posts.length );
                    assert.equal( m.collections.blog, m.blog );
                    assert.equal( m.collections.articles, m.articles );
                    assert.equal( m.collections.drafts, m.drafts );
                    assert.equal( m.collections.posts, m.posts );
                    done();
                } );
        } );

        it( 'should add file path', function( done ) {
            let metalsmith = Metalsmith( fixturePath + '/sort' );
            metalsmith
                .use( collections( {
                    articles: {
                        sortBy: 'title'
                    }
                } ) )
                .build( function( err ) {
                    if ( err ) return done( err );
                    let articles = metalsmith.metadata().articles;
                    assert( articles[ 0 ].path );
                    assert.equal( articles[ 0 ].path, 'one.md' );
                    done();
                } );
        } );

    } );

    context( 'provides functionality that', function() {
        const fixtureRoot = path.resolve( __dirname, 'nested-fixtures' );
        const collectionsConfig = {
            posts: {
                pattern: 'posts/**/*.md',
                sortBy: 'date',
                reverse: true
            },
            'metalsmith-tutorial': {
                pattern: 'posts/metalsmith-tutorial/*.md',
                sortBy: 'date',
                reverse: true
            },
            'shocking-secret': {
                pattern: 'posts/shocking-secret/*.md',
                sortBy: 'date',
                reverse: true
            }
        };

        before( function( done ) {
            rimraf( fixtureRoot + '/*/build', done );
        } );

        it( 'adds "nextInCollection" and "prevInCollection" to file metadata', function( done ) {
            let fixturePath = path.resolve( fixtureRoot, 'basic' );
            let metalsmith = Metalsmith( fixturePath );
            metalsmith
                .use( collections( collectionsConfig ) )
                .build( function( err, files ) {
                    if ( err ) return done( err );
                    let metadata = metalsmith.metadata();

                    // Save file and collection metadata to JSON files
                    let metadataCollection = {
                        files: files,
                        collections: metadata
                    };
                    saveMetadata( fixturePath, metadataCollection );

                    // Test using the `collections` group in the global metadata
                    let names = Object.keys( metadata.collections );
                    for ( let name of names ) {
                        let collection = metadata[ name ];
                        expect( Array.isArray( collection ) ).to.be.true();
                        collection.forEach( ( file, index, array ) => {
                            if ( index > 0 ) {
                                expect( file ).to.have.ownProperty( 'prevInCollection' );
                            }
                            if ( index < ( array.length - 1 ) ) {
                                expect( file ).to.have.ownProperty( 'nextInCollection' );
                            }
                        } );
                    }

                    done();
                } );
        } );

        it( 'adds links by collection to each file', function( done ) {
            let fixturePath = path.resolve( fixtureRoot, 'basic' );
            let metalsmith = Metalsmith( fixturePath );
            metalsmith
                .use( collections( collectionsConfig ) )
                .build( function( err, files ) {
                    if ( err ) return done( err );
                    let metadata = metalsmith.metadata();

                    // Test using the `collections` group in the global metadata
                    let names = Object.keys( metadata.collections );
                    for ( let name of names ) {
                        let collection = metadata.collections[ name ];
                        expect( Array.isArray( collection ) ).to.be.true();
                        collection.forEach( ( file, index, array ) => {
                            if ( index > 0 ) {
                                let prevLinks = file.prevInCollection;
                                expect( prevLinks ).to.be.ok();
                                expect( prevLinks ).to.have.ownProperty( name );
                            }

                            if ( index < ( array.length - 1) ) {
                                let nextLinks = file.nextInCollection;
                                expect( nextLinks ).to.be.ok();
                                expect( nextLinks ).to.have.ownProperty( name );
                            }
                        } );
                    }

                    done();
                } );
        } );

        it( 'correctly links between files in each collection', function( done ){
            let fixturePath = path.resolve( fixtureRoot, 'basic' );
            let metalsmith = Metalsmith( fixturePath );
            metalsmith
                .use( collections( collectionsConfig ) )
                .build( function( err, files ) {
                    if ( err ) return done( err );

                    let todo = [
                        'test links in "metalsmith-tutorial" collection',
                        'test links in "shocking-secret" collection',
                        'test links in "posts" collection'
                    ];
                    let todoMessage = ' <<< There are still ' + todo.length + ' items to complete! >>> ';

                    expect( todo, todoMessage ).to.have.lengthOf( 0 );
                    done();
                } );
        } );

    } );

} );
<|endoftext|>


<commit_before>var test = require('tape');
var mercury = require('mercury');
var Ndarray = require('ndarray');
var raf = require('raf');
var event = require('synthetic-dom-events');
var document = require('global/document');
var stringify = require('node-stringify');

var Grid = require('../');

function end (t, el) {
  // cleanup
  document.body.removeChild(el);
  t.end();
}

test("creating a 4x4 grid of random content", function (t) {
  // setup
  var ndarray = new Ndarray([
    0,[],"",{},null,undefined,
  ], [2,3]);
  var grid = Grid({
    model: ndarray,
    config: {
      edgeSize: 40,
      itemSize: {
        x: 80,
        y: 80,
      },
    },
  });

  // start app
  mercury.app(document.body, grid.state, Grid.render);

  // after render
  raf(function () {
    var el = document.getElementsByClassName('grid ui')[0];

    t.equal(el.style.paddingBottom, "40px");
    t.equal(el.style.paddingLeft, "40px");
    t.equal(el.style.paddingRight, "40px");
    t.equal(el.style.paddingTop, "40px");

    var debugToggle = el.childNodes[0];
    t.ok(debugToggle);
    t.equal(debugToggle.className, "debug toggle");
    var controls = el.childNodes[1];
    t.ok(controls);
    t.equal(controls.className, "controls");
    var rows = el.childNodes[2];
    t.ok(rows);
    t.equal(rows.className, "rows");

    for (var y = 0; y < rows.childNodes.length; y++) {
      var row = rows.childNodes[y];
      t.equal(row.className, "row");

      for (var x = 0; x < row.childNodes.length; x++) {
        var itemContainer = row.childNodes[x];
        t.equal(itemContainer.className, "item");
        t.equal(itemContainer.style.height, "80px");
        t.equal(itemContainer.style.width, "80px");
        t.equal(itemContainer.childNodes.length, 1);
        var item = itemContainer.childNodes[0];
        t.equal(
          item.textContent || item.data,
          stringify(ndarray.get(x, y))
        );
      }
    }

    end(t, el);
  });
});

test("change shape of grid with controls", function (t) {
  // setup
  var data = [
    0,1,2,3,4,5
  ];
  var grid = Grid({
    model: new Ndarray(data, [2, 3]),
    config: {
      debug: true,
    },
  });

  // start app
  mercury.app(document.body, grid.state, Grid.render);

  function assertShape (el, data, shape) {
    var ndarray = new Ndarray(data, shape);

    var rows = el.getElementsByClassName('rows')[0];
    t.equal(rows.childNodes.length, shape[1]);

    for (var y = 0; y < rows.childNodes.length; y++) {
      var row = rows.childNodes[y];
      t.equal(row.childNodes.length, shape[0]);

      for (var x = 0; x < row.childNodes.length; x++) {
        var itemContainer = row.childNodes[x];
        var item = itemContainer.childNodes[0];
        t.equal(
          item.textContent || item.data,
          stringify(ndarray.get(x, y))
        );
      }
    }
  }

  function changeShape (el, shape) {

    if (shape[0]) {
      var xControl = el.getElementsByClassName('shape x control')[0];
      var xInput = xControl.getElementsByClassName('input')[0];
      xInput.value = shape[0].toString();
      xInput.dispatchEvent(event('input', { bubbles: true }));
    }

    if (shape[1]) {
      var yControl = el.getElementsByClassName('shape y control')[0];
      var yInput = yControl.getElementsByClassName('input')[0];
      yInput.value = shape[1].toString();
      yInput.dispatchEvent(event('input', { bubbles: true }));
    }
  }

  // animate
  raf(function () {
    var el = document.getElementsByClassName('grid ui')[0];

    assertShape(el, data, [2, 3]);
    changeShape(el, [3, 2]);

    raf(function () {
      assertShape(el, data, [3, 2]);
      changeShape(el, [1, 6]);

      raf(function () {
        assertShape(el, data, [1, 6]);
        changeShape(el, [6, 1]);

        raf(function () {
          assertShape(el, data, [6, 1]);

          end(t, el);
        });
      });
    });
  });
});
<commit_msg>fix tests now that debug toggle is gone<commit_after>var test = require('tape');
var mercury = require('mercury');
var Ndarray = require('ndarray');
var raf = require('raf');
var event = require('synthetic-dom-events');
var document = require('global/document');
var stringify = require('node-stringify');

var Grid = require('../');

function end (t, el) {
  // cleanup
  document.body.removeChild(el);
  t.end();
}

test("creating a 4x4 grid of random content", function (t) {
  // setup
  var ndarray = new Ndarray([
    0,[],"",{},null,undefined,
  ], [2,3]);
  var grid = Grid({
    model: ndarray,
    config: {
      edgeSize: 40,
      itemSize: {
        x: 80,
        y: 80,
      },
    },
  });

  // start app
  mercury.app(document.body, grid.state, Grid.render);

  // after render
  raf(function () {
    var el = document.getElementsByClassName('grid ui')[0];

    t.equal(el.style.paddingBottom, "40px");
    t.equal(el.style.paddingLeft, "40px");
    t.equal(el.style.paddingRight, "40px");
    t.equal(el.style.paddingTop, "40px");

    var controls = el.childNodes[0];
    t.ok(controls);
    t.equal(controls.className, "controls");
    var rows = el.childNodes[1];
    t.ok(rows);
    t.equal(rows.className, "rows");

    for (var y = 0; y < rows.childNodes.length; y++) {
      var row = rows.childNodes[y];
      t.equal(row.className, "row");

      for (var x = 0; x < row.childNodes.length; x++) {
        var itemContainer = row.childNodes[x];
        t.equal(itemContainer.className, "item");
        t.equal(itemContainer.style.height, "80px");
        t.equal(itemContainer.style.width, "80px");
        t.equal(itemContainer.childNodes.length, 1);
        var item = itemContainer.childNodes[0];
        t.equal(
          item.textContent || item.data,
          stringify(ndarray.get(x, y))
        );
      }
    }

    end(t, el);
  });
});

test("change shape of grid with controls", function (t) {
  // setup
  var data = [
    0,1,2,3,4,5
  ];
  var grid = Grid({
    model: new Ndarray(data, [2, 3]),
    config: {
      debug: true,
    },
  });

  // start app
  mercury.app(document.body, grid.state, Grid.render);

  function assertShape (el, data, shape) {
    var ndarray = new Ndarray(data, shape);

    var rows = el.getElementsByClassName('rows')[0];
    t.equal(rows.childNodes.length, shape[1]);

    for (var y = 0; y < rows.childNodes.length; y++) {
      var row = rows.childNodes[y];
      t.equal(row.childNodes.length, shape[0]);

      for (var x = 0; x < row.childNodes.length; x++) {
        var itemContainer = row.childNodes[x];
        var item = itemContainer.childNodes[0];
        t.equal(
          item.textContent || item.data,
          stringify(ndarray.get(x, y))
        );
      }
    }
  }

  function changeShape (el, shape) {

    if (shape[0]) {
      var xControl = el.getElementsByClassName('shape x control')[0];
      var xInput = xControl.getElementsByClassName('input')[0];
      xInput.value = shape[0].toString();
      xInput.dispatchEvent(event('input', { bubbles: true }));
    }

    if (shape[1]) {
      var yControl = el.getElementsByClassName('shape y control')[0];
      var yInput = yControl.getElementsByClassName('input')[0];
      yInput.value = shape[1].toString();
      yInput.dispatchEvent(event('input', { bubbles: true }));
    }
  }

  // animate
  raf(function () {
    var el = document.getElementsByClassName('grid ui')[0];

    assertShape(el, data, [2, 3]);
    changeShape(el, [3, 2]);

    raf(function () {
      assertShape(el, data, [3, 2]);
      changeShape(el, [1, 6]);

      raf(function () {
        assertShape(el, data, [1, 6]);
        changeShape(el, [6, 1]);

        raf(function () {
          assertShape(el, data, [6, 1]);

          end(t, el);
        });
      });
    });
  });
});
<|endoftext|>


<commit_before>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const makeSerializable = require("./makeSerializable.js");

/**
 * @template T
 * @param {Set<T>} targetSet set where items should be added
 * @param {Set<Iterable<T>>} toMerge iterables to be merged
 * @returns {void}
 */
const merge = (targetSet, toMerge) => {
	for (const set of toMerge) {
		for (const item of set) {
			targetSet.add(item);
		}
	}
};

/**
 * @template T
 * @param {Set<Iterable<T>>} targetSet set where iterables should be added
 * @param {Set<Iterable<T> | LazySet<T>>} toDeepMerge iterables or lazy set to be flattened
 * @returns {void}
 */
const flatten = (targetSet, toDeepMerge) => {
	for (const set of toDeepMerge) {
		if (set instanceof LazySet) {
			targetSet.add(set._set);
			if (set._needMerge) {
				for (const mergedSet of set._toMerge) {
					targetSet.add(mergedSet);
				}
				flatten(targetSet, set._toDeepMerge);
			}
		} else {
			targetSet.add(set);
		}
	}
};

/**
 * Like Set but with an addAll method to eventually add items from another iterable.
 * Access methods make sure that all delayed operations are executed.
 * Iteration methods deopts to normal Set performance until clear is called again (because of the chance of modifications during iteration).
 * @template T
 */
class LazySet {
	/**
	 * @param {Iterable<T>=} iterable init iterable
	 */
	constructor(iterable) {
		/** @type {Set<T>} */
		this._set = new Set(iterable);
		/** @type {Set<Iterable<T>>} */
		this._toMerge = new Set();
		/** @type {Set<Iterable<T> | LazySet<T>>} */
		this._toDeepMerge = new Set();
		this._needMerge = false;
		this._deopt = false;
	}

	_flatten() {
		flatten(this._toMerge, this._toDeepMerge);
		this._toDeepMerge.clear();
	}

	_merge() {
		this._flatten();
		merge(this._set, this._toMerge);
		this._toMerge.clear();
		this._needMerge = false;
	}

	get size() {
		if (this._needMerge) this._merge();
		return this._set.size;
	}

	/**
	 * @param {T} item an item
	 * @returns {this} itself
	 */
	add(item) {
		this._set.add(item);
		return this;
	}

	/**
	 * @param {Iterable<T> | LazySet<T>} iterable a immutable iterable or another immutable LazySet which will eventually be merged into the Set
	 * @returns {this} itself
	 */
	addAll(iterable) {
		if (this._deopt) {
			const _set = this._set;
			for (const item of iterable) {
				_set.add(item);
			}
		} else {
			this._toDeepMerge.add(iterable);
			this._needMerge = true;
			// Avoid being too memory hungry
			if (this._toDeepMerge.size > 100000) {
				this._flatten();
				if (this._toMerge.size > 100000) this._merge();
			}
		}
		return this;
	}

	clear() {
		this._set.clear();
		this._toMerge.clear();
		this._toDeepMerge.clear();
		this._needMerge = false;
		this._deopt = false;
	}

	/**
	 * @param {T} value an item
	 * @returns {boolean} true, if the value was in the Set before
	 */
	delete(value) {
		if (this._needMerge) this._merge();
		return this._set.delete(value);
	}

	entries() {
		this._deopt = true;
		if (this._needMerge) this._merge();
		return this._set.entries();
	}

	/**
	 * @param {function(T, T, Set<T>): void} callbackFn function called for each entry
	 * @param {any} thisArg this argument for the callbackFn
	 * @returns {void}
	 */
	forEach(callbackFn, thisArg) {
		this._deopt = true;
		if (this._needMerge) this._merge();
		this._set.forEach(callbackFn, thisArg);
	}

	/**
	 * @param {T} item an item
	 * @returns {boolean} true, when the item is in the Set
	 */
	has(item) {
		if (this._needMerge) this._merge();
		return this._set.has(item);
	}

	keys() {
		this._deopt = true;
		if (this._needMerge) this._merge();
		return this._set.keys();
	}

	values() {
		this._deopt = true;
		if (this._needMerge) this._merge();
		return this._set.values();
	}

	[Symbol.iterator]() {
		this._deopt = true;
		if (this._needMerge) this._merge();
		return this._set[Symbol.iterator]();
	}

	/* istanbul ignore next */
	get [Symbol.toStringTag]() {
		return "LazySet";
	}

	serialize({ write }) {
		if (this._needMerge) this._merge();
		write(this._set.size);
		for (const item of this._set) write(item);
	}

	static deserialize({ read }) {
		const count = read();
		const items = [];
		for (let i = 0; i < count; i++) {
			items.push(read());
		}
		return new LazySet(items);
	}
}

makeSerializable(LazySet, "webpack/lib/util/LazySet");

module.exports = LazySet;
<commit_msg>LazySet do not check for duplicate LazySets in addAll<commit_after>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const makeSerializable = require("./makeSerializable.js");

/**
 * @template T
 * @param {Set<T>} targetSet set where items should be added
 * @param {Set<Iterable<T>>} toMerge iterables to be merged
 * @returns {void}
 */
const merge = (targetSet, toMerge) => {
	for (const set of toMerge) {
		for (const item of set) {
			targetSet.add(item);
		}
	}
};

/**
 * @template T
 * @param {Set<Iterable<T>>} targetSet set where iterables should be added
 * @param {Array<Iterable<T> | LazySet<T>>} toDeepMerge iterables or lazy set to be flattened
 * @returns {void}
 */
const flatten = (targetSet, toDeepMerge) => {
	for (const set of toDeepMerge) {
		if (set instanceof LazySet) {
			if (set._set.size > 0) targetSet.add(set._set);
			if (set._needMerge) {
				for (const mergedSet of set._toMerge) {
					targetSet.add(mergedSet);
				}
				flatten(targetSet, set._toDeepMerge);
			}
		} else {
			targetSet.add(set);
		}
	}
};

/**
 * Like Set but with an addAll method to eventually add items from another iterable.
 * Access methods make sure that all delayed operations are executed.
 * Iteration methods deopts to normal Set performance until clear is called again (because of the chance of modifications during iteration).
 * @template T
 */
class LazySet {
	/**
	 * @param {Iterable<T>=} iterable init iterable
	 */
	constructor(iterable) {
		/** @type {Set<T>} */
		this._set = new Set(iterable);
		/** @type {Set<Iterable<T>>} */
		this._toMerge = new Set();
		/** @type {Array<Iterable<T> | LazySet<T>>} */
		this._toDeepMerge = [];
		this._needMerge = false;
		this._deopt = false;
	}

	_flatten() {
		flatten(this._toMerge, this._toDeepMerge);
		this._toDeepMerge.length = 0;
	}

	_merge() {
		this._flatten();
		merge(this._set, this._toMerge);
		this._toMerge.clear();
		this._needMerge = false;
	}

	get size() {
		if (this._needMerge) this._merge();
		return this._set.size;
	}

	/**
	 * @param {T} item an item
	 * @returns {this} itself
	 */
	add(item) {
		this._set.add(item);
		return this;
	}

	/**
	 * @param {Iterable<T> | LazySet<T>} iterable a immutable iterable or another immutable LazySet which will eventually be merged into the Set
	 * @returns {this} itself
	 */
	addAll(iterable) {
		if (this._deopt) {
			const _set = this._set;
			for (const item of iterable) {
				_set.add(item);
			}
		} else {
			this._toDeepMerge.push(iterable);
			this._needMerge = true;
			// Avoid being too memory hungry
			if (this._toDeepMerge.length > 100000) {
				this._flatten();
				if (this._toMerge.size > 100000) this._merge();
			}
		}
		return this;
	}

	clear() {
		this._set.clear();
		this._toMerge.clear();
		this._toDeepMerge.length = 0;
		this._needMerge = false;
		this._deopt = false;
	}

	/**
	 * @param {T} value an item
	 * @returns {boolean} true, if the value was in the Set before
	 */
	delete(value) {
		if (this._needMerge) this._merge();
		return this._set.delete(value);
	}

	entries() {
		this._deopt = true;
		if (this._needMerge) this._merge();
		return this._set.entries();
	}

	/**
	 * @param {function(T, T, Set<T>): void} callbackFn function called for each entry
	 * @param {any} thisArg this argument for the callbackFn
	 * @returns {void}
	 */
	forEach(callbackFn, thisArg) {
		this._deopt = true;
		if (this._needMerge) this._merge();
		this._set.forEach(callbackFn, thisArg);
	}

	/**
	 * @param {T} item an item
	 * @returns {boolean} true, when the item is in the Set
	 */
	has(item) {
		if (this._needMerge) this._merge();
		return this._set.has(item);
	}

	keys() {
		this._deopt = true;
		if (this._needMerge) this._merge();
		return this._set.keys();
	}

	values() {
		this._deopt = true;
		if (this._needMerge) this._merge();
		return this._set.values();
	}

	[Symbol.iterator]() {
		this._deopt = true;
		if (this._needMerge) this._merge();
		return this._set[Symbol.iterator]();
	}

	/* istanbul ignore next */
	get [Symbol.toStringTag]() {
		return "LazySet";
	}

	serialize({ write }) {
		if (this._needMerge) this._merge();
		write(this._set.size);
		for (const item of this._set) write(item);
	}

	static deserialize({ read }) {
		const count = read();
		const items = [];
		for (let i = 0; i < count; i++) {
			items.push(read());
		}
		return new LazySet(items);
	}
}

makeSerializable(LazySet, "webpack/lib/util/LazySet");

module.exports = LazySet;
<|endoftext|>


<commit_before>/* jQuery Deferred replacement

	provides a Promise constructor and a then method
	conforming to the Promises/A+ spec
*/

function Promise(resolver) {
	var doneList = $.Callbacks('once memory'),
		failList = $.Callbacks('once memory'),
		promise = {
			// Get promise
			// If obj is provided, the promise aspect is added to the object
			promise: function( obj ) {
				return obj != null ? $.extend( obj, promise ) : promise;
			},
			done: doneList.add,
			fail: failList.add
		};

	// Resolve recursively if fn is provided
	function resolveWith(context, args, fn, thenable) {
		var resolved;

		function resolve(value) {
			if (!resolved)
				try {
					var then = arguments.length == 1 && _.isObject(value) && value.then;
					resolved = true;
					resolveWith(context, arguments, then, value);
				} catch (e) {
					reject(e);
				}
		}

		function reject() {
			if (resolved) return;
			resolved = true;
			failList.fireWith(context, arguments);
		}

		if (_.isFunction(fn))
			try {
				if (thenable === promise)
					throw new TypeError('Cannot resolve promise with itself');

				// If thenable is a promise, adopt its state
				if (fn == then)
					promise = thenable.promise().done(doneList.fire).fail(failList.fire);
				else
					fn.call(thenable, resolve, reject);
			} catch (e) {
				reject(e);
			}
		else
			doneList.fireWith(context, args);

		return this;
	}

	// Handle state
	doneList.add(failList.disable);
	failList.add(doneList.disable);

	// Assign promise properties to this instance
	promise = promise.promise(this);

	// resolver(resolveWith, rejectWith)
	resolver(resolveWith, failList.fireWith);
	return promise;
}

Promise.prototype = {
	then: then,
	always: function() {
		return this.done(arguments).fail(arguments);
	},
	progress: function() {
		return this;
	}
};

function then(onFulfilled, onRejected) {
	var fn = onFulfilled,
		promise = this.promise().fail(function() { fn = onRejected; });

	return new Promise(function(resolveWith) {
		promise.always(function() {
			var values = arguments;

			resolveWith(this, null, function(resolve, reject) {
				if (_.isFunction(fn))
					setTimeout(function() {
						try {
							resolve(fn.apply(void 0, values));
						} catch (e) {
							reject(e);
						}
					}, 0);
				else
					resolve(promise);
			});
		});
	});
}

$.Deferred = function( func ) {
	var progressList = $.Callbacks('memory'),
		deferred = {},
		promise = new Promise(function(resolveWith, rejectWith) {
			$.each({
				resolve: resolveWith,
				reject: rejectWith,
				notify: progressList.fireWith
			}, function(action, fireWith) {
				// deferred[ resolve | reject | notify ]
				deferred[ action ] = function() {
					fireWith( this === deferred ? promise : this, arguments );
					return this;
				};
				deferred[ action + 'With' ] = fireWith;
			});
		})
		.always(progressList.lock);

	promise.progress = progressList.add;

	// Make the deferred a promise
	promise.promise( deferred );

	// Call given func if any
	if ( func ) {
		func.call( deferred, deferred );
	}

	// All done!
	return deferred;
};

module.exports = function(resolver, context) {
	return new Promise(function(resolveWith) {
		resolveWith(context, null, resolver);
	});
};
<commit_msg>Fix resolver not called with context<commit_after>/* jQuery Deferred replacement

	provides a Promise constructor and a then method
	conforming to the Promises/A+ spec
*/

function Promise(resolver) {
	var doneList = $.Callbacks('once memory'),
		failList = $.Callbacks('once memory'),
		promise = {
			// Get promise
			// If obj is provided, the promise aspect is added to the object
			promise: function( obj ) {
				return obj != null ? $.extend( obj, promise ) : promise;
			},
			done: doneList.add,
			fail: failList.add
		};

	// Resolve recursively if fn is provided
	function resolveWith(context, args, fn, thenable) {
		var resolved;

		function resolve(value) {
			if (!resolved)
				try {
					var then = arguments.length == 1 && _.isObject(value) && value.then;
					resolved = true;
					resolveWith(context, arguments, then, value);
				} catch (e) {
					reject(e);
				}
		}

		function reject() {
			if (resolved) return;
			resolved = true;
			failList.fireWith(context, arguments);
		}

		if (_.isFunction(fn))
			try {
				if (thenable === promise)
					throw new TypeError('Cannot resolve promise with itself');

				// If thenable is a promise, adopt its state
				if (fn == then)
					promise = thenable.promise().done(doneList.fire).fail(failList.fire);
				else
					fn.call(thenable, resolve, reject);
			} catch (e) {
				reject(e);
			}
		else
			doneList.fireWith(context, args);

		return this;
	}

	// Handle state
	doneList.add(failList.disable);
	failList.add(doneList.disable);

	// Assign promise properties to this instance
	promise = promise.promise(this);

	// resolver(resolveWith, rejectWith)
	resolver(resolveWith, failList.fireWith);
	return promise;
}

Promise.prototype = {
	then: then,
	always: function() {
		return this.done(arguments).fail(arguments);
	},
	progress: function() {
		return this;
	}
};

function then(onFulfilled, onRejected) {
	var fn = onFulfilled,
		promise = this.promise().fail(function() { fn = onRejected; });

	return new Promise(function(resolveWith) {
		promise.always(function() {
			var values = arguments;

			resolveWith(this, null, function(resolve, reject) {
				if (_.isFunction(fn))
					setTimeout(function() {
						try {
							resolve(fn.apply(void 0, values));
						} catch (e) {
							reject(e);
						}
					}, 0);
				else
					resolve(promise);
			});
		});
	});
}

$.Deferred = function( func ) {
	var progressList = $.Callbacks('memory'),
		deferred = {},
		promise = new Promise(function(resolveWith, rejectWith) {
			$.each({
				resolve: resolveWith,
				reject: rejectWith,
				notify: progressList.fireWith
			}, function(action, fireWith) {
				// deferred[ resolve | reject | notify ]
				deferred[ action ] = function() {
					fireWith( this === deferred ? promise : this, arguments );
					return this;
				};
				deferred[ action + 'With' ] = fireWith;
			});
		})
		.always(progressList.lock);

	promise.progress = progressList.add;

	// Make the deferred a promise
	promise.promise( deferred );

	// Call given func if any
	if ( func ) {
		func.call( deferred, deferred );
	}

	// All done!
	return deferred;
};

module.exports = function(resolver, context) {
	return new Promise(function(resolveWith) {
		resolveWith(context, null, resolver, context);
	});
};
<|endoftext|>


<commit_before>
import * as updater from './updater'
import * as appWindow from './appWindow'
import * as quickStart from './quickStart'
const electron = require('electron')

const Menu = electron.Menu

const isDarwin = process.platform === 'darwin'

let appMenu = null

const separatorMenuItem = { type: 'separator' }

const aboutTadMenuItem = () => {
  return {
    label: 'About Tad',
    role: 'about'
  }
}
const checkForUpdateMenuItem = () => {
  return {
    label: 'Check for Updates',
    click: updater.checkForUpdates
  }
}
export const createMenu = () => {
  const fileSubmenu = [
    {
      label: 'Open...',
      accelerator: 'CmdOrCtrl+O',
      click: (item, focusedWindow) => {
        appWindow.openDialog()
      }
    },
    separatorMenuItem,
    {
      label: 'Save As...',
      accelerator: 'Shift+CmdOrCtrl+S',
      click: (item, focusedWindow) => {
        appWindow.saveAsDialog()
      }
    }
  ]
  const debugSubmenu = [
    { role: 'toggledevtools' },
    { label: 'Show Hidden Columns',
      type: 'checkbox',
      click: (item, focusedWindow) => {
        console.log('show hidden...: ', item)
        focusedWindow.webContents.send('set-show-hidden-cols', item.checked)
      }
    }
  ]
  const helpSubmenu = [
    {
      label: 'Quick Start Guide',
      click: (item, focusedWindow) => {
        quickStart.showQuickStart()
      }
    },
    {
      label: 'Send Feedback / Bug Reports',
      click: (item, focusedWindow) => {
        electron.shell.openExternal('mailto:tad-feedback@tadviewer.com')
      }
    }
  ]
  const template = [
    { label: 'File', submenu: fileSubmenu }
  ]
  if (process.env.NODE_ENV === 'development') {
    template.push({
      label: 'Debug',
      submenu: debugSubmenu
    })
  }
  template.push({
    label: 'Help',
    submenu: helpSubmenu
  })
  if (isDarwin) {
    template.unshift({
      label: 'Tad', // ignored on Mac OS; comes from plist
      submenu: [
        aboutTadMenuItem(),
        separatorMenuItem,
        checkForUpdateMenuItem(),
        separatorMenuItem,
        { role: 'quit' }
      ]
    })
  }

  let oldMenu = appMenu
  appMenu = Menu.buildFromTemplate(template)
  Menu.setApplicationMenu(appMenu)
  if (oldMenu) {
    oldMenu.destroy()
  }
}
<commit_msg>Add quit to File menu on non-Darwin.<commit_after>
import * as updater from './updater'
import * as appWindow from './appWindow'
import * as quickStart from './quickStart'
const electron = require('electron')

const Menu = electron.Menu

const isDarwin = process.platform === 'darwin'

let appMenu = null

const separatorMenuItem = { type: 'separator' }

const aboutTadMenuItem = () => {
  return {
    label: 'About Tad',
    role: 'about'
  }
}
const checkForUpdateMenuItem = () => {
  return {
    label: 'Check for Updates',
    click: updater.checkForUpdates
  }
}
export const createMenu = () => {
  const fileSubmenu = [
    {
      label: 'Open...',
      accelerator: 'CmdOrCtrl+O',
      click: (item, focusedWindow) => {
        appWindow.openDialog()
      }
    },
    separatorMenuItem,
    {
      label: 'Save As...',
      accelerator: 'Shift+CmdOrCtrl+S',
      click: (item, focusedWindow) => {
        appWindow.saveAsDialog()
      }
    }
  ]
  if (!isDarwin) {
    fileSubmenu.push(separatorMenuItem)
    fileSubmenu.push({ role: 'quit' })
  }
  const debugSubmenu = [
    { role: 'toggledevtools' },
    { label: 'Show Hidden Columns',
      type: 'checkbox',
      click: (item, focusedWindow) => {
        console.log('show hidden...: ', item)
        focusedWindow.webContents.send('set-show-hidden-cols', item.checked)
      }
    }
  ]
  const helpSubmenu = [
    {
      label: 'Quick Start Guide',
      click: (item, focusedWindow) => {
        quickStart.showQuickStart()
      }
    },
    {
      label: 'Send Feedback / Bug Reports',
      click: (item, focusedWindow) => {
        electron.shell.openExternal('mailto:tad-feedback@tadviewer.com')
      }
    }
  ]
  const template = [
    { label: 'File', submenu: fileSubmenu }
  ]
  if (process.env.NODE_ENV === 'development') {
    template.push({
      label: 'Debug',
      submenu: debugSubmenu
    })
  }
  template.push({
    label: 'Help',
    submenu: helpSubmenu
  })
  if (isDarwin) {
    template.unshift({
      label: 'Tad', // ignored on Mac OS; comes from plist
      submenu: [
        aboutTadMenuItem(),
        separatorMenuItem,
        checkForUpdateMenuItem(),
        separatorMenuItem,
        { role: 'quit' }
      ]
    })
  }

  let oldMenu = appMenu
  appMenu = Menu.buildFromTemplate(template)
  Menu.setApplicationMenu(appMenu)
  if (oldMenu) {
    oldMenu.destroy()
  }
}
<|endoftext|>


<commit_before>/* eslint camelcase: 0 */
import { getControlsState, getFormDataFromControls } from '../stores/store';
import * as actions from '../actions/exploreActions';

export default function exploreReducer(state = {}, action) {
  const actionHandlers = {
    [actions.TOGGLE_FAVE_STAR]() {
      return Object.assign({}, state, { isStarred: action.isStarred });
    },
    [actions.FETCH_DATASOURCE_STARTED]() {
      return Object.assign({}, state, { isDatasourceMetaLoading: true });
    },
    [actions.FETCH_DATASOURCE_SUCCEEDED]() {
      return Object.assign({}, state, { isDatasourceMetaLoading: false });
    },
    [actions.FETCH_DATASOURCE_FAILED]() {
      // todo(alanna) handle failure/error state
      return Object.assign({}, state,
        {
          isDatasourceMetaLoading: false,
          controlPanelAlert: action.error,
        });
    },
    [actions.SET_DATASOURCE]() {
      return Object.assign({}, state, { datasource: action.datasource });
    },
    [actions.FETCH_DATASOURCES_STARTED]() {
      return Object.assign({}, state, { isDatasourcesLoading: true });
    },
    [actions.FETCH_DATASOURCES_SUCCEEDED]() {
      return Object.assign({}, state, { isDatasourcesLoading: false });
    },
    [actions.FETCH_DATASOURCES_FAILED]() {
      // todo(alanna) handle failure/error state
      return Object.assign({}, state,
        {
          isDatasourcesLoading: false,
          controlPanelAlert: action.error,
        });
    },
    [actions.SET_DATASOURCES]() {
      return Object.assign({}, state, { datasources: action.datasources });
    },
    [actions.REMOVE_CONTROL_PANEL_ALERT]() {
      return Object.assign({}, state, { controlPanelAlert: null });
    },
    [actions.SET_FIELD_VALUE]() {
      const controls = Object.assign({}, state.controls);
      const control = Object.assign({}, controls[action.controlName]);
      control.value = action.value;
      control.validationErrors = action.validationErrors;
      controls[action.controlName] = control;
      const changes = { controls };
      if (control.renderTrigger) {
        changes.triggerRender = true;
      }
      return Object.assign({}, state, changes);
    },
    [actions.SET_EXPLORE_CONTROLS]() {
      const controls = getControlsState(state, action.formData);
      return Object.assign({}, state, { controls });
    },
    [actions.UPDATE_CHART_TITLE]() {
      const updatedSlice = Object.assign({}, state.slice, { slice_name: action.slice_name });
      return Object.assign({}, state, { slice: updatedSlice });
    },
    [actions.RESET_FIELDS]() {
      const controls = getControlsState(state, getFormDataFromControls(state.controls));
      return Object.assign({}, state, { controls });
    },
    [actions.CREATE_NEW_SLICE]() {
      return Object.assign({}, state, {
        slice: action.slice,
        controls: getControlsState(state, action.form_data),
        can_add: action.can_add,
        can_download: action.can_download,
        can_overwrite: action.can_overwrite,
      });
    },
  };
  if (action.type in actionHandlers) {
    return actionHandlers[action.type]();
  }
  return state;
}
<commit_msg>Refactoring on exploreReducer.js (#4836)<commit_after>/* eslint camelcase: 0 */
import { getControlsState, getFormDataFromControls } from '../stores/store';
import * as actions from '../actions/exploreActions';

export default function exploreReducer(state = {}, action) {
  const actionHandlers = {
    [actions.TOGGLE_FAVE_STAR]() {
      return {
        ...state,
        isStarred: action.isStarred,
      };
    },
    [actions.FETCH_DATASOURCE_STARTED]() {
      return {
        ...state,
        isDatasourceMetaLoading: true,
      };
    },
    [actions.FETCH_DATASOURCE_SUCCEEDED]() {
      return {
        ...state,
        isDatasourceMetaLoading: false,
      };
    },
    [actions.FETCH_DATASOURCE_FAILED]() {
      return {
        ...state,
        isDatasourceMetaLoading: false,
        controlPanelAlert: action.error,
      };
    },
    [actions.SET_DATASOURCE]() {

      return {
        ...state,
        datasource: action.datasource,
      };
    },
    [actions.FETCH_DATASOURCES_STARTED]() {

      return {
        ...state,
        isDatasourcesLoading: true,
      };
    },
    [actions.FETCH_DATASOURCES_SUCCEEDED]() {

      return {
        ...state,
        isDatasourcesLoading: false,
      };
    },
    [actions.FETCH_DATASOURCES_FAILED]() {

      return {
        ...state,
        isDatasourcesLoading: false,
        controlPanelAlert: action.error,
      };
    },
    [actions.SET_DATASOURCES]() {
      return {
        ...state,
        datasources: action.datasources,
      };
    },
    [actions.REMOVE_CONTROL_PANEL_ALERT]() {
      return {
        ...state,
        controlPanelAlert: null,
      };
    },
    [actions.SET_FIELD_VALUE]() {
      const controls = Object.assign({}, state.controls);
      const control = Object.assign({}, controls[action.controlName]);
      control.value = action.value;
      control.validationErrors = action.validationErrors;
      controls[action.controlName] = control;
      const changes = {
        controls,
      };
      if (control.renderTrigger) {
        changes.triggerRender = true;
      }
      return {
        ...state,
        ...changes,
      };
    },
    [actions.SET_EXPLORE_CONTROLS]() {
      return {
        ...state,
        controls: getControlsState(state, action.formData),
      };
    },
    [actions.UPDATE_CHART_TITLE]() {
      const updatedSlice = Object.assign({}, state.slice, { slice_name: action.slice_name });
      return {
        ...state,
        slice: updatedSlice,
      };
    },
    [actions.RESET_FIELDS]() {
      return {
        ...state,
        controls: getControlsState(state, getFormDataFromControls(state.controls)),
      };
    },
    [actions.CREATE_NEW_SLICE]() {
      return {
        ...state,
        slice: action.slice,
        controls: getControlsState(state, action.form_data),
        can_add: action.can_add,
        can_download: action.can_download,
        can_overwrite: action.can_overwrite,
      };
    },
  };
  if (action.type in actionHandlers) {
    return actionHandlers[action.type]();
  }
  return state;
}
<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash');
var kbox = require('../kbox.js');
var pp = require('util').inspect;

/*
 * Returns current version of kalabox.
 */
var get = function() {

  var globalConfig = kbox.core.deps.get('globalConfig');
  return globalConfig.version;

};

/*
 * Parse a version string into a version object.
 */
var parse = function(s) {

  // Validate version string is in fact a string.
  if (typeof s !== 'string') {
    throw new Error('Invalid version string: ' + pp(s));
  }

  // Split string into parts.
  var parts = s.split('.');

  // Validate.
  if (parts.length !== 3) {
    throw new Error('Invalid config.version: ' + s);
  }

  // Return as an object.
  return {
    major: parts[0],
    minor: parts[1],
    patch: parts[2]
  };

};

/*
 * List of valid property keys for a version object.
 */
var validPropertyKeys = _.once(function() {

  return _.keys(parse('0.0.0'));

});

/*
 * Format a version object into a string.
 */
var format = function(o) {

  // Validate object is an object.
  if (typeof o !== 'object') {
    throw new Error('Invalid version object: ' + pp(o));
  }

  // Validate object properties.
  _.each(o, function(val, key) {
    if (typeof val !== 'string' || !_.contains(validPropertyKeys, key)) {
      throw new Error('Invalid version object: ' + pp(o));
    }
  });

  // Return as a string.
  return [o.major, o.minor, o.patch].join('.');

};

/*
 * Take a version and set it's patch to zero.
 */
var truncatePatch = function(version) {

  var o = parse(version);
  o.patch = '0';
  return format(o);

};
<commit_msg>Added module.exports to lib/util/version.js.<commit_after>'use strict';

var _ = require('lodash');
var kbox = require('../kbox.js');
var pp = require('util').inspect;

/*
 * Returns current version of kalabox.
 */
var get = function() {

  var globalConfig = kbox.core.deps.get('globalConfig');
  return globalConfig.version;

};

/*
 * Parse a version string into a version object.
 */
var parse = function(s) {

  // Validate version string is in fact a string.
  if (typeof s !== 'string') {
    throw new Error('Invalid version string: ' + pp(s));
  }

  // Split string into parts.
  var parts = s.split('.');

  // Validate.
  if (parts.length !== 3) {
    throw new Error('Invalid config.version: ' + s);
  }

  // Return as an object.
  return {
    major: parts[0],
    minor: parts[1],
    patch: parts[2]
  };

};

/*
 * List of valid property keys for a version object.
 */
var validPropertyKeys = _.once(function() {

  return _.keys(parse('0.0.0'));

});

/*
 * Format a version object into a string.
 */
var format = function(o) {

  // Validate object is an object.
  if (typeof o !== 'object') {
    throw new Error('Invalid version object: ' + pp(o));
  }

  // Validate object properties.
  _.each(o, function(val, key) {
    if (typeof val !== 'string' || !_.contains(validPropertyKeys, key)) {
      throw new Error('Invalid version object: ' + pp(o));
    }
  });

  // Return as a string.
  return [o.major, o.minor, o.patch].join('.');

};

/*
 * Take a version and set it's patch to zero.
 */
var truncatePatch = function(version) {

  var o = parse(version);
  o.patch = '0';
  return format(o);

};

module.exports = {
  format: format,
  get: get,
  parse: parse,
  truncatePatch: truncatePatch
};
<|endoftext|>


<commit_before>/* eslint-env mocha */

'use strict';

const fs = require('fs');
const assert = require('assert');
const oust = require('..');

it('should return an array of stylesheet link hrefs', () => {
    const links = oust(fs.readFileSync('test/sample/index.html', 'utf8'), 'stylesheets');
    assert(Array.isArray(links));
    assert(links.length === 2);
    assert(links[0] === 'bower_components/bootstrap/dist/css/bootstrap.css');
    assert(links[1] === 'styles/main.css');
});

it('should return an array of refs when passed a HTML string', () => {
    const links = oust('<link rel="stylesheet" href="styles/main.css">', 'stylesheets');
    assert(Array.isArray(links));
    assert(links.length === 1);
    assert(links[0] === 'styles/main.css');
});

it('should return an array of stylesheet link cheerio elements', () => {
    const links = oust.raw(fs.readFileSync('test/media.html', 'utf8'), 'stylesheets');

    assert(Array.isArray(links));
    links.forEach(link => {
        assert(typeof link.$el.attr === 'function');
        assert(typeof link.$el.attr === 'function');
        assert(typeof link.$el.html === 'function');
        assert(typeof link.$el.val === 'function');
        assert(typeof link.$el.contents === 'function');
    });

    assert(links.length === 2);
    assert(links[0].value === 'styles/main.css');
    assert(links[1].value === 'styles/print.css');
});

it('should return an array of script srcs', () => {
    const links = oust(fs.readFileSync('test/sample/index.html', 'utf8'), 'scripts');
    assert(Array.isArray(links));
    assert(links.length === 1);
    assert(links[0] === 'scripts/main.js');
});

it('should return an array of HTML imports', () => {
    const links = oust(fs.readFileSync('test/imports.html', 'utf8'), 'imports');
    assert(Array.isArray(links));
    assert(links.length === 3);
    assert(links[0] === '../polymer/polymer.html');
    assert(links[1] === '../core-ajax/core-ajax.html');
});

it('should return an array of stylesheet preload hrefs', () => {
    const links = oust(fs.readFileSync('test/sample/index.html', 'utf8'), 'preload');
    assert(Array.isArray(links));
    assert(links.length === 1);
    assert(links[0] === 'styles/preload.css');
});

it('should return an array of link URLs', () => {
    const links = oust(fs.readFileSync('test/sample/index.html', 'utf8'), 'links');
    assert(Array.isArray(links));
    assert(links.length === 4);
    assert(links[0] === 'index.html');
    assert(links[1] === 'about.html');
    assert(links[2] === 'contact.html');
});

it('should return an array of image sources', () => {
    const links = oust(fs.readFileSync('test/sample/index.html', 'utf8'), 'images');
    assert(Array.isArray(links));
    assert(links.length === 3);
    assert(links[0] === 'http://placekitten.com/200/300');
    assert(links[1] === 'http://placekitten.com/300/400');
    assert(links[2] === 'http://placekitten.com/500/600');
});

it('should fail if no valid source is specified', () => {
    assert.throws(() => {
        oust();
    });
});

it('should fail if no valid type is specified', () => {
    assert.throws(() => {
        oust(fs.readFileSync('test/imports.html', 'utf8'));
    });
});
<commit_msg>Rewrite tests. (#32)<commit_after>/* eslint-env mocha */

'use strict';

const fs = require('fs');
const assert = require('assert');
const oust = require('..');

const read = file => fs.readFileSync(file, 'utf8');

it('should return an array of stylesheet link hrefs', () => {
    const links = oust(read('test/sample/index.html'), 'stylesheets');
    const expected = [
        'bower_components/bootstrap/dist/css/bootstrap.css',
        'styles/main.css'
    ];

    assert.strictEqual(Array.isArray(links), true);
    assert.strictEqual(links.length, expected.length);
    assert.deepStrictEqual(links, expected);
});

it('should return an array of refs when passed a HTML string', () => {
    const links = oust('<link rel="stylesheet" href="styles/main.css">', 'stylesheets');
    const expected = [
        'styles/main.css'
    ];

    assert.strictEqual(Array.isArray(links), true);
    assert.strictEqual(links.length, expected.length);
    assert.deepStrictEqual(links, expected);
});

it('should return an array of stylesheet link cheerio elements', () => {
    const links = oust.raw(read('test/media.html'), 'stylesheets');
    const expected = [{
        value: 'styles/main.css'
    }, {
        value: 'styles/print.css'
    }];

    assert.strictEqual(Array.isArray(links), true);
    assert.strictEqual(links.length, expected.length);

    links.forEach((link, index) => {
        assert.strictEqual(typeof link.$el.attr, 'function');
        assert.strictEqual(typeof link.$el.html, 'function');
        assert.strictEqual(typeof link.$el.val, 'function');
        assert.strictEqual(typeof link.$el.contents, 'function');
        assert.strictEqual(link.value, expected[index].value);
    });
});

it('should return an array of script srcs', () => {
    const links = oust(read('test/sample/index.html'), 'scripts');
    const expected = [
        'scripts/main.js'
    ];

    assert.strictEqual(Array.isArray(links), true);
    assert.strictEqual(links.length, expected.length);
    assert.deepStrictEqual(links, expected);
});

it('should return an array of HTML imports', () => {
    const links = oust(read('test/imports.html'), 'imports');
    const expected = [
        '../polymer/polymer.html',
        '../core-ajax/core-ajax.html',
        '../core-input/core-input.html'
    ];

    assert.strictEqual(Array.isArray(links), true);
    assert.strictEqual(links.length, expected.length);
    assert.deepStrictEqual(links, expected);
});

it('should return an array of stylesheet preload hrefs', () => {
    const links = oust(read('test/sample/index.html'), 'preload');
    const expected = [
        'styles/preload.css'
    ];

    assert.strictEqual(Array.isArray(links), true);
    assert.strictEqual(links.length, expected.length);
    assert.deepStrictEqual(links, expected);
});

it('should return an array of link URLs', () => {
    const links = oust(read('test/sample/index.html'), 'links');
    const expected = [
        'index.html',
        'about.html',
        'contact.html',
        '#'
    ];

    assert.strictEqual(Array.isArray(links), true);
    assert.strictEqual(links.length, expected.length);
    assert.deepStrictEqual(links, expected);
});

it('should return an array of image sources', () => {
    const links = oust(read('test/sample/index.html'), 'images');
    const expected = [
        'http://placekitten.com/200/300',
        'http://placekitten.com/300/400',
        'http://placekitten.com/500/600'
    ];

    assert.strictEqual(Array.isArray(links), true);
    assert.strictEqual(links.length, expected.length);
    assert.deepStrictEqual(links, expected);
});

it('should fail if no valid source is specified', () => {
    assert.throws(() => {
        oust();
    }, /^Error: `src` and `type` required$/);
});

it('should fail if no valid type is specified', () => {
    assert.throws(() => {
        oust(read('test/imports.html'));
    }, /^Error: `src` and `type` required$/);
});
<|endoftext|>