├── src ├── install.coffee ├── tasks.coffee ├── options.coffee ├── index.coffee ├── option.coffee ├── watch.coffee ├── running.coffee ├── invoke │ ├── async.coffee │ ├── sync.coffee │ ├── parallel.coffee │ ├── serial.coffee │ ├── index.coffee │ ├── generator.coffee │ └── invoke.coffee ├── use.coffee ├── cp.coffee ├── log.coffee ├── task.coffee └── sake.coffee ├── .npmignore ├── .gitignore ├── .travis.yml ├── test └── test.coffee ├── sake-core.d.ts ├── Sakefile ├── LICENSE ├── package.json └── README.md /src/install.coffee: -------------------------------------------------------------------------------- 1 | import {install} from './sake' 2 | install() 3 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .npmignore 2 | .travis.yml 3 | Cakefile 4 | src/ 5 | test/ 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | lib/ 3 | npm-debug.log 4 | npm-debug.log.* 5 | install.* 6 | -------------------------------------------------------------------------------- /src/tasks.coffee: -------------------------------------------------------------------------------- 1 | # Global task cache 2 | tasks = {} 3 | 4 | tasks.has = (key) -> 5 | tasks[key]? 6 | 7 | export default tasks 8 | -------------------------------------------------------------------------------- /src/options.coffee: -------------------------------------------------------------------------------- 1 | # Global options cache 2 | options = {} 3 | 4 | options.has = (key) -> 5 | options[key]? 6 | 7 | export default options 8 | -------------------------------------------------------------------------------- /src/index.coffee: -------------------------------------------------------------------------------- 1 | import * as sake from './sake' 2 | 3 | export {version} from '../package.json' 4 | export * from './sake' 5 | export default sake 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - 7 5 | script: 6 | - npm test 7 | cache: 8 | directories: 9 | - node_modules 10 | -------------------------------------------------------------------------------- /test/test.coffee: -------------------------------------------------------------------------------- 1 | {install} = require '../' 2 | 3 | describe 'sake', -> 4 | describe '#install', -> 5 | it 'should install globals', -> 6 | install() 7 | unless invoke? 8 | throw new Error 'expect invoke to exist' 9 | -------------------------------------------------------------------------------- /src/option.coffee: -------------------------------------------------------------------------------- 1 | import options from './options' 2 | 3 | export default (letter, flag, description) -> 4 | unless description? 5 | [description, flag] = [flag, null] 6 | 7 | options[letter] = 8 | letter: letter 9 | flag: flag 10 | description: description 11 | -------------------------------------------------------------------------------- /src/watch.coffee: -------------------------------------------------------------------------------- 1 | import isFunction from 'es-is/function' 2 | import isString from 'es-is/string' 3 | import vigil from 'vigil' 4 | 5 | export default (dir, task, opts = {}) -> 6 | if isString task 7 | fn = -> invoke task 8 | else if isFunction task 9 | fn = task 10 | vigil.watch dir, fn, opts 11 | -------------------------------------------------------------------------------- /sake-core.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import executive from 'executive' 4 | 5 | declare global { 6 | var exec: executive 7 | var invoke: (command: string | string[]) => Promise 8 | var task: (command: string, description: string, ...args: any[]) => void 9 | var use: (plugin: string, options?: any) => void 10 | var watch: (path: string, fn: any) => void 11 | } 12 | -------------------------------------------------------------------------------- /src/running.coffee: -------------------------------------------------------------------------------- 1 | import log from './log' 2 | 3 | # Keep track of running tasks 4 | runningTasks = {} 5 | 6 | running = (name) -> 7 | return runningTasks[name] 8 | 9 | running.start = (name) -> 10 | log.info 'running', name 11 | runningTasks[name] = true 12 | 13 | running.stop = (name) -> 14 | log.info 'stopped', name 15 | runningTasks[name] = false 16 | 17 | export default running 18 | -------------------------------------------------------------------------------- /src/invoke/async.coffee: -------------------------------------------------------------------------------- 1 | import log from '../log' 2 | import running from '../running' 3 | 4 | # Invoke async task 5 | invokeAsync = (name, action, opts, cb) -> 6 | log.debug 'invokeAsync', name 7 | 8 | running.start name 9 | 10 | done = -> 11 | running.stop name 12 | cb.apply null, arguments 13 | 14 | if opts? 15 | action opts, done 16 | else 17 | action done 18 | 19 | export default invokeAsync 20 | -------------------------------------------------------------------------------- /Sakefile: -------------------------------------------------------------------------------- 1 | use 'sake-bundle' 2 | use 'sake-outdated' 3 | use 'sake-publish' 4 | use 'sake-test' 5 | use 'sake-version' 6 | 7 | task 'build', 'build project', -> 8 | b = new Bundle 9 | compilers: 10 | coffee: version: 1 11 | 12 | Promise.all [ 13 | b.write 14 | entry: 'src/index.coffee' 15 | b.write 16 | entry: 'src/install.coffee' 17 | dest: 'install.js' 18 | format: 'cjs' 19 | sourceMap: false 20 | ] 21 | -------------------------------------------------------------------------------- /src/use.coffee: -------------------------------------------------------------------------------- 1 | import isFunction from 'es-is/function' 2 | import isString from 'es-is/string' 3 | import resolve from 'resolve' 4 | 5 | export default (pkg, opts = {}) -> 6 | if isString pkg 7 | path = resolve.sync pkg, basedir: process.cwd() 8 | pkg = require path 9 | 10 | # Support CJS formatted ES modules with named + default exports 11 | if pkg.default? 12 | pkg = pkg.default 13 | 14 | if isFunction pkg 15 | pkg opts 16 | -------------------------------------------------------------------------------- /src/cp.coffee: -------------------------------------------------------------------------------- 1 | import cp from 'cp' 2 | import path from 'path' 3 | import fs from 'fs' 4 | import isFunction from 'es-is/function' 5 | 6 | export default (src, dst, opts, cb) -> 7 | if isFunction opts 8 | [opts, cb] = [{}, opts] 9 | 10 | opts ?= {} 11 | 12 | p = new Promise (resolve, reject) -> 13 | fs.stat dst, (err, stats) -> 14 | if stats.isDirectory 15 | dst = path.join dst, path.basename src 16 | 17 | cp src, dst, (err) -> 18 | if err? 19 | reject err 20 | else 21 | resolve() 22 | 23 | p.callback cb 24 | p 25 | -------------------------------------------------------------------------------- /src/invoke/sync.coffee: -------------------------------------------------------------------------------- 1 | import isPromise from 'es-is/promise' 2 | 3 | import log from '../log' 4 | import running from '../running' 5 | 6 | 7 | # Invoke sync task 8 | invokeSync = (name, action, opts, cb) -> 9 | log.debug 'invokeSync', name 10 | 11 | running.start name 12 | 13 | ret = action opts 14 | 15 | if isPromise promise = ret 16 | promise 17 | .then (value) -> 18 | running.stop name 19 | cb null, value 20 | .catch (err) -> 21 | running.stop name 22 | cb err 23 | else 24 | running.stop name 25 | cb null, ret 26 | 27 | export default invokeSync 28 | -------------------------------------------------------------------------------- /src/invoke/parallel.coffee: -------------------------------------------------------------------------------- 1 | import isFunction from 'es-is/function' 2 | 3 | import log from '../log' 4 | 5 | import invoke from './invoke' 6 | 7 | # Invoke tasks in serial 8 | invokeParallel = (tasks, opts, cb) -> 9 | log.debug 'invokeParallel', tasks, opts 10 | 11 | parallel = (cb) -> 12 | done = 0 13 | for task in tasks 14 | invoke task, opts, -> 15 | if ++done == tasks.length 16 | cb() 17 | 18 | return (parallel cb) if isFunction cb 19 | 20 | new Promise (resolve, reject) -> 21 | parallel (err) -> 22 | reject err if err? 23 | resolve() 24 | cb err if isFunction cb 25 | 26 | export default invokeParallel 27 | -------------------------------------------------------------------------------- /src/invoke/serial.coffee: -------------------------------------------------------------------------------- 1 | import isFunction from 'es-is/function' 2 | 3 | import log from '../log' 4 | 5 | import invoke from './invoke' 6 | 7 | 8 | # Invoke tasks in serial 9 | invokeSerial = (tasks, opts, cb) -> 10 | log.debug 'invokeSerial', tasks, opts 11 | 12 | serial = (cb) -> 13 | next = (err) -> 14 | return cb err if err? 15 | 16 | if tasks.length 17 | invoke tasks.shift(), opts, next 18 | else 19 | cb() 20 | next() 21 | 22 | return (serial cb) if isFunction cb 23 | 24 | new Promise (resolve, reject) -> 25 | serial (err) -> 26 | reject err if err? 27 | resolve() 28 | cb err if isFunction cb 29 | 30 | export default invokeSerial 31 | -------------------------------------------------------------------------------- /src/invoke/index.coffee: -------------------------------------------------------------------------------- 1 | import isArray from 'es-is/array' 2 | import isFunction from 'es-is/function' 3 | 4 | import parallel from './parallel' 5 | import serial from './serial' 6 | 7 | # Wrap invokeSerial, invokeParallel to ensure sane arguments 8 | wrap = (fn) -> 9 | (tasks, opts, cb) -> 10 | # Ensure tasks are an array 11 | tasks = [tasks] unless isArray tasks 12 | 13 | # Called with a callback and no options 14 | if isFunction opts 15 | [cb, opts] = [opts, {}] 16 | 17 | # Ensure opts exists 18 | opts ?= {} 19 | 20 | fn tasks, opts, cb 21 | 22 | wrapper = wrap serial 23 | wrapper.serial = wrapper # aliased 24 | wrapper.parallel = wrap parallel 25 | 26 | export default wrapper 27 | -------------------------------------------------------------------------------- /src/log.coffee: -------------------------------------------------------------------------------- 1 | import chalk from 'chalk' 2 | import isString from 'es-is/string' 3 | 4 | verbose = process.env.VERBOSE ? false 5 | 6 | pretty = (obj) -> 7 | JSON.stringify obj, null, 2 8 | 9 | logger = (method, color) -> 10 | prefix = chalk[color] method 11 | 12 | (args...) -> 13 | return unless verbose 14 | 15 | msg = prefix 16 | 17 | for arg in args 18 | if isString arg 19 | msg += ' ' + arg 20 | else 21 | msg += '\n' + pretty arg 22 | 23 | console.log msg 24 | 25 | methods = 26 | debug: 'blue' 27 | info: 'white' 28 | warn: 'yellow' 29 | error: 'red' 30 | 31 | bebop: 'black' 32 | modified: 'cyan' 33 | compiled: 'blue' 34 | 35 | wrapper = logger 'info', 'white' 36 | for k,v of methods 37 | wrapper[k] = logger k,v 38 | 39 | wrapper.verbose = (bool = !verbose) -> 40 | verbose = bool 41 | 42 | export default wrapper 43 | -------------------------------------------------------------------------------- /src/task.coffee: -------------------------------------------------------------------------------- 1 | import isArray from 'es-is/array' 2 | import isFunction from 'es-is/function' 3 | 4 | import log from './log' 5 | import tasks from './tasks' 6 | 7 | export default (name, description, deps, action) -> 8 | # No description, just deps 9 | if isArray description 10 | action = deps if isFunction deps 11 | [description, deps] = ['', description] 12 | 13 | # If we're passed name, action 14 | if isFunction description 15 | [action, description, deps] = [description, '', []] 16 | 17 | # No dependencies specified, ex: `task 'name', 'description', ->` 18 | if isFunction deps 19 | [action, deps] = [deps, []] 20 | 21 | # Missing task function (body), ex: `task 'name', 'description', ['1','2','3']` 22 | unless isFunction action 23 | action = -> 24 | 25 | # Store reference for ourselves 26 | tasks[name] = 27 | name: name 28 | description: description 29 | deps: deps 30 | action: action 31 | 32 | log.debug 'added task', tasks[name] 33 | -------------------------------------------------------------------------------- /src/invoke/generator.coffee: -------------------------------------------------------------------------------- 1 | import log from '../log' 2 | import running from '../running' 3 | import isPromise from 'es-is/promise' 4 | 5 | 6 | # Invoke a enerator task continually until consumed 7 | invokeGenerator = (name, action, opts, cb) -> 8 | log.debug 'invokeGenerator', name 9 | 10 | running.start name 11 | 12 | gen = action opts 13 | 14 | last = null 15 | prev = null 16 | 17 | done = (err) -> 18 | running.stop name 19 | console.error err.stack if err? 20 | cb err, (last ? prev) 21 | 22 | next = (value) -> 23 | try 24 | res = gen.next value 25 | catch err 26 | console.error err.stack 27 | return done err 28 | 29 | prev = last 30 | last = res.value 31 | 32 | if isPromise promise = res.value 33 | promise 34 | .then (value) -> 35 | next value 36 | .catch (err) -> 37 | done err 38 | else if not res.done 39 | next res.value 40 | else 41 | done() 42 | 43 | next() 44 | 45 | export default invokeGenerator 46 | -------------------------------------------------------------------------------- /src/sake.coffee: -------------------------------------------------------------------------------- 1 | import exec from 'executive' 2 | import {join} from 'path' 3 | 4 | import invoke from './invoke' 5 | import option from './option' 6 | import options from './options' 7 | import parallel from './invoke/parallel' 8 | import running from './running' 9 | import serial from './invoke/serial' 10 | import task from './task' 11 | import tasks from './tasks' 12 | import use from './use' 13 | import watch from './watch' 14 | 15 | import {version} from '../package.json' 16 | 17 | install = -> 18 | # Ensure local node_modules bin is on the front of $PATH 19 | binPath = join process.cwd(), 'node_modules/', '.bin' 20 | process.env.PATH = ([binPath].concat process.env.PATH.split ':').join ':' 21 | 22 | global.invoke = invoke 23 | global.option = option 24 | global.options = options 25 | global.running = running 26 | global.task = task 27 | global.tasks = tasks 28 | global.use = use 29 | 30 | global.watch = watch # Deprecated 31 | global.exec = exec # Deprecated 32 | 33 | export { 34 | install 35 | invoke 36 | option 37 | options 38 | parallel 39 | running 40 | serial 41 | task 42 | tasks 43 | use 44 | version 45 | watch 46 | } 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD License 2 | 3 | Copyright (c) 2017-present, Hanzo, Inc. 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name Hanzo nor the names of its contributors may be used to 17 | endorse or promote products derived from this software without specific 18 | prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /src/invoke/invoke.coffee: -------------------------------------------------------------------------------- 1 | import isFunction from 'es-is/function' 2 | import isGeneratorFunction from 'es-is/generator-function' 3 | 4 | import log from '../log' 5 | import tasks from '../tasks' 6 | 7 | import invokeAsync from './async' 8 | import invokeGenerator from './generator' 9 | import invokeSync from './sync' 10 | import serial from './serial' 11 | 12 | invoked = {} 13 | 14 | # Invoke delegates to one of the above 15 | invoke = (name, opts, cb) -> 16 | log.debug 'invoke', name, opts 17 | 18 | # Prevent recursive calls 19 | return if invoked[name] 20 | invoked[name] = true 21 | 22 | unless (task = tasks[name])? 23 | throw new Error "No such task: #{name}" 24 | 25 | # Grab task action, any deps and parsed options 26 | {action, deps} = tasks[name] 27 | 28 | done = (err) -> 29 | invoked = {} 30 | (cb err) if isFunction cb 31 | 32 | invokeAction = (err) -> 33 | return done err if err? 34 | 35 | # Is a generator task 36 | if isGeneratorFunction action 37 | return invokeGenerator name, action, opts, done 38 | 39 | # Two arguments, action expects callback 40 | if action.length == 2 41 | return invokeAsync name, action, opts, done 42 | 43 | # Single argument, detected callback 44 | if /^function \((callback|cb|done|next)\)/.test action 45 | return invokeAsync name, action, null, done 46 | 47 | # 0 or 1 argument action, no callback detected 48 | invokeSync name, action, opts, done 49 | 50 | # Process deps first if any 51 | return serial deps, opts, invokeAction 52 | 53 | invokeAction() 54 | 55 | export default invoke 56 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sake-core", 3 | "version": "1.6.7", 4 | "description": "Build system for JavaScript applications with extensible core and support for modern JS.", 5 | "main": "lib/sake-core.js", 6 | "module": "lib/sake-core.mjs", 7 | "types": "sake-core.d.ts", 8 | "files": [ 9 | "sake-core.d.ts", 10 | "install.js", 11 | "lib/", 12 | "src/" 13 | ], 14 | "repository": { 15 | "type": "git", 16 | "url": "git://github.com/sakejs/sake-core" 17 | }, 18 | "keywords": [ 19 | "async", 20 | "build", 21 | "bundle", 22 | "sake", 23 | "sakefile", 24 | "cli", 25 | "coffee", 26 | "coffee-script", 27 | "make", 28 | "minify", 29 | "reload", 30 | "sake", 31 | "sakefile", 32 | "scaffold", 33 | "server", 34 | "task", 35 | "test", 36 | "tool", 37 | "uglify", 38 | "watch" 39 | ], 40 | "author": "Hanzo, Inc. It is cold, but · we have Sake · and the hot spring 11 | 12 | Sake is a build tool and task runner for JavaScript. Sake features an extensible 13 | core and support for modern JS. Inspired by 14 | [Cake](http://coffeescript.org/documentation/docs/cake.html), Sake is the 15 | perfect DSL for building projects. 16 | 17 | ### Features 18 | - Additional helpers to make writing tasks faster and more pleasant. 19 | - Generator based-control flow in tasks with full support for Promises. 20 | - Intutive CLI and automatic option parsing. 21 | - Plugin architecture with available plugins for many common build tasks. 22 | - Tasks can declare dependencies and be easily composed of and interact with 23 | other tasks. 24 | - Modern JS support: 25 | - Async/Await 26 | - ES modules 27 | - Generators 28 | - Promises 29 | 30 | ### Install 31 | ``` 32 | npm install sake-core --save-dev 33 | ``` 34 | 35 | ### Usage 36 | Typically Sake is used via it's command line interface which can be installed 37 | with `npm install -g sake-cli`. Once the [`sake`][sake-cli] command is 38 | available, you can begin writing a `Sakefile` and defining available tasks in 39 | your project. 40 | 41 | ### Sakefile 42 | Sake will search for a Sakefile with tasks defined for your current project. 43 | Sakefiles can be written in ES2015 JavaScript and support modules natively. 44 | 45 | Optionally, you can write your Sakefile in CoffeeScript, which allows a very 46 | nice DSL-ish experience. 47 | 48 | ### Examples 49 | #### Async tasks 50 | Async tasks are easy to declare, any task with an obvious callback will be 51 | treated as asynchronous. Add an additional argument called `callback`, `cb`, 52 | `done` or `next` and use it to indicate when your task is finished executing. 53 | 54 | ```coffee 55 | task 'compile:js', 'compile js', (done) -> 56 | exec 'coffee -bc app.coffee', done 57 | 58 | task 'minify:js', 'minify js', (done) -> 59 | exec 'uglify-js --compress --mangle app.js > app.min.js', done 60 | ``` 61 | 62 | #### Promise tasks 63 | You can also return a promise from your task and sake will automatically 64 | wait for it to resolve. Since `executive` returns a promise, this works too: 65 | 66 | ```coffee 67 | task 'compile:js', 'compile js', -> 68 | exec 'coffee -bc app.coffee' 69 | ``` 70 | 71 | #### Invoking multiple tasks 72 | You can manually invoke tasks and string them together with callbacks: 73 | 74 | ```coffee 75 | task 'build', 'build project', -> 76 | invoke 'compile:js', -> 77 | invoke 'minify:js' 78 | ``` 79 | 80 | #### Declaring dependencies 81 | Dependencies can be declared by adding an array of task names after your task's 82 | description. 83 | 84 | ```coffee 85 | task 'build', 'build project', ['compile:js', 'minify:js'] 86 | ``` 87 | 88 | #### Serial tasks 89 | You can also pass an array of tasks `invoke` and it will execute them in order 90 | for you: 91 | 92 | ```coffee 93 | task 'build', 'build project', (done) -> 94 | invoke ['compile:js', 'minify:js'], done 95 | ``` 96 | 97 | ...or more explicitly using `invoke.serial`. 98 | 99 | #### Parallel tasks 100 | If you want to execute tasks in parallel you can use `invoke.parallel`. 101 | 102 | ```coffee 103 | task 'compile', 'compile css & js', (done) -> 104 | invoke.parallel ['compile:css', 'compile:js'], done 105 | ``` 106 | 107 | #### Detecting running tasks 108 | You can check for running tasks using the `running` helper. 109 | 110 | ```coffee 111 | task 'watch', 'watch for changes and re-compile js', -> 112 | exec 'coffee -bcmw -o lib/ src/' 113 | 114 | task 'watch:test', 'watch for changes and re-run tests', (options) -> 115 | invoke 'watch' 116 | 117 | require('vigil').watch __dirname, (filename, stats) -> 118 | return if running 'test' 119 | 120 | if /^test/.test filename 121 | invoke 'test', test: filename 122 | if /^src/.test filename 123 | invoke 'test' 124 | ``` 125 | 126 | #### Generator tasks 127 | You can also use `yield` to wait for the value of a promise and eschew the use 128 | of callbacks. 129 | 130 | ```coffee 131 | task 'compile:js', 'compile js', -> 132 | yield exec 'coffee -bc app.coffee' 133 | 134 | task 'minify:js', 'minify js', -> 135 | yield exec 'uglify-js --compress --mangle app.js > app.min.js' 136 | ``` 137 | 138 | This really pays dividends with more complicated tasks: 139 | 140 | ```coffee 141 | task 'package', 'Package project', -> 142 | yield exec ''' 143 | mkdir -p dist 144 | rm -rf dist/* 145 | ''' 146 | 147 | yield exec.parallel ''' 148 | cp manifest.json dist 149 | cp -rf assets dist 150 | cp -rf lib dist 151 | cp -rf views dist 152 | ''' 153 | 154 | yield exec ''' 155 | zip -r package.zip dist 156 | rm -rf dist 157 | ''' 158 | ``` 159 | 160 | ### Using Sake with Cake 161 | You can upgrade any Cakefile into a Sakefile by requiring `sake-core` at the top 162 | of your Cakefile. 163 | 164 | #### More 165 | You can peruse Sake's [Sakefile][sakefile] for a real world example. 166 | 167 | ## License 168 | [BSD-3-Clause][license-url] 169 | 170 | [sake-cli]: https://github.com/sakejs/sake-cli 171 | [sakefile]: https://github.com/sakejs/sake-core/blob/master/Sakefile 172 | 173 | [build-img]: https://img.shields.io/travis/sakejs/sake-core.svg 174 | [build-url]: https://travis-ci.org/sakejs/sake-core 175 | [chat-img]: https://badges.gitter.im/join-chat.svg 176 | [chat-url]: https://gitter.im/sakejs/chat 177 | [coverage-img]: https://coveralls.io/repos/sakejs/sake-core/badge.svg?branch=master&service=github 178 | [coverage-url]: https://coveralls.io/github/sakejs/sake-core?branch=master 179 | [dependencies-img]: https://david-dm.org/sakejs/sake-core.svg 180 | [dependencies-url]: https://david-dm.org/sakejs/sake-core 181 | [downloads-img]: https://img.shields.io/npm/dm/sake-core.svg 182 | [downloads-url]: http://badge.fury.io/js/sake-core 183 | [license-img]: https://img.shields.io/npm/l/sake-core.svg 184 | [license-url]: https://github.com/sakejs/sake-core/blob/master/LICENSE 185 | [npm-img]: https://img.shields.io/npm/v/sake-core.svg 186 | [npm-url]: https://www.npmjs.com/package/sake-core 187 | --------------------------------------------------------------------------------