<commit_before>'use strict';

var u = require('./util'),
    error = u.error,
    warning = u.warning;

function ratio_denominator(node) {
    var is_all_zeros = true,
        den = node.denominator;
    for (var i = 0; i < den.length; i++) {
        if ( den[i] !== '0' ) {
            is_all_zeros = false;
        }
    }
    if ( is_all_zeros ) {
        return [error('divide by 0', node.pos, {})];
    }
    return [];
}

function integer_base(node) {
    var base = parseInt(node.base, 10);
    if ( base > 36 ) {
        return [error('radix too large', node.pos, {'radix': base})];
    } else if ( base <= 1 ) {
        return [error('radix too small', node.pos, {'radix': base})];
    }
    return [];
}

function integer_digits(node) {
    var base = node.base,
        errs = [];
    node.digits.split('').map(function(d) {
        var norm,
            c = d.charCodeAt();
        if ( ( c >= 48 ) && ( c <= 57 ) ) { // 0-9
            norm = (c - 48);
        } else if ( ( c >= 65 ) && ( c <= 90 ) ) { // A-Z
            norm = ((c - 65) + 10);
        } else if ( ( c >= 97 ) && ( c <= 122 ) ) { // a-z
            norm = ((c - 97) + 10);
        } else {
            throw new Error('unrecognized digit in ' + JSON.stringify(node));
        }
        if ( norm >= base ) {
            errs.push(error('out of range digit', node.pos, {'digit': d, 'base': base})); // TODO wrong position
        }
    });
    return errs;
}

function float_range(node) {
    var errs = [];
    if ( node.exponent === null ) {
        // TODO what about floats with really big decimal parts? i.e. 330 digits
        return errs;
    }
    var s = node.exponent.sign,
        exp_sign = ( s === null ) ? '' : s,
        exp = parseInt(exp_sign + node.exponent.power, 10),
        d = {'exponent': exp};
    if ( node.suffix === null ) {
        // it's a float: maxes out at about 1e308 or 1e309
        // bottoms out at about 1e-323 or 1e-324
        if ( exp > 308 ) {
            errs.push(warning('possible float overflow', node.pos, d));
        } else if ( exp < -323 ) {
            errs.push(warning('possible float underflow', node.pos, d));
        }
    } else {
        // it's a big decimal
        // exponent has to fit in 32 bits, so between -2147483647 and 2147483647
        if ( exp > 2147473647 ) {
            errs.push(warning('possible big decimal overflow', node.pos, d));
        } else if ( exp < -2147483647 ) {
            errs.push(warning('possible big decimal underflow', node.pos, d));
        }
    }
    return errs;
}

var long_chars = {
    "newline"   : 1,
    "space"     : 1,
    "tab"       : 1,
    "backspace" : 1,
    "formfeed"  : 1,
    "return"    : 1
};

function char_long(node) {
    if ( node.kind !== 'long' ) {
        return [];
    }
    if ( !(long_chars.hasOwnProperty(node.value)) ) {
        return [error('invalid long char', node.pos, {'value': node.value})];
    }
    return [];
}

/*function char_octal(node) {

}*/

/*function char_unicode(node) {

}*/

function string_unicode(node) {

}

// forms

var allows_metadata = {
    'table': 1, 'set': 1, 'list': 1,
    'vector': 1, 'function': 1, 'symbol': 1
};

function metadata_value(node) {
    var errs = [];
    if ( node.meta.length > 0 ) {
        if ( !allows_metadata.hasOwnProperty(node.type) ) {
            errs.push(error('form does not support metadata', node.pos, {'type': node.type}));
        }
    }
    return errs;
}

var can_be_metadata = {
    'keyword': 1, 'autokey': 1,
    'symbol': 1, 'string': 1, 'table': 1
};

function metadata_meta(node) {
    var errs = [];
    node.meta.map(function(m) {
        if ( !can_be_metadata.hasOwnProperty(m.type) ) {
            errs.push(error('invalid metadata type', m.pos, {'type': m.type}));
        }
    });
    return errs;
}

function table_even(node) {
    var errs = [];
    if ( ( node.elems.length % 2 ) === 1 ) {
        errs.push(error('uneven number of elements in table', node.pos, {'number': node.elems.length}));
    }
    return errs;
}

function eval_reader(node) {
    if ( node.elems.length !== 1 ) {
        throw new Error('eval form must have exactly one child');
    }
    var form = node.elems[0],
        errs = [];
    if ( form.type === 'symbol' ) {
        // good to go
    } else if ( form.type === 'list' ) {
        if ( form.elems.length === 0 ) {
            errs.push(error('list in eval reader must have at least one form', form.pos, {}));
        }
    } else {
        errs.push(error('eval reader requires symbol or list', node.pos, {'actual': form.type}));
    }
    return errs;
}

function traverse(f) {
    return function inner(node) {
        var errs = [];
        errs = errs.concat(f(node));
        switch (node._tag) {
            case 'token':
                break;
            case 'struct':
                node.elems.map(function(e) {
                    errs = errs.concat(inner(e));
                });
                break;
            default:
                throw new Error('unexpected AST node tag -- ' + JSON.stringify(node));
        }
        node.meta.map(function(m) {
            errs = errs.concat(inner(m));
        });
        return errs;
    };
}

function run_metadata(node) {
    function f_meta(node) {
        var errs = metadata_value(node);
        errs = errs.concat(metadata_meta(node));
        return errs;
    }
    return traverse(f_meta)(node);
}

var actions = {
    'integer': [integer_digits, integer_base]  ,
    'float'  : [float_range]                   ,
    'char'   : [char_long]                     ,
    'ratio'  : [ratio_denominator]             ,
    'table'  : [table_even]                    ,
    'eval'   : [eval_reader]                   ,
};

function node_check(node) {
//    console.log('bye -- ' + JSON.stringify(node));
    if ( !actions.hasOwnProperty(node.type) ) {
        return [];
    }
    var errs = [];
    actions[node.type].map(function(a) {
        errs = errs.concat(a(node));
    });
    return errs;
}

function run_singles(node) {
    return traverse(node_check)(node);
}

function run(node) {
    var errs = run_singles(node);
    errs.concat(run_metadata);
    return errs;
}

module.exports = {
    'checks': {
        // tokens
        'ratio_denominator' : ratio_denominator ,
        'integer_base'      : integer_base      ,
        'integer_digits'    : integer_digits    ,
        'float_range'       : float_range       ,
        'char_long'         : char_long         ,
        //
        'metadata_value'    : metadata_value    ,
        'metadata_meta'     : metadata_meta     ,
        'table_even'        : table_even        ,
        'eval_reader'       : eval_reader       ,
    },
    'run': run
};

<commit_msg>check for surrogates in unicode character literals<commit_after>'use strict';

var u = require('./util'),
    error = u.error,
    warning = u.warning;

function ratio_denominator(node) {
    var is_all_zeros = true,
        den = node.denominator;
    for (var i = 0; i < den.length; i++) {
        if ( den[i] !== '0' ) {
            is_all_zeros = false;
        }
    }
    if ( is_all_zeros ) {
        return [error('divide by 0', node.pos, {})];
    }
    return [];
}

function integer_base(node) {
    var base = parseInt(node.base, 10);
    if ( base > 36 ) {
        return [error('radix too large', node.pos, {'radix': base})];
    } else if ( base <= 1 ) {
        return [error('radix too small', node.pos, {'radix': base})];
    }
    return [];
}

function integer_digits(node) {
    var base = node.base,
        errs = [];
    node.digits.split('').map(function(d) {
        var norm,
            c = d.charCodeAt();
        if ( ( c >= 48 ) && ( c <= 57 ) ) { // 0-9
            norm = (c - 48);
        } else if ( ( c >= 65 ) && ( c <= 90 ) ) { // A-Z
            norm = ((c - 65) + 10);
        } else if ( ( c >= 97 ) && ( c <= 122 ) ) { // a-z
            norm = ((c - 97) + 10);
        } else {
            throw new Error('unrecognized digit in ' + JSON.stringify(node));
        }
        if ( norm >= base ) {
            errs.push(error('out of range digit', node.pos, {'digit': d, 'base': base})); // TODO wrong position
        }
    });
    return errs;
}

function float_range(node) {
    var errs = [];
    if ( node.exponent === null ) {
        // TODO what about floats with really big decimal parts? i.e. 330 digits
        return errs;
    }
    var s = node.exponent.sign,
        exp_sign = ( s === null ) ? '' : s,
        exp = parseInt(exp_sign + node.exponent.power, 10),
        d = {'exponent': exp};
    if ( node.suffix === null ) {
        // it's a float: maxes out at about 1e308 or 1e309
        // bottoms out at about 1e-323 or 1e-324
        if ( exp > 308 ) {
            errs.push(warning('possible float overflow', node.pos, d));
        } else if ( exp < -323 ) {
            errs.push(warning('possible float underflow', node.pos, d));
        }
    } else {
        // it's a big decimal
        // exponent has to fit in 32 bits, so between -2147483647 and 2147483647
        if ( exp > 2147473647 ) {
            errs.push(warning('possible big decimal overflow', node.pos, d));
        } else if ( exp < -2147483647 ) {
            errs.push(warning('possible big decimal underflow', node.pos, d));
        }
    }
    return errs;
}

var long_chars = {
    "newline"   : 1,
    "space"     : 1,
    "tab"       : 1,
    "backspace" : 1,
    "formfeed"  : 1,
    "return"    : 1
};

function char_long(node) {
    if ( node.kind !== 'long' ) {
        return [];
    }
    if ( !(long_chars.hasOwnProperty(node.value)) ) {
        return [error('invalid long char', node.pos, {'value': node.value})];
    }
    return [];
}

/*function char_octal(node) {

}*/

var _surrogate_start = 55296, // D800
    _surrogate_stop  = 57343; // DFFF

function char_unicode(node) {
    if ( node.kind !== 'unicode' ) {
        return [];
    }
    var val = parseInt(node.value, 16);
    if ( ( val >= _surrogate_start ) &&
         ( val <= _surrogate_stop ) ) {
        return [error('invalid character constant: surrogate code unit', node.pos, {'value': node.value})];
    }
    return [];
}

function string_unicode(node) {

}

// forms

var allows_metadata = {
    'table': 1, 'set': 1, 'list': 1,
    'vector': 1, 'function': 1, 'symbol': 1
};

function metadata_value(node) {
    var errs = [];
    if ( node.meta.length > 0 ) {
        if ( !allows_metadata.hasOwnProperty(node.type) ) {
            errs.push(error('form does not support metadata', node.pos, {'type': node.type}));
        }
    }
    return errs;
}

var can_be_metadata = {
    'keyword': 1, 'autokey': 1,
    'symbol': 1, 'string': 1, 'table': 1
};

function metadata_meta(node) {
    var errs = [];
    node.meta.map(function(m) {
        if ( !can_be_metadata.hasOwnProperty(m.type) ) {
            errs.push(error('invalid metadata type', m.pos, {'type': m.type}));
        }
    });
    return errs;
}

function table_even(node) {
    var errs = [];
    if ( ( node.elems.length % 2 ) === 1 ) {
        errs.push(error('uneven number of elements in table', node.pos, {'number': node.elems.length}));
    }
    return errs;
}

function eval_reader(node) {
    if ( node.elems.length !== 1 ) {
        throw new Error('eval form must have exactly one child');
    }
    var form = node.elems[0],
        errs = [];
    if ( form.type === 'symbol' ) {
        // good to go
    } else if ( form.type === 'list' ) {
        if ( form.elems.length === 0 ) {
            errs.push(error('list in eval reader must have at least one form', form.pos, {}));
        }
    } else {
        errs.push(error('eval reader requires symbol or list', node.pos, {'actual': form.type}));
    }
    return errs;
}

function traverse(f) {
    return function inner(node) {
        var errs = [];
        errs = errs.concat(f(node));
        switch (node._tag) {
            case 'token':
                break;
            case 'struct':
                node.elems.map(function(e) {
                    errs = errs.concat(inner(e));
                });
                break;
            default:
                throw new Error('unexpected AST node tag -- ' + JSON.stringify(node));
        }
        node.meta.map(function(m) {
            errs = errs.concat(inner(m));
        });
        return errs;
    };
}

function run_metadata(node) {
    function f_meta(node) {
        var errs = metadata_value(node);
        errs = errs.concat(metadata_meta(node));
        return errs;
    }
    return traverse(f_meta)(node);
}

var actions = {
    'integer': [integer_digits, integer_base]  ,
    'float'  : [float_range]                   ,
    'char'   : [char_long, char_unicode]       ,
    'ratio'  : [ratio_denominator]             ,
    'table'  : [table_even]                    ,
    'eval'   : [eval_reader]                   ,
};

function node_check(node) {
//    console.log('bye -- ' + JSON.stringify(node));
    if ( !actions.hasOwnProperty(node.type) ) {
        return [];
    }
    var errs = [];
    actions[node.type].map(function(a) {
        errs = errs.concat(a(node));
    });
    return errs;
}

function run_singles(node) {
    return traverse(node_check)(node);
}

function run(node) {
    var errs = run_singles(node);
    errs.concat(run_metadata);
    return errs;
}

module.exports = {
    'checks': {
        // tokens
        'ratio_denominator' : ratio_denominator ,
        'integer_base'      : integer_base      ,
        'integer_digits'    : integer_digits    ,
        'float_range'       : float_range       ,
        'char_long'         : char_long         ,
        //
        'metadata_value'    : metadata_value    ,
        'metadata_meta'     : metadata_meta     ,
        'table_even'        : table_even        ,
        'eval_reader'       : eval_reader       ,
    },
    'run': run
};

<|endoftext|>


<commit_before>#!/usr/bin/env node
var fs = require('fs')
var path = require('path')
var watch = require('rollup-watch')
var rollup = require('rollup')
var program = require('commander')
var chalk = require('chalk')
var babel = require('rollup-plugin-babel')
var replace = require('rollup-plugin-replace')
var postReplace = require('rollup-plugin-post-replace')
var commonjs = require('rollup-plugin-commonjs')
var nodeResolve = require('rollup-plugin-node-resolve')

var buildEmojis = ['🔧', '🔨', '⚒', '🛠', '⛏', '🔩']
function randomBuildEmoji () {
  return buildEmojis[Math.floor(Math.random() * buildEmojis.length)]
}

program
  .usage('[options]')
  .option('-w, --watch', 'Watch and rebuild automatically')
  .parse(process.argv)

var packageJSON
try {
  packageJSON = require(path.join(process.cwd(), 'package.json'))
} catch (err) {
  console.error(chalk.red('error') + ' Error while reading the package.json file')
  console.error(err)
  process.exit(1)
}

if (!packageJSON.main) {
  console.error(chalk.red('error') + ' Missing "main" field in the package.json. Should point to the ".sketchplugin" file')
  process.exit(1)
}
if (!packageJSON.manifest) {
  console.error(chalk.red('error') + ' Missing "manifest" field in the package.json. Should point to the "manifest.json" file')
  process.exit(1)
}

var output = path.join(process.cwd(), packageJSON.main)
var manifest = path.join(process.cwd(), packageJSON.manifest)

var manifestJSON
try {
  manifestJSON = require(manifest)
} catch (err) {
  console.error(err)
  process.exit(1)
}

var userDefinedRollupConfig = {}
try {
	if (fs.existsSync(path.join(process.cwd(), 'rollup.config.js'))) {
		userDefinedRollupConfig = require(path.join(process.cwd(), 'rollup.config.js'))
	}
} catch (err) {
	console.error(chalk.red('error') + ' Error while reading rollup.config.js')
	console.error(err)
}

if (!fs.existsSync(output)) {
  fs.mkdirSync(output)
}

if (!fs.existsSync(path.join(output, 'Contents'))) {
  fs.mkdirSync(path.join(output, 'Contents'))
}

if (!fs.existsSync(path.join(output, 'Contents', 'Sketch'))) {
  fs.mkdirSync(path.join(output, 'Contents', 'Sketch'))
}

var manifestFolder = path.dirname(manifest)

function userDefinedPlugin (name) {
	return (userDefinedRollupConfig.plugins || []).find(p => p.name === name)
}

function otherUserDefinedPlugin (names) {
	return (userDefinedRollupConfig.plugins || []).filter(p => names.indexOf(p.name) === -1)
}

function rollupConfig (file, command) {
  const _config = {
    entry: path.join(command ? manifestFolder : process.cwd(), file),
    plugins: [
      userDefinedPlugin('babel') || babel({
				exclude: 'node_modules/**',
			}),
      userDefinedPlugin('node-resolve') || nodeResolve({
        jsnext: true,
        main: true
      }),
      userDefinedPlugin('commonjs') || commonjs({
        ignoreGlobal: false
      }),
      replace({
        'process.env.NODE_ENV': process.env.NODE_ENV
      })
    ].concat(command ? [
      replace({
        'export default': 'module.exports.__skpm_export__ =',
        'module.exports': 'module.exports.__skpm_export__',
        exclude: 'node_modules/**'
      }),
      postReplace({
        'module.exports.__skpm_export__': 'var onRun'
      })
    ] : []).concat(otherUserDefinedPlugin(['babel', 'node-resolve', 'commonjs']))
  }

	Object.keys(userDefinedRollupConfig).forEach(function (key) {
		if (!_config[key]) {
			_config[key] = userDefinedRollupConfig[key]
		}
	})

	return _config
}

var consolePolyfill = fs.readFileSync(require.resolve('./utils/consolePolyfill'), 'utf8')

function destConfig (file, command) {
  var basename = path.basename(file)
  return {
    intro: command ? consolePolyfill : '',
    useStrict: false,
    format: 'cjs',
    dest: command
      ? path.join(output, 'Contents', 'Sketch', basename.replace('.js', '.cocoascript'))
      : path.join(output, 'Contents', 'Resources', basename)
  }
}

function copyManifest () {
  return new Promise(function (resolve, reject) {
    var copy = Object.assign({}, manifestJSON)
    copy.version = manifestJSON.version || packageJSON.version
    copy.description = manifestJSON.description || packageJSON.description
    copy.homepage = manifestJSON.homepage || packageJSON.homepage
    copy.name = manifestJSON.name || packageJSON.name
    copy.disableCocoaScriptPreprocessor = typeof manifestJSON.disableCocoaScriptPreprocessor === 'undefined' ? true : manifestJSON.disableCocoaScriptPreprocessor

    copy.commands = manifestJSON.commands.map(function (command) {
      var basename = path.basename(command.script)
      return Object.assign({}, command, {script: basename.replace('.js', '.cocoascript')})
    })

    fs.writeFile(path.join(output, 'Contents', 'Sketch', 'manifest.json'), JSON.stringify(copy, null, 2), function (err) {
      if (err) {
        reject('Error while writing the manifest: ' + err.message)
        return
      }
      resolve()
    })
  })
}

var counter = 0
var steps = manifestJSON.commands.length + (packageJSON.resources || []).length + 1
function checkEnd () {
  if (++counter >= steps) {
    console.log(chalk.green('success') + ' Plugin built')
    process.exit(0)
  }
}

manifestJSON.commands.concat(packageJSON.resources || []).forEach(function (command) {
  var file = command.script || command
  var isCommand = command.script
  if (program.watch) {
    const watcher = watch(rollup, Object.assign(rollupConfig(file, isCommand), destConfig(file, isCommand)))
    watcher.on('event', function (event) {
      switch (event.code) {
        case 'BUILD_START':
          break
        case 'BUILD_END':
          console.log(randomBuildEmoji() + '  Built ' + chalk.blue(file) + ' in ' + chalk.grey(event.duration) + 'ms')
          break
        case 'ERROR':
          console.error(chalk.red('error') + ' Error while building ' + file)
          console.error(event.error)
          break
      }
    })
  } else {
    var now = Date.now()
    rollup.rollup(rollupConfig(file, isCommand)).then(function (bundle) {
      return bundle.write(destConfig(file, isCommand))
    }).then(function () {
      console.log(chalk.dim('[' + (counter + 1) + '/' + steps + '] ') + randomBuildEmoji() + '  Built ' + chalk.blue(file) + ' in ' + chalk.grey(Date.now() - now) + 'ms')
      checkEnd()
    }).catch(function (err) {
      console.error(chalk.red('error') + ' Error while building ' + file)
      console.error(err)
      process.exit(1)
    })
  }
})

var now = Date.now()
copyManifest().then(function () {
  if (!program.watch) {
    console.log(chalk.dim('[' + (counter + 1) + '/' + steps + ']') + ' 🖨  Copied ' + chalk.blue(packageJSON.manifest) + ' in ' + chalk.grey(Date.now() - now) + 'ms')
    checkEnd()
  } else {
    console.log('🖨  Copied ' + chalk.blue(packageJSON.manifest) + ' in ' + chalk.grey(Date.now() - now) + 'ms')
  }
}).catch(function (err) {
  console.error(chalk.red('error') + ' Error while copying ' + packageJSON.manifest)
  console.error(err)
  if (!program.watch) {
    process.exit(1)
  }
})
<commit_msg>deduplicate command files only build the files once even if they are specified by by multiple commands<commit_after>#!/usr/bin/env node
var fs = require('fs')
var path = require('path')
var watch = require('rollup-watch')
var rollup = require('rollup')
var program = require('commander')
var chalk = require('chalk')
var uniqBy = require('lodash.uniqby')
var babel = require('rollup-plugin-babel')
var replace = require('rollup-plugin-replace')
var postReplace = require('rollup-plugin-post-replace')
var commonjs = require('rollup-plugin-commonjs')
var nodeResolve = require('rollup-plugin-node-resolve')

var buildEmojis = ['🔧', '🔨', '⚒', '🛠', '⛏', '🔩']
function randomBuildEmoji () {
  return buildEmojis[Math.floor(Math.random() * buildEmojis.length)]
}

program
  .usage('[options]')
  .option('-w, --watch', 'Watch and rebuild automatically')
  .parse(process.argv)

var packageJSON
try {
  packageJSON = require(path.join(process.cwd(), 'package.json'))
} catch (err) {
  console.error(chalk.red('error') + ' Error while reading the package.json file')
  console.error(err)
  process.exit(1)
}

if (!packageJSON.main) {
  console.error(chalk.red('error') + ' Missing "main" field in the package.json. Should point to the ".sketchplugin" file')
  process.exit(1)
}
if (!packageJSON.manifest) {
  console.error(chalk.red('error') + ' Missing "manifest" field in the package.json. Should point to the "manifest.json" file')
  process.exit(1)
}

var output = path.join(process.cwd(), packageJSON.main)
var manifest = path.join(process.cwd(), packageJSON.manifest)

var manifestJSON
try {
  manifestJSON = require(manifest)
} catch (err) {
  console.error(err)
  process.exit(1)
}

var userDefinedRollupConfig = {}
try {
	if (fs.existsSync(path.join(process.cwd(), 'rollup.config.js'))) {
		userDefinedRollupConfig = require(path.join(process.cwd(), 'rollup.config.js'))
	}
} catch (err) {
	console.error(chalk.red('error') + ' Error while reading rollup.config.js')
	console.error(err)
}

if (!fs.existsSync(output)) {
  fs.mkdirSync(output)
}

if (!fs.existsSync(path.join(output, 'Contents'))) {
  fs.mkdirSync(path.join(output, 'Contents'))
}

if (!fs.existsSync(path.join(output, 'Contents', 'Sketch'))) {
  fs.mkdirSync(path.join(output, 'Contents', 'Sketch'))
}

var manifestFolder = path.dirname(manifest)

function userDefinedPlugin (name) {
	return (userDefinedRollupConfig.plugins || []).find(p => p.name === name)
}

function otherUserDefinedPlugin (names) {
	return (userDefinedRollupConfig.plugins || []).filter(p => names.indexOf(p.name) === -1)
}

function rollupConfig (file, command) {
  const _config = {
    entry: path.join(command ? manifestFolder : process.cwd(), file),
    plugins: [
      userDefinedPlugin('babel') || babel({
				exclude: 'node_modules/**',
			}),
      userDefinedPlugin('node-resolve') || nodeResolve({
        jsnext: true,
        main: true
      }),
      userDefinedPlugin('commonjs') || commonjs({
        ignoreGlobal: false
      }),
      replace({
        'process.env.NODE_ENV': process.env.NODE_ENV
      })
    ].concat(command ? [
      replace({
        'export default': 'module.exports.__skpm_export__ =',
        'module.exports': 'module.exports.__skpm_export__',
        exclude: 'node_modules/**'
      }),
      postReplace({
        'module.exports.__skpm_export__': 'var onRun'
      })
    ] : []).concat(otherUserDefinedPlugin(['babel', 'node-resolve', 'commonjs']))
  }

	Object.keys(userDefinedRollupConfig).forEach(function (key) {
		if (!_config[key]) {
			_config[key] = userDefinedRollupConfig[key]
		}
	})

	return _config
}

var consolePolyfill = fs.readFileSync(require.resolve('./utils/consolePolyfill'), 'utf8')

function destConfig (file, command) {
  var basename = path.basename(file)
  return {
    intro: command ? consolePolyfill : '',
    useStrict: false,
    format: 'cjs',
    dest: command
      ? path.join(output, 'Contents', 'Sketch', basename.replace('.js', '.cocoascript'))
      : path.join(output, 'Contents', 'Resources', basename)
  }
}

function copyManifest () {
  return new Promise(function (resolve, reject) {
    var copy = Object.assign({}, manifestJSON)
    copy.version = manifestJSON.version || packageJSON.version
    copy.description = manifestJSON.description || packageJSON.description
    copy.homepage = manifestJSON.homepage || packageJSON.homepage
    copy.name = manifestJSON.name || packageJSON.name
    copy.disableCocoaScriptPreprocessor = typeof manifestJSON.disableCocoaScriptPreprocessor === 'undefined' ? true : manifestJSON.disableCocoaScriptPreprocessor

    copy.commands = manifestJSON.commands.map(function (command) {
      var basename = path.basename(command.script)
      return Object.assign({}, command, {script: basename.replace('.js', '.cocoascript')})
    })

    fs.writeFile(path.join(output, 'Contents', 'Sketch', 'manifest.json'), JSON.stringify(copy, null, 2), function (err) {
      if (err) {
        reject('Error while writing the manifest: ' + err.message)
        return
      }
      resolve()
    })
  })
}

var counter = 0
var commands = uniqBy(manifestJSON.commands, function (c) { return c.script })
var steps = commands.length + (packageJSON.resources || []).length + 1
function checkEnd () {
  if (++counter >= steps) {
    console.log(chalk.green('success') + ' Plugin built')
    process.exit(0)
  }
}

commands.concat(packageJSON.resources || []).forEach(function (command) {
  var file = command.script || command
  var isCommand = command.script
  if (program.watch) {
    const watcher = watch(rollup, Object.assign(rollupConfig(file, isCommand), destConfig(file, isCommand)))
    watcher.on('event', function (event) {
      switch (event.code) {
        case 'BUILD_START':
          break
        case 'BUILD_END':
          console.log(randomBuildEmoji() + '  Built ' + chalk.blue(file) + ' in ' + chalk.grey(event.duration) + 'ms')
          break
        case 'ERROR':
          console.error(chalk.red('error') + ' Error while building ' + file)
          console.error(event.error)
          break
      }
    })
  } else {
    var now = Date.now()
    rollup.rollup(rollupConfig(file, isCommand)).then(function (bundle) {
      return bundle.write(destConfig(file, isCommand))
    }).then(function () {
      console.log(chalk.dim('[' + (counter + 1) + '/' + steps + '] ') + randomBuildEmoji() + '  Built ' + chalk.blue(file) + ' in ' + chalk.grey(Date.now() - now) + 'ms')
      checkEnd()
    }).catch(function (err) {
      console.error(chalk.red('error') + ' Error while building ' + file)
      console.error(err)
      process.exit(1)
    })
  }
})

var now = Date.now()
copyManifest().then(function () {
  if (!program.watch) {
    console.log(chalk.dim('[' + (counter + 1) + '/' + steps + ']') + ' 🖨  Copied ' + chalk.blue(packageJSON.manifest) + ' in ' + chalk.grey(Date.now() - now) + 'ms')
    checkEnd()
  } else {
    console.log('🖨  Copied ' + chalk.blue(packageJSON.manifest) + ' in ' + chalk.grey(Date.now() - now) + 'ms')
  }
}).catch(function (err) {
  console.error(chalk.red('error') + ' Error while copying ' + packageJSON.manifest)
  console.error(err)
  if (!program.watch) {
    process.exit(1)
  }
})
<|endoftext|>


<commit_before>#!/usr/bin/env node
var fs = require('fs')
var path = require('path')
var webpack = require('webpack')
var program = require('commander')
var parseAuthor = require('parse-author')
var chalk = require('chalk')
var objectAssign = require('object-assign')
var generateWebpackConfig = require('./utils/webpackConfig')
var getRepoFromPackageJSON = require('./utils/getRepoFromPackageJSON')
var getSketchVersion = require('./utils/getSketchVersion')

var buildEmojis = ['🔧', '🔨', '⚒', '🛠', '⛏', '🔩']
function randomBuildEmoji () {
  return buildEmojis[Math.floor(Math.random() * buildEmojis.length)]
}

program
  .description('Compile the javascript files into cocoascript')
  .usage('[options]')
  .option('-w, --watch', 'Watch and rebuild automatically')
  .option('-q, --quiet', 'Hide compilation warnings')
  .option('-r, --run', 'Run plugin after compiling')
  .parse(process.argv)

var packageJSON
try {
  packageJSON = require(path.join(process.cwd(), 'package.json'))
} catch (err) {
  console.error(chalk.red('error') + ' Error while reading the package.json file')
  console.error(err)
  process.exit(1)
}

if (!packageJSON.main) {
  console.error(chalk.red('error') + ' Missing "main" field in the package.json. Should point to the ".sketchplugin" file')
  process.exit(1)
}
if (!packageJSON.manifest) {
  console.error(chalk.red('error') + ' Missing "manifest" field in the package.json. Should point to the "manifest.json" file')
  process.exit(1)
}

var output = path.join(process.cwd(), packageJSON.main)
var manifest = path.join(process.cwd(), packageJSON.manifest)

var manifestJSON
try {
  manifestJSON = require(manifest)
} catch (err) {
  console.error(err)
  process.exit(1)
}

if (!fs.existsSync(output)) {
  fs.mkdirSync(output)
}

if (!fs.existsSync(path.join(output, 'Contents'))) {
  fs.mkdirSync(path.join(output, 'Contents'))
}

if (!fs.existsSync(path.join(output, 'Contents', 'Sketch'))) {
  fs.mkdirSync(path.join(output, 'Contents', 'Sketch'))
}

var manifestFolder = path.dirname(manifest)

var webpackConfig = generateWebpackConfig(program, output, manifestFolder, packageJSON)

var defaultAppcastURL = 'https://raw.githubusercontent.com/' + getRepoFromPackageJSON(packageJSON) + '/master/.appcast.xml'

function copyManifest () {
  return new Promise(function (resolve, reject) {
    var copy = objectAssign({}, manifestJSON)
    copy.version = manifestJSON.version || packageJSON.version
    copy.description = manifestJSON.description || packageJSON.description
    copy.homepage = manifestJSON.homepage || packageJSON.homepage
    copy.name = manifestJSON.name || packageJSON.name
    copy.disableCocoaScriptPreprocessor = typeof manifestJSON.disableCocoaScriptPreprocessor === 'undefined' ? true : manifestJSON.disableCocoaScriptPreprocessor
    if (manifestJSON.appcast !== false && packageJSON.appcast !== false) {
      copy.appcast = manifestJSON.appcast || packageJSON.appcast || defaultAppcastURL
    } else {
      delete copy.appcast
    }

    if (!copy.author && packageJSON.author) {
      var author = packageJSON.author
      if (typeof packageJSON.author === 'string') {
        author = parseAuthor(packageJSON.author)
      }
      copy.author = author.name
      if (!copy.email && author.email) {
        copy.email = author.email
      }
    }

    copy.commands = manifestJSON.commands.map(function (command) {
      var basename = path.basename(command.script)
      return objectAssign({}, command, {script: basename})
    })

    fs.writeFile(path.join(output, 'Contents', 'Sketch', 'manifest.json'), JSON.stringify(copy, null, 2), function (err) {
      if (err) {
        reject(new Error('Error while writing the manifest: ' + err.message))
        return
      }
      resolve()
    })
  })
}

var counter = 0

const commandsAndHandlers = manifestJSON.commands.reduce(function (prev, c) {
  if (!prev[c.script]) {
    prev[c.script] = {
      script: c.script,
      handlers: [],
      identifiers: []
    }
  }
  prev[c.script].handlers.push(c.handler || 'onRun')
  prev[c.script].identifiers.push(c.identifier)
  return prev
}, {})

var commands = Object.keys(commandsAndHandlers).map(function (k) {
  return commandsAndHandlers[k]
})

var steps = commands.length + (packageJSON.resources || []).length + 1
function checkEnd () {
  if (++counter >= steps) {
    console.log(chalk.green('success') + ' Plugin built')
    process.exit(0)
  }
}

function buildCallback (file, watching) {
  return function (err, stats) {
    if (err) {
      console.error(chalk.red('error') + ' Error while building ' + file)
      console.error(err.stack || err)
      if (err.details) {
        console.error(err.details)
      }
      process.exit(1)
    }

    var info = stats.toJson({
      chunks: false,
      colors: true,
      modules: false,
      assets: false,
      performance: false,
      reasons: false,
      version: false
    })

    if (stats.hasErrors()) {
      console.error(chalk.red('error') + ' Error while building ' + file)
      ;(info.errors || []).forEach(function (error) {
        console.error(error)
      })
      if (!watching) {
        process.exit(1)
      }
    } else {
      if (stats.hasWarnings() && !program.quiet) {
        (info.warnings || []).forEach(function (warning) {
          console.warn(warning)
        })
      }
      console.log(
        (watching ? '' : chalk.dim('[' + (counter + 1) + '/' + steps + '] ')) +
        randomBuildEmoji() + '  Built ' + chalk.blue(file) + ' in ' + chalk.grey(info.time) + 'ms'
      )
      if (!watching) {
        checkEnd()
      }
    }
  }
}

getSketchVersion().then(function (sketchVersion) {
  commands.concat(packageJSON.resources || []).forEach(function (command) {
    var file = command.script || command
    const compiler = webpack(webpackConfig(file, command.identifiers, command.handlers, sketchVersion))
    if (program.watch) {
      compiler.watch({}, buildCallback(file, program.watch))
    } else {
      compiler.run(buildCallback(file, program.watch))
    }
  })
})

var now = Date.now()
copyManifest().then(function () {
  if (!program.watch) {
    console.log(chalk.dim('[' + (counter + 1) + '/' + steps + ']') + ' 🖨  Copied ' + chalk.blue(packageJSON.manifest) + ' in ' + chalk.grey(Date.now() - now) + 'ms')
    checkEnd()
  } else {
    console.log('🖨  Copied ' + chalk.blue(packageJSON.manifest) + ' in ' + chalk.grey(Date.now() - now) + 'ms')
  }
}).catch(function (err) {
  console.error(chalk.red('error') + ' Error while copying ' + packageJSON.manifest)
  console.error(err)
  if (!program.watch) {
    process.exit(1)
  }
})
<commit_msg>catch when building<commit_after>#!/usr/bin/env node
var fs = require('fs')
var path = require('path')
var webpack = require('webpack')
var program = require('commander')
var parseAuthor = require('parse-author')
var chalk = require('chalk')
var objectAssign = require('object-assign')
var generateWebpackConfig = require('./utils/webpackConfig')
var getRepoFromPackageJSON = require('./utils/getRepoFromPackageJSON')
var getSketchVersion = require('./utils/getSketchVersion')

var buildEmojis = ['🔧', '🔨', '⚒', '🛠', '⛏', '🔩']
function randomBuildEmoji () {
  return buildEmojis[Math.floor(Math.random() * buildEmojis.length)]
}

program
  .description('Compile the javascript files into cocoascript')
  .usage('[options]')
  .option('-w, --watch', 'Watch and rebuild automatically')
  .option('-q, --quiet', 'Hide compilation warnings')
  .option('-r, --run', 'Run plugin after compiling')
  .parse(process.argv)

var packageJSON
try {
  packageJSON = require(path.join(process.cwd(), 'package.json'))
} catch (err) {
  console.error(chalk.red('error') + ' Error while reading the package.json file')
  console.error(err)
  process.exit(1)
}

if (!packageJSON.main) {
  console.error(chalk.red('error') + ' Missing "main" field in the package.json. Should point to the ".sketchplugin" file')
  process.exit(1)
}
if (!packageJSON.manifest) {
  console.error(chalk.red('error') + ' Missing "manifest" field in the package.json. Should point to the "manifest.json" file')
  process.exit(1)
}

var output = path.join(process.cwd(), packageJSON.main)
var manifest = path.join(process.cwd(), packageJSON.manifest)

var manifestJSON
try {
  manifestJSON = require(manifest)
} catch (err) {
  console.error(err)
  process.exit(1)
}

if (!fs.existsSync(output)) {
  fs.mkdirSync(output)
}

if (!fs.existsSync(path.join(output, 'Contents'))) {
  fs.mkdirSync(path.join(output, 'Contents'))
}

if (!fs.existsSync(path.join(output, 'Contents', 'Sketch'))) {
  fs.mkdirSync(path.join(output, 'Contents', 'Sketch'))
}

var manifestFolder = path.dirname(manifest)

var webpackConfig = generateWebpackConfig(program, output, manifestFolder, packageJSON)

var defaultAppcastURL = 'https://raw.githubusercontent.com/' + getRepoFromPackageJSON(packageJSON) + '/master/.appcast.xml'

function copyManifest () {
  return new Promise(function (resolve, reject) {
    var copy = objectAssign({}, manifestJSON)
    copy.version = manifestJSON.version || packageJSON.version
    copy.description = manifestJSON.description || packageJSON.description
    copy.homepage = manifestJSON.homepage || packageJSON.homepage
    copy.name = manifestJSON.name || packageJSON.name
    copy.disableCocoaScriptPreprocessor = typeof manifestJSON.disableCocoaScriptPreprocessor === 'undefined' ? true : manifestJSON.disableCocoaScriptPreprocessor
    if (manifestJSON.appcast !== false && packageJSON.appcast !== false) {
      copy.appcast = manifestJSON.appcast || packageJSON.appcast || defaultAppcastURL
    } else {
      delete copy.appcast
    }

    if (!copy.author && packageJSON.author) {
      var author = packageJSON.author
      if (typeof packageJSON.author === 'string') {
        author = parseAuthor(packageJSON.author)
      }
      copy.author = author.name
      if (!copy.email && author.email) {
        copy.email = author.email
      }
    }

    copy.commands = manifestJSON.commands.map(function (command) {
      var basename = path.basename(command.script)
      return objectAssign({}, command, {script: basename})
    })

    fs.writeFile(path.join(output, 'Contents', 'Sketch', 'manifest.json'), JSON.stringify(copy, null, 2), function (err) {
      if (err) {
        reject(new Error('Error while writing the manifest: ' + err.message))
        return
      }
      resolve()
    })
  })
}

var counter = 0

const commandsAndHandlers = manifestJSON.commands.reduce(function (prev, c) {
  if (!prev[c.script]) {
    prev[c.script] = {
      script: c.script,
      handlers: [],
      identifiers: []
    }
  }
  prev[c.script].handlers.push(c.handler || 'onRun')
  prev[c.script].identifiers.push(c.identifier)
  return prev
}, {})

var commands = Object.keys(commandsAndHandlers).map(function (k) {
  return commandsAndHandlers[k]
})

var steps = commands.length + (packageJSON.resources || []).length + 1
function checkEnd () {
  if (++counter >= steps) {
    console.log(chalk.green('success') + ' Plugin built')
    process.exit(0)
  }
}

function buildCallback (file, watching) {
  return function (err, stats) {
    if (err) {
      console.error(chalk.red('error') + ' Error while building ' + file)
      console.error(err.stack || err)
      if (err.details) {
        console.error(err.details)
      }
      process.exit(1)
    }

    var info = stats.toJson({
      chunks: false,
      colors: true,
      modules: false,
      assets: false,
      performance: false,
      reasons: false,
      version: false
    })

    if (stats.hasErrors()) {
      console.error(chalk.red('error') + ' Error while building ' + file)
      ;(info.errors || []).forEach(function (error) {
        console.error(error)
      })
      if (!watching) {
        process.exit(1)
      }
    } else {
      if (stats.hasWarnings() && !program.quiet) {
        (info.warnings || []).forEach(function (warning) {
          console.warn(warning)
        })
      }
      console.log(
        (watching ? '' : chalk.dim('[' + (counter + 1) + '/' + steps + '] ')) +
        randomBuildEmoji() + '  Built ' + chalk.blue(file) + ' in ' + chalk.grey(info.time) + 'ms'
      )
      if (!watching) {
        checkEnd()
      }
    }
  }
}

getSketchVersion().then(function (sketchVersion) {
  commands.concat(packageJSON.resources || []).forEach(function (command) {
    var file = command.script || command
    const compiler = webpack(webpackConfig(file, command.identifiers, command.handlers, sketchVersion))
    if (program.watch) {
      compiler.watch({}, buildCallback(file, program.watch))
    } else {
      compiler.run(buildCallback(file, program.watch))
    }
  })
}).catch(function (err) {
  console.error(chalk.red('error') + ' Error while building')
  console.error(err)
  if (!program.watch) {
    process.exit(1)
  }
})

var now = Date.now()
copyManifest().then(function () {
  if (!program.watch) {
    console.log(chalk.dim('[' + (counter + 1) + '/' + steps + ']') + ' 🖨  Copied ' + chalk.blue(packageJSON.manifest) + ' in ' + chalk.grey(Date.now() - now) + 'ms')
    checkEnd()
  } else {
    console.log('🖨  Copied ' + chalk.blue(packageJSON.manifest) + ' in ' + chalk.grey(Date.now() - now) + 'ms')
  }
}).catch(function (err) {
  console.error(chalk.red('error') + ' Error while copying ' + packageJSON.manifest)
  console.error(err)
  if (!program.watch) {
    process.exit(1)
  }
})
<|endoftext|>


<commit_before>// Filter function for
//
// Copyright 2011, 2012 StatusNet Inc.
//
// 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.

var databank = require('databank'),
    Databank = databank.Databank,
    NoSuchThingError = databank.NoSuchThingError,
    Step = require('step');

var RELEVANCE_CUTOFF = 20;
var MINIMUM_OCCURENCES = 3;
var MINPROB = 0.0001;
var MAXPROB = 0.9999;
var DEFAULT_PROB = 0.4; // default probability for unseen values
var SPAM_PROB = 0.90; // cutoff for saying is or isn't

var SpamFilter = {

    db: null,

    opposite: function(cat) {
        if (cat === 'ham') {
            return 'spam';
        } else if (cat === 'spam') {
            return 'ham';
        } else {
            throw new Error('Unknown category: ' + cat);
        }
    },

    updateCounts: function(cat, tokens, onSuccess) {

        var filter = this,
            opp = this.opposite(cat),
            catTotalKey = cat + 'total',
            oppTotalKey = opp + 'total',
            catTotal, oppTotal;

        Step(
            function() {
                filter.db.incr(catTotalKey, 1, this);
            },
            function(err, result) {
                if (err) throw err;
                catTotal = result;
                filter.db.read(oppTotalKey, 1, this);
            },
            function(err, result) {
                var i, group = this.group();
                if (err) {
                    if (err instanceof NoSuchThingError) {
                        oppTotal = 0;
                    } else {
                        throw err;
                    }
                } else {
                    oppTotal = result;
                }
                for (i in tokens) { // Not sure I love this
                    this.updateTokenCount(cat, tokens[i], catTotal, oppTotal, group());
                }
            },
            function(err, results) {
                if (err) {
                    onSuccess(err, null);
                } else {
                    onSuccess(null, results);
                }
            }
        );
    },

    updateTokenCount: function(cat, token, catTotal, oppTotal, onSuccess) {
        var opp = this.opposite(cat),
            filter = this,
            catCount, oppCount;

        Step(
            function() {
                filter.db.incr(cat, token, this);
            },
            function(err, result) {
                if (err) throw err;
                catCount = result;
                filter.db.read(opp, token, this);
            },
            function(err, result) {
                if (err instanceof NoSuchThingError) {
                    oppCount = 0;
                } else if (err) {
                    onSuccess(err, null);
                } else {
                    oppCount = result;
                }

                if (cat === 'spam') {
                    filter.updateTokenProb(token, catCount, oppCount, catTotal, oppTotal, onSuccess);
                } else {
                    filter.updateTokenProb(token, oppCount, catCount, oppTotal, catTotal, onSuccess);
                }
            }
        );
    },

    updateTokenProb: function(token, spamCount, hamCount, spamTotal, hamTotal, onSuccess) {
        var g = 2 * hamCount,
            b = spamCount;

        if (g + b > 5) {
            var p = Math.max(MINPROB,
                             Math.min(MAXPROB,
                                      Math.min(1, b/spamTotal)/
                                      (Math.min(1, g/hamTotal) + Math.min(1, b/spamTotal))));
            this.db.save('prob', token, p, onSuccess);
        }
    },

    getProbabilities: function(tokens, onSuccess) {
        this.db.readAll('prob', tokens, function(err, probs) {
            var i, probabilities = [], token;
            for (i = 0; i < tokens.length; i++) {
                token = tokens[i];
                // There's probably a nicer data structure for this
                if (probs[token] === null) {
                    probabilities.push([token, DEFAULT_PROB]);
                } else {
                    probabilities.push([token, probs[token]]);
                }
            }
            onSuccess(probabilities);
        });
    },

    bestProbabilities: function(probs) {
        probs.sort(function (a, b) {
            var adist = Math.abs(a[1] - 0.5);
            var bdist = Math.abs(b[1] - 0.5);

            if (adist > bdist) {
                return -1;
            } else if (bdist > adist) {
                return 1;
            } else {
                return 0;
            }
        });

        // Get the most relevant
        return probs.slice(0, Math.min(probs.length, RELEVANCE_CUTOFF));
    },

    combineProbabilities: function(probs) {
        var prod = probs.reduce(function(coll, cur, index, array) {
            return coll * cur[1];
        }, 1.0);

        var invprod = probs.reduce(function(coll, cur, index, array) {
            return coll * (1 - cur[1]);
        }, 1.0);

        //bounded values
        return Math.min(MAXPROB, Math.max(MINPROB, (prod)/(prod + invprod))); // really?
    },

    schema: {'spam': {pkey: 'token'},
              'ham': {pkey: 'token'},
              'prob': {pkey: 'token'},
              'spamtotal': {pkey: 'service'},
              'hamtotal': {pkey: 'service'}}
};

exports.SpamFilter = SpamFilter;
<commit_msg>fix this in step<commit_after>// Filter function for
//
// Copyright 2011, 2012 StatusNet Inc.
//
// 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.

var databank = require('databank'),
    Databank = databank.Databank,
    NoSuchThingError = databank.NoSuchThingError,
    Step = require('step');

var RELEVANCE_CUTOFF = 20;
var MINIMUM_OCCURENCES = 3;
var MINPROB = 0.0001;
var MAXPROB = 0.9999;
var DEFAULT_PROB = 0.4; // default probability for unseen values
var SPAM_PROB = 0.90; // cutoff for saying is or isn't

var SpamFilter = {

    db: null,

    opposite: function(cat) {
        if (cat === 'ham') {
            return 'spam';
        } else if (cat === 'spam') {
            return 'ham';
        } else {
            throw new Error('Unknown category: ' + cat);
        }
    },

    updateCounts: function(cat, tokens, onSuccess) {

        var filter = this,
            opp = this.opposite(cat),
            catTotalKey = cat + 'total',
            oppTotalKey = opp + 'total',
            catTotal, oppTotal;

        Step(
            function() {
                filter.db.incr(catTotalKey, 1, this);
            },
            function(err, result) {
                if (err) throw err;
                catTotal = result;
                filter.db.read(oppTotalKey, 1, this);
            },
            function(err, result) {
                var i, group = this.group();
                if (err) {
                    if (err instanceof NoSuchThingError) {
                        oppTotal = 0;
                    } else {
                        throw err;
                    }
                } else {
                    oppTotal = result;
                }
                for (i in tokens) { // Not sure I love this
                    filter.updateTokenCount(cat, tokens[i], catTotal, oppTotal, group());
                }
            },
            function(err, results) {
                if (err) {
                    onSuccess(err, null);
                } else {
                    onSuccess(null, results);
                }
            }
        );
    },

    updateTokenCount: function(cat, token, catTotal, oppTotal, onSuccess) {
        var opp = this.opposite(cat),
            filter = this,
            catCount, oppCount;

        Step(
            function() {
                filter.db.incr(cat, token, this);
            },
            function(err, result) {
                if (err) throw err;
                catCount = result;
                filter.db.read(opp, token, this);
            },
            function(err, result) {
                if (err instanceof NoSuchThingError) {
                    oppCount = 0;
                } else if (err) {
                    onSuccess(err, null);
                } else {
                    oppCount = result;
                }

                if (cat === 'spam') {
                    filter.updateTokenProb(token, catCount, oppCount, catTotal, oppTotal, onSuccess);
                } else {
                    filter.updateTokenProb(token, oppCount, catCount, oppTotal, catTotal, onSuccess);
                }
            }
        );
    },

    updateTokenProb: function(token, spamCount, hamCount, spamTotal, hamTotal, onSuccess) {
        var g = 2 * hamCount,
            b = spamCount;

        if (g + b > 5) {
            var p = Math.max(MINPROB,
                             Math.min(MAXPROB,
                                      Math.min(1, b/spamTotal)/
                                      (Math.min(1, g/hamTotal) + Math.min(1, b/spamTotal))));
            this.db.save('prob', token, p, onSuccess);
        }
    },

    getProbabilities: function(tokens, onSuccess) {
        this.db.readAll('prob', tokens, function(err, probs) {
            var i, probabilities = [], token;
            for (i = 0; i < tokens.length; i++) {
                token = tokens[i];
                // There's probably a nicer data structure for this
                if (probs[token] === null) {
                    probabilities.push([token, DEFAULT_PROB]);
                } else {
                    probabilities.push([token, probs[token]]);
                }
            }
            onSuccess(probabilities);
        });
    },

    bestProbabilities: function(probs) {
        probs.sort(function (a, b) {
            var adist = Math.abs(a[1] - 0.5);
            var bdist = Math.abs(b[1] - 0.5);

            if (adist > bdist) {
                return -1;
            } else if (bdist > adist) {
                return 1;
            } else {
                return 0;
            }
        });

        // Get the most relevant
        return probs.slice(0, Math.min(probs.length, RELEVANCE_CUTOFF));
    },

    combineProbabilities: function(probs) {
        var prod = probs.reduce(function(coll, cur, index, array) {
            return coll * cur[1];
        }, 1.0);

        var invprod = probs.reduce(function(coll, cur, index, array) {
            return coll * (1 - cur[1]);
        }, 1.0);

        //bounded values
        return Math.min(MAXPROB, Math.max(MINPROB, (prod)/(prod + invprod))); // really?
    },

    schema: {'spam': {pkey: 'token'},
              'ham': {pkey: 'token'},
              'prob': {pkey: 'token'},
              'spamtotal': {pkey: 'service'},
              'hamtotal': {pkey: 'service'}}
};

exports.SpamFilter = SpamFilter;
<|endoftext|>


<commit_before>var unirest = require('unirest');
module.exports = {
	spec : function() {
		return {
			name : 'http',
			desc : '',
			fields : [
			{type:'string',name:'url',description:'',required:true},
			{type:'string',name:'method',description:'available: GET/POST, default GET'},
			{type:'object',name:'params',description:'only in POST'},
			{type:'object',name:'headers',description:''},
			{type:'string',name:'var',description:''},
			{type:'string',name:'varJson',description:''}
			]
		}
	}
	,
	process : function(ctx, step, checkNext) {
		if(typeof step.method === 'undefined') step.method = 'GET';
		var frequestObj = {
			url : step.url,
			method : step.method
		};
		if(typeof step.params !== 'undefined') frequestObj.params = step.params;
		if(typeof step.headers !== 'undefined') frequestObj.headers = step.headers;
		if(typeof step.varJson !== 'undefined') {
			frequestObj.callbackJSON = function(json) {
				ctx.vars[step.varJson] = json;
				process.nextTick(checkNext);
			}
		}
		else if(typeof step.var != 'undefined') {
			frequestObj.callback = function(body) {
				ctx.vars[step.var] = body;
				process.nextTick(checkNext);
			}
		}
		else {
			process.nextTick(checkNext);
			return;
		}
		frequest(frequestObj);
	}
}

var frequest = function(args) {
	var method = args.method ? args.method : 'GET';
	var req = null;
	if(method == 'GET') {
		req = unirest.get(args.url);
	}
	else if(method == 'POST') {
		req = unirest.post(args.url);
	}
	if(args.headers) {
		req.headers(args.headers);
	}
	if(args.params) {
		req.send(args.params);
	}
	req.end(function(resp) {
		if(args.callback) {
			var body = resp.body;
			if(typeof resp.body !== 'string') {
				body = JSON.stringify(resp.body);
			}
			args.callback(body);
		}
		if(args.callbackJSON) {
			try {
				var json;
				if(typeof resp.body === 'string') {
					json = JSON.parse(resp.body);
				}
				else {
					json = resp.body;
				}
				args.callbackJSON(json);
			} catch (e) {
				console.log(e);
				if(args.errorCallback) args.errorCallback(e);
			}
		}
	})
}<commit_msg>fix #57<commit_after>var unirest = require('unirest');
module.exports = {
	spec : function() {
		return {
			name : 'http',
			desc : '',
			fields : [
			{type:'string',name:'url',description:'',required:true},
			{type:'string',name:'method',description:'available: GET/POST, default GET'},
			{type:'object',name:'params',description:'only in POST'},
			{type:'object',name:'headers',description:''},
			{type:'string',name:'var',description:''},
			{type:'string',name:'varJson',description:''}
			]
		}
	}
	,
	process : function(ctx, step, checkNext) {
		if(typeof step.method === 'undefined') step.method = 'GET';
		var frequestObj = {
			url : step.url,
			method : step.method
		};
		if(typeof step.params !== 'undefined') frequestObj.params = step.params;
		if(typeof step.headers !== 'undefined') frequestObj.headers = step.headers;
		if(typeof step.varJson !== 'undefined') {
			frequestObj.callbackJSON = function(json) {
				ctx.vars[step.varJson] = json;
				process.nextTick(checkNext);
			}
		}
		else if(typeof step.var !== 'undefined') {
			frequestObj.callback = function(body) {
				ctx.vars[step.var] = body;
				process.nextTick(checkNext);
			}
		}
		else {
			process.nextTick(checkNext);
			return;
		}
		frequest(frequestObj);
	}
}

var frequest = function(args) {
	var method = args.method ? args.method : 'GET';
	var req = null;
	if(method === 'GET') {
		req = unirest.get(args.url);
	}
	else if(method === 'POST') {
		req = unirest.post(args.url);
	}
	if(args.headers) {
		req.headers(args.headers);
	}
	if(args.params) {
		req.send(args.params);
	}
	req.end(function(resp) {
		if(args.callback) {
			var body = resp.body;
			if(typeof resp.body !== 'string') {
				body = JSON.stringify(resp.body);
			}
			args.callback(body);
		}
		if(args.callbackJSON) {
			try {
				var json;
				if(typeof resp.body === 'string') {
					json = JSON.parse(resp.body);
				}
				else {
					json = resp.body;
				}
				args.callbackJSON(json);
			} catch (e) {
				console.log(e);
				if(args.errorCallback) args.errorCallback(e);
			}
		}
	})
}<|endoftext|>


<commit_before>/***
*
* styleguide.js
*
* Parses CSS/LESS/SASS files with KSS notation and generates a styleguide
*
* Heavily influenced by node-kss and gulp-kss projects
*
***/

'use strict';

var path = require('path'),
  through = require('through2'),
  gulp = require('gulp'),
  rename = require('gulp-rename'),
  mustache = require('gulp-mustache'),
  sass = require('gulp-sass'),
  please = require('gulp-pleeease'),
  replace = require('gulp-replace'),
  neat = require('node-neat'),
  minimatch = require('minimatch'),
  fs = require('fs-extra'),
  File = require('vinyl'),
  crypto = require('crypto'),
  Q = require('q'),
  _ = require('lodash'),
  markdown = require('./modules/markdown'),
  atRules = require('./modules/at-rules'),
  variableParser = require('./modules/variable-parser'),
  kssParser = require('./modules/kss-parser'),
  angularFiles = require('./modules/angular-files'),
  pseudoSelectors = require('./modules/pseudo-selectors'),
  wrapperMarkup = require('./modules/wrapper-markup'),
  common = require('./modules/common'),
  sgServer = require('./server'),
  distPath = path.join(__dirname, 'dist'),
  fileHashes = {},
  serverInstance;

function socketIsOpen() {
  return serverInstance && serverInstance.io;
}

function emitProgressStart() {
  if (socketIsOpen()) {
    serverInstance.io.emitProgressStart();
  }
}

function emitProgressEnd() {
  if (socketIsOpen()) {
    serverInstance.io.emitProgressEnd();
  }
}

function emitCompileError(error) {
  if (socketIsOpen()) {
    serverInstance.io.emitCompileError(error);
  }
}

function emitCompileSuccess() {
  if (socketIsOpen()) {
    serverInstance.io.emitCompileSuccess();
  }
}

function generateInheritedWrappers(json) {
  json.sections = wrapperMarkup.generateSectionWrapperMarkup(json.sections);
}

function copyUsedOptionsToJsonConfig(opt, json) {
  var used = ['appRoot', 'extraHead', 'commonClass', 'title', 'disableEncapsulation', 'disableHtml5Mode'];
  json.config = {};
  used.forEach(function(prop) {
    json.config[prop] = _.cloneDeep(opt[prop]);
  });
  return json;
}

function copyUsedOptionsToInlineJsonConfig(opt, json) {
  var used = ['title', 'disableEncapsulation', 'disableHtml5Mode'];
  json.config = {};
  used.forEach(function(prop) {
    json.config[prop] = _.cloneDeep(opt[prop]);
  });
  return json;
}

function addFileHashesAndReplaceAbsolutePaths(json) {
  if (!json) {
    return;
  }

  if (json.variables) {
    json.variables.forEach(function(variable) {
      variable.fileHash = fileHashes[variable.file];
      variable.file = basenameOf(variable.file);
    });
  }

  if (json.variables) {
    json.sections.forEach(function(section) {
      section.fileHash = fileHashes[section.file];
      section.file = basenameOf(section.file);
    });
  }
}

function basenameOf(p) {
  return path.basename(p);
}

function appendUsedVariablesToEachBlock(opt, styleguide) {
  // Go trough every styleguide style block and find used variables
  styleguide.sections.forEach(function(section) {
    // It is possible that the CSS is not valid anymore after it is splitted to sections
    // We need to catch possible parsing errors
    try {
      if (section.css) {
        section.variables = variableParser.findVariables(section.css, section.syntax, opt);
      }
    } catch (e) {
      console.error('Could not parse used variables from section', section.reference + ':');
      console.error(e.toString());
    }

    variableParser.findModifierVariables(section.modifiers).forEach(function(varName) {
      if (!section.variables || section.variables.indexOf(varName) === -1) {
        section.variables = section.variables || [];
        section.variables.push(varName);
      }
    });
    return section;
  });
}

function filterFiles(files, filter) {
  var filtered = {};
  Object.keys(files).forEach(function(filePath) {
    if (minimatch(filePath, filter)) {
      filtered[filePath] = files[filePath];
    }
  });
  return filtered;
}

module.exports.generate = function(options) {
  var opt = common.sanitizeOptions(options),
    filesBuffer = {},
    throughOpts = {
      objectMode: true,
      allowHalfOpen: false
    };

  function bufferFileContents(file, enc, done) {
    if (file.isNull()) {
      return;
    }
    if (file.isStream()) {
      return console.error('Styleguide does not support streams!');
    }

    // Exclude empty files
    if (file.contents.toString('utf8') !== '') {
      filesBuffer[file.path] = file.contents.toString('utf8');
      var hash = crypto.createHash('md5').update(file.path).digest('hex');
      fileHashes[file.path] = hash;
      fileHashes[hash] = file.path;
    }

    // Make sure file goes through the next gulp plugin
    // jshint -W040
    this.push(file);
    // jshint +W040
    done();
  }

  emitProgressStart();

  // A stream through which each file will pass
  return through(throughOpts, bufferFileContents, function(callback) {
      var _this = this,
        // Styleguide object to be built
        styleguide = {},
        // Parse KSS sections
        parseKSSPromise = kssParser.parseKssSections(filesBuffer, opt.kssOpt),
        // Filter variable files
        // File paths are full absolute paths so we need to add wildcard prefix
        // Also empty wildcard should return all files
        variableFiles = opt.styleVariables ? filterFiles(filesBuffer, '**/' + opt.styleVariables) : filesBuffer,
        // Parse variable decarations from files
        parseVariablesPromise = variableParser.parseVariableDeclarationsFromFiles(variableFiles, opt);

      Q.all([parseKSSPromise, parseVariablesPromise]).spread(function(sections, variables) {
        styleguide.sections = sections;
        styleguide.variables = variables;

        // Extend config with Angular directives declared in KSS
        opt.filesConfig = angularFiles.add(opt.filesConfig, sections);

        function pushAllFiles() {
          return through.obj(function(file, enc, cb) {
            _this.push(file);
            cb();
          });
        }

        function processOverviewMarkdown(opt) {
          return Q.Promise(function(resolve) {
            if (!opt.overviewPath) {
              resolve();
            }
            markdown.getStream(opt.overviewPath)
              .pipe(rename(function(path) {
                path.basename = 'overview';
                path.extname = '.html';
              }))
              .pipe(pushAllFiles())
              .on('finish', resolve);
          });
        }

        generateInheritedWrappers(styleguide);
        copyUsedOptionsToJsonConfig(opt, styleguide);
        appendUsedVariablesToEachBlock(opt, styleguide);
        addFileHashesAndReplaceAbsolutePaths(styleguide);

        // Create JSON containing KSS data
        _this.push(new File({
          path: 'styleguide.json',
          contents: new Buffer(JSON.stringify(styleguide))
        }));

        var stylesCompiled,
          overviewProcessed,
          filesCopied,
          indexHtmlProcessed;

        overviewProcessed = processOverviewMarkdown(opt);

        // Copy all files (except index.html) from dist from to output stream
        filesCopied = Q.Promise(function(resolve) {
          gulp.src([distPath + '/**', '!' + distPath + '/index.html'])
            .pipe(pushAllFiles())
            .on('finish', resolve);
        });

        // Compile UI styles
        stylesCompiled = Q.Promise(function(resolve) {
          var sassSrc = [distPath + '/sass/app.scss', distPath + '/sass/styleguide_helper_elements.scss'],
            sassIncludePaths = neat.includePaths || [];

          // If we have custom colors defined. Overwrite default empty file
          if (opt.customColors) {
            try {
              fs.copySync(opt.customColors, distPath + '/sass/_styleguide_custom_variables.scss');
              // Add directory of custom colors file to SASS includePaths
              // This allows to including external files in custom variable file
              sassIncludePaths.push(path.resolve(path.dirname(opt.customColors)));
            } catch (err) {
              console.log('ERROR: customColors option is defined but the file is not copyable. Using default colors.');
            }
          }
          gulp.src(sassSrc)
            .pipe(replace("{{{appRoot}}}", opt.appRoot))
            .pipe(sass({
              // Include neat
              includePaths: neat.includePaths
            }))
            .pipe(please({
              minifier: false
            }))
            .pipe(pushAllFiles())
            .on('finish', resolve);
        });

        // Process index.html
        indexHtmlProcessed = Q.Promise(function(resolve) {
          gulp.src([distPath + '/index.html'])
            .pipe(mustache({
              title: opt.title,
              extraHead: opt.extraHead,
              styleguideConfig: JSON.stringify(copyUsedOptionsToInlineJsonConfig(opt, {}).config),
              appRoot: opt.appRoot,
              socketIo: opt.server,
              filesConfig: JSON.stringify(opt.filesConfig)
            }))
            .pipe(pushAllFiles())
            .on('finish', resolve);
        });

        Q.all([stylesCompiled, overviewProcessed, filesCopied, indexHtmlProcessed])
          .then(function() {
            if (opt.server) {
              opt.fileHashes = fileHashes;
              startServer(opt);
            }
            emitCompileSuccess();
          })
          .catch(function(error) {
            console.error(error.toString());
            emitCompileError(error);
          })
          .finally(callback);
      }).catch(function(error) {
        console.error(error.toString());
        emitCompileError(error);
        callback();
      });
    }
  ).on('error', console.error.bind(console)).on('end', function() {
    emitProgressEnd();
  });
};

/* Build pseudo styles and ay rules from preprocessed CSS styles */

module.exports.applyStyles = function() {
  var throughOpts = {
    objectMode: true,
    allowHalfOpen: false
  }, stylesBuffer = '',
    pseudoStylesBuffer = '',
    atRulesBuffer = '';

  function bufferFileContents(file, enc, done) {
    var pseudoStylesPromise,
      atRulesPromise;

    // Make sure file goes through the next gulp plugin
    // jshint -W040
    this.push(file);
    // jshint +W040

    // Process only CSS files
    // For example gulp-ruby-sass generatsd sourcemaps to the stream that we do not want to include
    if (path.extname(file.path) !== '.css') {
      done();
      return;
    }

    // Add styles to common stylesheet
    stylesBuffer += file.contents.toString();

    // Create stylesheet that contains pseudo styles
    pseudoStylesPromise = Q.Promise(function(resolve) {
      pseudoStylesBuffer += pseudoSelectors.stylesFromString(file.contents.toString(), {
        source: file.path
      });
      resolve();
    });

    // Create stylesheet that contains at-rules
    atRulesPromise = Q.Promise(function(resolve) {
      atRulesBuffer += atRules.stylesFromString(file.contents.toString(), {
        source: file.path
      });
      resolve();
    });

    Q.all([pseudoStylesPromise, atRulesPromise]).then(function() {
      done();
    });
  }

  return through(throughOpts, bufferFileContents, function(cb) {
    this.push(new File({
      path: 'styleguide.css',
      contents: new Buffer(stylesBuffer)
    }));

    this.push(new File({
      path: 'styleguide_pseudo_styles.css',
      contents: new Buffer(pseudoStylesBuffer)
    }));

    this.push(new File({
      path: 'styleguide_at_rules.css',
      contents: new Buffer(atRulesBuffer)
    }));

    cb();
  }).on('end', function() {
    if (socketIsOpen()) {
      serverInstance.io.emitStylesChanged();
    }
  });
};

/* Built-in server */

module.exports.server = function(options) {
  startServer(options);
};

function startServer(options) {
  var port = options.port;
  // Ignore start server if we already have instance running
  if (!serverInstance) {
    serverInstance = sgServer(options);
    serverInstance.app.set('port', port);
    serverInstance.server.listen(serverInstance.app.get('port'), function() {
      console.log('Express server listening on port ' + serverInstance.server.address().port);
    }).on('error', function(error) {
      if (error.code === 'EADDRINUSE') {
        console.error('Port:' + port + ' is already in use.');
        console.error('Please provide port using --port <port>');
      }
    });
  }
  return serverInstance;
}
<commit_msg>Correct quote marks<commit_after>/***
*
* styleguide.js
*
* Parses CSS/LESS/SASS files with KSS notation and generates a styleguide
*
* Heavily influenced by node-kss and gulp-kss projects
*
***/

'use strict';

var path = require('path'),
  through = require('through2'),
  gulp = require('gulp'),
  rename = require('gulp-rename'),
  mustache = require('gulp-mustache'),
  sass = require('gulp-sass'),
  please = require('gulp-pleeease'),
  replace = require('gulp-replace'),
  neat = require('node-neat'),
  minimatch = require('minimatch'),
  fs = require('fs-extra'),
  File = require('vinyl'),
  crypto = require('crypto'),
  Q = require('q'),
  _ = require('lodash'),
  markdown = require('./modules/markdown'),
  atRules = require('./modules/at-rules'),
  variableParser = require('./modules/variable-parser'),
  kssParser = require('./modules/kss-parser'),
  angularFiles = require('./modules/angular-files'),
  pseudoSelectors = require('./modules/pseudo-selectors'),
  wrapperMarkup = require('./modules/wrapper-markup'),
  common = require('./modules/common'),
  sgServer = require('./server'),
  distPath = path.join(__dirname, 'dist'),
  fileHashes = {},
  serverInstance;

function socketIsOpen() {
  return serverInstance && serverInstance.io;
}

function emitProgressStart() {
  if (socketIsOpen()) {
    serverInstance.io.emitProgressStart();
  }
}

function emitProgressEnd() {
  if (socketIsOpen()) {
    serverInstance.io.emitProgressEnd();
  }
}

function emitCompileError(error) {
  if (socketIsOpen()) {
    serverInstance.io.emitCompileError(error);
  }
}

function emitCompileSuccess() {
  if (socketIsOpen()) {
    serverInstance.io.emitCompileSuccess();
  }
}

function generateInheritedWrappers(json) {
  json.sections = wrapperMarkup.generateSectionWrapperMarkup(json.sections);
}

function copyUsedOptionsToJsonConfig(opt, json) {
  var used = ['appRoot', 'extraHead', 'commonClass', 'title', 'disableEncapsulation', 'disableHtml5Mode'];
  json.config = {};
  used.forEach(function(prop) {
    json.config[prop] = _.cloneDeep(opt[prop]);
  });
  return json;
}

function copyUsedOptionsToInlineJsonConfig(opt, json) {
  var used = ['title', 'disableEncapsulation', 'disableHtml5Mode'];
  json.config = {};
  used.forEach(function(prop) {
    json.config[prop] = _.cloneDeep(opt[prop]);
  });
  return json;
}

function addFileHashesAndReplaceAbsolutePaths(json) {
  if (!json) {
    return;
  }

  if (json.variables) {
    json.variables.forEach(function(variable) {
      variable.fileHash = fileHashes[variable.file];
      variable.file = basenameOf(variable.file);
    });
  }

  if (json.variables) {
    json.sections.forEach(function(section) {
      section.fileHash = fileHashes[section.file];
      section.file = basenameOf(section.file);
    });
  }
}

function basenameOf(p) {
  return path.basename(p);
}

function appendUsedVariablesToEachBlock(opt, styleguide) {
  // Go trough every styleguide style block and find used variables
  styleguide.sections.forEach(function(section) {
    // It is possible that the CSS is not valid anymore after it is splitted to sections
    // We need to catch possible parsing errors
    try {
      if (section.css) {
        section.variables = variableParser.findVariables(section.css, section.syntax, opt);
      }
    } catch (e) {
      console.error('Could not parse used variables from section', section.reference + ':');
      console.error(e.toString());
    }

    variableParser.findModifierVariables(section.modifiers).forEach(function(varName) {
      if (!section.variables || section.variables.indexOf(varName) === -1) {
        section.variables = section.variables || [];
        section.variables.push(varName);
      }
    });
    return section;
  });
}

function filterFiles(files, filter) {
  var filtered = {};
  Object.keys(files).forEach(function(filePath) {
    if (minimatch(filePath, filter)) {
      filtered[filePath] = files[filePath];
    }
  });
  return filtered;
}

module.exports.generate = function(options) {
  var opt = common.sanitizeOptions(options),
    filesBuffer = {},
    throughOpts = {
      objectMode: true,
      allowHalfOpen: false
    };

  function bufferFileContents(file, enc, done) {
    if (file.isNull()) {
      return;
    }
    if (file.isStream()) {
      return console.error('Styleguide does not support streams!');
    }

    // Exclude empty files
    if (file.contents.toString('utf8') !== '') {
      filesBuffer[file.path] = file.contents.toString('utf8');
      var hash = crypto.createHash('md5').update(file.path).digest('hex');
      fileHashes[file.path] = hash;
      fileHashes[hash] = file.path;
    }

    // Make sure file goes through the next gulp plugin
    // jshint -W040
    this.push(file);
    // jshint +W040
    done();
  }

  emitProgressStart();

  // A stream through which each file will pass
  return through(throughOpts, bufferFileContents, function(callback) {
      var _this = this,
        // Styleguide object to be built
        styleguide = {},
        // Parse KSS sections
        parseKSSPromise = kssParser.parseKssSections(filesBuffer, opt.kssOpt),
        // Filter variable files
        // File paths are full absolute paths so we need to add wildcard prefix
        // Also empty wildcard should return all files
        variableFiles = opt.styleVariables ? filterFiles(filesBuffer, '**/' + opt.styleVariables) : filesBuffer,
        // Parse variable decarations from files
        parseVariablesPromise = variableParser.parseVariableDeclarationsFromFiles(variableFiles, opt);

      Q.all([parseKSSPromise, parseVariablesPromise]).spread(function(sections, variables) {
        styleguide.sections = sections;
        styleguide.variables = variables;

        // Extend config with Angular directives declared in KSS
        opt.filesConfig = angularFiles.add(opt.filesConfig, sections);

        function pushAllFiles() {
          return through.obj(function(file, enc, cb) {
            _this.push(file);
            cb();
          });
        }

        function processOverviewMarkdown(opt) {
          return Q.Promise(function(resolve) {
            if (!opt.overviewPath) {
              resolve();
            }
            markdown.getStream(opt.overviewPath)
              .pipe(rename(function(path) {
                path.basename = 'overview';
                path.extname = '.html';
              }))
              .pipe(pushAllFiles())
              .on('finish', resolve);
          });
        }

        generateInheritedWrappers(styleguide);
        copyUsedOptionsToJsonConfig(opt, styleguide);
        appendUsedVariablesToEachBlock(opt, styleguide);
        addFileHashesAndReplaceAbsolutePaths(styleguide);

        // Create JSON containing KSS data
        _this.push(new File({
          path: 'styleguide.json',
          contents: new Buffer(JSON.stringify(styleguide))
        }));

        var stylesCompiled,
          overviewProcessed,
          filesCopied,
          indexHtmlProcessed;

        overviewProcessed = processOverviewMarkdown(opt);

        // Copy all files (except index.html) from dist from to output stream
        filesCopied = Q.Promise(function(resolve) {
          gulp.src([distPath + '/**', '!' + distPath + '/index.html'])
            .pipe(pushAllFiles())
            .on('finish', resolve);
        });

        // Compile UI styles
        stylesCompiled = Q.Promise(function(resolve) {
          var sassSrc = [distPath + '/sass/app.scss', distPath + '/sass/styleguide_helper_elements.scss'],
            sassIncludePaths = neat.includePaths || [];

          // If we have custom colors defined. Overwrite default empty file
          if (opt.customColors) {
            try {
              fs.copySync(opt.customColors, distPath + '/sass/_styleguide_custom_variables.scss');
              // Add directory of custom colors file to SASS includePaths
              // This allows to including external files in custom variable file
              sassIncludePaths.push(path.resolve(path.dirname(opt.customColors)));
            } catch (err) {
              console.log('ERROR: customColors option is defined but the file is not copyable. Using default colors.');
            }
          }
          gulp.src(sassSrc)
            .pipe(replace('{{{appRoot}}}', opt.appRoot))
            .pipe(sass({
              // Include neat
              includePaths: neat.includePaths
            }))
            .pipe(please({
              minifier: false
            }))
            .pipe(pushAllFiles())
            .on('finish', resolve);
        });

        // Process index.html
        indexHtmlProcessed = Q.Promise(function(resolve) {
          gulp.src([distPath + '/index.html'])
            .pipe(mustache({
              title: opt.title,
              extraHead: opt.extraHead,
              styleguideConfig: JSON.stringify(copyUsedOptionsToInlineJsonConfig(opt, {}).config),
              appRoot: opt.appRoot,
              socketIo: opt.server,
              filesConfig: JSON.stringify(opt.filesConfig)
            }))
            .pipe(pushAllFiles())
            .on('finish', resolve);
        });

        Q.all([stylesCompiled, overviewProcessed, filesCopied, indexHtmlProcessed])
          .then(function() {
            if (opt.server) {
              opt.fileHashes = fileHashes;
              startServer(opt);
            }
            emitCompileSuccess();
          })
          .catch(function(error) {
            console.error(error.toString());
            emitCompileError(error);
          })
          .finally(callback);
      }).catch(function(error) {
        console.error(error.toString());
        emitCompileError(error);
        callback();
      });
    }
  ).on('error', console.error.bind(console)).on('end', function() {
    emitProgressEnd();
  });
};

/* Build pseudo styles and ay rules from preprocessed CSS styles */

module.exports.applyStyles = function() {
  var throughOpts = {
    objectMode: true,
    allowHalfOpen: false
  }, stylesBuffer = '',
    pseudoStylesBuffer = '',
    atRulesBuffer = '';

  function bufferFileContents(file, enc, done) {
    var pseudoStylesPromise,
      atRulesPromise;

    // Make sure file goes through the next gulp plugin
    // jshint -W040
    this.push(file);
    // jshint +W040

    // Process only CSS files
    // For example gulp-ruby-sass generatsd sourcemaps to the stream that we do not want to include
    if (path.extname(file.path) !== '.css') {
      done();
      return;
    }

    // Add styles to common stylesheet
    stylesBuffer += file.contents.toString();

    // Create stylesheet that contains pseudo styles
    pseudoStylesPromise = Q.Promise(function(resolve) {
      pseudoStylesBuffer += pseudoSelectors.stylesFromString(file.contents.toString(), {
        source: file.path
      });
      resolve();
    });

    // Create stylesheet that contains at-rules
    atRulesPromise = Q.Promise(function(resolve) {
      atRulesBuffer += atRules.stylesFromString(file.contents.toString(), {
        source: file.path
      });
      resolve();
    });

    Q.all([pseudoStylesPromise, atRulesPromise]).then(function() {
      done();
    });
  }

  return through(throughOpts, bufferFileContents, function(cb) {
    this.push(new File({
      path: 'styleguide.css',
      contents: new Buffer(stylesBuffer)
    }));

    this.push(new File({
      path: 'styleguide_pseudo_styles.css',
      contents: new Buffer(pseudoStylesBuffer)
    }));

    this.push(new File({
      path: 'styleguide_at_rules.css',
      contents: new Buffer(atRulesBuffer)
    }));

    cb();
  }).on('end', function() {
    if (socketIsOpen()) {
      serverInstance.io.emitStylesChanged();
    }
  });
};

/* Built-in server */

module.exports.server = function(options) {
  startServer(options);
};

function startServer(options) {
  var port = options.port;
  // Ignore start server if we already have instance running
  if (!serverInstance) {
    serverInstance = sgServer(options);
    serverInstance.app.set('port', port);
    serverInstance.server.listen(serverInstance.app.get('port'), function() {
      console.log('Express server listening on port ' + serverInstance.server.address().port);
    }).on('error', function(error) {
      if (error.code === 'EADDRINUSE') {
        console.error('Port:' + port + ' is already in use.');
        console.error('Please provide port using --port <port>');
      }
    });
  }
  return serverInstance;
}
<|endoftext|>