<commit_before>import { exec } from 'child_process';
import bs from 'browser-sync';
import { Server } from 'karma';
import del from 'del';
import runSequence from 'run-sequence';
import nib from 'nib';
import glob from 'glob';

/** Gulp plugins **/
import gulpHelp from 'gulp-help';
import gutil from 'gulp-util';
import git from 'gulp-git';
import eslint from 'gulp-eslint';
import bump from 'gulp-bump';
import stylus from 'gulp-stylus';
import sourcemaps from 'gulp-sourcemaps';
import autoprefixer from 'gulp-autoprefixer';

function deepAssign(target, ...rest) {
    let combined = target;
    rest.forEach(source => {
        combined = walkSource(combined, source);
    });

    return combined;
}

function walkSource(_target, _source) {
    Object.keys(_source).forEach(key => {
        const value = _source[key];

        if ( Array.isArray(value) ) {
            _target[key] = value.slice();
        } else if ( isObj(value) ) {
            _target[key] = deepAssign(_target[key] || {}, value);
        } else if ( value !== undefined ) {
            _target[key] = value;
        }
    });

    return _target;
}

function isObj(x) {
    const type = typeof x;
    return x !== null && (type === 'object' || type === 'function');
}

function setupConfig(_config) {
    const defaultConfig = {
        paths: {
            root: './',
            src: {
                root: 'src/',
                html: 'src/templates/',
                images: 'src/images/',
                javascript: 'src/javascript/',
                stylesheets: 'src/stylesheets/',
            },
            dist: {
                root: 'dist/',
                html: 'dist/templates/',
                images: 'dist/images/',
                javascript: 'dist/javascript/',
                stylesheets: 'dist/stylesheets/',
            },
            config: {
                karma: 'test/karma.conf.js',
            },
            test: {
                unit: 'test/unit/',
                e2e: 'test/e2e',
            },
            serve: 'demo/',
            lint: {
                js: [
                    'src/**/*.js',
                    'test/**/*.js',
                    'demo/**/*.js',
                ],
            },
            stylusInclude: glob.sync(process.cwd() + '/jspm_packages/apsis/tenko*/'),
        },
    };

    return deepAssign({}, defaultConfig, _config);
}

class Apsis {
    constructor(_gulp, _config) {
        const gulp = gulpHelp(_gulp);
        this.config = setupConfig(_config);

        this.options = gutil.env;

        this.releaseFn(gulp, this.config);
        this.bumpFn(gulp, this.config);
        this.cleanFn(gulp, this.config);
        this.copyFn(gulp, this.config);
        this.defaultFn(gulp, this.config);
        this.eslintFn(gulp, this.config);
        this.gitFn(gulp, this.config);
        this.npmFn(gulp, this.config);
        this.serveFn(gulp, this.config);
        this.stylusFn(gulp, this.config);
        this.testFn(gulp, this.config);
        this.watchFn(gulp, this.config);
    }

    bumpFn(gulp, config) {
        gulp.task('bump', 'Bump the package version in package.json', () => {
            const type = gutil.env.bump || 'patch';

            gulp.src(config.paths.root + 'package.json')
                .pipe(bump({type}))
                .pipe(gulp.dest(config.paths.root));
        }, {
            options: {
                'bump': 'what bump to perform. [ patch, minor, major]',
            },
        });
    }

    cleanFn(gulp, config) {
        gulp.task('clean:dist', 'Delete the dist/ directory', () => {
            del([
                config.paths.dist.root,
            ]);
        });
    }

    copyFn(gulp, config) {
        gulp.task('copy:dist', 'Copy JS and HTML to dist/', () => {
            gulp.src([
                config.paths.src.root + '**/*.js',
                config.paths.src.root + '**/*.html',
            ])
                .pipe(gulp.dest(config.paths.dist.root));
        });
    }

    defaultFn(gulp) {
        gulp.task('default', 'Sets up the dev environment', () => {
            const taskArr = [
                [ 'stylus', 'eslint' ],
                'watch',
                'serve',
            ];

            if ( !this.options.skipinstall ) {
                taskArr.unshift('npm:install');
            } else {
                gutil.log(gutil.colors.red('Skipping npm installation process.'));
            }

            return runSequence.use(gulp).apply(gulp, taskArr);
        }, {
            options: {
                'skipinstall': 'add to skip npm install at the top of the task',
            },
        });
    }

    eslintFn(gulp, config) {
        gulp.task('eslint', 'Lint your JavaScript with ESLint', () => {
            return gulp.src(config.paths.lint.js)
                .pipe(eslint())
                .pipe(eslint.format());
        });

        gulp.task('eslint:fail', false, () => {
            return gulp.src(config.paths.lint.js)
                .pipe(eslint())
                .pipe(eslint.format())
                .pipe(eslint.failOnError());
        });
    }

    gitFn(gulp) {
        gulp.task('commit:bump', false, () => {
            return gulp.src('.')
                .pipe(git.add())
                .pipe(git.commit('[Prerelease] Bump version number'));
        });

        gulp.task('commit:dist', false, () => {
            return gulp.src('.')
                .pipe(git.add())
                .pipe(git.commit('[Prerelease] Update dist/ files'));
        });
    }

    npmFn(gulp) {
        gulp.task('npm:install', 'Run npm install', (cb) => {
            Apsis.runExec('npm install', cb);
        });

        gulp.task('npm:update', 'Run npm install', (cb) => {
            Apsis.runExec('npm update', cb);
        });
    }

    releaseFn(gulp) {
        gulp.task('release', done => {
            runSequence.use(gulp)(
                'clean:dist',
                'eslint:fail',
                [ 'copy:dist', 'stylus:dist' ],
                'commit:dist',
                'bump',
                'commit:bump',
                error => {
                    if (error) {
                        gutil.log(error.message);
                    } else {
                        gutil.log('RELEASE FINISHED SUCCESSFULLY');
                    }
                    done(error);
                }
            );
        });
    }

    serveFn(gulp, config) {
        const browserSync = bs.create();

        gulp.task('serve', 'Create a server instance on localhost:9000', () => {
            const browserSyncOptions = {
                port: 9000,
                startPath: config.paths.serve,
                files: [
                    config.paths.serve + '*.html',
                    config.paths.serve + '*.js',
                    config.paths.src.javascript + 'src/javascript/**/*.js',
                    config.paths.src.images + '**/*',
                    config.paths.src.html + '*.html',
                    config.paths.src.stylesheets + '*.css',
                ],
                open: !!gutil.env.browser,
                server: {
                    baseDir: ['./'],
                    middleware: (req, res, next) => {
                        res.setHeader('Access-Control-Allow-Origin', '*');
                        next();
                    },
                },
            };

            if (!!gutil.env.browser ) {
                browserSyncOptions.browser = gutil.env.browser;
            }

            return browserSync.init(browserSyncOptions);
        }, {
            options: {
                'browser': 'Open the given browser on init',
            },
        });
    }

    stylusFn(gulp, config) {
        function getStylusOptions(_options = {}) {
            const defaultOptions = {
                use: nib(),
                compress: false,
            };

            if ( !!config.paths.stylusInclude ) {
                defaultOptions.include = config.paths.stylusInclude;
            }

            return Object.assign(defaultOptions, _options);
        }

        gulp.task('stylus', 'Compile stylus files into src/stylesheets.', () => {
            const options = getStylusOptions();

            return gulp.src(config.paths.src.stylesheets + '**/*.styl')
                .pipe(sourcemaps.init())
                .pipe(stylus(options))
                .pipe(autoprefixer())
                .pipe(sourcemaps.write())
                .pipe(gulp.dest(config.paths.src.stylesheets));
        }, {
            aliases: [ 'styles' ],
        });

        gulp.task('stylus:dist', false, () => {
            const options = getStylusOptions({
                compress: true,
            });

            return gulp.src(config.paths.src.stylesheets + '**/*.styl')
                .pipe(stylus(options))
                .pipe(autoprefixer())
                .pipe(gulp.dest(config.paths.dist.stylesheets));
        });
    }

    testFn(gulp, config) {
        gulp.task('test', 'Run Karma tests', done => {
            new Server({
                configFile: process.cwd() + config.paths.config.karma,
            }, done).start();
        });

        gulp.task('tdd', 'Run Karma tests', done => {
            new Server({
                configFile: process.cwd() + config.paths.config.karma,
            }, done).start();
        });
    }

    watchFn(gulp, config) {
        gulp.task('watch', false, () => {
            gulp.watch(config.paths.lint.js, ['eslint']);
            gulp.watch(config.paths.src.stylesheets + '**/*.styl', ['stylus']);
        });
    }

    static runExec(cmd, cb) {
        exec(cmd, (err, stdout) => {
            gutil.log(stdout);

            cb(err);
        });
    }
}

function apsisGulpConfig(_gulp, _config) {
    return new Apsis(_gulp, _config);
}

export { apsisGulpConfig };
<commit_msg>add fixes for developing components with a linked tenko package<commit_after>import { exec } from 'child_process';
import bs from 'browser-sync';
import { Server } from 'karma';
import del from 'del';
import runSequence from 'run-sequence';
import nib from 'nib';
import glob from 'glob';

/** Gulp plugins **/
import gulpHelp from 'gulp-help';
import gutil from 'gulp-util';
import git from 'gulp-git';
import eslint from 'gulp-eslint';
import bump from 'gulp-bump';
import stylus from 'gulp-stylus';
import sourcemaps from 'gulp-sourcemaps';
import autoprefixer from 'gulp-autoprefixer';

function deepAssign(target, ...rest) {
    let combined = target;
    rest.forEach(source => {
        combined = walkSource(combined, source);
    });

    return combined;
}

function walkSource(_target, _source) {
    Object.keys(_source).forEach(key => {
        const value = _source[key];

        if ( Array.isArray(value) ) {
            _target[key] = value.slice();
        } else if ( isObj(value) ) {
            _target[key] = deepAssign(_target[key] || {}, value);
        } else if ( value !== undefined ) {
            _target[key] = value;
        }
    });

    return _target;
}

function isObj(x) {
    const type = typeof x;
    return x !== null && (type === 'object' || type === 'function');
}

function setupConfig(_config) {
    const defaultConfig = {
        paths: {
            root: './',
            src: {
                root: 'src/',
                html: 'src/templates/',
                images: 'src/images/',
                javascript: 'src/javascript/',
                stylesheets: 'src/stylesheets/',
            },
            dist: {
                root: 'dist/',
                html: 'dist/templates/',
                images: 'dist/images/',
                javascript: 'dist/javascript/',
                stylesheets: 'dist/stylesheets/',
            },
            config: {
                karma: 'test/karma.conf.js',
            },
            test: {
                unit: 'test/unit/',
                e2e: 'test/e2e',
            },
            serve: 'demo/',
            lint: {
                js: ['src/**/*.js', 'test/**/*.js', 'demo/**/*.js'],
            },
            watch: {
                stylesheets: false,
                javascript: false,
            },
            stylusInclude: glob.sync(process.cwd() + '/jspm_packages/apsis/tenko*/'),
        },
        options: {
            'stylusTenkoTimeout': 500,
        },
    };

    return deepAssign({}, defaultConfig, _config);
}

class Apsis {
    constructor(_gulp, _config) {
        const gulp = gulpHelp(_gulp);
        this.config = setupConfig(_config);

        this.options = gutil.env;

        this.releaseFn(gulp, this.config);
        this.bumpFn(gulp, this.config);
        this.cleanFn(gulp, this.config);
        this.copyFn(gulp, this.config);
        this.defaultFn(gulp, this.config);
        this.eslintFn(gulp, this.config);
        this.gitFn(gulp, this.config);
        this.npmFn(gulp, this.config);
        this.serveFn(gulp, this.config);
        this.stylusFn(gulp, this.config);
        this.testFn(gulp, this.config);
        this.watchFn(gulp, this.config);
    }

    bumpFn(gulp, config) {
        gulp.task('bump', 'Bump the package version in package.json', () => {
            const type = gutil.env.bump || 'patch';

            gulp.src(config.paths.root + 'package.json')
                .pipe(bump({type}))
                .pipe(gulp.dest(config.paths.root));
        }, {
            options: {
                'bump': 'what bump to perform. [ patch, minor, major]',
            },
        });
    }

    cleanFn(gulp, config) {
        gulp.task('clean:dist', 'Delete the dist/ directory', () => {
            del([
                config.paths.dist.root,
            ]);
        });
    }

    copyFn(gulp, config) {
        gulp.task('copy:dist', 'Copy JS and HTML to dist/', () => {
            gulp.src([
                config.paths.src.root + '**/*.js',
                config.paths.src.root + '**/*.html',
            ])
                .pipe(gulp.dest(config.paths.dist.root));
        });
    }

    defaultFn(gulp) {
        gulp.task('default', 'Sets up the dev environment', () => {
            const taskArr = [
                [ 'stylus', 'eslint' ],
                'watch',
                'serve',
            ];

            if ( !this.options.skipinstall ) {
                taskArr.unshift('npm:install');
            } else {
                gutil.log(gutil.colors.red('Skipping npm installation process.'));
            }

            return runSequence.use(gulp).apply(gulp, taskArr);
        }, {
            options: {
                'skipinstall': 'add to skip npm install at the top of the task',
            },
        });
    }

    eslintFn(gulp, config) {
        gulp.task('eslint', 'Lint your JavaScript with ESLint', () => {
            return gulp.src(config.paths.lint.js)
                .pipe(eslint())
                .pipe(eslint.format());
        });

        gulp.task('eslint:fail', false, () => {
            return gulp.src(config.paths.lint.js)
                .pipe(eslint())
                .pipe(eslint.format())
                .pipe(eslint.failOnError());
        });
    }

    gitFn(gulp) {
        gulp.task('commit:bump', false, () => {
            return gulp.src('.')
                .pipe(git.add())
                .pipe(git.commit('[Prerelease] Bump version number'));
        });

        gulp.task('commit:dist', false, () => {
            return gulp.src('.')
                .pipe(git.add())
                .pipe(git.commit('[Prerelease] Update dist/ files'));
        });
    }

    npmFn(gulp) {
        gulp.task('npm:install', 'Run npm install', (cb) => {
            Apsis.runExec('npm install', cb);
        });

        gulp.task('npm:update', 'Run npm install', (cb) => {
            Apsis.runExec('npm update', cb);
        });
    }

    releaseFn(gulp) {
        gulp.task('release', done => {
            runSequence.use(gulp)(
                'clean:dist',
                'eslint:fail',
                [ 'copy:dist', 'stylus:dist' ],
                'commit:dist',
                'bump',
                'commit:bump',
                error => {
                    if (error) {
                        gutil.log(error.message);
                    } else {
                        gutil.log('RELEASE FINISHED SUCCESSFULLY');
                    }
                    done(error);
                }
            );
        });
    }

    serveFn(gulp, config) {
        const browserSync = bs.create();

        gulp.task('serve', 'Create a server instance on localhost:9000', () => {
            const browserSyncOptions = {
                port: 9000,
                startPath: config.paths.serve,
                files: [
                    config.paths.serve + '*.html',
                    config.paths.serve + '*.js',
                    config.paths.src.javascript + 'src/javascript/**/*.js',
                    config.paths.src.images + '**/*',
                    config.paths.src.html + '*.html',
                    config.paths.src.stylesheets + '*.css',
                ],
                open: !!gutil.env.browser,
                server: {
                    baseDir: ['./'],
                    middleware: (req, res, next) => {
                        res.setHeader('Access-Control-Allow-Origin', '*');
                        next();
                    },
                },
            };

            if (!!gutil.env.browser ) {
                browserSyncOptions.browser = gutil.env.browser;
            }

            return browserSync.init(browserSyncOptions);
        }, {
            options: {
                'browser': 'Open the given browser on init',
            },
        });
    }

    stylusFn(gulp, config) {
        function getStylusOptions(_options = {}) {
            const defaultOptions = {
                use: nib(),
                compress: false,
            };

            if ( !!config.paths.stylusInclude ) {
                defaultOptions.include = config.paths.stylusInclude;
            }

            return Object.assign(defaultOptions, _options);
        }

        gulp.task('stylus', 'Compile stylus files into src/stylesheets.', () => {
            const options = getStylusOptions();

            return gulp.src(config.paths.src.stylesheets + '**/*.styl')
                .pipe(sourcemaps.init())
                .pipe(stylus(options))
                .pipe(autoprefixer())
                .pipe(sourcemaps.write())
                .pipe(gulp.dest(config.paths.src.stylesheets));
        }, {
            aliases: [ 'styles' ],
        });

        gulp.task('stylus:tenko', false, cb => {
            const options = getStylusOptions();

            setTimeout(() => {
                gulp.src(config.paths.src.stylesheets + '**/*.styl')
                    .pipe(sourcemaps.init())
                    .pipe(stylus(options))
                    .pipe(autoprefixer())
                    .pipe(sourcemaps.write())
                    .pipe(gulp.dest(config.paths.src.stylesheets))
                    .on('end', cb);
            }, config.options.stylusTenkoTimeout);
        });

        gulp.task('stylus:dist', false, () => {
            const options = getStylusOptions({
                compress: true,
            });

            return gulp.src(config.paths.src.stylesheets + '**/*.styl')
                .pipe(stylus(options))
                .pipe(autoprefixer())
                .pipe(gulp.dest(config.paths.dist.stylesheets));
        });
    }

    testFn(gulp, config) {
        gulp.task('test', 'Run Karma tests', done => {
            new Server({
                configFile: process.cwd() + config.paths.config.karma,
            }, done).start();
        });

        gulp.task('tdd', 'Run Karma tests', done => {
            new Server({
                configFile: process.cwd() + config.paths.config.karma,
            }, done).start();
        });
    }

    watchFn(gulp, config) {
        const stylusWatchPath = config.paths.watch.stylesheets || config.paths.src.stylesheets + '**/*.styl';
        let stylusTask = ['stylus'];

        if ( !!gutil.env.tenko ) {
            stylusTask = [ 'stylus:tenko' ];
        }

        gulp.task('watch', false, () => {
            gulp.watch(config.paths.lint.js, ['eslint']);
            gulp.watch(stylusWatchPath, stylusTask);
        }, {
            options: {
                'tenko': 'run a special tenko task, that makes it possible to used a linked Tenko package',
            },
        });
    }

    static runExec(cmd, cb) {
        exec(cmd, (err, stdout) => {
            gutil.log(stdout);

            cb(err);
        });
    }
}

function apsisGulpConfig(_gulp, _config) {
    return new Apsis(_gulp, _config);
}

export { apsisGulpConfig };
<|endoftext|>


<commit_before>import { h, Component } from 'preact';

const routers = [];

export function route(url) {
	if (history) {
		history.pushState(null, null, url);
	}
	routeTo(url);
}

function routeTo(url) {
	routers.forEach( router => router.routeTo(url) );
}

function getCurrentUrl() {
	return `${location.pathname || ''}${location.search || ''}`;
}

if (typeof addEventListener==='function') {
	addEventListener('popstate', () => routeTo(getCurrentUrl()));
}

function handleLinkClick(e) {
	route(this.getAttribute('href'));
	if (e.stopImmediatePropagation) e.stopImmediatePropagation();
	e.stopPropagation();
	e.preventDefault();
	return false;
}

export const Link = ({ children, ...props }) => (
	{ children }
);

export class Router extends Component {
	getInitialState() {
		return { url: getCurrentUrl() };
	}

	routeTo(url) {
		this.setState({ url });
	}

	componentWillMount() {
		routers.push(this);
	}

	componentWillUnmount() {
		routers.splice(routers.indexOf(this), 1);
	}

	render({ children, onChange }, { url }) {
		let active = children.filter( ({ attributes }) => {
			let path = attributes.path,
				matches = exec(url, path);
			if (matches) {
				attributes.url = url;
				attributes.matches = matches;
				// copy matches onto props
				for (let i in matches) {
					if (matches.hasOwnProperty(i)) {
						attributes[i] = matches[i];
					}
				}
				return true;
			}
		});
		let previous = this.previousUrl;
		if (url!==previous) {
			this.previousUrl = url;
			if (typeof onChange==='function') {
				onChange({
					router: this,
					url,
					previous,
					active,
					current: active[0]
				});
			}
		}
		return <router style="position:static;display:inline;">{ active }</router>;
	}
}

export const Route = ({ component:RoutedComponent, url, matches }) => (
	<RoutedComponent {...{url, matches}} />
);

/*
export class Route extends Component {
	render({ component:RoutedComponent, url, matches }) {
		return <RoutedComponent { ...{url, matches} } />;
	}
}
*/

function exec(url, route) {
	let reg = /(?:\?([^#]*))?(#.*)?$/,
		c = url.match(reg),
		matches = {};
	if (c && c[1]) {
		let p = c[1].split('&');
		for (let i=0; i<p.length; i++) {
			let r = p[i].split('=');
			matches[decodeURIComponent(r[0])] = decodeURIComponent(r.slice(1).join('='));
		}
	}
	url = segmentize(url.replace(reg, ''));
	route = segmentize(route);
	let max = Math.max(url.length, route.length);
	for (let i=0; i<max; i++) {
		if (route[i] && route[i].charAt(0)===':') {
			matches[route[i].substring(1)] = decodeURIComponent(url[i] || '');
		}
		else {
			if (route[i]!==url[i]) {
				return false;
			}
		}
	}
	return matches;
}

Router.route = route;
Router.Route = Route;
Router.Link = Link;
export default Router;

let segmentize = url => strip(url).split('/');

let strip = url => url.replace(/(^\/+|\/+$)/g, '');
<commit_msg>Switch to using high order components<commit_after>import { h, Component } from 'preact';

const routers = [];

export function route(url) {
	if (history) {
		history.pushState(null, null, url);
	}
	routeTo(url);
}

function routeTo(url) {
	routers.forEach( router => router.routeTo(url) );
}

function getCurrentUrl() {
	return `${location.pathname || ''}${location.search || ''}`;
}

if (typeof addEventListener==='function') {
	addEventListener('popstate', () => routeTo(getCurrentUrl()));
}

function handleLinkClick(e) {
	route(this.getAttribute('href'));
	if (e.stopImmediatePropagation) e.stopImmediatePropagation();
	e.stopPropagation();
	e.preventDefault();
	return false;
}

export const Link = ({ children, ...props }) => (
	{ children }
);

export class Router extends Component {
	getInitialState() {
		return { url: getCurrentUrl() };
	}

	routeTo(url) {
		this.setState({ url });
	}

	componentWillMount() {
		routers.push(this);
	}

	componentWillUnmount() {
		routers.splice(routers.indexOf(this), 1);
	}

	render({ children, onChange }, { url }) {
		let active = children.filter( ({ attributes }) => {
			let path = attributes.path,
				matches = exec(url, path);
			if (matches) {
				attributes.url = url;
				attributes.matches = matches;
				// copy matches onto props
				for (let i in matches) {
					if (matches.hasOwnProperty(i)) {
						attributes[i] = matches[i];
					}
				}
				return true;
			}
		});
		let previous = this.previousUrl;
		if (url!==previous) {
			this.previousUrl = url;
			if (typeof onChange==='function') {
				onChange({
					router: this,
					url,
					previous,
					active,
					current: active[0]
				});
			}
		}
		return active[0] || null;
	}
}

export const Route = ({ component:RoutedComponent, url, matches }) => (
	<RoutedComponent {...{url, matches}} />
);

/*
export class Route extends Component {
	render({ component:RoutedComponent, url, matches }) {
		return <RoutedComponent { ...{url, matches} } />;
	}
}
*/

function exec(url, route) {
	let reg = /(?:\?([^#]*))?(#.*)?$/,
		c = url.match(reg),
		matches = {};
	if (c && c[1]) {
		let p = c[1].split('&');
		for (let i=0; i<p.length; i++) {
			let r = p[i].split('=');
			matches[decodeURIComponent(r[0])] = decodeURIComponent(r.slice(1).join('='));
		}
	}
	url = segmentize(url.replace(reg, ''));
	route = segmentize(route);
	let max = Math.max(url.length, route.length);
	for (let i=0; i<max; i++) {
		if (route[i] && route[i].charAt(0)===':') {
			matches[route[i].substring(1)] = decodeURIComponent(url[i] || '');
		}
		else {
			if (route[i]!==url[i]) {
				return false;
			}
		}
	}
	return matches;
}

Router.route = route;
Router.Route = Route;
Router.Link = Link;
export default Router;

let segmentize = url => strip(url).split('/');

let strip = url => url.replace(/(^\/+|\/+$)/g, '');
<|endoftext|>


<commit_before>const join = require('path').join
const execSync = require('child_process').execSync
const chalk = require('chalk')
const gitFiles = require('git-files')
const jumper = require('terminal-jumper')
const Interactive = require('./interactive')
const utils = require('./utils')

/**
 * Reads a file glob and a commit message, and commits to git.
 * @class
 */
class GitAddAndCommit {
	constructor(options = {}) {
		this.options = options

		if (options.help || options.args.length === 0) {
			this.showHelpScreen()
		} else if (options.interactive) {
			new Interactive(options).run()
		} else {
			this.run()
		}
	}

	/**
	 * Finds all files that match the given globs and options given by the user.
	 * If there are already staged files, it promps the user to continue. Tries
	 * to stage all matched files and commits. If there is an error, it lets the
	 * user know and resets all files that were staged successfully.
	 */
	run() {
		if (this.options.args.length < 2) {
			console.log('File glob and commit message required. See help screen for correct usage.')
			return
		}

		this.globs = this.options.args.slice()
		this.message = this.globs.pop()

		// find all files based on the given globs and options
		let files = utils.getFilesOfTypes(this.options.find)
		this.matches = utils.matchGlobsAgainstFiles(files, this.globs, {
			caseSensitive: this.options.caseSensitive
		})

		this.checkForStagedFiles().then(shouldContinue => {
			this.matches.forEach(file => {
				execSync(`git add ${file}`)
			})

			execSync(`git commit -m "${this.message}"`)
			console.log(`Commit successful.`)
		}).catch(() => {
			console.log(`Error encountered -- aborting.`)

			try {
				this.matches.forEach(file => {
					execSync(`git reset ${file}`)
				})
			} catch (e) {}
		})
	}

	/**
	 * If there are already staged files that don't match any of the given globs,
	 * prints them to the screen and prompts the user to continue with the commit.
	 */
	checkForStagedFiles() {
		return new Promise((resolve, reject) => {
			let extraStagedFiles = gitFiles.staged('relative').filter(file => {
				return !this.matches.includes(file)
			})

			if (extraStagedFiles.length === 0) {
				resolve()
			} else {
				jumper.block(chalk.bold(`There are files already staged for commit but do not match the glob(s) given.`))
				extraStagedFiles.forEach(file => jumper.block(`  ${chalk.green(file)}`))
				jumper.break()

				jumper.block(chalk.bold(`Continue? (y/n): `), 'continue')
				jumper.render()
				jumper.jumpTo('continue', -1)

				process.stdin.on('data', (data) => {
					process.stdin.end()
					let answer = data.toString('utf8').trim().toLowerCase()

					true && ['yes', 'y'].includes(answer) ? resolve() : reject()

					// this doesn't work. node will throw a `cannot read property 'includes' of undefined`. Bonkers.
					// ['yes', 'y'].includes(answer) ? resolve() : reject()

					// there is also this way as a workaround
					// let nothing = ['yes', 'y'].includes(answer) ? resolve() : reject()

					// what's another way...let me see...

					// this one's pretty cool. I still think there's an even worse way to do it...
					// !!['yes', 'y'].includes(answer) ? resolve() : reject()

					// Haha! I found you.
					// eval(`['yes', 'y'].includes(answer) ? resolve() : reject()`)
				})
			}
		})
	}

	/**
 	 * Shows the help screen.
   */
	showHelpScreen() {
		let helpFile = join(__dirname, '../help.txt')
		let helpScreen = execSync(`cat ${helpFile}`)
		console.log(helpScreen.toString('utf8'))
	}
}

module.exports = GitAddAndCommit
<commit_msg>Remove rambling comments<commit_after>const join = require('path').join
const execSync = require('child_process').execSync
const chalk = require('chalk')
const gitFiles = require('git-files')
const jumper = require('terminal-jumper')
const Interactive = require('./interactive')
const utils = require('./utils')

/**
 * Reads a file glob and a commit message, and commits to git.
 * @class
 */
class GitAddAndCommit {
	constructor(options = {}) {
		this.options = options

		if (options.help || options.args.length === 0) {
			this.showHelpScreen()
		} else if (options.interactive) {
			new Interactive(options).run()
		} else {
			this.run()
		}
	}

	/**
	 * Finds all files that match the given globs and options given by the user.
	 * If there are already staged files, it promps the user to continue. Tries
	 * to stage all matched files and commits. If there is an error, it lets the
	 * user know and resets all files that were staged successfully.
	 */
	run() {
		if (this.options.args.length < 2) {
			console.log('File glob and commit message required. See help screen for correct usage.')
			return
		}

		this.globs = this.options.args.slice()
		this.message = this.globs.pop()

		// find all files based on the given globs and options
		let files = utils.getFilesOfTypes(this.options.find)
		this.matches = utils.matchGlobsAgainstFiles(files, this.globs, {
			caseSensitive: this.options.caseSensitive
		})

		this.checkForStagedFiles().then(shouldContinue => {
			this.matches.forEach(file => {
				execSync(`git add ${file}`)
			})

			execSync(`git commit -m "${this.message}"`)
			console.log(`Commit successful.`)
		}).catch(() => {
			console.log(`Error encountered -- aborting.`)

			try {
				this.matches.forEach(file => {
					execSync(`git reset ${file}`)
				})
			} catch (e) {}
		})
	}

	/**
	 * If there are already staged files that don't match any of the given globs,
	 * prints them to the screen and prompts the user to continue with the commit.
	 */
	checkForStagedFiles() {
		return new Promise((resolve, reject) => {
			let extraStagedFiles = gitFiles.staged('relative').filter(file => {
				return !this.matches.includes(file)
			})

			if (extraStagedFiles.length === 0) {
				resolve()
			} else {
				jumper.block(chalk.bold(`There are files already staged for commit but do not match the glob(s) given.`))
				extraStagedFiles.forEach(file => jumper.block(`  ${chalk.green(file)}`))
				jumper.break()

				jumper.block(chalk.bold(`Continue? (y/n): `), 'continue')
				jumper.render()
				jumper.jumpTo('continue', -1)

				process.stdin.on('data', (data) => {
					process.stdin.end()
					let answer = data.toString('utf8').trim().toLowerCase()

					// without eval, node will throw a `cannot read property 'includes' of undefined`. Bonkers.
					eval(`['yes', 'y'].includes(answer) ? resolve() : reject()`)
				})
			}
		})
	}

	/**
 	 * Shows the help screen.
   */
	showHelpScreen() {
		let helpFile = join(__dirname, '../help.txt')
		let helpScreen = execSync(`cat ${helpFile}`)
		console.log(helpScreen.toString('utf8'))
	}
}

module.exports = GitAddAndCommit
<|endoftext|>


<commit_before>import _ from 'lodash'
import AWS from 'aws-sdk'
import winston from 'winston'

const AWS_PREFIX = 'aws'

/**
 * @param key the name of the ElasticSearch cluster to resolve
 * @param awsParameters parameters to pass to the AWS.ES constructor
 * @returns {Promise<AWS.ES.ElasticsearchDomainStatus>}
 * @see http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/ES.html#describeElasticsearchDomain-property
 */
async function getESSValue(key, awsParameters) {
  winston.debug(`Resolving ElasticSearch cluster with name ${key}`)
  const ess = new AWS.ES({ ...awsParameters, apiVersion: '2015-01-01' })
  const result = await ess.describeElasticsearchDomain({ DomainName: key }).promise()
  if (!result || !result.DomainStatus) {
    throw new Error(`Could not find ElasticSearch cluster with name ${key}`)
  }

  return result.DomainStatus
}

/**
 * @param key the name of the security group to resolve
 * @param awsParameters parameters to pass to the AWS.EC2 constructor
 * @returns {Promise<AWS.EC2.SecurityGroup>}
 * @see http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/EC2.html#describeSecurityGroups-property
 */
async function getEC2Value(key, awsParameters) {
  const ec2 = new AWS.EC2({...awsParameters, apiVersion: '2015-01-01'})

  const values = key.split(':')

  if (values[0] === 'vpc') {
    return getVPCValue(values[1], awsParameters)
  } else if (values[0] === 'subnet') {
    return getSubnetValue(values[1], awsParameters)
  } else if (values[0] === 'securityGroup') {
    const groupValues = values[1].split('-')
    const vpc = await getVPCValue(groupValues[0], awsParameters)
    const result = await ec2.describeSecurityGroups(
      {
        Filters: [{Name: 'group-name', Values: [groupValues[1]]},
          {Name: 'vpc-id', Values: [vpc.VpcId]}]
      }).promise()

    if (!result || !result.SecurityGroups.length) {
      throw new Error(`Could not find security group with name ${groupValues[1]} in ${vpc.VpcId}`)
    }
    return result.SecurityGroups[0]
  }
  throw new Error(`Unsupported EC2 value. ${values[0]}`)
}

/**
 * @param key the name of the VPC to resolve
 * @param awsParameters parameters to pass to the AWS.EC2 constructor
 * @returns {Promise<AWS.EC2.DescribeVpcs>}
 * @see http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/EC2.html#describeVpcs-property
 */
async function getVPCValue(key, awsParameters) {
  winston.debug(`Resolving vpc with name ${key}`)
  const ec2 = new AWS.EC2({ ...awsParameters, apiVersion: '2015-01-01' })
  const result = await ec2.describeVpcs(
    {Filters: [{Name: 'tag-value', Values: [key]}]}).promise()

  if (!result || !result.Vpcs.length) {
    throw new Error(`Could not find vpc with name ${key}`)
  }

  return result.Vpcs[0]
}

/**
 * @param key the name of the subnet to resolve
 * @param awsParameters parameters to pass to the AWS.EC2 constructor
 * @returns {Promise<AWS.EC2.DescribeSubnets>}
 * @see http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/EC2.html#describeSubnets-property
 */
async function getSubnetValue(key, awsParameters) {
  winston.debug(`Resolving subnet with name ${key}`)
  const ec2 = new AWS.EC2({ ...awsParameters, apiVersion: '2015-01-01' })
  const result = await ec2.describeSubnets(
    {Filters: [{Name: 'tag-value', Values: [key]}]}).promise()

  if (!result || !result.Subnets.length) {
    throw new Error(`Could not find subnet with name ${key}`)
  }

  return result.Subnets[0]
}

/**
 * @param key the name of the Kinesis stream to resolve
 * @param awsParameters parameters to pass to the AWS.Kinesis constructor
 * @returns {Promise<AWS.Kinesis.StreamDescription>}
 * @see http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Kinesis.html#describeStream-property
 */
async function getKinesisValue(key, awsParameters) {
  winston.debug(`Resolving Kinesis stream with name ${key}`)
  const kinesis = new AWS.Kinesis({ ...awsParameters, apiVersion: '2013-12-02' })
  const result = await kinesis.describeStream({ StreamName: key }).promise()
  return result.StreamDescription
}

/**
 * @param key the name of the DynamoDb table to resolve
 * @param awsParameters parameters to pass to the AWS.DynamoDB constructor
 * @returns {Promise<AWS.DynamoDB.Table>}
 * @see http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB.html#describeTable-property
 */
async function getDynamoDbValue(key, awsParameters) {
  winston.debug(`Resolving Kinesis stream with name ${key}`)
  const dynamodb = new AWS.DynamoDB({ ...awsParameters, apiVersion: '2012-08-10' })
  const result = await dynamodb.describeTable({ TableName: key }).promise()
  return result.Table
}

/**
 * @param key the name of the RDS instance to resolve
 * @param awsParameters parameters to pass to the AWS.RDS constructor
 * @returns {Promise.<AWS.RDS.DBInstance>}
 * @see http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/RDS.html#describeDBInstances-property
 */
async function getRDSValue(key, awsParameters) {
  winston.debug(`Resolving RDS database with name ${key}`)
  const rds = new AWS.RDS({ ...awsParameters, apiVersion: '2014-10-31' })
  const result = await rds.describeDBInstances({ DBInstanceIdentifier: key }).promise()
  if (!result) {
    throw new Error(`Could Not find any databases with identifier ${key}`)
  }
  // Parse out the instances
  const instances = result.DBInstances

  if (instances.length !== 1) {
    throw new Error(`Expected exactly one DB instance for key ${key}. Got ${Object.keys(instances)}`)
  }

  return instances[0]
}

const AWS_HANDLERS = {
  ess: getESSValue,
  kinesis: getKinesisValue,
  dynamodb: getDynamoDbValue,
  rds: getRDSValue,
  ec2: getEC2Value
}

const DEFAULT_AWS_PATTERN = /^aws:\w+:[\w-.]+:\w+$/
const SUB_SERVICE_AWS_PATTERN = /^aws:\w+:\w+:[\w-.]+:\w+$/
/**
 * @param variableString the variable to resolve
 * @param region the AWS region to use
 * @returns {Promise.<String>} a promise for the resolved variable
 * @example const myResolvedVariable = await getValueFromAws('aws:kinesis:my-stream:StreamARN', 'us-east-1')
 */
async function getValueFromAws(variableString, region) {
  // The format is aws:${service}:${key}:${request} or aws:${service}:${subService}:${key}:${request}.
  // eg.: aws:kinesis:stream-name:StreamARN
  // Validate the input format
  if (!variableString.match(DEFAULT_AWS_PATTERN) && !variableString.match(SUB_SERVICE_AWS_PATTERN)) {
    throw new Error(`Invalid AWS format for variable ${variableString}`)
  }

  const rest = variableString.split(`${AWS_PREFIX}:`)[1]
  for (const service of Object.keys(AWS_HANDLERS)) {
    if (rest.startsWith(`${service}:`)) {
      const commonParameters = {}
      if (region) {
        commonParameters.region = region
      }

      // Parse out the key and request
      let subKey = rest.split(`${service}:`)[1]

      let request = ''
      let key = ''
      // We are dealing with a subService instead of a standard service
      if (variableString.match(SUB_SERVICE_AWS_PATTERN)) {
        request = subKey.split(':')[2]
        key = subKey.split(':').slice(0, 2).join(':')
      } else {
        request = subKey.split(':')[1]
        key = subKey.split(':')[0]
      }

      const description = await AWS_HANDLERS[service](key, commonParameters) // eslint-disable-line no-await-in-loop, max-len
      // Validate that the desired property exists
      if (!_.has(description, request)) {
        throw new Error(`Error resolving ${variableString}. Key '${request}' not found. Candidates are ${Object.keys(description)}`)
      }

      return _.get(description, request)
    }
  }

  throw new TypeError(`Cannot parse AWS type from ${rest}`)
}

/**
 * A plugin for the serverless framework that allows resolution of deployed AWS services into variable names
 */
class ServerlessAWSResolvers {
  constructor(serverless, options) {
    this.provider = 'aws'

    this.commands = {
      resolveAwsKey: {
        usage: `Resolves an AWS key (Supported prefixes: ${Object.keys(AWS_HANDLERS)})`,
        lifecycleEvents: ['run'],
        options: {
          key: {
            usage: 'The key to resolve',
            shortcut: 'k'
          }
        }
      }
    }

    this.hooks = {
      'resolveAwsKey:run': () => getValueFromAws(options.key, serverless.service.provider.region)
        .then(JSON.stringify)
        .then(_.bind(serverless.cli.log, serverless.cli))
    }

    const delegate = _.bind(serverless.variables.getValueFromSource, serverless.variables)
    serverless.variables.getValueFromSource = function getValueFromSource(variableString) { // eslint-disable-line no-param-reassign, max-len
      const region = serverless.service.provider.region
      if (!region) {
        throw new Error('Cannot hydrate AWS variables without a region')
      }
      if (variableString.startsWith(`${AWS_PREFIX}:`)) {
        return getValueFromAws(variableString, region)
      }

      return delegate(variableString)
    }
  }
}

module.exports = ServerlessAWSResolvers
<commit_msg>fix type in log<commit_after>import _ from 'lodash'
import AWS from 'aws-sdk'
import winston from 'winston'

const AWS_PREFIX = 'aws'

/**
 * @param key the name of the ElasticSearch cluster to resolve
 * @param awsParameters parameters to pass to the AWS.ES constructor
 * @returns {Promise<AWS.ES.ElasticsearchDomainStatus>}
 * @see http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/ES.html#describeElasticsearchDomain-property
 */
async function getESSValue(key, awsParameters) {
  winston.debug(`Resolving ElasticSearch cluster with name ${key}`)
  const ess = new AWS.ES({ ...awsParameters, apiVersion: '2015-01-01' })
  const result = await ess.describeElasticsearchDomain({ DomainName: key }).promise()
  if (!result || !result.DomainStatus) {
    throw new Error(`Could not find ElasticSearch cluster with name ${key}`)
  }

  return result.DomainStatus
}

/**
 * @param key the name of the security group to resolve
 * @param awsParameters parameters to pass to the AWS.EC2 constructor
 * @returns {Promise<AWS.EC2.SecurityGroup>}
 * @see http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/EC2.html#describeSecurityGroups-property
 */
async function getEC2Value(key, awsParameters) {
  const ec2 = new AWS.EC2({...awsParameters, apiVersion: '2015-01-01'})

  const values = key.split(':')

  if (values[0] === 'vpc') {
    return getVPCValue(values[1], awsParameters)
  } else if (values[0] === 'subnet') {
    return getSubnetValue(values[1], awsParameters)
  } else if (values[0] === 'securityGroup') {
    const groupValues = values[1].split('-')
    const vpc = await getVPCValue(groupValues[0], awsParameters)
    const result = await ec2.describeSecurityGroups(
      {
        Filters: [{Name: 'group-name', Values: [groupValues[1]]},
          {Name: 'vpc-id', Values: [vpc.VpcId]}]
      }).promise()

    if (!result || !result.SecurityGroups.length) {
      throw new Error(`Could not find security group with name ${groupValues[1]} in ${vpc.VpcId}`)
    }
    return result.SecurityGroups[0]
  }
  throw new Error(`Unsupported EC2 value. ${values[0]}`)
}

/**
 * @param key the name of the VPC to resolve
 * @param awsParameters parameters to pass to the AWS.EC2 constructor
 * @returns {Promise<AWS.EC2.DescribeVpcs>}
 * @see http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/EC2.html#describeVpcs-property
 */
async function getVPCValue(key, awsParameters) {
  winston.debug(`Resolving vpc with name ${key}`)
  const ec2 = new AWS.EC2({ ...awsParameters, apiVersion: '2015-01-01' })
  const result = await ec2.describeVpcs(
    {Filters: [{Name: 'tag-value', Values: [key]}]}).promise()

  if (!result || !result.Vpcs.length) {
    throw new Error(`Could not find vpc with name ${key}`)
  }

  return result.Vpcs[0]
}

/**
 * @param key the name of the subnet to resolve
 * @param awsParameters parameters to pass to the AWS.EC2 constructor
 * @returns {Promise<AWS.EC2.DescribeSubnets>}
 * @see http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/EC2.html#describeSubnets-property
 */
async function getSubnetValue(key, awsParameters) {
  winston.debug(`Resolving subnet with name ${key}`)
  const ec2 = new AWS.EC2({ ...awsParameters, apiVersion: '2015-01-01' })
  const result = await ec2.describeSubnets(
    {Filters: [{Name: 'tag-value', Values: [key]}]}).promise()

  if (!result || !result.Subnets.length) {
    throw new Error(`Could not find subnet with name ${key}`)
  }

  return result.Subnets[0]
}

/**
 * @param key the name of the Kinesis stream to resolve
 * @param awsParameters parameters to pass to the AWS.Kinesis constructor
 * @returns {Promise<AWS.Kinesis.StreamDescription>}
 * @see http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Kinesis.html#describeStream-property
 */
async function getKinesisValue(key, awsParameters) {
  winston.debug(`Resolving Kinesis stream with name ${key}`)
  const kinesis = new AWS.Kinesis({ ...awsParameters, apiVersion: '2013-12-02' })
  const result = await kinesis.describeStream({ StreamName: key }).promise()
  return result.StreamDescription
}

/**
 * @param key the name of the DynamoDb table to resolve
 * @param awsParameters parameters to pass to the AWS.DynamoDB constructor
 * @returns {Promise<AWS.DynamoDB.Table>}
 * @see http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB.html#describeTable-property
 */
async function getDynamoDbValue(key, awsParameters) {
  winston.debug(`Resolving DynamoDB stream with name ${key}`)
  const dynamodb = new AWS.DynamoDB({ ...awsParameters, apiVersion: '2012-08-10' })
  const result = await dynamodb.describeTable({ TableName: key }).promise()
  return result.Table
}

/**
 * @param key the name of the RDS instance to resolve
 * @param awsParameters parameters to pass to the AWS.RDS constructor
 * @returns {Promise.<AWS.RDS.DBInstance>}
 * @see http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/RDS.html#describeDBInstances-property
 */
async function getRDSValue(key, awsParameters) {
  winston.debug(`Resolving RDS database with name ${key}`)
  const rds = new AWS.RDS({ ...awsParameters, apiVersion: '2014-10-31' })
  const result = await rds.describeDBInstances({ DBInstanceIdentifier: key }).promise()
  if (!result) {
    throw new Error(`Could Not find any databases with identifier ${key}`)
  }
  // Parse out the instances
  const instances = result.DBInstances

  if (instances.length !== 1) {
    throw new Error(`Expected exactly one DB instance for key ${key}. Got ${Object.keys(instances)}`)
  }

  return instances[0]
}

const AWS_HANDLERS = {
  ess: getESSValue,
  kinesis: getKinesisValue,
  dynamodb: getDynamoDbValue,
  rds: getRDSValue,
  ec2: getEC2Value
}

const DEFAULT_AWS_PATTERN = /^aws:\w+:[\w-.]+:\w+$/
const SUB_SERVICE_AWS_PATTERN = /^aws:\w+:\w+:[\w-.]+:\w+$/
/**
 * @param variableString the variable to resolve
 * @param region the AWS region to use
 * @returns {Promise.<String>} a promise for the resolved variable
 * @example const myResolvedVariable = await getValueFromAws('aws:kinesis:my-stream:StreamARN', 'us-east-1')
 */
async function getValueFromAws(variableString, region) {
  // The format is aws:${service}:${key}:${request} or aws:${service}:${subService}:${key}:${request}.
  // eg.: aws:kinesis:stream-name:StreamARN
  // Validate the input format
  if (!variableString.match(DEFAULT_AWS_PATTERN) && !variableString.match(SUB_SERVICE_AWS_PATTERN)) {
    throw new Error(`Invalid AWS format for variable ${variableString}`)
  }

  const rest = variableString.split(`${AWS_PREFIX}:`)[1]
  for (const service of Object.keys(AWS_HANDLERS)) {
    if (rest.startsWith(`${service}:`)) {
      const commonParameters = {}
      if (region) {
        commonParameters.region = region
      }

      // Parse out the key and request
      let subKey = rest.split(`${service}:`)[1]

      let request = ''
      let key = ''
      // We are dealing with a subService instead of a standard service
      if (variableString.match(SUB_SERVICE_AWS_PATTERN)) {
        request = subKey.split(':')[2]
        key = subKey.split(':').slice(0, 2).join(':')
      } else {
        request = subKey.split(':')[1]
        key = subKey.split(':')[0]
      }

      const description = await AWS_HANDLERS[service](key, commonParameters) // eslint-disable-line no-await-in-loop, max-len
      // Validate that the desired property exists
      if (!_.has(description, request)) {
        throw new Error(`Error resolving ${variableString}. Key '${request}' not found. Candidates are ${Object.keys(description)}`)
      }

      return _.get(description, request)
    }
  }

  throw new TypeError(`Cannot parse AWS type from ${rest}`)
}

/**
 * A plugin for the serverless framework that allows resolution of deployed AWS services into variable names
 */
class ServerlessAWSResolvers {
  constructor(serverless, options) {
    this.provider = 'aws'

    this.commands = {
      resolveAwsKey: {
        usage: `Resolves an AWS key (Supported prefixes: ${Object.keys(AWS_HANDLERS)})`,
        lifecycleEvents: ['run'],
        options: {
          key: {
            usage: 'The key to resolve',
            shortcut: 'k'
          }
        }
      }
    }

    this.hooks = {
      'resolveAwsKey:run': () => getValueFromAws(options.key, serverless.service.provider.region)
        .then(JSON.stringify)
        .then(_.bind(serverless.cli.log, serverless.cli))
    }

    const delegate = _.bind(serverless.variables.getValueFromSource, serverless.variables)
    serverless.variables.getValueFromSource = function getValueFromSource(variableString) { // eslint-disable-line no-param-reassign, max-len
      const region = serverless.service.provider.region
      if (!region) {
        throw new Error('Cannot hydrate AWS variables without a region')
      }
      if (variableString.startsWith(`${AWS_PREFIX}:`)) {
        return getValueFromAws(variableString, region)
      }

      return delegate(variableString)
    }
  }
}

module.exports = ServerlessAWSResolvers
<|endoftext|>


<commit_before>import express from 'express'
import basicAuth from 'node-basicauth'
import bodyParser from 'body-parser'
import cookieParser from 'cookie-parser'
import compression from 'compression'
import babelify from 'express-babelify-middleware'
import fs from 'fs'
import morgan from 'morgan'
import winston from 'winston'
import errorHandler from 'express-error-handler'
import { join } from 'path'
import favicon from 'serve-favicon'
import stylus from 'stylus'
import nib from 'nib'

import { isArray, isFunction, isString, isIterable } from 'magic-types'
import log from 'magic-server-log'

import appRoutes from './routes'
import headers from './headers'
import handle404 from './errors/handle404'
import handle500 from './errors/handle500'

// import { init as initAdmin } from 'magic-admin';
// import blog from 'magic-blog';

export Nedb from 'nedb'

export { renderPage } from './pages'

export const conjure =
  () =>
    express()

export const Express = express

export const Router = express.Router

const start =
  ({ app, port }) => {
    app.listen(port, err => {
      if (err) {
        log.error(err)
      }

      log(`app listening to port ${port}`)
    })
  }

export const Magic = app => {
  const dir = app.get('cwd') || join(process.cwd(), 'src')
  const css = app.get('css') || stylus
  const routes = app.get('routes')
  const env = app.get('env') || 'production'
  const publicDir = app.get('publicDir') || join('client', 'public')
  const viewDir = app.get('viewDir') || join('client', 'views')
  const appDirs = app.get('dirs')
  const basicAuthConfig = app.get('basicAuth')
  const port = app.get('port') || 1337
  const viewEngine = app.get('view engine') || 'pug'
  const babelifyFiles = app.get('babelifyFiles')
  const logLevel = app.get('logLevel') || 'combined'
  const dirs = {
    root: dir,
    public: join(dir, publicDir),
    views: join(dir, viewDir),
    ...appDirs,
  }

  const logFiles = {
    access: join(dir, 'logs', 'access.log'),
    error: join(dir, 'logs', 'error.log'),
    ...app.get('logFiles'),
  }

  const faviconPath = join(dirs.public, 'favicon.ico')

  app.set('css', css)
  app.set('dirs', dirs)

  // set req.app to use in middleware
  app.use(
    (req, res, next) => {
      req.app = app
      next()
    })

  // set expiry headers
  app.use(headers)

  // enable http basicAuth
  if (basicAuthConfig) {
    app.use(basicAuth(basicAuthConfig))
  }

  // fs.existsSync only gets called once on first request
  if (faviconPath && !app.get('faviconChecked') && !app.get('faviconExists')) {
    app.set('faviconChecked', true)
    app.set('faviconExists', fs.existsSync(faviconPath))
  }

  if (app.get('faviconExists')) {
    app.use(favicon(faviconPath))
  }

  app.set('views', dirs.views)
  app.set('view engine', viewEngine)

  app.use(compression({ threshold: 128 }))

  const cssMiddleware =
    (str, path) =>
      css(str)
        .set('filename', path)
        .set('compress', env === 'production')
        .use(nib())
        .import('nib')

  app.use(css.middleware({
    src: dirs.public,
    maxage: '1d',
    compile: cssMiddleware,
  }))

  if (isString(babelifyFiles) || isArray(babelifyFiles)) {
    [].concat(babelifyFiles).forEach(
      f => {
        // Precompile a browserified file at a path
        const fileUrl = `/js/${f}.js`
        const bundleUrl = `${dirs.public}/js/${f}/index.js`

        app.use(fileUrl, babelify(bundleUrl))
      }
    )
  }

  app.use(express.static(join(__dirname, 'public'), { maxAge: '1w' }))

  app.use(express.static(dirs.public, { maxAge: '1d' }))

  // if (app.enabled('admin')) {
  //   app.use(initAdmin);
  // }

  /*
   TODO: reenable
  if (app.get('blogRoot')) {
    let blogRoot = app.get('blogRoot');
    if (typeof blogRoot !== 'string' && typeof blogRoot !== 'number') {
      blogRoot = 'blog';
    }
    if (blogRoot.charAt(0) !== '/') {
      blogRoot = '/' + blogRoot;
    } else {
      app.set('blogRoot', blogRoot.substr(1));
    }
    app.use(blogRoot, blog);
  }
   */

  // logging
  app.use(morgan(logLevel))

  app.use(
    app.get('env') === 'development'
      ? errorHandler({ dumpExceptions: true, showStack: true })
      : errorHandler()
  )

  if (logFiles) {
    if (logFiles.access) {
      winston.add(winston.transports.File, {
        filename: logFiles.access,
      })
    }

    if (logFiles.error) {
      winston.handleExceptions(new winston.transports.File({
        filename: logFiles.error,
      }))
    }
  }

  // if host sets bodyparser to true, init it
  if (app.enabled('bodyParser')) {
    app.use(bodyParser.json())
    app.use(bodyParser.urlencoded({ extended: true }))
  }

  // if host sets cookieparser to true, init it:
  if (app.enabled('cookieParser')) {
    app.use(cookieParser())
  }

  // load host specific router
  if (routes) {
    if (isIterable(routes)) {
      Object.keys(routes).forEach(
        key => {
          const route = routes[key]
          const { path, handler, method = 'get' } = routes[key]

          const isValidMethod = ['get', 'post'].some(v => v === method)
          if (!isValidMethod) {
            throw new Error(`Route method of type ${method} is not valid`)
          }

          if (!isString(path)) {
            throw new Error(`Route needs a path string to work ${route}`)
          }

          if (!isFunction(handler)) {
            throw new Error(`Route needs a handler function to work ${route}`)
          }

          app[method](path, handler)
        }
      )
    }
    else if (isFunction(routes)) {
      app.use(routes)
    }
  }

  // default router
  app.use(appRoutes)

  // we are in a 404 error
  app.use(handle404)

  // oops, worst case fallback, 500 server error.
  app.use(handle500)

  start({ app, port })

  return app
}

export default Magic
<commit_msg>export mailgun<commit_after>import express from 'express'
import basicAuth from 'node-basicauth'
import bodyParser from 'body-parser'
import cookieParser from 'cookie-parser'
import compression from 'compression'
import babelify from 'express-babelify-middleware'
import fs from 'fs'
import morgan from 'morgan'
import winston from 'winston'
import errorHandler from 'express-error-handler'
import { join } from 'path'
import favicon from 'serve-favicon'
import stylus from 'stylus'
import nib from 'nib'

import { isArray, isFunction, isString, isIterable } from 'magic-types'
import log from 'magic-server-log'

import appRoutes from './routes'
import headers from './headers'
import handle404 from './errors/handle404'
import handle500 from './errors/handle500'

// import { init as initAdmin } from 'magic-admin';
// import blog from 'magic-blog';

export Nedb from 'nedb'

export { Mailgun } from 'mailgun'

export { renderPage } from './pages'

export const conjure =
  () =>
    express()

export const Express = express

export const Router = express.Router

const start =
  ({ app, port }) => {
    app.listen(port, err => {
      if (err) {
        log.error(err)
      }

      log(`app listening to port ${port}`)
    })
  }

export const Magic = app => {
  const dir = app.get('cwd') || join(process.cwd(), 'src')
  const css = app.get('css') || stylus
  const routes = app.get('routes')
  const env = app.get('env') || 'production'
  const publicDir = app.get('publicDir') || join('client', 'public')
  const viewDir = app.get('viewDir') || join('client', 'views')
  const appDirs = app.get('dirs')
  const basicAuthConfig = app.get('basicAuth')
  const port = app.get('port') || 1337
  const viewEngine = app.get('view engine') || 'pug'
  const babelifyFiles = app.get('babelifyFiles')
  const logLevel = app.get('logLevel') || 'combined'
  const dirs = {
    root: dir,
    public: join(dir, publicDir),
    views: join(dir, viewDir),
    ...appDirs,
  }

  const logFiles = {
    access: join(dir, 'logs', 'access.log'),
    error: join(dir, 'logs', 'error.log'),
    ...app.get('logFiles'),
  }

  const faviconPath = join(dirs.public, 'favicon.ico')

  app.set('css', css)
  app.set('dirs', dirs)

  // set req.app to use in middleware
  app.use(
    (req, res, next) => {
      req.app = app
      next()
    })

  // set expiry headers
  app.use(headers)

  // enable http basicAuth
  if (basicAuthConfig) {
    app.use(basicAuth(basicAuthConfig))
  }

  // fs.existsSync only gets called once on first request
  if (faviconPath && !app.get('faviconChecked') && !app.get('faviconExists')) {
    app.set('faviconChecked', true)
    app.set('faviconExists', fs.existsSync(faviconPath))
  }

  if (app.get('faviconExists')) {
    app.use(favicon(faviconPath))
  }

  app.set('views', dirs.views)
  app.set('view engine', viewEngine)

  app.use(compression({ threshold: 128 }))

  const cssMiddleware =
    (str, path) =>
      css(str)
        .set('filename', path)
        .set('compress', env === 'production')
        .use(nib())
        .import('nib')

  app.use(css.middleware({
    src: dirs.public,
    maxage: '1d',
    compile: cssMiddleware,
  }))

  if (isString(babelifyFiles) || isArray(babelifyFiles)) {
    [].concat(babelifyFiles).forEach(
      f => {
        // Precompile a browserified file at a path
        const fileUrl = `/js/${f}.js`
        const bundleUrl = `${dirs.public}/js/${f}/index.js`

        app.use(fileUrl, babelify(bundleUrl))
      }
    )
  }

  app.use(express.static(join(__dirname, 'public'), { maxAge: '1w' }))

  app.use(express.static(dirs.public, { maxAge: '1d' }))

  // if (app.enabled('admin')) {
  //   app.use(initAdmin);
  // }

  /*
   TODO: reenable
  if (app.get('blogRoot')) {
    let blogRoot = app.get('blogRoot');
    if (typeof blogRoot !== 'string' && typeof blogRoot !== 'number') {
      blogRoot = 'blog';
    }
    if (blogRoot.charAt(0) !== '/') {
      blogRoot = '/' + blogRoot;
    } else {
      app.set('blogRoot', blogRoot.substr(1));
    }
    app.use(blogRoot, blog);
  }
   */

  // logging
  app.use(morgan(logLevel))

  app.use(
    app.get('env') === 'development'
      ? errorHandler({ dumpExceptions: true, showStack: true })
      : errorHandler()
  )

  if (logFiles) {
    if (logFiles.access) {
      winston.add(winston.transports.File, {
        filename: logFiles.access,
      })
    }

    if (logFiles.error) {
      winston.handleExceptions(new winston.transports.File({
        filename: logFiles.error,
      }))
    }
  }

  // if host sets bodyparser to true, init it
  if (app.enabled('bodyParser')) {
    app.use(bodyParser.json())
    app.use(bodyParser.urlencoded({ extended: true }))
  }

  // if host sets cookieparser to true, init it:
  if (app.enabled('cookieParser')) {
    app.use(cookieParser())
  }

  // load host specific router
  if (routes) {
    if (isIterable(routes)) {
      Object.keys(routes).forEach(
        key => {
          const route = routes[key]
          const { path, handler, method = 'get' } = routes[key]

          const isValidMethod = ['get', 'post'].some(v => v === method)
          if (!isValidMethod) {
            throw new Error(`Route method of type ${method} is not valid`)
          }

          if (!isString(path)) {
            throw new Error(`Route needs a path string to work ${route}`)
          }

          if (!isFunction(handler)) {
            throw new Error(`Route needs a handler function to work ${route}`)
          }

          app[method](path, handler)
        }
      )
    }
    else if (isFunction(routes)) {
      app.use(routes)
    }
  }

  // default router
  app.use(appRoutes)

  // we are in a 404 error
  app.use(handle404)

  // oops, worst case fallback, 500 server error.
  app.use(handle500)

  start({ app, port })

  return app
}

export default Magic
<|endoftext|>


<commit_before>import {HID} from 'node-hid';

const NIL = 0x00;

/**
 * Luxafor
 * @type {object}
 */
export default class Luxafor {

  constructor(pid = 62322, vid = 1240) {
    this.pid = pid;
    this.vid = vid;

    // Modes to change color in
    this.commands = {
      color: 1,
      fade: 2,
      strobe: 3,
      wave: 4
    };

    // Sides color can be applied
    this.sides = {
      both: 0xff,
      back: 0x42,
      front: 0x41
    };

    this.patterns = {
      police: 5
    };

    // Grab device
    this.device = new HID(vid, pid);
  }

  /**
   * Write to Luxafor
   * @author Josh Kloster <klosterjosh@gmail.com>
   * @param   {string}   command Lighting command
   * @param   {number}   speed Speed value 0-255
   * @param   {number}   repeat Repeat value 0-255
   * @returns {object[]} Three timing bytes
   */
  getTiming({command, speed, repeat}) {
    const timingBytes = {
      color: [NIL, NIL, NIL],
      fade: [speed, NIL, NIL],
      strobe: [speed, NIL, repeat],
      wave: [NIL, repeat, speed]
    };

    return timingBytes[command];
  }

  /**
   * Write to Luxafor
   * @author Matt Goucher <matt@mattgoucher.com>
   * @param   {string} command Lighting command
   * @param   {string} side Side to write to
   * @param   {number} r Red value 0-255
   * @param   {number} g Green value 0-255
   * @param   {number} b Blue value 0-255
   * @param   {number} speed value 0-255
   * @param   {number} repeat value 0-255
   * @returns {object} Instance
   */
  write({command, side, r, g, b, speed, repeat}) {
    const baseBytes = [this.commands[command], this.sides[side], r, g, b];
    const timingBytes = this.getTiming({command, speed, repeat});

    this.device.write([...baseBytes, ...timingBytes]);
    return this;
  }

  /**
   * Change the Luxafor's color
   * @author Matt Goucher <matt@mattgoucher.com>
   * @param   {number} r Red value 0-255
   * @param   {number} g Green value 0-255
   * @param   {number} b Blue value 0-255
   * @param   {string} side Side to change
   * @param   {string} command Lighting mode
   * @returns {object} Instance
   */
  setColor(r, g, b, side = 'both', command = 'color') {
    this.write({command, side, r, g, b, speed: NIL, repeat: NIL});
    return this;
  }
}
<commit_msg>Fixed jsdocs<commit_after>import {HID} from 'node-hid';

const NIL = 0x00;

/**
 * Luxafor
 * @type {object}
 */
export default class Luxafor {

  constructor(pid = 62322, vid = 1240) {
    this.pid = pid;
    this.vid = vid;

    // Modes to change color in
    this.commands = {
      color: 1,
      fade: 2,
      strobe: 3,
      wave: 4
    };

    // Sides color can be applied
    this.sides = {
      both: 0xff,
      back: 0x42,
      front: 0x41
    };

    this.patterns = {
      police: 5
    };

    // Grab device
    this.device = new HID(vid, pid);
  }

  /**
   * Write to Luxafor
   * @author Josh Kloster <klosterjosh@gmail.com>
   * @param   {string}   command Lighting command
   * @param   {number}   speed Speed value 0-255
   * @param   {number}   repeat Repeat value 0-255
   * @returns {number[]} Three timing bytes
   */
  getTiming({command, speed, repeat}) {
    const timingBytes = {
      color: [NIL, NIL, NIL],
      fade: [speed, NIL, NIL],
      strobe: [speed, NIL, repeat],
      wave: [NIL, repeat, speed]
    };

    return timingBytes[command];
  }

  /**
   * Write to Luxafor
   * @author Matt Goucher <matt@mattgoucher.com>
   * @param   {string} command Lighting command
   * @param   {string} side Side to write to
   * @param   {number} r Red value 0-255
   * @param   {number} g Green value 0-255
   * @param   {number} b Blue value 0-255
   * @param   {number} speed value 0-255
   * @param   {number} repeat value 0-255
   * @returns {object} Instance
   */
  write({command, side, r, g, b, speed, repeat}) {
    const baseBytes = [this.commands[command], this.sides[side], r, g, b];
    const timingBytes = this.getTiming({command, speed, repeat});

    this.device.write([...baseBytes, ...timingBytes]);
    return this;
  }

  /**
   * Change the Luxafor's color
   * @author Matt Goucher <matt@mattgoucher.com>
   * @param   {number} r Red value 0-255
   * @param   {number} g Green value 0-255
   * @param   {number} b Blue value 0-255
   * @param   {string} side Side to change
   * @param   {string} command Lighting mode
   * @returns {object} Instance
   */
  setColor(r, g, b, side = 'both', command = 'color') {
    this.write({command, side, r, g, b, speed: NIL, repeat: NIL});
    return this;
  }
}
<|endoftext|>


<commit_before>var express = require('express');
var path = require('path');
var https = require('https');

var app = express();

const port = process.env.PORT || 8080;

app.set('view engine', 'ejs');
app.use(express.static(path.join(__dirname, '/public')));

app.get('/', function(request, response) {
    response.render(path.join(__dirname, 'views', 'index'));
});

app.post('/event-handler', function(request) {
    var payload = '';

    request.on('data', function(chunk) {
        payload += chunk.toString();
    });

    request.on('end', function() {
        var pullRequest = JSON.parse(payload).pull_request;
        var sha = pullRequest.head.sha;
        var postData = JSON.stringify(
            {
                'state': 'success',
                'target_url': 'https://example.com/build/status',
                'description': 'The build succeeded!',
                'context': 'repo-state'
            }
        );

        var options = {
            protocol: 'https:',
            host: 'api.github.com',
            path: '/repos/ratherblue/ramis/statuses/' +
                sha + '?access_token=' + process.env.GITHUB_AUTH_TOKEN,
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Content-Length': Buffer.byteLength(postData),
                'User-Agent': 'Ramis-App'
            }
        };

        var req = https.request(options, function(res) {
            res.setEncoding('utf8');
        });

        req.write(postData);
        req.end();
    });
});

app.get('/oauth', function(request, response) {
    var params = [
        'client_id=368d97fad7902db3554c',
        'redirect_uri=http://localhost:8080/oauth-success',
        'scope=public_repo'
    ];

    var url = 'https://github.com/login/oauth/authorize?' + params.join('&');

    response.redirect(url);
});

app.get('/oauth-success', function(request, response) {
    response.render(path.join(__dirname, 'views', 'success'));
});

app.listen(port, function() {
    // eslint-disable-next-line no-console
    console.log('Running on http://localhost:' + port);
});

exports.init = function() {
    return false;
};
<commit_msg>externalize url<commit_after>var express = require('express');
var path = require('path');
var https = require('https');

var app = express();

const deployUrl = 'https://ramis-app.herokuapp.com';
const port = process.env.PORT || 8080;

app.set('view engine', 'ejs');
app.use(express.static(path.join(__dirname, '/public')));

app.get('/', function(request, response) {
    response.render(path.join(__dirname, 'views', 'index'));
});

app.post('/event-handler', function(request) {
    var payload = '';

    request.on('data', function(chunk) {
        payload += chunk.toString();
    });

    request.on('end', function() {
        var pullRequest = JSON.parse(payload).pull_request;
        var sha = pullRequest.head.sha;
        var postData = JSON.stringify(
            {
                'state': 'success',
                'target_url': 'https://example.com/build/status',
                'description': 'The build succeeded!',
                'context': 'repo-state'
            }
        );

        var options = {
            protocol: 'https:',
            host: 'api.github.com',
            path: '/repos/ratherblue/ramis/statuses/' +
                sha + '?access_token=' + process.env.GITHUB_AUTH_TOKEN,
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Content-Length': Buffer.byteLength(postData),
                'User-Agent': 'Ramis-App'
            }
        };

        var req = https.request(options, function(res) {
            res.setEncoding('utf8');
        });

        req.write(postData);
        req.end();
    });
});

app.get('/oauth', function(request, response) {
    var params = [
        'client_id=368d97fad7902db3554c',
        'redirect_uri=' + deployUrl + '/oauth-success',
        'scope=public_repo'
    ];

    var url = 'https://github.com/login/oauth/authorize?' + params.join('&');

    response.redirect(url);
});

app.get('/oauth-success', function(request, response) {
    response.render(path.join(__dirname, 'views', 'success'));
});

app.listen(port, function() {
    // eslint-disable-next-line no-console
    console.log('Running on http://localhost:' + port);
});

exports.init = function() {
    return false;
};
<|endoftext|>


<commit_before>const metas = new Map;
const queue = [];
const map = queue.map;
const some = queue.some;
const hasOwnProperty = queue.hasOwnProperty;
const origin = "https://unpkg.com/";
const parseRe = /^((?:@[^/@]+\/)?[^/@]+)(?:@([^/]+))?(?:\/(.*))?$/;

function string(value) {
  return typeof value === "string" ? value : "";
}

function parseIdentifier(identifier) {
  const match = parseRe.exec(identifier);
  return match && {
    name: match[1],
    version: match[2],
    path: match[3]
  };
}

function resolveMeta(target) {
  const url = `${origin}${target.name}${target.version ? `@${target.version}` : ""}/package.json`;
  let meta = metas.get(url);
  if (!meta) metas.set(url, meta = fetch(url).then(response => {
    if (!response.ok) throw new Error("unable to load package.json");
    if (response.redirected && !metas.has(response.url)) metas.set(response.url, meta);
    return response.json();
  }));
  return meta;
}

async function resolve(name, base) {
  if (name.startsWith(origin)) name = name.substring(origin.length);
  if (/^(\w+:)|\/\//i.test(name)) return name;
  if (/^[.]{0,2}\//i.test(name)) return new URL(name, base == null ? location : base).href;
  if (!name.length || /^[\s._]/.test(name) || /\s$/.test(name)) throw new Error("illegal name");
  const target = parseIdentifier(name);
  if (!target) return `${origin}${name}`;
  if (!target.version && base != null && base.startsWith(origin)) {
    const meta = await resolveMeta(parseIdentifier(base.substring(origin.length)));
    target.version = meta.dependencies && meta.dependencies[target.name] || meta.peerDependencies && meta.peerDependencies[target.name];
  }
  const meta = await resolveMeta(target);
  return `${origin}${meta.name}@${meta.version}/${target.path || string(meta.unpkg) || string(meta.browser) || string(meta.main) || "index.js"}`;
}

export const require = requireFrom(resolve);

export function requireFrom(resolver) {
  const cache = new Map;
  const requireBase = requireRelative(null);

  function requireAbsolute(url) {
    if (typeof url !== "string") return url;
    let module = cache.get(url);
    if (!module) cache.set(url, module = new Promise((resolve, reject) => {
      const script = document.createElement("script");
      script.onload = () => {
        try { resolve(queue.pop()(requireRelative(url))); }
        catch (error) { reject(new Error("invalid module")); }
        script.remove();
      };
      script.onerror = () => {
        reject(new Error("unable to load module"));
        script.remove();
      };
      script.async = true;
      script.src = url;
      window.define = define;
      document.head.appendChild(script);
    }));
    return module;
  }

  function requireRelative(base) {
    return name => Promise.resolve(resolver(name, base)).then(requireAbsolute);
  }

  function requireAlias(aliases) {
    return requireFrom((name, base) => {
      if (name in aliases) {
        name = aliases[name], base = null;
        if (typeof name !== "string") return name;
      }
      return resolver(name, base);
    });
  }

  function require(name) {
    return arguments.length > 1
        ? Promise.all(map.call(arguments, requireBase)).then(merge)
        : requireBase(name);
  }

  require.alias = requireAlias;
  require.resolve = resolver;

  return require;
}

function merge(modules) {
  const o = {};
  for (const m of modules) {
    for (const k in m) {
      if (hasOwnProperty.call(m, k)) {
        if (m[k] == null) Object.defineProperty(o, k, {get: getter(m, k)});
        else o[k] = m[k];
      }
    }
  }
  return o;
}

function getter(object, name) {
  return () => object[name];
}

function isexports(name) {
  return (name + "") === "exports";
}

function define(name, dependencies, factory) {
  const n = arguments.length;
  if (n < 2) factory = name, dependencies = [];
  else if (n < 3) factory = dependencies, dependencies = typeof name === "string" ? [] : name;
  queue.push(some.call(dependencies, isexports) ? require => {
    const exports = {};
    return Promise.all(map.call(dependencies, name => {
      return isexports(name += "") ? exports : require(name);
    })).then(dependencies => {
      factory.apply(null, dependencies);
      return exports;
    });
  } : require => {
    return Promise.all(map.call(dependencies, require)).then(dependencies => {
      return typeof factory === "function" ? factory.apply(null, dependencies) : factory;
    });
  });
}

define.amd = {};
<commit_msg>Skip package.json when explicit path and version.<commit_after>const metas = new Map;
const queue = [];
const map = queue.map;
const some = queue.some;
const hasOwnProperty = queue.hasOwnProperty;
const origin = "https://unpkg.com/";
const identifierRe = /^((?:@[^/@]+\/)?[^/@]+)(?:@([^/]+))?(?:\/(.*))?$/;
const versionRe = /^\d+\.\d+\.\d+(-[\w-.+]+)?$/g;

function string(value) {
  return typeof value === "string" ? value : "";
}

function parseIdentifier(identifier) {
  const match = identifierRe.exec(identifier);
  return match && {
    name: match[1],
    version: match[2],
    path: match[3]
  };
}

function resolveMeta(target) {
  const url = `${origin}${target.name}${target.version ? `@${target.version}` : ""}/package.json`;
  let meta = metas.get(url);
  if (!meta) metas.set(url, meta = fetch(url).then(response => {
    if (!response.ok) throw new Error("unable to load package.json");
    if (response.redirected && !metas.has(response.url)) metas.set(response.url, meta);
    return response.json();
  }));
  return meta;
}

async function resolve(name, base) {
  if (name.startsWith(origin)) name = name.substring(origin.length);
  if (/^(\w+:)|\/\//i.test(name)) return name;
  if (/^[.]{0,2}\//i.test(name)) return new URL(name, base == null ? location : base).href;
  if (!name.length || /^[\s._]/.test(name) || /\s$/.test(name)) throw new Error("illegal name");
  const target = parseIdentifier(name);
  if (!target) return `${origin}${name}`;
  if (!target.version && base != null && base.startsWith(origin)) {
    const meta = await resolveMeta(parseIdentifier(base.substring(origin.length)));
    target.version = meta.dependencies && meta.dependencies[target.name] || meta.peerDependencies && meta.peerDependencies[target.name];
  }
  if (target.path && target.version && versionRe.test(target.version)) return `${origin}${target.name}@${target.version}/${target.path}`;
  const meta = await resolveMeta(target);
  return `${origin}${meta.name}@${meta.version}/${target.path || string(meta.unpkg) || string(meta.browser) || string(meta.main) || "index.js"}`;
}

export const require = requireFrom(resolve);

export function requireFrom(resolver) {
  const cache = new Map;
  const requireBase = requireRelative(null);

  function requireAbsolute(url) {
    if (typeof url !== "string") return url;
    let module = cache.get(url);
    if (!module) cache.set(url, module = new Promise((resolve, reject) => {
      const script = document.createElement("script");
      script.onload = () => {
        try { resolve(queue.pop()(requireRelative(url))); }
        catch (error) { reject(new Error("invalid module")); }
        script.remove();
      };
      script.onerror = () => {
        reject(new Error("unable to load module"));
        script.remove();
      };
      script.async = true;
      script.src = url;
      window.define = define;
      document.head.appendChild(script);
    }));
    return module;
  }

  function requireRelative(base) {
    return name => Promise.resolve(resolver(name, base)).then(requireAbsolute);
  }

  function requireAlias(aliases) {
    return requireFrom((name, base) => {
      if (name in aliases) {
        name = aliases[name], base = null;
        if (typeof name !== "string") return name;
      }
      return resolver(name, base);
    });
  }

  function require(name) {
    return arguments.length > 1
        ? Promise.all(map.call(arguments, requireBase)).then(merge)
        : requireBase(name);
  }

  require.alias = requireAlias;
  require.resolve = resolver;

  return require;
}

function merge(modules) {
  const o = {};
  for (const m of modules) {
    for (const k in m) {
      if (hasOwnProperty.call(m, k)) {
        if (m[k] == null) Object.defineProperty(o, k, {get: getter(m, k)});
        else o[k] = m[k];
      }
    }
  }
  return o;
}

function getter(object, name) {
  return () => object[name];
}

function isexports(name) {
  return (name + "") === "exports";
}

function define(name, dependencies, factory) {
  const n = arguments.length;
  if (n < 2) factory = name, dependencies = [];
  else if (n < 3) factory = dependencies, dependencies = typeof name === "string" ? [] : name;
  queue.push(some.call(dependencies, isexports) ? require => {
    const exports = {};
    return Promise.all(map.call(dependencies, name => {
      return isexports(name += "") ? exports : require(name);
    })).then(dependencies => {
      factory.apply(null, dependencies);
      return exports;
    });
  } : require => {
    return Promise.all(map.call(dependencies, require)).then(dependencies => {
      return typeof factory === "function" ? factory.apply(null, dependencies) : factory;
    });
  });
}

define.amd = {};
<|endoftext|>