Giter Club home page Giter Club logo

nokit's Introduction

Overview

A light weight set of handy tools for real world program.

Reduce the gap between different systems. Such as watch directory changes on a network file system, operate spawn on Windows and Linux, handle async IO api with promise, etc.

Rather than help you decide what to do, it is designed to create possibilities. Even this document is generated by nokit itself.

It's one of the core lib of nobone.

NPM version Build Status Build status Deps Up to Date

Features

  • All async functions will return promise.
  • All functions are highly lazy designed, minimum boot time.
  • Test on Node 0.8 - 0.12 on Mac, Linux and Windows.
  • Light weight and self-reference.

Installation

As a lib dependency, install it locally: npm i nokit.

Nokit has provided a cli tool like GNU Make. If you install it globally like this:

npm -g i nokit

, then have fun with your nofile, it can be js, coffee or livescript. For more information goto the CLI section.

Quick Start

vs Gulp

Here it will automatically lint, compile, compress and cache files by their extensions. You can goto Drives section to see what extensions are supported, or write your own.

kit = require 'nokit'
drives = kit.require 'drives'

kit.warp 'src/**/*.@(jade|less|coffee|ls)'
    # # To disable cache.
    # .load drives.reader isCache: false
    .load drives.auto 'lint'
    .load drives.auto 'compile', '.coffee': { bare: false }
    .load drives.auto 'compress'
    .load concat 'main.js'
.run 'dist/path'

Write your own drives

Nokit has already provided some handy example drives, you can check them in the Drives section. It's fairly easy to write your own.

kit = require 'nokit'
coffee = require 'coffee-script'

# A drive for coffee, a simple curried function.
compiler = (opts) -> ->
    # Change extension from '.coffee' to '.js'.
    @dest.ext = '.js'
    @set coffee.compile(@contents, opts)

# A drive to prepend lisence to each file.
# Here "fileInfo.set" is the same with the "@set".
lisencer = (lisence) -> (fileInfo) ->
    @set lisence + '\n' + @contents

# A drive to concat all files. It will override the default writer.
concat = (outputFile) ->
    all = ''

    # Object.assign
    kit._.assign ->
        all += @contents
    , isWriter: true, onEnd: ->
        # This will enable the auto-cache.
        @deps = kit._.pluck @list, 'path'

        @dest = @to + '/' + outputFile
        @set all

        # Call the overrided writer.
        # Call two times and create two output files.
        @super().then =>
            @dest = @dest + '.info'
            @set = '/* info */\n' + all
            @super()

kit.warp 'src/**/*.coffee'
    .load compiler bare: true
    .load lisencer '/* MIT lisence */'
    .load concat 'bundle.js'
.run 'dist'
.then ->
    kit.log 'Build Done'

CLI

By default nokit only supports js, if you want nokit to support coffee, you should install nokit like this:

npm i -g nokit coffee-cache coffee-script

It's recommended to use coffee-cache, since large build project may consume a large portion of your nofile's startup time. Of course, it's optional, you may run npm i -g nokit coffee-script without any problem.

Same works with livescript:

npm i -g nokit LiveScript

Remarks: for the sake of boot performance, nokit will only load coffee-cache coffee-script/register by default. For livescript or other precompiler, you have to set environment varialbe nokitPreload to what you want, such as on unix: export nokitPreload='LiveScript coffee-script/register'. Different module names are separated by spaces.

Create a nofile.coffee (or .js, .ls) at your current working directory or any of its parents directory. The syntax of nofile is almost the same as the Cakefile, only the option's first argument is slightly changed.

Assume your file content is:

module.exports = (task, option) ->
    kit = require 'nokit'

    option '-w, --hello [world]', 'Just a test option', ''

    # Define a default task, and it depends on the "clean" task.
    task 'default', ['clean'], 'This is a comment info', (opts) ->
        kit.log opts.hello

        # Use colors.
        kit.require 'colors'
        kit.log 'print red words'.red

    task 'clean', ->
        kit.remove 'dist'

    # To add alias to a task, just use space to separate names.
    # Here 'build' and 'b' are the same task.
    task 'build b', ->
        kit.require 'drives'
        kit.warp 'src/**/*.js'
        .load kit.drives.auto 'compile'
        .run 'dist'

    task 'sequential', ['clean', 'build'], true, ->
        kit.log 'Run clean and build non-concurrently.'

Then you can run it in command line: no. Just that simple, without task name, no will try to call the default task directly.

You can run no -h to display help info.

Call no build or no b to run the build task.

For real world example, just see the nofile that nokit is using.

For more doc for the option goto commander.js.

Changelog

Goto changelog

API

  • Nokit extends all the functions of nofs. You can use it as same as nofs. For more info, see the doc:

    Offline Documentation

    • example:

      kit.readFile('test.txt', 'utf8').then (str) ->
      	console.log str
      
      kit.outputFile 'a.txt', 'test'
      .then -> kit.log 'done'
      
      kit.writeJSON 'b.json', { a: 10 }
      .then -> kit.log 'done'
      
      kit.mkdirs 'b.json', { a: 10 }
      .then -> kit.log 'done'
  • The lodash lib.

    • type: { Object }

    • example:

      kit._.map [1, 2, 3]
  • An throttled version of Promise.all, it runs all the tasks under a concurrent limitation. To run tasks sequentially, use kit.flow.

    • param: limit { Int }

      The max task to run at a time. It's optional. Default is Infinity.

    • param: list { Array | Function }

      If the list is an array, it should be a list of functions or promises, and each function will return a promise. If the list is a function, it should be a iterator that returns a promise, when it returns kit.async.end, the iteration ends.

    • param: saveResults { Boolean }

      Whether to save each promise's result or not. Default is true.

    • param: progress { Function }

      If a task ends, the resolve value will be passed to this function.

    • return: { Promise }

    • example:

      urls = [
      	'http://a.com'
      	'http://b.com'
      	'http://c.com'
      	'http://d.com'
      ]
      tasks = [
      	-> kit.request url[0]
      	-> kit.request url[1]
      	-> kit.request url[2]
      	-> kit.request url[3]
      ]
      
      kit.async(tasks).then ->
      	kit.log 'all done!'
      
      kit.async(2, tasks).then ->
      	kit.log 'max concurrent limit is 2'
      
      kit.async 3, ->
      	url = urls.pop()
      	if url
      		kit.request url
      	else
      		kit.async.end
      .then ->
      	kit.log 'all done!'
  • The browser helper.

    • static:

    • param: opts { Object }

      The options of the client, defaults:

      {
      	autoReload: kit.isDevelopment()
      	host: '' # The host of the event source.
      }
    • param: useJs { Boolean }

      By default use html. Default is false.

    • return: { String }

      The code of client helper.

    • example:

      When the client code is loaded on the browser, you can use the nb.log to log anything to server's terminal. The server will auto-format and log the information to the terminal. It's convinient for mobile development when remote debug is not possible.

      # The nb is assigned to the "window" object.
      nb.log { a: 10 }
      nb.log 10
  • The colors lib makes it easier to print colorful info in CLI. You must kit.require 'colors' before using it. Sometimes use kit.require 'colors/safe' will be better.

    • type: { Object }

    • example:

      cs = kit.require 'colors/safe'
      kit.log cs.red 'error info'
  • A fast file cache helper. It uses hard link to cache files.

    • param: info { Object }

      Not optional.

      {
      	# The first item is the key path, others are
      	# its dependencies.
      	deps: Array
      
      	# The path of the output file.
      	# If it's undefined, depsCache will try to get cache.
      	dests: Array
      
      	cacheDir: '.nokit'
      }
    • return: { Promise }

      Resolve a info object.

      {
      	isNewer: Boolean
      
      	# { path: mtime }
      	deps: Object
      
      	# { destPath: cachePath }
      	dests: Object
      
      	cacheError: undefined | Error
      }
    • example:

      # Set cache
      kit.depsCache {
      	dests: ['index.css']
      	deps: ['index.less', 'b.less', 'c.less']
      }
      
      # Get cache
      # You don't have to sepecify 'b.less', 'c.less'.
      kit.depsCache { deps: ['index.less'] }
      .then (cache) ->
      	if cache.isNewer
      		kit.log 'cache is newer'.
      		kit.log cache.dests
  • Daemonize a program. Just a shortcut usage of kit.spawn.

    • param: opts { Object }

      Defaults:

      {
      	bin: 'node'
      	args: ['app.js']
      	stdout: 'stdout.log' # Can also be a fd
      	stderr: 'stderr.log' # Can also be a fd
      }
    • return: { Porcess }

      The daemonized process.

  • A simple decrypt helper. Cross-version of node.

    • param: data { Any }

    • param: password { String | Buffer }

    • param: algorithm { String }

      Default is 'aes128'.

    • return: { Buffer }

  • The warp drives. You must kit.require 'drives' before using it. For more information goto the Drives section.

    • type: { Object }
  • A simple encrypt helper. Cross-version of node.

    • param: data { Any }

    • param: password { String | Buffer }

    • param: algorithm { String }

      Default is 'aes128'.

    • return: { Buffer }

  • A error log shortcut for kit.log(msg, 'error', opts)

    • param: msg { Any }

    • param: opts { Object }

  • A better child_process.exec. Supports multi-line shell script. For supporting old version of node, it will create 3 temp files, the temp files will be removed after the execution.

    • param: cmd { String }

      Shell commands.

    • param: shell { String }

      Shell name. Such as bash, zsh. Optinal.

    • return: { Promise }

      Resolves when the process's stdio is drained. The resolve value is like:

      {
      	code: 0
      	signal: null
      	stdout: 'hello world'
      	stderr: ''
      }
    • example:

      kit.exec("""
      	a='hello world'
       echo $a
      """).then ({code, stdout}) ->
      	kit.log code # output => 0
      	kit.log stdout # output => "hello world"
      
      # Bash doesn't support "**" recusive match pattern.
      p = kit.exec """
      	echo **/*.css
      """, 'zsh'
      
      # Get the child process object.
      p.process.then (proc) ->
      	kit.log proc.pid
  • Creates a function that is the composition of the provided functions. Besides, it can also accept async function that returns promise. See kit.async, if you need concurrent support.

    • param: fns { Function | Array }

      Functions that return promise or any value. And the array can also contains promises or values other than function. If there's only one argument and it's a function, it will treat as an iterator, when it returns kit.flow.end, the iteration ends.

    • return: { Function }

      (val) -> Promise A function that will return a promise.

    • example:

      # It helps to decouple sequential pipeline code logic.
      
      createUrl = (name) ->
      	return "http://test.com/" + name
      
      curl = (url) ->
      	kit.request(url).then (body) ->
      		kit.log 'get'
      		body
      
      save = (str) ->
      	kit.outputFile('a.txt', str).then ->
      		kit.log 'saved'
      
      download = kit.flow createUrl, curl, save
      # same as "download = kit.flow [createUrl, curl, save]"
      
      download 'home'
    • example:

      Walk through first link of each page.

      list = []
      iter = (url) ->
      	return kit.flow.end if not url
      
      	kit.request url
      	.then (body) ->
      		list.push body
      		m = body.match /href="(.+?)"/
      		m[0] if m
      
      walker = kit.flow iter
      walker 'test.com'
  • Format the parsed comments array to a markdown string.

    • param: comments { Array }

    • param: opts { Object }

      Defaults:

      {
      	indent: 0
      	name: ({ name }) ->
      		name = name.replace 'self.', ''
      		"- \#\#\#\# #{name}\n\n"
      	tag: ({ tagName, name, type }) ->
      		tname = if name then " `#{name}`" else ''
      		ttype = if type then " { _#{type}_ }" else ''
      		"- **<u>#{tagName}</u>**:#{tname}#{ttype}"
      }
    • return: { String }

  • See my project nofs.

    Offline Documentation

  • Fuzzy search a string list by a key word.

    • param: keys { String }

      The key word.

    • param: list { Array }

      The list of string to search.

    • param: opts { Object }

      Defaults:

      {
      	result: (wrappedList) ->
      		wrappedList.min('distance').words
      	threshold: (cOffset, keyLen, cIndex) ->
      		Infinity
      	notFound: (cOffset, keyLen, cIndex) ->
      		Infinity
      	span: (cOffset, keyLen, cIndex) ->
      		cOffset
      	found: (cOffset, keyLen, cIndex) ->
      		(Math.exp(cOffset + 1) - 1) * (keyLen - cIndex)
      	tail: (cOffset, keyLen, cIndex, tailLen) ->
      		tailLen
      }
    • return: { String }

      The best matched one. If not found, return undefined.

    • example:

      kit.fuzzySearch 'hw', ['test', 'hello world', 'hey world']
      # output => 'hey world'
      
      # To get a sortable weighted list.
      kit.fuzzySearch 'hw', ['test', 'hello world', 'hey world'], {
      	result: (wrappedList) -> wrappedList.value()
      }
      # output => [
      #  { distance: Infinity }
      #  { words: 'hello world', distance: 1110.069 }
      #  { words: 'hey world', distance: 159.849 }
      # ]
  • Generate a list of module paths from a name and a directory.

    • param: moduleName { String }

      The module name.

    • param: dir { String }

      The root path. Default is current working dir.

    • param: modDir { String }

      Default is 'node_modules'.

    • return: { Array }

      Paths

    • example:

      # Suppose current working directory is '/home/a'
      kit.genModulePaths 'test'
      # output => ['/home/a/node_modules/test', '/home/node_modules/test', '/node_modules/test']
  • Indent a text block.

    • param: text { String }

    • param: num { Int }

    • param: char { String }

    • param: reg { RegExp }

      Default is /^/mg.

    • return: { String }

      The indented text block.

    • example:

      # Increase
      kit.indent "one\ntwo", 2
      # => "  one\n  two"
      
      # Decrease
      kit.indent "--one\n--two", 0, '', /^--/mg
      # => "one\ntwo"
  • Nokit use it to check the running mode of the app. Overwrite it if you want to control the check logic. By default it returns the rocess.env.NODE_ENV == 'development'.

    • return: { Boolean }
  • Nokit use it to check the running mode of the app. Overwrite it if you want to control the check logic. By default it returns the rocess.env.NODE_ENV == 'production'.

    • return: { Boolean }
  • A fast helper to hash string or binary file. See my jhash project. You must kit.require 'jhash' before using it.

    Offline Documentation

    • example:

      kit.require 'jhash'
      kit.jhash.hash 'test' # output => '349o'
      
      jhash.hash kit.readFileSync('a.jpg')
      
      # Control the hash char set.
      kit.jhash.setSymbols 'abcdef'
      kit.jhash.hash 'test' # output => 'decfddfe'
      
      # Control the max length of the result hash value. Unit is bit.
      jhash.setMaskLen 10
      jhash.hash 'test' # output => 'ede'
  • A better log for debugging, it uses the kit.xinspect to log.

    Use terminal command like logReg='pattern' node app.js to filter the log info.

    Use logTrace='on' node app.js to force each log end with a stack trace.

    • param: msg { Any }

      Your log message.

    • param: action { String }

      'log', 'error', 'warn'.

    • param: opts { Object }

      Default is same with kit.xinspect, but with some extra options:

      {
      	isShowTime: true
      	logReg: process.env.logReg and new RegExp process.env.logReg
      	logTrace: process.env.logTrace == 'on'
      }
    • example:

      kit.log 'test'
      # => '[2015-02-07 08:31:49] test'
      
      kit.log 'test', { isShowTime: false }
      # => 'test'
      
      kit.log 'test', { logReg: /a/ }
      # => ''
      
      kit.log '%s %s %d', ['a', 'b', 10]
      # => '[2015-02-07 08:31:49] a b 10'
  • Shortcut for logging multiple strings.

    • param: args { Any }

      ...

    • example:

      kit.log 'test1', 'test2', test3'
      # => [2015-02-07 08:31:49] test1 test2 test3
  • Monitor an application and automatically restart it when file changed. Even when the monitored app exit with error, the monitor will still wait for your file change to restart the application. Not only nodejs, but also other programs like ruby or python. It will print useful infomation when it application unexceptedly.

    • param: opts { Object }

      Defaults:

      {
      	bin: 'node'
      	args: ['index.js']
      	watchList: [] # By default, the same with the "args".
      	isNodeDeps: true
      	opts: {} # Same as the opts of 'kit.spawn'.
      
      	# The option of `kit.parseDependency`
      	parseDependency: {}
      
      	onStart: ->
      		kit.log "Monitor: " + opts.watchList
      	onRestart: (path) ->
      		kit.log "Reload app, modified: " + path
      	onWatchFiles: (paths) ->
      		kit.log 'Watching:' + paths.join(', ')
      	onNormalExit: ({ code, signal }) ->
      		kit.log 'EXIT' +
      			" code: #{code} signal: #{signal}"
      	onErrorExit: ({ code, signal }) ->
      		kit.err 'EXIT' +
      		" code: #{code} signal: #{signal}\n" +
      		'Process closed. Edit and save
      			the watched file to restart.'
      	sepLine: ->
      		process.stdout.write _.repeat('*', process.stdout.columns)
      }
    • return: { Promise }

      It has a property process, which is the monitored child process. Properties:

      {
      	process: Object
      
      	# Call it to stop monitor.
      	stop: ->
      
      	# Resolve a list of watch handlers.
      	watchPromise: Promise
      }
    • example:

      kit.monitorApp {
      	bin: 'coffee'
      	args: ['main.coffee']
      }
      
      kit.monitorApp {
      	bin: 'ruby'
      	args: ['app.rb', 'lib/**/*.rb']
      	isNodeDeps: false
      }
  • Node version. Such as v0.10.23 is 0.1023, v0.10.1 is 0.1001.

    • return: { Float }
  • A helper for arguments type based function override.

    • param: args { Array | Object }

      The arguments to set.

    • param: defaults { Object }

      The default argument settings. The key value of the setting is the argument name, the value is an object, and the key is the type of the argument, the value is the default value of the argument.

    • return: { Object }

    • example:

      foo = ->
      	args = kit.defaultArgs arguments, {
      		name: { String: 'A' }
      		colors: { Array: [] }
      		family: { String: null }
      		isReal: { Boolean: false }
      		fn: { Function: -> 'callback' }
      	}
      
      kit.log foo('test', false, ['red'], -> 'nothing')
      # Here the logged value will deeply equal:
      { name: 'test', colors: ['red'], family: null, fn: -> 'nothing' }
  • A comments parser for javascript and coffee-script. Used to generate documentation from source code automatically. It will traverse through all the comments of a coffee file.

    • param: code { String }

      Coffee source code.

    • param: opts { Object }

      Parser options:

      {
      	commentReg: RegExp
      	splitReg: RegExp
      	tagNameReg: RegExp
      	typeReg: RegExp
      	nameReg: RegExp
      	nameTags: ['param', 'property']
      	descriptionReg: RegExp
      }
    • return: { Array }

      The parsed comments. Each item is something like:

      {
      	name: 'parseComment'
      	description: 'A comments parser for coffee-script.'
      	tags: [
      		{
      			tagName: 'param'
      			type: 'string'
      			name: 'code'
      			description: 'The name of the module it belongs to.'
      			index: 256 # The target char index in the file.
      			line: 32 # The line number of the target in the file.
      		}
      	]
      }
  • Parse dependency tree by regex. The dependency relationships is not a tree, but a graph. To avoid dependency cycle, this function only return an linear array of the dependencies, from which you won't get the detail relationshops between files.

    • param: entryPaths { String | Array }

      The file to begin with.

    • param: opts { Object }

      Defaults:

      {
      	depReg: /require\s*\(?['"](.+)['"]\)?/gm
      	depRoots: ['']
      	extensions: ['.js', '.coffee', 'index.js', 'index.coffee']
      
      	# It will handle all the matched paths.
      	# Return false value if you don't want this match.
      	handle: (path) ->
      		path.replace(/^[\s'"]+/, '').replace(/[\s'";]+$/, '')
      }
    • return: { Promise }

      It resolves the dependency path array.

    • example:

      kit.parseDependency 'main.', {
      	depReg: /require\s*\(?['"](.+)['"]\)?/gm
      	handle: (path) ->
      		return path if path.match /^(?:\.|/|[a-z]:)/i
      }
      .then (markdownStr) ->
      	kit.log markdownStr
  • io.js native module path. See nofs for more information.

  • The promise lib. Now, it uses Yaku as ES5 polyfill. In the future, the Yaku will be replaced with native ES6 Promise. Please don't use any API other than the ES6 spec.

    • type: { Object }
  • Convert a callback style function to a promise function.

    • param: fn { Function }

    • param: this { Any }

      this object of the function.

    • return: { Function }

      The function will return a promise object.

    • example:

      readFile = kit.promisify fs.readFile, fs
      readFile('a.txt').then kit.log
  • Create a getter & setter for an object's property.

    • param: self { Object }

    • param: prop { String }

      The property name.

    • return: { Function }

      (v) -> Any

      # Two arguments
      data = { path: 'a.txt' }
      txt = kit.prop data, 'txt'
      txt kit.readFile data.path
      .then ->
      	kit.log data
      	kit.log txt()
      
      # Two arguments another form.
      kit.readFile data.path
      .then txt
      .then ->
      	kit.log data
      
      # One argument.
      txt = kit.prop 'default value'
      kit.log txt() # => "default value"
      txt 20
      kit.log txt() # => 20
  • The proxy module. You must kit.require 'proxy' before using it. For more information goto the Proxy section.

  • Much faster than the native require of node, but you should follow some rules to use it safely. Use it to load nokit's internal module.

    • param: moduleName { String }

      The module path or name.

    • param: dir { String }

      Current absolute file path. Not optional, expect when requiring nokit's internal modules. On most times, just pass __dirname to it is enough.

    • param: loaded { Function }

      Run only the first time after the module loaded.

    • return: { Module }

      The module that you require.

    • example:

      Use it to load nokit's internal module.

      kit.require 'jhash'
      # Then you can use the module, or it will be null.
      kit.jhash.hash 'test'

      To load a relative path, or you own module, the second parameter 'dir' is required.

      mod = kit.require './mod', __dirname
      
      # Or load your own 'jhash', rather than nokit's.
      jhash = kit.require 'jhash', __dirname
  • Require an optional package. If not found, it will warn the user to npm install it, and exit the process.

    • param: name { String }

      Package name

    • param: dir { String }

      Current absolute file path. Not optional. On most times, just pass __dirname to it is enough.

    • param: semver { String }

      Specify what version you need, such as ^0.3.1 or >=1.2.3, ect.

    • return: { Any }

      The required package.

  • A handy extended combination of http.request and https.request.

    • param: opts { Object }

      The same as the http.request, but with some extra options:

      {
      	# String or Url Object.
      	url: String | Object
      
      	# Other than return `res` with `res.body`,return `body` directly.
      	body: true
      
      	# Max times of auto redirect. If 0, no auto redirect.
      	redirect: 0
      
      	# Timeout of the socket of the http connection.
      	# If timeout happens, the promise will reject.
      	# Zero means no timeout.
      	timeout: 0
      
      	# The key of headers should be lowercased.
      	headers: {}
      
      	protocol: 'http:' or 'https:'
      
      	agent: null
      
      	# Set "transfer-encoding" header to 'chunked'.
      	setTE: false
      
      	# Set null to use buffer, optional.
      	# It supports GBK, ShiftJIS etc.
      	# For more info, see https://github.com/ashtuchkin/iconv-lite
      	resEncoding: 'auto'
      
      	# It's string, object or buffer, optional. When it's an object,
      	# The request will be 'application/x-www-form-urlencoded'.
      	reqData: null
      
      	# auto end the request.
      	autoEndReq: true
      
      	# Readable stream.
      	reqPipe: null
      
      	# Writable stream.
      	resPipe: null
      
      	# The progress of the request.
      	reqProgress: (complete, total) ->
      
      	# The progress of the response.
      	resProgress: (complete, total) ->
      }

      And if set opts as string, it will be treated as the url.

    • return: { Promise }

      Contains the http response object, it has an extra body property. You can also get the request object by using Promise.req.

    • example:

      p = kit.request 'http://test.com'
      p.req.on 'response', (res) ->
      	kit.log res.headers['content-length']
      p.then (body) ->
      	kit.log body # html or buffer
      
      kit.request {
      	url: {
      		protocol: 'https', hostname: 'test.com'
      		port: 8123, path: '/a.mp3?s=1'
      	}
      	body: false
      	resProgress: (complete, total) ->
      		kit.log "Progress: #{complete} / #{total}"
      }
      .then (res) ->
      	kit.log res.body.length
      	kit.log res.headers
      
      # Send form-data.
      form = new (require 'form-data')
      form.append 'image', new Buffer(0), {
      	filename: 'a.jpg', contentType: 'image/jpg'
      }
      form.append 'key', 'value'
      kit.request {
      	url: 'a.com'
      	method: 'POST'
      	headers: form.getHeaders()
      
      	# Use chunked encoding, so that we don't have to calculate
      	# the 'Content-Length'.
      	setTE: true
      
      	reqPipe: form
      }
      .then (body) ->
      	kit.log body
  • The semantic versioner for npm, known as semver. You must kit.require 'semver' before using it.

    • type: { Object }
  • Create a http request handler middleware.

    • param: opts { Object }

      Same as the sse.

    • return: { Function }

      (req, res, next) ->

    • example:

      Visit 'http://127.0.0.1:80123', every 3 sec, the page will be reloaded.

      http = require 'http'
      handler = kit.serverHelper()
      
      http.createServer (req, res) ->
      	handler req, res, ->
      		res.end kit.browserHelper()
      
      .listen 8123, ->
      	kit.log 'listen ' + 8123
      
      	setInterval ->
      		handler.sse.emit 'fileModified', 'changed-file-path.js'
      	, 3000

      You can also use the nokit.log on the browser to log to the remote server.

      nokit.log { any: 'thing' }
  • Sleep for awhile. Works same as the setTimeout

    • param: time { Integer }

      Time to sleep, millisecond.

    • return: { Promise }

    • example:

      kit.sleep 1000
      .then ->
      	kit.log 'wake'
  • A safer version of child_process.spawn to cross-platform run a process. In some conditions, it may be more convenient to use the kit.exec. It will automatically add node_modules/.bin to the PATH environment variable.

    • param: cmd { String }

      Path or name of an executable program.

    • param: args { Array }

      CLI arguments.

    • param: opts { Object }

      Process options. Same with the Node.js official documentation. Except that it will inherit the parent's stdio.

    • return: { Promise }

      The promise.process is the spawned child process object. Resolves when the process's stdio is drained and the exit code is either 0 or 130. The resolve value is like:

      {
      	code: 0
      	signal: null
      }
    • example:

      kit.spawn 'git', ['commit', '-m', '42 is the answer to everything']
      .then ({code}) -> kit.log code
  • The sse module. You must kit.require 'sse' before using it. For more information goto the sse section.

  • Sequencing and executing tasks and dependencies concurrently.

    • param: name { String }

      The task name.

    • param: opts { Object }

      Optional. Defaults:

      {
      	deps: String | Array
      	description: String
      	logStart: ->
      	logEnd: ->
      
      	# Whether to run dependency in a row.
      	isSequential: false
      }
    • param: fn { Function }

      (val) -> Promise | Any The task function. If it is a async task, it should return a promise. It will get its dependency tasks' resolved values.

    • property: run { Function }

      Use it to start tasks. Each task will only run once. (names = 'default', opts) ->. The names can be a string or array. The default opts:

      {
      	isSequential: false
      
      	# Will be passed as the first task's argument.
      	init: undefined
      
      	# To stop the run currently in process. Set the `$stop`
      	# reference to true. It will reject a "runStopped" error.
      	warp: { $stop: false }
      }
    • property: list { Object }

      The defined task functions.

    • return: { Promise }

      Resolve with the last task's resolved value. When isSequential == true, it resolves a value, else it resolves an array.

    • example:

      kit.task 'default', { deps: 'build' }, ->
      	kit.log 'run defaults...'
      
      kit.task 'build', { deps: ['clean'] }, (isFull) ->
      	if isFull
      		'do something'
      	else
      		'do something else'
      
      kit.task 'clean', (opts) ->
      	if opts.isForce
      		kit.remove 'dist/**', { isForce: true }
      	else
      		kit.remove 'dist/**'
      
      kit.task.run()
      .then ->
      	kit.log 'All Done!'
  • The url module of io.js. You must kit.require 'url' before using it.

  • Works much like gulp.src, but with Promise instead. The warp control and error handling is more pleasant.

    • param: from { String }

      Glob pattern string.

    • param: opts { Object }

      It extends the options of nofs.glob, but with some extra proptereis. Defaults:

      {
      	# The base directory of the pattern.
      	baseDir: String
      }
    • return: { Object }

      The returned warp object has these members:

      {
      	# The drive can also be a promise that will resolve a drive.
      	load: (drive) -> fileInfo | null
      
      	run: (path) -> Promise
      }

      Each piped drive will recieve a object that extends nofs's fileInfo object:

      {
      	# Set the contents and return self.
      	set: (String | Buffer) -> fileInfo
      
      	# The src file path.
      	path: String
      
      	# The dest root path.
      	to: String
      
      	baseDir: String
      
      	# The destination path.
      	# Alter it if you want to change the output file's location.
      	# You can set it to string, warp will auto-convert it to object.
      	# It's "valueOf" will return "kit.path.join dir, name + ext".
      	dest: { root, dir, base, ext, name }
      
      	# The file content.
      	contents: String | Buffer
      
      	isDir: Boolean
      
      	stats: fs.Stats
      
      	# Alter it to control the left drives dynamically.
      	drives: [Function]
      
      	# All the globbed files.
      	list: Array
      
      	driveList: Array
      
      	# The opts you passed to "kit.warp", it will be extended.
      	opts: Object
      }

      Each drive can have a onEnd: (fileInfo) -> Any | Promise function, which will be called after a file's whole warp is ended.

      The drive can have a isReader property, which will make the drive override the default file reader.

      The drive can have a isWriter property, which will make the drive override the default file writer.

      If a drive overrides another, it can call fileInfo.super() to use it again.

    • example:

      # Define a simple workflow.
      kit.warp 'src/**/*.js'
      .load (fileInfo) ->
      	fileInfo.set '/* Lisence Info */' + fileInfo.contents
      .load jslint()
      .load minify()
      .run 'build/minified'
      
      # Override warp's file reader with a custom one.
      myReader = kit._.extend (fileInfo) ->
      	# Note that we can also use "@path",
      	# its the same with "fileInfo.path" here.
      	kit.readFile @path, 'hex'
      	.then @set
      , {
      	# This will tell warp you want use your own reader.
      	isReader: true
      }
      
      # Override writer.
      myWriter = kit._.extend (fileInfo) ->
      	return if @dest == 'a.js'
      
      	# Call the overrided writer.
      	@super()
      , isWriter: true, onEnd: -> @super()
      	kit.log @list
      
      kit.warp 'src/**/*.js'
      .load myWriter
      .run 'dist'
      
      # Use nokit's built-in warp drives.
      drives = kit.require 'drives'
      kit.warp src/**/*.coffee'
      .load drives.coffee()
      .run 'dist'
  • Same as the unix which command. You must kit.require 'which' before using it.

    • param: name { String }

      The command.

    • return: { Promise }

  • Sync version of which. You must kit.require 'whichSync' before using it.

    • type: { Function }
  • For debugging. Dump a colorful object.

    • param: obj { Object }

      Your target object.

    • param: opts { Object }

      Options. Default:

      { colors: true, depth: 5 }
    • return: { String }

  • Open a thing that your system can recognize. Now only support Windows, OSX or system that installed 'xdg-open'.

    • param: cmds { String | Array }

      The thing you want to open.

    • param: opts { Object }

      The options of the node native child_process.exec.

    • return: { Promise }

      When the child process exists.

    • example:

      # Open a webpage with the default browser.
      kit.open 'http://ysmood.org'

Drives

  • The built-in plguins for warp. It's more like examples to show how to use nokit efficiently.

  • clean-css

    • param: opts { Object }

    • return: { Function }

  • coffee-script compiler

    • param: opts { Object }

      Default is { bare: true }.

    • return: { Function }

  • coffeelint processor

    • param: opts { Object }

      It extends the default config of coffeelint, properties:

      {
      	colorize: true
      	reporter: 'default'
      
      	# The json of the "coffeelint.json".
      	# If it's null, coffeelint will try to find
      	# "coffeelint.json" as its content.
      	config: null | JSON | JsonFilePath
      }
    • return: { Function }

  • Parse commment from a js, coffee, or livescript file, and output a markdown string.

    • param: path { String }

    • param: opts { Object }

      Defaults:

      {
      	# Output doc path.
      	out: 'readme.md'
      
      	# jst template path.
      	tpl: 'readme.jst.md'
      
      	# Init doc info.
      	doc: {}
      
      	# Header size.
      	h: 3
      
      	parseComment: -> ...
      	formatComment: -> ...
      }
    • return: { Function }

    • example:

      The nofile of nokit shows how to use it.

  • Auto-compiler file by extension. It will search through kit.drives, and find proper drive to run the task. You can extend kit.drives to let it support more. For example:

    kit.drives.myCompiler = kit._.extend ->
    	# your compile logic
    , compiler: ['.jsx']
    • param: action { String }

      By default, it can be 'compile' or 'compress' or 'lint'

    • param: opts { Object }

      {
      	# If no compiler match.
      	onNotFound: (fileInfo) ->
      }
    • return: { Function }

  • Change dest path with a filter.

    • param: dir { String }

    • param: filter { Function }

      (fileInfo, dir) -> Boolean

    • return: { Function }

  • a batch file concat helper

    • param: name { String }

      The output file path.

    • param: dir { String }

      Optional. Override the dest of warp's.

    • return: { Function }

  • Suffix file name with the hash value of file content.

    • param: hashMapPath { String }

      The output file name hash map.

    • return: { Function }

  • Lint js via jshint.

    • param: opts { Object }

      Properties:

      {
      	global: null
      	config: null | JSON | JsonFilePath
      }
    • return: { Function }

  • Compile less.

    • param: { Object }

    • return: { Function }

  • LiveScript compiler.

    • param: opts { Object }

      Default is { bare: true }.

    • return: { Function }

  • mocha test

    • param: opts { Object }

      {
      	timeout: 5000
      }
      
    • return: { Function }

  • read file and set contents

    • param: opts { Object }

      Defaults:

      {
      	isCache: true
      	encoding: 'utf8'
      	cacheDir: '.nokit/warp'
      }
    • return: { Function }

  • Compile stylus.

    • param: opts { Object }

      It will use stylus.set to iterate opts and set the key-value, is the value is not a function.

      {
      	config: (styl) ->
      }
    • return: { Function }

    • example:

      kit.drives.stylus {
      	compress: true
      	config: (styl) ->
      		styl.define 'jack', 'a persion'
      }
  • uglify-js processor

    • param: opts { Object }

      Defaults:

      {
      	output:
      		comments: (node, comment) ->
      			text = comment.value
      			type = comment.type
      			if type == "comment2"
      				return /@preserve|@license|@cc_on/i.test text
      }
    • return: { Function }

  • Output file by contents and dest. If the 'ext' or 'name' is not null, the 'base' will be override by the 'ext' and 'name'.

    • return: { Function }

Proxy

  • For test, page injection development. A cross-platform programmable Fiddler alternative.

  • Use it to proxy one url to another.

    • param: req { http.IncomingMessage }

      Also supports Express.js.

    • param: res { http.ServerResponse }

      Also supports Express.js.

    • param: url { String | Object }

      The target url forced to. Optional. Such as force 'http://test.com/a' to 'http://test.com/b', force 'http://test.com/a' to 'http://other.com/a', force 'http://test.com' to 'other.com'. It can also be an url object. Such as { protocol: 'http:', host: 'test.com:8123', pathname: '/a/b', query: 's=1' }.

    • param: opts { Object }

      Other options. Default:

      {
      	# Limit the bandwidth byte per second.
      	bps: null
      
      	# if the bps is the global bps.
      	globalBps: false
      
      	agent: customHttpAgent
      
      	# You can hack the headers before the proxy send it.
      	handleReqHeaders: (headers) -> headers
      	handleResHeaders: (headers) -> headers
      }
    • param: err { Function }

      Custom error handler.

    • return: { Promise }

    • example:

      kit = require 'nokit'
      kit.require 'proxy'
      kit.require 'url'
      http = require 'http'
      
      server = http.createServer (req, res) ->
      	url = kit.url.parse req.url
      	switch url.path
      		when '/a'
      			kit.proxy.url req, res, 'a.com', (err) ->
      				kit.log err
      		when '/b'
      			kit.proxy.url req, res, '/c'
      		when '/c'
      			kit.proxy.url req, res, 'http://b.com/c.js'
      		else
      			# Transparent proxy.
      			service.use kit.proxy.url
      
      server.listen 8123
  • Http CONNECT method tunneling proxy helper. Most times used with https proxing.

    • param: req { http.IncomingMessage }

    • param: sock { net.Socket }

    • param: head { Buffer }

    • param: host { String }

      The host force to. It's optional.

    • param: port { Int }

      The port force to. It's optional.

    • param: err { Function }

      Custom error handler.

    • example:

      kit = require 'nokit'
      kit.require 'proxy'
      http = require 'http'
      
      server = http.createServer()
      
      # Directly connect to the original site.
      server.on 'connect', kit.proxy.connect
      
      server.listen 8123

SSE

  • A Server-Sent Event Manager. For more info see Using server-sent events. It is used to implement the live-reload of web assets.

    • param: opts { Object }

      Defaults:

      {
      	# The reconnection time to use when attempting to send the event, unit is ms.
      	retry: 1000
      }
    • example:

      Your server side code may look like this:

      http = require 'http'
      kit = require 'nokit'
      sse = kit.require 'sse'
      sseHandler = sse()
      http.createServer (req, res) ->
      	if req.url == '/sse'
       	sseHandler req, res
       else
       	res.end()
      .listen 8080, ->
      	setTimeout ->
      		sseHandler.emit 'test', { test: 'ok' }

      You browser code should be something like this:

      es = new EventSource('/sse')
      es.addEventListener('test', (e) ->
      	msg = JSON.parse(e.data)
       console.log(msg) # => { test: 'ok' }
  • The sse middleware for http handler.

    • param: req { http.IncomingMessage }

      Also supports Express.js.

    • param: res { http.ServerResponse }

      Also supports Express.js.

  • The sessions of connected clients.

    • type: { Array }
  • Broadcast a event to all clients.

    • param: event { String }

      The event name.

    • param: msg { Object | String }

      The data you want to emit to session.

    • param: { String }

      [path] The namespace of target sessions. If not set, broadcast to all clients.

  • Create a sse session.

    • param: req { http.IncomingMessage }

      Also supports Express.js.

    • param: res { http.ServerResponse }

      Also supports Express.js.

    • return: { SSESession }

  • A session object is something like:

    {
    	req  # The http req object.
     res  # The http res object.
    }
  • Emit message to client.

    • param: event { String }

      The event name.

    • param: msg { Object | String }

      The message to send to the client.

Contribution

Unit Test

npm test or npm run no -- test

Others

Run npm run no -- -h for all command you can use. Such as run npm run no -- build to build this project.

Docs

Edit the templete of the readme at doc/readme.jst.md.

Lisence

MIT

nokit's People

Contributors

ysmood avatar dracupid avatar

Watchers

James Cloos avatar barbabravo avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.