<commit_before>import Ember from 'ember';
import Remarkable from 'remarkable';
import hljs from 'hljs';
import layout from '../templates/components/md-text';

const {computed, HTMLBars} = Ember;

export default Ember.Component.extend({
  layout,

  tagName: '',

  text: '',
  typographer: false,
  linkify: false,
  html: false,
  extensions: true,
  dynamic: false,

  parsedMarkdownUnsafe: computed('text', 'html', 'typographer', 'linkify', function() {
    var md = new Remarkable({
      typographer: this.get('typographer'),
      linkify:     this.get('linkify'),
      html:        this.get('html'),

      highlight: function (str, lang) {
        if (lang === 'text' || lang === 'no-highlight') {
          return '';
        }

        if (lang && hljs.getLanguage(lang)) {
          try {
            return hljs.highlight(lang, str).value;
          } catch (err) {
          }
        }

        try {
          return hljs.highlightAuto(str).value;
        } catch (err) {
        }

        return '';
      }
    });

    if (this.get('extensions')) {
      md.core.ruler.enable([
        'abbr'
      ]);
      md.block.ruler.enable([
        'footnote',
        'deflist'
      ]);
      md.inline.ruler.enable([
        'footnote_inline',
        'ins',
        'mark',
        'sub',
        'sup'
      ]);
    }

    let plugins = this.get('plugins');
    if (plugins) {
      plugins.forEach((plugin) => md.use(plugin));
    }

    return md.render(this.get('text'));
  }),

  parsedMarkdown: computed('parsedMarkdownUnsafe', function () {
    const parsedMarkdownUnsafe = this.get('parsedMarkdownUnsafe');
    return new Ember.String.htmlSafe(parsedMarkdownUnsafe);
  }),

  precompiledTemplate: computed('parsedMarkdownUnsafe', function () {
    const parsedMarkdownUnsafe = this.get('parsedMarkdownUnsafe');
    return HTMLBars.compile(parsedMarkdownUnsafe, false);
  }),
});
<commit_msg>Only use highlight if not excluded an refactor highlight() as seperate function<commit_after>import Ember from 'ember';
import Remarkable from 'remarkable';
import layout from '../templates/components/md-text';

const { computed, HTMLBars } = Ember;

export default Ember.Component.extend({
  layout,

  tagName: '',

  text: '',
  typographer: false,
  linkify: false,
  html: false,
  extensions: true,
  dynamic: false,
  highlightJsExcluded: Ember.computed(function () {
    let config = Ember.getOwner(this).resolveRegistration('config:environment');
    return config.remarkable.excludeHighlightJs || false;
  }),
  highlight: Ember.computed('highlightJsExcluded', function() {
    let highlightJsExcluded = this.get('highlightJsExcluded');
    return function (str, lang) {
      if (!highlightJsExcluded) {
        if (lang === 'text' || lang === 'no-highlight') {
          return '';
        }

        if (lang && hljs.getLanguage(lang)) {
          try {
            return hljs.highlight(lang, str).value;
          } catch (err) {
          }
        }

        try {
          return hljs.highlightAuto(str).value;
        } catch (err) {
        }
      }

      return '';
    }
  }),

  parsedMarkdownUnsafe: computed('text', 'html', 'typographer', 'linkify', function () {
    var md = new Remarkable({
      typographer: this.get('typographer'),
      linkify: this.get('linkify'),
      html: this.get('html'),
      highlight: this.get('highlight')
    });

    if (this.get('extensions')) {
      md.core.ruler.enable([
        'abbr'
      ]);
      md.block.ruler.enable([
        'footnote',
        'deflist'
      ]);
      md.inline.ruler.enable([
        'footnote_inline',
        'ins',
        'mark',
        'sub',
        'sup'
      ]);
    }

    let plugins = this.get('plugins');
    if (plugins) {
      plugins.forEach((plugin) => md.use(plugin));
    }

    return md.render(this.get('text'));
  }),

  parsedMarkdown: computed('parsedMarkdownUnsafe', function () {
    const parsedMarkdownUnsafe = this.get('parsedMarkdownUnsafe');
    return new Ember.String.htmlSafe(parsedMarkdownUnsafe);
  }),

  precompiledTemplate: computed('parsedMarkdownUnsafe', function () {
    const parsedMarkdownUnsafe = this.get('parsedMarkdownUnsafe');
    return HTMLBars.compile(parsedMarkdownUnsafe, false);
  })
});
<|endoftext|>


<commit_before>Kwc.Directories.Item.Directory.GridPanel = Ext.extend(Kwf.Binding.ProxyPanel,
{
    layout: 'border',

    initComponent: function() {
        this.grid = new Kwf.Auto.GridPanel({
            controllerUrl: this.controllerUrl,
            multiFileUpload: this.multiFileUpload,
            region: 'center',
            baseParams: this.baseParams
        });
        this.proxyItem = this.grid;
        this.items = [this.grid];

        // Add multiFileUpload field if set
        if (this.multiFileUpload) {
            this.multiFileUploadPanel = new Kwf.Utils.MultiFileUploadPanel(Ext.applyIf({
                border: false,
                region: 'south',
                height: 50,
                bodyStyle: 'padding-top: 15px; padding-left:80px;',
                controllerUrl: this.controllerUrl,
                baseParams: this.baseParams
            }), this.multiFileUpload);
            this.multiFileUploadPanel.on('uploaded', function() {
                this.grid.reload();
            }, this);
            this.items.push(this.multiFileUploadPanel);
        }

        Kwc.Directories.Item.Directory.GridPanel.superclass.initComponent.call(this);
    },

    applyBaseParams: function(baseParams) {
        if (this.multiFileUploadPanel) {
            this.multiFileUploadPanel.applyBaseParams(baseParams);
        }
        return Kwc.Directories.Item.Directory.GridPanel.superclass.applyBaseParams.apply(this, arguments);
    },
    setBaseParams : function(baseParams) {
        if (this.multiFileUploadPanel) {
            this.multiFileUploadPanel.setBaseParams(baseParams);
        }
        return Kwc.Directories.Item.Directory.GridPanel.superclass.setBaseParams.apply(this, arguments);
    },
    addBinding: function (bindForm) {
        this.proxyItem.addBinding(bindForm);
    }
});

Ext.reg('kwc.directories.item.directory', Kwc.Directories.Item.Directory.GridPanel);
<commit_msg>fix for item directory<commit_after>Kwc.Directories.Item.Directory.GridPanel = Ext.extend(Kwf.Binding.ProxyPanel,
{
    layout: 'border',

    initComponent: function() {
        this.grid = new Kwf.Auto.GridPanel({
            controllerUrl: this.controllerUrl,
            multiFileUpload: this.multiFileUpload,
            region: 'center',
            baseParams: this.baseParams
        });
        this.proxyItem = this.grid;
        this.items = [this.grid];

        // Add multiFileUpload field if set
        if (this.multiFileUpload) {
            this.multiFileUploadPanel = new Kwf.Utils.MultiFileUploadPanel(Ext.applyIf({
                border: false,
                region: 'south',
                height: 50,
                bodyStyle: 'padding-top: 15px; padding-left:80px;',
                controllerUrl: this.controllerUrl,
                baseParams: this.baseParams
            }), this.multiFileUpload);
            this.multiFileUploadPanel.on('uploaded', function() {
                this.grid.reload();
            }, this);
            this.items.push(this.multiFileUploadPanel);
        }

        Kwc.Directories.Item.Directory.GridPanel.superclass.initComponent.call(this);
    },

    applyBaseParams: function(baseParams) {
        if (this.multiFileUploadPanel) {
            this.multiFileUploadPanel.applyBaseParams(baseParams);
        }
        return Kwc.Directories.Item.Directory.GridPanel.superclass.applyBaseParams.apply(this, arguments);
    },
    setBaseParams : function(baseParams) {
        if (this.multiFileUploadPanel) {
            this.multiFileUploadPanel.setBaseParams(baseParams);
        }
        return Kwc.Directories.Item.Directory.GridPanel.superclass.setBaseParams.apply(this, arguments);
    },
    addBinding: function (bindForm) {
        this.proxyItem.addBinding(bindForm);
    }
});
<|endoftext|>


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

var fs = require('fs');

var fmt = require('fmt');
var async = require('async');
var inspect   = require('eyes').inspector();

var awssum    = require('awssum');
var amazon    = awssum.load('amazon/amazon');
var S3        = awssum.load('amazon/s3').S3;

var accessKeyId     = process.env.ACCESS_KEY_ID;
var secretAccessKey = process.env.SECRET_ACCESS_KEY;
var awsAccountId    = process.env.AWS_ACCOUNT_ID;

// --------------------------------------------------------------------------------------------------------------------

var argv = require('optimist')
    .usage('Usage: $0 --bucket name [files...]')

    .demand('b')
    .alias('b', 'bucket')
    .describe('b', 'bucket to sync with')

    .alias('c', 'concurrency')
    .default('c', 3)
    .describe('c', 'concurrency level for uploads/downloads')

    .describe('debug', 'to turn debugging on')
    .argv;

// --------------------------------------------------------------------------------------------------------------------

var s3 = new S3({
    accessKeyId     : accessKeyId,
    secretAccessKey : secretAccessKey,
    awsAccountId    : awsAccountId,
    region          : amazon.US_EAST_1
});

fmt.sep();
fmt.title('amazon-s3-sync-up.js');
fmt.field('Bucket', argv.bucket);
fmt.line();

// --------------------------------------------------------------------------------------------------------------------

// set up some queues which we can put things onto
var s3Objects = {};
var deleteObjectQueue = async.queue(deleteObject, argv.concurrency);
var deleteFileQueue   = async.queue(deleteFile,   argv.concurrency);

// put all the files onto the first queue to delete
argv._.forEach(function(filename, i) {
    deleteObjectQueue.push(filename);
});

function deleteObject(filename, callback) {
    var opts = {
        'BucketName' : argv.bucket,
        'ObjectName' : filename,
    };

    s3.DeleteObject(opts, function(err, data) {
        if (err) {
            fmt.field('ObjectDeleteFailed', filename);
            callback();
            return;
        }

        deleteFileQueue.push(filename);
        callback();
    })
}

function deleteFile(filename, callback) {
    fs.unlink(filename, function(err) {
        if (err) {
            fmt.field('FileDeleteFailed', filename);
            callback();
            return;
        }

        fmt.field('Deleted', filename);
        callback();
    });
}

// --------------------------------------------------------------------------------------------------------------------
<commit_msg>Make sure the correct title is used<commit_after>#!/usr/bin/env node
// --------------------------------------------------------------------------------------------------------------------

var fs = require('fs');

var fmt = require('fmt');
var async = require('async');
var inspect   = require('eyes').inspector();

var awssum    = require('awssum');
var amazon    = awssum.load('amazon/amazon');
var S3        = awssum.load('amazon/s3').S3;

var accessKeyId     = process.env.ACCESS_KEY_ID;
var secretAccessKey = process.env.SECRET_ACCESS_KEY;
var awsAccountId    = process.env.AWS_ACCOUNT_ID;

// --------------------------------------------------------------------------------------------------------------------

var argv = require('optimist')
    .usage('Usage: $0 --bucket name [files...]')

    .demand('b')
    .alias('b', 'bucket')
    .describe('b', 'bucket to sync with')

    .alias('c', 'concurrency')
    .default('c', 3)
    .describe('c', 'concurrency level for uploads/downloads')

    .describe('debug', 'to turn debugging on')
    .argv;

// --------------------------------------------------------------------------------------------------------------------

var s3 = new S3({
    accessKeyId     : accessKeyId,
    secretAccessKey : secretAccessKey,
    awsAccountId    : awsAccountId,
    region          : amazon.US_EAST_1
});

fmt.sep();
fmt.title('amazon-s3-delete.js');
fmt.field('Bucket', argv.bucket);
fmt.line();

// --------------------------------------------------------------------------------------------------------------------

// set up some queues which we can put things onto
var s3Objects = {};
var deleteObjectQueue = async.queue(deleteObject, argv.concurrency);
var deleteFileQueue   = async.queue(deleteFile,   argv.concurrency);

// put all the files onto the first queue to delete
argv._.forEach(function(filename, i) {
    deleteObjectQueue.push(filename);
});

function deleteObject(filename, callback) {
    var opts = {
        'BucketName' : argv.bucket,
        'ObjectName' : filename,
    };

    s3.DeleteObject(opts, function(err, data) {
        if (err) {
            fmt.field('ObjectDeleteFailed', filename);
            callback();
            return;
        }

        deleteFileQueue.push(filename);
        callback();
    })
}

function deleteFile(filename, callback) {
    fs.unlink(filename, function(err) {
        if (err) {
            fmt.field('FileDeleteFailed', filename);
            callback();
            return;
        }

        fmt.field('Deleted', filename);
        callback();
    });
}

// --------------------------------------------------------------------------------------------------------------------
<|endoftext|>


<commit_before>/*
---

name: Entity

description: Provides the base class for every objects that are displayed
             through an element.

license: MIT-style license.

authors:
	- Jean-Philippe Dery (jeanphilippe.dery@gmail.com)

requires:
	- Core/Class
	- Core/Class.Extras
	- Class-Extras/Class.Binds

provides:
	- Entity

...
*/

if (!window.Moobile) window.Moobile = {};

Moobile.Entity = new Class({

	Implements: [
		Events,
		Options,
		Class.Binds
	],

	name: null,

	element: null,

	children: [],

	owner: null,

	window: null,

	options: {
		className: null,
		tagName: 'div',
	},

	initialize: function(element, options, name) {

		this.name = name;

		this.setOptions(options);
		this.setElement(element);

		var className = this.options.className;
		if (className) {
			this.element.addClass(className);
		}

		this.setup();
		this.attachEvents();

		return this;
	},

	setup: function() {
		return this;
	},

	teardown: function() {
		return this;
	},

	destroy: function() {

		this.detachEvents();

		this.children.each(function(child){child.destroy()});
		this.children = null;

		this.teardown();

		this.removeFromParent();

		this.element.destroy();
		this.element = null;
		this.window = null;

		return this;
	},

	attachEvents: function() {
		this.element.addEvent('click', this.bound('onClick'));
		this.element.addEvent('mouseup', this.bound('onMouseUp'))
		this.element.addEvent('mousedown', this.bound('onMouseDown'));
		return this;
	},

	detachEvents: function() {
		this.element.removeEvent('click', this.bound('onClick'));
		this.element.removeEvent('mouseup', this.bound('onMouseUp'));
		this.element.removeEvent('mousedown', this.bound('onMouseDown'));
		return this;
	},

	addChild: function(child, where, relative) {

		if (this.children.contains(child))
			return this;

		this.willAddChild(child);

		var element = child.getElement();

		if (!this.element.contains(element)) {

			var context = document.id(relative);
			if (context == null) {
				context = this.element;
			} else if (!this.element.contains(context)) {
				throw new Error('You are trying to add a child relative to an element that does not belong to this entity');
			}

			element.inject(context, where);
		}

		this.children.push(child);

		child.ownerWillChange(this);
		child.setOwner(this);
		child.setWindow(this.window);
		child.ownerDidChange(this);

		this.didAddChild(child);

		return this;
	},

	getChild: function(name) {
		return this.children.find(function(children) {
			return children.getName() == name;
		});
	},

	getChildAt: function(index) {
		return this.children[index] || null;
	},

	replaceChild: function(replace, child) {
		return this.addChild(child, 'before', replace).removeChild(replace);
	},

	removeChild: function(child) {

		if (!this.children.contains(child))
			return this;

		this.willRemoveChild(child);
		child.ownerWillChange(null);
		child.setOwner(null);
		child.setWindow(null);
		child.ownerDidChange(null);

		child.getElement().dispose();

		this.children.erase(child);
		this.didRemoveChild(child);

		return this;
	},

	removeFromParent: function() {
		var parent = this.owner || this.window;
		if (parent) parent.removeChild(this);
		return this;
	},

	show: function() {
		this.willShow();
		this.element.show();
		this.didShow();
		return this;
	},

	hide: function() {
		this.willHide();
		this.element.hide();
		this.didHide();
		return this;
	},

	setWindow: function(window) {
		this.window = window;
		return this;
	},

	getWindow: function(window) {
		return this.window;
	},

	getName: function() {
		return this.name;
	},

	setElement: function(element) {

		if (this.element)
			return;

		var root = document.id(element);
		if (root == null) {
			root = new Element(this.options.tagName);
			if (typeof element == 'string' && element.trim().match(/^<\s*([^ >]+)[^>]*>.*?<\/\s*\1\s*>$/mig)) {
				root = root.set('html', element).getElement(':first-child');
			}
		}

		this.element = root;

		return this;
	},

	getElement: function(selector) {
		return selector
			? this.element.getElement(selector)
			: this.element;
	},

	getElements: function(selector) {
		return this.element.getElements(selector);
	},

	setOwner: function(owner) {
		this.owner = owner;
		return this;
	},

	getOwner: function() {
		return this.owner;
	},

	getChildren: function() {
		return this.children;
	},

	getSize: function() {
		return this.element.getSize();
	},

	ownerWillChange: function(owner) {
		return this;
	},

	ownerDidChange: function(owner) {
		return this;
	},

	willAddChild: function(child) {
		return this;
	},

	didAddChild: function(child) {
		return this;
	},

	willRemoveChild: function(child) {
		return this;
	},

	didRemoveChild: function(child) {
		return this;
	},

	willShow: function() {
		return this;
	},

	didShow: function() {
		return this;
	},

	willHide: function() {
		return this;
	},

	didHide: function() {
		return this;
	},

	onClick: function(e) {
		e.target = this;
		this.fireEvent('click', e);
		return this;
	},

	onMouseUp: function(e) {
		e.target = this;
		this.fireEvent('mouseup', e);
		return this;
	},

	onMouseDown: function(e) {
		e.target = this;
		this.fireEvent('mousedown', e);
		return this;
	},

	toElement: function() {
		return this.element;
	}

});<commit_msg>Added a didBecomeReady method and the code to handle it<commit_after>/*
---

name: Entity

description: Provides the base class for every objects that are displayed
             through an element.

license: MIT-style license.

authors:
	- Jean-Philippe Dery (jeanphilippe.dery@gmail.com)

requires:
	- Core/Class
	- Core/Class.Extras
	- Class-Extras/Class.Binds

provides:
	- Entity

...
*/

if (!window.Moobile) window.Moobile = {};

Moobile.Entity = new Class({

	Implements: [
		Events,
		Options,
		Class.Binds
	],

	name: null,

	element: null,

	children: [],

	owner: null,

	window: null,

	ready: false,

	options: {
		className: null,
		tagName: 'div',
	},

	initialize: function(element, options, name) {

		this.name = name;

		this.setOptions(options);
		this.setElement(element);

		var className = this.options.className;
		if (className) {
			this.element.addClass(className);
		}

		this.setup();
		this.attachEvents();

		return this;
	},

	setup: function() {
		return this;
	},

	teardown: function() {
		return this;
	},

	destroy: function() {

		this.detachEvents();

		this.children.each(function(child){child.destroy()});
		this.children = null;

		this.teardown();

		this.removeFromParent();

		this.element.destroy();
		this.element = null;
		this.window = null;
		this.ready = false;

		return this;
	},

	attachEvents: function() {
		this.element.addEvent('click', this.bound('onClick'));
		this.element.addEvent('mouseup', this.bound('onMouseUp'))
		this.element.addEvent('mousedown', this.bound('onMouseDown'));
		return this;
	},

	detachEvents: function() {
		this.element.removeEvent('click', this.bound('onClick'));
		this.element.removeEvent('mouseup', this.bound('onMouseUp'));
		this.element.removeEvent('mousedown', this.bound('onMouseDown'));
		return this;
	},

	addChild: function(child, where, relative) {

		if (this.children.contains(child))
			return this;

		this.willAddChild(child);

		var element = child.getElement();

		if (!this.element.contains(element)) {

			var context = document.id(relative);
			if (context == null) {
				context = this.element;
			} else if (!this.element.contains(context)) {
				throw new Error('You are trying to add a child relative to an element that does not belong to this entity');
			}

			element.inject(context, where);
		}

		this.children.push(child);

		child.ownerWillChange(this);
		child.setOwner(this);
		child.setWindow(this.window);
		child.ownerDidChange(this);

		this.didAddChild(child);

		var ready = function() {
			child.setReady(true);
			child.didBecomeReady();
		};

		if (this.ready == false) {
			this.addEvent('ready:once', ready);
		} else {
			ready();
		}

		return this;
	},

	getChild: function(name) {
		return this.children.find(function(children) {
			return children.getName() == name;
		});
	},

	getChildAt: function(index) {
		return this.children[index] || null;
	},

	replaceChild: function(replace, child) {
		return this.addChild(child, 'before', replace).removeChild(replace);
	},

	removeChild: function(child) {

		if (!this.children.contains(child))
			return this;

		var element = child.getElement();

		this.willRemoveChild(child);

		child.ownerWillChange(null);
		child.setOwner(null);
		child.setWindow(null);
		child.ownerDidChange(null);
		child.setReady(false);

		element.dispose();

		this.children.erase(child);

		this.didRemoveChild(child);

		return this;
	},

	removeFromParent: function() {
		var parent = this.owner || this.window;
		if (parent) parent.removeChild(this);
		return this;
	},

	show: function() {
		this.willShow();
		this.element.show();
		this.didShow();
		return this;
	},

	hide: function() {
		this.willHide();
		this.element.hide();
		this.didHide();
		return this;
	},

	setWindow: function(window) {
		this.window = window;
		return this;
	},

	getWindow: function(window) {
		return this.window;
	},

	getName: function() {
		return this.name;
	},

	setElement: function(element) {

		if (this.element)
			return;

		var root = document.id(element);
		if (root == null) {
			root = new Element(this.options.tagName);
			if (typeof element == 'string' && element.trim().match(/^<\s*([^ >]+)[^>]*>.*?<\/\s*\1\s*>$/mig)) {
				root = root.set('html', element).getElement(':first-child');
			}
		}

		this.element = root;

		return this;
	},

	getElement: function(selector) {
		return selector
			? this.element.getElement(selector)
			: this.element;
	},

	getElements: function(selector) {
		return this.element.getElements(selector);
	},

	setOwner: function(owner) {
		this.owner = owner;
		return this;
	},

	getOwner: function() {
		return this.owner;
	},

	getChildren: function() {
		return this.children;
	},

	getSize: function() {
		return this.element.getSize();
	},

	setReady: function(ready) {

		if (this.ready != ready) {
			this.ready = ready;
			if (this.ready) {
				this.fireEvent('ready');
			}
		}

		return this;
	},

	isReady: function() {
		return this.ready;
	},

	didBecomeReady: function() {
		return this;
	},

	willAddChild: function(child) {
		return this;
	},

	didAddChild: function(child) {
		return this;
	},

	willRemoveChild: function(child) {
		return this;
	},

	didRemoveChild: function(child) {
		return this;
	},

	willShow: function() {
		return this;
	},

	didShow: function() {
		return this;
	},

	willHide: function() {
		return this;
	},

	didHide: function() {
		return this;
	},

	ownerWillChange: function(owner) {
		return this;
	},

	ownerDidChange: function(owner) {
		return this;
	},

	onClick: function(e) {
		e.target = this;
		this.fireEvent('click', e);
		return this;
	},

	onMouseUp: function(e) {
		e.target = this;
		this.fireEvent('mouseup', e);
		return this;
	},

	onMouseDown: function(e) {
		e.target = this;
		this.fireEvent('mousedown', e);
		return this;
	},

	toElement: function() {
		return this.element;
	}

});<|endoftext|>


<commit_before>'use strict';

var isDate         = require('es5-ext/date/is-date')
  , i              = require('es5-ext/function/i')
  , isFunction     = require('es5-ext/function/is-function')
  , assign         = require('es5-ext/object/assign')
  , create         = require('es5-ext/object/create')
  , mixin          = require('es5-ext/object/mixin')
  , setPrototypeOf = require('es5-ext/object/set-prototype-of')
  , isRegExp     = require('es5-ext/reg-exp/is-reg-exp')
  , d              = require('d/d')
  , lazy           = require('d/lazy')
  , DbjsError      = require('../error')
  , Event          = require('../event')
  , ObjectsSet     = require('../objects-set')
  , turnPrototype  = require('../utils/propagate-prototype-turn').object
  , serialize      = require('../serialize/value')
  , getMessage     = require('../utils/get-sub-error-message')
  , updateEnum     = require('../utils/update-enumerability')
  , unserialize    = require('../unserialize/key')

  , push = Array.prototype.push, slice = Array.prototype.slice
  , defineProperties = Object.defineProperties
  , defineProperty = Object.defineProperty, keys = Object.keys
  , getPrototypeOf = Object.getPrototypeOf
  , isValidTypeName = RegExp.prototype.test.bind(/^[A-Z][0-9a-zA-Z]*$/)
  , typeMap = { boolean: 1, number: 2, string: 3, function: 4,  object: 4 }
  , getObjectType
  , destroy = function (sKey) { this[sKey]._destroy_(); }
  , updateObjEnum;

updateObjEnum = function (obj) {
	var sKey, descs = obj.__descriptors__, desc;
	for (sKey in descs) {
		desc = descs[sKey];
		if (desc._reverse_) continue;
		if (desc.nested || desc.multiple) updateEnum(obj, sKey, true);
	}
	return obj;
};

getObjectType = function (value) {
	if (isDate(value)) return 4;
	if (isRegExp(value)) return 5;
	if (typeof value === 'function') return 6;
	return 7;
};

module.exports = function (db, createObj, object) {
	var Base, existingIds = db.objects.__setData__;

	Base = module.exports = function Self(value) {
		if (Self.is(value)) return value;
		return Self.create.apply(Self, arguments);
	};
	setPrototypeOf(Base, object);
	try { mixin(Base, Function.prototype); } catch (ignore) {}

	defineProperties(Base, assign({
		__id__: d('', 'Base'),
		object: d('', Base),
		extend: d(function (name) {
			return this._extendAndInitialize_.apply(this,
				this._validateExtend_.apply(this, arguments));
		}),
		_validateExtend_: d(function (name) {
			if (!isValidTypeName(name)) {
				throw new DbjsError(name + " is not valid type name",
					'INVALID_TYPE_NAME');
			}
			if (existingIds[name]) {
				throw new DbjsError(name + " type is already created", 'TYPE_EXISTS');
			}
			return [name].concat(this._validateExtendInitialize_.apply(this,
				slice.call(arguments, 1)));
		}),
		_validateExtendInitialize_: d(function (initialize, nsProps, objProps) {
			var errors;
			if (!isFunction(initialize)) {
				objProps = nsProps;
				nsProps = initialize;
				initialize = null;
			} else if (!nsProps) {
				nsProps = { _initialize_: { value: initialize } };
			} else {
				nsProps._initialize_ = { value: initialize };
			}

			if (nsProps) {
				try {
					nsProps = create(this)._validateDefineProperties_(nsProps);
				} catch (e) {
					if (e.name !== 'DbjsError') throw e;
					if (e.errors) errors = e.errors;
					else errors = [e];
				}
			}
			if (objProps) {
				try {
					objProps =
						create(this.prototype)._validateDefineProperties_(objProps);
				} catch (e) {
					if (e.name !== 'DbjsError') throw e;
					if (errors) {
						if (e.errors) push.apply(errors, e.errors);
						else errors.push(e);
					} else {
						if (e.errors) errors = e.errors;
						else errors = [e];
					}
				}
			}
			if (!errors) return [nsProps, objProps];
			throw new DbjsError("Invalid properties:\n\t" +
				errors.map(getMessage).join('\t\n'), 'TYPE_CONSTRUCTION_ERROR',
				{ errors: errors });
		}),
		_extendAndInitialize_: d(function (name) {
			var constructor = this._extend_(name);
			new Event(constructor, this); //jslint: skip
			constructor._initialize_.apply(constructor, slice.call(arguments, 1));
			return constructor;
		}),
		_initialize_: d(function (nsProps, objProps) {
			if (nsProps) this._defineProperties_(nsProps);
			if (objProps) this.prototype._defineProperties_(objProps);
		}),
		is: d(function (value) { return Boolean(serialize(value)); }),
		normalize: d(function (value) { return this.is(value) ? value : null; }),
		validate: d(function (value) {
			if (!serialize(value)) {
				throw new DbjsError(value + " cannot be handled by dbjs",
					'NOT_SUPPORTED_VALUE');
			}
			return value;
		}),
		compare: d(function (a, b) {
			var aType, bType;
			if (a == null) {
				if (b == null) return 0;
				return -Infinity;
			}
			if (b == null) return Infinity;
			aType = typeMap[typeof a];
			bType = typeMap[typeof b];
			if (aType !== bType) return aType - bType;
			if ((aType === 1) || (aType === 2)) return a - b;
			if (aType === 3) return String(a).localeCompare(b);
			aType = getObjectType(a);
			bType = getObjectType(b);
			if (aType !== bType) return aType - bType;
			if (aType === 4) return a - b;
			if ((aType === 5) || (aType === 6)) return String(a).localeCompare(b);
			return String(a.__id__).localeCompare(b.__id__);
		}),
		_extend_: d(function (name) {
			var constructor = function Self(value) {
				if (Self.is(value)) return value;
				return Self.create.apply(Self, arguments);
			};
			setPrototypeOf(constructor, this);
			defineProperties(constructor, {
				__id__: d('', name),
				object: d('', constructor)
			});
			constructor.prototype = create(this.prototype, {
				constructor: d(constructor),
				__id__: d('', name + '#')
			});
			defineProperty(constructor.prototype, 'object', d('',
				constructor.prototype));
			db.objects._add(constructor);
			db.objects._add(constructor.prototype);
			this._descendants_._add(constructor);
			this.prototype._descendants_._add(constructor.prototype);
			if (!(name in db)) db[name] = constructor;
			updateObjEnum(constructor);
			updateObjEnum(constructor.prototype);
			return constructor;
		}),
		_setValue_: d(function (nu, dbEvent) {
			var old = getPrototypeOf(this), postponed;
			if (!nu) nu = Base;
			if (old === nu) return;
			postponed = turnPrototype(this, nu, dbEvent);
			db._release_(turnPrototype(this.prototype, nu.prototype,
				dbEvent, postponed));
		}),
		create: d(function () {
			return this._createAndInitialize_.apply(this,
				this._validateCreate_.apply(this, arguments));
		}),
		_createNested_: d(function (object, sKey) {
			var nested;
			if (!this._keys_[sKey]) this._serialize_(unserialize(sKey, db.objects));
			nested = this._create_(object.__id__ + '/' + sKey, object.master);
			return defineProperties(nested, {
				owner: d('', object),
				key: d('', this._keys_[sKey]),
				__sKey__: d('', sKey)
			});
		}),
		_validateCreate_: d(function (value) { return [this.validate(value)]; }),
		_createAndInitialize_: d(i),
		_create_: d(function (id, master) {
			return updateObjEnum(createObj(this.prototype, id, null, master));
		}),
		find: d(function (key, value) {
			var sKey = this._serialize_(key), sValue;
			if (sKey == null) {
				throw new DbjsError(key + " is invalid key", 'INVALID_KEY');
			}
			if (value == null) {
				throw new DbjsError(value + " is not a value", 'INVALID_VALUE');
			}
			sValue = serialize(value);
			if (sValue == null) {
				throw new DbjsError(value + " is invalid database value",
					'NOT_SUPPORTED_VALUE');
			}
			return this.prototype._getReverseMap_(sKey)._getMultiple_(sValue, value);
		}),
		_destroy_: d(function () {
			if (this.hasOwnProperty('__typeAssignments__')) {
				this.__typeAssignments__._plainForEach_(function (obj) {
					new Event(obj.$type); //jslint: skip
				});
			}
			this.prototype._destroy_();
			this.prototype._destroy_.call(this);
		})
	}, lazy({
		_typeAssignments_: d(function () { return new ObjectsSet(); },
			{ cacheName: '__typeAssignments__', desc: '' })
	})));

	db.objects._add(Base);
	db.Base = Base;
	Base.prototype = object;

	defineProperties(object, {
		constructor: d(Base),
		_destroy_: d(function () {
			if (this.hasOwnProperty('__descendants__')) {
				this.__descendants__._plainForEach_(function (obj) {
					obj._destroy_();
				});
			}
			if (this.hasOwnProperty('__assignments__')) {
				this.__assignments__._plainForEach_(function (obj) {
					new Event(this); //jslint: skip
				});
			}
			if (this.hasOwnProperty('__objects__')) {
				keys(this.__objects__).forEach(destroy, this.__objects__);
			}
			if (this.hasOwnProperty('__descriptors__')) {
				keys(this.__descriptors__).forEach(destroy, this.__descriptors__);
			}
			if (this.hasOwnProperty('__multiples__')) {
				keys(this.__multiples__).forEach(function (pSKey) {
					keys(this[pSKey]).forEach(destroy, this[pSKey]);
				}, this.__multiples__);
			}
			if (this.constructor.prototype === this) return;
			new Event(this); //jslint: skip
		}),
		_setValue_: d(function (nu, dbEvent) {
			var old;
			if (this.constructor.prototype === this) {
				// Sanity check
				throw new DbjsError("Turn of prototype of the prototypes is forbidden",
					'PROTOTYPE_TURN');
			}
			old = getPrototypeOf(this);
			if (!nu) nu = object;
			if (old === nu) return;
			db._release_(turnPrototype(this, nu, dbEvent));
		})
	});
};
<commit_msg>Strict validation of prototype inputs<commit_after>'use strict';

var isDate         = require('es5-ext/date/is-date')
  , i              = require('es5-ext/function/i')
  , isFunction     = require('es5-ext/function/is-function')
  , validFunction  = require('es5-ext/function/valid-function')
  , assign         = require('es5-ext/object/assign')
  , create         = require('es5-ext/object/create')
  , mixin          = require('es5-ext/object/mixin')
  , setPrototypeOf = require('es5-ext/object/set-prototype-of')
  , isRegExp     = require('es5-ext/reg-exp/is-reg-exp')
  , d              = require('d/d')
  , lazy           = require('d/lazy')
  , DbjsError      = require('../error')
  , Event          = require('../event')
  , ObjectsSet     = require('../objects-set')
  , turnPrototype  = require('../utils/propagate-prototype-turn').object
  , serialize      = require('../serialize/value')
  , getMessage     = require('../utils/get-sub-error-message')
  , updateEnum     = require('../utils/update-enumerability')
  , unserialize    = require('../unserialize/key')
  , validDbValue   = require('../../valid-dbjs-value')

  , push = Array.prototype.push, slice = Array.prototype.slice
  , defineProperties = Object.defineProperties
  , defineProperty = Object.defineProperty, keys = Object.keys
  , getPrototypeOf = Object.getPrototypeOf
  , isValidTypeName = RegExp.prototype.test.bind(/^[A-Z][0-9a-zA-Z]*$/)
  , typeMap = { boolean: 1, number: 2, string: 3, function: 4,  object: 4 }
  , getObjectType
  , destroy = function (sKey) { this[sKey]._destroy_(); }
  , updateObjEnum;

updateObjEnum = function (obj) {
	var sKey, descs = obj.__descriptors__, desc;
	for (sKey in descs) {
		desc = descs[sKey];
		if (desc._reverse_) continue;
		if (desc.nested || desc.multiple) updateEnum(obj, sKey, true);
	}
	return obj;
};

getObjectType = function (value) {
	if (isDate(value)) return 4;
	if (isRegExp(value)) return 5;
	if (typeof value === 'function') return 6;
	return 7;
};

module.exports = function (db, createObj, object) {
	var Base, existingIds = db.objects.__setData__;

	Base = module.exports = function Self(value) {
		if (Self.is(value)) return value;
		return Self.create.apply(Self, arguments);
	};
	setPrototypeOf(Base, object);
	try { mixin(Base, Function.prototype); } catch (ignore) {}

	defineProperties(Base, assign({
		__id__: d('', 'Base'),
		object: d('', Base),
		extend: d(function (name) {
			return this._extendAndInitialize_.apply(this,
				this._validateExtend_.apply(this, arguments));
		}),
		_validateExtend_: d(function (name) {
			if (!isValidTypeName(name)) {
				throw new DbjsError(name + " is not valid type name",
					'INVALID_TYPE_NAME');
			}
			if (existingIds[name]) {
				throw new DbjsError(name + " type is already created", 'TYPE_EXISTS');
			}
			return [name].concat(this._validateExtendInitialize_.apply(this,
				slice.call(arguments, 1)));
		}),
		_validateExtendInitialize_: d(function (initialize, nsProps, objProps) {
			var errors;
			if (!isFunction(initialize)) {
				objProps = nsProps;
				nsProps = initialize;
				initialize = null;
			} else if (!nsProps) {
				nsProps = { _initialize_: { value: initialize } };
			} else {
				nsProps._initialize_ = { value: initialize };
			}

			if (nsProps) {
				try {
					nsProps = create(this)._validateDefineProperties_(nsProps);
				} catch (e) {
					if (e.name !== 'DbjsError') throw e;
					if (e.errors) errors = e.errors;
					else errors = [e];
				}
			}
			if (objProps) {
				try {
					objProps =
						create(this.prototype)._validateDefineProperties_(objProps);
				} catch (e) {
					if (e.name !== 'DbjsError') throw e;
					if (errors) {
						if (e.errors) push.apply(errors, e.errors);
						else errors.push(e);
					} else {
						if (e.errors) errors = e.errors;
						else errors = [e];
					}
				}
			}
			if (!errors) return [nsProps, objProps];
			throw new DbjsError("Invalid properties:\n\t" +
				errors.map(getMessage).join('\t\n'), 'TYPE_CONSTRUCTION_ERROR',
				{ errors: errors });
		}),
		_extendAndInitialize_: d(function (name) {
			var constructor = this._extend_(name);
			new Event(constructor, this); //jslint: skip
			constructor._initialize_.apply(constructor, slice.call(arguments, 1));
			return constructor;
		}),
		_initialize_: d(function (nsProps, objProps) {
			if (nsProps) this._defineProperties_(nsProps);
			if (objProps) this.prototype._defineProperties_(objProps);
		}),
		is: d(function (value) { return Boolean(serialize(value)); }),
		normalize: d(function (value) { return this.is(value) ? value : null; }),
		validate: d(function (value) {
			if (!serialize(value)) {
				throw new DbjsError(value + " cannot be handled by dbjs",
					'NOT_SUPPORTED_VALUE');
			}
			return value;
		}),
		compare: d(function (a, b) {
			var aType, bType;
			if (a == null) {
				if (b == null) return 0;
				return -Infinity;
			}
			if (b == null) return Infinity;
			aType = typeMap[typeof a];
			bType = typeMap[typeof b];
			if (aType !== bType) return aType - bType;
			if ((aType === 1) || (aType === 2)) return a - b;
			if (aType === 3) return String(a).localeCompare(b);
			aType = getObjectType(a);
			bType = getObjectType(b);
			if (aType !== bType) return aType - bType;
			if (aType === 4) return a - b;
			if ((aType === 5) || (aType === 6)) return String(a).localeCompare(b);
			return String(a.__id__).localeCompare(b.__id__);
		}),
		_extend_: d(function (name) {
			var constructor = function Self(value) {
				if (Self.is(value)) return value;
				return Self.create.apply(Self, arguments);
			};
			setPrototypeOf(constructor, this);
			defineProperties(constructor, {
				__id__: d('', name),
				object: d('', constructor)
			});
			constructor.prototype = create(this.prototype, {
				constructor: d(constructor),
				__id__: d('', name + '#')
			});
			defineProperty(constructor.prototype, 'object', d('',
				constructor.prototype));
			db.objects._add(constructor);
			db.objects._add(constructor.prototype);
			this._descendants_._add(constructor);
			this.prototype._descendants_._add(constructor.prototype);
			if (!(name in db)) db[name] = constructor;
			updateObjEnum(constructor);
			updateObjEnum(constructor.prototype);
			return constructor;
		}),
		_setValue_: d(function (nu, dbEvent) {
			var old = getPrototypeOf(this), postponed;
			if (!nu) nu = Base;
			else validDbValue(validFunction(nu));
			if (old === nu) return;
			postponed = turnPrototype(this, nu, dbEvent);
			db._release_(turnPrototype(this.prototype, nu.prototype,
				dbEvent, postponed));
		}),
		create: d(function () {
			return this._createAndInitialize_.apply(this,
				this._validateCreate_.apply(this, arguments));
		}),
		_createNested_: d(function (object, sKey) {
			var nested;
			if (!this._keys_[sKey]) this._serialize_(unserialize(sKey, db.objects));
			nested = this._create_(object.__id__ + '/' + sKey, object.master);
			return defineProperties(nested, {
				owner: d('', object),
				key: d('', this._keys_[sKey]),
				__sKey__: d('', sKey)
			});
		}),
		_validateCreate_: d(function (value) { return [this.validate(value)]; }),
		_createAndInitialize_: d(i),
		_create_: d(function (id, master) {
			return updateObjEnum(createObj(this.prototype, id, null, master));
		}),
		find: d(function (key, value) {
			var sKey = this._serialize_(key), sValue;
			if (sKey == null) {
				throw new DbjsError(key + " is invalid key", 'INVALID_KEY');
			}
			if (value == null) {
				throw new DbjsError(value + " is not a value", 'INVALID_VALUE');
			}
			sValue = serialize(value);
			if (sValue == null) {
				throw new DbjsError(value + " is invalid database value",
					'NOT_SUPPORTED_VALUE');
			}
			return this.prototype._getReverseMap_(sKey)._getMultiple_(sValue, value);
		}),
		_destroy_: d(function () {
			if (this.hasOwnProperty('__typeAssignments__')) {
				this.__typeAssignments__._plainForEach_(function (obj) {
					new Event(obj.$type); //jslint: skip
				});
			}
			this.prototype._destroy_();
			this.prototype._destroy_.call(this);
		})
	}, lazy({
		_typeAssignments_: d(function () { return new ObjectsSet(); },
			{ cacheName: '__typeAssignments__', desc: '' })
	})));

	db.objects._add(Base);
	db.Base = Base;
	Base.prototype = object;

	defineProperties(object, {
		constructor: d(Base),
		_destroy_: d(function () {
			if (this.hasOwnProperty('__descendants__')) {
				this.__descendants__._plainForEach_(function (obj) {
					obj._destroy_();
				});
			}
			if (this.hasOwnProperty('__assignments__')) {
				this.__assignments__._plainForEach_(function (obj) {
					new Event(this); //jslint: skip
				});
			}
			if (this.hasOwnProperty('__objects__')) {
				keys(this.__objects__).forEach(destroy, this.__objects__);
			}
			if (this.hasOwnProperty('__descriptors__')) {
				keys(this.__descriptors__).forEach(destroy, this.__descriptors__);
			}
			if (this.hasOwnProperty('__multiples__')) {
				keys(this.__multiples__).forEach(function (pSKey) {
					keys(this[pSKey]).forEach(destroy, this[pSKey]);
				}, this.__multiples__);
			}
			if (this.constructor.prototype === this) return;
			new Event(this); //jslint: skip
		}),
		_setValue_: d(function (nu, dbEvent) {
			var old;
			if (this.constructor.prototype === this) {
				// Sanity check
				throw new DbjsError("Turn of prototype of the prototypes is forbidden",
					'PROTOTYPE_TURN');
			}
			old = getPrototypeOf(this);
			if (!nu) {
				nu = object;
			} else {
				validDbValue(nu);
				if (nu._kind_ !== 'object') {
					throw new DbjsError("Prototype must be object kind",
						'NON_OBJECT_PROTOTYPE');
				}
			}
			if (old === nu) return;
			db._release_(turnPrototype(this, nu, dbEvent));
		})
	});
};
<|endoftext|>


<commit_before>// AST walker module for Mozilla Parser API compatible trees

// A simple walk is one where you simply specify callbacks to be
// called on specific nodes. The last two arguments are optional. A
// simple use would be
//
//     walk.simple(myTree, {
//         Expression: function(node) { ... }
//     });
//
// to do something with all expressions. All Parser API node types
// can be used to identify node types, as well as Expression and
// Statement, which denote categories of nodes.
//
// The base argument can be used to pass a custom (recursive)
// walker, and state can be used to give this walked an initial
// state.

export function simple(node, visitors, baseVisitor, state, override) {
  if (!baseVisitor) baseVisitor = base
  ;(function c(node, st, override) {
    let type = override || node.type, found = visitors[type]
    baseVisitor[type](node, st, c)
    if (found) found(node, st)
  })(node, state, override)
}

// An ancestor walk keeps an array of ancestor nodes (including the
// current node) and passes them to the callback as third parameter
// (and also as state parameter when no other state is present).
export function ancestor(node, visitors, baseVisitor, state) {
  let ancestors = []
  if (!baseVisitor) baseVisitor = base
  ;(function c(node, st, override) {
    let type = override || node.type, found = visitors[type]
    let isNew = node !== ancestors[ancestors.length - 1]
    if (isNew) ancestors.push(node)
    baseVisitor[type](node, st, c)
    if (found) found(node, st || ancestors, ancestors)
    if (isNew) ancestors.pop()
  })(node, state)
}

// A recursive walk is one where your functions override the default
// walkers. They can modify and replace the state parameter that's
// threaded through the walk, and can opt how and whether to walk
// their child nodes (by calling their third argument on these
// nodes).
export function recursive(node, state, funcs, baseVisitor, override) {
  let visitor = funcs ? make(funcs, baseVisitor || undefined) : baseVisitor
  ;(function c(node, st, override) {
    visitor[override || node.type](node, st, c)
  })(node, state, override)
}

function makeTest(test) {
  if (typeof test === "string")
    return type => type === test
  else if (!test)
    return () => true
  else
    return test
}

class Found {
  constructor(node, state) { this.node = node; this.state = state }
}

// A full walk triggers the callback on each node
export function full(node, callback, baseVisitor, state, override) {
  if (!baseVisitor) baseVisitor = base
  ;(function c(node, st, override) {
    let type = override || node.type
    baseVisitor[type](node, st, c)
    if (!override) callback(node, st, type)
  })(node, state, override)
}

// An fullAncestor walk is like an ancestor walk, but triggers
// the callback on each node
export function fullAncestor(node, callback, baseVisitor, state) {
  if (!baseVisitor) baseVisitor = base
  let ancestors = []
  ;(function c(node, st, override) {
    let type = override || node.type
    let isNew = node !== ancestors[ancestors.length - 1]
    if (isNew) ancestors.push(node)
    baseVisitor[type](node, st, c)
    if (!override) callback(node, st || ancestors, ancestors, type)
    if (isNew) ancestors.pop()
  })(node, state)
}

// Find a node with a given start, end, and type (all are optional,
// null can be used as wildcard). Returns a {node, state} object, or
// undefined when it doesn't find a matching node.
export function findNodeAt(node, start, end, test, baseVisitor, state) {
  if (!baseVisitor) baseVisitor = base
  test = makeTest(test)
  try {
    (function c(node, st, override) {
      let type = override || node.type
      if ((start == null || node.start <= start) &&
          (end == null || node.end >= end))
        baseVisitor[type](node, st, c)
      if ((start == null || node.start === start) &&
          (end == null || node.end === end) &&
          test(type, node))
        throw new Found(node, st)
    })(node, state)
  } catch (e) {
    if (e instanceof Found) return e
    throw e
  }
}

// Find the innermost node of a given type that contains the given
// position. Interface similar to findNodeAt.
export function findNodeAround(node, pos, test, baseVisitor, state) {
  test = makeTest(test)
  if (!baseVisitor) baseVisitor = base
  try {
    (function c(node, st, override) {
      let type = override || node.type
      if (node.start > pos || node.end < pos) return
      baseVisitor[type](node, st, c)
      if (test(type, node)) throw new Found(node, st)
    })(node, state)
  } catch (e) {
    if (e instanceof Found) return e
    throw e
  }
}

// Find the outermost matching node after a given position.
export function findNodeAfter(node, pos, test, baseVisitor, state) {
  test = makeTest(test)
  if (!baseVisitor) baseVisitor = base
  try {
    (function c(node, st, override) {
      if (node.end < pos) return
      let type = override || node.type
      if (node.start >= pos && test(type, node)) throw new Found(node, st)
      baseVisitor[type](node, st, c)
    })(node, state)
  } catch (e) {
    if (e instanceof Found) return e
    throw e
  }
}

// Find the outermost matching node before a given position.
export function findNodeBefore(node, pos, test, baseVisitor, state) {
  test = makeTest(test)
  if (!baseVisitor) baseVisitor = base
  let max
  ;(function c(node, st, override) {
    if (node.start > pos) return
    let type = override || node.type
    if (node.end <= pos && (!max || max.node.end < node.end) && test(type, node))
      max = new Found(node, st)
    baseVisitor[type](node, st, c)
  })(node, state)
  return max
}

// Fallback to an Object.create polyfill for older environments.
const create = Object.create || function(proto) {
  function Ctor() {}
  Ctor.prototype = proto
  return new Ctor
}

// Used to create a custom walker. Will fill in all missing node
// type properties with the defaults.
export function make(funcs, baseVisitor) {
  let visitor = create(baseVisitor || base)
  for (let type in funcs) visitor[type] = funcs[type]
  return visitor
}

function skipThrough(node, st, c) { c(node, st) }
function ignore(_node, _st, _c) {}

// Node walkers.

export const base = {}

base.Program = base.BlockStatement = (node, st, c) => {
  for (let stmt of node.body)
    c(stmt, st, "Statement")
}
base.Statement = skipThrough
base.EmptyStatement = ignore
base.ExpressionStatement = base.ParenthesizedExpression =
  (node, st, c) => c(node.expression, st, "Expression")
base.IfStatement = (node, st, c) => {
  c(node.test, st, "Expression")
  c(node.consequent, st, "Statement")
  if (node.alternate) c(node.alternate, st, "Statement")
}
base.LabeledStatement = (node, st, c) => c(node.body, st, "Statement")
base.BreakStatement = base.ContinueStatement = ignore
base.WithStatement = (node, st, c) => {
  c(node.object, st, "Expression")
  c(node.body, st, "Statement")
}
base.SwitchStatement = (node, st, c) => {
  c(node.discriminant, st, "Expression")
  for (let cs of node.cases) {
    if (cs.test) c(cs.test, st, "Expression")
    for (let cons of cs.consequent)
      c(cons, st, "Statement")
  }
}
base.SwitchCase = (node, st, c) => {
  if (node.test) c(node.test, st, "Expression")
  for (let cons of node.consequent)
    c(cons, st, "Statement")
}
base.ReturnStatement = base.YieldExpression = base.AwaitExpression = (node, st, c) => {
  if (node.argument) c(node.argument, st, "Expression")
}
base.ThrowStatement = base.SpreadElement =
  (node, st, c) => c(node.argument, st, "Expression")
base.TryStatement = (node, st, c) => {
  c(node.block, st, "Statement")
  if (node.handler) c(node.handler, st)
  if (node.finalizer) c(node.finalizer, st, "Statement")
}
base.CatchClause = (node, st, c) => {
  if (node.param) c(node.param, st, "Pattern")
  c(node.body, st, "Statement")
}
base.WhileStatement = base.DoWhileStatement = (node, st, c) => {
  c(node.test, st, "Expression")
  c(node.body, st, "Statement")
}
base.ForStatement = (node, st, c) => {
  if (node.init) c(node.init, st, "ForInit")
  if (node.test) c(node.test, st, "Expression")
  if (node.update) c(node.update, st, "Expression")
  c(node.body, st, "Statement")
}
base.ForInStatement = base.ForOfStatement = (node, st, c) => {
  c(node.left, st, "ForInit")
  c(node.right, st, "Expression")
  c(node.body, st, "Statement")
}
base.ForInit = (node, st, c) => {
  if (node.type === "VariableDeclaration") c(node, st)
  else c(node, st, "Expression")
}
base.DebuggerStatement = ignore

base.FunctionDeclaration = (node, st, c) => c(node, st, "Function")
base.VariableDeclaration = (node, st, c) => {
  for (let decl of node.declarations)
    c(decl, st)
}
base.VariableDeclarator = (node, st, c) => {
  c(node.id, st, "Pattern")
  if (node.init) c(node.init, st, "Expression")
}

base.Function = (node, st, c) => {
  if (node.id) c(node.id, st, "Pattern")
  for (let param of node.params)
    c(param, st, "Pattern")
  c(node.body, st, node.expression ? "Expression" : "Statement")
}

base.Pattern = (node, st, c) => {
  if (node.type === "Identifier")
    c(node, st, "VariablePattern")
  else if (node.type === "MemberExpression")
    c(node, st, "MemberPattern")
  else
    c(node, st)
}
base.VariablePattern = ignore
base.MemberPattern = skipThrough
base.RestElement = (node, st, c) => c(node.argument, st, "Pattern")
base.ArrayPattern = (node, st, c) => {
  for (let elt of node.elements) {
    if (elt) c(elt, st, "Pattern")
  }
}
base.ObjectPattern = (node, st, c) => {
  for (let prop of node.properties) {
    if (prop.type === "Property") {
      if (prop.computed) c(prop.key, st, "Expression")
      c(prop.value, st, "Pattern")
    } else if (prop.type === "RestElement") {
      c(prop.argument, st, "Pattern")
    }
  }
}

base.Expression = skipThrough
base.ThisExpression = base.Super = base.MetaProperty = ignore
base.ArrayExpression = (node, st, c) => {
  for (let elt of node.elements) {
    if (elt) c(elt, st, "Expression")
  }
}
base.ObjectExpression = (node, st, c) => {
  for (let prop of node.properties)
    c(prop, st)
}
base.FunctionExpression = base.ArrowFunctionExpression = base.FunctionDeclaration
base.SequenceExpression = (node, st, c) => {
  for (let expr of node.expressions)
    c(expr, st, "Expression")
}
base.TemplateLiteral = (node, st, c) => {
  for (let quasi of node.quasis)
    c(quasi, st)

  for (let expr of node.expressions)
    c(expr, st, "Expression")
}
base.TemplateElement = ignore
base.UnaryExpression = base.UpdateExpression = (node, st, c) => {
  c(node.argument, st, "Expression")
}
base.BinaryExpression = base.LogicalExpression = (node, st, c) => {
  c(node.left, st, "Expression")
  c(node.right, st, "Expression")
}
base.AssignmentExpression = base.AssignmentPattern = (node, st, c) => {
  c(node.left, st, "Pattern")
  c(node.right, st, "Expression")
}
base.ConditionalExpression = (node, st, c) => {
  c(node.test, st, "Expression")
  c(node.consequent, st, "Expression")
  c(node.alternate, st, "Expression")
}
base.NewExpression = base.CallExpression = (node, st, c) => {
  c(node.callee, st, "Expression")
  if (node.arguments)
    for (let arg of node.arguments)
      c(arg, st, "Expression")
}
base.MemberExpression = (node, st, c) => {
  c(node.object, st, "Expression")
  if (node.computed) c(node.property, st, "Expression")
}
base.ExportNamedDeclaration = base.ExportDefaultDeclaration = (node, st, c) => {
  if (node.declaration)
    c(node.declaration, st, node.type === "ExportNamedDeclaration" || node.declaration.id ? "Statement" : "Expression")
  if (node.source) c(node.source, st, "Expression")
}
base.ExportAllDeclaration = (node, st, c) => {
  c(node.source, st, "Expression")
}
base.ImportDeclaration = (node, st, c) => {
  for (let spec of node.specifiers)
    c(spec, st)
  c(node.source, st, "Expression")
}
base.ImportSpecifier = base.ImportDefaultSpecifier = base.ImportNamespaceSpecifier = base.Identifier = base.Literal = base.Import = ignore

base.TaggedTemplateExpression = (node, st, c) => {
  c(node.tag, st, "Expression")
  c(node.quasi, st, "Expression")
}
base.ClassDeclaration = base.ClassExpression = (node, st, c) => c(node, st, "Class")
base.Class = (node, st, c) => {
  if (node.id) c(node.id, st, "Pattern")
  if (node.superClass) c(node.superClass, st, "Expression")
  c(node.body, st)
}
base.ClassBody = (node, st, c) => {
  for (let elt of node.body)
    c(elt, st)
}
base.MethodDefinition = base.Property = (node, st, c) => {
  if (node.computed) c(node.key, st, "Expression")
  c(node.value, st, "Expression")
}
<commit_msg>Make walker support ImportExpression nodes<commit_after>// AST walker module for Mozilla Parser API compatible trees

// A simple walk is one where you simply specify callbacks to be
// called on specific nodes. The last two arguments are optional. A
// simple use would be
//
//     walk.simple(myTree, {
//         Expression: function(node) { ... }
//     });
//
// to do something with all expressions. All Parser API node types
// can be used to identify node types, as well as Expression and
// Statement, which denote categories of nodes.
//
// The base argument can be used to pass a custom (recursive)
// walker, and state can be used to give this walked an initial
// state.

export function simple(node, visitors, baseVisitor, state, override) {
  if (!baseVisitor) baseVisitor = base
  ;(function c(node, st, override) {
    let type = override || node.type, found = visitors[type]
    baseVisitor[type](node, st, c)
    if (found) found(node, st)
  })(node, state, override)
}

// An ancestor walk keeps an array of ancestor nodes (including the
// current node) and passes them to the callback as third parameter
// (and also as state parameter when no other state is present).
export function ancestor(node, visitors, baseVisitor, state) {
  let ancestors = []
  if (!baseVisitor) baseVisitor = base
  ;(function c(node, st, override) {
    let type = override || node.type, found = visitors[type]
    let isNew = node !== ancestors[ancestors.length - 1]
    if (isNew) ancestors.push(node)
    baseVisitor[type](node, st, c)
    if (found) found(node, st || ancestors, ancestors)
    if (isNew) ancestors.pop()
  })(node, state)
}

// A recursive walk is one where your functions override the default
// walkers. They can modify and replace the state parameter that's
// threaded through the walk, and can opt how and whether to walk
// their child nodes (by calling their third argument on these
// nodes).
export function recursive(node, state, funcs, baseVisitor, override) {
  let visitor = funcs ? make(funcs, baseVisitor || undefined) : baseVisitor
  ;(function c(node, st, override) {
    visitor[override || node.type](node, st, c)
  })(node, state, override)
}

function makeTest(test) {
  if (typeof test === "string")
    return type => type === test
  else if (!test)
    return () => true
  else
    return test
}

class Found {
  constructor(node, state) { this.node = node; this.state = state }
}

// A full walk triggers the callback on each node
export function full(node, callback, baseVisitor, state, override) {
  if (!baseVisitor) baseVisitor = base
  ;(function c(node, st, override) {
    let type = override || node.type
    baseVisitor[type](node, st, c)
    if (!override) callback(node, st, type)
  })(node, state, override)
}

// An fullAncestor walk is like an ancestor walk, but triggers
// the callback on each node
export function fullAncestor(node, callback, baseVisitor, state) {
  if (!baseVisitor) baseVisitor = base
  let ancestors = []
  ;(function c(node, st, override) {
    let type = override || node.type
    let isNew = node !== ancestors[ancestors.length - 1]
    if (isNew) ancestors.push(node)
    baseVisitor[type](node, st, c)
    if (!override) callback(node, st || ancestors, ancestors, type)
    if (isNew) ancestors.pop()
  })(node, state)
}

// Find a node with a given start, end, and type (all are optional,
// null can be used as wildcard). Returns a {node, state} object, or
// undefined when it doesn't find a matching node.
export function findNodeAt(node, start, end, test, baseVisitor, state) {
  if (!baseVisitor) baseVisitor = base
  test = makeTest(test)
  try {
    (function c(node, st, override) {
      let type = override || node.type
      if ((start == null || node.start <= start) &&
          (end == null || node.end >= end))
        baseVisitor[type](node, st, c)
      if ((start == null || node.start === start) &&
          (end == null || node.end === end) &&
          test(type, node))
        throw new Found(node, st)
    })(node, state)
  } catch (e) {
    if (e instanceof Found) return e
    throw e
  }
}

// Find the innermost node of a given type that contains the given
// position. Interface similar to findNodeAt.
export function findNodeAround(node, pos, test, baseVisitor, state) {
  test = makeTest(test)
  if (!baseVisitor) baseVisitor = base
  try {
    (function c(node, st, override) {
      let type = override || node.type
      if (node.start > pos || node.end < pos) return
      baseVisitor[type](node, st, c)
      if (test(type, node)) throw new Found(node, st)
    })(node, state)
  } catch (e) {
    if (e instanceof Found) return e
    throw e
  }
}

// Find the outermost matching node after a given position.
export function findNodeAfter(node, pos, test, baseVisitor, state) {
  test = makeTest(test)
  if (!baseVisitor) baseVisitor = base
  try {
    (function c(node, st, override) {
      if (node.end < pos) return
      let type = override || node.type
      if (node.start >= pos && test(type, node)) throw new Found(node, st)
      baseVisitor[type](node, st, c)
    })(node, state)
  } catch (e) {
    if (e instanceof Found) return e
    throw e
  }
}

// Find the outermost matching node before a given position.
export function findNodeBefore(node, pos, test, baseVisitor, state) {
  test = makeTest(test)
  if (!baseVisitor) baseVisitor = base
  let max
  ;(function c(node, st, override) {
    if (node.start > pos) return
    let type = override || node.type
    if (node.end <= pos && (!max || max.node.end < node.end) && test(type, node))
      max = new Found(node, st)
    baseVisitor[type](node, st, c)
  })(node, state)
  return max
}

// Fallback to an Object.create polyfill for older environments.
const create = Object.create || function(proto) {
  function Ctor() {}
  Ctor.prototype = proto
  return new Ctor
}

// Used to create a custom walker. Will fill in all missing node
// type properties with the defaults.
export function make(funcs, baseVisitor) {
  let visitor = create(baseVisitor || base)
  for (let type in funcs) visitor[type] = funcs[type]
  return visitor
}

function skipThrough(node, st, c) { c(node, st) }
function ignore(_node, _st, _c) {}

// Node walkers.

export const base = {}

base.Program = base.BlockStatement = (node, st, c) => {
  for (let stmt of node.body)
    c(stmt, st, "Statement")
}
base.Statement = skipThrough
base.EmptyStatement = ignore
base.ExpressionStatement = base.ParenthesizedExpression =
  (node, st, c) => c(node.expression, st, "Expression")
base.IfStatement = (node, st, c) => {
  c(node.test, st, "Expression")
  c(node.consequent, st, "Statement")
  if (node.alternate) c(node.alternate, st, "Statement")
}
base.LabeledStatement = (node, st, c) => c(node.body, st, "Statement")
base.BreakStatement = base.ContinueStatement = ignore
base.WithStatement = (node, st, c) => {
  c(node.object, st, "Expression")
  c(node.body, st, "Statement")
}
base.SwitchStatement = (node, st, c) => {
  c(node.discriminant, st, "Expression")
  for (let cs of node.cases) {
    if (cs.test) c(cs.test, st, "Expression")
    for (let cons of cs.consequent)
      c(cons, st, "Statement")
  }
}
base.SwitchCase = (node, st, c) => {
  if (node.test) c(node.test, st, "Expression")
  for (let cons of node.consequent)
    c(cons, st, "Statement")
}
base.ReturnStatement = base.YieldExpression = base.AwaitExpression = (node, st, c) => {
  if (node.argument) c(node.argument, st, "Expression")
}
base.ThrowStatement = base.SpreadElement =
  (node, st, c) => c(node.argument, st, "Expression")
base.TryStatement = (node, st, c) => {
  c(node.block, st, "Statement")
  if (node.handler) c(node.handler, st)
  if (node.finalizer) c(node.finalizer, st, "Statement")
}
base.CatchClause = (node, st, c) => {
  if (node.param) c(node.param, st, "Pattern")
  c(node.body, st, "Statement")
}
base.WhileStatement = base.DoWhileStatement = (node, st, c) => {
  c(node.test, st, "Expression")
  c(node.body, st, "Statement")
}
base.ForStatement = (node, st, c) => {
  if (node.init) c(node.init, st, "ForInit")
  if (node.test) c(node.test, st, "Expression")
  if (node.update) c(node.update, st, "Expression")
  c(node.body, st, "Statement")
}
base.ForInStatement = base.ForOfStatement = (node, st, c) => {
  c(node.left, st, "ForInit")
  c(node.right, st, "Expression")
  c(node.body, st, "Statement")
}
base.ForInit = (node, st, c) => {
  if (node.type === "VariableDeclaration") c(node, st)
  else c(node, st, "Expression")
}
base.DebuggerStatement = ignore

base.FunctionDeclaration = (node, st, c) => c(node, st, "Function")
base.VariableDeclaration = (node, st, c) => {
  for (let decl of node.declarations)
    c(decl, st)
}
base.VariableDeclarator = (node, st, c) => {
  c(node.id, st, "Pattern")
  if (node.init) c(node.init, st, "Expression")
}

base.Function = (node, st, c) => {
  if (node.id) c(node.id, st, "Pattern")
  for (let param of node.params)
    c(param, st, "Pattern")
  c(node.body, st, node.expression ? "Expression" : "Statement")
}

base.Pattern = (node, st, c) => {
  if (node.type === "Identifier")
    c(node, st, "VariablePattern")
  else if (node.type === "MemberExpression")
    c(node, st, "MemberPattern")
  else
    c(node, st)
}
base.VariablePattern = ignore
base.MemberPattern = skipThrough
base.RestElement = (node, st, c) => c(node.argument, st, "Pattern")
base.ArrayPattern = (node, st, c) => {
  for (let elt of node.elements) {
    if (elt) c(elt, st, "Pattern")
  }
}
base.ObjectPattern = (node, st, c) => {
  for (let prop of node.properties) {
    if (prop.type === "Property") {
      if (prop.computed) c(prop.key, st, "Expression")
      c(prop.value, st, "Pattern")
    } else if (prop.type === "RestElement") {
      c(prop.argument, st, "Pattern")
    }
  }
}

base.Expression = skipThrough
base.ThisExpression = base.Super = base.MetaProperty = ignore
base.ArrayExpression = (node, st, c) => {
  for (let elt of node.elements) {
    if (elt) c(elt, st, "Expression")
  }
}
base.ObjectExpression = (node, st, c) => {
  for (let prop of node.properties)
    c(prop, st)
}
base.FunctionExpression = base.ArrowFunctionExpression = base.FunctionDeclaration
base.SequenceExpression = (node, st, c) => {
  for (let expr of node.expressions)
    c(expr, st, "Expression")
}
base.TemplateLiteral = (node, st, c) => {
  for (let quasi of node.quasis)
    c(quasi, st)

  for (let expr of node.expressions)
    c(expr, st, "Expression")
}
base.TemplateElement = ignore
base.UnaryExpression = base.UpdateExpression = (node, st, c) => {
  c(node.argument, st, "Expression")
}
base.BinaryExpression = base.LogicalExpression = (node, st, c) => {
  c(node.left, st, "Expression")
  c(node.right, st, "Expression")
}
base.AssignmentExpression = base.AssignmentPattern = (node, st, c) => {
  c(node.left, st, "Pattern")
  c(node.right, st, "Expression")
}
base.ConditionalExpression = (node, st, c) => {
  c(node.test, st, "Expression")
  c(node.consequent, st, "Expression")
  c(node.alternate, st, "Expression")
}
base.NewExpression = base.CallExpression = (node, st, c) => {
  c(node.callee, st, "Expression")
  if (node.arguments)
    for (let arg of node.arguments)
      c(arg, st, "Expression")
}
base.MemberExpression = (node, st, c) => {
  c(node.object, st, "Expression")
  if (node.computed) c(node.property, st, "Expression")
}
base.ExportNamedDeclaration = base.ExportDefaultDeclaration = (node, st, c) => {
  if (node.declaration)
    c(node.declaration, st, node.type === "ExportNamedDeclaration" || node.declaration.id ? "Statement" : "Expression")
  if (node.source) c(node.source, st, "Expression")
}
base.ExportAllDeclaration = (node, st, c) => {
  c(node.source, st, "Expression")
}
base.ImportDeclaration = (node, st, c) => {
  for (let spec of node.specifiers)
    c(spec, st)
  c(node.source, st, "Expression")
}
base.ImportExpression = (node, st, c) => {
  c(node.source, st, "Expression")
}
base.ImportSpecifier = base.ImportDefaultSpecifier = base.ImportNamespaceSpecifier = base.Identifier = base.Literal = base.Import = ignore

base.TaggedTemplateExpression = (node, st, c) => {
  c(node.tag, st, "Expression")
  c(node.quasi, st, "Expression")
}
base.ClassDeclaration = base.ClassExpression = (node, st, c) => c(node, st, "Class")
base.Class = (node, st, c) => {
  if (node.id) c(node.id, st, "Pattern")
  if (node.superClass) c(node.superClass, st, "Expression")
  c(node.body, st)
}
base.ClassBody = (node, st, c) => {
  for (let elt of node.body)
    c(elt, st)
}
base.MethodDefinition = base.Property = (node, st, c) => {
  if (node.computed) c(node.key, st, "Expression")
  c(node.value, st, "Expression")
}
<|endoftext|>