├── .editorconfig ├── .eslintrc.json ├── .gitattributes ├── .gitignore ├── .travis.yml ├── .verb.md ├── LICENSE ├── README.md ├── docs ├── authoring.md ├── examples.md ├── options.md └── terminology.md ├── examples.js ├── gulpfile.js ├── index.js ├── package.json ├── test ├── fixtures │ ├── a.txt │ ├── a │ │ ├── a.txt │ │ └── aa │ │ │ ├── aa.txt │ │ │ └── aaa │ │ │ └── aaa.txt │ ├── b.txt │ ├── b │ │ ├── alpha.js │ │ ├── beta.js │ │ └── gamma.js │ ├── c.txt │ ├── c │ │ ├── apple.coffee │ │ ├── celery.coffee │ │ └── walnut.coffee │ ├── d.txt │ ├── foo.bar │ │ └── baz.qux │ │ │ ├── fez.faz │ │ │ └── x.y.z │ │ │ └── foo │ ├── one.md │ ├── scaffolds │ │ ├── includes │ │ │ └── include.hbs │ │ ├── layouts │ │ │ └── default.hbs │ │ ├── pages │ │ │ └── index.hbs │ │ ├── posts │ │ │ └── post.md │ │ └── sf.js │ ├── templates │ │ ├── includes │ │ │ └── include.hbs │ │ ├── layouts │ │ │ └── default.hbs │ │ ├── pages │ │ │ └── index.hbs │ │ ├── posts │ │ │ └── post.md │ │ └── sf.js │ ├── three.md │ ├── two.md │ ├── x.js │ ├── y.js │ └── z.js ├── name.js ├── scaffolds │ ├── scripts │ │ └── button.js │ ├── styles │ │ └── button.css │ └── templates │ │ └── button.hbs ├── support │ └── index.js ├── templates │ ├── a.txt │ ├── b.txt │ ├── c.txt │ ├── d.txt │ ├── e.txt │ └── f.txt └── test.js └── utils.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | end_of_line = lf 7 | charset = utf-8 8 | indent_size = 2 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | insert_final_newline = false 15 | 16 | [test/**] 17 | trim_trailing_whitespace = false 18 | insert_final_newline = false 19 | 20 | [templates/**] 21 | trim_trailing_whitespace = false 22 | insert_final_newline = false 23 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "ecmaFeatures": { 3 | "modules": true, 4 | "experimentalObjectRestSpread": true 5 | }, 6 | 7 | "env": { 8 | "browser": false, 9 | "es6": true, 10 | "node": true, 11 | "mocha": true 12 | }, 13 | 14 | "globals": { 15 | "document": false, 16 | "navigator": false, 17 | "window": false 18 | }, 19 | 20 | "rules": { 21 | "accessor-pairs": 2, 22 | "arrow-spacing": [2, { "before": true, "after": true }], 23 | "block-spacing": [2, "always"], 24 | "brace-style": [2, "1tbs", { "allowSingleLine": true }], 25 | "comma-dangle": [2, "never"], 26 | "comma-spacing": [2, { "before": false, "after": true }], 27 | "comma-style": [2, "last"], 28 | "constructor-super": 2, 29 | "curly": [2, "multi-line"], 30 | "dot-location": [2, "property"], 31 | "eol-last": 2, 32 | "eqeqeq": [2, "allow-null"], 33 | "generator-star-spacing": [2, { "before": true, "after": true }], 34 | "handle-callback-err": [2, "^(err|error)$" ], 35 | "indent": [2, 2, { "SwitchCase": 1 }], 36 | "key-spacing": [2, { "beforeColon": false, "afterColon": true }], 37 | "keyword-spacing": [2, { "before": true, "after": true }], 38 | "new-cap": [2, { "newIsCap": true, "capIsNew": false }], 39 | "new-parens": 2, 40 | "no-array-constructor": 2, 41 | "no-caller": 2, 42 | "no-class-assign": 2, 43 | "no-cond-assign": 2, 44 | "no-const-assign": 2, 45 | "no-control-regex": 2, 46 | "no-debugger": 2, 47 | "no-delete-var": 2, 48 | "no-dupe-args": 2, 49 | "no-dupe-class-members": 2, 50 | "no-dupe-keys": 2, 51 | "no-duplicate-case": 2, 52 | "no-empty-character-class": 2, 53 | "no-eval": 2, 54 | "no-ex-assign": 2, 55 | "no-extend-native": 2, 56 | "no-extra-bind": 2, 57 | "no-extra-boolean-cast": 2, 58 | "no-extra-parens": [2, "functions"], 59 | "no-fallthrough": 2, 60 | "no-floating-decimal": 2, 61 | "no-func-assign": 2, 62 | "no-implied-eval": 2, 63 | "no-inner-declarations": [2, "functions"], 64 | "no-invalid-regexp": 2, 65 | "no-irregular-whitespace": 2, 66 | "no-iterator": 2, 67 | "no-label-var": 2, 68 | "no-labels": 2, 69 | "no-lone-blocks": 2, 70 | "no-mixed-spaces-and-tabs": 2, 71 | "no-multi-spaces": 2, 72 | "no-multi-str": 2, 73 | "no-multiple-empty-lines": [2, { "max": 1 }], 74 | "no-native-reassign": 0, 75 | "no-negated-in-lhs": 2, 76 | "no-new": 2, 77 | "no-new-func": 2, 78 | "no-new-object": 2, 79 | "no-new-require": 2, 80 | "no-new-wrappers": 2, 81 | "no-obj-calls": 2, 82 | "no-octal": 2, 83 | "no-octal-escape": 2, 84 | "no-proto": 0, 85 | "no-redeclare": 2, 86 | "no-regex-spaces": 2, 87 | "no-return-assign": 2, 88 | "no-self-compare": 2, 89 | "no-sequences": 2, 90 | "no-shadow-restricted-names": 2, 91 | "no-spaced-func": 2, 92 | "no-sparse-arrays": 2, 93 | "no-this-before-super": 2, 94 | "no-throw-literal": 2, 95 | "no-trailing-spaces": 0, 96 | "no-undef": 2, 97 | "no-undef-init": 2, 98 | "no-unexpected-multiline": 2, 99 | "no-unneeded-ternary": [2, { "defaultAssignment": false }], 100 | "no-unreachable": 2, 101 | "no-unused-vars": [2, { "vars": "all", "args": "none" }], 102 | "no-useless-call": 0, 103 | "no-with": 2, 104 | "one-var": [0, { "initialized": "never" }], 105 | "operator-linebreak": [0, "after", { "overrides": { "?": "before", ":": "before" } }], 106 | "padded-blocks": [0, "never"], 107 | "quotes": [2, "single", "avoid-escape"], 108 | "radix": 2, 109 | "semi": [2, "always"], 110 | "semi-spacing": [2, { "before": false, "after": true }], 111 | "space-before-blocks": [2, "always"], 112 | "space-before-function-paren": [2, "never"], 113 | "space-in-parens": [2, "never"], 114 | "space-infix-ops": 2, 115 | "space-unary-ops": [2, { "words": true, "nonwords": false }], 116 | "spaced-comment": [0, "always", { "markers": ["global", "globals", "eslint", "eslint-disable", "*package", "!", ","] }], 117 | "use-isnan": 2, 118 | "valid-typeof": 2, 119 | "wrap-iife": [2, "any"], 120 | "yoda": [2, "never"] 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Enforce Unix newlines 2 | * text eol=lf 3 | 4 | # binaries 5 | *.ai binary 6 | *.psd binary 7 | *.jpg binary 8 | *.gif binary 9 | *.png binary 10 | *.jpeg binary 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | *.sublime-* 3 | _gh_pages 4 | bower_components 5 | node_modules 6 | npm-debug.log 7 | actual 8 | test/actual 9 | temp 10 | tmp 11 | TODO.md 12 | vendor 13 | .idea 14 | benchmark 15 | coverage 16 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - '5' 5 | - '4' 6 | - '0.12' 7 | - '0.10' 8 | matrix: 9 | fast_finish: true 10 | allow_failures: 11 | - node_js: '4' 12 | - node_js: '0.10' 13 | - node_js: '0.12' 14 | -------------------------------------------------------------------------------- /.verb.md: -------------------------------------------------------------------------------- 1 | [What is a scaffold?](#comparison-table) | [gulp-scaffold-example](https://github.com/jonschlinkert/gulp-scaffold-example) 2 | 3 | The following scaffold expands into a configuration object that can be passed to [gulp][], [grunt][], [assemble][], [metalsmith][], or even [yeoman][] for scaffolding out various parts of a blog or site (like adding a new post, UI component, etc): 4 | 5 | ```js 6 | var Scaffold = require('{%= name %}'); 7 | var scaffold = new Scaffold({ 8 | posts: { 9 | src: 'templates/post.md', 10 | dest: 'blog/' 11 | }, 12 | components: { 13 | cwd: 'content', 14 | src: ['templates/*.hbs'], 15 | dest: 'blog/' 16 | } 17 | }); 18 | ``` 19 | 20 | **Example result** 21 | 22 | The above scaffold might expand into something like the following: 23 | 24 | ```js 25 | { 26 | options: {}, 27 | blog: { 28 | options: {cwd: 'blog'}, 29 | files: [ 30 | { 31 | src: ['content/post.md', 'content/about.md'], 32 | dest: 'src/posts/' 33 | }, 34 | { 35 | src: ['data/ipsum.json'], 36 | dest: 'src/data/' 37 | } 38 | ] 39 | }, 40 | components: { 41 | options: {cwd: 'ui'}, 42 | files: [ 43 | { 44 | options: {cwd: 'templates/layouts'}, 45 | src: ['default.hbs', '3-column.hbs'], 46 | dest: 'src/templates/layouts' 47 | }, 48 | { 49 | options: {cwd: 'templates/components'}, 50 | src: ['button.hbs', 'modal.hbs', 'navbar.hbs'], 51 | dest: 'src/templates/partials' 52 | }, 53 | { 54 | src: ['scripts/button.js'], 55 | dest: 'src/assets/js/' 56 | }, 57 | { 58 | src: ['data/ipsum.json'], 59 | dest: 'src/assets/data/' 60 | } 61 | ] 62 | } 63 | } 64 | ``` 65 | 66 | Since we're just creating an object (with zero application logic), anything can obviously be extended, overridden, etc. 67 | 68 | ## Install 69 | 70 | {%= include("install-npm", {save: true}) %} 71 | 72 | ## Usage 73 | 74 | Create an instance of scaffold: 75 | 76 | ```js 77 | var Scaffold = require('{%= name %}'); 78 | var foo = new Scaffold({ 79 | // config/options here 80 | }); 81 | ``` 82 | 83 | Scaffold uses [expand-target][] and [expand-files][] as dependencies. Visit those projects for the full range of available features and options: 84 | 85 | ## Examples 86 | 87 | The following are just a few random examples of what a scaffold could be, but there are many more use cases. 88 | 89 | **Blog posts** 90 | 91 | Create a scaffold for adding blog posts to a project: 92 | 93 | ```js 94 | var blog = new Scaffold({ 95 | post: { 96 | cwd: 'content', 97 | src: 'content/post.md', 98 | dest: 'src/posts/' 99 | } 100 | }); 101 | ``` 102 | 103 | **UI components** 104 | 105 | Create a scaffold for adding UI components to a project: 106 | 107 | ```js 108 | var components = new Scaffold({ 109 | foo: { 110 | options: {cwd: 'scaffolds'}, 111 | files: [ 112 | {src: 'templates/component.hbs', dest: 'src/templates/'}, 113 | {src: 'scripts/component.js', dest: 'src/scripts/'}, 114 | {src: 'styles/component.css', dest: 'src/styles/'}, 115 | ] 116 | } 117 | }); 118 | ``` 119 | 120 | ## API 121 | {%= apidocs("index.js") %} 122 | 123 | ### Comparison table 124 | 125 | Many definitions exist for the terms "boilerplate", "scaffold" and "template". The following definitions describe these concepts as it relates to this project. 126 | 127 | | **type** | **description** | 128 | | --- | --- | 129 | | [template](https://github.com/jonschlinkert/templates) | Resuable file, code or content which contains "placeholder" values that will eventually be replaced with real values by a rendering (template) engine | 130 | | [scaffold](#{%= name %}) | Consists of one or more templates or source files and serves as a "temporary support structure" that may be used to initialize a new project, or to provide ad-hoc "components" throughout the duration of a project. | 131 | | [boilerplate](https://github.com/boilerplates) | Boilerplates consist of all of the necessary files required to initialize a complete project. | 132 | 133 | ## History 134 | 135 | **v0.3.0** 136 | 137 | - **breaking change**: targets are now stored on the `targets` object 138 | - **feature**: now emits `files` when a files object is expanded. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2016, Jon Schlinkert. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # scaffold [![NPM version](https://img.shields.io/npm/v/scaffold.svg?style=flat)](https://www.npmjs.com/package/scaffold) [![NPM downloads](https://img.shields.io/npm/dm/scaffold.svg?style=flat)](https://npmjs.org/package/scaffold) [![Build Status](https://img.shields.io/travis/jonschlinkert/scaffold.svg?style=flat)](https://travis-ci.org/jonschlinkert/scaffold) 2 | 3 | Conventions and API for creating declarative configuration objects for project scaffolds - similar in format to a grunt task, but more portable, generic and can be used by any build system or generator - even gulp. 4 | 5 | ## Install 6 | 7 | Install with [npm](https://www.npmjs.com/): 8 | 9 | ```sh 10 | $ npm install --save scaffold 11 | ``` 12 | 13 | [What is a scaffold?](#comparison-table) | [gulp-scaffold-example](https://github.com/jonschlinkert/gulp-scaffold-example) 14 | 15 | The following scaffold expands into a configuration object that can be passed to [gulp](http://gulpjs.com), [grunt](http://gruntjs.com/), [assemble](https://github.com/assemble/assemble), [metalsmith](https://github.com/segmentio/metalsmith), or even [yeoman](http://yeoman.io) for scaffolding out various parts of a blog or site (like adding a new post, UI component, etc): 16 | 17 | ```js 18 | var Scaffold = require('scaffold'); 19 | var scaffold = new Scaffold({ 20 | posts: { 21 | src: 'templates/post.md', 22 | dest: 'blog/' 23 | }, 24 | components: { 25 | cwd: 'content', 26 | src: ['templates/*.hbs'], 27 | dest: 'blog/' 28 | } 29 | }); 30 | ``` 31 | 32 | **Example result** 33 | 34 | The above scaffold might expand into something like the following: 35 | 36 | ```js 37 | { 38 | options: {}, 39 | blog: { 40 | options: {cwd: 'blog'}, 41 | files: [ 42 | { 43 | src: ['content/post.md', 'content/about.md'], 44 | dest: 'src/posts/' 45 | }, 46 | { 47 | src: ['data/ipsum.json'], 48 | dest: 'src/data/' 49 | } 50 | ] 51 | }, 52 | components: { 53 | options: {cwd: 'ui'}, 54 | files: [ 55 | { 56 | options: {cwd: 'templates/layouts'}, 57 | src: ['default.hbs', '3-column.hbs'], 58 | dest: 'src/templates/layouts' 59 | }, 60 | { 61 | options: {cwd: 'templates/components'}, 62 | src: ['button.hbs', 'modal.hbs', 'navbar.hbs'], 63 | dest: 'src/templates/partials' 64 | }, 65 | { 66 | src: ['scripts/button.js'], 67 | dest: 'src/assets/js/' 68 | }, 69 | { 70 | src: ['data/ipsum.json'], 71 | dest: 'src/assets/data/' 72 | } 73 | ] 74 | } 75 | } 76 | ``` 77 | 78 | Since we're just creating an object (with zero application logic), anything can obviously be extended, overridden, etc. 79 | 80 | ## Install 81 | 82 | Install with [npm](https://www.npmjs.com/): 83 | 84 | ```sh 85 | $ npm install --save scaffold 86 | ``` 87 | 88 | ## Usage 89 | 90 | Create an instance of scaffold: 91 | 92 | ```js 93 | var Scaffold = require('scaffold'); 94 | var foo = new Scaffold({ 95 | // config/options here 96 | }); 97 | ``` 98 | 99 | Scaffold uses [expand-target](https://github.com/jonschlinkert/expand-target) and [expand-files](https://github.com/jonschlinkert/expand-files) as dependencies. Visit those projects for the full range of available features and options: 100 | 101 | ## Examples 102 | 103 | The following are just a few random examples of what a scaffold could be, but there are many more use cases. 104 | 105 | **Blog posts** 106 | 107 | Create a scaffold for adding blog posts to a project: 108 | 109 | ```js 110 | var blog = new Scaffold({ 111 | post: { 112 | cwd: 'content', 113 | src: 'content/post.md', 114 | dest: 'src/posts/' 115 | } 116 | }); 117 | ``` 118 | 119 | **UI components** 120 | 121 | Create a scaffold for adding UI components to a project: 122 | 123 | ```js 124 | var components = new Scaffold({ 125 | foo: { 126 | options: {cwd: 'scaffolds'}, 127 | files: [ 128 | {src: 'templates/component.hbs', dest: 'src/templates/'}, 129 | {src: 'scripts/component.js', dest: 'src/scripts/'}, 130 | {src: 'styles/component.css', dest: 'src/styles/'}, 131 | ] 132 | } 133 | }); 134 | ``` 135 | 136 | ## API 137 | 138 | ### [Scaffold](index.js#L28) 139 | 140 | Create a new Scaffold with the given `options` 141 | 142 | **Params** 143 | 144 | * `options` **{Object}** 145 | 146 | **Example** 147 | 148 | ```js 149 | var scaffold = new Scaffold({cwd: 'src'}); 150 | scaffold.addTargets({ 151 | site: {src: ['*.hbs']}, 152 | blog: {src: ['*.md']} 153 | }); 154 | ``` 155 | 156 | ### [.isScaffold](index.js#L81) 157 | 158 | Static method, returns `true` if the given value is an instance of `Scaffold` or appears to be a valid `scaffold` configuration object. 159 | 160 | **Params** 161 | 162 | * `val` **{Object}**: The value to check 163 | * `returns` **{Boolean}** 164 | 165 | **Example** 166 | 167 | ```js 168 | Scaffold.isScaffold({}); 169 | //=> false 170 | 171 | var blog = new Scaffold({ 172 | post: { 173 | src: 'content/post.md', 174 | dest: 'src/posts/' 175 | } 176 | }); 177 | Scaffold.isScaffold(blog); 178 | //=> true 179 | ``` 180 | 181 | ### [.addTargets](index.js#L100) 182 | 183 | Add targets to the scaffold, while also normalizing src-dest mappings and expanding glob patterns in each target. 184 | 185 | **Params** 186 | 187 | * `targets` **{Object}**: Object of targets, `options`, or arbitrary properties. 188 | * `returns` **{Object}** 189 | 190 | **Example** 191 | 192 | ```js 193 | scaffold.addTargets({ 194 | site: {src: '*.hbs', dest: 'templates/'}, 195 | docs: {src: '*.md', dest: 'content/'} 196 | }); 197 | ``` 198 | 199 | ### [.addTarget](index.js#L145) 200 | 201 | Add a single target to the scaffold, while also normalizing src-dest mappings and expanding glob patterns in the target. 202 | 203 | **Params** 204 | 205 | * `name` **{String}** 206 | * `config` **{Object}** 207 | * `returns` **{Object}** 208 | 209 | **Example** 210 | 211 | ```js 212 | scaffold.addTarget('foo', { 213 | src: 'templates/*.hbs', 214 | dest: 'site' 215 | }); 216 | 217 | // other configurations are possible 218 | scaffold.addTarget('foo', { 219 | options: {cwd: 'templates'} 220 | files: [ 221 | {src: '*.hbs', dest: 'site'}, 222 | {src: '*.md', dest: 'site'} 223 | ] 224 | }); 225 | ``` 226 | 227 | ### [.Target](index.js#L183) 228 | 229 | Getter/setter for the `Target` constructor to use for creating new targets. 230 | 231 | * `returns` **{Function}**: Returns the `Target` constructor to use for creating new targets. 232 | 233 | **Example** 234 | 235 | ```js 236 | var Target = scaffold.get('Target'); 237 | var target = new Target(); 238 | ``` 239 | 240 | ### [.name](index.js#L219) 241 | 242 | Getter/setter for `scaffold.name`. The `name` property can be set on the options or directly on the instance. 243 | 244 | * `returns` **{Function}**: Returns the `Target` constructor to use for creating new targets. 245 | 246 | **Example** 247 | 248 | ```js 249 | var scaffold = new Scaffold({name: 'foo'}); 250 | console.log(scaffold.name); 251 | //=> 'foo' 252 | 253 | // or 254 | var scaffold = new Scaffold(); 255 | scaffold.options.name = 'bar'; 256 | console.log(scaffold.name); 257 | //=> 'bar' 258 | 259 | // or 260 | var scaffold = new Scaffold(); 261 | scaffold.name = 'baz'; 262 | console.log(scaffold.name); 263 | //=> 'baz' 264 | ``` 265 | 266 | ### Comparison table 267 | 268 | Many definitions exist for the terms "boilerplate", "scaffold" and "template". The following definitions describe these concepts as it relates to this project. 269 | 270 | | **type** | **description** | 271 | | --- | --- | 272 | | [template](https://github.com/jonschlinkert/templates) | Resuable file, code or content which contains "placeholder" values that will eventually be replaced with real values by a rendering (template) engine | 273 | | [scaffold](#scaffold) | Consists of one or more templates or source files and serves as a "temporary support structure" that may be used to initialize a new project, or to provide ad-hoc "components" throughout the duration of a project. | 274 | | [boilerplate](https://github.com/boilerplates) | Boilerplates consist of all of the necessary files required to initialize a complete project. | 275 | 276 | ## History 277 | 278 | **v0.3.0** 279 | 280 | * **breaking change**: targets are now stored on the `targets` object 281 | * **feature**: now emits `files` when a files object is expanded. 282 | 283 | ## Related projects 284 | 285 | You might also be interested in these projects: 286 | 287 | * [assemble](https://www.npmjs.com/package/assemble): Assemble is a powerful, extendable and easy to use static site generator for node.js. Used… [more](https://github.com/assemble/assemble) | [homepage](https://github.com/assemble/assemble "Assemble is a powerful, extendable and easy to use static site generator for node.js. Used by thousands of projects for much more than building websites, Assemble is also used for creating themes, scaffolds, boilerplates, e-books, UI components, API docum") 288 | * [boilerplate](https://www.npmjs.com/package/boilerplate): Tools and conventions for authoring and publishing boilerplates that can be generated by any build… [more](https://github.com/jonschlinkert/boilerplate) | [homepage](https://github.com/jonschlinkert/boilerplate "Tools and conventions for authoring and publishing boilerplates that can be generated by any build system or generator.") 289 | * [generate](https://www.npmjs.com/package/generate): The Santa Claus machine for GitHub projects. Scaffolds out new projects, or creates any kind… [more](https://github.com/generate/generate) | [homepage](https://github.com/generate/generate "The Santa Claus machine for GitHub projects. Scaffolds out new projects, or creates any kind of required file or document from any given templates or source materials.") 290 | * [templates](https://www.npmjs.com/package/templates): System for creating and managing template collections, and rendering templates with any node.js template engine… [more](https://github.com/jonschlinkert/templates) | [homepage](https://github.com/jonschlinkert/templates "System for creating and managing template collections, and rendering templates with any node.js template engine. Can be used as the basis for creating a static site generator or blog framework.") 291 | * [update](https://www.npmjs.com/package/update): Easily keep anything in your project up-to-date by installing the updaters you want to use… [more](https://github.com/update/update) | [homepage](https://github.com/update/update "Easily keep anything in your project up-to-date by installing the updaters you want to use and running `update` in the command line! Update the copyright date, licence type, ensure that a project uses your latest eslint or jshint configuration, remove dep") 292 | * [verb](https://www.npmjs.com/package/verb): Documentation generator for GitHub projects. Verb is extremely powerful, easy to use, and is used… [more](https://github.com/verbose/verb) | [homepage](https://github.com/verbose/verb "Documentation generator for GitHub projects. Verb is extremely powerful, easy to use, and is used on hundreds of projects of all sizes to generate everything from API docs to readmes.") 293 | 294 | ## Contributing 295 | 296 | This document was generated by [verb-readme-generator](https://github.com/verbose/verb-readme-generator) (a [verb](https://github.com/verbose/verb) generator), please don't edit directly. Any changes to the readme must be made in [.verb.md](.verb.md). See [Building Docs](#building-docs). 297 | 298 | Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new). 299 | 300 | Or visit the [verb-readme-generator](https://github.com/verbose/verb-readme-generator) project to submit bug reports or pull requests for the readme layout template. 301 | 302 | ## Building docs 303 | 304 | _(This document was generated by [verb-readme-generator](https://github.com/verbose/verb-readme-generator) (a [verb](https://github.com/verbose/verb) generator), please don't edit the readme directly. Any changes to the readme must be made in [.verb.md](.verb.md).)_ 305 | 306 | Generate readme and API documentation with [verb](https://github.com/verbose/verb): 307 | 308 | ```sh 309 | $ npm install -g verb verb-readme-generator && verb 310 | ``` 311 | 312 | ## Running tests 313 | 314 | Install dev dependencies: 315 | 316 | ```sh 317 | $ npm install -d && npm test 318 | ``` 319 | 320 | ## Author 321 | 322 | **Jon Schlinkert** 323 | 324 | * [github/jonschlinkert](https://github.com/jonschlinkert) 325 | * [twitter/jonschlinkert](http://twitter.com/jonschlinkert) 326 | 327 | ## License 328 | 329 | Copyright © 2016, [Jon Schlinkert](https://github.com/jonschlinkert). 330 | Released under the [MIT license](https://github.com/jonschlinkert/scaffold/blob/master/LICENSE). 331 | 332 | *** 333 | 334 | _This file was generated by [verb](https://github.com/verbose/verb), v0.9.0, on June 26, 2016._ -------------------------------------------------------------------------------- /docs/authoring.md: -------------------------------------------------------------------------------- 1 | # Publishing scaffolds 2 | 3 | > You've authored your first scaffold, now it's time to share your amazing work with the rest of the world! 4 | 5 | ## Tell the world! 6 | 7 | - Add the `scaffold` keyword to `package.json`, `bower.json`, or whatever project manifest is relevant for your project. 8 | - Create a pull request to [let us know about your scaffold](https://github.com/scaffolds/scaffolds/issues/new?title=scaffold-%5Bname%20here%5D&body=I%20created%20a%20new%20scaffold%3A%0A%0A*%20homepage%3A%20%5Bproject%20url%5D%20%0A*%20description%3A%20%5Bscaffold%20description%5D)! 9 | - Tweet about your scaffold! 10 | 11 | ## Good practice 12 | 13 | - In addition to the `scaffold` keyword, a handful of semantically relevant `keywords` in package.json will make your project more likely to show up in NPM searches. 14 | -------------------------------------------------------------------------------- /docs/examples.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ```js 4 | function component(name) { 5 | return new Scaffold(name, { 6 | options: {cwd: 'scaffolds', flatten: true, destBase: }, 7 | src: ['**/component.*'], 8 | rename: function(dest, src, opts) { 9 | return 10 | } 11 | }); 12 | } 13 | ``` 14 | 15 | 16 | ```sh 17 | . 18 | ├── scaffoldfile.js 19 | ├── src/ 20 | │ ├── scripts/ 21 | │ │ └── component.js 22 | │ ├── styles/ 23 | │ │ └── component.css 24 | │ └── templates/ 25 | │ └── component.hbs 26 | └── dest 27 | └── button/ 28 | └── index.css 29 | └── index.hbs 30 | └── index.js 31 | ``` -------------------------------------------------------------------------------- /docs/options.md: -------------------------------------------------------------------------------- 1 | #### process 2 | Type: `Function(content, srcpath)` 3 | 4 | This option is passed to `grunt.file.copy` as an advanced way to control the file contents that are copied. 5 | 6 | *`processContent` has been renamed to `process` and the option name will be removed in the future.* 7 | -------------------------------------------------------------------------------- /docs/terminology.md: -------------------------------------------------------------------------------- 1 | # Terminology and conventions 2 | 3 | ## Overview 4 | 5 | This document describes the terminology and conventions used in this project, to help guide authors in creating effective, reusable scaffolds 6 | 7 | 8 | 9 | ## What is a scaffold? 10 | 11 | There are exceptions to every rule, but as a general rule of thumb effective scaffolds have the following attributes: 12 | 13 | 1. **Temporary support structure** Scaffolds typically consist of one or more templates or source files that serve as a "temporary support structure". In contrast to [boilerplates][boilerplate], which are intended to be used to initialize a project _only_, a scaffold may be used at init, and/or throughout the duration of a project. 14 | 1. **Logically grouped files or templates** Scaffolds consist of one or more templates or source files. 15 | 1. **Generalized code and content.** When code is generalized, other code can be built on top of it to make it more specific. This doesn't mean "generic and boring", it just means that placeholders, templates or even code comments should be used wherever the user will need to make customizations. 16 | 1. **Be specific.** Although the code and content of a scaffold should be generalized, the actual purpose and target audience for the scaffold should be as crystal-clear as possible. 17 | 18 | ### Idiomatic scaffolds 19 | 20 | If you'd like to go above and beyond in creating your scaffold, this section is for you. Here are some of the characteristics of an idiomatic scaffold: 21 | 22 | 1. **Keep it simple.** With few exceptions, the more complicated the scaffold, the less likely it is to be useful to more developers. (_"simple" is not the same as "specific"_) 23 | 1. **Well organized and documented.** Good documentation - and code comments when necessary - make it easier for build systems and generators to consume your scaffold as part of a larger build process. 24 | 1. **Customizable.** Use sensible defaults that can easily be overridden. This allows users to customize style, code and content based on a project-by-project basis. 25 | 1. **Discoverable.** Make it easy for other developers to find and use your scaffold. Read [more about discoverability](./authoring.md) 26 | 27 | ## Reference 28 | 29 | Here is a quick reference comparing the difference between boilerplates, scaffolds and templates. 30 | 31 | | **type** | **description** | 32 | | [template][] | Resuable file, code or content which contains "placeholder" values that will eventually be replaced with real values by a rendering (template) engine | 33 | | [scaffold][] | Consist of one or more templates or source files and serve as a "temporary support structure" that may be used at init, or throughout the duration of a project. | 34 | | [boilerplate][] | Boilerplates consist of all of the necessary files required to initialize a complete project. | 35 | 36 | 37 | {%= reflinks(['boilerplate', 'scaffold', 'template']) %} 38 | -------------------------------------------------------------------------------- /examples.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var gm = require('global-modules'); 3 | var stringify = require('./test/support/'); 4 | var Scaffold = require('./'); 5 | 6 | /** 7 | * UI component 8 | */ 9 | 10 | var npm = new Scaffold({ 11 | options: {a: 'b'}, 12 | component: { 13 | options: { 14 | data: {title: 'Foo'}, 15 | cwd: gm + '/scaffolds-example/scaffolds', 16 | expand: true, 17 | }, 18 | files: [ 19 | {src: 'templates/*.hbs', dest: 'src/'}, 20 | {src: 'scripts/*.js', dest: 'src/'}, 21 | {src: 'styles/*.css', dest: 'src/', options: {data: {title: 'Bar'}}}, 22 | ] 23 | } 24 | }); 25 | console.log(stringify(npm)); 26 | 27 | /** 28 | * Site components 29 | */ 30 | 31 | var site = new Scaffold({ 32 | blog: { 33 | cwd: 'test/scaffolds', 34 | files: [ 35 | {src: 'content/post.md', dest: 'src/posts/'}, 36 | {src: 'scripts/*.js', dest: 'src/scripts/'}, 37 | {src: 'data/ipsum.json', dest: 'src/data/'} 38 | ] 39 | }, 40 | components: { 41 | cwd: 'test/scaffolds', 42 | files: [ 43 | {src: 'content/post.md', dest: 'src/posts/'}, 44 | {src: 'scripts/*.js', dest: 'src/scripts/'}, 45 | {src: 'data/ipsum.json', dest: 'src/data/'} 46 | ] 47 | } 48 | }); 49 | console.log(stringify(site)); 50 | 51 | /** 52 | * Dotfiles 53 | */ 54 | 55 | var dotfiles = new Scaffold({ 56 | root: { 57 | src: '.*', 58 | filter: function(fp) { 59 | return !/DS_Store/.test(fp); 60 | } 61 | } 62 | }); 63 | 64 | console.log(stringify(dotfiles)); 65 | 66 | // `~` tilde expands to the user's home directory 67 | var home = new Scaffold({ 68 | foo: { 69 | options: {cwd: '~/scaffolds'}, 70 | src: ['**/component*'], 71 | dest: 'local/src/' 72 | }, 73 | bar: { 74 | options: {cwd: '~', srcBase: 'scaffolds'}, 75 | src: ['*/component.*'], 76 | dest: 'local/src/' 77 | } 78 | }); 79 | console.log(stringify(home)) 80 | 81 | function component(name) { 82 | var scaffold = {}; 83 | scaffold[name] = { 84 | files: { 85 | src: ['*.js'], 86 | dest: 'src' 87 | }, 88 | rename: function(dest, src, opts) { 89 | return path.join(dest, name, 'index') + path.extname(src); 90 | } 91 | }; 92 | return new Scaffold(scaffold); 93 | } 94 | 95 | console.log(component('foo')); 96 | //=> 'src/foo/index.js' 97 | console.log(component('bar')); 98 | //=> 'src/bar/index.js' 99 | console.log(component('baz')); 100 | //=> 'src/baz/index.js' 101 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | var mocha = require('gulp-mocha'); 5 | var istanbul = require('gulp-istanbul'); 6 | var eslint = require('gulp-eslint'); 7 | 8 | var coverage = ['index.js', 'lib/*.js']; 9 | 10 | gulp.task('coverage', function() { 11 | return gulp.src(coverage) 12 | .pipe(istanbul()) 13 | .pipe(istanbul.hookRequire()); 14 | }); 15 | 16 | gulp.task('mocha', ['coverage'], function() { 17 | return gulp.src('test/*.js') 18 | .pipe(mocha({reporter: 'spec'})) 19 | .pipe(istanbul.writeReports()); 20 | }); 21 | 22 | gulp.task('eslint', function() { 23 | return gulp.src(coverage.concat('test/*.js')) 24 | .pipe(eslint()) 25 | }); 26 | 27 | gulp.task('default', ['mocha', 'eslint']); 28 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * scaffold 3 | * 4 | * Copyright (c) 2015, Jon Schlinkert. 5 | * Licensed under the MIT License. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | var Base = require('base'); 11 | var util = require('expand-utils'); 12 | var utils = require('./utils'); 13 | 14 | /** 15 | * Create a new Scaffold with the given `options` 16 | * 17 | * ```js 18 | * var scaffold = new Scaffold({cwd: 'src'}); 19 | * scaffold.addTargets({ 20 | * site: {src: ['*.hbs']}, 21 | * blog: {src: ['*.md']} 22 | * }); 23 | * ``` 24 | * @param {Object} `options` 25 | * @api public 26 | */ 27 | 28 | function Scaffold(options) { 29 | if (!(this instanceof Scaffold)) { 30 | return new Scaffold(options); 31 | } 32 | 33 | Base.call(this); 34 | this.use(utils.plugins()); 35 | this.is('scaffold'); 36 | 37 | options = options || {}; 38 | this.options = options; 39 | this.targets = {}; 40 | 41 | if (Scaffold.isScaffold(options)) { 42 | this.options = {}; 43 | foward(this, options); 44 | this.addTargets(options); 45 | return this; 46 | } else { 47 | foward(this, options); 48 | } 49 | } 50 | 51 | /** 52 | * Inherit `Base` 53 | */ 54 | 55 | Base.extend(Scaffold); 56 | 57 | /** 58 | * Static method, returns `true` if the given value is an 59 | * instance of `Scaffold` or appears to be a valid `scaffold` 60 | * configuration object. 61 | * 62 | * ```js 63 | * Scaffold.isScaffold({}); 64 | * //=> false 65 | * 66 | * var blog = new Scaffold({ 67 | * post: { 68 | * src: 'content/post.md', 69 | * dest: 'src/posts/' 70 | * } 71 | * }); 72 | * Scaffold.isScaffold(blog); 73 | * //=> true 74 | * ``` 75 | * @static 76 | * @param {Object} `val` The value to check 77 | * @return {Boolean} 78 | * @api public 79 | */ 80 | 81 | Scaffold.isScaffold = function(val) { 82 | return util.isTask(val) || utils.isScaffold(val); 83 | }; 84 | 85 | /** 86 | * Add targets to the scaffold, while also normalizing src-dest mappings and 87 | * expanding glob patterns in each target. 88 | * 89 | * ```js 90 | * scaffold.addTargets({ 91 | * site: {src: '*.hbs', dest: 'templates/'}, 92 | * docs: {src: '*.md', dest: 'content/'} 93 | * }); 94 | * ``` 95 | * @param {Object} `targets` Object of targets, `options`, or arbitrary properties. 96 | * @return {Object} 97 | * @api public 98 | */ 99 | 100 | Scaffold.prototype.addTargets = function(config) { 101 | if (!utils.isObject(config)) { 102 | throw new TypeError('expected an object'); 103 | } 104 | 105 | if (util.isTarget(config)) { 106 | return this.addTarget(config.name, config); 107 | } 108 | 109 | for (var key in config) { 110 | if (config.hasOwnProperty(key)) { 111 | var val = config[key]; 112 | 113 | if (util.isTarget(val)) { 114 | this.addTarget(key, val); 115 | 116 | } else { 117 | this[key] = val; 118 | } 119 | } 120 | } 121 | return this; 122 | }; 123 | 124 | /** 125 | * Add a single target to the scaffold, while also normalizing src-dest mappings and 126 | * expanding glob patterns in the target. 127 | * 128 | * ```js 129 | * scaffold.addTarget('foo', { 130 | * src: 'templates/*.hbs', 131 | * dest: 'site' 132 | * }); 133 | * 134 | * // other configurations are possible 135 | * scaffold.addTarget('foo', { 136 | * options: {cwd: 'templates'} 137 | * files: [ 138 | * {src: '*.hbs', dest: 'site'}, 139 | * {src: '*.md', dest: 'site'} 140 | * ] 141 | * }); 142 | * ``` 143 | * @param {String} `name` 144 | * @param {Object} `config` 145 | * @return {Object} 146 | * @api public 147 | */ 148 | 149 | Scaffold.prototype.addTarget = function(name, config) { 150 | if (typeof name !== 'string') { 151 | throw new TypeError('expected name to be a string'); 152 | } 153 | 154 | if (!utils.isObject(config)) { 155 | throw new TypeError('expected an object'); 156 | } 157 | 158 | var self = this; 159 | var Target = this.get('Target'); 160 | var target = new Target(this.options); 161 | utils.define(target, 'parent', this); 162 | utils.define(target, 'name', name); 163 | utils.define(target, 'key', name); 164 | 165 | target.on('files', function(stage, files) { 166 | utils.define(files, 'parent', target); 167 | self.emit('files', stage, files); 168 | }); 169 | 170 | target.options = utils.extend({}, target.options, config.options); 171 | this.emit('target', target); 172 | this.run(target); 173 | 174 | target.addFiles(config); 175 | this.targets[name] = target; 176 | return target; 177 | }; 178 | 179 | /** 180 | * Getter/setter for the `Target` constructor to use for creating new targets. 181 | * 182 | * ```js 183 | * var Target = scaffold.get('Target'); 184 | * var target = new Target(); 185 | * ``` 186 | * @name .Target 187 | * @return {Function} Returns the `Target` constructor to use for creating new targets. 188 | * @api public 189 | */ 190 | 191 | Object.defineProperty(Scaffold.prototype, 'Target', { 192 | configurable: true, 193 | set: function(Target) { 194 | utils.define(this, '_Target', Target); 195 | }, 196 | get: function() { 197 | return this._Target || this.options.Target || utils.Target; 198 | } 199 | }); 200 | 201 | /** 202 | * Getter/setter for `scaffold.name`. The `name` property can be set on the options or 203 | * directly on the instance. 204 | * 205 | * ```js 206 | * var scaffold = new Scaffold({name: 'foo'}); 207 | * console.log(scaffold.name); 208 | * //=> 'foo' 209 | * 210 | * // or 211 | * var scaffold = new Scaffold(); 212 | * scaffold.options.name = 'bar'; 213 | * console.log(scaffold.name); 214 | * //=> 'bar' 215 | * 216 | * // or 217 | * var scaffold = new Scaffold(); 218 | * scaffold.name = 'baz'; 219 | * console.log(scaffold.name); 220 | * //=> 'baz' 221 | * ``` 222 | * @name .name 223 | * @return {Function} Returns the `Target` constructor to use for creating new targets. 224 | * @api public 225 | */ 226 | 227 | Object.defineProperty(Scaffold.prototype, 'name', { 228 | configurable: true, 229 | set: function(val) { 230 | utils.define(this, '_scaffoldName', val); 231 | }, 232 | get: function() { 233 | return this._scaffoldName || this.options.name; 234 | } 235 | }); 236 | 237 | /** 238 | * Forward events from the scaffold instance to the `Scaffold` constructor 239 | */ 240 | 241 | function foward(app, options) { 242 | if (typeof options.name === 'string') { 243 | app.name = options.name; 244 | delete options.name; 245 | } 246 | Scaffold.emit('scaffold', app); 247 | emit('target', app, Scaffold); 248 | emit('files', app, Scaffold); 249 | } 250 | 251 | /** 252 | * Forward events from emitter `a` to emitter `b` 253 | */ 254 | 255 | function emit(name, a, b) { 256 | a.on(name, b.emit.bind(b, name)); 257 | } 258 | 259 | /** 260 | * Expose `Scaffold` 261 | */ 262 | 263 | module.exports = Scaffold; 264 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "scaffold", 3 | "description": "Conventions and API for creating declarative configuration objects for project scaffolds - similar in format to a grunt task, but more portable, generic and can be used by any build system or generator - even gulp.", 4 | "version": "0.2.13", 5 | "homepage": "https://github.com/jonschlinkert/scaffold", 6 | "author": "Jon Schlinkert (https://github.com/jonschlinkert)", 7 | "repository": "jonschlinkert/scaffold", 8 | "bugs": { 9 | "url": "https://github.com/jonschlinkert/scaffold/issues" 10 | }, 11 | "license": "MIT", 12 | "files": [ 13 | "index.js", 14 | "LICENSE", 15 | "README.md", 16 | "utils.js" 17 | ], 18 | "main": "index.js", 19 | "engines": { 20 | "node": ">=0.10.0" 21 | }, 22 | "scripts": { 23 | "test": "gulp" 24 | }, 25 | "dependencies": { 26 | "base": "^0.11.1", 27 | "base-plugins": "^0.4.13", 28 | "define-property": "^0.2.5", 29 | "expand-target": "^0.6.4", 30 | "expand-utils": "^0.2.2", 31 | "extend-shallow": "^2.0.1", 32 | "is-scaffold": "^0.1.1", 33 | "isobject": "^2.1.0", 34 | "lazy-cache": "^2.0.1" 35 | }, 36 | "devDependencies": { 37 | "global-modules": "^0.2.2", 38 | "gulp": "^3.9.1", 39 | "gulp-eslint": "^2.0.0", 40 | "gulp-format-md": "^0.1.9", 41 | "gulp-istanbul": "^1.0.0", 42 | "gulp-mocha": "^2.2.0", 43 | "mocha": "^2.5.3", 44 | "repeat-string": "^1.5.4", 45 | "should": "^9.0.2", 46 | "stringify-object": "^2.4.0" 47 | }, 48 | "keywords": [ 49 | "app", 50 | "boilerplate", 51 | "boilerplates", 52 | "bootstrap", 53 | "build", 54 | "cli", 55 | "dev", 56 | "development", 57 | "framework", 58 | "generate", 59 | "generator", 60 | "grunt", 61 | "gulpfriendly", 62 | "plugin", 63 | "project", 64 | "scaffold", 65 | "scaffolding", 66 | "skeleton", 67 | "start", 68 | "starter", 69 | "system", 70 | "template", 71 | "tool", 72 | "toolkit", 73 | "yeoman" 74 | ], 75 | "verb": { 76 | "toc": false, 77 | "layout": "default", 78 | "tasks": [ 79 | "readme" 80 | ], 81 | "plugins": [ 82 | "gulp-format-md" 83 | ], 84 | "related": { 85 | "list": [ 86 | "assemble", 87 | "boilerplate", 88 | "generate", 89 | "templates", 90 | "update", 91 | "verb" 92 | ] 93 | }, 94 | "reflinks": [ 95 | "assemble", 96 | "boilerplate", 97 | "expand-files", 98 | "expand-target", 99 | "generate", 100 | "grunt", 101 | "gulp", 102 | "metalsmith", 103 | "scaffold", 104 | "templates", 105 | "verb", 106 | "verb-readme-generator", 107 | "yeoman" 108 | ], 109 | "lint": { 110 | "reflinks": true 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /test/fixtures/a.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boilerplates/scaffold/baa526928d0f7e0bcae266fbaa6174ddf4007a66/test/fixtures/a.txt -------------------------------------------------------------------------------- /test/fixtures/a/a.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boilerplates/scaffold/baa526928d0f7e0bcae266fbaa6174ddf4007a66/test/fixtures/a/a.txt -------------------------------------------------------------------------------- /test/fixtures/a/aa/aa.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boilerplates/scaffold/baa526928d0f7e0bcae266fbaa6174ddf4007a66/test/fixtures/a/aa/aa.txt -------------------------------------------------------------------------------- /test/fixtures/a/aa/aaa/aaa.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boilerplates/scaffold/baa526928d0f7e0bcae266fbaa6174ddf4007a66/test/fixtures/a/aa/aaa/aaa.txt -------------------------------------------------------------------------------- /test/fixtures/b.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boilerplates/scaffold/baa526928d0f7e0bcae266fbaa6174ddf4007a66/test/fixtures/b.txt -------------------------------------------------------------------------------- /test/fixtures/b/alpha.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boilerplates/scaffold/baa526928d0f7e0bcae266fbaa6174ddf4007a66/test/fixtures/b/alpha.js -------------------------------------------------------------------------------- /test/fixtures/b/beta.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boilerplates/scaffold/baa526928d0f7e0bcae266fbaa6174ddf4007a66/test/fixtures/b/beta.js -------------------------------------------------------------------------------- /test/fixtures/b/gamma.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boilerplates/scaffold/baa526928d0f7e0bcae266fbaa6174ddf4007a66/test/fixtures/b/gamma.js -------------------------------------------------------------------------------- /test/fixtures/c.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boilerplates/scaffold/baa526928d0f7e0bcae266fbaa6174ddf4007a66/test/fixtures/c.txt -------------------------------------------------------------------------------- /test/fixtures/c/apple.coffee: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boilerplates/scaffold/baa526928d0f7e0bcae266fbaa6174ddf4007a66/test/fixtures/c/apple.coffee -------------------------------------------------------------------------------- /test/fixtures/c/celery.coffee: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boilerplates/scaffold/baa526928d0f7e0bcae266fbaa6174ddf4007a66/test/fixtures/c/celery.coffee -------------------------------------------------------------------------------- /test/fixtures/c/walnut.coffee: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boilerplates/scaffold/baa526928d0f7e0bcae266fbaa6174ddf4007a66/test/fixtures/c/walnut.coffee -------------------------------------------------------------------------------- /test/fixtures/d.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boilerplates/scaffold/baa526928d0f7e0bcae266fbaa6174ddf4007a66/test/fixtures/d.txt -------------------------------------------------------------------------------- /test/fixtures/foo.bar/baz.qux/fez.faz/x.y.z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boilerplates/scaffold/baa526928d0f7e0bcae266fbaa6174ddf4007a66/test/fixtures/foo.bar/baz.qux/fez.faz/x.y.z -------------------------------------------------------------------------------- /test/fixtures/foo.bar/baz.qux/foo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boilerplates/scaffold/baa526928d0f7e0bcae266fbaa6174ddf4007a66/test/fixtures/foo.bar/baz.qux/foo -------------------------------------------------------------------------------- /test/fixtures/one.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boilerplates/scaffold/baa526928d0f7e0bcae266fbaa6174ddf4007a66/test/fixtures/one.md -------------------------------------------------------------------------------- /test/fixtures/scaffolds/includes/include.hbs: -------------------------------------------------------------------------------- 1 |
2 | -------------------------------------------------------------------------------- /test/fixtures/scaffolds/layouts/default.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{title}} 6 | 7 | 8 | {% body %} 9 | 10 | 11 | -------------------------------------------------------------------------------- /test/fixtures/scaffolds/pages/index.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | layout: <%= layout %> 3 | slug: <%= slug %> 4 | title: <% title %> 5 | --- 6 | 7 | {{title}} 8 | -------------------------------------------------------------------------------- /test/fixtures/scaffolds/posts/post.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: <%= layout %> 3 | slug: <%= slug %> 4 | --- 5 | 6 | {{title}} -------------------------------------------------------------------------------- /test/fixtures/scaffolds/sf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | var Scaffold = require('../../'); 6 | var scaffold = new Scaffold(); 7 | -------------------------------------------------------------------------------- /test/fixtures/templates/includes/include.hbs: -------------------------------------------------------------------------------- 1 |
2 | -------------------------------------------------------------------------------- /test/fixtures/templates/layouts/default.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{title}} 6 | 7 | 8 | {% body %} 9 | 10 | 11 | -------------------------------------------------------------------------------- /test/fixtures/templates/pages/index.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | slug: index 4 | title: Foo 5 | --- 6 | 7 | {{title}} 8 | -------------------------------------------------------------------------------- /test/fixtures/templates/posts/post.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: <%= layout %> 3 | slug: <%= slug %> 4 | --- 5 | 6 | {{title}} -------------------------------------------------------------------------------- /test/fixtures/templates/sf.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var Scaffold = require('../../'); 4 | var scaffold = new Scaffold(); 5 | 6 | 7 | scaffold.create('pages'); 8 | scaffold.create('posts'); 9 | scaffold.create('layouts'); 10 | 11 | scaffold.layouts('docs/scaffolds/layouts/*.hbs'); 12 | 13 | module.exports = scaffold.views; 14 | -------------------------------------------------------------------------------- /test/fixtures/three.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boilerplates/scaffold/baa526928d0f7e0bcae266fbaa6174ddf4007a66/test/fixtures/three.md -------------------------------------------------------------------------------- /test/fixtures/two.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boilerplates/scaffold/baa526928d0f7e0bcae266fbaa6174ddf4007a66/test/fixtures/two.md -------------------------------------------------------------------------------- /test/fixtures/x.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boilerplates/scaffold/baa526928d0f7e0bcae266fbaa6174ddf4007a66/test/fixtures/x.js -------------------------------------------------------------------------------- /test/fixtures/y.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boilerplates/scaffold/baa526928d0f7e0bcae266fbaa6174ddf4007a66/test/fixtures/y.js -------------------------------------------------------------------------------- /test/fixtures/z.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boilerplates/scaffold/baa526928d0f7e0bcae266fbaa6174ddf4007a66/test/fixtures/z.js -------------------------------------------------------------------------------- /test/name.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('mocha'); 4 | require('should'); 5 | var path = require('path'); 6 | var util = require('util'); 7 | var assert = require('assert'); 8 | var Scaffold = require('..'); 9 | var scaffold; 10 | 11 | var cwd = path.resolve.bind(path, __dirname); 12 | 13 | describe('.name', function() { 14 | beforeEach(function() { 15 | scaffold = new Scaffold(); 16 | }); 17 | 18 | it('should get name from ctor options', function() { 19 | var scaffold = new Scaffold({name: 'foo'}); 20 | assert.strictEqual(scaffold.name, 'foo'); 21 | }); 22 | 23 | it('should get name from scaffold.options', function() { 24 | var scaffold = new Scaffold(); 25 | scaffold.options.name = 'foo'; 26 | assert.strictEqual(scaffold.name, 'foo'); 27 | }); 28 | 29 | it('should get name from scaffold.name', function() { 30 | var scaffold = new Scaffold(); 31 | scaffold.name = 'foo'; 32 | assert.strictEqual(scaffold.name, 'foo'); 33 | }); 34 | 35 | it('should get name from another Scaffold instance', function() { 36 | var foo = new Scaffold({name: 'foo'}); 37 | var scaffold = new Scaffold(foo); 38 | scaffold.name = 'foo'; 39 | assert.strictEqual(scaffold.name, 'foo'); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /test/scaffolds/scripts/button.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boilerplates/scaffold/baa526928d0f7e0bcae266fbaa6174ddf4007a66/test/scaffolds/scripts/button.js -------------------------------------------------------------------------------- /test/scaffolds/styles/button.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boilerplates/scaffold/baa526928d0f7e0bcae266fbaa6174ddf4007a66/test/scaffolds/styles/button.css -------------------------------------------------------------------------------- /test/scaffolds/templates/button.hbs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boilerplates/scaffold/baa526928d0f7e0bcae266fbaa6174ddf4007a66/test/scaffolds/templates/button.hbs -------------------------------------------------------------------------------- /test/support/index.js: -------------------------------------------------------------------------------- 1 | var repeat = require('repeat-string'); 2 | var inspect = require('stringify-object'); 3 | 4 | 5 | module.exports = function stringify(config) { 6 | var obj = inspect(config, { 7 | singleQuotes: true, 8 | indent: ' ' 9 | }); 10 | return fixIndent(obj); 11 | }; 12 | 13 | 14 | function fixIndent(str) { 15 | str = indentArray(str); 16 | 17 | var lines = str.split('\n'); 18 | var len = lines.length, i = -1; 19 | 20 | while (++i < len) { 21 | var prev = lines[i - 1]; 22 | var line = lines[i]; 23 | var next = lines[i + 1]; 24 | 25 | if (isBody(line, prev)) { 26 | var lineIndent = indentAmount(line); 27 | var prevIndent = indentAmount(prev); 28 | lines[i] = repeat(' ', prevIndent + 2) + line.trim(); 29 | if (/^\s+}/.test(next)) { 30 | lines[i + 1] = repeat(' ', prevIndent) + next.trim(); 31 | } 32 | } 33 | } 34 | return lines.join('\n'); 35 | } 36 | 37 | function isBody(curr, prev) { 38 | return /^\s*return/.test(curr) && /\{\s*$/.test(prev); 39 | } 40 | 41 | function indentAmount(str) { 42 | var m = str.match(/^(\s+)/); 43 | return m ? m[1].length : 0; 44 | } 45 | 46 | function indentArray(str, n) { 47 | var re = /src: \[[\s\n]+'([^\n\]]+)'[\n\s]+\]/g; 48 | var m; 49 | while (m = re.exec(str)) { 50 | str = str.split(m[0]).join('src: [\'' + m[1] + '\']'); 51 | } 52 | return str; 53 | } 54 | -------------------------------------------------------------------------------- /test/templates/a.txt: -------------------------------------------------------------------------------- 1 | <%= name %> 2 | -------------------------------------------------------------------------------- /test/templates/b.txt: -------------------------------------------------------------------------------- 1 | <%= name %> 2 | -------------------------------------------------------------------------------- /test/templates/c.txt: -------------------------------------------------------------------------------- 1 | <%= name %> 2 | -------------------------------------------------------------------------------- /test/templates/d.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boilerplates/scaffold/baa526928d0f7e0bcae266fbaa6174ddf4007a66/test/templates/d.txt -------------------------------------------------------------------------------- /test/templates/e.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boilerplates/scaffold/baa526928d0f7e0bcae266fbaa6174ddf4007a66/test/templates/e.txt -------------------------------------------------------------------------------- /test/templates/f.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boilerplates/scaffold/baa526928d0f7e0bcae266fbaa6174ddf4007a66/test/templates/f.txt -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('mocha'); 4 | require('should'); 5 | var path = require('path'); 6 | var util = require('util'); 7 | var assert = require('assert'); 8 | var Scaffold = require('..'); 9 | var scaffold; 10 | 11 | var cwd = path.resolve.bind(path, __dirname); 12 | 13 | describe('scaffolds', function() { 14 | beforeEach(function() { 15 | scaffold = new Scaffold(); 16 | }); 17 | 18 | describe('main export', function() { 19 | it('should export a function', function() { 20 | assert.equal(typeof Scaffold, 'function'); 21 | }); 22 | 23 | it('should expose isScaffold', function() { 24 | assert.equal(typeof Scaffold.isScaffold, 'function'); 25 | }); 26 | }); 27 | 28 | describe('instance', function() { 29 | it('should create an instance of scaffold', function() { 30 | assert(scaffold instanceof Scaffold); 31 | }); 32 | 33 | it('should return true if an instance appears to be a scaffold', function() { 34 | assert(Scaffold.isScaffold(scaffold)); 35 | }); 36 | }); 37 | 38 | describe('.options', function() { 39 | it('should support passing a targets configuration on constructor options', function() { 40 | var scaffold = new Scaffold({ 41 | foo: { 42 | cwd: cwd('templates'), 43 | files: [{src: '*.txt', dest: 'foo'}] 44 | } 45 | }); 46 | 47 | assert(scaffold.targets.foo); 48 | assert(Array.isArray(scaffold.targets.foo.files)); 49 | assert(scaffold.targets.foo.files[0].src.length > 1); 50 | }); 51 | 52 | it('should expose an "options" property', function() { 53 | scaffold.addTargets({}); 54 | assert(scaffold.options); 55 | }); 56 | }); 57 | 58 | describe('.addTargets', function() { 59 | it('should expose an addTargets method', function() { 60 | assert.equal(typeof scaffold.addTargets, 'function'); 61 | }); 62 | 63 | it('should add targets to `scaffold`', function() { 64 | scaffold.addTargets({ 65 | foo: {src: '*'}, 66 | bar: {src: '*'} 67 | }); 68 | assert(scaffold.targets.foo); 69 | assert(scaffold.targets.bar); 70 | }); 71 | 72 | it('should expand files arrays', function() { 73 | scaffold.addTargets({ 74 | foo: {src: '*'}, 75 | bar: {src: '*'} 76 | }); 77 | assert(scaffold.targets.foo); 78 | assert(scaffold.targets.bar); 79 | }); 80 | 81 | it('should expand src patterns in targets', function() { 82 | scaffold.addTargets({ 83 | foo: {src: cwd('fixtures/*.md')}, 84 | bar: {src: cwd('fixtures/*.js')} 85 | }); 86 | assert(Array.isArray(scaffold.targets.foo.files)); 87 | assert(Array.isArray(scaffold.targets.foo.files[0].src)); 88 | assert(scaffold.targets.foo.files[0].src.length); 89 | }); 90 | 91 | it('should use scaffold options on targets', function() { 92 | scaffold.addTargets({ 93 | options: {cwd: cwd('fixtures')}, 94 | foo: {src: 'a.*'}, 95 | bar: {src: 'one.*'} 96 | }); 97 | assert.equal(scaffold.targets.foo.files[0].src[0], 'a.txt'); 98 | assert.equal(scaffold.targets.bar.files[0].src[0], 'one.md'); 99 | }); 100 | 101 | it('should retain arbitrary properties on targets', function() { 102 | scaffold.addTargets({ 103 | foo: {src: '*.md', data: {title: 'My Blog'}}, 104 | bar: {src: '*.js'} 105 | }); 106 | assert(scaffold.targets.foo.files[0].data); 107 | assert(scaffold.targets.foo.files[0].data.title); 108 | assert.equal(scaffold.targets.foo.files[0].data.title, 'My Blog'); 109 | }); 110 | }); 111 | 112 | describe('events', function() { 113 | it('should emit `target`', function() { 114 | var count = 0; 115 | 116 | scaffold.on('target', function(target) { 117 | assert(target.isTarget); 118 | count++; 119 | }); 120 | 121 | scaffold.addTargets({ 122 | foo: {src: '*'}, 123 | bar: {src: '*'} 124 | }); 125 | 126 | assert.equal(count, 2); 127 | }); 128 | 129 | it('should emit `files`', function() { 130 | var count = 0; 131 | 132 | scaffold.on('files', function(name, files) { 133 | count++; 134 | }); 135 | 136 | scaffold.addTargets({ 137 | foo: { 138 | files: [{src: ['*']}] 139 | }, 140 | bar: { 141 | files: [{src: ['*']}] 142 | } 143 | }); 144 | 145 | assert.equal(count, 6); 146 | }); 147 | }); 148 | 149 | describe('.use', function() { 150 | it('should use plugins on targets', function() { 151 | scaffold.use(function(config) { 152 | return function fn(node) { 153 | if (config.options.data && !node.data) { 154 | node.data = config.options.data; 155 | } 156 | return fn; 157 | } 158 | }); 159 | 160 | scaffold.addTargets({ 161 | options: {data: {title: 'My Site'}}, 162 | foo: {src: '*.md', data: {title: 'My Blog'}}, 163 | bar: {src: '*.js'} 164 | }); 165 | 166 | assert(scaffold.targets.foo.files[0].data); 167 | assert(scaffold.targets.foo.files[0].data.title); 168 | assert.equal(scaffold.targets.foo.files[0].data.title, 'My Blog'); 169 | 170 | assert(scaffold.targets.bar.options.data); 171 | assert.equal(scaffold.targets.bar.options.data.title, 'My Site'); 172 | assert(scaffold.targets.bar.files[0].data); 173 | assert(scaffold.targets.bar.files[0].data.title); 174 | assert.equal(scaffold.targets.bar.files[0].data.title, 'My Site'); 175 | }); 176 | }); 177 | }); 178 | -------------------------------------------------------------------------------- /utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var utils = require('lazy-cache')(require); 4 | var fn = require; 5 | require = utils; 6 | 7 | /** 8 | * Lazily required module dependencies 9 | */ 10 | 11 | require('base-plugins', 'plugins'); 12 | require('define-property', 'define'); 13 | require('extend-shallow', 'extend'); 14 | require('expand-target', 'Target'); 15 | require('isobject', 'isObject'); 16 | require('is-scaffold'); 17 | require = fn; 18 | 19 | /** 20 | * Expose `utils` modules 21 | */ 22 | 23 | module.exports = utils; 24 | --------------------------------------------------------------------------------