<commit_before>const _loggingFacility = require('logging-facility');
const _logger = _loggingFacility.getLogger('NodeMCU-Tool');
const _nodemcutool = require('./nodemcu-tool');
const _fs = require('fs-magic');
const _path = require('path');
const _configFilename = _path.join(process.cwd(), '.nodemcutool');

async function parseOptions(options){
    // default
    options = options || {};

    // debug mode enabled by flag ?
    if (options.parent.debug===true){
        // enable silent mode (decrease logging level)
        _loggingFacility.setBackend(_loggingFacility.LOGGER.FANCY(_loggingFacility.LEVEL.DEBUG));

    // silent mode enabled by flag ?
    // silent mode enabled by json output format ?
    // silent mode enabled by json raw format ?
    } else if (options.parent.silent===true || options.json === true || options.raw === true){
        // enable silent mode (decrease logging level)
        _loggingFacility.setBackend(_loggingFacility.LOGGER.FANCY(_loggingFacility.LEVEL.WARNING));
    }else{
        _loggingFacility.setBackend(_loggingFacility.LOGGER.FANCY(_loggingFacility.LEVEL.INFO));
    }

    // project based configuration
    let configFile = {};
    if (await _fs.isFile(_configFilename)){

        // try to load project based configuration
        const data = await _fs.readFile(_configFilename, 'utf8');

        if (data.length > 10){
            // decode json based data
            configFile = JSON.parse(data);
            _logger.log('Project based configuration loaded');
        }
    }

    // generated config
    const config = {};

    // utility function to merge different options
    // cli args take presendence over config
    function mergeOptions(...opt){
        // extract default (last argument)
        const result = opt.pop();

        // try to find first match
        while (opt.length > 0){
            // extract first argument (priority)
            const o = opt.shift();

            // value set ?
            if (typeof o !== 'undefined' && o !== null){
                return o;
            }
        }

        return result;
    }

    // merge global flags, command flags and global defaults
    // config file + cli args
    config.baudrate =        mergeOptions(options.parent.baud, configFile.baudrate, '115200');
    config.port =           mergeOptions(options.parent.port, configFile.port, '/dev/ttyUSB0');
    config.connectionDelay = mergeOptions(options.parent.connectionDelay, configFile.connectionDelay, 0);
    config.minify =         mergeOptions(options.minify, configFile.minify, false);
    config.compile =        mergeOptions(options.compile, configFile.compile, false);
    config.keeppath =       mergeOptions(options.keeppath, configFile.keeppath, false);

    // CLI args only
    config.remotename =     mergeOptions(options.minify, null);
    config.run =            mergeOptions(options.run, false);
    config.all =            mergeOptions(options.all, false);
    config.json =           mergeOptions(options.json, false);
    config.raw =            mergeOptions(options.raw, false);
    config.softreset =      mergeOptions(options.softreset, false);

    // set port/baud options
    _nodemcutool.setOptions({
        device:             config.port,
        baudrate:           config.baudrate,
        connectionDelay:    config.connectionDelay
    });

    return config;
}

// write options to file
async function storeOptions(options){
    await _fs.writeFile(_configFilename, JSON.stringify(options, null, 4));
}

module.exports = {
    parse: parseOptions,
    store: storeOptions
};<commit_msg>typo: remotename config variable<commit_after>const _loggingFacility = require('logging-facility');
const _logger = _loggingFacility.getLogger('NodeMCU-Tool');
const _nodemcutool = require('./nodemcu-tool');
const _fs = require('fs-magic');
const _path = require('path');
const _configFilename = _path.join(process.cwd(), '.nodemcutool');

async function parseOptions(options){
    // default
    options = options || {};

    // debug mode enabled by flag ?
    if (options.parent.debug===true){
        // enable silent mode (decrease logging level)
        _loggingFacility.setBackend(_loggingFacility.LOGGER.FANCY(_loggingFacility.LEVEL.DEBUG));

    // silent mode enabled by flag ?
    // silent mode enabled by json output format ?
    // silent mode enabled by json raw format ?
    } else if (options.parent.silent===true || options.json === true || options.raw === true){
        // enable silent mode (decrease logging level)
        _loggingFacility.setBackend(_loggingFacility.LOGGER.FANCY(_loggingFacility.LEVEL.WARNING));
    }else{
        _loggingFacility.setBackend(_loggingFacility.LOGGER.FANCY(_loggingFacility.LEVEL.INFO));
    }

    // project based configuration
    let configFile = {};
    if (await _fs.isFile(_configFilename)){

        // try to load project based configuration
        const data = await _fs.readFile(_configFilename, 'utf8');

        if (data.length > 10){
            // decode json based data
            configFile = JSON.parse(data);
            _logger.log('Project based configuration loaded');
        }
    }

    // generated config
    const config = {};

    // utility function to merge different options
    // cli args take presendence over config
    function mergeOptions(...opt){
        // extract default (last argument)
        const result = opt.pop();

        // try to find first match
        while (opt.length > 0){
            // extract first argument (priority)
            const o = opt.shift();

            // value set ?
            if (typeof o !== 'undefined' && o !== null){
                return o;
            }
        }

        return result;
    }

    // merge global flags, command flags and global defaults
    // config file + cli args
    config.baudrate =        mergeOptions(options.parent.baud, configFile.baudrate, '115200');
    config.port =           mergeOptions(options.parent.port, configFile.port, '/dev/ttyUSB0');
    config.connectionDelay = mergeOptions(options.parent.connectionDelay, configFile.connectionDelay, 0);
    config.minify =         mergeOptions(options.minify, configFile.minify, false);
    config.compile =        mergeOptions(options.compile, configFile.compile, false);
    config.keeppath =       mergeOptions(options.keeppath, configFile.keeppath, false);

    // CLI args only
    config.remotename =     mergeOptions(options.remotename, null);
    config.run =            mergeOptions(options.run, false);
    config.all =            mergeOptions(options.all, false);
    config.json =           mergeOptions(options.json, false);
    config.raw =            mergeOptions(options.raw, false);
    config.softreset =      mergeOptions(options.softreset, false);

    // set port/baud options
    _nodemcutool.setOptions({
        device:             config.port,
        baudrate:           config.baudrate,
        connectionDelay:    config.connectionDelay
    });

    return config;
}

// write options to file
async function storeOptions(options){
    await _fs.writeFile(_configFilename, JSON.stringify(options, null, 4));
}

module.exports = {
    parse: parseOptions,
    store: storeOptions
};<|endoftext|>


<commit_before>'use strict';

var assert = require('assert')
  , Grid = require('../lib/grid');

describe('Grid', function() {
  var gridDimensions = 32;
  describe('constructor', function() {
    it('should instantiate a new grid', function() {
      var grid = new Grid(gridDimensions);
      assert(grid instanceof Grid);
    });

    it('should create a 2d array representing the grid', function() {
      var grid = new Grid(gridDimensions);
      assert(grid.gridMatrix instanceof Array);
      assert(grid.gridMatrix.length === gridDimensions);
      assert(grid.gridMatrix[0].length === gridDimensions);
    });
  });
});
<commit_msg>added a test for redis but it doesn't work yet...<commit_after>'use strict';

var assert = require('assert')
  , Grid = require('../lib/grid')
  , redis = require('redis');

describe('Grid', function() {
  var gridDimensions = 32;
  var redisClient = redis.createClient();
  redisClient.select(15);

  beforeEach(function() {
    redisClient.flushdb();
  });

  describe('constructor', function() {
    it('should instantiate a new grid', function() {
      var grid = new Grid(gridDimensions, redisClient);
      assert(grid instanceof Grid);
    });

    it('should create a 2d array representing the grid', function() {
      var grid = new Grid(gridDimensions, redisClient);
      assert(grid.gridMatrix instanceof Array);
      assert(grid.gridMatrix.length === gridDimensions);
      assert(grid.gridMatrix[0].length === gridDimensions);
    });

    it('should set a flag that indicates redis is now saving the grid', function() {
      redisClient.get('gridSaved', function(err, reply) {
        assert(!reply);
      });
      var grid = new Grid(gridDimensions, redisClient);
      redisClient.get('gridSaved', function(err, reply) {
        assert(reply);
      });
    });
  });
});
<|endoftext|>


<commit_before>import 'systemjs-hmr'
import io from 'socket.io-client'

import {reloadStore, runOnce} from './acrossReload.js'

let socket = null

const connect = (port) => {

    if (socket == null) {

        socket = io("//" + window.location.hostname + ":" + port)

        socket.on('connect', () => {
            socket.emit('identification', navigator.userAgent)
        })

        socket.on('reload', () => {
            document.location.reload(true)
        })

        socket.on('change', (event) => {
            System.reload(event.path)
        })

    }
}

const defaultOptions = {
    port: 1337
}

const devtools = (opts = {}) => {
    const options = Object.assign({}, defaultOptions, opts)

    connect(options.port)
}

export {reloadStore, runOnce, devtools}
<commit_msg>Explicitely load https socket<commit_after>import 'systemjs-hmr'
import io from 'socket.io-client'

import {reloadStore, runOnce} from './acrossReload.js'

let socket = null

const connect = (port) => {

    if (socket == null) {

        socket = io("https://" + window.location.hostname + ":" + port)

        socket.on('connect', () => {
            socket.emit('identification', navigator.userAgent)
        })

        socket.on('reload', () => {
            document.location.reload(true)
        })

        socket.on('change', (event) => {
            System.reload(event.path)
        })

    }
}

const defaultOptions = {
    port: 1337
}

const devtools = (opts = {}) => {
    const options = Object.assign({}, defaultOptions, opts)

    connect(options.port)
}

export {reloadStore, runOnce, devtools}
<|endoftext|>


<commit_before>define([
    'require',
    'flight/lib/component',
    '../withDropdown',
    'tpl!./propForm',
    'fields/selection/selection',
    'tpl!util/alert',
    'util/withTeardown',
    'util/vertex/formatters',
    'util/withDataRequest'
], function(
    require,
    defineComponent,
    withDropdown,
    template,
    FieldSelection,
    alertTemplate,
    withTeardown,
    F,
    withDataRequest
) {
    'use strict';

        // Animates the property value to the justification reference on paste if false
    var SKIP_SELECTION_ANIMATION = true;

    return defineComponent(PropertyForm, withDropdown, withTeardown, withDataRequest);

    function PropertyForm() {

        this.defaultAttrs({
            propertyListSelector: '.property-list',
            saveButtonSelector: '.btn-primary',
            deleteButtonSelector: '.btn-danger',
            configurationSelector: '.configuration',
            configurationFieldSelector: '.configuration input',
            previousValuesSelector: '.previous-values',
            previousValuesDropdownSelector: '.previous-values-container .dropdown-menu',
            visibilitySelector: '.visibility',
            justificationSelector: '.justification',
            propertyInputSelector: '.input-row input',
            visibilityInputSelector: '.visibility input'
        });

        this.before('initialize', function(n, c) {
            if (c.property) {
                c.manualOpen = true;
            }
        })

        this.after('initialize', function() {
            var self = this,
                vertex = this.attr.data;

            this.on('click', {
                saveButtonSelector: this.onSave,
                deleteButtonSelector: this.onDelete,
                previousValuesSelector: this.onPreviousValuesButtons
            });
            this.on('keyup', {
                propertyInputSelector: this.onKeyup,
                justificationSelector: this.onKeyup,
                visibilityInputSelector: this.onKeyup
            });

            this.on('propertyerror', this.onPropertyError);
            this.on('propertychange', this.onPropertyChange);
            this.on('propertyinvalid', this.onPropertyInvalid);
            this.on('propertyselected', this.onPropertySelected);
            this.on('visibilitychange', this.onVisibilityChange);
            this.on('justificationchange', this.onJustificationChange);
            this.on('justificationfrompaste', this.onJustificationFromPaste);
            this.on('paste', {
                configurationFieldSelector: _.debounce(this.onPaste.bind(this), 10)
            });
            this.on('click', {
                previousValuesDropdownSelector: this.onPreviousValuesDropdown
            });
            this.$node.html(template({
                property: this.attr.property
            }));

            self.select('saveButtonSelector').attr('disabled', true);
            self.select('deleteButtonSelector').hide();
            self.select('saveButtonSelector').hide();

            if (this.attr.property) {
                this.trigger('propertyselected', {
                    disablePreviousValuePrompt: true,
                    property: _.chain(this.attr.property)
                        .pick('displayName key name value visibility metadata'.split(' '))
                        .extend({
                            title: this.attr.property.name
                        })
                        .value()
                });
            } else if (F.vertex.isEdge(this.attr.data)) {
                throw new Error('Property form not supported for edges');
            } else {
                this.dataRequest('ontology', 'propertiesByConceptId', F.vertex.prop(vertex, 'conceptType'))
                    .done(function(properties) {
                        var propertiesList = [];

                        properties.list.forEach(function(property) {
                            if (property.userVisible) {
                                propertiesList.push(_.pick(property, 'displayName', 'title', 'userVisible'));
                            }
                        });

                        FieldSelection.attachTo(self.select('propertyListSelector'), {
                            properties: propertiesList,
                            placeholder: i18n('property.form.field.selection.placeholder')
                        });
                    });
            }
        });

        this.after('teardown', function() {
            this.select('visibilitySelector').teardownAllComponents();

            if (this.$node.closest('.buttons').length === 0) {
                this.$node.closest('tr').remove();
            }
        });

        this.onPaste = function(event) {
            var self = this,
                value = $(event.target).val();

            _.defer(function() {
                self.trigger(
                    self.select('justificationSelector'),
                    'valuepasted',
                    { value: value }
                );
            });
        };

        this.onPreviousValuesButtons = function(event) {
            var dropdown = this.select('previousValuesDropdownSelector'),
                buttons = this.select('previousValuesSelector').find('.active').removeClass('active'),
                action = $(event.target).closest('button').addClass('active').data('action');

            if (action === 'add') {
                dropdown.hide();
                this.trigger('propertyselected', {
                    fromPreviousValuePrompt: true,
                    property: _.omit(this.currentProperty, 'value', 'key')
                });
            } else if (this.previousValues.length > 1) {
                this.trigger('propertyselected', {
                    property: _.omit(this.currentProperty, 'value', 'key')
                });

                dropdown.html(
                        this.previousValues.map(function(p, i) {
                            var visibility = p['http://lumify.io#visibilityJson'];
                            return _.template(
                                '
' +
                                    '{value}' +
                                        '
' +
                                    '' +
                                '
')({
                                value: F.vertex.displayProp(p),
                                visibilityJson: JSON.stringify(visibility || {}),
                                i: i
                            });
                        }).join('')
                    ).show();

                require(['configuration/plugins/visibility/visibilityDisplay'], function(Visibility) {
                    dropdown.find('.visibility').each(function() {
                        var value = $(this).data('visibility');
                        Visibility.attachTo(this, {
                            value: value && value.source
                        });
                    });
                });

            } else {
                dropdown.hide();
                this.trigger('propertyselected', {
                    fromPreviousValuePrompt: true,
                    property: $.extend({}, this.currentProperty, this.previousValues[0])
                });
            }
        };

        this.onPreviousValuesDropdown = function(event) {
            var li = $(event.target).closest('li');
                index = li.data('index');

            this.$node.find('.previous-values .edit-previous').addClass('active');
            this.trigger('propertyselected', {
                fromPreviousValuePrompt: true,
                property: $.extend({}, this.currentProperty, this.previousValues[index])
            });
        };

        this.onPropertySelected = function(event, data) {
            var self = this,
                property = data.property,
                disablePreviousValuePrompt = data.disablePreviousValuePrompt,
                propertyName = property.title,
                config = self.select('configurationSelector'),
                visibility = self.select('visibilitySelector'),
                justification = self.select('justificationSelector');

            this.currentProperty = property;
            this.$node.find('.errors').hide();

            config.teardownAllComponents();
            visibility.teardownAllComponents();
            justification.teardownAllComponents();

            var vertexProperty = property.key || property.key === '' ?
                    F.vertex.propForNameAndKey(this.attr.data, property.name, property.key) : undefined,
                previousValue = vertexProperty && (vertexProperty.latitude ? vertexProperty : vertexProperty.value),
                visibilityValue = vertexProperty && vertexProperty['http://lumify.io#visibilityJson'],
                sandboxStatus = vertexProperty && vertexProperty.sandboxStatus,
                isExistingProperty = typeof vertexProperty !== 'undefined',
                previousValues = disablePreviousValuePrompt !== true && F.vertex.props(this.attr.data, propertyName);

            this.currentValue = previousValue;
            if (this.currentValue && this.currentValue.latitude) {
                this.currentValue = 'point(' + this.currentValue.latitude + ',' + this.currentValue.longitude + ')';
            }

            if (visibilityValue) {
                visibilityValue = visibilityValue.source;
                this.visibilitySource = { value: visibilityValue, valid: true };
            }

            if (property.name === 'http://lumify.io#visibilityJson') {
                vertexProperty = property;
                isExistingProperty = true;
                previousValues = null;
            }

            if (data.fromPreviousValuePrompt !== true) {
                previousValues = _.reject(previousValues, function(prevVal) {
                    return prevVal.sandboxStatus === 'PUBLIC';
                });

                if (previousValues && previousValues.length) {
                    this.previousValues = previousValues;
                    this.select('previousValuesSelector')
                        .show()
                        .find('.active').removeClass('active')
                        .addBack()
                        .find('.edit-previous span').text(previousValues.length)
                        .addBack()
                        .find('.edit-previous small').toggle(previousValues.length > 1);

                    this.select('justificationSelector').hide();
                    this.select('visibilitySelector').hide();
                    this.select('saveButtonSelector').hide();
                    this.select('previousValuesDropdownSelector').hide();

                    return;
                } else {
                    this.select('previousValuesSelector').hide();
                }
            }

            this.select('previousValuesDropdownSelector').hide();
            this.select('justificationSelector').show();
            this.select('visibilitySelector').show();
            this.select('saveButtonSelector').show();

            this.select('deleteButtonSelector')
                .text(
                    sandboxStatus === 'PRIVATE' ?  i18n('property.form.button.delete') :
                    sandboxStatus === 'PUBLIC_CHANGED' ?  i18n('property.form.button.undo') : ''
                )
                .toggle(
                    (!!isExistingProperty) &&
                    sandboxStatus !== 'PUBLIC' &&
                    propertyName !== 'http://lumify.io#visibilityJson'
                );

            var button = this.select('saveButtonSelector')
                .text(isExistingProperty ? i18n('property.form.button.update') : i18n('property.form.button.add'));
            if (isExistingProperty) {
                button.removeAttr('disabled');
            } else {
                button.attr('disabled', true);
            }

            this.dataRequest('ontology', 'properties').done(function(properties) {
                var propertyDetails = properties.byTitle[propertyName];
                if (propertyName === 'http://lumify.io#visibilityJson') {
                    require([
                        'configuration/plugins/visibility/visibilityEditor'
                    ], function(Visibility) {
                        var val = vertexProperty && vertexProperty.value,
                            source = (val && val.source) || (val && val.value && val.value.source);

                        Visibility.attachTo(visibility, {
                            value: source || ''
                        });
                        visibility.find('input').focus();
                        self.settingVisibility = true;
                        self.visibilitySource = { value: source, valid: true };

                        self.checkValid();
                        self.manualOpen();
                    });
                } else if (propertyDetails) {
                    require([
                        (
                            propertyDetails.possibleValues ?
                                'fields/restrictValues' :
                                'fields/' + propertyDetails.dataType
                        ),
                        'detail/dropdowns/propertyForm/justification',
                        'configuration/plugins/visibility/visibilityEditor'
                    ], function(PropertyField, Justification, Visibility) {

                        PropertyField.attachTo(config, {
                            property: propertyDetails,
                            vertexProperty: vertexProperty,
                            value: previousValue,
                            predicates: false,
                            tooltip: {
                                html: true,
                                title:
                                    '' +
                                    i18n('justification.field.tooltip.title') +
                                    '
' +
                                    i18n('justification.field.tooltip.subtitle'),
                                placement: 'left',
                                trigger: 'focus'
                            }
                        });

                        Justification.attachTo(justification, vertexProperty);

                        Visibility.attachTo(visibility, {
                            value: visibilityValue || ''
                        });

                        self.settingVisibility = false;
                        self.checkValid();
                        self.manualOpen();
                    });
                } else console.warn('Property ' + propertyName + ' not found in ontology');
            });
        };

        this.onVisibilityChange = function(event, data) {
            this.visibilitySource = data;
            this.checkValid();
        };

        this.onJustificationChange = function(event, data) {
            this.justification = data;
            this.checkValid();
        };

        this.onJustificationFromPaste = function(event, data) {
            var justification = this.select('justificationSelector'),
                configuration = this.select('configurationSelector'),
                selection = justification.find('.selection'),
                clonedSelection = selection.clone(),
                popSnippet = function() {
                    selection.closest('.animationwrap').removeClass('pop-fast').addClass('pop-fast');
                };

            if (!clonedSelection.length) return;

            // More than number of words shouldn't animate, just pop text
            if (SKIP_SELECTION_ANIMATION || selection.text().split(/\s+/).length > 3) {
                return popSnippet();
            }

            configuration.find('.input-row input').after(clonedSelection);

            var position = selection.position(),
                clonedPosition = clonedSelection.position(),
                clonedMarginLeft = parseInt(clonedSelection.css('left'), 10);

            clonedSelection.one(TRANSITION_END, function() {
                    clonedSelection.remove();
                    popSnippet();
                }).css({
                    textIndent: (selection.get(0).offsetLeft - clonedMarginLeft) + 'px',
                    marginTop: -1 * (clonedPosition.top - position.top) + 'px'
                });
        };

        this.onPropertyInvalid = function(event, data) {
            event.stopPropagation();

            this.propertyInvalid = true;
            this.checkValid();
        };

        this.checkValid = function() {
            if (this.settingVisibility) {
                this.valid = this.visibilitySource && this.visibilitySource.valid;
            } else {
                this.valid = !this.propertyInvalid &&
                    (this.visibilitySource && this.visibilitySource.valid) &&
                    (this.justification && this.justification.valid);
            }

            if (this.valid) {
                this.select('saveButtonSelector').removeAttr('disabled');
            } else {
                this.select('saveButtonSelector').attr('disabled', true);
            }
        }

        this.onPropertyChange = function(event, data) {
            this.propertyInvalid = false;
            this.checkValid();

            event.stopPropagation();

            if (data.values.length === 1) {
                this.currentValue = data.values[0];
            } else if (data.values.length === 2) {
                // Must be geoLocation
                this.currentValue = 'point(' + data.values.join(',') + ')';
            } else if (data.values.length === 3) {
                this.currentValue = JSON.stringify({
                    description: data.values[0],
                    latitude: data.values[1],
                    longitude: data.values[2]
                });
            }

            this.currentMetadata = data.metadata;
        };

        this.onPropertyError = function(event, data) {
            var messages = this.markFieldErrors(data.error);

            this.$node.find('.errors').html(
                alertTemplate({
                    error: messages
                })
            ).show();
            _.defer(this.clearLoading.bind(this));
        };

        this.onKeyup = function(evt) {
            if (evt.which === $.ui.keyCode.ENTER) {
                this.onSave();
            }
        };

        this.onDelete = function() {
            _.defer(this.buttonLoading.bind(this, this.attr.deleteButtonSelector));
            this.trigger('deleteProperty', {
                property: _.pick(this.currentProperty, 'key', 'name')
            });
        };

        this.onSave = function(evt) {
            if (!this.valid) return;

            var vertexId = this.attr.data.id,
                propertyKey = this.currentProperty.key,
                propertyName = this.currentProperty.title,
                value = this.currentValue,
                justification = _.pick(this.justification || {}, 'sourceInfo', 'justificationText');

            _.defer(this.buttonLoading.bind(this, this.attr.saveButtonSelector));

            this.$node.find('input').tooltip('hide')

            this.$node.find('.errors').hide();
            if (propertyName.length &&
                (this.settingVisibility ||
                 (((_.isString(value) && value.length) || value)))) {

                this.trigger('addProperty', {
                    isEdge: F.vertex.isEdge (this.attr.data),
                    property: $.extend({
                            key: propertyKey,
                            name: propertyName,
                            value: value,
                            visibilitySource: this.visibilitySource.value,
                            metadata: this.currentMetadata
                        }, justification)
                });
            }
        };
    }
});
<commit_msg>Allow deletion of public properties in UI<commit_after>define([
    'require',
    'flight/lib/component',
    '../withDropdown',
    'tpl!./propForm',
    'fields/selection/selection',
    'tpl!util/alert',
    'util/withTeardown',
    'util/vertex/formatters',
    'util/withDataRequest'
], function(
    require,
    defineComponent,
    withDropdown,
    template,
    FieldSelection,
    alertTemplate,
    withTeardown,
    F,
    withDataRequest
) {
    'use strict';

        // Animates the property value to the justification reference on paste if false
    var SKIP_SELECTION_ANIMATION = true;

    return defineComponent(PropertyForm, withDropdown, withTeardown, withDataRequest);

    function PropertyForm() {

        this.defaultAttrs({
            propertyListSelector: '.property-list',
            saveButtonSelector: '.btn-primary',
            deleteButtonSelector: '.btn-danger',
            configurationSelector: '.configuration',
            configurationFieldSelector: '.configuration input',
            previousValuesSelector: '.previous-values',
            previousValuesDropdownSelector: '.previous-values-container .dropdown-menu',
            visibilitySelector: '.visibility',
            justificationSelector: '.justification',
            propertyInputSelector: '.input-row input',
            visibilityInputSelector: '.visibility input'
        });

        this.before('initialize', function(n, c) {
            if (c.property) {
                c.manualOpen = true;
            }
        })

        this.after('initialize', function() {
            var self = this,
                vertex = this.attr.data;

            this.on('click', {
                saveButtonSelector: this.onSave,
                deleteButtonSelector: this.onDelete,
                previousValuesSelector: this.onPreviousValuesButtons
            });
            this.on('keyup', {
                propertyInputSelector: this.onKeyup,
                justificationSelector: this.onKeyup,
                visibilityInputSelector: this.onKeyup
            });

            this.on('propertyerror', this.onPropertyError);
            this.on('propertychange', this.onPropertyChange);
            this.on('propertyinvalid', this.onPropertyInvalid);
            this.on('propertyselected', this.onPropertySelected);
            this.on('visibilitychange', this.onVisibilityChange);
            this.on('justificationchange', this.onJustificationChange);
            this.on('justificationfrompaste', this.onJustificationFromPaste);
            this.on('paste', {
                configurationFieldSelector: _.debounce(this.onPaste.bind(this), 10)
            });
            this.on('click', {
                previousValuesDropdownSelector: this.onPreviousValuesDropdown
            });
            this.$node.html(template({
                property: this.attr.property
            }));

            self.select('saveButtonSelector').attr('disabled', true);
            self.select('deleteButtonSelector').hide();
            self.select('saveButtonSelector').hide();

            if (this.attr.property) {
                this.trigger('propertyselected', {
                    disablePreviousValuePrompt: true,
                    property: _.chain(this.attr.property)
                        .pick('displayName key name value visibility metadata'.split(' '))
                        .extend({
                            title: this.attr.property.name
                        })
                        .value()
                });
            } else if (F.vertex.isEdge(this.attr.data)) {
                throw new Error('Property form not supported for edges');
            } else {
                this.dataRequest('ontology', 'propertiesByConceptId', F.vertex.prop(vertex, 'conceptType'))
                    .done(function(properties) {
                        var propertiesList = [];

                        properties.list.forEach(function(property) {
                            if (property.userVisible) {
                                propertiesList.push(_.pick(property, 'displayName', 'title', 'userVisible'));
                            }
                        });

                        FieldSelection.attachTo(self.select('propertyListSelector'), {
                            properties: propertiesList,
                            placeholder: i18n('property.form.field.selection.placeholder')
                        });
                    });
            }
        });

        this.after('teardown', function() {
            this.select('visibilitySelector').teardownAllComponents();

            if (this.$node.closest('.buttons').length === 0) {
                this.$node.closest('tr').remove();
            }
        });

        this.onPaste = function(event) {
            var self = this,
                value = $(event.target).val();

            _.defer(function() {
                self.trigger(
                    self.select('justificationSelector'),
                    'valuepasted',
                    { value: value }
                );
            });
        };

        this.onPreviousValuesButtons = function(event) {
            var dropdown = this.select('previousValuesDropdownSelector'),
                buttons = this.select('previousValuesSelector').find('.active').removeClass('active'),
                action = $(event.target).closest('button').addClass('active').data('action');

            if (action === 'add') {
                dropdown.hide();
                this.trigger('propertyselected', {
                    fromPreviousValuePrompt: true,
                    property: _.omit(this.currentProperty, 'value', 'key')
                });
            } else if (this.previousValues.length > 1) {
                this.trigger('propertyselected', {
                    property: _.omit(this.currentProperty, 'value', 'key')
                });

                dropdown.html(
                        this.previousValues.map(function(p, i) {
                            var visibility = p['http://lumify.io#visibilityJson'];
                            return _.template(
                                '
' +
                                    '{value}' +
                                        '
' +
                                    '' +
                                '
')({
                                value: F.vertex.displayProp(p),
                                visibilityJson: JSON.stringify(visibility || {}),
                                i: i
                            });
                        }).join('')
                    ).show();

                require(['configuration/plugins/visibility/visibilityDisplay'], function(Visibility) {
                    dropdown.find('.visibility').each(function() {
                        var value = $(this).data('visibility');
                        Visibility.attachTo(this, {
                            value: value && value.source
                        });
                    });
                });

            } else {
                dropdown.hide();
                this.trigger('propertyselected', {
                    fromPreviousValuePrompt: true,
                    property: $.extend({}, this.currentProperty, this.previousValues[0])
                });
            }
        };

        this.onPreviousValuesDropdown = function(event) {
            var li = $(event.target).closest('li');
                index = li.data('index');

            this.$node.find('.previous-values .edit-previous').addClass('active');
            this.trigger('propertyselected', {
                fromPreviousValuePrompt: true,
                property: $.extend({}, this.currentProperty, this.previousValues[index])
            });
        };

        this.onPropertySelected = function(event, data) {
            var self = this,
                property = data.property,
                disablePreviousValuePrompt = data.disablePreviousValuePrompt,
                propertyName = property.title,
                config = self.select('configurationSelector'),
                visibility = self.select('visibilitySelector'),
                justification = self.select('justificationSelector');

            this.currentProperty = property;
            this.$node.find('.errors').hide();

            config.teardownAllComponents();
            visibility.teardownAllComponents();
            justification.teardownAllComponents();

            var vertexProperty = property.key || property.key === '' ?
                    F.vertex.propForNameAndKey(this.attr.data, property.name, property.key) : undefined,
                previousValue = vertexProperty && (vertexProperty.latitude ? vertexProperty : vertexProperty.value),
                visibilityValue = vertexProperty && vertexProperty['http://lumify.io#visibilityJson'],
                sandboxStatus = vertexProperty && vertexProperty.sandboxStatus,
                isExistingProperty = typeof vertexProperty !== 'undefined',
                previousValues = disablePreviousValuePrompt !== true && F.vertex.props(this.attr.data, propertyName);

            this.currentValue = previousValue;
            if (this.currentValue && this.currentValue.latitude) {
                this.currentValue = 'point(' + this.currentValue.latitude + ',' + this.currentValue.longitude + ')';
            }

            if (visibilityValue) {
                visibilityValue = visibilityValue.source;
                this.visibilitySource = { value: visibilityValue, valid: true };
            }

            if (property.name === 'http://lumify.io#visibilityJson') {
                vertexProperty = property;
                isExistingProperty = true;
                previousValues = null;
            }

            if (data.fromPreviousValuePrompt !== true) {
                if (previousValues && previousValues.length) {
                    this.previousValues = previousValues;
                    this.select('previousValuesSelector')
                        .show()
                        .find('.active').removeClass('active')
                        .addBack()
                        .find('.edit-previous span').text(previousValues.length)
                        .addBack()
                        .find('.edit-previous small').toggle(previousValues.length > 1);

                    this.select('justificationSelector').hide();
                    this.select('visibilitySelector').hide();
                    this.select('saveButtonSelector').hide();
                    this.select('previousValuesDropdownSelector').hide();

                    return;
                } else {
                    this.select('previousValuesSelector').hide();
                }
            }

            this.select('previousValuesDropdownSelector').hide();
            this.select('justificationSelector').show();
            this.select('visibilitySelector').show();
            this.select('saveButtonSelector').show();

            this.select('deleteButtonSelector')
                .text(
                    sandboxStatus === 'PUBLIC_CHANGED' ?
                    i18n('property.form.button.undo') :
                    i18n('property.form.button.delete')
                )
                .toggle(
                    (!!isExistingProperty) &&
                    propertyName !== 'http://lumify.io#visibilityJson'
                );

            var button = this.select('saveButtonSelector')
                .text(isExistingProperty ? i18n('property.form.button.update') : i18n('property.form.button.add'));
            if (isExistingProperty) {
                button.removeAttr('disabled');
            } else {
                button.attr('disabled', true);
            }

            this.dataRequest('ontology', 'properties').done(function(properties) {
                var propertyDetails = properties.byTitle[propertyName];
                if (propertyName === 'http://lumify.io#visibilityJson') {
                    require([
                        'configuration/plugins/visibility/visibilityEditor'
                    ], function(Visibility) {
                        var val = vertexProperty && vertexProperty.value,
                            source = (val && val.source) || (val && val.value && val.value.source);

                        Visibility.attachTo(visibility, {
                            value: source || ''
                        });
                        visibility.find('input').focus();
                        self.settingVisibility = true;
                        self.visibilitySource = { value: source, valid: true };

                        self.checkValid();
                        self.manualOpen();
                    });
                } else if (propertyDetails) {
                    require([
                        (
                            propertyDetails.possibleValues ?
                                'fields/restrictValues' :
                                'fields/' + propertyDetails.dataType
                        ),
                        'detail/dropdowns/propertyForm/justification',
                        'configuration/plugins/visibility/visibilityEditor'
                    ], function(PropertyField, Justification, Visibility) {

                        PropertyField.attachTo(config, {
                            property: propertyDetails,
                            vertexProperty: vertexProperty,
                            value: previousValue,
                            predicates: false,
                            tooltip: {
                                html: true,
                                title:
                                    '' +
                                    i18n('justification.field.tooltip.title') +
                                    '
' +
                                    i18n('justification.field.tooltip.subtitle'),
                                placement: 'left',
                                trigger: 'focus'
                            }
                        });

                        Justification.attachTo(justification, vertexProperty);

                        Visibility.attachTo(visibility, {
                            value: visibilityValue || ''
                        });

                        self.settingVisibility = false;
                        self.checkValid();
                        self.manualOpen();
                    });
                } else console.warn('Property ' + propertyName + ' not found in ontology');
            });
        };

        this.onVisibilityChange = function(event, data) {
            this.visibilitySource = data;
            this.checkValid();
        };

        this.onJustificationChange = function(event, data) {
            this.justification = data;
            this.checkValid();
        };

        this.onJustificationFromPaste = function(event, data) {
            var justification = this.select('justificationSelector'),
                configuration = this.select('configurationSelector'),
                selection = justification.find('.selection'),
                clonedSelection = selection.clone(),
                popSnippet = function() {
                    selection.closest('.animationwrap').removeClass('pop-fast').addClass('pop-fast');
                };

            if (!clonedSelection.length) return;

            // More than number of words shouldn't animate, just pop text
            if (SKIP_SELECTION_ANIMATION || selection.text().split(/\s+/).length > 3) {
                return popSnippet();
            }

            configuration.find('.input-row input').after(clonedSelection);

            var position = selection.position(),
                clonedPosition = clonedSelection.position(),
                clonedMarginLeft = parseInt(clonedSelection.css('left'), 10);

            clonedSelection.one(TRANSITION_END, function() {
                    clonedSelection.remove();
                    popSnippet();
                }).css({
                    textIndent: (selection.get(0).offsetLeft - clonedMarginLeft) + 'px',
                    marginTop: -1 * (clonedPosition.top - position.top) + 'px'
                });
        };

        this.onPropertyInvalid = function(event, data) {
            event.stopPropagation();

            this.propertyInvalid = true;
            this.checkValid();
        };

        this.checkValid = function() {
            if (this.settingVisibility) {
                this.valid = this.visibilitySource && this.visibilitySource.valid;
            } else {
                this.valid = !this.propertyInvalid &&
                    (this.visibilitySource && this.visibilitySource.valid) &&
                    (this.justification && this.justification.valid);
            }

            if (this.valid) {
                this.select('saveButtonSelector').removeAttr('disabled');
            } else {
                this.select('saveButtonSelector').attr('disabled', true);
            }
        }

        this.onPropertyChange = function(event, data) {
            this.propertyInvalid = false;
            this.checkValid();

            event.stopPropagation();

            if (data.values.length === 1) {
                this.currentValue = data.values[0];
            } else if (data.values.length === 2) {
                // Must be geoLocation
                this.currentValue = 'point(' + data.values.join(',') + ')';
            } else if (data.values.length === 3) {
                this.currentValue = JSON.stringify({
                    description: data.values[0],
                    latitude: data.values[1],
                    longitude: data.values[2]
                });
            }

            this.currentMetadata = data.metadata;
        };

        this.onPropertyError = function(event, data) {
            var messages = this.markFieldErrors(data.error);

            this.$node.find('.errors').html(
                alertTemplate({
                    error: messages
                })
            ).show();
            _.defer(this.clearLoading.bind(this));
        };

        this.onKeyup = function(evt) {
            if (evt.which === $.ui.keyCode.ENTER) {
                this.onSave();
            }
        };

        this.onDelete = function() {
            _.defer(this.buttonLoading.bind(this, this.attr.deleteButtonSelector));
            this.trigger('deleteProperty', {
                property: _.pick(this.currentProperty, 'key', 'name')
            });
        };

        this.onSave = function(evt) {
            if (!this.valid) return;

            var vertexId = this.attr.data.id,
                propertyKey = this.currentProperty.key,
                propertyName = this.currentProperty.title,
                value = this.currentValue,
                justification = _.pick(this.justification || {}, 'sourceInfo', 'justificationText');

            _.defer(this.buttonLoading.bind(this, this.attr.saveButtonSelector));

            this.$node.find('input').tooltip('hide')

            this.$node.find('.errors').hide();
            if (propertyName.length &&
                (this.settingVisibility ||
                 (((_.isString(value) && value.length) || value)))) {

                this.trigger('addProperty', {
                    isEdge: F.vertex.isEdge (this.attr.data),
                    property: $.extend({
                            key: propertyKey,
                            name: propertyName,
                            value: value,
                            visibilitySource: this.visibilitySource.value,
                            metadata: this.currentMetadata
                        }, justification)
                });
            }
        };
    }
});
<|endoftext|>


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

/**
 * @fileoverview Tests for gulp-google-closure-compiler plugin
 *
 * @author Chad Killingsworth (chadkillingsworth@gmail.com)
 */

'use strict';

const assert = require('stream-assert');
const should = require('should');
const gulp = require('gulp');
const sourcemaps = require('gulp-sourcemaps');
const File = require('vinyl');
const compilerPackage = require('../');
const ClosureCompiler = require('../lib/node/closure-compiler');
const JsClosureCompiler = require('../lib/node/closure-compiler-js');

require('mocha');

process.on('unhandledRejection', e => { throw e; });

describe('gulp-google-closure-compiler', function() {
  let originalCompilerRunMethod;
  let originalJsCompilerRunMethod;
  let platformUtilized;

  before(() => {
    originalCompilerRunMethod = Object.getOwnPropertyDescriptor(ClosureCompiler.prototype, 'run');
    Object.defineProperty(ClosureCompiler.prototype, 'run', {
      value: function(...args) {
        const retVal = originalCompilerRunMethod.value.apply(this, args);
        platformUtilized = /^java/.test(this.getFullCommand()) ? 'java' : 'native';
        return retVal;
      },
      writable: true,
      enumerable: false,
      configurable: true
    });

    originalJsCompilerRunMethod = Object.getOwnPropertyDescriptor(JsClosureCompiler.prototype, 'run');
    Object.defineProperty(JsClosureCompiler.prototype, 'run', {
      value: function(...args) {
        platformUtilized = 'javascript';
        return originalJsCompilerRunMethod.value.apply(this, args);
      },
      writable: true,
      enumerable: false,
      configurable: true
    });
  });

  after(() => {
    Object.defineProperty(ClosureCompiler.prototype, 'run', originalCompilerRunMethod);
    Object.defineProperty(JsClosureCompiler.prototype, 'run', originalJsCompilerRunMethod);
  });

  ['java', 'native', 'javascript'].forEach(platform => {
    describe(`${platform} version`, function() {
      const closureCompiler = compilerPackage.gulp();

      this.timeout(30000);
      this.slow(10000);

      const fakeFile1 = new File({
        path: '/foo.js',
        contents: new Buffer('console.log("foo");')
      });
      const fakeFile2 = new File({
        path: '/bar.js',
        contents: new Buffer('console.log("bar");')
      });

      const fixturesCompiled = 'function log(a){console.log(a)}log("one.js");' +
          'var WindowInfo=function(){this.props=[]};WindowInfo.prototype.propList=function(){' +
          'for(var a in window)this.props.push(a)};WindowInfo.prototype.list=function(){' +
          'log(this.props.join(", "))};(new WindowInfo).list();\n';

      afterEach(() => {
        if (platformUtilized) {
          should.equal(platform, platformUtilized);
        }
        platformUtilized = undefined;
      });

      it('should emit an error for invalid options', done => {
        const stream = closureCompiler({
          compilation_level: 'FOO'
        }, {
          platform
        });

        stream.on('error', err => {
          err.message.should.startWith('Compilation error');
          done();
        });
        stream.write(fakeFile1);
        stream.end();
      });

      it('should compile a single file', done => {
        const stream = closureCompiler({
          compilation_level: 'SIMPLE',
          warning_level: 'VERBOSE'
        }, {
          platform
        });

        stream.pipe(assert.length(1))
          .pipe(assert.first(f => {
            f.contents.toString().trim().should.eql(fakeFile1.contents.toString());
          }))
          .pipe(assert.end(done));

        stream.write(fakeFile1);
        stream.end();
      });

      it('should name the output file when no js_output_file option is provided', done => {
        const stream = closureCompiler({
          compilation_level: 'SIMPLE',
          warning_level: 'VERBOSE'
        }, {
          platform
        });
        stream.pipe(assert.length(1))
          .pipe(assert.first(f => {
            f.path.should.eql('compiled.js');
          }))
          .pipe(assert.end(done));

        stream.write(fakeFile1);
        stream.end();
      });

      it('should name the output file from the js_output_file option', done => {
        const stream = closureCompiler({
          compilation_level: 'SIMPLE',
          warning_level: 'VERBOSE',
          js_output_file: 'out.js'
        }, {
          platform
        });
        stream.pipe(assert.length(1))
          .pipe(assert.first(f => {
            f.path.should.eql('out.js');
          }))
          .pipe(assert.end(done));

        stream.write(fakeFile1);
        stream.end();
      });

      it('should compile multiple input files into a single output', done => {
        const stream = closureCompiler({
          compilation_level: 'SIMPLE',
          warning_level: 'VERBOSE'
        }, {
          platform
        });

        stream.pipe(assert.length(1))
          .pipe(assert.first(f => {
            f.contents.toString().trim().should.eql(fakeFile1.contents.toString() +
                fakeFile2.contents.toString());
          }))
          .pipe(assert.end(done));

        stream.write(fakeFile1);
        stream.write(fakeFile2);
        stream.end();
      });

      if (platform !== 'javascript') {
        it('should compile multiple inputs into multiple outputs with chunk options', done => {
          const stream = closureCompiler({
            compilation_level: 'SIMPLE',
            warning_level: 'VERBOSE',
            chunk: [
              'one:1',
              'two:1'
            ],
            createSourceMap: true
          }, {
            platform
          });

          stream.pipe(assert.length(2))
              .pipe(assert.first(f => {
                f.contents.toString().trim().should.eql(fakeFile1.contents.toString());
                f.path.should.eql('one.js');
              }))
              .pipe(assert.second(f => {
                f.contents.toString().trim().should.eql(fakeFile2.contents.toString());
                f.path.should.eql('two.js');
              }))
              .pipe(assert.end(done));

          stream.write(fakeFile1);
          stream.write(fakeFile2);
          stream.end();
        });
      }

      it('should generate a sourcemap for a single output file', done => {
        gulp.src('test/fixtures/**/*.js', {base: './'})
          .pipe(sourcemaps.init())
          .pipe(closureCompiler({
            compilation_level: 'SIMPLE',
            warning_level: 'VERBOSE'
          }, {
            platform
          }))
          .pipe(assert.length(1))
          .pipe(assert.first(f => {
            f.sourceMap.sources.should.have.length(2);
            f.sourceMap.file.should.eql('compiled.js');
          }))
          .pipe(assert.end(done));
      });

      if (platform !== 'javascript') {
        it('should generate a sourcemap for each output file with chunks', done => {
          gulp.src([__dirname + '/fixtures/one.js', __dirname + '/fixtures/two.js'])
              .pipe(sourcemaps.init())
              .pipe(closureCompiler({
                compilation_level: 'SIMPLE',
                warning_level: 'VERBOSE',
                chunk: [
                  'one:1',
                  'two:1:one'
                ],
                createSourceMap: true
              }, {
                debugLog: true,
                platform
              }))
              .pipe(assert.length(2))
              .pipe(assert.first(f => {
                f.sourceMap.sources.should.have.length(1);
                f.sourceMap.file.should.eql('./one.js');
              }))
              .pipe(assert.second(f => {
                f.sourceMap.sources.should.have.length(1);
                f.sourceMap.file.should.eql('./two.js');
              }))
              .pipe(assert.end(done));
        });
      }

      if (platform !== 'javascript') {
        it('should support passing input globs directly to the compiler', done => {
          const stream = closureCompiler({
            js: __dirname + '/fixtures/**.js',
            compilation_level: 'SIMPLE',
            warning_level: 'VERBOSE'
          }, {
            platform
          })
            .src()
            .pipe(assert.length(1))
            .pipe(assert.first(f => {
              f.contents.toString().should.eql(fixturesCompiled);
            }))
            .pipe(assert.end(done));
        });

        it('should include js options before gulp.src files', done => {
          gulp.src(__dirname + '/fixtures/two.js')
            .pipe(closureCompiler({
              js: __dirname + '/fixtures/one.js',
              compilation_level: 'SIMPLE',
              warning_level: 'VERBOSE'
            }, {
              platform
            }))
            .pipe(assert.length(1))
            .pipe(assert.first(f => {
              f.contents.toString().should.eql(fixturesCompiled);
            }))
            .pipe(assert.end(done));
        });

        it('should support calling the compiler with an arguments array', done => {
          const stream = closureCompiler([
            '--js="' + __dirname + '/fixtures/**.js"',
            '--compilation_level=SIMPLE',
            '--warning_level=VERBOSE'
          ], {
            platform
          })
            .src()
            .pipe(assert.length(1))
            .pipe(assert.first(f => {
              f.contents.toString().should.eql(fixturesCompiled);
            }))
            .pipe(assert.end(done));
        });

        it('should compile without gulp.src files when .src() is called', done => {
          closureCompiler({
            compilation_level: 'SIMPLE',
            warning_level: 'VERBOSE',
            js: __dirname + '/fixtures/**.js'
          }, {
            platform
          })
            .src()
            .pipe(assert.length(1))
            .pipe(assert.first(f => {
              f.contents.toString().should.eql(fixturesCompiled);
            }))
            .pipe(assert.end(done));
        });
      }

      it('should generate no output without gulp.src files', done => {
        gulp.src([])
          .pipe(closureCompiler({
            compilation_level: 'SIMPLE',
            warning_level: 'VERBOSE'
          }, {
            platform
          }))
          .pipe(assert.length(0))
          .pipe(assert.end(done));
      });

      it('should properly compose sourcemaps when multiple transformations are chained', done => {
        gulp.src(['test/fixtures/one.js', 'test/fixtures/two.js'], {base: './'})
          .pipe(sourcemaps.init())
          .pipe(closureCompiler({
            compilation_level: 'WHITESPACE_ONLY',
            warning_level: 'VERBOSE',
            formatting: 'PRETTY_PRINT',
            sourceMapIncludeContent: true
          }, {
            platform
          }))
          .pipe(closureCompiler({
            compilation_level: 'SIMPLE',
            warning_level: 'QUIET',
            formatting: 'PRETTY_PRINT',
            js_output_file: 'final.js',
            sourceMapIncludeContent: true
          }, {
            platform
          }))
          .pipe(assert.first(f => {
            f.sourceMap.sources.should.containEql('test/fixtures/one.js');
            f.sourceMap.sources.should.containEql('test/fixtures/two.js');
          }))
          .pipe(assert.end(done))
          .on('error', err => {
            console.error(err);
          });
      });

      it('in streaming mode should emit an error', done => {
        gulp.src(__dirname + '/fixtures/**/*.js', {buffer: false})
          .pipe(closureCompiler({
            compilation_level: 'SIMPLE',
            warning_level: 'VERBOSE'
          }, {
            platform
          }))
          .on('error', err => {
            err.message.should.eql('Streaming not supported');
            done();
          });
      });
    });
  });
});
<commit_msg>Replace new Buffer() with Buffer.from()<commit_after>/*
 * Copyright 2015 The Closure Compiler Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview Tests for gulp-google-closure-compiler plugin
 *
 * @author Chad Killingsworth (chadkillingsworth@gmail.com)
 */

'use strict';

const assert = require('stream-assert');
const should = require('should');
const gulp = require('gulp');
const sourcemaps = require('gulp-sourcemaps');
const File = require('vinyl');
const compilerPackage = require('../');
const ClosureCompiler = require('../lib/node/closure-compiler');
const JsClosureCompiler = require('../lib/node/closure-compiler-js');

require('mocha');

process.on('unhandledRejection', e => { throw e; });

describe('gulp-google-closure-compiler', function() {
  let originalCompilerRunMethod;
  let originalJsCompilerRunMethod;
  let platformUtilized;

  before(() => {
    originalCompilerRunMethod = Object.getOwnPropertyDescriptor(ClosureCompiler.prototype, 'run');
    Object.defineProperty(ClosureCompiler.prototype, 'run', {
      value: function(...args) {
        const retVal = originalCompilerRunMethod.value.apply(this, args);
        platformUtilized = /^java/.test(this.getFullCommand()) ? 'java' : 'native';
        return retVal;
      },
      writable: true,
      enumerable: false,
      configurable: true
    });

    originalJsCompilerRunMethod = Object.getOwnPropertyDescriptor(JsClosureCompiler.prototype, 'run');
    Object.defineProperty(JsClosureCompiler.prototype, 'run', {
      value: function(...args) {
        platformUtilized = 'javascript';
        return originalJsCompilerRunMethod.value.apply(this, args);
      },
      writable: true,
      enumerable: false,
      configurable: true
    });
  });

  after(() => {
    Object.defineProperty(ClosureCompiler.prototype, 'run', originalCompilerRunMethod);
    Object.defineProperty(JsClosureCompiler.prototype, 'run', originalJsCompilerRunMethod);
  });

  ['java', 'native', 'javascript'].forEach(platform => {
    describe(`${platform} version`, function() {
      const closureCompiler = compilerPackage.gulp();

      this.timeout(30000);
      this.slow(10000);

      const fakeFile1 = new File({
        path: '/foo.js',
        contents: Buffer.from('console.log("foo");')
      });
      const fakeFile2 = new File({
        path: '/bar.js',
        contents: Buffer.from('console.log("bar");')
      });

      const fixturesCompiled = 'function log(a){console.log(a)}log("one.js");' +
          'var WindowInfo=function(){this.props=[]};WindowInfo.prototype.propList=function(){' +
          'for(var a in window)this.props.push(a)};WindowInfo.prototype.list=function(){' +
          'log(this.props.join(", "))};(new WindowInfo).list();\n';

      afterEach(() => {
        if (platformUtilized) {
          should.equal(platform, platformUtilized);
        }
        platformUtilized = undefined;
      });

      it('should emit an error for invalid options', done => {
        const stream = closureCompiler({
          compilation_level: 'FOO'
        }, {
          platform
        });

        stream.on('error', err => {
          err.message.should.startWith('Compilation error');
          done();
        });
        stream.write(fakeFile1);
        stream.end();
      });

      it('should compile a single file', done => {
        const stream = closureCompiler({
          compilation_level: 'SIMPLE',
          warning_level: 'VERBOSE'
        }, {
          platform
        });

        stream.pipe(assert.length(1))
          .pipe(assert.first(f => {
            f.contents.toString().trim().should.eql(fakeFile1.contents.toString());
          }))
          .pipe(assert.end(done));

        stream.write(fakeFile1);
        stream.end();
      });

      it('should name the output file when no js_output_file option is provided', done => {
        const stream = closureCompiler({
          compilation_level: 'SIMPLE',
          warning_level: 'VERBOSE'
        }, {
          platform
        });
        stream.pipe(assert.length(1))
          .pipe(assert.first(f => {
            f.path.should.eql('compiled.js');
          }))
          .pipe(assert.end(done));

        stream.write(fakeFile1);
        stream.end();
      });

      it('should name the output file from the js_output_file option', done => {
        const stream = closureCompiler({
          compilation_level: 'SIMPLE',
          warning_level: 'VERBOSE',
          js_output_file: 'out.js'
        }, {
          platform
        });
        stream.pipe(assert.length(1))
          .pipe(assert.first(f => {
            f.path.should.eql('out.js');
          }))
          .pipe(assert.end(done));

        stream.write(fakeFile1);
        stream.end();
      });

      it('should compile multiple input files into a single output', done => {
        const stream = closureCompiler({
          compilation_level: 'SIMPLE',
          warning_level: 'VERBOSE'
        }, {
          platform
        });

        stream.pipe(assert.length(1))
          .pipe(assert.first(f => {
            f.contents.toString().trim().should.eql(fakeFile1.contents.toString() +
                fakeFile2.contents.toString());
          }))
          .pipe(assert.end(done));

        stream.write(fakeFile1);
        stream.write(fakeFile2);
        stream.end();
      });

      if (platform !== 'javascript') {
        it('should compile multiple inputs into multiple outputs with chunk options', done => {
          const stream = closureCompiler({
            compilation_level: 'SIMPLE',
            warning_level: 'VERBOSE',
            chunk: [
              'one:1',
              'two:1'
            ],
            createSourceMap: true
          }, {
            platform
          });

          stream.pipe(assert.length(2))
              .pipe(assert.first(f => {
                f.contents.toString().trim().should.eql(fakeFile1.contents.toString());
                f.path.should.eql('one.js');
              }))
              .pipe(assert.second(f => {
                f.contents.toString().trim().should.eql(fakeFile2.contents.toString());
                f.path.should.eql('two.js');
              }))
              .pipe(assert.end(done));

          stream.write(fakeFile1);
          stream.write(fakeFile2);
          stream.end();
        });
      }

      it('should generate a sourcemap for a single output file', done => {
        gulp.src('test/fixtures/**/*.js', {base: './'})
          .pipe(sourcemaps.init())
          .pipe(closureCompiler({
            compilation_level: 'SIMPLE',
            warning_level: 'VERBOSE'
          }, {
            platform
          }))
          .pipe(assert.length(1))
          .pipe(assert.first(f => {
            f.sourceMap.sources.should.have.length(2);
            f.sourceMap.file.should.eql('compiled.js');
          }))
          .pipe(assert.end(done));
      });

      if (platform !== 'javascript') {
        it('should generate a sourcemap for each output file with chunks', done => {
          gulp.src([__dirname + '/fixtures/one.js', __dirname + '/fixtures/two.js'])
              .pipe(sourcemaps.init())
              .pipe(closureCompiler({
                compilation_level: 'SIMPLE',
                warning_level: 'VERBOSE',
                chunk: [
                  'one:1',
                  'two:1:one'
                ],
                createSourceMap: true
              }, {
                debugLog: true,
                platform
              }))
              .pipe(assert.length(2))
              .pipe(assert.first(f => {
                f.sourceMap.sources.should.have.length(1);
                f.sourceMap.file.should.eql('./one.js');
              }))
              .pipe(assert.second(f => {
                f.sourceMap.sources.should.have.length(1);
                f.sourceMap.file.should.eql('./two.js');
              }))
              .pipe(assert.end(done));
        });
      }

      if (platform !== 'javascript') {
        it('should support passing input globs directly to the compiler', done => {
          const stream = closureCompiler({
            js: __dirname + '/fixtures/**.js',
            compilation_level: 'SIMPLE',
            warning_level: 'VERBOSE'
          }, {
            platform
          })
            .src()
            .pipe(assert.length(1))
            .pipe(assert.first(f => {
              f.contents.toString().should.eql(fixturesCompiled);
            }))
            .pipe(assert.end(done));
        });

        it('should include js options before gulp.src files', done => {
          gulp.src(__dirname + '/fixtures/two.js')
            .pipe(closureCompiler({
              js: __dirname + '/fixtures/one.js',
              compilation_level: 'SIMPLE',
              warning_level: 'VERBOSE'
            }, {
              platform
            }))
            .pipe(assert.length(1))
            .pipe(assert.first(f => {
              f.contents.toString().should.eql(fixturesCompiled);
            }))
            .pipe(assert.end(done));
        });

        it('should support calling the compiler with an arguments array', done => {
          const stream = closureCompiler([
            '--js="' + __dirname + '/fixtures/**.js"',
            '--compilation_level=SIMPLE',
            '--warning_level=VERBOSE'
          ], {
            platform
          })
            .src()
            .pipe(assert.length(1))
            .pipe(assert.first(f => {
              f.contents.toString().should.eql(fixturesCompiled);
            }))
            .pipe(assert.end(done));
        });

        it('should compile without gulp.src files when .src() is called', done => {
          closureCompiler({
            compilation_level: 'SIMPLE',
            warning_level: 'VERBOSE',
            js: __dirname + '/fixtures/**.js'
          }, {
            platform
          })
            .src()
            .pipe(assert.length(1))
            .pipe(assert.first(f => {
              f.contents.toString().should.eql(fixturesCompiled);
            }))
            .pipe(assert.end(done));
        });
      }

      it('should generate no output without gulp.src files', done => {
        gulp.src([])
          .pipe(closureCompiler({
            compilation_level: 'SIMPLE',
            warning_level: 'VERBOSE'
          }, {
            platform
          }))
          .pipe(assert.length(0))
          .pipe(assert.end(done));
      });

      it('should properly compose sourcemaps when multiple transformations are chained', done => {
        gulp.src(['test/fixtures/one.js', 'test/fixtures/two.js'], {base: './'})
          .pipe(sourcemaps.init())
          .pipe(closureCompiler({
            compilation_level: 'WHITESPACE_ONLY',
            warning_level: 'VERBOSE',
            formatting: 'PRETTY_PRINT',
            sourceMapIncludeContent: true
          }, {
            platform
          }))
          .pipe(closureCompiler({
            compilation_level: 'SIMPLE',
            warning_level: 'QUIET',
            formatting: 'PRETTY_PRINT',
            js_output_file: 'final.js',
            sourceMapIncludeContent: true
          }, {
            platform
          }))
          .pipe(assert.first(f => {
            f.sourceMap.sources.should.containEql('test/fixtures/one.js');
            f.sourceMap.sources.should.containEql('test/fixtures/two.js');
          }))
          .pipe(assert.end(done))
          .on('error', err => {
            console.error(err);
          });
      });

      it('in streaming mode should emit an error', done => {
        gulp.src(__dirname + '/fixtures/**/*.js', {buffer: false})
          .pipe(closureCompiler({
            compilation_level: 'SIMPLE',
            warning_level: 'VERBOSE'
          }, {
            platform
          }))
          .on('error', err => {
            err.message.should.eql('Streaming not supported');
            done();
          });
      });
    });
  });
});
<|endoftext|>