<commit_before>// @flow

import {Patcher} from '../patch'
import luid from './luid'
import debug from './debug'

// A mutation describing a number of operations on a single document
// This should be considered an immutable structure. Mutations are compiled
// on first application, and any changes in properties will not effectively
// change its behavior after that.
export default class Mutation {
  params : {
    transactionId : string,
    transition : string,
    identity : string,
    previousRev : string,
    resultRev : string,
    mutations : Array<Object>,
    timestamp: String,
  }
  compiled : Function
  constructor(options : Object) {
    this.params = options
  }

  get transactionId() : string {
    return this.params.transactionId
  }
  get transition() : string {
    return this.params.transition
  }
  get identity() : string {
    return this.params.identity
  }
  get previousRev() : string {
    return this.params.previousRev
  }
  get resultRev() : string {
    return this.params.resultRev
  }
  get mutations() : Array<Object> {
    return this.params.mutations
  }
  get timestamp() : Date {
    if (typeof this.params.timestamp == 'string') {
      return new Date(this.params.timestamp)
    }
    return undefined
  }
  assignRandomTransactionId() {
    this.params.resultRev = this.params.transactionId = luid()
  }
  appliesToMissingDocument() {
    if (typeof this._appliesToMissingDocument !== 'undefined') {
      return this._appliesToMissingDocument
    }
    // Only mutations starting with a create operation apply to documents that do not exist ...
    const firstMut = this.mutations[0]
    if (firstMut) {
      this._appliesToMissingDocument = (firstMut.create || firstMut.createIfNotExist || firstMut.createOrReplace)
    } else {
      this._appliesToMissingDocument = true
    }
    return this._appliesToMissingDocument
  }
  // Compiles all mutations into a handy function
  compile() {
    const operations = []
    this.mutations.forEach(mutation => {
      if (mutation.create) {
        operations.push(doc => (doc === null ? mutation.create : doc))
      } else if (mutation.createIfNotExist) {
        operations.push(doc => (doc === null ? mutation.createIfNotExist : doc))
      } else if (mutation.createOrReplace) {
        operations.push(() => mutation.createOrReplace)
      } else if (mutation.delete) {
        operations.push(() => null)
      } else if (mutation.patch) {
        const patch = new Patcher(mutation.patch)
        operations.push(doc => patch.apply(doc))
      } else {
        throw new Error(`Unsupported mutation ${JSON.stringify(mutation, null, 2)}`)
      }
    })
    const prevRev = this.previousRev
    const rev = this.resultRev || this.transactionId
    this.compiled = doc => {
      if (prevRev && prevRev != doc._rev) {
        throw new Error(`Previous revision for this mutation was ${prevRev}, but the document revision is ${doc._rev}`)
      }
      const result = operations.reduce((revision, operation) => operation(revision), doc)
      if (result && rev) {
        result._rev = rev
      }
      return result
    }
  }
  apply(document : Object) : Object {
    debug(`Applying mutation ${JSON.stringify(this.mutations)} to document ${JSON.stringify(document)}`)
    if (!this.compiled) {
      this.compile()
    }
    const result = this.compiled(document)
    debug(`  => ${JSON.stringify(result)}`)
    return result
  }
  static applyAll(document : Object, mutations : Array<Mutation>) : Object {
    return mutations.reduce((doc, mutation) => mutation.apply(doc), document)
  }
  // Given a number of yet-to-be-committed mutation objects, collects them into one big mutation
  // any metadata like transactionId is ignored and must be submitted by the client. It is assumed
  // that all mutations are on the same document.
  // TOOO: Optimize mutations, eliminating mutations that overwrite themselves!
  static squash(document : Object, mutations : Array<Mutation>) : Mutation {
    const squashed = mutations.reduce((result, mutation) => result.concat(...mutation.mutations), [])
    return new Mutation({mutations: squashed})
  }
}
<commit_msg>[mutator] Changes createIfNotExist to creatIfNotExists<commit_after>// @flow

import { Patcher } from '../patch'
import luid from './luid'
import debug from './debug'

// A mutation describing a number of operations on a single document
// This should be considered an immutable structure. Mutations are compiled
// on first application, and any changes in properties will not effectively
// change its behavior after that.
export default class Mutation {
  params: {
    transactionId: string,
    transition: string,
    identity: string,
    previousRev: string,
    resultRev: string,
    mutations: Array<Object>,
    timestamp: String
  }
  compiled: Function
  constructor(options: Object) {
    this.params = options
  }

  get transactionId(): string {
    return this.params.transactionId
  }
  get transition(): string {
    return this.params.transition
  }
  get identity(): string {
    return this.params.identity
  }
  get previousRev(): string {
    return this.params.previousRev
  }
  get resultRev(): string {
    return this.params.resultRev
  }
  get mutations(): Array<Object> {
    return this.params.mutations
  }
  get timestamp(): Date {
    if (typeof this.params.timestamp == 'string') {
      return new Date(this.params.timestamp)
    }
    return undefined
  }
  assignRandomTransactionId() {
    this.params.resultRev = this.params.transactionId = luid()
  }
  appliesToMissingDocument() {
    if (typeof this._appliesToMissingDocument !== 'undefined') {
      return this._appliesToMissingDocument
    }
    // Only mutations starting with a create operation apply to documents that do not exist ...
    const firstMut = this.mutations[0]
    if (firstMut) {
      this._appliesToMissingDocument =
        firstMut.create ||
        firstMut.createIfNotExists ||
        firstMut.createOrReplace
    } else {
      this._appliesToMissingDocument = true
    }
    return this._appliesToMissingDocument
  }
  // Compiles all mutations into a handy function
  compile() {
    const operations = []
    this.mutations.forEach(mutation => {
      if (mutation.create) {
        operations.push(doc => (doc === null ? mutation.create : doc))
      } else if (mutation.createIfNotExists) {
        operations.push(
          doc => (doc === null ? mutation.createIfNotExists : doc)
        )
      } else if (mutation.createOrReplace) {
        operations.push(() => mutation.createOrReplace)
      } else if (mutation.delete) {
        operations.push(() => null)
      } else if (mutation.patch) {
        const patch = new Patcher(mutation.patch)
        operations.push(doc => patch.apply(doc))
      } else {
        throw new Error(
          `Unsupported mutation ${JSON.stringify(mutation, null, 2)}`
        )
      }
    })
    const prevRev = this.previousRev
    const rev = this.resultRev || this.transactionId
    this.compiled = doc => {
      if (prevRev && prevRev != doc._rev) {
        throw new Error(
          `Previous revision for this mutation was ${prevRev}, but the document revision is ${doc._rev}`
        )
      }
      const result = operations.reduce(
        (revision, operation) => operation(revision),
        doc
      )
      if (result && rev) {
        result._rev = rev
      }
      return result
    }
  }
  apply(document: Object): Object {
    debug(
      `Applying mutation ${JSON.stringify(this.mutations)} to document ${JSON.stringify(document)}`
    )
    if (!this.compiled) {
      this.compile()
    }
    const result = this.compiled(document)
    debug(`  => ${JSON.stringify(result)}`)
    return result
  }
  static applyAll(document: Object, mutations: Array<Mutation>): Object {
    return mutations.reduce((doc, mutation) => mutation.apply(doc), document)
  }
  // Given a number of yet-to-be-committed mutation objects, collects them into one big mutation
  // any metadata like transactionId is ignored and must be submitted by the client. It is assumed
  // that all mutations are on the same document.
  // TOOO: Optimize mutations, eliminating mutations that overwrite themselves!
  static squash(document: Object, mutations: Array<Mutation>): Mutation {
    const squashed = mutations.reduce(
      (result, mutation) => result.concat(...mutation.mutations),
      []
    )
    return new Mutation({ mutations: squashed })
  }
}
<|endoftext|>


<commit_before>import {pick, omit} from 'lodash'
import assert from 'assert'
import {lazyGetter} from './utils'

const OVERRIDABLE_FIELDS = ['jsonType', 'type', 'name', 'title', 'description', 'options', 'fieldsets']

const ARRAY_CORE = {
  name: 'array',
  type: null,
  jsonType: 'array',
  of: []
}

export const ArrayType = {
  get() {
    return ARRAY_CORE
  },
  extend(subTypeDef, createMemberType) {
    const parsed = Object.assign(pick(ARRAY_CORE, OVERRIDABLE_FIELDS), subTypeDef, {
      type: ARRAY_CORE,
    })
    lazyGetter(parsed, 'of', () => {
      return subTypeDef.of.map(ofTypeDef => {
        return createMemberType(ofTypeDef)
      })
    })

    return subtype(parsed)

    function subtype(parent) {
      return {
        get() {
          return parent
        },
        extend: extensionDef => {
          if (extensionDef.of) {
            throw new Error('Cannot override `of` property of subtypes of "array"')
          }
          const current = Object.assign({}, parent, pick(extensionDef, OVERRIDABLE_FIELDS), {type: parent})
          return subtype(current)
        }
      }
    }
  }
}
const Person = ArrayType.extend({
  name: 'person',
  title: 'Person',
  of: [
    {type: 'string', name: 'lol'}
  ]
}, v => v)

const TypeOfPerson = Person.extend({
  name: 'typeofperson',
  title: 'Type Of Person'
}, v => v)

const TypeOfTypeOfPerson = TypeOfPerson.extend({
  name: 'typeoftypeofperson',
  title: 'Type Of Type Of Person'
}, v => v)

assert.equal(TypeOfTypeOfPerson.get().type, TypeOfPerson.get())
assert.equal(TypeOfTypeOfPerson.get().type, TypeOfPerson.get())
assert.equal(TypeOfTypeOfPerson.get().fields, Person.get().fields)
assert.throws(
  () => TypeOfTypeOfPerson.extend({name: 'lol', of: []}),
  /Cannot override `of` property of subtypes of "array"/
)
// console.log('TypeOfTypeOfPerson', TypeOfTypeOfPerson.get())
<commit_msg>[schema] Remove stray test code from array schema type<commit_after>import {pick} from 'lodash'
import {lazyGetter} from './utils'

const OVERRIDABLE_FIELDS = ['jsonType', 'type', 'name', 'title', 'description', 'options', 'fieldsets']

const ARRAY_CORE = {
  name: 'array',
  type: null,
  jsonType: 'array',
  of: []
}

export const ArrayType = {
  get() {
    return ARRAY_CORE
  },
  extend(subTypeDef, createMemberType) {
    const parsed = Object.assign(pick(ARRAY_CORE, OVERRIDABLE_FIELDS), subTypeDef, {
      type: ARRAY_CORE,
    })
    lazyGetter(parsed, 'of', () => {
      return subTypeDef.of.map(ofTypeDef => {
        return createMemberType(ofTypeDef)
      })
    })

    return subtype(parsed)

    function subtype(parent) {
      return {
        get() {
          return parent
        },
        extend: extensionDef => {
          if (extensionDef.of) {
            throw new Error('Cannot override `of` property of subtypes of "array"')
          }
          const current = Object.assign({}, parent, pick(extensionDef, OVERRIDABLE_FIELDS), {type: parent})
          return subtype(current)
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>'use strict'

const path = require('path')
const loaderUtils = require('loader-utils')
const resolver = require('@sanity/resolver')
const multiImplementationHandler = require('./multiImplementationHandler')

function sanityPartLoader(input) {
  const callback = this.async()

  const part = this.data.sanityPart
  const basePath = this.data.basePath

  if (!part) {
    return callback(new Error('`sanityPart` property must be passed to the part loader'))
  }

  if (!basePath) {
    return callback(new Error('`basePath` property must be passed to part loader'))
  }

  this.addDependency(path.join(basePath, 'sanity.json'))

  return resolver
    .resolveParts({basePath: basePath})
    .then(parts => {
      if (this.cacheable) {
        this.cacheable()
      }

      // Also add plugin manifests as dependencies, as parts and paths may change
      parts.plugins.forEach(plugin => {
        this.addDependency(path.join(plugin.path, 'sanity.json'))
      })

      const loadAll = part.indexOf('all:') === 0
      const partName = loadAll ? part.substr(4) : part
      const opts = {part: partName, input, parts}

      if (partName === 'sanity:debug') {
        return setImmediate(
          callback,
          null,
          `module.exports = ${JSON.stringify(parts, null, 2)}\n`
        )
      }

      return loadAll
        ? setImmediate(multiImplementationHandler, opts, callback)
        : callback(null, input)
    })
    .catch(err => {
      this.emitWarning(err.message)
      throw err
    })
}

sanityPartLoader.pitch = function (remaining, preceding, data) {
  if (remaining.indexOf('sanityPart=') === -1) {
    return
  }

  const qs = remaining.substring(remaining.indexOf('?'))
  Object.assign(data, loaderUtils.parseQuery(qs) || {})
}

module.exports = sanityPartLoader
<commit_msg>Dont check for cachable function to be available, just call it<commit_after>'use strict'

const path = require('path')
const loaderUtils = require('loader-utils')
const resolver = require('@sanity/resolver')
const multiImplementationHandler = require('./multiImplementationHandler')

function sanityPartLoader(input) {
  const callback = this.async()

  const part = this.data.sanityPart
  const basePath = this.data.basePath

  if (!part) {
    return callback(new Error('`sanityPart` property must be passed to the part loader'))
  }

  if (!basePath) {
    return callback(new Error('`basePath` property must be passed to part loader'))
  }

  this.addDependency(path.join(basePath, 'sanity.json'))

  return resolver
    .resolveParts({basePath: basePath})
    .then(parts => {
      this.cacheable()

      // Also add plugin manifests as dependencies, as parts and paths may change
      parts.plugins.forEach(plugin => {
        this.addDependency(path.join(plugin.path, 'sanity.json'))
      })

      const loadAll = part.indexOf('all:') === 0
      const partName = loadAll ? part.substr(4) : part
      const opts = {part: partName, input, parts}

      if (partName === 'sanity:debug') {
        return setImmediate(
          callback,
          null,
          `module.exports = ${JSON.stringify(parts, null, 2)}\n`
        )
      }

      return loadAll
        ? setImmediate(multiImplementationHandler, opts, callback)
        : callback(null, input)
    })
    .catch(err => {
      this.emitWarning(err.message)
      throw err
    })
}

sanityPartLoader.pitch = function (remaining, preceding, data) {
  if (remaining.indexOf('sanityPart=') === -1) {
    return
  }

  const qs = remaining.substring(remaining.indexOf('?'))
  Object.assign(data, loaderUtils.parseQuery(qs) || {})
}

module.exports = sanityPartLoader
<|endoftext|>


<commit_before>'use strict';

var BN = require('./bn');
var _ = require('lodash');
var $ = require('../util/preconditions');
var BufferUtil = require('../util/buffer');
var JSUtil = require('../util/js');

var Signature = function Signature(r, s, isSchnorr) {
  if (!(this instanceof Signature)) {
    return new Signature(r, s, isSchnorr);
  }
  if (r instanceof BN) {
    this.set({
      r: r,
      s: s,
      isSchnorr: isSchnorr,
    });
  } else if (r) {
    var obj = r;
    this.set(obj);
  }
};

/* jshint maxcomplexity: 7 */
Signature.prototype.set = function(obj) {
  this.r = obj.r || this.r || undefined;
  this.s = obj.s || this.s || undefined;

  this.i = typeof obj.i !== 'undefined' ? obj.i : this.i; //public key recovery parameter in range [0, 3]
  this.compressed = typeof obj.compressed !== 'undefined' ?
    obj.compressed : this.compressed; // whether the recovered pubkey is compressed
  this.isSchnorr = obj.isSchnorr;
  this.nhashtype = obj.nhashtype || this.nhashtype || undefined;
  return this;
};

Signature.fromCompact = function(buf) {
  $.checkArgument(BufferUtil.isBuffer(buf), 'Argument is expected to be a Buffer');

  var sig = new Signature();

  var compressed = true;
  var i = buf.slice(0, 1)[0] - 27 - 4;
  if (i < 0) {
    compressed = false;
    i = i + 4;
  }

  var b2 = buf.slice(1, 33);
  var b3 = buf.slice(33, 65);

  $.checkArgument(i === 0 || i === 1 || i === 2 || i === 3, new Error('i must be 0, 1, 2, or 3'));
  $.checkArgument(b2.length === 32, new Error('r must be 32 bytes'));
  $.checkArgument(b3.length === 32, new Error('s must be 32 bytes'));

  sig.compressed = compressed;
  sig.i = i;
  sig.r = BN.fromBuffer(b2);
  sig.s = BN.fromBuffer(b3);

  return sig;
};

Signature.fromDER = Signature.fromBuffer = function(buf, strict) {
  // Schnorr Signatures use 65 byte for in tx r [len] 32 , s [len] 32, nhashtype
  if((buf.length === 64) && buf[0] != 0x30) {
    let obj = Signature.parseSchnorrEncodedSig(buf);
    let sig = new Signature();
    sig.r = obj.r;
    sig.s = obj.s;
    sig.isSchnorr = true;
    return sig;
  } if (buf.length === 64 && buf[0] === 0x30) {
    return "64 DER (ecdsa) signautres not allowed";
  }

  var obj = Signature.parseDER(buf, strict);
  var sig = new Signature();

  sig.r = obj.r;
  sig.s = obj.s;

  return sig;
};

// The format used in a tx
Signature.fromTxFormat = function(buf) {
  var nhashtype = buf.readUInt8(buf.length - 1);
  var derbuf = buf.slice(0, buf.length - 1);
  var sig = new Signature.fromDER(derbuf, false);
  sig.nhashtype = nhashtype;
  return sig;
};

// The format used in a tx
Signature.fromDataFormat = function(buf) {
  var derbuf = buf.slice(0, buf.length);
  var sig = new Signature.fromDER(derbuf, false);
  return sig;
};

Signature.fromString = function(str) {
  var buf = Buffer.from(str, 'hex');

  return Signature.fromDER(buf);
};

Signature.parseSchnorrEncodedSig = function(buf) {
  let r = buf.slice(0,32);
  let s = buf.slice(32, 64);
  let hashtype;
  if (buf.length === 65) {
    hashtype = buf.slice(64,65);
    this.nhashtype = hashtype;
  }

  var obj = {
    r: BN.fromBuffer(r),
    s: BN.fromBuffer(s),
    nhashtype: hashtype
  };

  return obj;
};

/**
 * In order to mimic the non-strict DER encoding of OpenSSL, set strict = false.
 */
Signature.parseDER = function(buf, strict) {
  $.checkArgument(BufferUtil.isBuffer(buf), new Error('DER formatted signature should be a buffer'));
  if (_.isUndefined(strict)) {
    strict = true;
  }

  var header = buf[0];
  $.checkArgument(header === 0x30, new Error('Header byte should be 0x30'));

  var length = buf[1];
  var buflength = buf.slice(2).length;
  $.checkArgument(!strict || length === buflength, new Error('Length byte should length of what follows'));

  length = length < buflength ? length : buflength;

  var rheader = buf[2 + 0];
  $.checkArgument(rheader === 0x02, new Error('Integer byte for r should be 0x02'));

  var rlength = buf[2 + 1];
  var rbuf = buf.slice(2 + 2, 2 + 2 + rlength);
  var r = BN.fromBuffer(rbuf);
  var rneg = buf[2 + 1 + 1] === 0x00 ? true : false;
  $.checkArgument(rlength === rbuf.length, new Error('Length of r incorrect'));

  var sheader = buf[2 + 2 + rlength + 0];
  $.checkArgument(sheader === 0x02, new Error('Integer byte for s should be 0x02'));

  var slength = buf[2 + 2 + rlength + 1];
  var sbuf = buf.slice(2 + 2 + rlength + 2, 2 + 2 + rlength + 2 + slength);
  var s = BN.fromBuffer(sbuf);
  var sneg = buf[2 + 2 + rlength + 2 + 2] === 0x00 ? true : false;
  $.checkArgument(slength === sbuf.length, new Error('Length of s incorrect'));

  var sumlength = 2 + 2 + rlength + 2 + slength;
  $.checkArgument(length === sumlength - 2, new Error('Length of signature incorrect'));

  var obj = {
    header: header,
    length: length,
    rheader: rheader,
    rlength: rlength,
    rneg: rneg,
    rbuf: rbuf,
    r: r,
    sheader: sheader,
    slength: slength,
    sneg: sneg,
    sbuf: sbuf,
    s: s
  };

  return obj;
};

Signature.prototype.toCompact = function(i, compressed) {
  i = typeof i === 'number' ? i : this.i;
  compressed = typeof compressed === 'boolean' ? compressed : this.compressed;

  if (!(i === 0 || i === 1 || i === 2 || i === 3)) {
    throw new Error('i must be equal to 0, 1, 2, or 3');
  }

  var val = i + 27 + 4;
  if (compressed === false) {
    val = val - 4;
  }
  var b1 = Buffer.from([val]);
  var b2 = this.r.toBuffer({
    size: 32
  });
  var b3 = this.s.toBuffer({
    size: 32
  });
  return Buffer.concat([b1, b2, b3]);
};

Signature.prototype.toBuffer = Signature.prototype.toDER = function(signingMethod) {

  // Schnorr signatures use a 64 byte r,s format, where as ECDSA takes the form decribed
  // below, above the isDER function signature.

  signingMethod = signingMethod || "ecdsa";

  var rnbuf = this.r.toBuffer();
  var snbuf = this.s.toBuffer();

  if(signingMethod === "schnorr") {
    return Buffer.concat([rnbuf, snbuf]);
  }

  var rneg = rnbuf[0] & 0x80 ? true : false;
  var sneg = snbuf[0] & 0x80 ? true : false;

  var rbuf = rneg ? Buffer.concat([Buffer.from([0x00]), rnbuf]) : rnbuf;
  var sbuf = sneg ? Buffer.concat([Buffer.from([0x00]), snbuf]) : snbuf;

  var rlength = rbuf.length;
  var slength = sbuf.length;
  var length = 2 + rlength + 2 + slength;
  var rheader = 0x02;
  var sheader = 0x02;
  var header = 0x30;

  var der = Buffer.concat([Buffer.from([header, length, rheader, rlength]), rbuf, Buffer.from([sheader, slength]), sbuf]);
  return der;
};

Signature.prototype.toString = function() {
  var buf = this.toDER();
  return buf.toString('hex');
};

Signature.isTxDER = function(buf) {
  return Signature.isDER(buf.slice(0, buf.length-1));
}

/**
 * This function is translated from bitcoind's IsDERSignature and is used in
 * the script interpreter.  This "DER" format actually includes an extra byte,
 * the nhashtype, at the end. It is really the tx format, not DER format.
 *
 * A canonical signature exists of: [30] [total len] [02] [len R] [R] [02] [len S] [S]
 * Where R and S are not negative (their first byte has its highest bit not set), and not
 * excessively padded (do not start with a 0 byte, unless an otherwise negative number follows,
 * in which case a single 0 byte is necessary and even required).
 *
 * See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623
 */
Signature.isDER = function(buf) {
  // Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S]
  // * total-length: 1-byte length descriptor of everything that follows,
  // excluding the sighash byte.
  // * R-length: 1-byte length descriptor of the R value that follows.
  // * R: arbitrary-length big-endian encoded R value. It must use the
  // shortest possible encoding for a positive integers (which means no null
  // bytes at the start, except a single one when the next byte has its
  // highest bit set).
  // * S-length: 1-byte length descriptor of the S value that follows.
  // * S: arbitrary-length big-endian encoded S value. The same rules apply.

  // Minimum and maximum size constraints.
  if (buf.length < 8 || buf.length > 72) {
    return false;
  }

  //
  // Check that the signature is a compound structure of proper size.
  //

  // A signature is of type 0x30 (compound).
  if (buf[0] != 0x30) {
    return false;
  }

  // Make sure the length covers the entire signature.
  // Remove:
  // * 1 byte for the coupound type.
  // * 1 byte for the length of the signature.
  if (buf[1] != buf.length - 2) {
    return false;
  }

  //
  // Check that R is an positive integer of sensible size.
  //

  // Check whether the R element is an integer.
  if (buf[2] != 0x02) {
    return false;
  }

  // Extract the length of the R element.
  var lenR = buf[3];

  // Zero-length integers are not allowed for R.
  if (lenR == 0) {
    return false;
  }

  // Negative numbers are not allowed for R.
  if (buf[4] & 0x80) {
    return false;
  }

  // Make sure the length of the R element is consistent with the signature
  // size.
  // Remove:
  // * 1 byte for the coumpound type.
  // * 1 byte for the length of the signature.
  // * 2 bytes for the integer type of R and S.
  // * 2 bytes for the size of R and S.
  // * 1 byte for S itself.
  if (lenR > (buf.length - 7)) {
    return false;
  }

  // Null bytes at the start of R are not allowed, unless R would otherwise be
  // interpreted as a negative number.
  //
  // /!\ This check can only be performed after we checked that lenR is
  //     consistent with the size of the signature or we risk to access out of
  //     bound elements.
  if (lenR > 1 && (buf[4] == 0x00) && !(buf[5] & 0x80)) {
    return false;
  }

  //
  // Check that S is an positive integer of sensible size.
  //

  // S's definition starts after R's definition:
  // * 1 byte for the coumpound type.
  // * 1 byte for the length of the signature.
  // * 1 byte for the size of R.
  // * lenR bytes for R itself.
  // * 1 byte to get to S.
  var startS = lenR + 4;

  // Check whether the S element is an integer.
  if (buf[startS] != 0x02) {
    return false;
  }

  // Extract the length of the S element.
  var lenS = buf[startS + 1];

  // Zero-length integers are not allowed for S.
  if (lenS == 0) {
    return false;
  }

  // Negative numbers are not allowed for S.
  if (buf[startS + 2] & 0x80) {
    return false;
  }

  // Verify that the length of S is consistent with the size of the signature
  // including metadatas:
  // * 1 byte for the integer type of S.
  // * 1 byte for the size of S.
  if (startS + lenS + 2 != buf.length) {
    return false;
  }

  // Null bytes at the start of S are not allowed, unless S would otherwise be
  // interpreted as a negative number.
  //
  // /!\ This check can only be performed after we checked that lenR and lenS
  //     are consistent with the size of the signature or we risk to access
  //     out of bound elements.
  if (lenS > 1 && (buf[startS + 2] == 0x00) && !(buf[startS + 3] & 0x80)) {
    return false;
  }

  return true;
};

/**
 * Compares to bitcoind's IsLowDERSignature
 * See also ECDSA signature algorithm which enforces this.
 * See also BIP 62, "low S values in signatures"
 */
Signature.prototype.hasLowS = function() {
  if (this.s.lt(new BN(1)) ||
    this.s.gt(new BN('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0', 'hex'))) {
    return false;
  }
  return true;
};

/**
 * @returns true if the nhashtype is exactly equal to one of the standard options or combinations thereof.
 * Translated from bitcoind's IsDefinedHashtypeSignature
 */
Signature.prototype.hasDefinedHashtype = function() {
  if (!JSUtil.isNaturalNumber(this.nhashtype)) {
    return false;
  }
  // accept with or without Signature.SIGHASH_ANYONECANPAY by ignoring the bit
  // base mask was 1F
  var mask =  ~(Signature.SIGHASH_FORKID | Signature.SIGHASH_ANYONECANPAY) >>>0;
  var temp = this.nhashtype  & mask;
  if (temp < Signature.SIGHASH_ALL || temp > Signature.SIGHASH_SINGLE) {
    return false;
  }
  return true;
};

Signature.prototype.toTxFormat = function(signingMethod) {
  var derbuf = this.toDER(signingMethod);
  var buf = Buffer.alloc(1);
  buf.writeUInt8(this.nhashtype, 0);
  return Buffer.concat([derbuf, buf]);
};

Signature.SIGHASH_ALL = 0x01;
Signature.SIGHASH_NONE = 0x02;
Signature.SIGHASH_SINGLE = 0x03;
Signature.SIGHASH_FORKID = 0x40;
Signature.SIGHASH_ANYONECANPAY = 0x80;

module.exports = Signature;
<commit_msg>account for 64, 65 byte DER sigs<commit_after>'use strict';

var BN = require('./bn');
var _ = require('lodash');
var $ = require('../util/preconditions');
var BufferUtil = require('../util/buffer');
var JSUtil = require('../util/js');
const { sign } = require('./ecdsa');

var Signature = function Signature(r, s, isSchnorr) {
  if (!(this instanceof Signature)) {
    return new Signature(r, s, isSchnorr);
  }
  if (r instanceof BN) {
    this.set({
      r: r,
      s: s,
      isSchnorr: isSchnorr,
    });
  } else if (r) {
    var obj = r;
    this.set(obj);
  }
};

/* jshint maxcomplexity: 7 */
Signature.prototype.set = function(obj) {
  this.r = obj.r || this.r || undefined;
  this.s = obj.s || this.s || undefined;

  this.i = typeof obj.i !== 'undefined' ? obj.i : this.i; //public key recovery parameter in range [0, 3]
  this.compressed = typeof obj.compressed !== 'undefined' ?
    obj.compressed : this.compressed; // whether the recovered pubkey is compressed
  this.isSchnorr = obj.isSchnorr;
  this.nhashtype = obj.nhashtype || this.nhashtype || undefined;
  return this;
};

Signature.fromCompact = function(buf) {
  $.checkArgument(BufferUtil.isBuffer(buf), 'Argument is expected to be a Buffer');

  var sig = new Signature();

  var compressed = true;
  var i = buf.slice(0, 1)[0] - 27 - 4;
  if (i < 0) {
    compressed = false;
    i = i + 4;
  }

  var b2 = buf.slice(1, 33);
  var b3 = buf.slice(33, 65);

  $.checkArgument(i === 0 || i === 1 || i === 2 || i === 3, new Error('i must be 0, 1, 2, or 3'));
  $.checkArgument(b2.length === 32, new Error('r must be 32 bytes'));
  $.checkArgument(b3.length === 32, new Error('s must be 32 bytes'));

  sig.compressed = compressed;
  sig.i = i;
  sig.r = BN.fromBuffer(b2);
  sig.s = BN.fromBuffer(b3);

  return sig;
};

Signature.fromDER = Signature.fromBuffer = function(buf, strict) {
  // Schnorr Signatures use 65 byte for in tx r [len] 32 , s [len] 32, nhashtype
  if((buf.length === 64 || buf.length === 65) && buf[0] != 0x30) {
    let obj = Signature.parseSchnorrEncodedSig(buf);
    let sig = new Signature();
    sig.r = obj.r;
    sig.s = obj.s;
    sig.isSchnorr = true;
    return sig;
  } if (buf.length === 64 && buf[0] === 0x30) {
    return "64 DER (ecdsa) signatures not allowed";
  }

  var obj = Signature.parseDER(buf, strict);
  var sig = new Signature();

  sig.r = obj.r;
  sig.s = obj.s;

  return sig;
};

// The format used in a tx
Signature.fromTxFormat = function(buf) {
  var nhashtype = buf.readUInt8(buf.length - 1);
  var derbuf = buf.slice(0, buf.length - 1);
  var sig = new Signature.fromDER(derbuf, false);
  sig.nhashtype = nhashtype;
  return sig;
};

// The format used in a tx
Signature.fromDataFormat = function(buf) {
  var derbuf = buf.slice(0, buf.length);
  var sig = new Signature.fromDER(derbuf, false);
  return sig;
};

Signature.fromString = function(str) {
  var buf = Buffer.from(str, 'hex');

  return Signature.fromDER(buf);
};

Signature.parseSchnorrEncodedSig = function(buf) {
  let r = buf.slice(0,32);
  let s = buf.slice(32, 64);
  let hashtype;
  if (buf.length === 65) {
    hashtype = buf.slice(64,65);
    this.nhashtype = hashtype;
  }

  var obj = {
    r: BN.fromBuffer(r),
    s: BN.fromBuffer(s),
    nhashtype: hashtype
  };

  return obj;
};

/**
 * In order to mimic the non-strict DER encoding of OpenSSL, set strict = false.
 */
Signature.parseDER = function(buf, strict) {
  $.checkArgument(BufferUtil.isBuffer(buf), new Error('DER formatted signature should be a buffer'));
  if (_.isUndefined(strict)) {
    strict = true;
  }

  var header = buf[0];
  $.checkArgument(header === 0x30, new Error('Header byte should be 0x30'));

  var length = buf[1];
  var buflength = buf.slice(2).length;
  $.checkArgument(!strict || length === buflength, new Error('Length byte should length of what follows'));

  length = length < buflength ? length : buflength;

  var rheader = buf[2 + 0];
  $.checkArgument(rheader === 0x02, new Error('Integer byte for r should be 0x02'));

  var rlength = buf[2 + 1];
  var rbuf = buf.slice(2 + 2, 2 + 2 + rlength);
  var r = BN.fromBuffer(rbuf);
  var rneg = buf[2 + 1 + 1] === 0x00 ? true : false;
  $.checkArgument(rlength === rbuf.length, new Error('Length of r incorrect'));

  var sheader = buf[2 + 2 + rlength + 0];
  $.checkArgument(sheader === 0x02, new Error('Integer byte for s should be 0x02'));

  var slength = buf[2 + 2 + rlength + 1];
  var sbuf = buf.slice(2 + 2 + rlength + 2, 2 + 2 + rlength + 2 + slength);
  var s = BN.fromBuffer(sbuf);
  var sneg = buf[2 + 2 + rlength + 2 + 2] === 0x00 ? true : false;
  $.checkArgument(slength === sbuf.length, new Error('Length of s incorrect'));

  var sumlength = 2 + 2 + rlength + 2 + slength;
  $.checkArgument(length === sumlength - 2, new Error('Length of signature incorrect'));

  var obj = {
    header: header,
    length: length,
    rheader: rheader,
    rlength: rlength,
    rneg: rneg,
    rbuf: rbuf,
    r: r,
    sheader: sheader,
    slength: slength,
    sneg: sneg,
    sbuf: sbuf,
    s: s
  };

  return obj;
};

Signature.prototype.toCompact = function(i, compressed) {
  i = typeof i === 'number' ? i : this.i;
  compressed = typeof compressed === 'boolean' ? compressed : this.compressed;

  if (!(i === 0 || i === 1 || i === 2 || i === 3)) {
    throw new Error('i must be equal to 0, 1, 2, or 3');
  }

  var val = i + 27 + 4;
  if (compressed === false) {
    val = val - 4;
  }
  var b1 = Buffer.from([val]);
  var b2 = this.r.toBuffer({
    size: 32
  });
  var b3 = this.s.toBuffer({
    size: 32
  });
  return Buffer.concat([b1, b2, b3]);
};

Signature.prototype.toBuffer = Signature.prototype.toDER = function(signingMethod) {

  // Schnorr signatures use a 64 byte r,s format, where as ECDSA takes the form decribed
  // below, above the isDER function signature.

  signingMethod = signingMethod || "ecdsa";

  var rnbuf = this.r.toBuffer();
  var snbuf = this.s.toBuffer();

  if(signingMethod === "schnorr") {
    return Buffer.concat([rnbuf, snbuf]);
  }

  var rneg = rnbuf[0] & 0x80 ? true : false;
  var sneg = snbuf[0] & 0x80 ? true : false;

  var rbuf = rneg ? Buffer.concat([Buffer.from([0x00]), rnbuf]) : rnbuf;
  var sbuf = sneg ? Buffer.concat([Buffer.from([0x00]), snbuf]) : snbuf;

  var rlength = rbuf.length;
  var slength = sbuf.length;
  var length = 2 + rlength + 2 + slength;
  var rheader = 0x02;
  var sheader = 0x02;
  var header = 0x30;

  var der = Buffer.concat([Buffer.from([header, length, rheader, rlength]), rbuf, Buffer.from([sheader, slength]), sbuf]);
  return der;
};

Signature.prototype.toString = function() {
  var buf = this.toDER();
  return buf.toString('hex');
};

Signature.isTxDER = function(buf) {
  return Signature.isDER(buf.slice(0, buf.length-1));
}

/**
 * This function is translated from bitcoind's IsDERSignature and is used in
 * the script interpreter.  This "DER" format actually includes an extra byte,
 * the nhashtype, at the end. It is really the tx format, not DER format.
 *
 * A canonical signature exists of: [30] [total len] [02] [len R] [R] [02] [len S] [S]
 * Where R and S are not negative (their first byte has its highest bit not set), and not
 * excessively padded (do not start with a 0 byte, unless an otherwise negative number follows,
 * in which case a single 0 byte is necessary and even required).
 *
 * See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623
 */
Signature.isDER = function(buf) {
  // Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S]
  // * total-length: 1-byte length descriptor of everything that follows,
  // excluding the sighash byte.
  // * R-length: 1-byte length descriptor of the R value that follows.
  // * R: arbitrary-length big-endian encoded R value. It must use the
  // shortest possible encoding for a positive integers (which means no null
  // bytes at the start, except a single one when the next byte has its
  // highest bit set).
  // * S-length: 1-byte length descriptor of the S value that follows.
  // * S: arbitrary-length big-endian encoded S value. The same rules apply.

  // Minimum and maximum size constraints.
  if (buf.length < 8 || buf.length > 72) {
    return false;
  }

  //
  // Check that the signature is a compound structure of proper size.
  //

  // A signature is of type 0x30 (compound).
  if (buf[0] != 0x30) {
    return false;
  }

  // Make sure the length covers the entire signature.
  // Remove:
  // * 1 byte for the coupound type.
  // * 1 byte for the length of the signature.
  if (buf[1] != buf.length - 2) {
    return false;
  }

  //
  // Check that R is an positive integer of sensible size.
  //

  // Check whether the R element is an integer.
  if (buf[2] != 0x02) {
    return false;
  }

  // Extract the length of the R element.
  var lenR = buf[3];

  // Zero-length integers are not allowed for R.
  if (lenR == 0) {
    return false;
  }

  // Negative numbers are not allowed for R.
  if (buf[4] & 0x80) {
    return false;
  }

  // Make sure the length of the R element is consistent with the signature
  // size.
  // Remove:
  // * 1 byte for the coumpound type.
  // * 1 byte for the length of the signature.
  // * 2 bytes for the integer type of R and S.
  // * 2 bytes for the size of R and S.
  // * 1 byte for S itself.
  if (lenR > (buf.length - 7)) {
    return false;
  }

  // Null bytes at the start of R are not allowed, unless R would otherwise be
  // interpreted as a negative number.
  //
  // /!\ This check can only be performed after we checked that lenR is
  //     consistent with the size of the signature or we risk to access out of
  //     bound elements.
  if (lenR > 1 && (buf[4] == 0x00) && !(buf[5] & 0x80)) {
    return false;
  }

  //
  // Check that S is an positive integer of sensible size.
  //

  // S's definition starts after R's definition:
  // * 1 byte for the coumpound type.
  // * 1 byte for the length of the signature.
  // * 1 byte for the size of R.
  // * lenR bytes for R itself.
  // * 1 byte to get to S.
  var startS = lenR + 4;

  // Check whether the S element is an integer.
  if (buf[startS] != 0x02) {
    return false;
  }

  // Extract the length of the S element.
  var lenS = buf[startS + 1];

  // Zero-length integers are not allowed for S.
  if (lenS == 0) {
    return false;
  }

  // Negative numbers are not allowed for S.
  if (buf[startS + 2] & 0x80) {
    return false;
  }

  // Verify that the length of S is consistent with the size of the signature
  // including metadatas:
  // * 1 byte for the integer type of S.
  // * 1 byte for the size of S.
  if (startS + lenS + 2 != buf.length) {
    return false;
  }

  // Null bytes at the start of S are not allowed, unless S would otherwise be
  // interpreted as a negative number.
  //
  // /!\ This check can only be performed after we checked that lenR and lenS
  //     are consistent with the size of the signature or we risk to access
  //     out of bound elements.
  if (lenS > 1 && (buf[startS + 2] == 0x00) && !(buf[startS + 3] & 0x80)) {
    return false;
  }

  return true;
};

/**
 * Compares to bitcoind's IsLowDERSignature
 * See also ECDSA signature algorithm which enforces this.
 * See also BIP 62, "low S values in signatures"
 */
Signature.prototype.hasLowS = function() {
  if (this.s.lt(new BN(1)) ||
    this.s.gt(new BN('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0', 'hex'))) {
    return false;
  }
  return true;
};

/**
 * @returns true if the nhashtype is exactly equal to one of the standard options or combinations thereof.
 * Translated from bitcoind's IsDefinedHashtypeSignature
 */
Signature.prototype.hasDefinedHashtype = function() {
  if (!JSUtil.isNaturalNumber(this.nhashtype)) {
    return false;
  }
  // accept with or without Signature.SIGHASH_ANYONECANPAY by ignoring the bit
  // base mask was 1F
  var mask =  ~(Signature.SIGHASH_FORKID | Signature.SIGHASH_ANYONECANPAY) >>>0;
  var temp = this.nhashtype  & mask;
  if (temp < Signature.SIGHASH_ALL || temp > Signature.SIGHASH_SINGLE) {
    return false;
  }
  return true;
};

Signature.prototype.toTxFormat = function(signingMethod) {
  var derbuf = this.toDER(signingMethod);
  var buf = Buffer.alloc(1);
  buf.writeUInt8(this.nhashtype, 0);
  return Buffer.concat([derbuf, buf]);
};

Signature.SIGHASH_ALL = 0x01;
Signature.SIGHASH_NONE = 0x02;
Signature.SIGHASH_SINGLE = 0x03;
Signature.SIGHASH_FORKID = 0x40;
Signature.SIGHASH_ANYONECANPAY = 0x80;

module.exports = Signature;
<|endoftext|>


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

import React from 'react';
import PropTypes from 'prop-types';
import { IndexLink } from 'react-router';

import BpkLink from 'bpk-component-link';
import AnimateHeight from 'bpk-animate-height';
import BpkRouterLink from 'bpk-component-router-link';
import { BpkGridContainer, BpkGridRow, BpkGridColumn } from 'bpk-component-grid';
import { cssModules } from 'bpk-react-utils';

import STYLES from './Header.scss';
import * as ROUTES from './../../constants/routes';
import HamburgerButton from './HamburgerButton';

const getClassName = cssModules(STYLES);

const headerLinks = [
  { to: ROUTES.USING_BACKPACK, children: 'Using Backpack' },
  { to: ROUTES.STYLE, children: 'Style' },
  { to: ROUTES.TOKENS, children: 'Tokens' },
  { to: ROUTES.COMPONENTS, children: 'Components' },
  { to: ROUTES.RESOURCES, children: 'Resources' },
  { href: 'https://github.com/Skyscanner/backpack', children: 'Github', blank: true },
];

const toNavList = (links, hideOnTablet) => {
  const classNames = [getClassName('bpkdocs-header__nav-list')];

  if (hideOnTablet) { classNames.push(getClassName('bpkdocs-header__nav-list--hide-on-tablet')); }

  return (

      {links.map((link = {}) => (

          {link.to
            ? <BpkRouterLink className={getClassName('bpkdocs-header__nav-list-link')} {...link} />
            : <BpkLink className={getClassName('bpkdocs-header__nav-list-link')} {...link} />}

        ))}

  );
};

const Header = (props) => {
  const { expanded, onHamburgerClick } = props;

  return (

      <BpkGridContainer>
        <BpkGridRow>
          <BpkGridColumn width={2} mobileWidth={6}>
            <IndexLink to={ROUTES.HOME} className={getClassName('bpkdocs-header__logo-link')}>
              Backpack
            </IndexLink>
          </BpkGridColumn>
          <BpkGridColumn width={10} mobileWidth={6}>

              <HamburgerButton
                expanded={expanded}
                onClick={onHamburgerClick}
                className={getClassName('bpkdocs-header__hamburger')}
              />
              {toNavList(headerLinks, true)}

          </BpkGridColumn>
        </BpkGridRow>
      </BpkGridContainer>
      <AnimateHeight
        height={expanded ? 'auto' : 0}
        duration={200}
      >
        <BpkGridContainer className={getClassName('bpkdocs-header__tablet-nav-container')}>
          <BpkGridRow>
            <BpkGridColumn width={12} padded={false}>

                {toNavList(headerLinks)}

            </BpkGridColumn>
          </BpkGridRow>
        </BpkGridContainer>
      </AnimateHeight>

  );
};

Header.propTypes = {
  expanded: PropTypes.bool.isRequired,
  onHamburgerClick: PropTypes.func.isRequired,
};

export default Header;
<commit_msg>[no jira] Hide 'style' from header<commit_after>/*
 * Backpack - Skyscanner's Design System
 *
 * Copyright 2017 Skyscanner Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import React from 'react';
import PropTypes from 'prop-types';
import { IndexLink } from 'react-router';

import BpkLink from 'bpk-component-link';
import AnimateHeight from 'bpk-animate-height';
import BpkRouterLink from 'bpk-component-router-link';
import { BpkGridContainer, BpkGridRow, BpkGridColumn } from 'bpk-component-grid';
import { cssModules } from 'bpk-react-utils';

import STYLES from './Header.scss';
import * as ROUTES from './../../constants/routes';
import HamburgerButton from './HamburgerButton';

const getClassName = cssModules(STYLES);

const headerLinks = [
  { to: ROUTES.USING_BACKPACK, children: 'Using Backpack' },
  { to: ROUTES.TOKENS, children: 'Tokens' },
  { to: ROUTES.COMPONENTS, children: 'Components' },
  { to: ROUTES.RESOURCES, children: 'Resources' },
  { href: 'https://github.com/Skyscanner/backpack', children: 'Github', blank: true },
];

const toNavList = (links, hideOnTablet) => {
  const classNames = [getClassName('bpkdocs-header__nav-list')];

  if (hideOnTablet) { classNames.push(getClassName('bpkdocs-header__nav-list--hide-on-tablet')); }

  return (

      {links.map((link = {}) => (

          {link.to
            ? <BpkRouterLink className={getClassName('bpkdocs-header__nav-list-link')} {...link} />
            : <BpkLink className={getClassName('bpkdocs-header__nav-list-link')} {...link} />}

        ))}

  );
};

const Header = (props) => {
  const { expanded, onHamburgerClick } = props;

  return (

      <BpkGridContainer>
        <BpkGridRow>
          <BpkGridColumn width={2} mobileWidth={6}>
            <IndexLink to={ROUTES.HOME} className={getClassName('bpkdocs-header__logo-link')}>
              Backpack
            </IndexLink>
          </BpkGridColumn>
          <BpkGridColumn width={10} mobileWidth={6}>

              <HamburgerButton
                expanded={expanded}
                onClick={onHamburgerClick}
                className={getClassName('bpkdocs-header__hamburger')}
              />
              {toNavList(headerLinks, true)}

          </BpkGridColumn>
        </BpkGridRow>
      </BpkGridContainer>
      <AnimateHeight
        height={expanded ? 'auto' : 0}
        duration={200}
      >
        <BpkGridContainer className={getClassName('bpkdocs-header__tablet-nav-container')}>
          <BpkGridRow>
            <BpkGridColumn width={12} padded={false}>

                {toNavList(headerLinks)}

            </BpkGridColumn>
          </BpkGridRow>
        </BpkGridContainer>
      </AnimateHeight>

  );
};

Header.propTypes = {
  expanded: PropTypes.bool.isRequired,
  onHamburgerClick: PropTypes.func.isRequired,
};

export default Header;
<|endoftext|>


<commit_before>import { render } from '@bolt/twig-renderer';

const timeout = 60000;

const imageVrtConfig = {
  failureThreshold: '0.02',
  failureThresholdType: 'percent',
};

describe('<bolt-ratio> Component', () => {
  let page;

  beforeEach(async () => {
    page = await global.__BROWSER__.newPage();
    await page.goto('http://127.0.0.1:4444/', {
      timeout: 0,
      waitLoad: true,
      waitNetworkIdle: true, // defaults to false
    });
  }, timeout);

  test('<bolt-ratio> compiles', async () => {
    const results = await render('@bolt-components-ratio/ratio.twig', {
      children: '',
      ratio: '1200/660',
    });
    expect(results.ok).toBe(true);
    expect(results.html).toMatchSnapshot();
  });

  test('Default <bolt-ratio> w/o Shadow DOM renders', async function() {
    const renderedRatioHTML = await page.evaluate(() => {
      const ratio = document.createElement('bolt-ratio');
      const img = document.createElement('img');
      img.setAttribute('src', '/fixtures/1200x660.jpg');
      ratio.setAttribute('no-shadow', '');
      ratio.setAttribute('ratio', '1200/660');
      ratio.appendChild(img);
      document.body.appendChild(ratio);
      ratio.useShadow = false;
      ratio.updated();
      return ratio.outerHTML;
    });
    expect(renderedRatioHTML).toMatchSnapshot();

    const image = await page.screenshot();
    expect(image).toMatchImageSnapshot(imageVrtConfig);

    const renderedRatioStyles = await page.evaluate(() => {
      const ratio = document.querySelector('bolt-ratio');
      const innerRatio = ratio.renderRoot.querySelector('.c-bolt-ratio');
      return innerRatio.style.getPropertyValue('--aspect-ratio').trim();
    });

    expect(renderedRatioStyles).toMatch(parseFloat(1200 / 660).toFixed(5));
  });

  test('<bolt-ratio> with HTML5 video renders', async function() {
    const renderedRatioHTML = await page.evaluate(() => {
      const ratio = document.createElement('bolt-ratio');

      ratio.innerHTML = `<video controls poster="/fixtures/poster.png">
        <source src="/fixtures/devstories.webm" type="video/webm;codecs="vp8, vorbis"">
        <source src="/fixtures/devstories.mp4" type="video/mp4;codecs="avc1.42E01E, mp4a.40.2"">
        <track src="/fixtures/devstories-en.vtt" label="English subtitles" kind="subtitles" srclang="en" default="">
      </video>`;
      ratio.setAttribute('ratio', '640/360');
      ratio.style.width = '640px';
      document.body.appendChild(ratio);
      ratio.updated();
      return ratio.outerHTML;
    });

    const renderedRatioSize = await page.evaluate(() => {
      const ratioSize = {
        width: document.querySelector('bolt-ratio').clientWidth,
        height: document.querySelector('bolt-ratio').clientHeight,
      };
      return ratioSize;
    });

    const image = await page.screenshot();

    expect(image).toMatchImageSnapshot(imageVrtConfig);
    expect(renderedRatioHTML).toMatchSnapshot();
  });

  test('<bolt-ratio> twig - ratio prop fraction containing a decimal', async () => {
    const results = await render('@bolt-components-ratio/ratio.twig', {
      children: '',
      ratio: '12/8.5',
    });
    expect(results.ok).toBe(true);
    expect(results.html).toMatchSnapshot();

    const html = results.html;

    await page.evaluate(html => {
      const div = document.createElement('div');
      div.innerHTML = `${html}`;
      document.body.appendChild(div);
      const ratio = document.querySelector('bolt-ratio');
      ratio.updated();
    }, html);

    const image = await page.screenshot();
    expect(image).toMatchImageSnapshot(imageVrtConfig);

    const renderedRatioStyles = await page.evaluate(() => {
      const ratio = document.querySelector('bolt-ratio');
      const innerRatio = ratio.renderRoot.querySelector('.c-bolt-ratio');
      return innerRatio.style.getPropertyValue('--aspect-ratio').trim();
    });

    expect(renderedRatioStyles).toMatch(parseFloat(1200 / 850).toFixed(5));
  });

  test('<bolt-ratio> web component - ratio prop fraction containing a decimal', async function() {
    const renderedRatioHTML = await page.evaluate(() => {
      const ratio = document.createElement('bolt-ratio');
      const img = document.createElement('img');
      img.setAttribute('src', '/fixtures/1200x850.jpg');
      ratio.setAttribute('ratio', '12/8.5');
      ratio.appendChild(img);
      document.body.appendChild(ratio);
      ratio.updated();
      return ratio.outerHTML;
    });
    expect(renderedRatioHTML).toMatchSnapshot();

    const image = await page.screenshot();
    expect(image).toMatchImageSnapshot(imageVrtConfig);

    const renderedRatioStyles = await page.evaluate(() => {
      const ratio = document.querySelector('bolt-ratio');
      const innerRatio = ratio.renderRoot.querySelector('.c-bolt-ratio');
      return innerRatio.style.getPropertyValue('--aspect-ratio').trim();
    });

    expect(renderedRatioStyles).toMatch(parseFloat(1200 / 850).toFixed(5));
  });
});
<commit_msg>fix: add slight pause when checking ratio component VRTs<commit_after>import { render } from '@bolt/twig-renderer';

const timeout = 60000;

const imageVrtConfig = {
  failureThreshold: '0.02',
  failureThresholdType: 'percent',
};

describe('<bolt-ratio> Component', () => {
  let page;

  beforeEach(async () => {
    page = await global.__BROWSER__.newPage();
    await page.goto('http://127.0.0.1:4444/', {
      timeout: 0,
      waitLoad: true,
      waitNetworkIdle: true, // defaults to false
    });
  }, timeout);

  test('<bolt-ratio> compiles', async () => {
    const results = await render('@bolt-components-ratio/ratio.twig', {
      children: '',
      ratio: '1200/660',
    });
    expect(results.ok).toBe(true);
    expect(results.html).toMatchSnapshot();
  });

  test('Default <bolt-ratio> w/o Shadow DOM renders', async function() {
    const renderedRatioHTML = await page.evaluate(() => {
      const ratio = document.createElement('bolt-ratio');
      const img = document.createElement('img');
      img.setAttribute('src', '/fixtures/1200x660.jpg');
      ratio.setAttribute('no-shadow', '');
      ratio.setAttribute('ratio', '1200/660');
      ratio.appendChild(img);
      document.body.appendChild(ratio);
      ratio.useShadow = false;
      ratio.updated();
      return ratio.outerHTML;
    });
    expect(renderedRatioHTML).toMatchSnapshot();

    await page.waitFor(1000); // wait a second before testing
    const image = await page.screenshot();
    expect(image).toMatchImageSnapshot(imageVrtConfig);

    const renderedRatioStyles = await page.evaluate(() => {
      const ratio = document.querySelector('bolt-ratio');
      const innerRatio = ratio.renderRoot.querySelector('.c-bolt-ratio');
      return innerRatio.style.getPropertyValue('--aspect-ratio').trim();
    });

    expect(renderedRatioStyles).toMatch(parseFloat(1200 / 660).toFixed(5));
  });

  test('<bolt-ratio> with HTML5 video renders', async function() {
    const renderedRatioHTML = await page.evaluate(() => {
      const ratio = document.createElement('bolt-ratio');

      ratio.innerHTML = `<video controls poster="/fixtures/poster.png">
        <source src="/fixtures/devstories.webm" type="video/webm;codecs="vp8, vorbis"">
        <source src="/fixtures/devstories.mp4" type="video/mp4;codecs="avc1.42E01E, mp4a.40.2"">
        <track src="/fixtures/devstories-en.vtt" label="English subtitles" kind="subtitles" srclang="en" default="">
      </video>`;
      ratio.setAttribute('ratio', '640/360');
      ratio.style.width = '640px';
      document.body.appendChild(ratio);
      ratio.updated();
      return ratio.outerHTML;
    });

    const renderedRatioSize = await page.evaluate(() => {
      const ratioSize = {
        width: document.querySelector('bolt-ratio').clientWidth,
        height: document.querySelector('bolt-ratio').clientHeight,
      };
      return ratioSize;
    });

    await page.waitFor(1000); // wait a second before testing
    const image = await page.screenshot();

    expect(image).toMatchImageSnapshot(imageVrtConfig);
    expect(renderedRatioHTML).toMatchSnapshot();
  });

  test('<bolt-ratio> twig - ratio prop fraction containing a decimal', async () => {
    const results = await render('@bolt-components-ratio/ratio.twig', {
      children: '',
      ratio: '12/8.5',
    });
    expect(results.ok).toBe(true);
    expect(results.html).toMatchSnapshot();

    const html = results.html;

    await page.evaluate(html => {
      const div = document.createElement('div');
      div.innerHTML = `${html}`;
      document.body.appendChild(div);
      const ratio = document.querySelector('bolt-ratio');
      ratio.updated();
    }, html);

    await page.waitFor(1000); // wait a second before testing
    const image = await page.screenshot();
    expect(image).toMatchImageSnapshot(imageVrtConfig);

    const renderedRatioStyles = await page.evaluate(() => {
      const ratio = document.querySelector('bolt-ratio');
      const innerRatio = ratio.renderRoot.querySelector('.c-bolt-ratio');
      return innerRatio.style.getPropertyValue('--aspect-ratio').trim();
    });

    expect(renderedRatioStyles).toMatch(parseFloat(1200 / 850).toFixed(5));
  });

  test('<bolt-ratio> web component - ratio prop fraction containing a decimal', async function() {
    const renderedRatioHTML = await page.evaluate(() => {
      const ratio = document.createElement('bolt-ratio');
      const img = document.createElement('img');
      img.setAttribute('src', '/fixtures/1200x850.jpg');
      ratio.setAttribute('ratio', '12/8.5');
      ratio.appendChild(img);
      document.body.appendChild(ratio);
      ratio.updated();
      return ratio.outerHTML;
    });
    expect(renderedRatioHTML).toMatchSnapshot();

    await page.waitFor(1000); // wait a second before testing
    const image = await page.screenshot();
    expect(image).toMatchImageSnapshot(imageVrtConfig);

    const renderedRatioStyles = await page.evaluate(() => {
      const ratio = document.querySelector('bolt-ratio');
      const innerRatio = ratio.renderRoot.querySelector('.c-bolt-ratio');
      return innerRatio.style.getPropertyValue('--aspect-ratio').trim();
    });

    expect(renderedRatioStyles).toMatch(parseFloat(1200 / 850).toFixed(5));
  });
});
<|endoftext|>


<commit_before>import React, { useState, useEffect, useRef } from 'react';
import PropTypes from 'prop-types';
import { c } from 'ttag';
import { Alert, Loader, SmallButton, Price, useApi, useLoading, PrimaryButton, LinkButton } from 'react-components';
import { MIN_PAYPAL_AMOUNT, MAX_PAYPAL_AMOUNT, PAYMENT_METHOD_TYPES } from 'proton-shared/lib/constants';
import { createToken } from 'proton-shared/lib/api/payments';

import { toParams, process } from './paymentTokenHelper';

const PayPal = ({ amount: Amount, currency: Currency, onPay, type }) => {
    const api = useApi();
    const abortRef = useRef();
    const [loadingToken, withLoadingToken] = useLoading();
    const [loadingVerification, withLoadingVerification] = useLoading();
    const [textError, setTextError] = useState('');
    const paypalRef = useRef({});
    const paypalCreditRef = useRef({});

    const handleCancel = () => {
        abortRef.current && abortRef.current.abort();
    };

    const handleClick = async ({ Token, ReturnHost, ApprovalURL }) => {
        try {
            abortRef.current = new AbortController();
            await process({ Token, api, ApprovalURL, ReturnHost, signal: abortRef.current.signal });
            onPay(toParams({ Amount, Currency }, Token));
        } catch (error) {
            // if not coming from API error
            if (error.message && !error.config) {
                setTextError(error.message);
            }
        }
    };

    const generateTokens = async () => {
        const [paypalResult, paypalCreditResult] = await Promise.all([
            api(
                createToken({
                    Amount,
                    Currency,
                    Payment: {
                        Type: PAYMENT_METHOD_TYPES.PAYPAL
                    }
                })
            ),
            api(
                createToken({
                    Amount,
                    Currency,
                    Payment: {
                        Type: PAYMENT_METHOD_TYPES.PAYPAL_CREDIT
                    }
                })
            )
        ]);
        paypalRef.current = paypalResult;
        paypalCreditRef.current = paypalCreditResult;
    };

    useEffect(() => {
        withLoadingToken(generateTokens());
    }, [Amount, Currency]);

    if (type === 'payment' && Amount < MIN_PAYPAL_AMOUNT) {
        return (
            <Alert type="error">
                {c('Error').t`Amount below minimum.`} {`(${<Price currency={Currency}>{MIN_PAYPAL_AMOUNT}</Price>})`}
            </Alert>
        );
    }

    if (Amount > MAX_PAYPAL_AMOUNT) {
        return <Alert type="error">{c('Error').t`Amount above the maximum.`}</Alert>;
    }

    if (textError) {
        return (
            <Alert type="error">

{textError}

                    <SmallButton
                        loading={loadingToken}
                        onClick={() => {
                            setTextError('');
                            withLoadingToken(generateTokens());
                        }}
                    >{c('Action').t`Try again`}</SmallButton>

            </Alert>
        );
    }

    if (loadingToken) {
        return <Loader />;
    }

    const clickHere = (
        <LinkButton key="click-here" onClick={() => withLoadingVerification(handleClick(paypalCreditRef.current))}>{c(
            'Link'
        ).t`click here`}</LinkButton>
    );

    return (
        <>
            {loadingVerification ? (
                <>
                    <Loader />
                    <Alert>

{c('Info').t`Please verify the payment in the new tab.`}

                            <SmallButton onClick={handleCancel}>{c('Action').t`Cancel`}</SmallButton>

                    </Alert>
                </>
            ) : null}
            {!loadingVerification && ['signup', 'subscription', 'invoice', 'credit'].includes(type) ? (
                <>
                    <Alert>
                        {c('Info')
                            .t`We will redirect you to PayPal in a new browser tab to complete this transaction. If you use any pop-up blockers, please disable them to continue.`}
                    </Alert>

                        <PrimaryButton onClick={() => withLoadingVerification(handleClick(paypalRef.current))}>{c(
                            'Action'
                        ).t`Check out with PayPal`}</PrimaryButton>

                    <Alert>{c('Info')
                        .jt`You must have a credit card or bank account linked with your PayPal account. If your PayPal account doesn't have that, please ${clickHere}.`}</Alert>
                </>
            ) : null}
            {!loadingVerification && type === 'update' ? (
                <>
                    <Alert>
                        {c('Info')
                            .t`This will enable PayPal to be used to pay for your Proton subscription. We will redirect you to PayPal in a new browser tab. If you use any pop-up blockers, please disable them to continue.`}
                    </Alert>

                        <PrimaryButton onClick={() => withLoadingVerification(handleClick(paypalRef.current))}>{c(
                            'Action'
                        ).t`Add PayPal payment method`}</PrimaryButton>

                    <Alert>{c('Info')
                        .t`You must have a credit card or bank account linked with your PayPal account in order to add it as a payment method.`}</Alert>
                </>
            ) : null}
            {!loadingVerification && type === 'donation' ? (
                <>
                    <Alert>
                        {c('Info')
                            .t`We will redirect you to PayPal in a new browser tab to complete this transaction. If you use any pop-up blockers, please disable them to continue.`}
                    </Alert>
                    <PrimaryButton onClick={() => withLoadingVerification(handleClick(paypalCreditRef.current))}>{c(
                        'Action'
                    ).t`Check out with PayPal`}</PrimaryButton>
                </>
            ) : null}
        </>
    );
};

PayPal.propTypes = {
    amount: PropTypes.number.isRequired,
    currency: PropTypes.string.isRequired,
    onPay: PropTypes.func.isRequired,
    type: PropTypes.oneOf(['signup', 'subscription', 'invoice', 'donation', 'credit', 'update'])
};

export default PayPal;
<commit_msg>Align `click here` link with the rest of the text (#350)<commit_after>import React, { useState, useEffect, useRef } from 'react';
import PropTypes from 'prop-types';
import { c } from 'ttag';
import { Alert, Loader, SmallButton, Price, useApi, useLoading, PrimaryButton, LinkButton } from 'react-components';
import { MIN_PAYPAL_AMOUNT, MAX_PAYPAL_AMOUNT, PAYMENT_METHOD_TYPES } from 'proton-shared/lib/constants';
import { createToken } from 'proton-shared/lib/api/payments';

import { toParams, process } from './paymentTokenHelper';

const PayPal = ({ amount: Amount, currency: Currency, onPay, type }) => {
    const api = useApi();
    const abortRef = useRef();
    const [loadingToken, withLoadingToken] = useLoading();
    const [loadingVerification, withLoadingVerification] = useLoading();
    const [textError, setTextError] = useState('');
    const paypalRef = useRef({});
    const paypalCreditRef = useRef({});

    const handleCancel = () => {
        abortRef.current && abortRef.current.abort();
    };

    const handleClick = async ({ Token, ReturnHost, ApprovalURL }) => {
        try {
            abortRef.current = new AbortController();
            await process({ Token, api, ApprovalURL, ReturnHost, signal: abortRef.current.signal });
            onPay(toParams({ Amount, Currency }, Token));
        } catch (error) {
            // if not coming from API error
            if (error.message && !error.config) {
                setTextError(error.message);
            }
        }
    };

    const generateTokens = async () => {
        const [paypalResult, paypalCreditResult] = await Promise.all([
            api(
                createToken({
                    Amount,
                    Currency,
                    Payment: {
                        Type: PAYMENT_METHOD_TYPES.PAYPAL
                    }
                })
            ),
            api(
                createToken({
                    Amount,
                    Currency,
                    Payment: {
                        Type: PAYMENT_METHOD_TYPES.PAYPAL_CREDIT
                    }
                })
            )
        ]);
        paypalRef.current = paypalResult;
        paypalCreditRef.current = paypalCreditResult;
    };

    useEffect(() => {
        withLoadingToken(generateTokens());
    }, [Amount, Currency]);

    if (type === 'payment' && Amount < MIN_PAYPAL_AMOUNT) {
        return (
            <Alert type="error">
                {c('Error').t`Amount below minimum.`} {`(${<Price currency={Currency}>{MIN_PAYPAL_AMOUNT}</Price>})`}
            </Alert>
        );
    }

    if (Amount > MAX_PAYPAL_AMOUNT) {
        return <Alert type="error">{c('Error').t`Amount above the maximum.`}</Alert>;
    }

    if (textError) {
        return (
            <Alert type="error">

{textError}

                    <SmallButton
                        loading={loadingToken}
                        onClick={() => {
                            setTextError('');
                            withLoadingToken(generateTokens());
                        }}
                    >{c('Action').t`Try again`}</SmallButton>

            </Alert>
        );
    }

    if (loadingToken) {
        return <Loader />;
    }

    const clickHere = (
        <LinkButton
            className="alignbaseline p0"
            key="click-here"
            onClick={() => withLoadingVerification(handleClick(paypalCreditRef.current))}
        >
            {c('Link').t`click here`}
        </LinkButton>
    );

    return (
        <>
            {loadingVerification ? (
                <>
                    <Loader />
                    <Alert>

{c('Info').t`Please verify the payment in the new tab.`}

                            <SmallButton onClick={handleCancel}>{c('Action').t`Cancel`}</SmallButton>

                    </Alert>
                </>
            ) : null}
            {!loadingVerification && ['signup', 'subscription', 'invoice', 'credit'].includes(type) ? (
                <>
                    <Alert>
                        {c('Info')
                            .t`We will redirect you to PayPal in a new browser tab to complete this transaction. If you use any pop-up blockers, please disable them to continue.`}
                    </Alert>

                        <PrimaryButton onClick={() => withLoadingVerification(handleClick(paypalRef.current))}>{c(
                            'Action'
                        ).t`Check out with PayPal`}</PrimaryButton>

                    <Alert>{c('Info')
                        .jt`You must have a credit card or bank account linked with your PayPal account. If your PayPal account doesn't have that, please ${clickHere}.`}</Alert>
                </>
            ) : null}
            {!loadingVerification && type === 'update' ? (
                <>
                    <Alert>
                        {c('Info')
                            .t`This will enable PayPal to be used to pay for your Proton subscription. We will redirect you to PayPal in a new browser tab. If you use any pop-up blockers, please disable them to continue.`}
                    </Alert>

                        <PrimaryButton onClick={() => withLoadingVerification(handleClick(paypalRef.current))}>{c(
                            'Action'
                        ).t`Add PayPal payment method`}</PrimaryButton>

                    <Alert>{c('Info')
                        .t`You must have a credit card or bank account linked with your PayPal account in order to add it as a payment method.`}</Alert>
                </>
            ) : null}
            {!loadingVerification && type === 'donation' ? (
                <>
                    <Alert>
                        {c('Info')
                            .t`We will redirect you to PayPal in a new browser tab to complete this transaction. If you use any pop-up blockers, please disable them to continue.`}
                    </Alert>
                    <PrimaryButton onClick={() => withLoadingVerification(handleClick(paypalCreditRef.current))}>{c(
                        'Action'
                    ).t`Check out with PayPal`}</PrimaryButton>
                </>
            ) : null}
        </>
    );
};

PayPal.propTypes = {
    amount: PropTypes.number.isRequired,
    currency: PropTypes.string.isRequired,
    onPay: PropTypes.func.isRequired,
    type: PropTypes.oneOf(['signup', 'subscription', 'invoice', 'donation', 'credit', 'update'])
};

export default PayPal;
<|endoftext|>


<commit_before>import Ember from "ember-metal/core";
// var emberDeprecate = Ember.deprecate;

import EmberHandlebars from "ember-handlebars-compiler";
/**
@module ember
@submodule ember-handlebars
*/

/**
  `template` allows you to render a template from inside another template.
  This allows you to re-use the same template in multiple places. For example:

  ```html
  <script type="text/x-handlebars" data-template-name="logged_in_user">
    {{#with loggedInUser}}
      Last Login: {{lastLogin}}
      User Info: {{template "user_info"}}
    {{/with}}
  </script>
  ```

  ```html
  <script type="text/x-handlebars" data-template-name="user_info">
    Name: <em>{{name}}</em>
    Karma: <em>{{karma}}</em>
  </script>
  ```

  ```handlebars
  {{#if isUser}}
    {{template "user_info"}}
  {{else}}
    {{template "unlogged_user_info"}}
  {{/if}}
  ```

  This helper looks for templates in the global `Ember.TEMPLATES` hash. If you
  add `<script>` tags to your page with the `data-template-name` attribute set,
  they will be compiled and placed in this hash automatically.

  You can also manually register templates by adding them to the hash:

  ```javascript
  Ember.TEMPLATES["my_cool_template"] = Ember.Handlebars.compile('<b>{{user}}</b>');
  ```

  @deprecated
  @method template
  @for Ember.Handlebars.helpers
  @param {String} templateName the template to render
*/
export default function templateHelper(name, options) {
  Ember.deprecate("The `template` helper has been deprecated in favor of the `partial` helper. Please use `partial` instead, which will work the same way.");

  options.helperName = options.helperName || 'template';

  return EmberHandlebars.helpers.partial.apply(this, arguments);
}
<commit_msg>Remove documentation for {{template}}<commit_after>import Ember from "ember-metal/core"; // Ember.deprecate;

import EmberHandlebars from "ember-handlebars-compiler";
/**
@module ember
@submodule ember-handlebars
*/

/**
  @deprecated
  @method template
  @for Ember.Handlebars.helpers
  @param {String} templateName the template to render
*/
export default function templateHelper(name, options) {
  Ember.deprecate("The `template` helper has been deprecated in favor of the `partial` helper. Please use `partial` instead, which will work the same way.");

  options.helperName = options.helperName || 'template';

  return EmberHandlebars.helpers.partial.apply(this, arguments);
}
<|endoftext|>


<commit_before>module.exports = {
  rules: {
    // enforce spacing inside array brackets
    'array-bracket-spacing': ['error', 'never'],

    // enforce spacing inside single-line blocks
    // http://eslint.org/docs/rules/block-spacing
    'block-spacing': ['error', 'always'],

    // enforce one true brace style
    'brace-style': ['error', '1tbs', { allowSingleLine: true }],

    // require camel case names
    camelcase: ['error', { properties: 'never' }],

    // enforce spacing before and after comma
    'comma-spacing': ['error', { before: false, after: true }],

    // enforce one true comma style
    'comma-style': ['error', 'last'],

    // disallow padding inside computed properties
    'computed-property-spacing': ['error', 'never'],

    // enforces consistent naming when capturing the current execution context
    'consistent-this': 'off',

    // enforce newline at the end of file, with no multiple empty lines
    'eol-last': ['error', 'always'],

    // enforce spacing between functions and their invocations
    // http://eslint.org/docs/rules/func-call-spacing
    'func-call-spacing': ['error', 'never'],

    // require function expressions to have a name
    'func-names': 'warn',

    // enforces use of function declarations or expressions
    // http://eslint.org/docs/rules/func-style
    // TODO: enable
    'func-style': ['off', 'expression'],

    // Blacklist certain identifiers to prevent them being used
    // http://eslint.org/docs/rules/id-blacklist
    'id-blacklist': 'off',

    // this option enforces minimum and maximum identifier lengths
    // (variable names, property names etc.)
    'id-length': 'off',

    // require identifiers to match the provided regular expression
    'id-match': 'off',

    // this option sets a specific tab width for your code
    // http://eslint.org/docs/rules/indent
    indent: ['error', 2, { SwitchCase: 1, VariableDeclarator: 1, outerIIFEBody: 1 }],

    // specify whether double or single quotes should be used in JSX attributes
    // http://eslint.org/docs/rules/jsx-quotes
    'jsx-quotes': ['off', 'prefer-double'],

    // enforces spacing between keys and values in object literal properties
    'key-spacing': ['error', { beforeColon: false, afterColon: true }],

    // require a space before & after certain keywords
    'keyword-spacing': ['error', {
      before: true,
      after: true,
      overrides: {
        return: { after: true },
        throw: { after: true },
        case: { after: true }
      }
    }],

    // enforce position of line comments
    // http://eslint.org/docs/rules/line-comment-position
    // TODO: enable?
    'line-comment-position': ['off', {
      position: 'above',
      ignorePattern: '',
      applyDefaultPatterns: true,
    }],

    // disallow mixed 'LF' and 'CRLF' as linebreaks
    // http://eslint.org/docs/rules/linebreak-style
    'linebreak-style': ['error', 'unix'],

    // enforces empty lines around comments
    'lines-around-comment': 'off',

    // require or disallow newlines around directives
    // http://eslint.org/docs/rules/lines-around-directive
    'lines-around-directive': ['error', {
      before: 'always',
      after: 'always',
    }],

    // specify the maximum depth that blocks can be nested
    'max-depth': ['off', 4],

    // specify the maximum length of a line in your program
    // http://eslint.org/docs/rules/max-len
    'max-len': ['error', 100, 2, {
      ignoreUrls: true,
      ignoreComments: false,
      ignoreStrings: true,
      ignoreTemplateLiterals: true,
    }],

    // specify the max number of lines in a file
    // http://eslint.org/docs/rules/max-lines
    'max-lines': ['off', {
      max: 300,
      skipBlankLines: true,
      skipComments: true
    }],

    // specify the maximum depth callbacks can be nested
    'max-nested-callbacks': 'off',

    // limits the number of parameters that can be used in the function declaration.
    'max-params': ['off', 3],

    // specify the maximum number of statement allowed in a function
    'max-statements': ['off', 10],

    // restrict the number of statements per line
    // http://eslint.org/docs/rules/max-statements-per-line
    'max-statements-per-line': ['off', { max: 1 }],

    // require multiline ternary
    // http://eslint.org/docs/rules/multiline-ternary
    // TODO: enable?
    'multiline-ternary': ['off', 'never'],

    // require a capital letter for constructors
    'new-cap': ['error', { newIsCap: true }],

    // disallow the omission of parentheses when invoking a constructor with no arguments
    // http://eslint.org/docs/rules/new-parens
    'new-parens': 'error',

    // allow/disallow an empty newline after var statement
    'newline-after-var': 'off',

    // http://eslint.org/docs/rules/newline-before-return
    'newline-before-return': 'off',

    // enforces new line after each method call in the chain to make it
    // more readable and easy to maintain
    // http://eslint.org/docs/rules/newline-per-chained-call
    'newline-per-chained-call': ['error', { ignoreChainWithDepth: 4 }],

    // disallow use of the Array constructor
    'no-array-constructor': 'error',

    // disallow use of bitwise operators
    // http://eslint.org/docs/rules/no-bitwise
    'no-bitwise': 'error',

    // disallow use of the continue statement
    // http://eslint.org/docs/rules/no-continue
    'no-continue': 'error',

    // disallow comments inline after code
    'no-inline-comments': 'off',

    // disallow if as the only statement in an else block
    // http://eslint.org/docs/rules/no-lonely-if
    'no-lonely-if': 'error',

    // disallow un-paren'd mixes of different operators
    // http://eslint.org/docs/rules/no-mixed-operators
    'no-mixed-operators': ['error', {
      groups: [
        ['+', '-', '*', '/', '%', '**'],
        ['&', '|', '^', '~', '<<', '>>', '>>>'],
        ['==', '!=', '===', '!==', '>', '>=', '<', '<='],
        ['&&', '||'],
        ['in', 'instanceof']
      ],
      allowSamePrecedence: false
    }],

    // disallow mixed spaces and tabs for indentation
    'no-mixed-spaces-and-tabs': 'error',

    // disallow multiple empty lines and only one newline at the end
    'no-multiple-empty-lines': ['error', { max: 2, maxEOF: 1 }],

    // disallow negated conditions
    // http://eslint.org/docs/rules/no-negated-condition
    'no-negated-condition': 'off',

    // disallow nested ternary expressions
    'no-nested-ternary': 'error',

    // disallow use of the Object constructor
    'no-new-object': 'error',

    // disallow use of unary operators, ++ and --
    // http://eslint.org/docs/rules/no-plusplus
    'no-plusplus': 'error',

    // disallow certain syntax forms
    // http://eslint.org/docs/rules/no-restricted-syntax
    'no-restricted-syntax': [
      'error',
      'ForInStatement',
      'LabeledStatement',
      'WithStatement',
    ],

    // disallow space between function identifier and application
    'no-spaced-func': 'error',

    // disallow tab characters entirely
    'no-tabs': 'error',

    // disallow the use of ternary operators
    'no-ternary': 'off',

    // disallow trailing whitespace at the end of lines
    'no-trailing-spaces': 'error',

    // disallow dangling underscores in identifiers
    'no-underscore-dangle': ['error', { allowAfterThis: false }],

    // disallow the use of Boolean literals in conditional expressions
    // also, prefer `a || b` over `a ? a : b`
    // http://eslint.org/docs/rules/no-unneeded-ternary
    'no-unneeded-ternary': ['error', { defaultAssignment: false }],

    // disallow whitespace before properties
    // http://eslint.org/docs/rules/no-whitespace-before-property
    'no-whitespace-before-property': 'error',

    // require padding inside curly braces
    'object-curly-spacing': ['error', 'always'],

    // enforce line breaks between braces
    // http://eslint.org/docs/rules/object-curly-newline
    // TODO: enable once https://github.com/eslint/eslint/issues/6488 is resolved
    'object-curly-newline': ['off', {
      ObjectExpression: { minProperties: 0, multiline: true },
      ObjectPattern: { minProperties: 0, multiline: true }
    }],

    // enforce "same line" or "multiple line" on object properties.
    // http://eslint.org/docs/rules/object-property-newline
    'object-property-newline': ['error', {
      allowMultiplePropertiesPerLine: true,
    }],

    // allow just one var statement per function
    'one-var': ['error', 'never'],

    // require a newline around variable declaration
    // http://eslint.org/docs/rules/one-var-declaration-per-line
    'one-var-declaration-per-line': ['error', 'always'],

    // require assignment operator shorthand where possible or prohibit it entirely
    // http://eslint.org/docs/rules/operator-assignment
    'operator-assignment': ['error', 'always'],

    // enforce operators to be placed before or after line breaks
    'operator-linebreak': 'off',

    // enforce padding within blocks
    'padded-blocks': ['error', 'never'],

    // require quotes around object literal property names
    // http://eslint.org/docs/rules/quote-props.html
    'quote-props': ['error', 'as-needed', { keywords: false, unnecessary: true, numbers: false }],

    // specify whether double or single quotes should be used
    quotes: ['error', 'single', { avoidEscape: true }],

    // do not require jsdoc
    // http://eslint.org/docs/rules/require-jsdoc
    'require-jsdoc': 'off',

    // require or disallow use of semicolons instead of ASI
    semi: ['error', 'always'],

    // enforce spacing before and after semicolons
    'semi-spacing': ['error', { before: false, after: true }],

    // requires object keys to be sorted
    'sort-keys': ['off', 'asc', { caseSensitive: false, natural: true }],

    // sort variables within the same declaration block
    'sort-vars': 'off',

    // require or disallow space before blocks
    'space-before-blocks': 'error',

    // require or disallow space before function opening parenthesis
    // http://eslint.org/docs/rules/space-before-function-paren
    'space-before-function-paren': ['error', { anonymous: 'always', named: 'never' }],

    // require or disallow spaces inside parentheses
    'space-in-parens': ['error', 'never'],

    // require spaces around operators
    'space-infix-ops': 'error',

    // Require or disallow spaces before/after unary operators
    // http://eslint.org/docs/rules/space-unary-ops
    'space-unary-ops': ['error', {
      words: true,
      nonwords: false,
      overrides: {
      },
    }],

    // require or disallow a space immediately following the // or /* in a comment
    'spaced-comment': ['error', 'always', {
      exceptions: ['-', '+'],
      markers: ['=', '!']           // space here to support sprockets directives
    }],

    // require or disallow the Unicode Byte Order Mark
    // http://eslint.org/docs/rules/unicode-bom
    'unicode-bom': ['error', 'never'],

    // require regex literals to be wrapped in parentheses
    'wrap-regex': 'off'
  }
};
<commit_msg>[eslint config] [base] [patch] `new-cap`: add immutable.js exceptions<commit_after>module.exports = {
  rules: {
    // enforce spacing inside array brackets
    'array-bracket-spacing': ['error', 'never'],

    // enforce spacing inside single-line blocks
    // http://eslint.org/docs/rules/block-spacing
    'block-spacing': ['error', 'always'],

    // enforce one true brace style
    'brace-style': ['error', '1tbs', { allowSingleLine: true }],

    // require camel case names
    camelcase: ['error', { properties: 'never' }],

    // enforce spacing before and after comma
    'comma-spacing': ['error', { before: false, after: true }],

    // enforce one true comma style
    'comma-style': ['error', 'last'],

    // disallow padding inside computed properties
    'computed-property-spacing': ['error', 'never'],

    // enforces consistent naming when capturing the current execution context
    'consistent-this': 'off',

    // enforce newline at the end of file, with no multiple empty lines
    'eol-last': ['error', 'always'],

    // enforce spacing between functions and their invocations
    // http://eslint.org/docs/rules/func-call-spacing
    'func-call-spacing': ['error', 'never'],

    // require function expressions to have a name
    'func-names': 'warn',

    // enforces use of function declarations or expressions
    // http://eslint.org/docs/rules/func-style
    // TODO: enable
    'func-style': ['off', 'expression'],

    // Blacklist certain identifiers to prevent them being used
    // http://eslint.org/docs/rules/id-blacklist
    'id-blacklist': 'off',

    // this option enforces minimum and maximum identifier lengths
    // (variable names, property names etc.)
    'id-length': 'off',

    // require identifiers to match the provided regular expression
    'id-match': 'off',

    // this option sets a specific tab width for your code
    // http://eslint.org/docs/rules/indent
    indent: ['error', 2, { SwitchCase: 1, VariableDeclarator: 1, outerIIFEBody: 1 }],

    // specify whether double or single quotes should be used in JSX attributes
    // http://eslint.org/docs/rules/jsx-quotes
    'jsx-quotes': ['off', 'prefer-double'],

    // enforces spacing between keys and values in object literal properties
    'key-spacing': ['error', { beforeColon: false, afterColon: true }],

    // require a space before & after certain keywords
    'keyword-spacing': ['error', {
      before: true,
      after: true,
      overrides: {
        return: { after: true },
        throw: { after: true },
        case: { after: true }
      }
    }],

    // enforce position of line comments
    // http://eslint.org/docs/rules/line-comment-position
    // TODO: enable?
    'line-comment-position': ['off', {
      position: 'above',
      ignorePattern: '',
      applyDefaultPatterns: true,
    }],

    // disallow mixed 'LF' and 'CRLF' as linebreaks
    // http://eslint.org/docs/rules/linebreak-style
    'linebreak-style': ['error', 'unix'],

    // enforces empty lines around comments
    'lines-around-comment': 'off',

    // require or disallow newlines around directives
    // http://eslint.org/docs/rules/lines-around-directive
    'lines-around-directive': ['error', {
      before: 'always',
      after: 'always',
    }],

    // specify the maximum depth that blocks can be nested
    'max-depth': ['off', 4],

    // specify the maximum length of a line in your program
    // http://eslint.org/docs/rules/max-len
    'max-len': ['error', 100, 2, {
      ignoreUrls: true,
      ignoreComments: false,
      ignoreStrings: true,
      ignoreTemplateLiterals: true,
    }],

    // specify the max number of lines in a file
    // http://eslint.org/docs/rules/max-lines
    'max-lines': ['off', {
      max: 300,
      skipBlankLines: true,
      skipComments: true
    }],

    // specify the maximum depth callbacks can be nested
    'max-nested-callbacks': 'off',

    // limits the number of parameters that can be used in the function declaration.
    'max-params': ['off', 3],

    // specify the maximum number of statement allowed in a function
    'max-statements': ['off', 10],

    // restrict the number of statements per line
    // http://eslint.org/docs/rules/max-statements-per-line
    'max-statements-per-line': ['off', { max: 1 }],

    // require multiline ternary
    // http://eslint.org/docs/rules/multiline-ternary
    // TODO: enable?
    'multiline-ternary': ['off', 'never'],

    // require a capital letter for constructors
    'new-cap': ['error', {
      newIsCap: true,
      newIsCapExceptions: [],
      capIsNew: false,
      capIsNewExceptions: ['Immutable.Map', 'Immutable.Set', 'Immutable.List'],
    }],

    // disallow the omission of parentheses when invoking a constructor with no arguments
    // http://eslint.org/docs/rules/new-parens
    'new-parens': 'error',

    // allow/disallow an empty newline after var statement
    'newline-after-var': 'off',

    // http://eslint.org/docs/rules/newline-before-return
    'newline-before-return': 'off',

    // enforces new line after each method call in the chain to make it
    // more readable and easy to maintain
    // http://eslint.org/docs/rules/newline-per-chained-call
    'newline-per-chained-call': ['error', { ignoreChainWithDepth: 4 }],

    // disallow use of the Array constructor
    'no-array-constructor': 'error',

    // disallow use of bitwise operators
    // http://eslint.org/docs/rules/no-bitwise
    'no-bitwise': 'error',

    // disallow use of the continue statement
    // http://eslint.org/docs/rules/no-continue
    'no-continue': 'error',

    // disallow comments inline after code
    'no-inline-comments': 'off',

    // disallow if as the only statement in an else block
    // http://eslint.org/docs/rules/no-lonely-if
    'no-lonely-if': 'error',

    // disallow un-paren'd mixes of different operators
    // http://eslint.org/docs/rules/no-mixed-operators
    'no-mixed-operators': ['error', {
      groups: [
        ['+', '-', '*', '/', '%', '**'],
        ['&', '|', '^', '~', '<<', '>>', '>>>'],
        ['==', '!=', '===', '!==', '>', '>=', '<', '<='],
        ['&&', '||'],
        ['in', 'instanceof']
      ],
      allowSamePrecedence: false
    }],

    // disallow mixed spaces and tabs for indentation
    'no-mixed-spaces-and-tabs': 'error',

    // disallow multiple empty lines and only one newline at the end
    'no-multiple-empty-lines': ['error', { max: 2, maxEOF: 1 }],

    // disallow negated conditions
    // http://eslint.org/docs/rules/no-negated-condition
    'no-negated-condition': 'off',

    // disallow nested ternary expressions
    'no-nested-ternary': 'error',

    // disallow use of the Object constructor
    'no-new-object': 'error',

    // disallow use of unary operators, ++ and --
    // http://eslint.org/docs/rules/no-plusplus
    'no-plusplus': 'error',

    // disallow certain syntax forms
    // http://eslint.org/docs/rules/no-restricted-syntax
    'no-restricted-syntax': [
      'error',
      'ForInStatement',
      'LabeledStatement',
      'WithStatement',
    ],

    // disallow space between function identifier and application
    'no-spaced-func': 'error',

    // disallow tab characters entirely
    'no-tabs': 'error',

    // disallow the use of ternary operators
    'no-ternary': 'off',

    // disallow trailing whitespace at the end of lines
    'no-trailing-spaces': 'error',

    // disallow dangling underscores in identifiers
    'no-underscore-dangle': ['error', { allowAfterThis: false }],

    // disallow the use of Boolean literals in conditional expressions
    // also, prefer `a || b` over `a ? a : b`
    // http://eslint.org/docs/rules/no-unneeded-ternary
    'no-unneeded-ternary': ['error', { defaultAssignment: false }],

    // disallow whitespace before properties
    // http://eslint.org/docs/rules/no-whitespace-before-property
    'no-whitespace-before-property': 'error',

    // require padding inside curly braces
    'object-curly-spacing': ['error', 'always'],

    // enforce line breaks between braces
    // http://eslint.org/docs/rules/object-curly-newline
    // TODO: enable once https://github.com/eslint/eslint/issues/6488 is resolved
    'object-curly-newline': ['off', {
      ObjectExpression: { minProperties: 0, multiline: true },
      ObjectPattern: { minProperties: 0, multiline: true }
    }],

    // enforce "same line" or "multiple line" on object properties.
    // http://eslint.org/docs/rules/object-property-newline
    'object-property-newline': ['error', {
      allowMultiplePropertiesPerLine: true,
    }],

    // allow just one var statement per function
    'one-var': ['error', 'never'],

    // require a newline around variable declaration
    // http://eslint.org/docs/rules/one-var-declaration-per-line
    'one-var-declaration-per-line': ['error', 'always'],

    // require assignment operator shorthand where possible or prohibit it entirely
    // http://eslint.org/docs/rules/operator-assignment
    'operator-assignment': ['error', 'always'],

    // enforce operators to be placed before or after line breaks
    'operator-linebreak': 'off',

    // enforce padding within blocks
    'padded-blocks': ['error', 'never'],

    // require quotes around object literal property names
    // http://eslint.org/docs/rules/quote-props.html
    'quote-props': ['error', 'as-needed', { keywords: false, unnecessary: true, numbers: false }],

    // specify whether double or single quotes should be used
    quotes: ['error', 'single', { avoidEscape: true }],

    // do not require jsdoc
    // http://eslint.org/docs/rules/require-jsdoc
    'require-jsdoc': 'off',

    // require or disallow use of semicolons instead of ASI
    semi: ['error', 'always'],

    // enforce spacing before and after semicolons
    'semi-spacing': ['error', { before: false, after: true }],

    // requires object keys to be sorted
    'sort-keys': ['off', 'asc', { caseSensitive: false, natural: true }],

    // sort variables within the same declaration block
    'sort-vars': 'off',

    // require or disallow space before blocks
    'space-before-blocks': 'error',

    // require or disallow space before function opening parenthesis
    // http://eslint.org/docs/rules/space-before-function-paren
    'space-before-function-paren': ['error', { anonymous: 'always', named: 'never' }],

    // require or disallow spaces inside parentheses
    'space-in-parens': ['error', 'never'],

    // require spaces around operators
    'space-infix-ops': 'error',

    // Require or disallow spaces before/after unary operators
    // http://eslint.org/docs/rules/space-unary-ops
    'space-unary-ops': ['error', {
      words: true,
      nonwords: false,
      overrides: {
      },
    }],

    // require or disallow a space immediately following the // or /* in a comment
    'spaced-comment': ['error', 'always', {
      exceptions: ['-', '+'],
      markers: ['=', '!']           // space here to support sprockets directives
    }],

    // require or disallow the Unicode Byte Order Mark
    // http://eslint.org/docs/rules/unicode-bom
    'unicode-bom': ['error', 'never'],

    // require regex literals to be wrapped in parentheses
    'wrap-regex': 'off'
  }
};
<|endoftext|>