├── 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 |
--------------------------------------------------------------------------------