<commit_before>/**
 * Imports
 */

var fs = require('fs')

/**
 * Vars
 */

var motor = {
  path: '/sys/class/tacho-motor/',
  available: getPaths('/sys/class/tacho-motor/'),
  prefix: 'out'
}

var sensor = {
  path: '/sys/class/lego-sensor/',
  available: getPaths('/sys/class/lego-sensor/'),
  prefix: 'in'
}

/**
 * Expose devices
 */

module.exports = devices

/**
 * Get a device
 * @param  {String} port
 * @return {String} path
 */

function devices (port) {
  var device = isNaN(port) ? motor : sensor
  if (device === motor) {
    port = port.toUpperCase()
  }
  return device.path + device.available[device.prefix + port]
}

function getPaths (path) {
  return fs.readdirSync(path).reduce(function (obj, file) {
    var portName = fs.readFileSync(path + file + '/port_name', 'utf-8').trim()
    obj[portName] = file.trim()
    return obj
  }, {})
}
<commit_msg>fix devices<commit_after>/**
 * Imports
 */

var fs = require('fs')

/**
 * Vars
 */

function motor () {
  return {
    path: '/sys/class/tacho-motor/',
    available: getPaths('/sys/class/tacho-motor/'),
    prefix: 'out'
  }
}

function sensor () {
  return {
    path: '/sys/class/lego-sensor/',
    available: getPaths('/sys/class/lego-sensor/'),
    prefix: 'in'
  }
}

/**
 * Expose devices
 */

module.exports = devices

/**
 * Get a device
 * @param  {String} port
 * @return {String} path
 */

function devices (port) {
  var device = isNaN(port) ? motor() : sensor()
  if (device === motor()) {
    port = port.toUpperCase()
  }
  return device.path + device.available[device.prefix + port]
}

function getPaths (path) {
  return fs.readdirSync(path).reduce(function (obj, file) {
    var portName = fs.readFileSync(path + file + '/port_name', 'utf-8').trim()
    obj[portName] = file.trim()
    return obj
  }, {})
}
<|endoftext|>


<commit_before>var EventEmitter = require('events').EventEmitter
var inherits = require('util').inherits

inherits(Channel, EventEmitter)

module.exports = Channel

function Channel(options) {
  if (!(this instanceof Channel))
    return new Channel(options)

  options = options || {}

  EventEmitter.call(this, options)

  this.concurrency = options.concurrency || Infinity
  // closed by default
  this.closed = !(options.closed === false || options.open)
  this.discard = options.discard

  this.fns = []
  this.results = []

  this.fnIndex = 0
  this.resultIndex = 0
  this.pending = 0
  this.errors = 0

  this.reading = true
}

Object.defineProperty(Channel.prototype, 'pushable', {
  get: function () {
    return this.reading && this.pending < this.concurrency
  }
})

// read queue
Object.defineProperty(Channel.prototype, 'queue', {
  get: function () {
    var queue = this.results.length + this.fns.length
    if (this.discard) queue += this.pending
    return queue
  }
})

// you can read from a channel if there's a read queue or if this channel is not closed
Object.defineProperty(Channel.prototype, 'readable', {
  get: function () {
    return this.queue || !this.closed
  }
})

Channel.prototype.open = function () {
  this.closed = false
  return this
}

Channel.prototype.close = function () {
  this.closed = true
  return this
}

/**
 * Push a function to the channel.
 * If `null`, just means closing the channel.
 */

Channel.prototype.push = function (fn) {
  if (fn == null) return this.close()

  if (typeof fn !== 'function')
    throw new TypeError('you may only push functions')

  this.fns.push(fn)
  if (!this.discard) this.results.length++
  this.call()
return this
}

Channel.prototype.call = function () {
  if (!this.pushable) return
  if (!this.fns.length) return

  var fn = this.fns.shift()
  var index = this.fnIndex++
  this.pending++

  var self = this
  fn(function (err, res) {
    self.pending--
    if (err) {
      self.reading = false
      self.errors++
      if (self.discard) {
        self.results.push(err)
      } else {
        self.results[index - self.resultIndex] = err
      }
    } else if (!self.discard) {
      self.results[index - self.resultIndex] = arguments.length > 2
        ? [].slice.call(arguments, 1)
        : res
    }

    self.emit(String(index))
    self.emit('callback')
    self.call()
  })
}

Channel.prototype.read = function* () {
  var self = this
  // continue executing callbacks if no errors occured
  if (!this.reading && !this.errors) this.reading = true

  if (!self.discard) {
    if (self.results.length && 0 in self.results) {
      var res = self.results.shift()
      self.resultIndex++
      if (res instanceof Error) {
        self.errors--
        throw res
      }
      return res
    }
  } else if (self.results.length) {
    // these can only be errors
    self.errors--
    throw self.results.shift()
  }

  // wait for the next result in the queue
  return yield function (done) {
    self.once(self.discard ?  'callback' : String(self.resultIndex), function () {
      if (!self.discard) {
        var res = self.results.shift()
        self.resultIndex++
        if (res instanceof Error) {
          self.errors--
          done(res)
        } else {
          done(null, res)
        }
      } else if (self.results.length) {
        // these can only be errors
        self.errors--
        done(self.results.shift())
      } else {
        done()
      }
    })
  }
}

Channel.prototype.flush = function* () {
  if (this.discard) {
    while (this.readable) yield* this.read()
    return
  }

  var results = []
  while (this.readable) results.push(yield* this.read())
  return results
}<commit_msg>style<commit_after>var EventEmitter = require('events').EventEmitter
var inherits = require('util').inherits

inherits(Channel, EventEmitter)

module.exports = Channel

function Channel(options) {
  if (!(this instanceof Channel))
    return new Channel(options)

  options = options || {}

  EventEmitter.call(this, options)

  this.concurrency = options.concurrency || Infinity
  // closed by default
  this.closed = !(options.closed === false || options.open)
  this.discard = options.discard

  this.fns = []
  this.results = []

  this.fnIndex = 0
  this.resultIndex = 0
  this.pending = 0
  this.errors = 0

  this.reading = true
}

Object.defineProperty(Channel.prototype, 'pushable', {
  get: function () {
    return this.reading && this.pending < this.concurrency
  }
})

// read queue
Object.defineProperty(Channel.prototype, 'queue', {
  get: function () {
    var queue = this.results.length + this.fns.length
    if (this.discard) queue += this.pending
    return queue
  }
})

// you can read from a channel if there's a read queue or if this channel is not closed
Object.defineProperty(Channel.prototype, 'readable', {
  get: function () {
    return this.queue || !this.closed
  }
})

Channel.prototype.open = function () {
  this.closed = false
  return this
}

Channel.prototype.close = function () {
  this.closed = true
  return this
}

/**
 * Push a function to the channel.
 * If `null`, just means closing the channel.
 */

Channel.prototype.push = function (fn) {
  if (fn == null) return this.close()

  if (typeof fn !== 'function')
    throw new TypeError('you may only push functions')

  this.fns.push(fn)
  if (!this.discard) this.results.length++
  this.call()
  return this
}

Channel.prototype.call = function () {
  if (!this.pushable) return
  if (!this.fns.length) return

  var fn = this.fns.shift()
  var index = this.fnIndex++
  this.pending++

  var self = this
  fn(function (err, res) {
    self.pending--
    if (err) {
      self.reading = false
      self.errors++
      if (self.discard) {
        self.results.push(err)
      } else {
        self.results[index - self.resultIndex] = err
      }
    } else if (!self.discard) {
      self.results[index - self.resultIndex] = arguments.length > 2
        ? [].slice.call(arguments, 1)
        : res
    }

    self.emit(String(index))
    self.emit('callback')
    self.call()
  })
}

Channel.prototype.read = function* () {
  var self = this
  // continue executing callbacks if no errors occured
  if (!this.reading && !this.errors) this.reading = true

  if (!self.discard) {
    if (self.results.length && 0 in self.results) {
      var res = self.results.shift()
      self.resultIndex++
      if (res instanceof Error) {
        self.errors--
        throw res
      }
      return res
    }
  } else if (self.results.length) {
    // these can only be errors
    self.errors--
    throw self.results.shift()
  }

  // wait for the next result in the queue
  return yield function (done) {
    self.once(self.discard ? 'callback' : String(self.resultIndex), function () {
      if (!self.discard) {
        var res = self.results.shift()
        self.resultIndex++
        if (res instanceof Error) {
          self.errors--
          done(res)
        } else {
          done(null, res)
        }
      } else if (self.results.length) {
        // these can only be errors
        self.errors--
        done(self.results.shift())
      } else {
        done()
      }
    })
  }
}

Channel.prototype.flush = function* () {
  if (this.discard) {
    while (this.readable) yield* this.read()
    return
  }

  var results = []
  while (this.readable) results.push(yield* this.read())
  return results
}<|endoftext|>


<commit_before>var path = require("path");
var fs = require("fs");

var natural = require("natural");
var _ = require("underscore");

exports.sniff = sniff;
exports.sniffPackageJson = sniffPackageJson;

function sniff(projectPath, callback) {
    var packageJsonPath = path.join(projectPath, "package.json");
    fs.readFile(packageJsonPath, "utf8", function(err, packageJsonContents) {
        if (err) {
            callback(err);
        } else {
            sniffPackageJson(packageJsonContents, function(err, license) {
                if (err) {
                    callback(err);
                } else if (license.names.length) {
                    callback(null, license);
                } else {
                    sniffLicenseFile(projectPath, callback);
                }
            });
        }
    });
}

function sniffPackageJson(packageJson, callback) {
    if (typeof packageJson === "string") {
        try {
            packageJson = JSON.parse(packageJson);
        } catch (err) {
            return callback(err);
        }
    }
    if (packageJson.license) {
        callback(null, {names: [packageJson.license]});
    } else if (packageJson.licenses) {
        var licenseNames = packageJson.licenses.map(function(license) {
            return license.type;
        });

        callback(null, {names: licenseNames});
    } else {
        callback(null, {names: []});
    }
}

function sniffLicenseFile(modulePath, callback) {
    var licensePath = path.join(modulePath, "LICENSE");
    fs.exists(licensePath, function(exists) {
        if (exists) {
            fs.readFile(licensePath, "utf8", function(err, licenseText) {
                if (err) {
                    callback(err);
                } else {
                    var license = detectLicenseFromText(licenseText);
                    var names = license ? [license] : [];
                    callback(null, {
                        names: names
                    });
                }
            });
        } else {
            callback(null, null);
        }
    });
}

var licenseTexts = [];
(function() {
    var licenseDir = path.join(__dirname, "../licenses");
    var licensesJson = JSON.parse(fs.readFileSync(path.join(licenseDir, "licenses.json"),"utf8"));

    licensesJson.forEach(function(license) {
        var licensePath = path.join(licenseDir, license.path);
        licenseTexts.push({
            name: license.name,
            text: fs.readFileSync(licensePath, "utf8")
        });
    });
})();

function detectLicenseFromText(text) {
    var distances = licenseTexts.map(function(license) {
        return {
            distance: natural.JaroWinklerDistance(license.text, text),
            license: license
        };
    });
    var closest = _.max(distances, function(distance) {
        return distance.distance;
    });
    if (closest.distance > 0.9) {
        return closest.license.name;
    } else {
        return null;
    }
}
<commit_msg>Switch to using LevenshteinDistance<commit_after>var path = require("path");
var fs = require("fs");

var natural = require("natural");
var _ = require("underscore");

exports.sniff = sniff;
exports.sniffPackageJson = sniffPackageJson;

function sniff(projectPath, callback) {
    var packageJsonPath = path.join(projectPath, "package.json");
    fs.readFile(packageJsonPath, "utf8", function(err, packageJsonContents) {
        if (err) {
            callback(err);
        } else {
            sniffPackageJson(packageJsonContents, function(err, license) {
                if (err) {
                    callback(err);
                } else if (license.names.length) {
                    callback(null, license);
                } else {
                    sniffLicenseFile(projectPath, callback);
                }
            });
        }
    });
}

function sniffPackageJson(packageJson, callback) {
    if (typeof packageJson === "string") {
        try {
            packageJson = JSON.parse(packageJson);
        } catch (err) {
            return callback(err);
        }
    }
    if (packageJson.license) {
        callback(null, {names: [packageJson.license]});
    } else if (packageJson.licenses) {
        var licenseNames = packageJson.licenses.map(function(license) {
            return license.type;
        });

        callback(null, {names: licenseNames});
    } else {
        callback(null, {names: []});
    }
}

function sniffLicenseFile(modulePath, callback) {
    var licensePath = path.join(modulePath, "LICENSE");
    fs.exists(licensePath, function(exists) {
        if (exists) {
            fs.readFile(licensePath, "utf8", function(err, licenseText) {
                if (err) {
                    callback(err);
                } else {
                    var license = detectLicenseFromText(licenseText);
                    var names = license ? [license] : [];
                    callback(null, {
                        names: names
                    });
                }
            });
        } else {
            callback(null, null);
        }
    });
}

var licenseTexts = [];
(function() {
    var licenseDir = path.join(__dirname, "../licenses");
    var licensesJson = JSON.parse(fs.readFileSync(path.join(licenseDir, "licenses.json"),"utf8"));

    licensesJson.forEach(function(license) {
        var licensePath = path.join(licenseDir, license.path);
        licenseTexts.push({
            name: license.name,
            text: fs.readFileSync(licensePath, "utf8")
        });
    });
})();

function detectLicenseFromText(text) {
    var distances = licenseTexts.map(function(license) {
        return {
            distance: natural.LevenshteinDistance(license.text, text) / Math.max(license.text.length, text.length),
            license: license
        };
    });
    var closest = _.min(distances, function(distance) {
        return distance.distance;
    });
    if (closest.distance < 0.2) {
        return closest.license.name;
    } else {
        return null;
    }
}
<|endoftext|>


<commit_before>/** @jsx dom */
import arrayUniq from 'array-uniq';
import clickOutside from 'click-outside';
import dom from 'magic-virtual-element';
import Option from './option';

const propTypes = {
	class: {
		type: 'string'
	},
	id: {
		type: 'string'
	},
	multiple: {
		type: 'boolean'
	},
	name: {
		type: 'string'
	},
	onChange: {
		type: 'function'
	},
	options: {
		type: 'array'
	},
	placeholder: {
		type: 'string'
	},
	symbol: {
		type: 'string'
	}
};

const defaultProps = {
	symbol: '\u2a2f'
};

const initialState = () => {
	return {
		active: []
	};
};

const afterMount = ({props, state}, el, setState) => {
	const {multiple, options} = props;
	const {active} = state;

	options.forEach(x => x.active && active.push(x));
	setState({active: multiple || !active.length ? active : [active[active.length - 1]]});

	clickOutside(el, () => setState({open: false}));
};

const onRemove = (val, props, state, setState) => {
	const {name, onChange} = props;
	const {active} = state;
	const arr = active.map(x => x.value);

	active.splice(arr.indexOf(val), 1);

	setState({active});

	if (onChange) {
		onChange({[name]: arrayUniq(active.map(x => x.value))});
	}

	return;
};

const getText = (props, state, setState) => {
	const {multiple, placeholder, symbol} = props;
	const {active} = state;

	if (active.length && multiple) {
		return active.map(x => {
			return (

 onRemove(x.value, props, state, setState)}>
						{symbol}

					{x.label}

			);
		});
	}

	if (active.length && !multiple) {
		return
{active[0].label}
;
	}

	return
{placeholder}
;
};

const onClick = (option, props, state, setState) => {
	const {multiple, name, onChange} = props;
	const {active, open} = state;
	const arr = active.map(x => x.value);
	let ret = [option];

	if (arr.includes(option.value)) {
		active.splice(arr.indexOf(option.value), 1);

		setState({active});

		if (onChange) {
			onChange({[name]: arrayUniq(active.map(x => x.value))});
		}

		return;
	}

	if (multiple) {
		ret = active.filter(x => x.value).concat(ret);
	}

	setState({active: arrayUniq(ret), open: multiple ? open : false});

	if (onChange) {
		onChange({[name]: arrayUniq(ret.map(x => x.value))});
	}
};

const getOptions = (props, state, setState) => {
	const {options} = props;
	const {active} = state;
	const arr = active.filter(x => x.value).map(x => x.value);

	return options.map(x => {
		return <Option active={arr.includes(x.value)} data={x} onClick={() => onClick(x, props, state, setState)}/>;
	});
};

const render = ({props, state}, setState) => {
	const {id} = props;
	const {open} = state;

	return (

 setState({open: true})}>
				{getText(props, state, setState)}

				{getOptions(props, state, setState)}

	);
};

export default {afterMount, defaultProps, initialState, propTypes, render};
<commit_msg>Add ability to always show `placeholder`<commit_after>/** @jsx dom */
import arrayUniq from 'array-uniq';
import clickOutside from 'click-outside';
import dom from 'magic-virtual-element';
import Option from './option';

const propTypes = {
	class: {
		type: 'string'
	},
	id: {
		type: 'string'
	},
	multiple: {
		type: 'boolean'
	},
	name: {
		type: 'string'
	},
	onChange: {
		type: 'function'
	},
	options: {
		type: 'array'
	},
	placeholder: {
		type: 'string'
	},
	symbol: {
		type: 'string'
	},
	showValue: {
		type: 'boolean'
	}
};

const defaultProps = {
	showValue: true,
	symbol: '\u2a2f'
};

const initialState = () => {
	return {
		active: []
	};
};

const afterMount = ({props, state}, el, setState) => {
	const {multiple, options} = props;
	const {active} = state;

	options.forEach(x => x.active && active.push(x));
	setState({active: multiple || !active.length ? active : [active[active.length - 1]]});

	clickOutside(el, () => setState({open: false}));
};

const onRemove = (val, props, state, setState) => {
	const {name, onChange} = props;
	const {active} = state;
	const arr = active.map(x => x.value);

	active.splice(arr.indexOf(val), 1);

	setState({active});

	if (onChange) {
		onChange({[name]: arrayUniq(active.map(x => x.value))});
	}

	return;
};

const getText = (props, state, setState) => {
	const {multiple, placeholder, showValue, symbol} = props;
	const {active} = state;

	if (active.length && multiple && showValue) {
		return active.map(x => {
			return (

 onRemove(x.value, props, state, setState)}>
						{symbol}

					{x.label}

			);
		});
	}

	if (active.length && !multiple && showValue) {
		return
{active[0].label}
;
	}

	return
{placeholder}
;
};

const onClick = (option, props, state, setState) => {
	const {multiple, name, onChange} = props;
	const {active, open} = state;
	const arr = active.map(x => x.value);
	let ret = [option];

	if (arr.includes(option.value)) {
		active.splice(arr.indexOf(option.value), 1);

		setState({active});

		if (onChange) {
			onChange({[name]: arrayUniq(active.map(x => x.value))});
		}

		return;
	}

	if (multiple) {
		ret = active.filter(x => x.value).concat(ret);
	}

	setState({active: arrayUniq(ret), open: multiple ? open : false});

	if (onChange) {
		onChange({[name]: arrayUniq(ret.map(x => x.value))});
	}
};

const getOptions = (props, state, setState) => {
	const {options} = props;
	const {active} = state;
	const arr = active.filter(x => x.value).map(x => x.value);

	return options.map(x => {
		return <Option active={arr.includes(x.value)} data={x} onClick={() => onClick(x, props, state, setState)}/>;
	});
};

const render = ({props, state}, setState) => {
	const {id} = props;
	const {open} = state;

	return (

 setState({open: true})}>
				{getText(props, state, setState)}

				{getOptions(props, state, setState)}

	);
};

export default {afterMount, defaultProps, initialState, propTypes, render};
<|endoftext|>


<commit_before>
const expect = require('chai').expect;
const RG = require('../../../client/src/battles');

const Item = RG.Item.Base;
const Actor = RG.Actor.Rogue;
const Slot = RG.Inv.EquipSlot;

describe('RG.Inv.EquipSlot', () => {

    it('Holds items or stacks of items', () => {
        const rogue = new RG.Actor.Rogue('rogue');
        const invEq = new RG.Inv.Inventory(rogue);
        const eq = invEq.getEquipment();
        const missSlot = new Slot(eq, 'missile', true);

        const arrow = new RG.Item.Missile('arrow');
        arrow.count = 10;
        expect(missSlot.equipItem(arrow)).to.equal(true);
        expect(missSlot.unequipItem(5)).to.equal(true);

        const arrowStack = missSlot.getItem();
        expect(arrowStack.count).to.equal(5);
        expect(missSlot.unequipItem(5)).to.equal(true);
        const nullArrowStack = missSlot.getItem();
        expect(nullArrowStack === null).to.equal(true);

    });
});

describe('RG.Inv.Equipment', () => {
    let player = null;
    let eq = null;

    beforeEach(() => {
        player = new RG.Actor.Rogue('rogue');
        eq = new RG.Inv.Equipment(player);
    });

    it('has different slots for items', () => {
        const slotTypes = eq.getSlotTypes();
        const nLast = slotTypes.length - 1;
        expect(slotTypes).to.have.length.above(5);
        expect(slotTypes[0]).to.equal('hand');
        expect(slotTypes[nLast]).to.equal('spiritgem');
    });

    it('can have items equipped', () => {
        eq.addSlot('spiritgem', new RG.Inv.EquipSlot(eq, 'spiritgem'));
        const items = eq.getItem('spiritgem');
        expect(items).to.have.length(2);
        expect(eq.getNumSlots('hand')).to.equal(1);
        expect(eq.getNumSlots('spiritgem')).to.equal(2);

        for (let i = 0; i < 2; i++) {
            const gem = new RG.Item.SpiritGem('my big gem ' + i);
            eq.equipItem(gem, i);
        }
        expect(eq.getItems()).to.have.length(2);

        const gems = eq.getItem('spiritgem');
        gems.forEach(gem => {
            expect(gem).not.to.be.empty;
        });

        expect(eq.unequipItem('spiritgem')).to.be.true;
        expect(eq.getItems()).to.have.length(1);
        const unequipped = eq.getUnequipped('spiritgem', 0);
        expect(unequipped.getType()).to.equal('spiritgem');

    });

    it('can have a shield equipped', () => {
        const shield = new RG.Item.Armour('shield');
        shield.setArmourType('shield');
        shield.setDefense(10);
        const actor = new RG.Actor.Rogue('shielder');
        const invEq = actor.getInvEq();
        invEq.addItem(shield);
        invEq.equipItem(shield);
        expect(actor.getShieldDefense()).to.equal(10);

        const skills = new RG.Component.Skills();
        skills.addSkill('Shields');
        skills.setLevel('Shields', 5);
        actor.add(skills);
        expect(actor.getShieldDefense()).to.equal(15);
    });

    it('can have equipped items removed and re-equipped', () => {
        const shield = new RG.Item.Armour('shield');
        shield.setArmourType('shield');

        const actor = new RG.Actor.Rogue('equipper');
        const invEq = actor.getInvEq();
        const eq = invEq.getEquipment();
        const eqItems = eq.getItems();
        invEq.addItem(shield);
        invEq.equipItem(shield);
        invEq.unequipItem('shield');
        expect(eqItems).to.have.length(0);

        expect(invEq.equipItem(shield)).to.be.true;
        expect(eqItems).to.have.length(1);
        invEq.unequipItem('shield', 1);
        expect(eqItems).to.have.length(0);
        invEq.equipItem(shield);
        expect(eqItems).to.have.length(1);
        invEq.unequipItem('shield', 1, 0);
        expect(eqItems).to.have.length(0);

        const arrows = new RG.Item.Ammo('arrow');
        arrows.count = 10;
        invEq.addItem(arrows);
        invEq.equipNItems(arrows, 10);
        expect(eqItems).to.have.length(1);
        invEq.unequipItem('missile', 5, 0);
        expect(eqItems).to.have.length(1);
        invEq.unequipItem('missile', 4, 0);
        expect(eqItems).to.have.length(1);
        invEq.unequipItem('missile', 1, 0);
        expect(eqItems).to.have.length(0);
    });

});

describe('RG.Inv.Inventory', () => {

    let actor = null;
    let invEq = null;

    beforeEach(() => {
        actor = new Actor('actor');
        invEq = actor.getInvEq();
    });

    it('can contain and equip items', () => {
        const food = new Item('Bagel');
        food.setType('food');
        const sword = new Item('Sword');
        sword.setType('weapon');

        invEq.addItem(food);
        expect(invEq.getInventory().getItems().length).to.equal(1);
        invEq.addItem(sword);
        expect(invEq.getInventory().getItems().length).to.equal(2);
        expect(invEq.equipItem(sword)).to.equal(true);
        expect(invEq.getInventory().getItems().length).to.equal(1);

        const handsEquipped = invEq.getEquipment().getEquipped('hand');
        expect(handsEquipped.equals(sword)).to.equal(true);
        expect(invEq.unequipItem('hand')).to.equal(true);
    });

    it('can equip and unequip items in inventory', () => {
        const sword = new RG.Item.Weapon('sword');

        invEq.addItem(sword);
        invEq.equipItem(sword);
        expect(invEq.getWeapon().getName()).to.equal(sword.getName());

        invEq.unequipItem('hand', 1);
        const items = invEq.getInventory().getItems();
        expect(items).to.have.length(1);
        expect(items[0].count).to.equal(1);

    });

    it('Equips armour into correct slots', () => {
        const helmet = new RG.Item.Armour('Helmet');
        helmet.setArmourType('head');

        invEq.addItem(helmet);
        expect(invEq.equipItem(helmet)).to.equal(true);

        const headEquipped = invEq.getEquipment().getEquipped('head');
        expect(headEquipped.equals(helmet)).to.equal(true);
        expect(invEq.unequipItem('head', 0)).to.equal(true);
    });

    it('Equips missile weapons and ammo correctly', () => {
        const rifle = new RG.Item.MissileWeapon('rifle');
        const ammo = new RG.Item.Ammo('rifle bullet');

        invEq.addItem(rifle);
        invEq.addItem(ammo);
        expect(invEq.equipItem(rifle)).to.equal(true);
        expect(invEq.equipItem(ammo)).to.equal(true);

        const missWeaponEquipped = invEq.getEquipment()
            .getEquipped('missileweapon');
        const ammoWeaponEquipped = invEq.getEquipment().getEquipped('missile');

        expect(missWeaponEquipped.getName()).to.equal('rifle');
        expect(ammoWeaponEquipped.getName()).to.equal('rifle bullet');

        const missWeapon = invEq.getMissileWeapon();
        expect(missWeapon.equals(missWeaponEquipped)).to.be.true;
    });

    it('Checks maximum weight allowed to carry', () => {
        const inv = invEq.getInventory();
        const eq = invEq.getEquipment();

        const heavySword = new RG.Item.Weapon('HeavySword');
        heavySword.setWeight(21.0);
        expect(invEq.canCarryItem(heavySword)).to.equal(false);

        const lightSword = new RG.Item.Weapon('Light lightSword');
        lightSword.setWeight(5.0);
        lightSword.count = 2;
        expect(invEq.canCarryItem(lightSword)).to.equal(true);
        invEq.addItem(lightSword);
        invEq.equipItem(lightSword);
        expect(eq.getWeight()).to.equal(5.0);
        expect(inv.getWeight()).to.equal(5.0);

        const shuriken = new RG.Item.Missile('Shuriken');
        shuriken.count = 20;
        shuriken.setWeight(0.1);
        invEq.addItem(shuriken);
        expect(inv.getWeight()).to.equal(7.0);
    });

    it('Should not lose the item count (Bug was found)', () => {
        const inv = invEq.getInventory();

        const dart = new RG.Item.Missile('Dart');
        dart.count = 1;
        const arrow = new RG.Item.Missile('Arrow');
        arrow.count = 1;

        invEq.addItem(dart);
        invEq.addItem(arrow);
        expect(invEq.equipItem(dart)).to.equal(true);
        expect(invEq.equipItem(arrow)).to.equal(false);

        let items = inv.getItems();
        expect(items[0].count).to.equal(1);

        invEq.unequipItem('missile', 1);
        expect(items).to.have.length(2);
        expect(invEq.equipNItems(dart, 1)).to.equal(true);
        expect(invEq.equipNItems(arrow, 1)).to.equal(false);

        items = inv.getItems();
        expect(items[0].count).to.equal(1);
    });

    it('should work with multiple slots of same type', () => {
        const eq = invEq.getEquipment();
        eq.addSlot('spiritgem', new RG.Inv.EquipSlot(eq, 'spiritgem'));
        for (let i = 0; i < 2; i++) {
            const gem = new RG.Item.SpiritGem('my big gem ' + i);
            const stats = new RG.Component.Stats();
            stats.setPerception(2);
            gem.add(stats);
            invEq.addItem(gem);
            invEq.equipItem(gem);
        }

        let perception = eq.getPerception();
        expect(perception).to.equal(4);

        expect(invEq.unequipItem('spiritgem', 1, 1)).to.be.true;
        expect(invEq.unequipItem('spiritgem', 1, 0)).to.be.true;

        perception = eq.getPerception();
        expect(perception).to.equal(0);

        const strength = eq.getStrength();
        expect(strength).to.equal(0);

        const swordOfStrength = new RG.Item.Weapon('sword');
        const stats = new RG.Component.Stats();
        stats.setStrength(10);
        swordOfStrength.add(stats);
        invEq.addItem(swordOfStrength);
        invEq.equipItem(swordOfStrength);
        expect(eq.getStrength()).to.equal(10);
    });
});
<commit_msg>Added a test to check that the ID is preserved between equips.<commit_after>
const expect = require('chai').expect;
const RG = require('../../../client/src/battles');

const Item = RG.Item.Base;
const Actor = RG.Actor.Rogue;
const Slot = RG.Inv.EquipSlot;

describe('RG.Inv.EquipSlot', () => {

    it('Holds items or stacks of items', () => {
        const rogue = new RG.Actor.Rogue('rogue');
        const invEq = new RG.Inv.Inventory(rogue);
        const eq = invEq.getEquipment();
        const missSlot = new Slot(eq, 'missile', true);

        const arrow = new RG.Item.Missile('arrow');
        arrow.count = 10;
        expect(missSlot.equipItem(arrow)).to.equal(true);
        expect(missSlot.unequipItem(5)).to.equal(true);

        const arrowStack = missSlot.getItem();
        expect(arrowStack.count).to.equal(5);
        expect(missSlot.unequipItem(5)).to.equal(true);
        const nullArrowStack = missSlot.getItem();
        expect(nullArrowStack === null).to.equal(true);

    });
});

describe('RG.Inv.Equipment', () => {
    let player = null;
    let eq = null;

    beforeEach(() => {
        player = new RG.Actor.Rogue('rogue');
        eq = new RG.Inv.Equipment(player);
    });

    it('has different slots for items', () => {
        const slotTypes = eq.getSlotTypes();
        const nLast = slotTypes.length - 1;
        expect(slotTypes).to.have.length.above(5);
        expect(slotTypes[0]).to.equal('hand');
        expect(slotTypes[nLast]).to.equal('spiritgem');
    });

    it('can have items equipped', () => {
        eq.addSlot('spiritgem', new RG.Inv.EquipSlot(eq, 'spiritgem'));
        const items = eq.getItem('spiritgem');
        expect(items).to.have.length(2);
        expect(eq.getNumSlots('hand')).to.equal(1);
        expect(eq.getNumSlots('spiritgem')).to.equal(2);

        for (let i = 0; i < 2; i++) {
            const gem = new RG.Item.SpiritGem('my big gem ' + i);
            eq.equipItem(gem, i);
        }
        expect(eq.getItems()).to.have.length(2);

        const gems = eq.getItem('spiritgem');
        gems.forEach(gem => {
            expect(gem).not.to.be.empty;
        });

        expect(eq.unequipItem('spiritgem')).to.be.true;
        expect(eq.getItems()).to.have.length(1);
        const unequipped = eq.getUnequipped('spiritgem', 0);
        expect(unequipped.getType()).to.equal('spiritgem');

    });

    it('can have a shield equipped', () => {
        const shield = new RG.Item.Armour('shield');
        shield.setArmourType('shield');
        shield.setDefense(10);
        const actor = new RG.Actor.Rogue('shielder');
        const invEq = actor.getInvEq();
        invEq.addItem(shield);
        invEq.equipItem(shield);
        expect(actor.getShieldDefense()).to.equal(10);

        const skills = new RG.Component.Skills();
        skills.addSkill('Shields');
        skills.setLevel('Shields', 5);
        actor.add(skills);
        expect(actor.getShieldDefense()).to.equal(15);
    });

    it('can have equipped items removed and re-equipped', () => {
        const shield = new RG.Item.Armour('shield');
        shield.setArmourType('shield');

        const actor = new RG.Actor.Rogue('equipper');
        const invEq = actor.getInvEq();
        const eq = invEq.getEquipment();
        const eqItems = eq.getItems();
        invEq.addItem(shield);
        invEq.equipItem(shield);
        invEq.unequipItem('shield');
        expect(eqItems).to.have.length(0);

        expect(invEq.equipItem(shield)).to.be.true;
        expect(eqItems).to.have.length(1);
        invEq.unequipItem('shield', 1);
        expect(eqItems).to.have.length(0);
        invEq.equipItem(shield);
        expect(eqItems).to.have.length(1);
        invEq.unequipItem('shield', 1, 0);
        expect(eqItems).to.have.length(0);

        const arrows = new RG.Item.Ammo('arrow');
        arrows.count = 10;
        invEq.addItem(arrows);
        invEq.equipNItems(arrows, 10);
        expect(eqItems).to.have.length(1);
        invEq.unequipItem('missile', 5, 0);
        expect(eqItems).to.have.length(1);
        invEq.unequipItem('missile', 4, 0);
        expect(eqItems).to.have.length(1);
        invEq.unequipItem('missile', 1, 0);
        expect(eqItems).to.have.length(0);
    });

});

describe('RG.Inv.Inventory', () => {

    let actor = null;
    let invEq = null;

    beforeEach(() => {
        actor = new Actor('actor');
        invEq = actor.getInvEq();
    });

    it('can contain and equip items', () => {
        const food = new Item('Bagel');
        food.setType('food');
        const sword = new Item('Sword');
        sword.setType('weapon');

        invEq.addItem(food);
        expect(invEq.getInventory().getItems().length).to.equal(1);
        invEq.addItem(sword);
        expect(invEq.getInventory().getItems().length).to.equal(2);
        expect(invEq.equipItem(sword)).to.equal(true);
        expect(invEq.getInventory().getItems().length).to.equal(1);

        const handsEquipped = invEq.getEquipment().getEquipped('hand');
        expect(handsEquipped.equals(sword)).to.equal(true);
        expect(invEq.unequipItem('hand')).to.equal(true);
    });

    it('can equip and unequip items in inventory', () => {
        const sword = new RG.Item.Weapon('sword');

        invEq.addItem(sword);
        invEq.equipItem(sword);
        expect(invEq.getWeapon().getName()).to.equal(sword.getName());

        invEq.unequipItem('hand', 1);
        const items = invEq.getInventory().getItems();
        expect(items).to.have.length(1);
        expect(items[0].count).to.equal(1);

    });

    it('Equips armour into correct slots', () => {
        const helmet = new RG.Item.Armour('Helmet');
        helmet.setArmourType('head');

        invEq.addItem(helmet);
        expect(invEq.equipItem(helmet)).to.equal(true);

        const headEquipped = invEq.getEquipment().getEquipped('head');
        expect(headEquipped.equals(helmet)).to.equal(true);
        expect(invEq.unequipItem('head', 0)).to.equal(true);
    });

    it('Equips missile weapons and ammo correctly', () => {
        const rifle = new RG.Item.MissileWeapon('rifle');
        const ammo = new RG.Item.Ammo('rifle bullet');

        invEq.addItem(rifle);
        invEq.addItem(ammo);
        expect(invEq.equipItem(rifle)).to.equal(true);
        expect(invEq.equipItem(ammo)).to.equal(true);

        const missWeaponEquipped = invEq.getEquipment()
            .getEquipped('missileweapon');
        const ammoWeaponEquipped = invEq.getEquipment().getEquipped('missile');

        expect(missWeaponEquipped.getName()).to.equal('rifle');
        expect(ammoWeaponEquipped.getName()).to.equal('rifle bullet');

        const missWeapon = invEq.getMissileWeapon();
        expect(missWeapon.equals(missWeaponEquipped)).to.be.true;
    });

    it('Checks maximum weight allowed to carry', () => {
        const inv = invEq.getInventory();
        const eq = invEq.getEquipment();

        const heavySword = new RG.Item.Weapon('HeavySword');
        heavySword.setWeight(21.0);
        expect(invEq.canCarryItem(heavySword)).to.equal(false);

        const lightSword = new RG.Item.Weapon('Light lightSword');
        lightSword.setWeight(5.0);
        lightSword.count = 2;
        expect(invEq.canCarryItem(lightSword)).to.equal(true);
        invEq.addItem(lightSword);
        invEq.equipItem(lightSword);
        expect(eq.getWeight()).to.equal(5.0);
        expect(inv.getWeight()).to.equal(5.0);

        const shuriken = new RG.Item.Missile('Shuriken');
        shuriken.count = 20;
        shuriken.setWeight(0.1);
        invEq.addItem(shuriken);
        expect(inv.getWeight()).to.equal(7.0);
    });

    it('Should not lose the item count (Bug was found)', () => {
        const inv = invEq.getInventory();

        const dart = new RG.Item.Missile('Dart');
        dart.count = 1;
        const arrow = new RG.Item.Missile('Arrow');
        arrow.count = 1;

        invEq.addItem(dart);
        invEq.addItem(arrow);
        expect(invEq.equipItem(dart)).to.equal(true);
        expect(invEq.equipItem(arrow)).to.equal(false);

        let items = inv.getItems();
        expect(items[0].count).to.equal(1);

        invEq.unequipItem('missile', 1);
        expect(items).to.have.length(2);
        expect(invEq.equipNItems(dart, 1)).to.equal(true);
        expect(invEq.equipNItems(arrow, 1)).to.equal(false);

        items = inv.getItems();
        expect(items[0].count).to.equal(1);
    });

    it('should work with multiple slots of same type', () => {
        const eq = invEq.getEquipment();
        eq.addSlot('spiritgem', new RG.Inv.EquipSlot(eq, 'spiritgem'));
        for (let i = 0; i < 2; i++) {
            const gem = new RG.Item.SpiritGem('my big gem ' + i);
            const stats = new RG.Component.Stats();
            stats.setPerception(2);
            gem.add(stats);
            invEq.addItem(gem);
            invEq.equipItem(gem);
        }

        let perception = eq.getPerception();
        expect(perception).to.equal(4);

        expect(invEq.unequipItem('spiritgem', 1, 1)).to.be.true;
        expect(invEq.unequipItem('spiritgem', 1, 0)).to.be.true;

        perception = eq.getPerception();
        expect(perception).to.equal(0);

        const strength = eq.getStrength();
        expect(strength).to.equal(0);

        const swordOfStrength = new RG.Item.Weapon('sword');
        const stats = new RG.Component.Stats();
        stats.setStrength(10);
        swordOfStrength.add(stats);
        invEq.addItem(swordOfStrength);
        invEq.equipItem(swordOfStrength);
        expect(eq.getStrength()).to.equal(10);
    });

    it('preserves entity ID between equips', () => {
        const sword = new RG.Item.Weapon('sword');
        const id = sword.getID();
        invEq.addItem(sword);
        invEq.equipItem(sword, 0);
        const unequippedSword = invEq.unequipAndGetItem('hand', 1);
        expect(unequippedSword.getID()).to.equal(id);

        const arrows = new RG.Item.Ammo();
        const arrowID = arrows.getID();
        arrows.count = 10;
        console.log('Adding items now');
        invEq.addItem(arrows);
        console.log('Equipping items now');
        invEq.equipNItems(arrows, arrows.count);

        const newArrows = invEq.getMissile();
        expect(newArrows.getID()).to.equal(arrowID);
    });
});
<|endoftext|>


<commit_before>'use strict';

function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }

var fs = _interopDefault(require('fs-extra'));
var glob = _interopDefault(require('glob'));
var path = _interopDefault(require('path'));
var Spritesmith = _interopDefault(require('spritesmith'));
var imagemin = _interopDefault(require('imagemin'));
var pngquant = _interopDefault(require('imagemin-pngquant'));
var CryptoJs = _interopDefault(require('crypto-js'));
var os = _interopDefault(require('os'));

var defaultOptions = {
    project_path: process.cwd(),
    http_path: '/',
    css_dir: 'stylesheets',
    images_dir: 'images',
    cache_dir: path.resolve(os.tmpdir(), 'sprite-magic-importer'),
    spritesmith: {},
    pngquant: {},

    get generated_images_dir() {
        return this.images_dir;
    },
    get http_generated_images_path() {
        return path.join(this.http_path, this.generated_images_dir);
    },
    get http_stylesheets_path() {
        return path.join(this.http_path, this.css_dir);
    }
};

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var stateClasses = ['hover', 'target', 'active', 'focus'];

function px(value) {
    return value === 0 ? '0' : value + 'px';
}

var SpriteMagic = function () {
    function SpriteMagic(options) {
        _classCallCheck(this, SpriteMagic);

        this.options = Object.assign({}, defaultOptions, options);
    }

    _createClass(SpriteMagic, [{
        key: 'resolve',
        value: function resolve(_ref) {
            var url = _ref.url,
                prev = _ref.prev;

            if (!/\.png$/.test(url)) {
                return Promise.resolve();
            }
            return this.process({ url: url, prev: prev });
        }
    }, {
        key: 'process',
        value: function process(context) {
            var _this = this;

            this.context = context;
            this.context.srcPath = path.resolve(this.options.images_dir, this.context.url);
            this.context.mapName = path.basename(path.dirname(this.context.srcPath));
            this.context.fileName = this.context.mapName + '.png';
            this.context.imagePath = path.resolve(this.options.generated_images_dir, this.context.fileName);

            return Promise.resolve().then(function () {
                return _this.getImagesInfo();
            }).then(function () {
                return _this.createHash();
            }).then(function () {
                return _this.checkCache();
            }).then(function () {
                return _this.context.hasCache ? Promise.resolve() : Promise.resolve().then(function () {
                    return _this.runSpritesmith();
                }).then(function () {
                    return _this.outputSpriteImage();
                }).then(function () {
                    return _this.createSass();
                }).then(function () {
                    return _this.outputSassFile();
                });
            }).then(function () {
                return _this.createResult();
            });
        }
    }, {
        key: 'getImagesInfo',
        value: function getImagesInfo() {
            var _this2 = this;

            return Promise.resolve().then(function () {
                return new Promise(function (resolve, reject) {
                    glob(_this2.context.srcPath, function (err, matches) {
                        if (err) {
                            return reject(err);
                        }

                        _this2.context.images = matches.map(function (filePath) {
                            return Object.assign({ filePath: filePath }, path.parse(filePath));
                        });
                        return resolve();
                    });
                });
            }).then(function () {
                return Promise.all(_this2.context.images.map(function (image) {
                    return new Promise(function (resolve, reject) {
                        fs.stat(image.filePath, function (err, stats) {
                            if (err) {
                                return reject(err);
                            }

                            Object.assign(image, { mtime: stats.mtime.getTime() });
                            return resolve();
                        });
                    });
                }));
            });
        }
    }, {
        key: 'createHash',
        value: function createHash() {
            var fingerprint = this.context.images.map(function (image) {
                return image.filePath + '~' + image.mtime;
            }).concat(JSON.stringify(this.options.spritesmith)).concat(JSON.stringify(this.options.pngquant)).concat(require('../package.json').version) // eslint-disable-line global-require
            .join('\0');
            this.context.hash = CryptoJs.SHA1(fingerprint).toString(CryptoJs.enc.HEX).substr(0, 7);

            var fileName = this.context.mapName + '-' + this.context.hash + '.scss';
            this.context.sassFilePath = path.resolve(this.options.cache_dir, fileName);
        }
    }, {
        key: 'checkCache',
        value: function checkCache() {
            var _this3 = this;

            var latestMtime = Math.max.apply(Math, _toConsumableArray(this.context.images.map(function (image) {
                return image.mtime;
            })));
            var promises = ['imagePath', 'sassFilePath'].map(function (key) {
                return new Promise(function (resolve, reject) {
                    fs.stat(_this3.context[key], function (err, stats) {
                        if (err || stats.mtime.getTime() < latestMtime) {
                            return reject();
                        }
                        return resolve();
                    });
                });
            });

            return new Promise(function (resolve) {
                Promise.all(promises).then(function () {
                    _this3.context.hasCache = true;
                    resolve();
                }).catch(resolve);
            });
        }
    }, {
        key: 'runSpritesmith',
        value: function runSpritesmith() {
            var _this4 = this;

            var options = Object.assign({}, this.options.spritesmith, {
                src: this.context.images.map(function (image) {
                    return image.filePath;
                })
            });

            return new Promise(function (resolve, reject) {
                Spritesmith.run(options, function (err, result) {
                    if (err) {
                        return reject(err);
                    }

                    _this4.context.imageData = result.image;
                    _this4.context.images.forEach(function (image) {
                        Object.assign(image, result.coordinates[image.filePath]);
                    });
                    return resolve();
                });
            });
        }
    }, {
        key: 'outputSpriteImage',
        value: function outputSpriteImage() {
            var _this5 = this;

            return Promise.resolve().then(function () {
                return imagemin.buffer(_this5.context.imageData, {
                    use: [pngquant(_this5.options.pngquant)]
                });
            }).then(function (buf) {
                return _this5.context.imageData = buf;
            }).then(function () {
                return new Promise(function (resolve, reject) {
                    fs.outputFile(_this5.context.imagePath, _this5.context.imageData, function (err) {
                        return err ? reject(err) : resolve();
                    });
                });
            });
        }
    }, {
        key: 'createSass',
        value: function createSass() {
            var _getSelectorInfo = this.getSelectorInfo(),
                selectors = _getSelectorInfo.selectors,
                pseudoMap = _getSelectorInfo.pseudoMap;

            var _context = this.context,
                mapName = _context.mapName,
                fileName = _context.fileName;

            var sass = [];

            // variables
            sass.push('\n            $disable-magic-sprite-selectors: false !default;\n            $sprite-selectors: ' + stateClasses.join(', ') + ' !default;\n            $default-sprite-separator: \'-\' !default;\n            $' + mapName + '-sprite-base-class: \'.' + mapName + '-sprite\' !default;\n            $' + mapName + '-sprite-dimensions: false !default;\n            $' + mapName + '-class-separator: $default-sprite-separator !default;');

            // sprite image class
            sass.push('\n            #{$' + mapName + '-sprite-base-class} {\n                background: url(\'' + this.imagePath(fileName) + '?_=' + this.context.hash + '\') no-repeat;\n            }');

            // sprites data
            sass.push('\n            $sprite-magic-' + mapName + ': (' + selectors.map(function (image) {
                return '\n                ' + image.name + ': (\n                    x: ' + px(image.x) + ', y: ' + px(image.y) + ', width: ' + px(image.width) + ', height: ' + px(image.height) + stateClasses.map(function (state) {
                    return !pseudoMap[image.name] || !pseudoMap[image.name][state] ? '' : ', ' + state + ': (' + ['x', 'y'].map(function (prop) {
                        return prop + ': ' + px(pseudoMap[image.name][state][prop]);
                    }).join(', ') + ')';
                }).join('') + '\n                )';
            }).join(',') + '\n            );');

            // width and height function
            sass.push.apply(sass, _toConsumableArray(['width', 'height'].map(function (prop) {
                return '\n            @function ' + mapName + '-sprite-' + prop + '($sprite) {\n                @return map-get(map-get($sprite-magic-' + mapName + ', $sprite), \'' + prop + '\');\n            }';
            })));

            // dimensions mixin
            sass.push('\n            @mixin ' + mapName + '-sprite-dimensions($sprite) {\n                width: ' + mapName + '-sprite-width($sprite);\n                height: ' + mapName + '-sprite-height($sprite);\n            }');

            // background position mixin
            sass.push('\n            @mixin sprite-magic-background-position($sprite-data, $offset-x: 0, $offset-y: 0) {\n                $x: $offset-x - map-get($sprite-data, \'x\');\n                $y: $offset-y - map-get($sprite-data, \'y\');\n                background-position: $x $y;\n            }');

            // state selector
            sass.push('\n            @mixin ' + mapName + '-sprite-selectors(\n                $sprite-name, $full-sprite-name, $offset-x: 0, $offset-y: 0,\n                $unsupported: false, $separator: $' + mapName + '-class-separator\n            ) {\n                $sprite-data: map-get($sprite-magic-' + mapName + ', $sprite-name);\n                @each $state in $sprite-selectors {\n                    @if map-has-key($sprite-data, $state) {\n                        $sprite-class: "#{$full-sprite-name}#{$separator}#{$state}";\n                        &:#{$state}, &.#{$sprite-class} {\n                            @include sprite-magic-background-position(map-get($sprite-data, $state), $offset-x, $offset-y);\n                        }\n                    }\n                }\n            }');

            // sprite mixin
            sass.push('\n            @mixin ' + mapName + '-sprite(\n                $sprite, $dimensions: $' + mapName + '-sprite-dimensions, $offset-x: 0, $offset-y: 0, $unsupported: false,\n                $use-magic-selectors: not $disable-magic-sprite-selectors, $separator: $' + mapName + '-class-separator\n            ) {\n                $sprite-data: map-get($sprite-magic-' + mapName + ', $sprite);\n                @extend #{$' + mapName + '-sprite-base-class};\n                @include sprite-magic-background-position($sprite-data, $offset-x, $offset-y);\n                @if $dimensions {\n                    @include ' + mapName + '-sprite-dimensions($sprite);\n                }\n                @if $use-magic-selectors {\n                    @include ' + mapName + '-sprite-selectors(\n                        $sprite, $sprite, $offset-x, $offset-y, $unsupported, $separator\n                    );\n                }\n            }');

            // all sprites mixin
            sass.push('\n            @mixin all-' + mapName + '-sprites($dimensions: $' + mapName + '-sprite-dimensions) {' + selectors.map(function (image) {
                return '\n                .' + mapName + '-' + image.name + ' {\n                    @include ' + mapName + '-sprite(' + image.name + ', $dimensions);\n                }';
            }).join('') + '\n            }');

            this.context.sass = sass.map(function (_) {
                return _ + '\n';
            }).join('').replace(/^\x20{12}/mg, '').slice(1);
        }
    }, {
        key: 'outputSassFile',
        value: function outputSassFile() {
            var _this6 = this;

            return new Promise(function (resolve, reject) {
                fs.outputFile(_this6.context.sassFilePath, _this6.context.sass, function (err) {
                    if (err) {
                        return reject(err);
                    }
                    return resolve();
                });
            });
        }
    }, {
        key: 'createResult',
        value: function createResult() {
            var msg = this.context.hasCache ? 'use cache' : 'create';
            // eslint-disable-next-line no-console
            console.info('sprite-magic-importer ' + msg + ' file: \'' + this.context.sassFilePath + '\'');

            return { file: this.context.sassFilePath };
        }
    }, {
        key: 'getSelectorInfo',
        value: function getSelectorInfo() {
            var selectors = [],
                pseudoMap = {};

            var regex = new RegExp('^(.*[^-_])[-_](' + stateClasses.join('|') + ')$');

            this.context.images.forEach(function (image) {
                if (regex.test(image.name)) {
                    var imageName = RegExp.$1,
                        pseudoClass = RegExp.$2;

                    (pseudoMap[imageName] || (pseudoMap[imageName] = {}))[pseudoClass] = image;
                } else {
                    selectors.push(image);
                }
            });

            return { selectors: selectors, pseudoMap: pseudoMap };
        }
    }, {
        key: 'imagePath',
        value: function imagePath(fileName) {
            return path.join(path.relative(this.options.http_stylesheets_path, this.options.http_generated_images_path), fileName).replace(/\\/g, '/');
        }
    }]);

    return SpriteMagic;
}();

var index = (function () {
    var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

    var spriteMagic = new SpriteMagic(options);

    return function (url, prev, done) {
        spriteMagic.resolve({ url: url, prev: prev }).then(done).catch(function (err) {
            return setImmediate(function () {
                throw err;
            });
        });
    };
});

module.exports = index;
<commit_msg>build<commit_after>'use strict';

function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }

var fs = _interopDefault(require('fs-extra'));
var glob = _interopDefault(require('glob'));
var path = _interopDefault(require('path'));
var Spritesmith = _interopDefault(require('spritesmith'));
var imagemin = _interopDefault(require('imagemin'));
var pngquant = _interopDefault(require('imagemin-pngquant'));
var CryptoJs = _interopDefault(require('crypto-js'));
var os = _interopDefault(require('os'));

var defaults = {
    project_path: process.cwd(),
    http_path: '/',
    sass_dir: 'sass',
    css_dir: 'stylesheets',
    images_dir: 'images',
    use_cache: true,
    cache_dir: path.resolve(os.tmpdir(), 'sprite-magic-importer'),
    spritesmith: {},
    pngquant: {}
};

var createOptions = function (options) {
    var self = Object.assign({}, defaults, options);

    if (typeof self.generated_images_dir === 'undefined') {
        self.generated_images_dir = self.images_dir;
    }

    return Object.assign({
        sass_path: path.resolve(self.project_path, self.sass_dir),
        images_path: path.resolve(self.project_path, self.images_dir),
        generated_images_path: path.resolve(self.project_path, self.generated_images_dir),
        http_generated_images_path: path.join(self.http_path, self.generated_images_dir),
        http_stylesheets_path: path.join(self.http_path, self.css_dir)
    }, self);
};

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var stateClasses = ['hover', 'target', 'active', 'focus'];

function px(value) {
    return value === 0 ? '0' : value + 'px';
}

var SpriteMagic = function () {
    function SpriteMagic(options) {
        _classCallCheck(this, SpriteMagic);

        this.options = createOptions(options);
    }

    _createClass(SpriteMagic, [{
        key: 'resolve',
        value: function resolve(_ref) {
            var url = _ref.url,
                prev = _ref.prev;

            if (!/\.png$/.test(url)) {
                return Promise.resolve();
            }

            var mapName = path.basename(path.dirname(url));
            return this.process({ url: url, prev: prev, mapName: mapName });
        }
    }, {
        key: 'process',
        value: function process(context) {
            var _this = this;

            this.context = context;

            return Promise.resolve().then(function () {
                return _this.getImagesInfo();
            }).then(function () {
                return _this.createHash();
            }).then(function () {
                return _this.checkCache();
            }).then(function () {
                return _this.context.hasCache || Promise.resolve().then(function () {
                    return _this.runSpritesmith();
                }).then(function () {
                    return _this.outputSpriteImage();
                }).then(function () {
                    return _this.createSass();
                }).then(function () {
                    return _this.outputSassFile();
                });
            }).then(function () {
                return _this.createResult();
            });
        }
    }, {
        key: 'getImagesInfo',
        value: function getImagesInfo() {
            var _this2 = this;

            var srcPath = path.resolve(this.options.images_path, this.context.url);

            return Promise.resolve().then(function () {
                return new Promise(function (resolve, reject) {
                    glob(srcPath, function (err, matches) {
                        if (err) {
                            return reject(err);
                        }
                        _this2.context.images = matches.map(function (filePath) {
                            return Object.assign({ filePath: filePath }, path.parse(filePath));
                        });
                        return resolve();
                    });
                });
            }).then(function () {
                return Promise.all(_this2.context.images.map(function (image) {
                    return new Promise(function (resolve, reject) {
                        fs.stat(image.filePath, function (err, stats) {
                            if (err) {
                                return reject(err);
                            }
                            Object.assign(image, { mtime: stats.mtime.getTime() });
                            return resolve();
                        });
                    });
                }));
            });
        }
    }, {
        key: 'createHash',
        value: function createHash() {
            var fingerprint = this.context.images.map(function (image) {
                return image.filePath + '#' + image.mtime;
            }).concat(JSON.stringify(this.options)).concat(require('../package.json').version) // eslint-disable-line global-require
            .join('\0');
            this.context.hash = CryptoJs.SHA1(fingerprint).toString(CryptoJs.enc.HEX).substr(0, 7);
        }
    }, {
        key: 'checkCache',
        value: function checkCache() {
            var _this3 = this;

            var latestMtime = Math.max.apply(Math, _toConsumableArray(this.context.images.map(function (image) {
                return image.mtime;
            })));
            var cacheFiles = [this.spriteImagePath(), this.spriteSassPath()];

            return new Promise(function (done) {
                Promise.all(cacheFiles.map(function (file) {
                    return new Promise(function (resolve, reject) {
                        fs.stat(file, function (err, stats) {
                            if (err || stats.mtime.getTime() < latestMtime) {
                                return reject();
                            }
                            return resolve();
                        });
                    });
                })).then(function () {
                    _this3.context.hasCache = _this3.options.use_cache;
                    done();
                }).catch(done);
            });
        }
    }, {
        key: 'runSpritesmith',
        value: function runSpritesmith() {
            var _this4 = this;

            var options = Object.assign({}, this.options.spritesmith, {
                src: this.context.images.map(function (image) {
                    return image.filePath;
                })
            });

            return new Promise(function (resolve, reject) {
                Spritesmith.run(options, function (err, result) {
                    if (err) {
                        return reject(err);
                    }
                    _this4.context.imageData = result.image;
                    _this4.context.images.forEach(function (image) {
                        Object.assign(image, result.coordinates[image.filePath]);
                    });
                    return resolve();
                });
            });
        }
    }, {
        key: 'outputSpriteImage',
        value: function outputSpriteImage() {
            var _this5 = this;

            return Promise.resolve().then(function () {
                return imagemin.buffer(_this5.context.imageData, {
                    use: [pngquant(_this5.options.pngquant)]
                });
            }).then(function (buf) {
                return _this5.context.imageData = buf;
            }).then(function () {
                return new Promise(function (resolve, reject) {
                    fs.outputFile(_this5.spriteImagePath(), _this5.context.imageData, function (err) {
                        return err ? reject(err) : resolve();
                    });
                });
            });
        }
    }, {
        key: 'createSass',
        value: function createSass() {
            var _getSelectorInfo = this.getSelectorInfo(),
                selectors = _getSelectorInfo.selectors,
                pseudoMap = _getSelectorInfo.pseudoMap;

            var mapName = this.context.mapName;

            var sass = [];

            // variables
            sass.push('\n            $disable-magic-sprite-selectors: false !default;\n            $sprite-selectors: ' + stateClasses.join(', ') + ' !default;\n            $default-sprite-separator: \'-\' !default;\n            $' + mapName + '-sprite-base-class: \'.' + mapName + '-sprite\' !default;\n            $' + mapName + '-sprite-dimensions: false !default;\n            $' + mapName + '-class-separator: $default-sprite-separator !default;');

            // sprite image class
            sass.push('\n            #{$' + mapName + '-sprite-base-class} {\n                background: url(\'' + this.spriteImageUrl() + '?_=' + this.context.hash + '\') no-repeat;\n            }');

            // sprites data
            sass.push('\n            $sprite-magic-' + mapName + ': (' + selectors.map(function (image) {
                return '\n                ' + image.name + ': (\n                    x: ' + px(image.x) + ', y: ' + px(image.y) + ', width: ' + px(image.width) + ', height: ' + px(image.height) + stateClasses.map(function (state) {
                    return !pseudoMap[image.name] || !pseudoMap[image.name][state] ? '' : ', ' + state + ': (' + ['x', 'y'].map(function (prop) {
                        return prop + ': ' + px(pseudoMap[image.name][state][prop]);
                    }).join(', ') + ')';
                }).join('') + '\n                )';
            }).join(',') + '\n            );');

            // width and height function
            sass.push.apply(sass, _toConsumableArray(['width', 'height'].map(function (prop) {
                return '\n            @function ' + mapName + '-sprite-' + prop + '($sprite) {\n                @return map-get(map-get($sprite-magic-' + mapName + ', $sprite), \'' + prop + '\');\n            }';
            })));

            // dimensions mixin
            sass.push('\n            @mixin ' + mapName + '-sprite-dimensions($sprite) {\n                width: ' + mapName + '-sprite-width($sprite);\n                height: ' + mapName + '-sprite-height($sprite);\n            }');

            // background position mixin
            sass.push('\n            @mixin sprite-magic-background-position($sprite-data, $offset-x: 0, $offset-y: 0) {\n                $x: $offset-x - map-get($sprite-data, \'x\');\n                $y: $offset-y - map-get($sprite-data, \'y\');\n                background-position: $x $y;\n            }');

            // state selector
            sass.push('\n            @mixin ' + mapName + '-sprite-selectors(\n                $sprite-name, $full-sprite-name, $offset-x: 0, $offset-y: 0,\n                $unsupported: false, $separator: $' + mapName + '-class-separator\n            ) {\n                $sprite-data: map-get($sprite-magic-' + mapName + ', $sprite-name);\n                @each $state in $sprite-selectors {\n                    @if map-has-key($sprite-data, $state) {\n                        $sprite-class: "#{$full-sprite-name}#{$separator}#{$state}";\n                        &:#{$state}, &.#{$sprite-class} {\n                            @include sprite-magic-background-position(map-get($sprite-data, $state), $offset-x, $offset-y);\n                        }\n                    }\n                }\n            }');

            // sprite mixin
            sass.push('\n            @mixin ' + mapName + '-sprite(\n                $sprite, $dimensions: $' + mapName + '-sprite-dimensions, $offset-x: 0, $offset-y: 0, $unsupported: false,\n                $use-magic-selectors: not $disable-magic-sprite-selectors, $separator: $' + mapName + '-class-separator\n            ) {\n                $sprite-data: map-get($sprite-magic-' + mapName + ', $sprite);\n                @extend #{$' + mapName + '-sprite-base-class};\n                @include sprite-magic-background-position($sprite-data, $offset-x, $offset-y);\n                @if $dimensions {\n                    @include ' + mapName + '-sprite-dimensions($sprite);\n                }\n                @if $use-magic-selectors {\n                    @include ' + mapName + '-sprite-selectors(\n                        $sprite, $sprite, $offset-x, $offset-y, $unsupported, $separator\n                    );\n                }\n            }');

            // all sprites mixin
            sass.push('\n            @mixin all-' + mapName + '-sprites($dimensions: $' + mapName + '-sprite-dimensions) {' + selectors.map(function (image) {
                return '\n                .' + mapName + '-' + image.name + ' {\n                    @include ' + mapName + '-sprite(' + image.name + ', $dimensions);\n                }';
            }).join('') + '\n            }');

            this.context.sass = sass.map(function (_) {
                return _ + '\n';
            }).join('').replace(/^\x20{12}/mg, '').slice(1);
        }
    }, {
        key: 'outputSassFile',
        value: function outputSassFile() {
            var _this6 = this;

            return new Promise(function (resolve, reject) {
                fs.outputFile(_this6.spriteSassPath(), _this6.context.sass, function (err) {
                    if (err) {
                        return reject(err);
                    }
                    return resolve();
                });
            });
        }
    }, {
        key: 'createResult',
        value: function createResult() {
            if (!this.context.hasCache) {
                var spriteFilePath = path.relative(this.options.project_path, this.spriteImagePath());
                // eslint-disable-next-line no-console
                console.info('Create CSS Sprites: ' + spriteFilePath + '#' + this.context.hash);
            }

            return { file: this.spriteSassPath() };
        }
    }, {
        key: 'getSelectorInfo',
        value: function getSelectorInfo() {
            var selectors = [],
                pseudoMap = {};

            var regex = new RegExp('^(.*[^-_])[-_](' + stateClasses.join('|') + ')$');

            this.context.images.forEach(function (image) {
                if (regex.test(image.name)) {
                    var imageName = RegExp.$1,
                        pseudoClass = RegExp.$2;

                    (pseudoMap[imageName] || (pseudoMap[imageName] = {}))[pseudoClass] = image;
                } else {
                    selectors.push(image);
                }
            });

            return { selectors: selectors, pseudoMap: pseudoMap };
        }
    }, {
        key: 'spriteImageUrl',
        value: function spriteImageUrl() {
            var imageUrlBase = path.dirname(path.normalize(path.join(this.options.http_generated_images_path, this.context.url)));

            if (imageUrlBase[0] === '/') {
                return (imageUrlBase + '.png').replace(/\\/g, '/');
            }

            return path.relative(path.dirname(path.join(this.options.http_stylesheets_path, path.relative(this.options.sass_path, this.context.prev))), imageUrlBase + '.png').replace(/\\/g, '/');
        }
    }, {
        key: 'spriteImagePath',
        value: function spriteImagePath() {
            var imageFileBase = path.dirname(path.resolve(this.options.generated_images_dir, this.context.url));
            return imageFileBase + '.png';
        }
    }, {
        key: 'spriteSassPath',
        value: function spriteSassPath() {
            var fileName = this.context.mapName + '-' + this.context.hash + '.scss';
            return path.resolve(this.options.cache_dir, fileName);
        }
    }]);

    return SpriteMagic;
}();

var index = (function () {
    var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

    var spriteMagic = new SpriteMagic(options);

    return function (url, prev, done) {
        spriteMagic.resolve({ url: url, prev: prev }).then(done).catch(function (err) {
            return setImmediate(function () {
                throw err;
            });
        });
    };
});

module.exports = index;
<|endoftext|>


<commit_before>var utils   = require('./utils')
  , implode = require('implode')

exports.State = require('./state')
exports.initialize = exports.State.init

exports.Template = require('./template')
exports.Fragment = require('./fragment')

exports.Routes = {}

var isServer = exports.isServer = utils.isServer
  , isClient = exports.isClient = utils.isClient
exports.UUID = utils.UUID

exports.register = function(name, helper) {
  implode.register(name, helper, [])
}

if (isClient) {
  var page = require('page')
    , qs   = require('qs')

  window.swac = {
    debug: false,
    State: exports.State,
    navigate: function(path) {
      var ctx = new page.Context(path, null)
      page.dispatch(ctx)
      if (!ctx.unhandled)
        ctx.pushState()
    }
  }

  function sameOrigin(href) {
    var origin = location.protocol + "//" + location.hostname + ":" + location.port
    return href.indexOf('http') == -1 || href.indexOf(origin) === 0
  }

  $(function() {
    $('body').on('click', 'a', function(e) {
      if (e.ctrlKey || e.metaKey) return
      if (Boolean($(this).data('extern'))) return
      if (this.protocol === 'javascript:' || this.protocol === 'data:') return
      if (this.hash || !$(this).attr('href') || $(this).attr('href') == '#') return
      if (!sameOrigin($(this).attr('href'))) return
      e.preventDefault()
      // if (this.pathname !== location.pathname)
      var path = this.pathname + this.search
      if ($(this).data('confirm') && !confirm($(this).data('confirm'))) return
      var ctx = new page.Context(path, {
        trigger: typeof $(this).data('trigger') === 'undefined' ? true : Boolean($(this).data('trigger'))
      })
      page.dispatch(ctx)
      if (!ctx.unhandled && !Boolean($(this).data('silent')))
        ctx.pushState()
    })
    $('body').on('submit', 'form', function(e) {
      if ($(this).data('side') == 'server') return
      var method = $(this).attr('method').toLowerCase()
        , ctx, path = this.action, origin = window.location.protocol + "//" + window.location.host
      if (path.indexOf(origin) === 0)
        path = path.substr(origin.length)
      if (method === 'post') {
        var _method = $(this).find('input[name=_method]')
        if (_method.length) method = _method.val()
        path = '/_' + method + (path === '' ? '/' : path)
        ctx = new page.Context(path, { body: qs.parse($(this).serialize()) })
        page.dispatch(ctx)
      } else {
        if (path.indexOf('?') > -1) path += '&'
        else path += '?'
        path += $(this).serialize()
        ctx = new page.Context(path)
        page.dispatch(ctx)
        if (!ctx.unhandled && !Boolean($(this).data('silent')))
          ctx.pushState()
      }
      if (!ctx.unhandled)
        e.preventDefault()
    })
  })

  var routing    = require('./routing')
  exports.init   = routing.init
  exports.get    = routing.get
  exports.post   = routing.post
  exports.put    = routing.put
  exports.delete = routing.delete
}<commit_msg>improve swac.navigate() method<commit_after>var utils   = require('./utils')
  , implode = require('implode')

exports.State = require('./state')
exports.initialize = exports.State.init

exports.Template = require('./template')
exports.Fragment = require('./fragment')

exports.Routes = {}

var isServer = exports.isServer = utils.isServer
  , isClient = exports.isClient = utils.isClient
exports.UUID = utils.UUID

exports.register = function(name, helper) {
  implode.register(name, helper, [])
}

if (isClient) {
  var page = require('page')
    , qs   = require('qs')

  window.swac = {
    debug: false,
    State: exports.State,
    navigate: function(path, opts) {
      if (!opts) opts = {}
      var ctx = new page.Context(path, null)
      if (opts.trigger !== false) {
        page.dispatch(ctx)
      }
      if (!ctx.unhandled) {
        if (opts.replaceState === true)
          ctx.save()
        else if (!opts.silent)
          ctx.pushState()
      }
    }
  }

  function sameOrigin(href) {
    var origin = location.protocol + "//" + location.hostname + ":" + location.port
    return href.indexOf('http') == -1 || href.indexOf(origin) === 0
  }

  $(function() {
    $('body').on('click', 'a', function(e) {
      if (e.ctrlKey || e.metaKey) return
      if (Boolean($(this).data('extern'))) return
      if (this.protocol === 'javascript:' || this.protocol === 'data:') return
      if (this.hash || !$(this).attr('href') || $(this).attr('href') == '#') return
      if (!sameOrigin($(this).attr('href'))) return
      e.preventDefault()
      // if (this.pathname !== location.pathname)
      var path = this.pathname + this.search
      if ($(this).data('confirm') && !confirm($(this).data('confirm'))) return
      var ctx = new page.Context(path, {
        trigger: typeof $(this).data('trigger') === 'undefined' ? true : Boolean($(this).data('trigger'))
      })
      page.dispatch(ctx)
      if (!ctx.unhandled && !Boolean($(this).data('silent')))
        ctx.pushState()
    })
    $('body').on('submit', 'form', function(e) {
      if ($(this).data('side') == 'server') return
      var method = $(this).attr('method').toLowerCase()
        , ctx, path = this.action, origin = window.location.protocol + "//" + window.location.host
      if (path.indexOf(origin) === 0)
        path = path.substr(origin.length)
      if (method === 'post') {
        var _method = $(this).find('input[name=_method]')
        if (_method.length) method = _method.val()
        path = '/_' + method + (path === '' ? '/' : path)
        ctx = new page.Context(path, { body: qs.parse($(this).serialize()) })
        page.dispatch(ctx)
      } else {
        if (path.indexOf('?') > -1) path += '&'
        else path += '?'
        path += $(this).serialize()
        ctx = new page.Context(path)
        page.dispatch(ctx)
        if (!ctx.unhandled && !Boolean($(this).data('silent')))
          ctx.pushState()
      }
      if (!ctx.unhandled)
        e.preventDefault()
    })
  })

  var routing    = require('./routing')
  exports.init   = routing.init
  exports.get    = routing.get
  exports.post   = routing.post
  exports.put    = routing.put
  exports.delete = routing.delete
}<|endoftext|>


<commit_before>
var gulp = require("gulp");
var del = require("del");
var sequence = require("gulp-sequence");
var typescript = require("gulp-typescript");
var json = require('gulp-json-editor');

gulp.task("clean:build", function() {
    return del(["build"]);
});

gulp.task("clean:package", function() {
    return del(["package"]);
});

gulp.task("clean", sequence("clean:build", "clean:package"));

gulp.task("build", function () {
    var config = typescript.createProject("./tsconfig.json");

    return gulp
        .src("src/**/*.ts")
        .pipe(config())
        .pipe(gulp.dest("build"));
});

gulp.task("watch", function () {
    gulp.watch("src/**/*.ts", ["build"]);
});

gulp.task("package:copy", function () {
    return gulp.src('build/**/*')
        .pipe(gulp.dest('package'));
});

gulp.task('package:license', function() {
    return gulp.src('./LICENSE')
        .pipe(gulp.dest('package'));
});

gulp.task("package:package.json", function () {
    return gulp.src('package.json')
        .pipe(json({ 'main': 'index.js', 'types': 'index.d.ts' }))
        .pipe(gulp.dest('package'));
});

gulp.task("package", sequence("clean:package", "build", "package:copy", "package:license", "package:package.json"));<commit_msg>Added missing clean step from build task<commit_after>
var gulp = require("gulp");
var del = require("del");
var sequence = require("gulp-sequence");
var typescript = require("gulp-typescript");
var json = require('gulp-json-editor');

gulp.task("clean:build", function() {
    return del(["build"]);
});

gulp.task("clean:package", function() {
    return del(["package"]);
});

gulp.task("clean", sequence("clean:build", "clean:package"));

gulp.task("build", function () {
    var config = typescript.createProject("./tsconfig.json");

    return gulp
        .src("src/**/*.ts")
        .pipe(config())
        .pipe(gulp.dest("build"));
});

gulp.task("watch", function () {
    gulp.watch("src/**/*.ts", ["build"]);
});

gulp.task("package:copy", function () {
    return gulp.src('build/**/*')
        .pipe(gulp.dest('package'));
});

gulp.task('package:license', function() {
    return gulp.src('./LICENSE')
        .pipe(gulp.dest('package'));
});

gulp.task("package:package.json", function () {
    return gulp.src('package.json')
        .pipe(json({ 'main': 'index.js', 'types': 'index.d.ts' }))
        .pipe(gulp.dest('package'));
});

gulp.task("package", sequence("clean", "build", "package:copy", "package:license", "package:package.json"));<|endoftext|>


<commit_before>const querystring = require('querystring');

// operators supported
const OPERATORS = new Map();
OPERATORS.set('<>', 'neq');
OPERATORS.set('>=', 'gte');
OPERATORS.set('<=', 'lte');
OPERATORS.set('=', 'eq');
OPERATORS.set('>', 'gt');
OPERATORS.set('<', 'lt');

// string patterns supported
const PATTERN = /^\s?set\s+(.+)\s+where\s+(.+)$/i;

const parse = (expression) => {
    if (typeof expression !== 'string') {
        return null;
    }

    const matches = expression.replace(/\n/g, ' ').match(PATTERN);
    if (matches === null) {
        return null;
    }

    return {
        operation: parseOperation(matches[1].trim()),
        condition: parseCondition(matches[2].trim()),
    };
};

const parseOperation = (expression) => {
    if (typeof expression !== 'string') {
        return null;
    }

    const operations = querystring.parse(expression.replace(/\s+/g, '').replace(/，/g, ','), ',', '=');
    for (const key in operations) {
        operations[key] = parseValue(operations[key]);
    }

    return operations;
};

/**
 * 把条件字符串解析成对象
 */
const parseCondition = (expression) => {
    if (typeof expression !== 'string') {
        return null;
    }

    const conditions = {};
    const tokens = expression
        .replace(/\s*=\s*/g, '=')
        .split(/\s*and\s*/i);   // only AND is supported now

    tokens.forEach((token) => {
        token = token.replace(/\s+/g, '');
        for (const [op, opInWords] of OPERATORS) {
            if (token.indexOf(op) === -1) {
                continue;
            }
            const [key, value] = token.split(op);
            if (typeof conditions[key] === 'undefined') {
                conditions[key] = {};
            }
            conditions[key][opInWords] = parseValue(value);

            return;
        }
    });

    return conditions;
};

const parseValue = (expression) => {
    try {
        const value = JSON.parse(expression);
        return typeof value === 'undefined' ? null : value;
    } catch (e) {
        return expression;
    }
};

module.exports = {
    parse,
    parseOperation,
    parseCondition,
    parseValue,
};

<commit_msg>support multiline string<commit_after>const querystring = require('querystring');

// operators supported
const OPERATORS = new Map();
OPERATORS.set('<>', 'neq');
OPERATORS.set('>=', 'gte');
OPERATORS.set('<=', 'lte');
OPERATORS.set('=', 'eq');
OPERATORS.set('>', 'gt');
OPERATORS.set('<', 'lt');

// string patterns supported
const PATTERN = /^\s?set\s+(.+)\s+where\s+(.+)$/i;

const parse = (expression) => {
    if (typeof expression !== 'string') {
        return null;
    }

    const matches = expression.replace(/\s+/g, ' ').match(PATTERN);
    if (matches === null) {
        return null;
    }

    return {
        operation: parseOperation(matches[1].trim()),
        condition: parseCondition(matches[2].trim()),
    };
};

const parseOperation = (expression) => {
    if (typeof expression !== 'string') {
        return null;
    }

    const operations = querystring.parse(expression.replace(/\s+/g, '').replace(/，/g, ','), ',', '=');
    for (const key in operations) {
        operations[key] = parseValue(operations[key]);
    }

    return operations;
};

/**
 * 把条件字符串解析成对象
 */
const parseCondition = (expression) => {
    if (typeof expression !== 'string') {
        return null;
    }

    const conditions = {};
    const tokens = expression
        .replace(/\s*=\s*/g, '=')
        .split(/\s*and\s*/i);   // only AND is supported now

    tokens.forEach((token) => {
        token = token.replace(/\s+/g, '');
        for (const [op, opInWords] of OPERATORS) {
            if (token.indexOf(op) === -1) {
                continue;
            }
            const [key, value] = token.split(op);
            if (typeof conditions[key] === 'undefined') {
                conditions[key] = {};
            }
            conditions[key][opInWords] = parseValue(value);

            return;
        }
    });

    return conditions;
};

const parseValue = (expression) => {
    try {
        const value = JSON.parse(expression);
        return typeof value === 'undefined' ? null : value;
    } catch (e) {
        return expression;
    }
};

module.exports = {
    parse,
    parseOperation,
    parseCondition,
    parseValue,
};

<|endoftext|>


<commit_before>var jwt = require("jsonwebtoken");
var UnauthorizedError = require("./errors/UnauthorizedError");
var async = require("async");
var AuthPolicy = require("./AuthPolicy");

var DEFAULT_REVOKED_FUNCTION = function(_, __, cb) {
  return cb(null, false);
};

function isFunction(object) {
  return Object.prototype.toString.call(object) === "[object Function]";
}

function wrapStaticSecretInCallback(secret) {
  return function(_, __, cb) {
    return cb(null, secret);
  };
}

module.exports = function(options) {
  if (!options || !options.secret) throw new Error("secret should be set");

  var secretCallback = options.secret;
  var extractPrincipalId = options.extractPrincipalId || (x => x);
  if (typeof extractPrincipalId === "string") {
    const key = extractPrincipalId;
    extractPrincipalId = x => x[key];
  }

  if (!isFunction(secretCallback)) {
    secretCallback = wrapStaticSecretInCallback(secretCallback);
  }

  var isRevokedCallback = options.isRevoked || DEFAULT_REVOKED_FUNCTION;

  var middleware = function(event, context, next) {
    var token;

    if (options.getToken && typeof options.getToken === "function") {
      try {
        token = options.getToken(event);
      } catch (e) {
        return next(e);
      }
    } else if (event.type === "TOKEN" || event.type === "REQUEST") {
      const inputToken =
        event.type === "REQUEST"
          ? (event.headers || {}).authorization
          : event.authorizationToken;

      var parts = (inputToken || "").split(" ");
      if (parts.length === 2) {
        var scheme = parts[0];
        var credentials = parts[1];

        if (/^Bearer$/i.test(scheme)) {
          token = credentials;
        } else {
          return next(
            new UnauthorizedError("credentials_bad_scheme", {
              message: "Format is Authorization: Bearer [token]"
            })
          );
        }
      } else if (inputToken) {
        return next(
          new UnauthorizedError("credentials_bad_format", {
            message: "Format is Authorization: Bearer [token]"
          })
        );
      }
    }

    if (!token) {
      return next(
        new UnauthorizedError("credentials_required", {
          message: "No authorization token was found"
        })
      );
    }

    var dtoken;

    try {
      dtoken = jwt.decode(token, { complete: true }) || {};
    } catch (err) {
      return next(new UnauthorizedError("invalid_token", err));
    }

    async.waterfall(
      [
        function getSecret(callback) {
          var arity = secretCallback.length;
          if (arity == 4) {
            secretCallback({}, dtoken.header, dtoken.payload, callback);
          } else {
            // arity == 3
            secretCallback({}, dtoken.payload, callback);
          }
        },
        function verifyToken(secret, callback) {
          jwt.verify(token, secret, options, function(err, decoded) {
            if (err) {
              callback(new UnauthorizedError("invalid_token", err));
            } else {
              callback(null, decoded);
            }
          });
        },
        function checkRevoked(decoded, callback) {
          isRevokedCallback({}, dtoken.payload, function(err, revoked) {
            if (err) {
              callback(err);
            } else if (revoked) {
              callback(
                new UnauthorizedError("revoked_token", {
                  message: "The token has been revoked."
                })
              );
            } else {
              callback(null, decoded);
            }
          });
        }
      ],
      function(err, result) {
        if (err) {
          return next(err);
        }

        const principalId = extractPrincipalId(result);

        // parse the ARN from the incoming event
        var apiOptions = {};
        var tmp = event.methodArn.split(":");
        var apiGatewayArnTmp = tmp[5].split("/");
        var awsAccountId = tmp[4];
        apiOptions.region = tmp[3];
        apiOptions.restApiId = apiGatewayArnTmp[0];
        apiOptions.stage = apiGatewayArnTmp[1];

        // AuthPolicy was taken from AWS Blueprint
        const policy = new AuthPolicy(principalId, awsAccountId, apiOptions);

        // Allow user access to all methods
        policy.allowAllMethods();

        next(null, policy.build());
      }
    );
  };

  middleware.UnauthorizedError = UnauthorizedError;

  return middleware;
};

module.exports.UnauthorizedError = UnauthorizedError;
<commit_msg>Return unauthorized on authentication failure so AWS returns 401<commit_after>var jwt = require("jsonwebtoken");
var UnauthorizedError = require("./errors/UnauthorizedError");
var async = require("async");
var AuthPolicy = require("./AuthPolicy");

var DEFAULT_REVOKED_FUNCTION = function(_, __, cb) {
  return cb(null, false);
};

function isFunction(object) {
  return Object.prototype.toString.call(object) === "[object Function]";
}

function wrapStaticSecretInCallback(secret) {
  return function(_, __, cb) {
    return cb(null, secret);
  };
}

module.exports = function(options) {
  if (!options || !options.secret) throw new Error("secret should be set");

  var secretCallback = options.secret;
  var extractPrincipalId = options.extractPrincipalId || (x => x);
  if (typeof extractPrincipalId === "string") {
    const key = extractPrincipalId;
    extractPrincipalId = x => x[key];
  }

  if (!isFunction(secretCallback)) {
    secretCallback = wrapStaticSecretInCallback(secretCallback);
  }

  var isRevokedCallback = options.isRevoked || DEFAULT_REVOKED_FUNCTION;

  var middleware = function(event, context, next) {
    var token;

    if (options.getToken && typeof options.getToken === "function") {
      try {
        token = options.getToken(event);
      } catch (e) {
        return next(e);
      }
    } else if (event.type === "TOKEN" || event.type === "REQUEST") {
      const inputToken =
        event.type === "REQUEST"
          ? (event.headers || {}).authorization
          : event.authorizationToken;

      var parts = (inputToken || "").split(" ");
      if (parts.length === 2) {
        var scheme = parts[0];
        var credentials = parts[1];

        if (/^Bearer$/i.test(scheme)) {
          token = credentials;
        } else {
          console.error("Format is Authorization: Bearer [token]", err);
          return next("Unauthorized");
        }
      } else if (inputToken) {
        console.error("Format is Authorization: Bearer [token]", err);
        return next("Unauthorized");
      }
    }

    if (!token) {
      console.error("No authorization token was found", err);
      return next("Unauthorized");
    }

    var dtoken;

    try {
      dtoken = jwt.decode(token, { complete: true }) || {};
    } catch (err) {
      console.error("Invalid token", err);
      return next("Unauthorized");
    }

    async.waterfall(
      [
        function getSecret(callback) {
          var arity = secretCallback.length;
          if (arity == 4) {
            secretCallback({}, dtoken.header, dtoken.payload, callback);
          } else {
            // arity == 3
            secretCallback({}, dtoken.payload, callback);
          }
        },
        function verifyToken(secret, callback) {
          jwt.verify(token, secret, options, function(err, decoded) {
            if (err) {
              console.error("Invalid token", err);
              callback("Unauthorized");
            } else {
              callback(null, decoded);
            }
          });
        },
        function checkRevoked(decoded, callback) {
          isRevokedCallback({}, dtoken.payload, function(err, revoked) {
            if (err) {
              console.error("Invalid token", err);
              callback("Unauthorized");
            } else if (revoked) {
              console.error("The token has been revoked");
              callback("Unauthorized");
            } else {
              callback(null, decoded);
            }
          });
        }
      ],
      function(err, result) {
        if (err) {
          return next(err);
        }

        const principalId = extractPrincipalId(result);

        // parse the ARN from the incoming event
        var apiOptions = {};
        var tmp = event.methodArn.split(":");
        var apiGatewayArnTmp = tmp[5].split("/");
        var awsAccountId = tmp[4];
        apiOptions.region = tmp[3];
        apiOptions.restApiId = apiGatewayArnTmp[0];
        apiOptions.stage = apiGatewayArnTmp[1];

        // AuthPolicy was taken from AWS Blueprint
        const policy = new AuthPolicy(principalId, awsAccountId, apiOptions);

        // Allow user access to all methods
        policy.allowAllMethods();

        next(null, policy.build());
      }
    );
  };

  middleware.UnauthorizedError = UnauthorizedError;

  return middleware;
};

module.exports.UnauthorizedError = UnauthorizedError;
<|endoftext|>


<commit_before>var gulp = require('gulp');
var runSequence = require('run-sequence');

// gulpディレクトリのタスク読み込み
var tasks = require('./gulp/load');
global.$ = tasks.plugins;
global.config = tasks.config;
global.isProduction = false;

gulp.task('watch', function () {
    gulp.watch(config.path.ejs.watch, ['ejs']);
    gulp.watch(config.path.html.src, ['html']);
    gulp.watch(config.path.style.src, ['style']);
    gulp.watch(config.path.sprite.watch, ['sprite', 'style', 'copy']);
    gulp.watch(config.path.images, ['copy']);
});
gulp.task('build', ['clean'], function (callback) {
    return runSequence('sprite', ['ejs', 'script', 'style', 'copy'], callback);
});
gulp.task('production',function () {
    global.isProduction = true;
    return runSequence('build', callback);
});
gulp.task('default', ['server', 'watch', 'watchScript', 'testWatch'], function () {
});<commit_msg>callback引数を忘れていた<commit_after>var gulp = require('gulp');
var runSequence = require('run-sequence');

// gulpディレクトリのタスク読み込み
var tasks = require('./gulp/load');
global.$ = tasks.plugins;
global.config = tasks.config;
global.isProduction = false;

gulp.task('watch', function () {
    gulp.watch(config.path.ejs.watch, ['ejs']);
    gulp.watch(config.path.html.src, ['html']);
    gulp.watch(config.path.style.src, ['style']);
    gulp.watch(config.path.sprite.watch, ['sprite', 'style', 'copy']);
    gulp.watch(config.path.images, ['copy']);
});
gulp.task('build', ['clean'], function (callback) {
    return runSequence('sprite', ['ejs', 'script', 'style', 'copy'], callback);
});
gulp.task('production',function (callback) {
    global.isProduction = true;
    return runSequence('build', callback);
});
gulp.task('default', ['server', 'watch', 'watchScript', 'testWatch'], function () {
});<|endoftext|>