<commit_before>'use strict';

var assert = require('assert');
var KoaRouter = require('koa-router');
var parseBody = require('co-body');
var methods = require('methods');
var extend = require('deep-extend');
var path = require('path');
var findUp = require('findup-sync');
var titleCase = require('title-case');
var jsonRefs = require('json-refs');

const onSuccess = [
  {
    200: {
      description: 'Success'
    }
  }
];

const onError = [
  {
    400: {
      description: 'Error'
    }
  }
];

var methodsData = new WeakMap();

class Method {
  constructor(spec, path, method, parent) {

    var match = path.match(/^\/(\w*)\/?/);
    let prefix;
    assert(match && (prefix = match[1]),
      `Path ${path} should be int format /path or /path/anything`);

    Object.assign(spec, {
      tags: [prefix],
      summary: titleCase(`${method} ${prefix}`),
      description: '',
      responses: Object.assign({}, onSuccess[0], onError[0]),
      security: [{ internalApiKey: [] }]
    });

    methodsData.set(this, { spec, onSuccess, onError, parent });

  }

  tags(tags) {
    methodsData.get(this).spec.tags = toArray(tags);
    return this;
  }

  summary(summary) {
    methodsData.get(this).spec.summary = summary;
    return this;
  }

  description(description) {
    methodsData.get(this).spec.description = description;
    return this;
  }

  security(value) {
    methodsData.get(this).spec.security = value;
    return this;
  }

  spec() {
    return methodsData.get(this).spec;
  }

  params(params) {
    this.bodyRequested = false;
    methodsData.get(this).spec.parameters = toArray(params)
      .map(param => {
        if (param.in === 'body') {
          this.bodyRequested = true;
        }
        return toSpecParam(param);
      });
    return this;
  }

  onSuccess(response) {
    var data = methodsData.get(this);
    data.onSuccess = [];
    toArray(response)
      .forEach(response => data.onSuccess.push(toSpecResponse(data.parent, response, 200)));
    data.spec.responses = Object.assign({},
      data.onSuccess.reduce((result, response) => Object.assign(result, response), {}),
      data.onError.reduce((result, response) => Object.assign(result, response), {}));
    return this;
  }

  onError(response) {
    var data = methodsData.get(this);
    data.onError = [];
    toArray(response)
      .forEach(response => data.onError.push(toSpecResponse(data.parent, response, 400)));
    data.spec.responses = Object.assign({},
      data.onSuccess.reduce((result, response) => Object.assign(result, response), {}),
      data.onError.reduce((result, response) => Object.assign(result, response), {}));
    return this;
  }

  successStatuses() {
    var data = methodsData.get(this);
    return data.onSuccess.map(response => Number(Object.keys(response)[0]));
  }

  errors() {
    var data = methodsData.get(this);
    return data.onError.map(response => ({
      status: Number(Object.keys(response)[0]),
      name: response[Object.keys(response)[0]].name,
      show: response[Object.keys(response)[0]].show,
      catch: response[Object.keys(response)[0]].catch || []
    }));
  }
}

var specsData = new WeakMap();

class Spec {
  constructor(options) {
    options = options || {};

    let spec = options.spec;

    /*eslint-disable*/
    let dirname = options.__dirname;
    /*eslint-enable*/

    var pack = require(findUp('package.json', {
      cwd: dirname || path.dirname(module.parent.filename)
    }));

    let it = {};
    it.spec = extend({
      swagger: '2.0',
      info: {
        title: titleCase(pack.name),
        description: pack.description,
        version: pack.version,
        contact: {
          name: pack.author && pack.author.name
        },
        license: {
          name: pack.private === true ? 'Proprietary' : pack.license
        }
      },
      produces: [
        'application/json',
        'text/plain; charset=utf-8'
      ],
      schemes: [
        'https'
      ],
      security: [{ internalApiKey: [] }],
      securityDefinitions: {
        internalApiKey: {
          type: 'apiKey',
          name: 'api_key',
          in: 'header'
        }
      }
    }, spec);

    it.spec.paths = spec && spec.paths || {};
    it.spec.definitions = spec && spec.definitions || {};
    specsData.set(this, it);
  }

  setBasePath(basePath) {
    let it = specsData.get(this);
    it.spec.basePath = basePath;
  }

  addDefinition(name, definition) {
    let it = specsData.get(this);
    it.spec.definitions[name] = toJsonSchema(definition);
  }

  addMethod(path, method) {
    let it = specsData.get(this);
    path = path.replace(/\:(\w*)/g, (match, name) => `{${name}}`);
    it.spec.paths[path] = it.spec.paths[path] || {};
    assert(it.spec.paths[path][method] === void 0, `Method ${method} already defined for path ${path}`);
    return new Method(it.spec.paths[path][method] = {}, path, method, this);
  }

  get() {
    return specsData.get(this).spec;
  }

}

var routersData = new WeakMap();

class Router {

  constructor(options) {
    options = options || {};
    let prefix = options.prefix;
    let router = new KoaRouter();
    let spec = new Spec(options);
    routersData.set(this, { prefix, spec, router });
  }

  param() {
    var router = routersData.get(this).router;
    return router.param.apply(router, arguments);
  }

  use() {
    var router = routersData.get(this).router;
    return router.use.apply(router, arguments);
  }

  allowedMethods() {
    var router = routersData.get(this).router;
    return router.allowedMethods.apply(router, arguments);
  }

  get spec() {
    return routersData.get(this).spec;
  }

  routes() {
    const it = routersData.get(this);
    this
      .get('/spec', function*() {
        let spec = yield stripNotAuthorizedActions.call(this, it.prefix, it.spec.get());
        spec.host = this.host;
        const definition = this.query.definition;
        if (definition) {
          if (definition in spec.definitions) {
            this.body = spec.definitions[definition];
          }
        } else {
          this.body = spec;
        }
      })
      .params({
        in: 'query',
        name: 'definition',
        description: 'Fetch only the requested definition'
      })
      .onSuccess({
        description: 'A swagger specification or definition'
      });
    return it.router.routes();
  }

}

function normalizeResource(prefix, resource) {
  resource = resource.replace(/\:(\w*)/g, () => '*');
  return prefix ? `/${prefix}${resource}` : `${resource}`;
}

function* stripNotAuthorizedActions(prefix, spec) {

  let strip = function*() {
    spec = Object.assign({}, spec);

    let paths = {};
    let pathsKeys = Object.keys(spec.paths);
    for (let i = 0; i < pathsKeys.length; i++) {
      let path = pathsKeys[i];
      let methods = {};
      let methodsKeys = Object.keys(spec.paths[path]);
      for (let j = 0; j < methodsKeys.length; j++) {
        let method = methodsKeys[j];
        try {
          yield this.state.authorize.call(this, method, normalizeResource(prefix, path), spec.paths[path][method]);
          methods[method] = spec.paths[path][method];
        } catch (error) {
          if (error.status !== 403) {
            throw error;
          }
        }
      }
      if (Object.keys(methods).length) {
        paths[path] = methods;
      }
    }

    let definitions = {};
    var refs = jsonRefs.findRefs(paths);
    Object.keys(refs).forEach(key => {
      let values = jsonRefs.pathFromPtr(refs[key].uri);
      let definition = values[1];
      definitions[definition] = spec.definitions[definition];
    });

    spec.paths = paths;
    spec.definitions = definitions;
    return spec;
  }.bind(this);

  return !this.state.authorize ? spec : yield strip();
}

methods.forEach(function(method) {
  Router.prototype[method] = function(path, middleware) {
    let it = routersData.get(this);
    let thisMethod = it.spec.addMethod(path, method);
    const normalizedResource = normalizeResource(it.prefix, path);
    const thisMethodSpec = thisMethod.spec();
    it.router[method](path, function*(next) {
      try {
        if (this.state.authorize) {
          yield this.state.authorize.call(this, method, normalizedResource, thisMethodSpec);
        }
        if (thisMethod.bodyRequested) {
          this.state.body = yield parseBody(this);
        }
        yield *middleware.call(this, next);
        if (this.body !== void 0) {
          let successStatus = thisMethod.successStatuses();
          if (successStatus.indexOf(this.status) === -1) {
            this.status = successStatus[0];
          }
        }
      } catch (e) {
        this.status = e.status || 500;
        let errors = thisMethod.errors();
        errors.forEach(error => {
          error.catch.forEach(fn => {
            if (typeof fn === 'string' ? fn === e.name : fn(e)) {
              this.status = error.status;
              this.body = error.show(e);
            }
          });
        });
        this.app.emit('error', e, this);
      }
    });
    return thisMethod;
  };
});

function toArray(any) {
  return any ? Array.isArray(any) ? any : [any] : [];
}

function toSpecParam(param) {
  let specParam = {};
  specParam.in = param.in || 'query';
  specParam.name = param.name;
  specParam.description = param.description || '';
  specParam.required = specParam.in === 'path' ? true : param.required === true || false;
  if (param.schema) {
    specParam.schema = typeof param.schema === 'string' ? {
      $ref: `#/definitions/${param.schema}`
    } : param.schema;
    if (param.type === 'array') {
      specParam.items = specParam.schema;
      delete specParam.schema;
    }
  } else if (['date', 'datetime', 'time'].indexOf(param.type) !== -1) {
    specParam.type = 'string';
  } else {
    specParam.type = param.type || 'string';
  }
  if (param.format) {
    specParam.format = param.format;
  }
  return specParam;
}

function toSpecResponse(spec, response, status) {
  let specResponse = {};
  let statusObject = specResponse[response.status || status] = {};
  Object.defineProperty(statusObject, 'name', {
    value: response.name,
    writable: true
  });
  if (typeof response.schema === 'string') {
    statusObject.schema = {
      $ref: `#/definitions/${response.schema}`
    };
    statusObject.name = response.name || response.schema;
  } else if ('schema' in response) {
    if (response.name) {
      spec.addDefinition(response.name, response.schema);
      statusObject.schema = {
        $ref: `#/definitions/${response.name}`
      };
    } else {
      statusObject.schema = response.schema;
    }
  }
  if (typeof response.items === 'string') {
    statusObject.schema = {
      type: 'array',
      items: {
        $ref: `#/definitions/${response.items}`
      }
    };
    statusObject.name = response.name || response.schema;
    delete response.items;
  }
  statusObject.description = response.description || (status >= 400 ? 'Error' : 'Success');
  if (status >= 400) {
    Object.defineProperty(statusObject, 'show', {
      value: response.show || (error => ({ message: error.message }))
    });
    Object.defineProperty(statusObject, 'catch', {
      value: response.catch || [statusObject.name]
    });
  }
  return specResponse;
}

function toJsonSchema(schema, level) {
  level = level || 0;
  let definition = {};
  Object.keys(schema).forEach(function(key) {
    var value = schema[key];
    if (level === 0) {
      if (['properties', 'title', 'description', 'type']
          .indexOf(key) === -1) {
        key = 'x-' + key;
      }
    } else {
      if (['properties', 'title', 'description', 'type', 'schema', 'items']
          .indexOf(key) === -1) {
        key = 'x-' + key;
      }
    }
    switch (typeof value) {
      //case 'function':
      //  break;
      //case 'array':
      //  definition[key] = value.slice(0);
      //  break;
      case 'object':
        definition[key] = Object.assign({}, value);
        break;
      default:
        definition[key] = value;
    }
  });
  var required = [];
  Object.keys(definition.properties).forEach(function(key) {
    let source = definition.properties[key];
    if (source.required === true) {
      required.push(key);
    }
    let property = {};
    Object.keys(source).forEach(function(key) {
      if (key === 'required') {
        return;
      }
      var value = source[key];
      if (['title', 'description', 'type', 'schema', 'properties',
          '$ref', 'maxLength', 'format', 'enum', 'items']
          .indexOf(key) === -1) {
        key = 'x-' + key;
      }
      property[key] = value;
    });
    if (property.enum && property.maxLength) {
      delete property.maxLength;
    }
    if (['date', 'datetime', 'time'].indexOf(property.type) !== -1) {
      property.format = property.type;
      property.type = 'string';
    }
    if (property.type === 'object') {
      definition.properties[key] = toJsonSchema(property, level + 1);
    } else {
      if (property.type === 'array' && typeof property.items === 'object') {
        if (property.items.type === 'object') {
          property.items = toJsonSchema(property.items, level + 1);
        } else {
          property.items = {};
          Object.keys(source.items).forEach(function(key) {
            var value = source.items[key];
            if (['type']
                .indexOf(key) === -1) {
              key = 'x-' + key;
            }
            property.items[key] = value;
          });
        }
      } else if (property.schema) {
        let schema = {};
        if (property.schema.$ref) {
          schema['x-$ref'] = property.schema.$ref;
        }
        if (property.schema.key) {
          schema['x-key'] = property.schema.key;
        }
        property['x-schema'] = schema;
        delete property.schema;
      } else if (property.$ref) {
        property['x-$ref'] = property.$ref;
        delete property.$ref;
      }
      definition.properties[key] = property;
    }
  });
  if (required.length) {
    definition.required = required;
  }
  return definition;

}

module.exports = Router;
<commit_msg>Expose route user spec<commit_after>'use strict';

var assert = require('assert');
var KoaRouter = require('koa-router');
var parseBody = require('co-body');
var methods = require('methods');
var extend = require('deep-extend');
var path = require('path');
var findUp = require('findup-sync');
var titleCase = require('title-case');
var jsonRefs = require('json-refs');

const onSuccess = [
  {
    200: {
      description: 'Success'
    }
  }
];

const onError = [
  {
    400: {
      description: 'Error'
    }
  }
];

var methodsData = new WeakMap();

class Method {
  constructor(spec, path, method, parent) {

    var match = path.match(/^\/(\w*)\/?/);
    let prefix;
    assert(match && (prefix = match[1]),
      `Path ${path} should be int format /path or /path/anything`);

    Object.assign(spec, {
      tags: [prefix],
      summary: titleCase(`${method} ${prefix}`),
      description: '',
      responses: Object.assign({}, onSuccess[0], onError[0]),
      security: [{ internalApiKey: [] }]
    });

    methodsData.set(this, { spec, onSuccess, onError, parent });

  }

  tags(tags) {
    methodsData.get(this).spec.tags = toArray(tags);
    return this;
  }

  summary(summary) {
    methodsData.get(this).spec.summary = summary;
    return this;
  }

  description(description) {
    methodsData.get(this).spec.description = description;
    return this;
  }

  security(value) {
    methodsData.get(this).spec.security = value;
    return this;
  }

  get spec() {
    return methodsData.get(this).spec;
  }

  params(params) {
    this.bodyRequested = false;
    methodsData.get(this).spec.parameters = toArray(params)
      .map(param => {
        if (param.in === 'body') {
          this.bodyRequested = true;
        }
        return toSpecParam(param);
      });
    return this;
  }

  onSuccess(response) {
    var data = methodsData.get(this);
    data.onSuccess = [];
    toArray(response)
      .forEach(response => data.onSuccess.push(toSpecResponse(data.parent, response, 200)));
    data.spec.responses = Object.assign({},
      data.onSuccess.reduce((result, response) => Object.assign(result, response), {}),
      data.onError.reduce((result, response) => Object.assign(result, response), {}));
    return this;
  }

  onError(response) {
    var data = methodsData.get(this);
    data.onError = [];
    toArray(response)
      .forEach(response => data.onError.push(toSpecResponse(data.parent, response, 400)));
    data.spec.responses = Object.assign({},
      data.onSuccess.reduce((result, response) => Object.assign(result, response), {}),
      data.onError.reduce((result, response) => Object.assign(result, response), {}));
    return this;
  }

  successStatuses() {
    var data = methodsData.get(this);
    return data.onSuccess.map(response => Number(Object.keys(response)[0]));
  }

  errors() {
    var data = methodsData.get(this);
    return data.onError.map(response => ({
      status: Number(Object.keys(response)[0]),
      name: response[Object.keys(response)[0]].name,
      show: response[Object.keys(response)[0]].show,
      catch: response[Object.keys(response)[0]].catch || []
    }));
  }
}

var specsData = new WeakMap();

class Spec {
  constructor(options) {
    options = options || {};

    let spec = options.spec;

    /*eslint-disable*/
    let dirname = options.__dirname;
    /*eslint-enable*/

    var pack = require(findUp('package.json', {
      cwd: dirname || path.dirname(module.parent.filename)
    }));

    let it = {};
    it.spec = extend({
      swagger: '2.0',
      info: {
        title: titleCase(pack.name),
        description: pack.description,
        version: pack.version,
        contact: {
          name: pack.author && pack.author.name
        },
        license: {
          name: pack.private === true ? 'Proprietary' : pack.license
        }
      },
      produces: [
        'application/json',
        'text/plain; charset=utf-8'
      ],
      schemes: [
        'https'
      ],
      security: [{ internalApiKey: [] }],
      securityDefinitions: {
        internalApiKey: {
          type: 'apiKey',
          name: 'api_key',
          in: 'header'
        }
      }
    }, spec);

    it.spec.paths = spec && spec.paths || {};
    it.spec.definitions = spec && spec.definitions || {};
    specsData.set(this, it);
  }

  setBasePath(basePath) {
    let it = specsData.get(this);
    it.spec.basePath = basePath;
  }

  addDefinition(name, definition) {
    let it = specsData.get(this);
    it.spec.definitions[name] = toJsonSchema(definition);
  }

  addMethod(path, method) {
    let it = specsData.get(this);
    path = path.replace(/\:(\w*)/g, (match, name) => `{${name}}`);
    it.spec.paths[path] = it.spec.paths[path] || {};
    assert(it.spec.paths[path][method] === void 0, `Method ${method} already defined for path ${path}`);
    return new Method(it.spec.paths[path][method] = {}, path, method, this);
  }

  get() {
    return specsData.get(this).spec;
  }

}

var routersData = new WeakMap();

class Router {

  constructor(options) {
    options = options || {};
    let prefix = options.prefix;
    let router = new KoaRouter();
    let spec = new Spec(options);
    routersData.set(this, { prefix, spec, router });
  }

  param() {
    var router = routersData.get(this).router;
    return router.param.apply(router, arguments);
  }

  use() {
    var router = routersData.get(this).router;
    return router.use.apply(router, arguments);
  }

  allowedMethods() {
    var router = routersData.get(this).router;
    return router.allowedMethods.apply(router, arguments);
  }

  get spec() {
    return routersData.get(this).spec;
  }

  userSpec() {
    const it = routersData.get(this);
    return function*() {
      let spec = yield stripNotAuthorizedActions.call(this, it.prefix, it.spec.get());
      spec.host = this.host;
      const definition = this.query.definition;
      if (definition) {
        if (definition in spec.definitions) {
          this.body = spec.definitions[definition];
        }
      } else {
        this.body = spec;
      }
    };
  }

  routes() {
    this
      .get('/spec', this.userSpec())
      .params({
        in: 'query',
        name: 'definition',
        description: 'Fetch only the requested definition'
      })
      .onSuccess({
        description: 'A swagger specification or definition'
      });
    return routersData.get(this).router.routes();
  }

}

function normalizeResource(prefix, resource) {
  resource = resource.replace(/\:(\w*)/g, () => '*');
  return prefix ? `/${prefix}${resource}` : `${resource}`;
}

function* stripNotAuthorizedActions(prefix, spec) {

  let strip = function*() {
    spec = Object.assign({}, spec);

    let paths = {};
    let pathsKeys = Object.keys(spec.paths);
    for (let i = 0; i < pathsKeys.length; i++) {
      let path = pathsKeys[i];
      let methods = {};
      let methodsKeys = Object.keys(spec.paths[path]);
      for (let j = 0; j < methodsKeys.length; j++) {
        let method = methodsKeys[j];
        try {
          yield this.state.authorize.call(this, method, normalizeResource(prefix, path), spec.paths[path][method]);
          methods[method] = spec.paths[path][method];
        } catch (error) {
          if (error.status !== 403) {
            throw error;
          }
        }
      }
      if (Object.keys(methods).length) {
        paths[path] = methods;
      }
    }

    let definitions = {};
    var refs = jsonRefs.findRefs(paths);
    Object.keys(refs).forEach(key => {
      let values = jsonRefs.pathFromPtr(refs[key].uri);
      let definition = values[1];
      definitions[definition] = spec.definitions[definition];
    });

    spec.paths = paths;
    spec.definitions = definitions;
    return spec;
  }.bind(this);

  return !this.state.authorize ? spec : yield strip();
}

methods.forEach(function(method) {
  Router.prototype[method] = function(path, middleware) {
    let it = routersData.get(this);
    let thisMethod = it.spec.addMethod(path, method);
    const normalizedResource = normalizeResource(it.prefix, path);
    const thisMethodSpec = thisMethod.spec;
    it.router[method](path, function*(next) {
      try {
        if (this.state.authorize) {
          yield this.state.authorize.call(this, method, normalizedResource, thisMethodSpec);
        }
        if (thisMethod.bodyRequested) {
          this.state.body = yield parseBody(this);
        }
        yield *middleware.call(this, next);
        if (this.body !== void 0) {
          let successStatus = thisMethod.successStatuses();
          if (successStatus.indexOf(this.status) === -1) {
            this.status = successStatus[0];
          }
        }
      } catch (e) {
        this.status = e.status || 500;
        let errors = thisMethod.errors();
        errors.forEach(error => {
          error.catch.forEach(fn => {
            if (typeof fn === 'string' ? fn === e.name : fn(e)) {
              this.status = error.status;
              this.body = error.show(e);
            }
          });
        });
        this.app.emit('error', e, this);
      }
    });
    return thisMethod;
  };
});

function toArray(any) {
  return any ? Array.isArray(any) ? any : [any] : [];
}

function toSpecParam(param) {
  let specParam = {};
  specParam.in = param.in || 'query';
  specParam.name = param.name;
  specParam.description = param.description || '';
  specParam.required = specParam.in === 'path' ? true : param.required === true || false;
  if (param.schema) {
    specParam.schema = typeof param.schema === 'string' ? {
      $ref: `#/definitions/${param.schema}`
    } : param.schema;
    if (param.type === 'array') {
      specParam.items = specParam.schema;
      delete specParam.schema;
    }
  } else if (['date', 'datetime', 'time'].indexOf(param.type) !== -1) {
    specParam.type = 'string';
  } else {
    specParam.type = param.type || 'string';
  }
  if (param.format) {
    specParam.format = param.format;
  }
  return specParam;
}

function toSpecResponse(spec, response, status) {
  let specResponse = {};
  let statusObject = specResponse[response.status || status] = {};
  Object.defineProperty(statusObject, 'name', {
    value: response.name,
    writable: true
  });
  if (typeof response.schema === 'string') {
    statusObject.schema = {
      $ref: `#/definitions/${response.schema}`
    };
    statusObject.name = response.name || response.schema;
  } else if ('schema' in response) {
    if (response.name) {
      spec.addDefinition(response.name, response.schema);
      statusObject.schema = {
        $ref: `#/definitions/${response.name}`
      };
    } else {
      statusObject.schema = response.schema;
    }
  }
  if (typeof response.items === 'string') {
    statusObject.schema = {
      type: 'array',
      items: {
        $ref: `#/definitions/${response.items}`
      }
    };
    statusObject.name = response.name || response.schema;
    delete response.items;
  }
  statusObject.description = response.description || (status >= 400 ? 'Error' : 'Success');
  if (status >= 400) {
    Object.defineProperty(statusObject, 'show', {
      value: response.show || (error => ({ message: error.message }))
    });
    Object.defineProperty(statusObject, 'catch', {
      value: response.catch || [statusObject.name]
    });
  }
  return specResponse;
}

function toJsonSchema(schema, level) {
  level = level || 0;
  let definition = {};
  Object.keys(schema).forEach(function(key) {
    var value = schema[key];
    if (level === 0) {
      if (['properties', 'title', 'description', 'type']
          .indexOf(key) === -1) {
        key = 'x-' + key;
      }
    } else {
      if (['properties', 'title', 'description', 'type', 'schema', 'items']
          .indexOf(key) === -1) {
        key = 'x-' + key;
      }
    }
    switch (typeof value) {
      //case 'function':
      //  break;
      //case 'array':
      //  definition[key] = value.slice(0);
      //  break;
      case 'object':
        definition[key] = Object.assign({}, value);
        break;
      default:
        definition[key] = value;
    }
  });
  var required = [];
  Object.keys(definition.properties).forEach(function(key) {
    let source = definition.properties[key];
    if (source.required === true) {
      required.push(key);
    }
    let property = {};
    Object.keys(source).forEach(function(key) {
      if (key === 'required') {
        return;
      }
      var value = source[key];
      if (['title', 'description', 'type', 'schema', 'properties',
          '$ref', 'maxLength', 'format', 'enum', 'items']
          .indexOf(key) === -1) {
        key = 'x-' + key;
      }
      property[key] = value;
    });
    if (property.enum && property.maxLength) {
      delete property.maxLength;
    }
    if (['date', 'datetime', 'time'].indexOf(property.type) !== -1) {
      property.format = property.type;
      property.type = 'string';
    }
    if (property.type === 'object') {
      definition.properties[key] = toJsonSchema(property, level + 1);
    } else {
      if (property.type === 'array' && typeof property.items === 'object') {
        if (property.items.type === 'object') {
          property.items = toJsonSchema(property.items, level + 1);
        } else {
          property.items = {};
          Object.keys(source.items).forEach(function(key) {
            var value = source.items[key];
            if (['type']
                .indexOf(key) === -1) {
              key = 'x-' + key;
            }
            property.items[key] = value;
          });
        }
      } else if (property.schema) {
        let schema = {};
        if (property.schema.$ref) {
          schema['x-$ref'] = property.schema.$ref;
        }
        if (property.schema.key) {
          schema['x-key'] = property.schema.key;
        }
        property['x-schema'] = schema;
        delete property.schema;
      } else if (property.$ref) {
        property['x-$ref'] = property.$ref;
        delete property.$ref;
      }
      definition.properties[key] = property;
    }
  });
  if (required.length) {
    definition.required = required;
  }
  return definition;

}

module.exports = Router;
<|endoftext|>


<commit_before>function h(type, props) {
  var node
  var stack = []
  var children = []

  for (var i = arguments.length; i-- > 2; ) {
    stack.push(arguments[i])
  }

  while (stack.length) {
    if (Array.isArray((node = stack.pop()))) {
      for (i = node.length; i--; ) {
        stack.push(node[i])
      }
    } else if (node != null && node !== true && node !== false) {
      children.push(typeof node === "number" ? (node = node + "") : node)
    }
  }

  return typeof type === "string"
    ? {
        type: type,
        props: props || {},
        children: children
      }
    : type(props || {}, children)
}

function vnode(element, map) {
  return (
    element &&
    h(
      element.tagName.toLowerCase(),
      {},
      map.call(element.childNodes, function(element) {
        return element.nodeType === 3 ? element.nodeValue : vnode(element, map)
      })
    )
  )
}

function app(props, container) {
  var root = (container = container || document.body).children[0]
  var node = vnode(root, [].map)
  var appState = props.state || {}
  var appActions = {}
  var lifecycle = []
  var lock

  function set(to, from) {
    for (var i in from) {
      to[i] = from[i]
    }
    return to
  }

  function merge(to, from) {
    return set(set({}, to), from)
  }

  function setDeep(path, value, from) {
    var to = {}
    return path.length === 0
      ? value
      : ((to[path[0]] =
          1 < path.length
            ? setDeep(path.slice(1), value, from[path[0]])
            : value),
        merge(from, to))
  }

  function get(path, from) {
    for (var i = 0; i < path.length; i++) {
      from = from[path[i]]
    }
    return from
  }

  function setElementProp(element, name, value, oldValue) {
    if (name === "key") {
    } else if (name === "style") {
      for (var name in merge(oldValue, (value = value || {}))) {
        element.style[name] = value[name] || ""
      }
    } else {
      try {
        element[name] = null == value ? "" : value
      } catch (_) {}

      if (typeof value !== "function") {
        if (null == value || false === value) {
          element.removeAttribute(name)
        } else {
          element.setAttribute(name, value)
        }
      }
    }
  }

  function createElement(node, isSVG) {
    if (typeof node === "string") {
      var element = document.createTextNode(node)
    } else {
      var element = (isSVG = isSVG || node.type === "svg")
        ? document.createElementNS("http://www.w3.org/2000/svg", node.type)
        : document.createElement(node.type)

      if (node.props.oncreate) {
        lifecycle.push(function() {
          node.props.oncreate(element)
        })
      }

      for (var i = 0; i < node.children.length; i++) {
        element.appendChild(createElement(node.children[i], isSVG))
      }

      for (var i in node.props) {
        setElementProp(element, i, node.props[i])
      }
    }
    return element
  }

  function updateElement(element, oldProps, props) {
    for (var i in merge(oldProps, props)) {
      var value = props[i]
      var oldValue = i === "value" || i === "checked" ? element[i] : oldProps[i]

      if (value !== oldValue) {
        setElementProp(element, i, value, oldValue)
      }
    }

    if (props.onupdate) {
      lifecycle.push(function() {
        props.onupdate(element, oldProps)
      })
    }
  }

  function removeElement(parent, element, props) {
    function done() {
      parent.removeChild(element)
    }

    if (props && props.onremove) {
      props.onremove(element, done)
    } else {
      done()
    }
  }

  function getKey(node) {
    if (node && node.props) {
      return node.props.key
    }
  }

  function patch(parent, element, oldNode, node, isSVG, nextSibling) {
    if (oldNode === node) {
    } else if (oldNode == null) {
      element = parent.insertBefore(createElement(node, isSVG), element)
    } else if (node.type != null && node.type === oldNode.type) {
      updateElement(element, oldNode.props, node.props)

      isSVG = isSVG || node.type === "svg"

      var len = node.children.length
      var oldLen = oldNode.children.length
      var oldKeyed = {}
      var oldElements = []
      var keyed = {}

      for (var i = 0; i < oldLen; i++) {
        var oldElement = (oldElements[i] = element.childNodes[i])
        var oldChild = oldNode.children[i]
        var oldKey = getKey(oldChild)

        if (null != oldKey) {
          oldKeyed[oldKey] = [oldElement, oldChild]
        }
      }

      var i = 0
      var j = 0

      while (j < len) {
        var oldElement = oldElements[i]
        var oldChild = oldNode.children[i]
        var newChild = node.children[j]

        var oldKey = getKey(oldChild)
        if (keyed[oldKey]) {
          i++
          continue
        }

        var newKey = getKey(newChild)
        var keyedNode = oldKeyed[newKey] || []

        if (null == newKey) {
          if (null == oldKey) {
            patch(element, oldElement, oldChild, newChild, isSVG)
            j++
          }
          i++
        } else {
          if (oldKey === newKey) {
            patch(element, keyedNode[0], keyedNode[1], newChild, isSVG)
            i++
          } else if (keyedNode[0]) {
            element.insertBefore(keyedNode[0], oldElement)
            patch(element, keyedNode[0], keyedNode[1], newChild, isSVG)
          } else {
            patch(element, oldElement, null, newChild, isSVG)
          }

          j++
          keyed[newKey] = newChild
        }
      }

      while (i < oldLen) {
        var oldChild = oldNode.children[i]
        var oldKey = getKey(oldChild)
        if (null == oldKey) {
          removeElement(element, oldElements[i], oldChild.props)
        }
        i++
      }

      for (var i in oldKeyed) {
        var keyedNode = oldKeyed[i]
        var reusableNode = keyedNode[1]
        if (!keyed[reusableNode.props.key]) {
          removeElement(element, keyedNode[0], reusableNode.props)
        }
      }
    } else if (element && node !== element.nodeValue) {
      if (typeof node === "string" && typeof oldNode === "string") {
        element.nodeValue = node
      } else {
        element = parent.insertBefore(
          createElement(node, isSVG),
          (nextSibling = element)
        )
        removeElement(parent, nextSibling, oldNode.props)
      }
    }

    return element
  }

  function render(next) {
    lock = !lock
    if ((next = props.view(appState, appActions)) && !lock) {
      root = patch(container, root, node, (node = next))
    }
    while ((next = lifecycle.pop())) next()
  }

  function repaint() {
    if (props.view && !lock) {
      setTimeout(render, (lock = !lock))
    }
  }

  function init(state, actions, from, path) {
    for (var key in from) {
      typeof from[key] === "function"
        ? (function(key) {
            actions[key] = function(data) {
              var result = from[key]((state = get(path, appState)), actions)

              if (typeof result === "function") {
                result = result(data)
              }

              if (result && result !== state && !result.then) {
                repaint(
                  (appState = setDeep(path, merge(state, result), appState))
                )
              }

              return result
            }
          })(key)
        : init(
            state[key] || (state[key] = {}),
            (actions[key] = {}),
            from[key],
            path.concat(key)
          )
    }
  }

  repaint(init(appState, appActions, props.actions, []))

  return appActions
}

export { h, app }
<commit_msg>Woof woof.<commit_after>export { h, app }

function app(props, container) {
  var root = (container = container || document.body).children[0]
  var node = vnode(root, [].map)
  var appState = props.state || {}
  var appActions = {}
  var lifecycle = []
  var lock

  function set(to, from) {
    for (var i in from) {
      to[i] = from[i]
    }
    return to
  }

  function merge(to, from) {
    return set(set({}, to), from)
  }

  function setDeep(path, value, from) {
    var to = {}
    return path.length === 0
      ? value
      : ((to[path[0]] =
          1 < path.length
            ? setDeep(path.slice(1), value, from[path[0]])
            : value),
        merge(from, to))
  }

  function get(path, from) {
    for (var i = 0; i < path.length; i++) {
      from = from[path[i]]
    }
    return from
  }

  function setElementProp(element, name, value, oldValue) {
    if (name === "key") {
    } else if (name === "style") {
      for (var name in merge(oldValue, (value = value || {}))) {
        element.style[name] = value[name] || ""
      }
    } else {
      try {
        element[name] = null == value ? "" : value
      } catch (_) {}

      if (typeof value !== "function") {
        if (null == value || false === value) {
          element.removeAttribute(name)
        } else {
          element.setAttribute(name, value)
        }
      }
    }
  }

  function createElement(node, isSVG) {
    if (typeof node === "string") {
      var element = document.createTextNode(node)
    } else {
      var element = (isSVG = isSVG || node.type === "svg")
        ? document.createElementNS("http://www.w3.org/2000/svg", node.type)
        : document.createElement(node.type)

      if (node.props.oncreate) {
        lifecycle.push(function() {
          node.props.oncreate(element)
        })
      }

      for (var i = 0; i < node.children.length; i++) {
        element.appendChild(createElement(node.children[i], isSVG))
      }

      for (var i in node.props) {
        setElementProp(element, i, node.props[i])
      }
    }
    return element
  }

  function updateElement(element, oldProps, props) {
    for (var i in merge(oldProps, props)) {
      var value = props[i]
      var oldValue = i === "value" || i === "checked" ? element[i] : oldProps[i]

      if (value !== oldValue) {
        setElementProp(element, i, value, oldValue)
      }
    }

    if (props.onupdate) {
      lifecycle.push(function() {
        props.onupdate(element, oldProps)
      })
    }
  }

  function removeElement(parent, element, props) {
    function done() {
      parent.removeChild(element)
    }

    if (props && props.onremove) {
      props.onremove(element, done)
    } else {
      done()
    }
  }

  function getKey(node) {
    if (node && node.props) {
      return node.props.key
    }
  }

  function patch(parent, element, oldNode, node, isSVG, nextSibling) {
    if (oldNode === node) {
    } else if (oldNode == null) {
      element = parent.insertBefore(createElement(node, isSVG), element)
    } else if (node.type != null && node.type === oldNode.type) {
      updateElement(element, oldNode.props, node.props)

      isSVG = isSVG || node.type === "svg"

      var len = node.children.length
      var oldLen = oldNode.children.length
      var oldKeyed = {}
      var oldElements = []
      var keyed = {}

      for (var i = 0; i < oldLen; i++) {
        var oldElement = (oldElements[i] = element.childNodes[i])
        var oldChild = oldNode.children[i]
        var oldKey = getKey(oldChild)

        if (null != oldKey) {
          oldKeyed[oldKey] = [oldElement, oldChild]
        }
      }

      var i = 0
      var j = 0

      while (j < len) {
        var oldElement = oldElements[i]
        var oldChild = oldNode.children[i]
        var newChild = node.children[j]

        var oldKey = getKey(oldChild)
        if (keyed[oldKey]) {
          i++
          continue
        }

        var newKey = getKey(newChild)
        var keyedNode = oldKeyed[newKey] || []

        if (null == newKey) {
          if (null == oldKey) {
            patch(element, oldElement, oldChild, newChild, isSVG)
            j++
          }
          i++
        } else {
          if (oldKey === newKey) {
            patch(element, keyedNode[0], keyedNode[1], newChild, isSVG)
            i++
          } else if (keyedNode[0]) {
            element.insertBefore(keyedNode[0], oldElement)
            patch(element, keyedNode[0], keyedNode[1], newChild, isSVG)
          } else {
            patch(element, oldElement, null, newChild, isSVG)
          }

          j++
          keyed[newKey] = newChild
        }
      }

      while (i < oldLen) {
        var oldChild = oldNode.children[i]
        var oldKey = getKey(oldChild)
        if (null == oldKey) {
          removeElement(element, oldElements[i], oldChild.props)
        }
        i++
      }

      for (var i in oldKeyed) {
        var keyedNode = oldKeyed[i]
        var reusableNode = keyedNode[1]
        if (!keyed[reusableNode.props.key]) {
          removeElement(element, keyedNode[0], reusableNode.props)
        }
      }
    } else if (element && node !== element.nodeValue) {
      if (typeof node === "string" && typeof oldNode === "string") {
        element.nodeValue = node
      } else {
        element = parent.insertBefore(
          createElement(node, isSVG),
          (nextSibling = element)
        )
        removeElement(parent, nextSibling, oldNode.props)
      }
    }

    return element
  }

  function render(next) {
    lock = !lock
    if ((next = props.view(appState, appActions)) && !lock) {
      root = patch(container, root, node, (node = next))
    }
    while ((next = lifecycle.pop())) next()
  }

  function repaint() {
    if (props.view && !lock) {
      setTimeout(render, (lock = !lock))
    }
  }

  function init(state, actions, from, path) {
    for (var key in from) {
      typeof from[key] === "function"
        ? (function(key) {
            actions[key] = function(data) {
              var result = from[key]((state = get(path, appState)), actions)

              if (typeof result === "function") {
                result = result(data)
              }

              if (result && result !== state && !result.then) {
                repaint(
                  (appState = setDeep(path, merge(state, result), appState))
                )
              }

              return result
            }
          })(key)
        : init(
            state[key] || (state[key] = {}),
            (actions[key] = {}),
            from[key],
            path.concat(key)
          )
    }
  }

  repaint(init(appState, appActions, props.actions, []))

  return appActions
}

function h(type, props) {
  var node
  var stack = []
  var children = []

  for (var i = arguments.length; i-- > 2; ) {
    stack.push(arguments[i])
  }

  while (stack.length) {
    if (Array.isArray((node = stack.pop()))) {
      for (i = node.length; i--; ) {
        stack.push(node[i])
      }
    } else if (node != null && node !== true && node !== false) {
      children.push(typeof node === "number" ? (node = node + "") : node)
    }
  }

  return typeof type === "string"
    ? {
        type: type,
        props: props || {},
        children: children
      }
    : type(props || {}, children)
}

function vnode(element, map) {
  return (
    element &&
    h(
      element.tagName.toLowerCase(),
      {},
      map.call(element.childNodes, function(element) {
        return element.nodeType === 3 ? element.nodeValue : vnode(element, map)
      })
    )
  )
}
<|endoftext|>


<commit_before>import router from "kinesis-router";
import pipeline from "./pipeline/";

export var handler = router()
    .on("element inserted in collection pod-reading", pipeline);
<commit_msg>Changed type of event to monitor (changed collection name)<commit_after>import router from "kinesis-router";
import pipeline from "./pipeline/";

export var handler = router()
    .on("element inserted in collection pod-readings", pipeline);
<|endoftext|>


<commit_before>
import _ from 'underscore'

/**
 * Base Query Builder Class
 */
class BaseQuery {

  /**
   * Query Builder constructor
   *
   * @param {Object} qb knex query builder
   * @constructor
   */
  constructor(qb) {
    this.builder = qb
    this.columns = []
    this.table = null
    this.alias = null
  }

  /**
   * Get the base query builder
   *
   * @return knex query builder
   */
  toBase() {
    return this.builder
  }

  /**
   * Get the selected columns prefixed by the table name
   *
   * @return array
   */
  getQualifiedColumns() {
    return this.columns.map(col => {
      if ( _.isString(col) && col.indexOf('.') === -1 ) {
        return this.getQualifiedColumnName(col)
      }

      return col
    })
  }

  /**
   * Get the column name prefixed by the table name
   *
   * @param {String} column
   * @return string
   */
  getQualifiedColumnName(column) {
    return (this.alias || this.table) + '.' + column
  }

  /**
   * Set the table name for this query
   *
   * @param {String} table
   * @param {String} alias
   * @return this query
   */
  from(table, alias) {
    this.table = table

    if ( alias ) {
      table += ' as ' + alias
      this.alias = alias
    }

    this.builder.from(table)
    return this
  }

  /**
   * Set the columns of the query
   *
   * @param {String|Array} columns
   * @return this query
   */
  select(columns) {
    this.columns.push(..._.flatten(arguments))
    return this
  }

  /**
   * Fetch many records from th database
   *
   * @param {String|Array} columns
   * @return promise
   */
  fetch(columns) {
    this.select(...arguments)
    return this.builder.select(this.getQualifiedColumns())
  }

  /**
   * Fetch the first record from the database
   *
   * @param {String|Array} columns
   * @return promise
   */
  first(columns) {
    this.select(...arguments)
    return this.builder.first(this.getQualifiedColumns())
  }

  /**
   * Delete a record from the database
   *
   * @return promise
   */
  destroy() {
    return this.builder.del()
  }

  /**
   * Get the `count` result of the query
   *
   * @param {String} column
   * @return promise
   */
  count(column = '*') {
    return this.aggregate('count', column)
  }

  /**
   * Get the `sum` of the values of a given column
   *
   * @param {String} column
   * @return promise
   */
  sum(column) {
    return this.aggregate('sum', column)
  }

  /**
   * Get the minimum value of a given column
   *
   * @param {String} column
   * @return promise
   */
  min(column) {
    return this.aggregate('min', column)
  }

  /**
   * Get the maximum value of a given column
   *
   * @param {String} column
   * @return promise
   */
  max(column) {
    return this.aggregate('max', column)
  }

  /**
   * Get the average of the values of a given column
   *
   * @param {String} column
   * @return promise
   */
  avg(column) {
    return this.aggregate('avg', column)
  }

  /**
   * Execute an aggregate function on the database
   *
   * @param {String} method
   * @param {String} column
   * @return promise
   */
  aggregate(method, column) {
    column += ' as aggregate'
    return this.builder[method](column).then(res => _.first(res)['aggregate'])
  }

  /**
   * Get a single column's value from the first result of a query
   *
   * @param {String} column
   * @return promise
   */
  value(column) {
    return this.builder.first(column).then(res => res[column])
  }

  /**
   * Simple pagination of the given query
   *
   * @param {Integer} page
   * @param {Integer} pageSize
   * @param {String|Array} columns
   * @return promise
   */
  paginate(page = 1, pageSize = 15, columns = '*') {
    return this.offset((page - 1) * pageSize).limit(pageSize).fetch(columns)
  }

}

// proxies
[
  'insert', 'update',
  'where', 'orWhere', 'whereRaw', 'whereNot',
  'whereIn', 'orWhereIn', 'whereNotIn', 'orWhereNotIn',
  'whereNull', 'orWhereNull', 'whereNotNull', 'orWhereNotNull',
  'whereExists', 'orWhereExists', 'whereNotExists', 'orWhereNotExists',
  'whereBetween', 'orWhereBetween', 'whereNotBetween', 'orWhereNotBetween',
  'offset', 'limit', 'groupBy', 'groupByRaw', 'having', 'orderBy', 'orderByRaw',
  'join', 'innerJoin', 'leftJoin', 'rightJoin', 'outerJoin', 'crossJoin', 'joinRaw',
  'select', 'distinct', 'from', 'union', 'unionAll', 'pluck', 'increment', 'decrement',
]
.forEach(name => {
  if ( _.has(BaseQuery.prototype, name) ) return

  BaseQuery.prototype[name] = function () {
    this.builder[name](...arguments)
    return this
  }
})

// exports
export default BaseQuery
<commit_msg>rename `getQualifiedColumnName()`<commit_after>
import _ from 'underscore'

/**
 * Base Query Builder Class
 */
class BaseQuery {

  /**
   * Query Builder constructor
   *
   * @param {Object} qb knex query builder
   * @constructor
   */
  constructor(qb) {
    this.builder = qb
    this.columns = []
    this.table = null
    this.alias = null
  }

  /**
   * Get the base query builder
   *
   * @return knex query builder
   */
  toBase() {
    return this.builder
  }

  /**
   * Get the selected columns prefixed by the table name
   *
   * @return array
   */
  getQualifiedColumns() {
    return this.columns.map(name => {
      if ( _.isString(name) && name.indexOf('.') === -1 ) {
        return this.getQualifiedColumn(name)
      }

      return name
    })
  }

  /**
   * Get the column name prefixed by the table name
   *
   * @param {String} name
   * @return string
   */
  getQualifiedColumn(name) {
    return (this.alias || this.table) + '.' + name
  }

  /**
   * Set the table name for this query
   *
   * @param {String} table
   * @param {String} alias
   * @return this query
   */
  from(table, alias) {
    this.table = table

    if ( alias ) {
      table += ' as ' + alias
      this.alias = alias
    }

    this.builder.from(table)
    return this
  }

  /**
   * Set the columns of the query
   *
   * @param {String|Array} columns
   * @return this query
   */
  select(columns) {
    this.columns.push(..._.flatten(arguments))
    return this
  }

  /**
   * Fetch many records from th database
   *
   * @param {String|Array} columns
   * @return promise
   */
  fetch(columns) {
    this.select(...arguments)
    return this.builder.select(this.getQualifiedColumns())
  }

  /**
   * Fetch the first record from the database
   *
   * @param {String|Array} columns
   * @return promise
   */
  first(columns) {
    this.select(...arguments)
    return this.builder.first(this.getQualifiedColumns())
  }

  /**
   * Delete a record from the database
   *
   * @return promise
   */
  destroy() {
    return this.builder.del()
  }

  /**
   * Get the `count` result of the query
   *
   * @param {String} column
   * @return promise
   */
  count(column = '*') {
    return this.aggregate('count', column)
  }

  /**
   * Get the `sum` of the values of a given column
   *
   * @param {String} column
   * @return promise
   */
  sum(column) {
    return this.aggregate('sum', column)
  }

  /**
   * Get the minimum value of a given column
   *
   * @param {String} column
   * @return promise
   */
  min(column) {
    return this.aggregate('min', column)
  }

  /**
   * Get the maximum value of a given column
   *
   * @param {String} column
   * @return promise
   */
  max(column) {
    return this.aggregate('max', column)
  }

  /**
   * Get the average of the values of a given column
   *
   * @param {String} column
   * @return promise
   */
  avg(column) {
    return this.aggregate('avg', column)
  }

  /**
   * Execute an aggregate function on the database
   *
   * @param {String} method
   * @param {String} column
   * @return promise
   */
  aggregate(method, column) {
    column += ' as aggregate'
    return this.builder[method](column).then(res => _.first(res)['aggregate'])
  }

  /**
   * Get a single column's value from the first result of a query
   *
   * @param {String} column
   * @return promise
   */
  value(column) {
    return this.builder.first(column).then(res => res[column])
  }

  /**
   * Simple pagination of the given query
   *
   * @param {Integer} page
   * @param {Integer} pageSize
   * @param {String|Array} columns
   * @return promise
   */
  paginate(page = 1, pageSize = 15, columns = '*') {
    return this.offset((page - 1) * pageSize).limit(pageSize).fetch(columns)
  }

}

// proxies
[
  'insert', 'update',
  'where', 'orWhere', 'whereRaw', 'whereNot',
  'whereIn', 'orWhereIn', 'whereNotIn', 'orWhereNotIn',
  'whereNull', 'orWhereNull', 'whereNotNull', 'orWhereNotNull',
  'whereExists', 'orWhereExists', 'whereNotExists', 'orWhereNotExists',
  'whereBetween', 'orWhereBetween', 'whereNotBetween', 'orWhereNotBetween',
  'offset', 'limit', 'groupBy', 'groupByRaw', 'having', 'orderBy', 'orderByRaw',
  'join', 'innerJoin', 'leftJoin', 'rightJoin', 'outerJoin', 'crossJoin', 'joinRaw',
  'select', 'distinct', 'from', 'union', 'unionAll', 'pluck', 'increment', 'decrement',
]
.forEach(name => {
  if ( _.has(BaseQuery.prototype, name) ) return

  BaseQuery.prototype[name] = function () {
    this.builder[name](...arguments)
    return this
  }
})

// exports
export default BaseQuery
<|endoftext|>


<commit_before>const http = require('http')
const path = require('path')
const fs = require('fs')
const net = require('net')

const express = require('express')
const ejs = require('ejs')
const app = express()
const server = http.createServer(app)
const io = require('socket.io')(server)
const spawn = require('child_process').spawn
const NODE_PORT = 3333

const args = [
  'autovideosrc',
  'horizontal-speed=1',
  'is-live=true',
  '!',
  'videoconvert',
  '!',
  'vp8enc',
  'cpu-used=5',
  'deadline=1',
  'keyframe-max-dist=10',
  '!',
  'queue',
  'leaky=1',
  '!',
  'm.',
  'autoaudiosrc',
  '!',
  'audioconvert',
  '!',
  'vorbisenc',
  '!',
  'queue',
  'leaky=1',
  '!',
  'm.',
  'webmmux',
  'name=m',
  'streamable=true',
  '!',
  'queue',
  'leaky=1',
  '!',
  'tcpserversink',
  'host=127.0.0.1',
  'port=9001',
  'sync-method=2'
]
const gstreamer = spawn('gst-launch-1.0', args, { stdio: 'inherit' })

gstreamer.on('exit', code => {
  if (code !== null) {
    console.log(`GStreamer error, exit code ${code}`)
  }
  process.exit()
})

app.set('view engine', 'ejs')
app.get('/', (req, res) => res.render('index'))

let connections = 0

io.on('connection', socket => {
  console.log('connection made to socket server')

  connections++
  socket.on('disconnect', () => {
    connections--
  })
})

const gs_socket = net.connect(9001, () => {
  gs_socket.on('close', error => {
    console.log(`gs socket closed =>>>`, error)
    // res.end()
  })
  gs_socket.on('data', data => {
    if (connections > 0) {
      io.sockets.emit('liveStream', data)
    }
  })
})

gs_socket.on('error', error => {
  console.log(`gs-error =>>>`, error)
})

// app.get('/webm', (req, res) => {
//   const date = new Date()

//   res.writeHead(200, {
//     Date: date.toUTCString(),
//     Connection: 'close',
//     'Cache-Control': 'private',
//     'Content-Type': 'video/webm',
//     Server: 'CustomStreamer/0.0.1'
//   })

// })

server.listen(NODE_PORT, () => {
  console.log(`Application running on port: ${NODE_PORT}`)
})
<commit_msg>remove audio<commit_after>const http = require('http')
const path = require('path')
const fs = require('fs')
const net = require('net')

const express = require('express')
const ejs = require('ejs')
const app = express()
const server = http.createServer(app)
const io = require('socket.io')(server)
const spawn = require('child_process').spawn
const NODE_PORT = 3333

const args = [
  'autovideosrc',
  'horizontal-speed=1',
  'is-live=true',
  '!',
  'videoconvert',
  '!',
  'vp8enc',
  'cpu-used=16',
  'deadline=1',
  'keyframe-max-dist=10',
  '!',
  'queue',
  'leaky=1',
  '!',
  'queue',
  'leaky=1',
  '!',
  'm.',
  'webmmux',
  'name=m',
  'streamable=true',
  '!',
  'queue',
  'leaky=1',
  '!',
  'tcpserversink',
  'host=127.0.0.1',
  'port=9001',
  'sync-method=2'
]
const gstreamer = spawn('gst-launch-1.0', args, { stdio: 'inherit' })

gstreamer.on('exit', code => {
  if (code !== null) {
    console.log(`GStreamer error, exit code ${code}`)
  }
  process.exit()
})

app.set('view engine', 'ejs')
app.get('/', (req, res) => res.render('index'))

let connections = 0

io.on('connection', socket => {
  console.log('connection made to socket server')

  connections++
  socket.on('disconnect', () => {
    connections--
  })
})

const gs_socket = net.connect(9001, () => {
  gs_socket.on('close', error => {
    console.log(`gs socket closed =>>>`, error)
    // res.end()
  })
  gs_socket.on('data', data => {
    if (connections > 0) {
      io.sockets.emit('liveStream', data)
    }
  })
})

gs_socket.on('error', error => {
  console.log(`gs-error =>>>`, error)
})

// app.get('/webm', (req, res) => {
//   const date = new Date()

//   res.writeHead(200, {
//     Date: date.toUTCString(),
//     Connection: 'close',
//     'Cache-Control': 'private',
//     'Content-Type': 'video/webm',
//     Server: 'CustomStreamer/0.0.1'
//   })

// })

server.listen(NODE_PORT, () => {
  console.log(`Application running on port: ${NODE_PORT}`)
})
<|endoftext|>


<commit_before>'use strict'

/**
 * Dependencies
 * @ignore
 */

/**
 * Module Dependencies
 * @ignore
 */
const InvalidOperationError = require('./InvalidOperationError')
const OperationNotSupportedError = require('./OperationNotSupportedError')
const types = require('./types')
const asn = require('./asn1')

/**
 * JWK
 *
 * @typedef {Object} JWK
 *
 * @description
 * A JWK Object
 */

/**
 * SerializedFormat
 *
 * @typedef {String} SerializableFormat
 *
 * @description
 * Available formats: 'jwk', 'pem', 'hex', 'blk'.
 */

/**
 * BufferFormat
 *
 * @typedef {String} BufferFormat
 *
 * @description
 * Available formats: 'raw', 'uint8_array'.
 */

/**
 * KeySelector
 *
 * @typedef {String} KeySelector
 *
 * @see SerializableFormat
 * @see BufferFormat
 *
 * @description
 * Available formats: 'public', 'private'.
 */

/**
 * PEMKeySelector
 *
 * @typedef {String} PEMKeySelector
 *
 * @see SerializableFormat
 * @see BufferFormat
 *
 * @description
 * Available formats: 'public_pkcs1', 'public_pkcs8', 'private_pkcs1', 'private_pkcs8'.
 *
 * Note these refer specifically to different ASN encodings for PEM encoded keys
 * and are not compatible with non-PEM output types.
 */

/**
 * Key
 * @ignore
 */
class Key {

  /**
   * constructor
   *
   * @class Key
   *
   * @internal For internal use only
   *
   * @description
   * A high level class for accepting and processing keys
   *
   * @throws {InvalidOperationError} If key is omitted
   *
   * @throws {InvalidOperationError} If required options are omitted
   *
   * @param  {Object} key
   * @param  {Object} options
   * @param  {String} options.format
   * @param  {String} options.kty - normalized key type name
   * @param  {String} [options.crv] - normalized curve name (EC & ED only)
   * @param  {String} [options.oid] - ASN oid algorithm descriptor
   * @param  {(KeySelector|PEMKeySelector)} options.selector
   */
  constructor (key, options) {
    if (!key) {
      throw new InvalidOperationError('key is required')
    }

    if (!options) {
      throw new InvalidOperationError('options are required')
    }

    let { kty, format, selector, crv, oid } = options

    if (!options.kty) {
      throw new InvalidOperationError('options.kty is required')
    }

    if (!options.format) {
      throw new InvalidOperationError('options.format is required')
    }

    if (!options.selector) {
      throw new InvalidOperationError('options.selector is required')
    }

    if (!options.crv && !options.oid) {
      throw new InvalidOperationError('options.crv or options.oid is required')
    }

    this.kty = kty
    this.format = format
    this.selector = selector
    this.crv = crv
    this.oid = oid
    this.key = this.parseKey(key)
  }

  /**
   * from
   *
   * @description
   * Import a key
   *
   * @example
Decode PEM and convert to JWK

   * const keyto = require('@eternaldeiwos/keyto')
   *
   * let pemPrivate = getPrivatePemStringSomehow()
   * let jwk = getPublicJwkSomehow()
   *
   * // String data can either be passed in directly:
   * let key = keyto.from(pemPrivate, 'pem').toJwk('public')
   *
   * // Or can be passed in as an object instead:
   * let key = keyto.from({ key: pemPrivate }, 'pem').toJwk('public')
   * assertEqual(jwk, key)
   *
   * @example
Decode HEX (Blockchain) private key and convert to PEM PKCS8 public key

   * const keyto = require('@eternaldeiwos/keyto')
   *
   * let blk = getPrivateBlockchainHexStringSomehow()
   * let pemPublic = getPublicPemSomehow()
   *
   * let key = keyto.from(blk, 'blk').toString('pem', 'public_pkcs8')
   * assertEqual(pemPublic, key)
   *
   * @throws {InvalidOperationError}
   * If key is omitted.
   *
   * @throws {InvalidOperationError}
   * If format is omitted.
   *
   * @param  {(JWK|String|Array|Buffer)} key
   * @param  {(SerializableFormat|BufferFormat)} format
   * @return {Key}
   */
  static from (key, format) {
    // Sanity checking
    if (!key) {
      throw new InvalidOperationError('key is required')
    }

    if (!format) {
      throw new InvalidOperationError('format is required')
    }

    // JWK
    if (format === 'jwk') {
      let jwk

      // Parse JSON
      if (typeof key === 'string') {
        try {
          jwk = JSON.parse(key)
        } catch (error) {
          throw new InvalidOperationError('key is not a valid JWK')
        }

      } else if (typeof key === 'object') {
        jwk = key
      }

      let { kty, crv } = jwk
      let oid

      // Required properties
      if (!kty) {
        throw new InvalidOperationError('kty is required for JWK')
      }

      if (kty === 'EC' && !crv) {
        throw new InvalidOperationError('crv is required for EC JWK')
      }

      if (kty === 'RSA') {
        oid = types._paramsRegistry[kty][0].oid
      }

      // Key type
      let selector = jwk.d ? 'private' : 'public'

      return new Key(jwk, { kty, crv, oid, format, selector })
    }

    // PEM
    if (format === 'pem') {
      if (typeof key !== 'string') {
        throw new InvalidOperationError('key is not a valid PEM string')
      }

      // Extract Base64 String
      let lines = key.split('\n')
      let header = lines.splice(0, 1)
      lines.splice(lines.length-1, 1)
      let base64pem = lines.join('')

      // Extract metadata from header
      let match = /^-----BEGIN ((RSA|EC) )?(PUBLIC|PRIVATE) KEY-----$/.exec(header)
      let oid, crv, kty = match ? match[2] : undefined
      let selector = match ? match[3] : undefined
      let pem = Buffer.from(base64pem, 'base64')

      if (!selector) {
        throw new InvalidOperationError('key is not a valid PEM string')
      }

      // PKCS8
      if (!kty) {
        let PrivateKeyInfo = asn.normalize('PrivateKeyInfo')
        let PublicKeyInfo = asn.normalize('PublicKeyInfo')

        let decoded
        if (selector === 'PRIVATE') {
          selector = 'private_pkcs8'
          decoded = PrivateKeyInfo.decode(pem, 'der')
        } else if (selector === 'PUBLIC') {
          selector = 'public_pkcs8'
          decoded = PublicKeyInfo.decode(pem, 'der')
        }

        let { algorithm: { algorithm } } = decoded
        oid = algorithm.join('.')
        kty = types.type(oid)

        if (!kty) {
          throw new OperationNotSupportedError()
        }

      // PKCS1
      } else {

        if (kty === 'RSA') {
          selector = selector === 'PRIVATE' ? 'private_pkcs1' : 'public_pkcs1'
          oid = types._paramsRegistry[kty][0].oid

        } else if (kty === 'EC') {
          let decoded
          if (selector === 'PRIVATE') {
            let KeyType = asn.normalize(`${kty}PrivateKey`)
            selector = 'private_pkcs1'
            decoded = KeyType.decode(pem, 'der')
          } else if (selector === 'PUBLIC') {
            let KeyType = asn.normalize(`${kty}PrivateKey`)
            selector = 'public_pkcs1'
            decoded = KeyType.decode(pem, 'der')
          }

          let { parameters: { value } } = decoded
          crv = types.normalize(kty, 'namedCurve', value.join('.')).params.crv
        }
      }

      return new Key(pem, { kty, oid, crv, format, selector })
    }

    // BLK
    if (format === 'blk') {
      return new Key(key, { kty: 'EC', crv: 'K-256', format, selector: 'private' })
    }

    throw new InvalidOperationError(`Invalid format ${format}`)
  }

  /**
   * alg
   * @ignore
   *
   * @internal For internal use only
   */
  get alg () {
    let { kty, crv, oid } = this

    if (!this.algorithm) {
      if (crv) {
        Object.defineProperty(this, 'algorithm', { value: types.normalize(kty, 'crv', crv) })
      } else if (oid) {
        Object.defineProperty(this, 'algorithm', { value: types.normalize(kty, 'oid', oid) })
      } else {
        throw new Error('Both crv and oid are undefined')
      }
    }

    return this.algorithm
  }

  /**
   * parseKey
   * @ignore
   *
   * @internal For internal use only
   */
  parseKey (key) {
    let { alg, format, selector } = this

    // PEM
    if (format === 'pem') {
      switch (selector) {
        case 'public_pkcs1':
          return alg.fromPublicPKCS1(key)

        case 'public_pkcs8':
          return alg.fromPublicPKCS8(key)

        case 'private_pkcs1':
          return alg.fromPrivatePKCS1(key)

        case 'private_pkcs8':
          return alg.fromPrivatePKCS8(key)

        default:
          throw new Error('Invalid selector value')
      }
    }

    // JWK
    if (format === 'jwk') {
      return alg.fromJwk(key, selector)
    }

    // BLK
    if (format === 'blk') {
      return alg.fromBlk(key)
    }
  }

  /**
   * toJwk
   *
   * @description
   * Convert a key to JWK.
   *
   * @param  {KeySelector} selector
   *
   * @return {JWK}
   */
  toJwk (selector) {
    let { key, alg, selector: type } = this

    switch (selector) {
      case 'public':
        return alg.toPublicJwk(key)

      case 'private':
        if (type.includes('public')) {
          throw new InvalidOperationError('Cannot export a private key from a public key')
        }
        return alg.toPrivateJwk(key)

      default:
        throw new Error('Invalid key selector')
    }

    throw new OperationNotSupportedError()
  }

  /**
   * toString
   *
   * @description
   * Serialize a key to the specified format
   *
   * @param  {SerializableFormat} [format=pem]
   * @param  {(KeySelector|PEMKeySelector)} [selector=public_pkcs8]
   * @return {String}
   */
  toString(format = 'pem', selector = 'public_pkcs8') {
    let { key, alg, selector: type } = this

    // PEM
    if (format === 'pem') {
      switch (selector) {
        case 'public_pkcs1':
          return alg.toPublicPKCS1(key)

        case 'public_pkcs8':
          return alg.toPublicPKCS8(key)

        case 'private_pkcs1':
          if (type.includes('public')) {
            throw new InvalidOperationError('Cannot export a private key from a public key')
          }
          return alg.toPrivatePKCS1(key)

        case 'private_pkcs8':
          if (type.includes('public')) {
            throw new InvalidOperationError('Cannot export a private key from a public key')
          }
          return alg.toPrivatePKCS8(key)

        default:
          throw new Error('Invalid key selector')
      }

    // JWK
    } else if (format === 'jwk') {
      switch (selector) {
        case 'public':
          return JSON.stringify(alg.toPublicJwk(key))

        case 'private':
          if (type.includes('public')) {
            throw new InvalidOperationError('Cannot export a private key from a public key')
          }
          return JSON.stringify(alg.toPrivateJwk(key))

        default:
          throw new Error('Invalid key selector')
      }

    // BLK
    } else if (format === 'blk') {
      switch (selector) {
        case 'private':
          if (type.includes('public')) {
            throw new InvalidOperationError('Cannot export a private key from a public key')
          }
          return alg.toBlk(key)

        case 'public':
          throw new OperationNotSupportedError()

        default:
          throw new Error('Invalid key selector')

      }
    }

    throw new OperationNotSupportedError()
  }

}

/**
 * Export
 * @ignore
 */
module.exports = Key
<commit_msg>refactor(keyto): lookup oid and crv names<commit_after>'use strict'

/**
 * Dependencies
 * @ignore
 */

/**
 * Module Dependencies
 * @ignore
 */
const InvalidOperationError = require('./InvalidOperationError')
const OperationNotSupportedError = require('./OperationNotSupportedError')
const types = require('./types')
const asn = require('./asn1')

/**
 * JWK
 *
 * @typedef {Object} JWK
 *
 * @description
 * A JWK Object
 */

/**
 * SerializedFormat
 *
 * @typedef {String} SerializableFormat
 *
 * @description
 * Available formats: 'jwk', 'pem', 'hex', 'blk'.
 */

/**
 * BufferFormat
 *
 * @typedef {String} BufferFormat
 *
 * @description
 * Available formats: 'raw', 'uint8_array'.
 */

/**
 * KeySelector
 *
 * @typedef {String} KeySelector
 *
 * @see SerializableFormat
 * @see BufferFormat
 *
 * @description
 * Available formats: 'public', 'private'.
 */

/**
 * PEMKeySelector
 *
 * @typedef {String} PEMKeySelector
 *
 * @see SerializableFormat
 * @see BufferFormat
 *
 * @description
 * Available formats: 'public_pkcs1', 'public_pkcs8', 'private_pkcs1', 'private_pkcs8'.
 *
 * Note these refer specifically to different ASN encodings for PEM encoded keys
 * and are not compatible with non-PEM output types.
 */

/**
 * Key
 * @ignore
 */
class Key {

  /**
   * constructor
   *
   * @class Key
   *
   * @internal For internal use only
   *
   * @description
   * A high level class for accepting and processing keys
   *
   * @throws {InvalidOperationError} If key is omitted
   *
   * @throws {InvalidOperationError} If required options are omitted
   *
   * @param  {Object} key
   * @param  {Object} options
   * @param  {String} options.format
   * @param  {String} options.kty - normalized key type name
   * @param  {String} [options.crv] - normalized curve name (EC & ED only)
   * @param  {String} [options.oid] - ASN oid algorithm descriptor
   * @param  {(KeySelector|PEMKeySelector)} options.selector
   */
  constructor (key, options) {
    if (!key) {
      throw new InvalidOperationError('key is required')
    }

    if (!options) {
      throw new InvalidOperationError('options are required')
    }

    let { kty, format, selector, crv, oid } = options

    if (!options.kty) {
      throw new InvalidOperationError('options.kty is required')
    }

    if (!options.format) {
      throw new InvalidOperationError('options.format is required')
    }

    if (!options.selector) {
      throw new InvalidOperationError('options.selector is required')
    }

    if (!options.crv && !options.oid) {
      throw new InvalidOperationError('options.crv or options.oid is required')
    }

    this.kty = kty
    this.format = format
    this.selector = selector
    this.crv = crv
    this.oid = oid
    this.key = this.parseKey(key)
  }

  /**
   * from
   *
   * @description
   * Import a key
   *
   * @example
Decode PEM and convert to JWK

   * const keyto = require('@eternaldeiwos/keyto')
   *
   * let pemPrivate = getPrivatePemStringSomehow()
   * let jwk = getPublicJwkSomehow()
   *
   * // String data can either be passed in directly:
   * let key = keyto.from(pemPrivate, 'pem').toJwk('public')
   *
   * // Or can be passed in as an object instead:
   * let key = keyto.from({ key: pemPrivate }, 'pem').toJwk('public')
   * assertEqual(jwk, key)
   *
   * @example
Decode HEX (Blockchain) private key and convert to PEM PKCS8 public key

   * const keyto = require('@eternaldeiwos/keyto')
   *
   * let blk = getPrivateBlockchainHexStringSomehow()
   * let pemPublic = getPublicPemSomehow()
   *
   * let key = keyto.from(blk, 'blk').toString('pem', 'public_pkcs8')
   * assertEqual(pemPublic, key)
   *
   * @throws {InvalidOperationError}
   * If key is omitted.
   *
   * @throws {InvalidOperationError}
   * If format is omitted.
   *
   * @param  {(JWK|String|Array|Buffer)} key
   * @param  {(SerializableFormat|BufferFormat)} format
   * @return {Key}
   */
  static from (key, format) {
    // Sanity checking
    if (!key) {
      throw new InvalidOperationError('key is required')
    }

    if (!format) {
      throw new InvalidOperationError('format is required')
    }

    // JWK
    if (format === 'jwk') {
      let jwk

      // Parse JSON
      if (typeof key === 'string') {
        try {
          jwk = JSON.parse(key)
        } catch (error) {
          throw new InvalidOperationError('key is not a valid JWK')
        }

      } else if (typeof key === 'object') {
        jwk = key
      }

      let { kty, crv } = jwk
      let oid

      // Required properties
      if (!kty) {
        throw new InvalidOperationError('kty is required for JWK')
      }

      if (kty === 'EC' && !crv) {
        throw new InvalidOperationError('crv is required for EC JWK')
      }

      if (kty === 'RSA') {
        oid = types.find(param => param.kty === kty).oid
      }

      // Key type
      let selector = jwk.d ? 'private' : 'public'

      return new Key(jwk, { kty, crv, oid, format, selector })
    }

    // PEM
    if (format === 'pem') {
      if (typeof key !== 'string') {
        throw new InvalidOperationError('key is not a valid PEM string')
      }

      // Extract Base64 String
      let lines = key.split('\n')
      let header = lines.splice(0, 1)
      lines.splice(lines.length-1, 1)
      let base64pem = lines.join('')

      // Extract metadata from header
      let match = /^-----BEGIN ((RSA|EC) )?(PUBLIC|PRIVATE) KEY-----$/.exec(header)
      let oid, crv, kty = match ? match[2] : undefined
      let selector = match ? match[3] : undefined
      let pem = Buffer.from(base64pem, 'base64')

      if (!selector) {
        throw new InvalidOperationError('key is not a valid PEM string')
      }

      // PKCS8
      if (!kty) {
        let PrivateKeyInfo = asn.normalize('PrivateKeyInfo')
        let PublicKeyInfo = asn.normalize('PublicKeyInfo')

        let decoded
        if (selector === 'PRIVATE') {
          selector = 'private_pkcs8'
          decoded = PrivateKeyInfo.decode(pem, 'der')
        } else if (selector === 'PUBLIC') {
          selector = 'public_pkcs8'
          decoded = PublicKeyInfo.decode(pem, 'der')
        }

        let { algorithm: { algorithm, parameters } } = decoded
        algorithm = algorithm.join('.')
        parameters = parameters.toString('hex')
        kty = types.find(param => param.oid === algorithm).kty

        if (!kty) {
          throw new OperationNotSupportedError()
        }

        if (kty === 'RSA') {
          oid = algorithm
        } else if (kty === 'EC') {
          crv = types.find(param => param.algParameters === parameters).crv
        }

      // PKCS1
      } else {

        if (kty === 'RSA') {
          selector = selector === 'PRIVATE' ? 'private_pkcs1' : 'public_pkcs1'
          oid = types.find(param => param.kty === kty).oid

        } else if (kty === 'EC') {
          let decoded
          if (selector === 'PRIVATE') {
            let KeyType = asn.normalize(`${kty}PrivateKey`)
            selector = 'private_pkcs1'
            decoded = KeyType.decode(pem, 'der')
          } else if (selector === 'PUBLIC') {
            let KeyType = asn.normalize(`${kty}PrivateKey`)
            selector = 'public_pkcs1'
            decoded = KeyType.decode(pem, 'der')
          }

          let { parameters: { value } } = decoded
          crv = types.find(param => param.namedCurve === value.join('.')).crv
        }
      }

      return new Key(pem, { kty, oid, crv, format, selector })
    }

    // BLK
    if (format === 'blk') {
      return new Key(key, { kty: 'EC', crv: 'K-256', format, selector: 'private' })
    }

    throw new InvalidOperationError(`Invalid format ${format}`)
  }

  /**
   * alg
   * @ignore
   *
   * @internal For internal use only
   */
  get alg () {
    let { kty, crv, oid } = this

    if (!this.algorithm) {
      if (crv) {
        Object.defineProperty(this, 'algorithm', { value: types.normalize(kty, 'crv', crv) })
      } else if (oid) {
        Object.defineProperty(this, 'algorithm', { value: types.normalize(kty, 'oid', oid) })
      } else {
        throw new Error('Both crv and oid are undefined')
      }
    }

    return this.algorithm
  }

  /**
   * parseKey
   * @ignore
   *
   * @internal For internal use only
   */
  parseKey (key) {
    let { alg, format, selector } = this

    // PEM
    if (format === 'pem') {
      switch (selector) {
        case 'public_pkcs1':
          return alg.fromPublicPKCS1(key)

        case 'public_pkcs8':
          return alg.fromPublicPKCS8(key)

        case 'private_pkcs1':
          return alg.fromPrivatePKCS1(key)

        case 'private_pkcs8':
          return alg.fromPrivatePKCS8(key)

        default:
          throw new Error('Invalid selector value')
      }
    }

    // JWK
    if (format === 'jwk') {
      return alg.fromJwk(key, selector)
    }

    // BLK
    if (format === 'blk') {
      return alg.fromBlk(key)
    }
  }

  /**
   * toJwk
   *
   * @description
   * Convert a key to JWK.
   *
   * @param  {KeySelector} selector
   *
   * @return {JWK}
   */
  toJwk (selector) {
    let { key, alg, selector: type } = this

    switch (selector) {
      case 'public':
        return alg.toPublicJwk(key)

      case 'private':
        if (type.includes('public')) {
          throw new InvalidOperationError('Cannot export a private key from a public key')
        }
        return alg.toPrivateJwk(key)

      default:
        throw new Error('Invalid key selector')
    }

    throw new OperationNotSupportedError()
  }

  /**
   * toString
   *
   * @description
   * Serialize a key to the specified format
   *
   * @param  {SerializableFormat} [format=pem]
   * @param  {(KeySelector|PEMKeySelector)} [selector=public_pkcs8]
   * @return {String}
   */
  toString(format = 'pem', selector = 'public_pkcs8') {
    let { key, alg, selector: type } = this

    // PEM
    if (format === 'pem') {
      switch (selector) {
        case 'public_pkcs1':
          return alg.toPublicPKCS1(key)

        case 'public_pkcs8':
          return alg.toPublicPKCS8(key)

        case 'private_pkcs1':
          if (type.includes('public')) {
            throw new InvalidOperationError('Cannot export a private key from a public key')
          }
          return alg.toPrivatePKCS1(key)

        case 'private_pkcs8':
          if (type.includes('public')) {
            throw new InvalidOperationError('Cannot export a private key from a public key')
          }
          return alg.toPrivatePKCS8(key)

        default:
          throw new Error('Invalid key selector')
      }

    // JWK
    } else if (format === 'jwk') {
      switch (selector) {
        case 'public':
          return JSON.stringify(alg.toPublicJwk(key))

        case 'private':
          if (type.includes('public')) {
            throw new InvalidOperationError('Cannot export a private key from a public key')
          }
          return JSON.stringify(alg.toPrivateJwk(key))

        default:
          throw new Error('Invalid key selector')
      }

    // BLK
    } else if (format === 'blk') {
      switch (selector) {
        case 'private':
          if (type.includes('public')) {
            throw new InvalidOperationError('Cannot export a private key from a public key')
          }
          return alg.toBlk(key)

        case 'public':
          throw new OperationNotSupportedError()

        default:
          throw new Error('Invalid key selector')

      }
    }

    throw new OperationNotSupportedError()
  }

}

/**
 * Export
 * @ignore
 */
module.exports = Key
<|endoftext|>


<commit_before>import parser from 'posthtml-parser';
import render from 'posthtml-render';
import rules from './rules.js';
import attrs from './attrs.js';
import tags from './tags.js';
import deepmerge from 'deepmerge';

const optionsDefault = {
	rules: rules,
	attrs: attrs,
	tags: tags,
	sync: false
};

const clean = tree => parser(render(tree))
	.filter(node => {
		return typeof node === 'object' || (typeof node === 'string' && (node.trim().length !== 0 || /doctype/gi.test(node)));
	})
	.map(node => {
		if (Object.prototype.hasOwnProperty.call(node, 'content')) {
			node.content = clean(node.content);
		}

		return typeof node === 'string' ? node.trim() : node;
	});

const parseConditional = tree => {
	return tree.map(node => {
		if (typeof node === 'object' && Object.prototype.hasOwnProperty.call(node, 'content')) {
			node.content = parseConditional(node.content);
		}

		if (typeof node === 'string' && /<!(?:--)?\[[\s\S]*?]>/.test(node)) {
			const conditional = /^((?:<[^>]+>)?<!(?:--)?\[[\s\S]*?]>(?:<!)?(?:-->)?)([\s\S]*?)(<!(?:--<!)?\[[\s\S]*?](?:--)?>)$/
				.exec(node)
				.slice(1)
				.map((node, index) => index === 1 ? {tag: 'conditional-content', content: clean(parser(node))} : node);

			return {
				tag: 'conditional',
				content: conditional
			};
		}

		return node;
	});
};

const renderConditional = tree => {
	return tree.reduce((previousValue, node) => {
		if (typeof node === 'object' && Object.prototype.hasOwnProperty.call(node, 'content')) {
			node.content = renderConditional(node.content);
		}

		if (typeof node === 'object' && node.tag === 'conditional') {
			return [...previousValue, ...node.content];
		}

		if (typeof node === 'object' && node.tag === 'conditional-content') {
			node.tag = false;
			return [...previousValue, node];
		}

		return [...previousValue, node];
	}, []);
};

const indent = (tree, {rules: {indent, eol}}) => {
	const indentString = typeof indent === 'number' ? ' '.repeat(indent) : '\t';

	const getIndent = level => `${eol}${indentString.repeat(level)}`;

	const setIndent = (tree, level = 0) => tree.reduce((previousValue, node, index) => {
		if (typeof node === 'object' && Object.prototype.hasOwnProperty.call(node, 'content')) {
			node.content = setIndent(node.content, ++level);
			--level;
		}

		if (tree.length === 1 && typeof tree[index] === 'string') {
			return [...previousValue, node];
		}

		if (level === 0 && (tree.length - 1) === index && tree.length > 1) {
			return [...previousValue, getIndent(level), node];
		}

		if (level === 0 && (tree.length - 1) === index && tree.length === 1) {
			return [...previousValue, node];
		}

		if (level === 0 && index === 0) {
			return [...previousValue, node, getIndent(level)];
		}

		if (level === 0) {
			return [...previousValue, getIndent(level), node, getIndent(level)];
		}

		if ((tree.length - 1) === index) {
			return [...previousValue, getIndent(level), node, getIndent(--level)];
		}

		if (typeof node === 'string' && /<!(?:--)?\[endif]*?]>/.test(node)) {
			return [...previousValue, getIndent(level), node, getIndent(0)];
		}

		if (typeof node === 'string' && /<!(?:--)?\[[\s\S]*?]>/.test(node)) {
			return [...previousValue, getIndent(level), node];
		}

		if (node.tag === false) {
			return [...previousValue, ...node.content.slice(0, -1)];
		}

		return [...previousValue, getIndent(level), node, getIndent(0)];
	}, []);

	return setIndent(tree);
};

const attrsBoolean = (tree, {attrs: {boolean}}) => {
	const removeAttrValue = tree => tree.map(node => {
		if (typeof node === 'object' && Object.prototype.hasOwnProperty.call(node, 'content')) {
			node.content = removeAttrValue(node.content);
		}

		if (typeof node === 'object' && Object.prototype.hasOwnProperty.call(node, 'attrs')) {
			Object.keys(node.attrs).forEach(key => {
				node.attrs[key] = boolean.includes(key) ? true : node.attrs[key].trim();
			});
		}

		return node;
	});

	return removeAttrValue(tree);
};

const lowerElementName = (tree, {tags}) => {
	tags = tags.map(({name}) => name);

	const bypass = tree => tree.map(node => {
		if (typeof node === 'object' && Object.prototype.hasOwnProperty.call(node, 'content')) {
			node.content = bypass(node.content);
		}

		if (
			typeof node === 'object' &&
			Object.prototype.hasOwnProperty.call(node, 'tag') &&
			tags.includes(node.tag.toLowerCase())
		) {
			node.tag = node.tag.toLowerCase();
		}

		return node;
	});

	return bypass(tree);
};

const lowerAttributeName = tree => {
	const bypass = tree => tree.map(node => {
		if (typeof node === 'object' && Object.prototype.hasOwnProperty.call(node, 'content')) {
			node.content = bypass(node.content);
		}

		if (
			typeof node === 'object' &&
			Object.prototype.hasOwnProperty.call(node, 'attrs')
		) {
			node.attrs = Object.keys(node.attrs).reduce((previousValue, key) => Object.assign(previousValue, {[key.toLowerCase()]: node.attrs[key]}), {});
		}

		return node;
	});

	return bypass(tree);
};

const eof = (tree, {rules: {eof}}) => eof ? [...tree, eof] : tree;

const beautify = (tree, options) => [
	clean,
	parseConditional,
	renderConditional,
	indent,
	lowerElementName,
	lowerAttributeName,
	attrsBoolean,
	eof
].reduce((previousValue, module) => typeof module === 'function' ? module(previousValue, options) : previousValue, tree);

export default (options = {}) => {
	return tree => {
		if (!Array.isArray(tree)) {
			return new Error(`tree is not Array`);
		}

		if (tree.length === 0) {
			return tree;
		}

		if (
			(
				Object.prototype.hasOwnProperty.call(tree, 'options') &&
				Object.prototype.hasOwnProperty.call(tree.options, 'sync') &&
				tree.options.sync
			) ||
			options.sync
		) {
			return beautify(tree, deepmerge(optionsDefault, options));
		}

		return Promise.resolve(beautify(tree, deepmerge(optionsDefault, options)));
	};
};
<commit_msg>feat(index): add options mini remove empty attributes<commit_after>import parser from 'posthtml-parser';
import render from 'posthtml-render';
import rules from './rules.js';
import attrs from './attrs.js';
import tags from './tags.js';
import deepmerge from 'deepmerge';

const optionsDefault = {
	rules: rules,
	attrs: attrs,
	tags: tags,
	sync: false,
	mini: {
		removeAttribute: false
	}
};

const clean = tree => parser(render(tree))
	.filter(node => {
		return typeof node === 'object' || (typeof node === 'string' && (node.trim().length !== 0 || /doctype/gi.test(node)));
	})
	.map(node => {
		if (Object.prototype.hasOwnProperty.call(node, 'content')) {
			node.content = clean(node.content);
		}

		return typeof node === 'string' ? node.trim() : node;
	});

const parseConditional = tree => {
	return tree.map(node => {
		if (typeof node === 'object' && Object.prototype.hasOwnProperty.call(node, 'content')) {
			node.content = parseConditional(node.content);
		}

		if (typeof node === 'string' && /<!(?:--)?\[[\s\S]*?]>/.test(node)) {
			const conditional = /^((?:<[^>]+>)?<!(?:--)?\[[\s\S]*?]>(?:<!)?(?:-->)?)([\s\S]*?)(<!(?:--<!)?\[[\s\S]*?](?:--)?>)$/
				.exec(node)
				.slice(1)
				.map((node, index) => index === 1 ? {tag: 'conditional-content', content: clean(parser(node))} : node);

			return {
				tag: 'conditional',
				content: conditional
			};
		}

		return node;
	});
};

const renderConditional = tree => {
	return tree.reduce((previousValue, node) => {
		if (typeof node === 'object' && Object.prototype.hasOwnProperty.call(node, 'content')) {
			node.content = renderConditional(node.content);
		}

		if (typeof node === 'object' && node.tag === 'conditional') {
			return [...previousValue, ...node.content];
		}

		if (typeof node === 'object' && node.tag === 'conditional-content') {
			node.tag = false;
			return [...previousValue, node];
		}

		return [...previousValue, node];
	}, []);
};

const indent = (tree, {rules: {indent, eol}}) => {
	const indentString = typeof indent === 'number' ? ' '.repeat(indent) : '\t';

	const getIndent = level => `${eol}${indentString.repeat(level)}`;

	const setIndent = (tree, level = 0) => tree.reduce((previousValue, node, index) => {
		if (typeof node === 'object' && Object.prototype.hasOwnProperty.call(node, 'content')) {
			node.content = setIndent(node.content, ++level);
			--level;
		}

		if (tree.length === 1 && typeof tree[index] === 'string') {
			return [...previousValue, node];
		}

		if (level === 0 && (tree.length - 1) === index && tree.length > 1) {
			return [...previousValue, getIndent(level), node];
		}

		if (level === 0 && (tree.length - 1) === index && tree.length === 1) {
			return [...previousValue, node];
		}

		if (level === 0 && index === 0) {
			return [...previousValue, node, getIndent(level)];
		}

		if (level === 0) {
			return [...previousValue, getIndent(level), node, getIndent(level)];
		}

		if ((tree.length - 1) === index) {
			return [...previousValue, getIndent(level), node, getIndent(--level)];
		}

		if (typeof node === 'string' && /<!(?:--)?\[endif]*?]>/.test(node)) {
			return [...previousValue, getIndent(level), node, getIndent(0)];
		}

		if (typeof node === 'string' && /<!(?:--)?\[[\s\S]*?]>/.test(node)) {
			return [...previousValue, getIndent(level), node];
		}

		if (node.tag === false) {
			return [...previousValue, ...node.content.slice(0, -1)];
		}

		return [...previousValue, getIndent(level), node, getIndent(0)];
	}, []);

	return setIndent(tree);
};

const attrsBoolean = (tree, {attrs: {boolean}}) => {
	const removeAttrValue = tree => tree.map(node => {
		if (typeof node === 'object' && Object.prototype.hasOwnProperty.call(node, 'content')) {
			node.content = removeAttrValue(node.content);
		}

		if (typeof node === 'object' && Object.prototype.hasOwnProperty.call(node, 'attrs')) {
			Object.keys(node.attrs).forEach(key => {
				node.attrs[key] = boolean.includes(key) ? true : node.attrs[key].trim();
			});
		}

		return node;
	});

	return removeAttrValue(tree);
};

const lowerElementName = (tree, {tags}) => {
	tags = tags.map(({name}) => name);

	const bypass = tree => tree.map(node => {
		if (typeof node === 'object' && Object.prototype.hasOwnProperty.call(node, 'content')) {
			node.content = bypass(node.content);
		}

		if (
			typeof node === 'object' &&
			Object.prototype.hasOwnProperty.call(node, 'tag') &&
			tags.includes(node.tag.toLowerCase())
		) {
			node.tag = node.tag.toLowerCase();
		}

		return node;
	});

	return bypass(tree);
};

const lowerAttributeName = tree => {
	const bypass = tree => tree.map(node => {
		if (typeof node === 'object' && Object.prototype.hasOwnProperty.call(node, 'content')) {
			node.content = bypass(node.content);
		}

		if (
			typeof node === 'object' &&
			Object.prototype.hasOwnProperty.call(node, 'attrs')
		) {
			node.attrs = Object.keys(node.attrs).reduce((previousValue, key) => Object.assign(previousValue, {[key.toLowerCase()]: node.attrs[key]}), {});
		}

		return node;
	});

	return bypass(tree);
};

const eof = (tree, {rules: {eof}}) => eof ? [...tree, eof] : tree;

const mini = (tree, {mini}) => {
	const bypass = tree => tree.map(node => {
		if (typeof node === 'object' && Object.prototype.hasOwnProperty.call(node, 'content')) {
			node.content = bypass(node.content);
		}

		if (
			typeof node === 'object' &&
			Object.prototype.hasOwnProperty.call(node, 'attrs')
		) {
			node.attrs = Object.keys(node.attrs).reduce((previousValue, key) => {
				if (
						mini.removeAttribute &&
						mini.removeAttribute === 'empty' &&
						node.attrs[key].length === 0
					) {
					return previousValue;
				}

				return Object.assign(previousValue, {[key.toLowerCase()]: node.attrs[key]});
			}, {});
		}

		return node;
	});

	return bypass(tree);
};

const beautify = (tree, options) => [
	clean,
	parseConditional,
	renderConditional,
	indent,
	lowerElementName,
	lowerAttributeName,
	attrsBoolean,
	eof,
	mini
].reduce((previousValue, module) => typeof module === 'function' ? module(previousValue, options) : previousValue, tree);

export default (options = {}) => {
	return tree => {
		if (!Array.isArray(tree)) {
			return new Error(`tree is not Array`);
		}

		if (tree.length === 0) {
			return tree;
		}

		if (
			(
				Object.prototype.hasOwnProperty.call(tree, 'options') &&
				Object.prototype.hasOwnProperty.call(tree.options, 'sync') &&
				tree.options.sync
			) ||
			options.sync
		) {
			return beautify(tree, deepmerge(optionsDefault, options));
		}

		return Promise.resolve(beautify(tree, deepmerge(optionsDefault, options)));
	};
};
<|endoftext|>