├── .editorconfig ├── .eslintrc.json ├── .gitattributes ├── .gitignore ├── .jshintrc ├── .travis.yml ├── .verb.md ├── LICENSE ├── README.md ├── index.js ├── package.json ├── test ├── app.copy.js ├── app.dest.js ├── app.src.js ├── fixtures │ ├── copy │ │ └── example.txt │ ├── generic │ │ ├── run.dmc │ │ └── test.dmc │ ├── test.coffee │ └── vinyl │ │ ├── bom-utf16be.txt │ │ ├── bom-utf16le.txt │ │ ├── bom-utf8.txt │ │ ├── test-symlink │ │ ├── test-symlink-dir │ │ ├── test.coffee │ │ └── wow │ │ └── suchempty └── support │ ├── ignore.js │ ├── index.js │ └── spy.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 | "new-cap": [2, { "newIsCap": true, "capIsNew": false }], 38 | "new-parens": 2, 39 | "no-array-constructor": 2, 40 | "no-caller": 2, 41 | "no-class-assign": 2, 42 | "no-cond-assign": 2, 43 | "no-const-assign": 2, 44 | "no-control-regex": 2, 45 | "no-debugger": 2, 46 | "no-delete-var": 2, 47 | "no-dupe-args": 2, 48 | "no-dupe-class-members": 2, 49 | "no-dupe-keys": 2, 50 | "no-duplicate-case": 2, 51 | "no-empty-character-class": 2, 52 | "no-empty-label": 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": 2, 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-after-keywords": [2, "always"], 112 | "space-before-blocks": [2, "always"], 113 | "space-before-function-paren": [2, "never"], 114 | "space-before-keywords": [2, "always"], 115 | "space-in-parens": [2, "never"], 116 | "space-infix-ops": 2, 117 | "space-return-throw-case": 2, 118 | "space-unary-ops": [2, { "words": true, "nonwords": false }], 119 | "spaced-comment": [0, "always", { "markers": ["global", "globals", "eslint", "eslint-disable", "*package", "!", ","] }], 120 | "use-isnan": 2, 121 | "valid-typeof": 2, 122 | "wrap-iife": [2, "any"], 123 | "yoda": [2, "never"] 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "asi": false, 3 | "boss": true, 4 | "curly": false, 5 | "eqeqeq": true, 6 | "eqnull": true, 7 | "esnext": true, 8 | "immed": true, 9 | "latedef": false, 10 | "laxbreak": true, 11 | "laxcomma": false, 12 | "mocha": true, 13 | "newcap": true, 14 | "noarg": true, 15 | "node": true, 16 | "sub": true, 17 | "undef": true, 18 | "unused": true 19 | } 20 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - "stable" 5 | - "5" 6 | - "4" 7 | - "0.12" 8 | - "0.10" 9 | matrix: 10 | fast_finish: true 11 | allow_failures: 12 | - node_js: "0.10" 13 | -------------------------------------------------------------------------------- /.verb.md: -------------------------------------------------------------------------------- 1 | ## Usage 2 | 3 | ```js 4 | var fs = require('{%= name %}'); 5 | var base = require('base-methods'); 6 | var app = base(); 7 | 8 | // create your application and add the plugin 9 | app.use(fs()); 10 | 11 | // now you can use `app.src` and `app.dest` 12 | app.src(['foo/*.hbs']) 13 | .pipe(app.dest('site/')); 14 | ``` 15 | 16 | ## API 17 | {%= apidocs("index.js") %} 18 | -------------------------------------------------------------------------------- /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 | # base-fs [![NPM version](https://img.shields.io/npm/v/base-fs.svg?style=flat)](https://www.npmjs.com/package/base-fs) [![NPM downloads](https://img.shields.io/npm/dm/base-fs.svg?style=flat)](https://npmjs.org/package/base-fs) [![Build Status](https://img.shields.io/travis/node-base/base-fs.svg?style=flat)](https://travis-ci.org/node-base/base-fs) 2 | 3 | base-methods plugin that adds vinyl-fs methods to your 'base' application for working with the file system, like src, dest, copy and symlink. 4 | 5 | You might also be interested in [base-fs-conflicts](https://github.com/node-base/base-fs-conflicts). 6 | 7 | ## Install 8 | 9 | Install with [npm](https://www.npmjs.com/): 10 | 11 | ```sh 12 | $ npm install base-fs --save 13 | ``` 14 | 15 | ## Usage 16 | 17 | ```js 18 | var fs = require('base-fs'); 19 | var base = require('base-methods'); 20 | var app = base(); 21 | 22 | // create your application and add the plugin 23 | app.use(fs()); 24 | 25 | // now you can use `app.src` and `app.dest` 26 | app.src(['foo/*.hbs']) 27 | .pipe(app.dest('site/')); 28 | ``` 29 | 30 | ## API 31 | 32 | ### [.src](index.js#L33) 33 | 34 | Glob patterns or filepaths to source files. 35 | 36 | **Params** 37 | 38 | * `glob` **{String|Array}**: Glob patterns or file paths to source files. 39 | * `options` **{Object}**: Options or locals to merge into the context and/or pass to `src` plugins 40 | 41 | **Example** 42 | 43 | ```js 44 | app.src('src/*.hbs', {layout: 'default'}); 45 | ``` 46 | 47 | ### [.symlink](index.js#L49) 48 | 49 | Glob patterns or paths for symlinks. 50 | 51 | **Params** 52 | 53 | * `glob` **{String|Array}** 54 | 55 | **Example** 56 | 57 | ```js 58 | app.symlink('src/**'); 59 | ``` 60 | 61 | ### [.dest](index.js#L65) 62 | 63 | Specify a destination for processed files. 64 | 65 | **Params** 66 | 67 | * `dest` **{String|Function}**: File path or rename function. 68 | * `options` **{Object}**: Options and locals to pass to `dest` plugins 69 | 70 | **Example** 71 | 72 | ```js 73 | app.dest('dist/'); 74 | ``` 75 | 76 | ### [.copy](index.js#L90) 77 | 78 | Copy files with the given glob `patterns` to the specified `dest`. 79 | 80 | **Params** 81 | 82 | * `patterns` **{String|Array}**: Glob patterns of files to copy. 83 | * `dest` **{String|Function}**: Desination directory. 84 | * `returns` **{Stream}**: Stream, to continue processing if necessary. 85 | 86 | **Example** 87 | 88 | ```js 89 | app.task('assets', function(cb) { 90 | app.copy('assets/**', 'dist/') 91 | .on('error', cb) 92 | .on('finish', cb) 93 | }); 94 | ``` 95 | 96 | ## Related projects 97 | 98 | You might also be interested in these projects: 99 | 100 | * [base-data](https://www.npmjs.com/package/base-data): adds a `data` method to base-methods. | [homepage](https://github.com/node-base/base-data) 101 | * [base-option](https://www.npmjs.com/package/base-option): Adds a few options methods to base, like `option`, `enable` and `disable`. See the readme… [more](https://www.npmjs.com/package/base-option) | [homepage](https://github.com/node-base/base-option) 102 | * [base-plugins](https://www.npmjs.com/package/base-plugins): Upgrade's plugin support in base applications to allow plugins to be called any time after… [more](https://www.npmjs.com/package/base-plugins) | [homepage](https://github.com/node-base/base-plugins) 103 | * [base-store](https://www.npmjs.com/package/base-store): Plugin for getting and persisting config values with your base-methods application. Adds a 'store' object… [more](https://www.npmjs.com/package/base-store) | [homepage](https://github.com/node-base/base-store) 104 | 105 | ## Contributing 106 | 107 | This document was generated by [verb](https://github.com/verbose/verb), please don't edit directly. Any changes to the readme must be made in [.verb.md](.verb.md). See [Building Docs](#building-docs). 108 | 109 | Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](https://github.com/node-base/base-fs/issues/new). 110 | 111 | ## Building docs 112 | 113 | Generate readme and API documentation with [verb](https://github.com/verbose/verb): 114 | 115 | ```sh 116 | $ npm install -g verb verb-readme-generator && verb 117 | ``` 118 | 119 | ## Running tests 120 | 121 | Install dev dependencies: 122 | 123 | ```sh 124 | $ npm install -d && npm test 125 | ``` 126 | 127 | ## Author 128 | 129 | **Jon Schlinkert** 130 | 131 | * [github/jonschlinkert](https://github.com/jonschlinkert) 132 | * [twitter/jonschlinkert](http://twitter.com/jonschlinkert) 133 | 134 | ## License 135 | 136 | Copyright © 2016, [Jon Schlinkert](https://github.com/jonschlinkert). 137 | Released under the [MIT license](https://github.com/node-base/base-fs/blob/master/LICENSE). 138 | 139 | *** 140 | 141 | _This file was generated by [verb](https://github.com/verbose/verb), v0.9.0, on May 28, 2016._ -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * base-fs 3 | * 4 | * Copyright (c) 2015, Jon Schlinkert. 5 | * Licensed under the MIT License. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | var utils = require('./utils'); 11 | 12 | /** 13 | * Support using the plugin on `app` or a 14 | * `collection` instance 15 | */ 16 | 17 | module.exports = function(config) { 18 | return function plugin(app) { 19 | if (!utils.isValid(app)) return; 20 | 21 | /** 22 | * Glob patterns or filepaths to source files. 23 | * 24 | * ```js 25 | * app.src('src/*.hbs', {layout: 'default'}); 26 | * ``` 27 | * @name .src 28 | * @param {String|Array} `glob` Glob patterns or file paths to source files. 29 | * @param {Object} `options` Options or locals to merge into the context and/or pass to `src` plugins 30 | * @api public 31 | */ 32 | 33 | this.define('src', function(patterns, options) { 34 | var opts = utils.extend({ allowEmpty: true }, config, this.options, options); 35 | return (this.stream = utils.vfs.src(patterns, opts)); 36 | }); 37 | 38 | /** 39 | * Glob patterns or paths for symlinks. 40 | * 41 | * ```js 42 | * app.symlink('src/**'); 43 | * ``` 44 | * @name .symlink 45 | * @param {String|Array} `glob` 46 | * @api public 47 | */ 48 | 49 | this.define('symlink', function() { 50 | return utils.fs.symlink.apply(this, arguments); 51 | }); 52 | 53 | /** 54 | * Specify a destination for processed files. 55 | * 56 | * ```js 57 | * app.dest('dist/'); 58 | * ``` 59 | * @name .dest 60 | * @param {String|Function} `dest` File path or rename function. 61 | * @param {Object} `options` Options and locals to pass to `dest` plugins 62 | * @api public 63 | */ 64 | 65 | this.define('dest', function(dir, options) { 66 | if (!dir) { 67 | throw new TypeError('expected dest to be a string or function.'); 68 | } 69 | var opts = utils.extend({}, config, this.options, options); 70 | return utils.exhaust(utils.dest(dir, opts)); 71 | }); 72 | 73 | /** 74 | * Copy files with the given glob `patterns` to the specified `dest`. 75 | * 76 | * ```js 77 | * app.task('assets', function(cb) { 78 | * app.copy('assets/**', 'dist/') 79 | * .on('error', cb) 80 | * .on('finish', cb) 81 | * }); 82 | * ``` 83 | * @name .copy 84 | * @param {String|Array} `patterns` Glob patterns of files to copy. 85 | * @param {String|Function} `dest` Desination directory. 86 | * @return {Stream} Stream, to continue processing if necessary. 87 | * @api public 88 | */ 89 | 90 | this.define('copy', function(patterns, dest, options) { 91 | return this.src(patterns, options) 92 | .pipe(this.dest(dest, options)); 93 | }); 94 | 95 | // return plugin if the instance is `app` 96 | if (this.isApp) { 97 | return plugin; 98 | } 99 | }; 100 | }; 101 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "base-fs", 3 | "description": "base-methods plugin that adds vinyl-fs methods to your 'base' application for working with the file system, like src, dest, copy and symlink.", 4 | "version": "0.3.5", 5 | "homepage": "https://github.com/node-base/base-fs", 6 | "author": "Jon Schlinkert (https://github.com/jonschlinkert)", 7 | "repository": "node-base/base-fs", 8 | "bugs": { 9 | "url": "https://github.com/node-base/base-fs/issues" 10 | }, 11 | "license": "MIT", 12 | "files": [ 13 | "index.js", 14 | "utils.js" 15 | ], 16 | "main": "index.js", 17 | "engines": { 18 | "node": ">=0.10.0" 19 | }, 20 | "scripts": { 21 | "test": "mocha" 22 | }, 23 | "dependencies": { 24 | "dest": "^0.3.1", 25 | "extend-shallow": "^2.0.1", 26 | "is-registered": "^0.1.4", 27 | "is-valid-instance": "^0.1.0", 28 | "lazy-cache": "^2.0.1", 29 | "stream-exhaust": "^1.0.1", 30 | "through2": "^2.0.1", 31 | "vinyl-fs": "^2.4.3" 32 | }, 33 | "devDependencies": { 34 | "base": "^0.6.4", 35 | "buffer-equal": "^1.0.0", 36 | "graceful-fs": "^4.1.2", 37 | "gulp-format-md": "^0.1.5", 38 | "mocha": "*", 39 | "rimraf": "^2.5.0", 40 | "should": "*", 41 | "sinon": "^1.17.2", 42 | "vinyl": "^1.1.1" 43 | }, 44 | "keywords": [ 45 | "base", 46 | "baseplugin", 47 | "file", 48 | "fs", 49 | "system", 50 | "vinyl" 51 | ], 52 | "verb": { 53 | "run": true, 54 | "toc": false, 55 | "layout": "default", 56 | "tasks": [ 57 | "readme" 58 | ], 59 | "plugins": [ 60 | "gulp-format-md" 61 | ], 62 | "related": { 63 | "highlight": "base-fs-conflicts", 64 | "list": [ 65 | "base-data", 66 | "base-option", 67 | "base-plugins", 68 | "base-store" 69 | ] 70 | }, 71 | "reflinks": [ 72 | "verb" 73 | ], 74 | "lint": { 75 | "reflinks": true 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /test/app.copy.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('mocha'); 4 | var path = require('path'); 5 | var assert = require('assert'); 6 | var rimraf = require('rimraf'); 7 | var base = require('base'); 8 | var fs = require('..'); 9 | var app; 10 | 11 | var fixtures = path.join(__dirname, 'fixtures/copy/*.txt'); 12 | var outpath = path.join(__dirname, 'out-fixtures'); 13 | 14 | describe('copy()', function() { 15 | beforeEach(function(cb) { 16 | rimraf(outpath, cb); 17 | app = base(); 18 | app.isApp = true; 19 | app.use(fs()); 20 | }); 21 | 22 | afterEach(function(cb) { 23 | rimraf(outpath, cb); 24 | }); 25 | 26 | describe('streams', function() { 27 | it('should copy files', function(cb) { 28 | app.copy(fixtures, path.join(__dirname, 'actual')) 29 | .on('data', function(file) { 30 | assert.equal(typeof file, 'object'); 31 | }) 32 | .on('end', cb); 33 | }); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /test/app.dest.js: -------------------------------------------------------------------------------- 1 | var spies = require('./support/spy'); 2 | var chmodSpy = spies.chmodSpy; 3 | var statSpy = spies.statSpy; 4 | 5 | require('mocha'); 6 | var should = require('should'); 7 | var assert = require('assert'); 8 | var base = require('base'); 9 | var vfs = require('..'); 10 | var app; 11 | 12 | var path = require('path'); 13 | var fs = require('graceful-fs'); 14 | var rimraf = require('rimraf'); 15 | 16 | var bufferStream; 17 | var bufEqual = require('buffer-equal'); 18 | var through = require('through2'); 19 | var File = require('vinyl'); 20 | 21 | var outpath = path.join(__dirname, './out-fixtures'); 22 | 23 | var wipeOut = function(cb) { 24 | app = base(); 25 | app.isApp = true; 26 | app.use(vfs()); 27 | 28 | rimraf(path.join(__dirname, './out-fixtures/'), cb); 29 | spies.setError('false'); 30 | statSpy.reset(); 31 | chmodSpy.reset(); 32 | }; 33 | 34 | var dataWrap = function(fn) { 35 | return function(data, enc, cb) { 36 | fn(data); 37 | cb(); 38 | }; 39 | }; 40 | 41 | var realMode = function(n) { 42 | return n & 07777; 43 | }; 44 | 45 | describe('dest stream', function() { 46 | beforeEach(wipeOut); 47 | afterEach(wipeOut); 48 | 49 | it('should explode on invalid folder (empty)', function(cb) { 50 | var stream; 51 | try { 52 | stream = app.dest(); 53 | } catch (err) { 54 | assert(err && typeof err === 'object'); 55 | should.not.exist(stream); 56 | cb(); 57 | } 58 | }); 59 | 60 | it('should explode on invalid folder (empty string)', function(cb) { 61 | var stream; 62 | try { 63 | stream = app.dest(''); 64 | } catch (err) { 65 | assert(err && typeof err === 'object'); 66 | should.not.exist(stream); 67 | cb(); 68 | } 69 | }); 70 | 71 | it('should pass through writes with cwd', function(cb) { 72 | var inputPath = path.join(__dirname, './fixtures/vinyl/test.coffee'); 73 | var buffered = []; 74 | 75 | var expectedFile = new File({ 76 | base: __dirname, 77 | cwd: __dirname, 78 | path: inputPath, 79 | contents: null 80 | }); 81 | 82 | var onEnd = function() { 83 | buffered.length.should.equal(1); 84 | buffered[0].should.equal(expectedFile); 85 | cb(); 86 | }; 87 | 88 | var stream = app.dest('./out-fixtures/', { 89 | cwd: __dirname 90 | }); 91 | 92 | bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); 93 | stream.pipe(bufferStream); 94 | stream.write(expectedFile); 95 | stream.end(); 96 | }); 97 | 98 | it('should pass through writes with default cwd', function(cb) { 99 | var inputPath = path.join(__dirname, './fixtures/vinyl/test.coffee'); 100 | 101 | var expectedFile = new File({ 102 | base: __dirname, 103 | cwd: __dirname, 104 | path: inputPath, 105 | contents: null 106 | }); 107 | 108 | var onEnd = function() { 109 | buffered.length.should.equal(1); 110 | buffered[0].should.equal(expectedFile); 111 | cb(); 112 | }; 113 | 114 | var stream = app.dest(path.join(__dirname, './out-fixtures/')); 115 | 116 | var buffered = []; 117 | bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); 118 | stream.pipe(bufferStream); 119 | stream.write(expectedFile); 120 | stream.end(); 121 | }); 122 | 123 | it('should not write null files', function(cb) { 124 | var inputPath = path.join(__dirname, './fixtures/vinyl/test.coffee'); 125 | var inputBase = path.join(__dirname, './fixtures/vinyl/'); 126 | var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); 127 | var expectedCwd = __dirname; 128 | var expectedBase = path.join(__dirname, './out-fixtures'); 129 | 130 | var expectedFile = new File({ 131 | base: inputBase, 132 | cwd: __dirname, 133 | path: inputPath, 134 | contents: null 135 | }); 136 | 137 | var onEnd = function() { 138 | buffered.length.should.equal(1); 139 | buffered[0].should.equal(expectedFile); 140 | buffered[0].cwd.should.equal(expectedCwd, 'cwd should have changed'); 141 | buffered[0].base.should.equal(expectedBase, 'base should have changed'); 142 | buffered[0].path.should.equal(expectedPath, 'path should have changed'); 143 | fs.existsSync(expectedPath).should.equal(false); 144 | cb(); 145 | }; 146 | 147 | var stream = app.dest('./out-fixtures/', { 148 | cwd: __dirname 149 | }); 150 | 151 | var buffered = []; 152 | bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); 153 | stream.pipe(bufferStream); 154 | stream.write(expectedFile); 155 | stream.end(); 156 | }); 157 | 158 | it('should write buffer files to the right folder with relative cwd', function(cb) { 159 | var inputPath = path.join(__dirname, './fixtures/vinyl/test.coffee'); 160 | var inputBase = path.join(__dirname, './fixtures/vinyl/'); 161 | var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); 162 | var expectedCwd = __dirname; 163 | var expectedBase = path.join(__dirname, './out-fixtures'); 164 | var expectedContents = fs.readFileSync(inputPath); 165 | 166 | var expectedFile = new File({ 167 | base: inputBase, 168 | cwd: __dirname, 169 | path: inputPath, 170 | contents: expectedContents 171 | }); 172 | 173 | var onEnd = function() { 174 | buffered.length.should.equal(1); 175 | buffered[0].should.equal(expectedFile); 176 | buffered[0].cwd.should.equal(expectedCwd, 'cwd should have changed'); 177 | buffered[0].base.should.equal(expectedBase, 'base should have changed'); 178 | buffered[0].path.should.equal(expectedPath, 'path should have changed'); 179 | fs.existsSync(expectedPath).should.equal(true); 180 | bufEqual(fs.readFileSync(expectedPath), expectedContents).should.equal(true); 181 | cb(); 182 | }; 183 | 184 | var stream = app.dest('./out-fixtures/', { 185 | cwd: path.relative(process.cwd(), __dirname) 186 | }); 187 | 188 | var buffered = []; 189 | bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); 190 | stream.pipe(bufferStream); 191 | stream.write(expectedFile); 192 | stream.end(); 193 | }); 194 | 195 | it('should write buffer files to the right folder with function and relative cwd', function(cb) { 196 | var inputPath = path.join(__dirname, './fixtures/vinyl/test.coffee'); 197 | var inputBase = path.join(__dirname, './fixtures/vinyl/'); 198 | var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); 199 | var expectedCwd = __dirname; 200 | var expectedBase = path.join(__dirname, './out-fixtures'); 201 | var expectedContents = fs.readFileSync(inputPath); 202 | 203 | var expectedFile = new File({ 204 | base: inputBase, 205 | cwd: __dirname, 206 | path: inputPath, 207 | contents: expectedContents 208 | }); 209 | 210 | var onEnd = function() { 211 | buffered.length.should.equal(1); 212 | buffered[0].should.equal(expectedFile); 213 | buffered[0].cwd.should.equal(expectedCwd, 'cwd should have changed'); 214 | buffered[0].base.should.equal(expectedBase, 'base should have changed'); 215 | buffered[0].path.should.equal(expectedPath, 'path should have changed'); 216 | fs.existsSync(expectedPath).should.equal(true); 217 | bufEqual(fs.readFileSync(expectedPath), expectedContents).should.equal(true); 218 | cb(); 219 | }; 220 | 221 | var stream = app.dest(function(file) { 222 | should.exist(file); 223 | file.should.equal(expectedFile); 224 | return './out-fixtures'; 225 | }, { 226 | cwd: path.relative(process.cwd(), __dirname) 227 | }); 228 | 229 | var buffered = []; 230 | bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); 231 | stream.pipe(bufferStream); 232 | stream.write(expectedFile); 233 | stream.end(); 234 | }); 235 | 236 | it('should write buffer files to the right folder', function(cb) { 237 | var inputPath = path.join(__dirname, './fixtures/vinyl/test.coffee'); 238 | var inputBase = path.join(__dirname, './fixtures/vinyl/'); 239 | var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); 240 | var expectedContents = fs.readFileSync(inputPath); 241 | var expectedCwd = __dirname; 242 | var expectedBase = path.join(__dirname, './out-fixtures'); 243 | var expectedMode = 0655; 244 | 245 | var expectedFile = new File({ 246 | base: inputBase, 247 | cwd: __dirname, 248 | path: inputPath, 249 | contents: expectedContents, 250 | stat: { 251 | mode: expectedMode 252 | } 253 | }); 254 | 255 | var onEnd = function() { 256 | buffered.length.should.equal(1); 257 | buffered[0].should.equal(expectedFile); 258 | buffered[0].cwd.should.equal(expectedCwd, 'cwd should have changed'); 259 | buffered[0].base.should.equal(expectedBase, 'base should have changed'); 260 | buffered[0].path.should.equal(expectedPath, 'path should have changed'); 261 | fs.existsSync(expectedPath).should.equal(true); 262 | bufEqual(fs.readFileSync(expectedPath), expectedContents).should.equal(true); 263 | realMode(fs.lstatSync(expectedPath).mode).should.equal(expectedMode); 264 | cb(); 265 | }; 266 | 267 | var stream = app.dest('./out-fixtures/', { 268 | cwd: __dirname 269 | }); 270 | 271 | var buffered = []; 272 | bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); 273 | stream.pipe(bufferStream); 274 | stream.write(expectedFile); 275 | stream.end(); 276 | }); 277 | 278 | it('should write streaming files to the right folder', function(cb) { 279 | var inputPath = path.join(__dirname, './fixtures/vinyl/test.coffee'); 280 | var inputBase = path.join(__dirname, './fixtures/vinyl/'); 281 | var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); 282 | var expectedContents = fs.readFileSync(inputPath); 283 | var expectedCwd = __dirname; 284 | var expectedBase = path.join(__dirname, './out-fixtures'); 285 | var expectedMode = 0655; 286 | 287 | var contentStream = through.obj(); 288 | var expectedFile = new File({ 289 | base: inputBase, 290 | cwd: __dirname, 291 | path: inputPath, 292 | contents: contentStream, 293 | stat: { 294 | mode: expectedMode 295 | } 296 | }); 297 | 298 | var onEnd = function() { 299 | buffered.length.should.equal(1); 300 | buffered[0].should.equal(expectedFile); 301 | buffered[0].cwd.should.equal(expectedCwd, 'cwd should have changed'); 302 | buffered[0].base.should.equal(expectedBase, 'base should have changed'); 303 | buffered[0].path.should.equal(expectedPath, 'path should have changed'); 304 | fs.existsSync(expectedPath).should.equal(true); 305 | bufEqual(fs.readFileSync(expectedPath), expectedContents).should.equal(true); 306 | realMode(fs.lstatSync(expectedPath).mode).should.equal(expectedMode); 307 | cb(); 308 | }; 309 | 310 | var stream = app.dest('./out-fixtures/', { 311 | cwd: __dirname 312 | }); 313 | 314 | var buffered = []; 315 | bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); 316 | stream.pipe(bufferStream); 317 | stream.write(expectedFile); 318 | setTimeout(function() { 319 | contentStream.write(expectedContents); 320 | contentStream.end(); 321 | }, 100); 322 | stream.end(); 323 | }); 324 | 325 | it('should write directories to the right folder', function(cb) { 326 | var inputPath = path.join(__dirname, './fixtures/vinyl/test'); 327 | var inputBase = path.join(__dirname, './fixtures/vinyl/'); 328 | var expectedPath = path.join(__dirname, './out-fixtures/test'); 329 | var expectedCwd = __dirname; 330 | var expectedBase = path.join(__dirname, './out-fixtures'); 331 | var expectedMode = 0655; 332 | 333 | var expectedFile = new File({ 334 | base: inputBase, 335 | cwd: __dirname, 336 | path: inputPath, 337 | contents: null, 338 | stat: { 339 | isDirectory: function() { 340 | return true; 341 | }, 342 | mode: expectedMode 343 | } 344 | }); 345 | 346 | var onEnd = function() { 347 | buffered.length.should.equal(1); 348 | buffered[0].should.equal(expectedFile); 349 | buffered[0].cwd.should.equal(expectedCwd, 'cwd should have changed'); 350 | buffered[0].base.should.equal(expectedBase, 'base should have changed'); 351 | buffered[0].path.should.equal(expectedPath, 'path should have changed'); 352 | fs.existsSync(expectedPath).should.equal(true); 353 | fs.lstatSync(expectedPath).isDirectory().should.equal(true); 354 | realMode(fs.lstatSync(expectedPath).mode).should.equal(expectedMode); 355 | cb(); 356 | }; 357 | 358 | var stream = app.dest('./out-fixtures/', { 359 | cwd: __dirname 360 | }); 361 | 362 | var buffered = []; 363 | bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); 364 | stream.pipe(bufferStream); 365 | stream.write(expectedFile); 366 | stream.end(); 367 | }); 368 | 369 | it('should allow piping multiple dests in streaming mode', function(cb) { 370 | var inputPath1 = path.join(__dirname, './out-fixtures/multiple-first'); 371 | var inputPath2 = path.join(__dirname, './out-fixtures/multiple-second'); 372 | var inputBase = path.join(__dirname, './out-fixtures/'); 373 | var srcPath = path.join(__dirname, './fixtures/vinyl/test.coffee'); 374 | var stream1 = app.dest('./out-fixtures/', { 375 | cwd: __dirname 376 | }); 377 | var stream2 = app.dest('./out-fixtures/', { 378 | cwd: __dirname 379 | }); 380 | var content = fs.readFileSync(srcPath); 381 | var rename = through.obj(function(file, _, next) { 382 | file.path = inputPath2; 383 | this.push(file); 384 | next(); 385 | }); 386 | 387 | stream1.on('data', function(file) { 388 | file.path.should.equal(inputPath1); 389 | }); 390 | 391 | stream1.pipe(rename).pipe(stream2); 392 | stream2.on('data', function(file) { 393 | file.path.should.equal(inputPath2); 394 | }).once('end', function() { 395 | fs.readFileSync(inputPath1, 'utf8').should.equal(content.toString()); 396 | fs.readFileSync(inputPath2, 'utf8').should.equal(content.toString()); 397 | cb(); 398 | }); 399 | 400 | var file = new File({ 401 | base: inputBase, 402 | path: inputPath1, 403 | cwd: __dirname, 404 | contents: content 405 | }); 406 | 407 | stream1.write(file); 408 | stream1.end(); 409 | }); 410 | 411 | it('should write new files with the default user mode', function(cb) { 412 | var inputPath = path.join(__dirname, './fixtures/vinyl/test.coffee'); 413 | var inputBase = path.join(__dirname, './fixtures/vinyl/'); 414 | var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); 415 | var expectedContents = fs.readFileSync(inputPath); 416 | var expectedMode = 0666 & (~process.umask()); 417 | 418 | var expectedFile = new File({ 419 | base: inputBase, 420 | cwd: __dirname, 421 | path: inputPath, 422 | contents: expectedContents, 423 | }); 424 | 425 | var onEnd = function() { 426 | buffered.length.should.equal(1); 427 | buffered[0].should.equal(expectedFile); 428 | fs.existsSync(expectedPath).should.equal(true); 429 | realMode(fs.lstatSync(expectedPath).mode).should.equal(expectedMode); 430 | cb(); 431 | }; 432 | 433 | chmodSpy.reset(); 434 | var stream = app.dest('./out-fixtures/', { 435 | cwd: __dirname 436 | }); 437 | 438 | var buffered = []; 439 | bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); 440 | 441 | stream.pipe(bufferStream); 442 | stream.write(expectedFile); 443 | stream.end(); 444 | }); 445 | 446 | it('should write new files with the specified mode', function(cb) { 447 | var inputPath = path.join(__dirname, './fixtures/vinyl/test.coffee'); 448 | var inputBase = path.join(__dirname, './fixtures/vinyl/'); 449 | var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); 450 | var expectedContents = fs.readFileSync(inputPath); 451 | var expectedMode = 0744; 452 | 453 | var expectedFile = new File({ 454 | base: inputBase, 455 | cwd: __dirname, 456 | path: inputPath, 457 | contents: expectedContents, 458 | }); 459 | 460 | var onEnd = function() { 461 | buffered.length.should.equal(1); 462 | buffered[0].should.equal(expectedFile); 463 | fs.existsSync(expectedPath).should.equal(true); 464 | realMode(fs.lstatSync(expectedPath).mode).should.equal(expectedMode); 465 | cb(); 466 | }; 467 | 468 | chmodSpy.reset(); 469 | var stream = app.dest('./out-fixtures/', { 470 | cwd: __dirname, 471 | mode: expectedMode 472 | }); 473 | 474 | var buffered = []; 475 | bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); 476 | 477 | stream.pipe(bufferStream); 478 | stream.write(expectedFile); 479 | stream.end(); 480 | }); 481 | 482 | it('should update file mode to match the vinyl mode', function(cb) { 483 | var inputPath = path.join(__dirname, './fixtures/vinyl/test.coffee'); 484 | var inputBase = path.join(__dirname, './fixtures/vinyl/'); 485 | var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); 486 | var expectedContents = fs.readFileSync(inputPath); 487 | var expectedBase = path.join(__dirname, './out-fixtures'); 488 | var startMode = 0655; 489 | var expectedMode = 0722; 490 | 491 | var expectedFile = new File({ 492 | base: inputBase, 493 | cwd: __dirname, 494 | path: inputPath, 495 | contents: expectedContents, 496 | stat: { 497 | mode: expectedMode 498 | } 499 | }); 500 | 501 | var onEnd = function() { 502 | assert(chmodSpy.called); 503 | buffered.length.should.equal(1); 504 | buffered[0].should.equal(expectedFile); 505 | fs.existsSync(expectedPath).should.equal(true); 506 | realMode(fs.lstatSync(expectedPath).mode).should.equal(expectedMode); 507 | cb(); 508 | }; 509 | 510 | fs.mkdirSync(expectedBase); 511 | fs.closeSync(fs.openSync(expectedPath, 'w')); 512 | fs.chmodSync(expectedPath, startMode); 513 | 514 | chmodSpy.reset(); 515 | var stream = app.dest('./out-fixtures/', { 516 | cwd: __dirname 517 | }); 518 | 519 | var buffered = []; 520 | bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); 521 | 522 | stream.pipe(bufferStream); 523 | stream.write(expectedFile); 524 | stream.end(); 525 | }); 526 | 527 | it('should use different modes for files and directories', function(cb) { 528 | var inputBase = path.join(__dirname, './fixtures/vinyl'); 529 | var inputPath = path.join(__dirname, './fixtures/vinyl/wow/suchempty'); 530 | var expectedBase = path.join(__dirname, './out-fixtures/wow'); 531 | var expectedDirMode = 0755; 532 | var expectedFileMode = 0655; 533 | 534 | var firstFile = new File({ 535 | base: inputBase, 536 | cwd: __dirname, 537 | path: inputPath, 538 | stat: fs.statSync(inputPath) 539 | }); 540 | 541 | var onEnd = function() { 542 | realMode(fs.lstatSync(expectedBase).mode).should.equal(expectedDirMode); 543 | realMode(buffered[0].stat.mode).should.equal(expectedFileMode); 544 | cb(); 545 | }; 546 | 547 | var stream = app.dest('./out-fixtures/', { 548 | cwd: __dirname, 549 | mode: expectedFileMode, 550 | dirMode: expectedDirMode 551 | }); 552 | 553 | var buffered = []; 554 | bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); 555 | 556 | stream.pipe(bufferStream); 557 | stream.write(firstFile); 558 | stream.end(); 559 | }); 560 | 561 | it('should change to the specified base as string', function(cb) { 562 | var inputBase = path.join(__dirname, './fixtures/vinyl'); 563 | var inputPath = path.join(__dirname, './fixtures/vinyl/wow/suchempty'); 564 | 565 | var firstFile = new File({ 566 | cwd: __dirname, 567 | path: inputPath, 568 | stat: fs.statSync(inputPath) 569 | }); 570 | 571 | var onEnd = function() { 572 | buffered[0].base.should.equal(inputBase); 573 | cb(); 574 | }; 575 | 576 | var stream = app.dest('./out-fixtures/', { 577 | cwd: __dirname, 578 | base: inputBase 579 | }); 580 | 581 | var buffered = []; 582 | bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); 583 | 584 | stream.pipe(bufferStream); 585 | stream.write(firstFile); 586 | stream.end(); 587 | }); 588 | 589 | it('should change to the specified base as function', function(cb) { 590 | var inputBase = path.join(__dirname, './fixtures/vinyl'); 591 | var inputPath = path.join(__dirname, './fixtures/vinyl/wow/suchempty'); 592 | 593 | var firstFile = new File({ 594 | cwd: __dirname, 595 | path: inputPath, 596 | stat: fs.statSync(inputPath) 597 | }); 598 | 599 | var onEnd = function() { 600 | buffered[0].base.should.equal(inputBase); 601 | cb(); 602 | }; 603 | 604 | var stream = app.dest('./out-fixtures/', { 605 | cwd: __dirname, 606 | base: function(file) { 607 | should.exist(file); 608 | file.path.should.equal(inputPath); 609 | return inputBase; 610 | } 611 | }); 612 | 613 | var buffered = []; 614 | bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); 615 | 616 | stream.pipe(bufferStream); 617 | stream.write(firstFile); 618 | stream.end(); 619 | }); 620 | 621 | it('should report IO errors', function(cb) { 622 | var inputPath = path.join(__dirname, './fixtures/vinyl/test.coffee'); 623 | var inputBase = path.join(__dirname, './fixtures/vinyl/'); 624 | var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); 625 | var expectedContents = fs.readFileSync(inputPath); 626 | var expectedBase = path.join(__dirname, './out-fixtures'); 627 | var expectedMode = 0722; 628 | 629 | var expectedFile = new File({ 630 | base: inputBase, 631 | cwd: __dirname, 632 | path: inputPath, 633 | contents: expectedContents, 634 | stat: { 635 | mode: expectedMode 636 | } 637 | }); 638 | 639 | fs.mkdirSync(expectedBase); 640 | fs.closeSync(fs.openSync(expectedPath, 'w')); 641 | fs.chmodSync(expectedPath, 0); 642 | 643 | var stream = app.dest('./out-fixtures/', { 644 | cwd: __dirname 645 | }); 646 | stream.on('error', function(err) { 647 | err.code.should.equal('EACCES'); 648 | cb(); 649 | }); 650 | stream.write(expectedFile); 651 | }); 652 | 653 | it('should report stat errors', function(cb) { 654 | var inputPath = path.join(__dirname, './fixtures/vinyl/test.coffee'); 655 | var inputBase = path.join(__dirname, './fixtures/vinyl/'); 656 | var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); 657 | var expectedContents = fs.readFileSync(inputPath); 658 | var expectedBase = path.join(__dirname, './out-fixtures'); 659 | var expectedMode = 0722; 660 | 661 | var expectedFile = new File({ 662 | base: inputBase, 663 | cwd: __dirname, 664 | path: inputPath, 665 | contents: expectedContents, 666 | stat: { 667 | mode: expectedMode 668 | } 669 | }); 670 | 671 | fs.mkdirSync(expectedBase); 672 | fs.closeSync(fs.openSync(expectedPath, 'w')); 673 | 674 | spies.setError(function(mod, fn) { 675 | if (fn === 'stat' && arguments[2] === expectedPath) { 676 | return new Error('stat error'); 677 | } 678 | }); 679 | 680 | var stream = app.dest('./out-fixtures/', { 681 | cwd: __dirname 682 | }); 683 | stream.on('error', function(err) { 684 | err.message.should.equal('stat error'); 685 | cb(); 686 | }); 687 | stream.write(expectedFile); 688 | }); 689 | 690 | it('should report chmod errors', function(cb) { 691 | var inputPath = path.join(__dirname, './fixtures/vinyl/test.coffee'); 692 | var inputBase = path.join(__dirname, './fixtures/vinyl/'); 693 | var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); 694 | var expectedContents = fs.readFileSync(inputPath); 695 | var expectedBase = path.join(__dirname, './out-fixtures'); 696 | var expectedMode = 0722; 697 | 698 | var expectedFile = new File({ 699 | base: inputBase, 700 | cwd: __dirname, 701 | path: inputPath, 702 | contents: expectedContents, 703 | stat: { 704 | mode: expectedMode 705 | } 706 | }); 707 | 708 | fs.mkdirSync(expectedBase); 709 | fs.closeSync(fs.openSync(expectedPath, 'w')); 710 | 711 | spies.setError(function(mod, fn) { 712 | if (fn === 'chmod' && arguments[2] === expectedPath) { 713 | return new Error('chmod error'); 714 | } 715 | }); 716 | 717 | var stream = app.dest('./out-fixtures/', { 718 | cwd: __dirname 719 | }); 720 | stream.on('error', function(err) { 721 | err.message.should.equal('chmod error'); 722 | cb(); 723 | }); 724 | stream.write(expectedFile); 725 | }); 726 | 727 | it('should not chmod a matching file', function(cb) { 728 | var inputPath = path.join(__dirname, './fixtures/vinyl/test.coffee'); 729 | var inputBase = path.join(__dirname, './fixtures/vinyl/'); 730 | var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); 731 | var expectedContents = fs.readFileSync(inputPath); 732 | var expectedBase = path.join(__dirname, './out-fixtures'); 733 | var expectedMode = 0722; 734 | 735 | var expectedFile = new File({ 736 | base: inputBase, 737 | cwd: __dirname, 738 | path: inputPath, 739 | contents: expectedContents, 740 | stat: { 741 | mode: expectedMode 742 | } 743 | }); 744 | 745 | var expectedCount = 0; 746 | spies.setError(function(mod, fn) { 747 | if (fn === 'stat' && arguments[2] === expectedPath) { 748 | expectedCount++; 749 | } 750 | }); 751 | 752 | var onEnd = function() { 753 | expectedCount.should.equal(1); 754 | assert(!chmodSpy.called); 755 | realMode(fs.lstatSync(expectedPath).mode).should.equal(expectedMode); 756 | cb(); 757 | }; 758 | 759 | fs.mkdirSync(expectedBase); 760 | fs.closeSync(fs.openSync(expectedPath, 'w')); 761 | fs.chmodSync(expectedPath, expectedMode); 762 | 763 | statSpy.reset(); 764 | chmodSpy.reset(); 765 | var stream = app.dest('./out-fixtures/', { 766 | cwd: __dirname 767 | }); 768 | 769 | var buffered = []; 770 | bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); 771 | 772 | stream.pipe(bufferStream); 773 | stream.write(expectedFile); 774 | stream.end(); 775 | }); 776 | 777 | it('should see a file with special chmod (setuid/setgid/sticky) as matching', function(cb) { 778 | var inputPath = path.join(__dirname, './fixtures/vinyl/test.coffee'); 779 | var inputBase = path.join(__dirname, './fixtures/vinyl/'); 780 | var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); 781 | var expectedContents = fs.readFileSync(inputPath); 782 | var expectedBase = path.join(__dirname, './out-fixtures'); 783 | var expectedMode = 03722; 784 | var normalMode = 0722; 785 | 786 | var expectedFile = new File({ 787 | base: inputBase, 788 | cwd: __dirname, 789 | path: inputPath, 790 | contents: expectedContents, 791 | stat: { 792 | mode: normalMode 793 | } 794 | }); 795 | 796 | var expectedCount = 0; 797 | spies.setError(function(mod, fn) { 798 | if (fn === 'stat' && arguments[2] === expectedPath) { 799 | expectedCount++; 800 | } 801 | }); 802 | 803 | var onEnd = function() { 804 | expectedCount.should.equal(1); 805 | assert(!chmodSpy.called); 806 | cb(); 807 | }; 808 | 809 | fs.mkdirSync(expectedBase); 810 | fs.closeSync(fs.openSync(expectedPath, 'w')); 811 | fs.chmodSync(expectedPath, expectedMode); 812 | 813 | statSpy.reset(); 814 | chmodSpy.reset(); 815 | var stream = app.dest('./out-fixtures/', { 816 | cwd: __dirname 817 | }); 818 | 819 | var buffered = []; 820 | bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); 821 | 822 | stream.pipe(bufferStream); 823 | stream.write(expectedFile); 824 | stream.end(); 825 | }); 826 | 827 | it('should not overwrite files with overwrite option set to false', function(cb) { 828 | var inputPath = path.join(__dirname, './fixtures/vinyl/test.coffee'); 829 | var inputBase = path.join(__dirname, './fixtures/vinyl/'); 830 | var inputContents = fs.readFileSync(inputPath); 831 | 832 | var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); 833 | var expectedBase = path.join(__dirname, './out-fixtures'); 834 | var existingContents = 'Lorem Ipsum'; 835 | 836 | var inputFile = new File({ 837 | base: inputBase, 838 | cwd: __dirname, 839 | path: inputPath, 840 | contents: inputContents 841 | }); 842 | 843 | var onEnd = function() { 844 | buffered.length.should.equal(1); 845 | bufEqual(fs.readFileSync(expectedPath), new Buffer(existingContents)).should.equal(true); 846 | cb(); 847 | }; 848 | 849 | // Write expected file which should not be overwritten 850 | fs.mkdirSync(expectedBase); 851 | fs.writeFileSync(expectedPath, existingContents); 852 | 853 | var stream = app.dest('./out-fixtures/', { 854 | cwd: __dirname, 855 | overwrite: false 856 | }); 857 | 858 | var buffered = []; 859 | bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); 860 | stream.pipe(bufferStream); 861 | stream.write(inputFile); 862 | stream.end(); 863 | }); 864 | 865 | it('should overwrite files with overwrite option set to true', function(cb) { 866 | var inputPath = path.join(__dirname, './fixtures/vinyl/test.coffee'); 867 | var inputBase = path.join(__dirname, './fixtures/vinyl/'); 868 | var inputContents = fs.readFileSync(inputPath); 869 | 870 | var expectedPath = path.join(__dirname, './out-fixtures/test.coffee'); 871 | var expectedBase = path.join(__dirname, './out-fixtures'); 872 | var existingContents = 'Lorem Ipsum'; 873 | 874 | var inputFile = new File({ 875 | base: inputBase, 876 | cwd: __dirname, 877 | path: inputPath, 878 | contents: inputContents 879 | }); 880 | 881 | var onEnd = function() { 882 | buffered.length.should.equal(1); 883 | bufEqual(fs.readFileSync(expectedPath), new Buffer(inputContents)).should.equal(true); 884 | cb(); 885 | }; 886 | 887 | // This should be overwritten 888 | fs.mkdirSync(expectedBase); 889 | fs.writeFileSync(expectedPath, existingContents); 890 | 891 | var stream = app.dest('./out-fixtures/', { 892 | cwd: __dirname, 893 | overwrite: true 894 | }); 895 | 896 | var buffered = []; 897 | bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); 898 | stream.pipe(bufferStream); 899 | stream.write(inputFile); 900 | stream.end(); 901 | }); 902 | 903 | it('should create symlinks when the `symlink` attribute is set on the file', function(cb) { 904 | var inputPath = path.join(__dirname, './fixtures/vinyl/test-create-dir-symlink'); 905 | var inputBase = path.join(__dirname, './fixtures/vinyl/'); 906 | var inputRelativeSymlinkPath = 'wow'; 907 | 908 | var expectedPath = path.join(__dirname, './out-fixtures/test-create-dir-symlink'); 909 | 910 | var inputFile = new File({ 911 | base: inputBase, 912 | cwd: __dirname, 913 | path: inputPath, 914 | contents: null, //'' 915 | }); 916 | 917 | // `src()` adds this side-effect with `keepSymlinks` option set to false 918 | inputFile.symlink = inputRelativeSymlinkPath; 919 | 920 | var onEnd = function() { 921 | fs.readlink(buffered[0].path, function() { 922 | buffered[0].symlink.should.equal(inputFile.symlink); 923 | buffered[0].path.should.equal(expectedPath); 924 | cb(); 925 | }); 926 | }; 927 | 928 | var stream = app.dest('./out-fixtures/', { 929 | cwd: __dirname 930 | }); 931 | 932 | var buffered = []; 933 | bufferStream = through.obj(dataWrap(buffered.push.bind(buffered)), onEnd); 934 | stream.pipe(bufferStream); 935 | stream.write(inputFile); 936 | stream.end(); 937 | }); 938 | 939 | it('should emit finish event', function(cb) { 940 | var srcPath = path.join(__dirname, './fixtures/vinyl/test.coffee'); 941 | var stream = app.dest('./out-fixtures/', { 942 | cwd: __dirname 943 | }); 944 | 945 | stream.once('finish', function() { 946 | cb(); 947 | }); 948 | 949 | var file = new File({ 950 | path: srcPath, 951 | cwd: __dirname, 952 | contents: new Buffer("1234567890") 953 | }); 954 | 955 | stream.write(file); 956 | stream.end(); 957 | }); 958 | }); 959 | 960 | describe('dest', function() { 961 | beforeEach(function(cb) { 962 | rimraf(outpath, cb); 963 | app = base(); 964 | app.isApp = true; 965 | app.use(vfs()); 966 | }); 967 | 968 | afterEach(function(cb) { 969 | rimraf(outpath, cb); 970 | }); 971 | 972 | describe('streams', function() { 973 | it('should return a stream', function(cb) { 974 | var stream = app.dest(path.join(__dirname, 'fixtures/')); 975 | should.exist(stream); 976 | should.exist(stream.on); 977 | cb(); 978 | }); 979 | 980 | it('should write files from app.stream', function(cb) { 981 | app.src(path.join(__dirname, 'fixtures/copy/*.txt')); 982 | 983 | var outstream = app.dest(outpath); 984 | app.stream.pipe(outstream); 985 | 986 | outstream.on('error', cb); 987 | outstream.on('data', function(file) { 988 | // data should be re-emitted correctly 989 | should.exist(file); 990 | should.exist(file.path); 991 | should.exist(file.contents); 992 | path.join(file.path, '').should.equal(path.join(outpath, 'example.txt')); 993 | String(file.contents).should.equal('Hello world!'); 994 | }); 995 | outstream.on('end', function() { 996 | fs.readFile(path.join(outpath, 'example.txt'), function(err, contents) { 997 | should.not.exist(err); 998 | should.exist(contents); 999 | String(contents).should.equal('Hello world!'); 1000 | cb(); 1001 | }); 1002 | }); 1003 | }); 1004 | 1005 | it('should return an output stream that writes files', function(cb) { 1006 | var instream = app.src(path.join(__dirname, 'fixtures/copy/*.txt')); 1007 | var outstream = app.dest(outpath); 1008 | instream.pipe(outstream); 1009 | 1010 | outstream.on('error', cb); 1011 | outstream.on('data', function(file) { 1012 | // data should be re-emitted correctly 1013 | should.exist(file); 1014 | should.exist(file.path); 1015 | should.exist(file.contents); 1016 | path.join(file.path, '').should.equal(path.join(outpath, 'example.txt')); 1017 | String(file.contents).should.equal('Hello world!'); 1018 | }); 1019 | 1020 | outstream.on('end', function() { 1021 | fs.readFile(path.join(outpath, 'example.txt'), function(err, contents) { 1022 | should.not.exist(err); 1023 | should.exist(contents); 1024 | String(contents).should.equal('Hello world!'); 1025 | cb(); 1026 | }); 1027 | }); 1028 | }); 1029 | 1030 | it('should return an output stream that does not write non-read files', function(cb) { 1031 | var instream = app.src(path.join(__dirname, 'fixtures/copy/*.txt'), { 1032 | read: false 1033 | }); 1034 | var outstream = app.dest(outpath); 1035 | instream.pipe(outstream); 1036 | 1037 | outstream.on('error', cb); 1038 | outstream.on('data', function(file) { 1039 | // data should be re-emitted correctly 1040 | should.exist(file); 1041 | should.exist(file.path); 1042 | should.not.exist(file.contents); 1043 | path.join(file.path, '').should.equal(path.join(outpath, 'example.txt')); 1044 | }); 1045 | 1046 | outstream.on('end', function() { 1047 | fs.readFile(path.join(outpath, 'example.txt'), function(err, contents) { 1048 | should.exist(err); 1049 | should.not.exist(contents); 1050 | cb(); 1051 | }); 1052 | }); 1053 | }); 1054 | 1055 | it('should return an output stream that writes streaming files', function(cb) { 1056 | var instream = app.src(path.join(__dirname, 'fixtures/copy/*.txt'), { 1057 | buffer: false 1058 | }); 1059 | var outstream = instream.pipe(app.dest(outpath)); 1060 | 1061 | outstream.on('error', cb); 1062 | outstream.on('data', function(file) { 1063 | // data should be re-emitted correctly 1064 | should.exist(file); 1065 | should.exist(file.path); 1066 | should.exist(file.contents); 1067 | path.join(file.path, '').should.equal(path.join(outpath, 'example.txt')); 1068 | }); 1069 | outstream.on('end', function() { 1070 | fs.readFile(path.join(outpath, 'example.txt'), function(err, contents) { 1071 | should.not.exist(err); 1072 | should.exist(contents); 1073 | String(contents).should.equal('Hello world!'); 1074 | cb(); 1075 | }); 1076 | }); 1077 | }); 1078 | 1079 | it('should return an output stream that writes streaming files to new directories', function(cb) { 1080 | testWriteDir({}, cb); 1081 | }); 1082 | 1083 | it('should return an output stream that writes streaming files to new directories (buffer: false)', function(cb) { 1084 | testWriteDir({ 1085 | buffer: false 1086 | }, cb); 1087 | }); 1088 | 1089 | it('should return an output stream that writes streaming files to new directories (read: false)', function(cb) { 1090 | testWriteDir({ 1091 | read: false 1092 | }, cb); 1093 | }); 1094 | 1095 | it('should return an output stream that writes streaming files to new directories (read: false, buffer: false)', function(cb) { 1096 | testWriteDir({ 1097 | buffer: false, 1098 | read: false 1099 | }, cb); 1100 | }); 1101 | 1102 | }); 1103 | 1104 | describe('ext', function() { 1105 | beforeEach(function() { 1106 | app = base(); 1107 | app.isApp = true; 1108 | app.use(vfs()); 1109 | app.set('ext', '.txt'); 1110 | }); 1111 | 1112 | afterEach(function() { 1113 | app.set('ext', '.html'); 1114 | }); 1115 | 1116 | it('should return a stream', function(cb) { 1117 | var stream = app.dest(path.join(__dirname, 'fixtures/')); 1118 | should.exist(stream); 1119 | should.exist(stream.on); 1120 | cb(); 1121 | }); 1122 | 1123 | it('should return an output stream that writes files', function(cb) { 1124 | var instream = app.src(path.join(__dirname, 'fixtures/copy/*.txt')); 1125 | var outstream = app.dest(outpath); 1126 | instream.pipe(outstream); 1127 | 1128 | outstream.on('error', cb); 1129 | outstream.on('data', function(file) { 1130 | // data should be re-emitted correctly 1131 | should.exist(file); 1132 | should.exist(file.path); 1133 | should.exist(file.contents); 1134 | path.join(file.path, '').should.equal(path.join(outpath, 'example.txt')); 1135 | String(file.contents).should.equal('Hello world!'); 1136 | }); 1137 | outstream.on('end', function() { 1138 | fs.readFile(path.join(outpath, 'example.txt'), function(err, contents) { 1139 | should.not.exist(err); 1140 | should.exist(contents); 1141 | String(contents).should.equal('Hello world!'); 1142 | cb(); 1143 | }); 1144 | }); 1145 | }); 1146 | 1147 | it('should return an output stream that does not write non-read files', function(cb) { 1148 | var instream = app.src(path.join(__dirname, 'fixtures/dest/*.txt'), { 1149 | read: false 1150 | }); 1151 | var outstream = app.dest(outpath); 1152 | instream.pipe(outstream); 1153 | 1154 | outstream.on('error', cb); 1155 | outstream.on('data', function(file) { 1156 | // data should be re-emitted correctly 1157 | should.exist(file); 1158 | should.exist(file.path); 1159 | should.not.exist(file.contents); 1160 | path.join(file.path, '').should.equal(path.join(outpath, 'example.txt')); 1161 | }); 1162 | 1163 | outstream.on('end', function() { 1164 | fs.readFile(path.join(outpath, 'example.txt'), function(err, contents) { 1165 | should.exist(err); 1166 | should.not.exist(contents); 1167 | cb(); 1168 | }); 1169 | }); 1170 | }); 1171 | }); 1172 | 1173 | function testWriteDir(srcOptions, cb) { 1174 | var instream = app.src(path.join(__dirname, 'fixtures/generic'), srcOptions); 1175 | var outstream = instream.pipe(app.dest(outpath)); 1176 | 1177 | outstream.on('error', cb); 1178 | outstream.on('data', function(file) { 1179 | // data should be re-emitted correctly 1180 | should.exist(file); 1181 | should.exist(file.path); 1182 | path.join(file.path, '').should.equal(path.join(outpath, './generic')); 1183 | }); 1184 | 1185 | outstream.on('end', function() { 1186 | fs.exists(path.join(outpath, 'generic'), function(exists) { 1187 | /* jshint expr: true */ 1188 | should(exists).be.ok; 1189 | /* jshint expr: false */ 1190 | cb(); 1191 | }); 1192 | }); 1193 | } 1194 | }); 1195 | -------------------------------------------------------------------------------- /test/app.src.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var assert = require('assert'); 5 | var should = require('should'); 6 | var base = require('base'); 7 | var fs = require('..'); 8 | var app; 9 | 10 | describe('src()', function() { 11 | beforeEach(function() { 12 | app = base(); 13 | app.isApp = true; 14 | app.use(fs()); 15 | }); 16 | 17 | it('should return a stream', function(cb) { 18 | var stream = app.src(path.join(__dirname, 'fixtures/*.coffee')); 19 | assert(stream); 20 | assert.equal(typeof stream.on, 'function'); 21 | assert.equal(typeof stream.pipe, 'function'); 22 | cb(); 23 | }); 24 | 25 | it('should return an input stream from a flat glob', function(cb) { 26 | var stream = app.src(path.join(__dirname, 'fixtures/*.coffee')); 27 | stream.on('error', cb); 28 | stream.on('data', function(file) { 29 | should.exist(file); 30 | should.exist(file.path); 31 | should.exist(file.contents); 32 | path.join(file.path, '').should.equal(path.join(__dirname, 'fixtures/test.coffee')); 33 | String(file.contents).should.equal('Hello world!'); 34 | }); 35 | stream.on('end', function() { 36 | cb(); 37 | }); 38 | }); 39 | 40 | it('should return an input stream for multiple globs', function(cb) { 41 | var globArray = [ 42 | path.join(__dirname, 'fixtures/generic/run.dmc'), 43 | path.join(__dirname, 'fixtures/generic/test.dmc') 44 | ]; 45 | var stream = app.src(globArray); 46 | 47 | var files = []; 48 | stream.on('error', cb); 49 | stream.on('data', function(file) { 50 | should.exist(file); 51 | should.exist(file.path); 52 | files.push(file); 53 | }); 54 | stream.on('end', function() { 55 | files.length.should.equal(2); 56 | files[0].path.should.equal(globArray[0]); 57 | files[1].path.should.equal(globArray[1]); 58 | cb(); 59 | }); 60 | }); 61 | 62 | it('should return an input stream for multiple globs with negation', function(cb) { 63 | var expectedPath = path.join(__dirname, 'fixtures/generic/run.dmc'); 64 | var globArray = [ 65 | path.join(__dirname, 'fixtures/generic/*.dmc'), 66 | '!' + path.join(__dirname, 'fixtures/generic/test.dmc'), 67 | ]; 68 | var stream = app.src(globArray); 69 | 70 | var files = []; 71 | stream.on('error', cb); 72 | stream.on('data', function(file) { 73 | should.exist(file); 74 | should.exist(file.path); 75 | files.push(file); 76 | }); 77 | stream.on('end', function() { 78 | files.length.should.equal(1); 79 | files[0].path.should.equal(expectedPath); 80 | cb(); 81 | }); 82 | }); 83 | 84 | it('should return an input stream with no contents when read is false', function(cb) { 85 | var stream = app.src(path.join(__dirname, 'fixtures/*.coffee'), {read: false}); 86 | stream.on('error', cb); 87 | stream.on('data', function(file) { 88 | should.exist(file); 89 | should.exist(file.path); 90 | should.not.exist(file.contents); 91 | path.join(file.path, '').should.equal(path.join(__dirname, 'fixtures/test.coffee')); 92 | }); 93 | stream.on('end', function() { 94 | cb(); 95 | }); 96 | }); 97 | 98 | it('should return an input stream with contents as stream when buffer is false', function(cb) { 99 | var stream = app.src(path.join(__dirname, 'fixtures/*.coffee'), {buffer: false}); 100 | stream.on('error', cb); 101 | stream.on('data', function(file) { 102 | should.exist(file); 103 | should.exist(file.path); 104 | should.exist(file.contents); 105 | var buf = ''; 106 | file.contents.on('data', function(d) { 107 | buf += d; 108 | }); 109 | file.contents.on('end', function() { 110 | buf.should.equal('Hello world!'); 111 | cb(); 112 | }); 113 | path.join(file.path, '').should.equal(path.join(__dirname, 'fixtures/test.coffee')); 114 | }); 115 | }); 116 | 117 | it('should return an input stream from a deep glob', function(cb) { 118 | var stream = app.src(path.join(__dirname, 'fixtures/**/*.jade')); 119 | stream.on('error', cb); 120 | stream.on('data', function(file) { 121 | should.exist(file); 122 | should.exist(file.path); 123 | should.exist(file.contents); 124 | path.join(file.path, '').should.equal(path.join(__dirname, 'fixtures/test/run.jade')); 125 | String(file.contents).should.equal('test template'); 126 | }); 127 | stream.on('end', function() { 128 | cb(); 129 | }); 130 | }); 131 | 132 | it('should return an input stream from a deeper glob', function(cb) { 133 | var stream = app.src(path.join(__dirname, 'fixtures/**/*.dmc')); 134 | var a = 0; 135 | stream.on('error', cb); 136 | stream.on('data', function() { 137 | ++a; 138 | }); 139 | stream.on('end', function() { 140 | a.should.equal(2); 141 | cb(); 142 | }); 143 | }); 144 | 145 | it('should return a file stream from a flat path', function(cb) { 146 | var a = 0; 147 | var stream = app.src(path.join(__dirname, 'fixtures/test.coffee')); 148 | stream.on('error', cb); 149 | stream.on('data', function(file) { 150 | ++a; 151 | should.exist(file); 152 | should.exist(file.path); 153 | should.exist(file.contents); 154 | path.join(file.path, '').should.equal(path.join(__dirname, 'fixtures/test.coffee')); 155 | String(file.contents).should.equal('Hello world!'); 156 | }); 157 | stream.on('end', function() { 158 | a.should.equal(1); 159 | cb(); 160 | }); 161 | }); 162 | 163 | it('should return a stream', function(cb) { 164 | var stream = app.src(path.join(__dirname, 'fixtures/*.coffee')); 165 | should.exist(stream); 166 | should.exist(stream.on); 167 | cb(); 168 | }); 169 | 170 | it('should return an input stream from a flat glob', function(cb) { 171 | var stream = app.src(path.join(__dirname, 'fixtures/*.coffee')); 172 | stream.on('error', cb); 173 | stream.on('data', function(file) { 174 | should.exist(file); 175 | should.exist(file.path); 176 | should.exist(file.contents); 177 | path.join(file.path, '').should.equal(path.join(__dirname, 'fixtures/test.coffee')); 178 | String(file.contents).should.equal('Hello world!'); 179 | }); 180 | stream.on('end', function() { 181 | cb(); 182 | }); 183 | }); 184 | 185 | it('should return an input stream for multiple globs', function(cb) { 186 | var globArray = [ 187 | path.join(__dirname, 'fixtures/generic/run.dmc'), 188 | path.join(__dirname, 'fixtures/generic/test.dmc') 189 | ]; 190 | var stream = app.src(globArray); 191 | 192 | var files = []; 193 | stream.on('error', cb); 194 | stream.on('data', function(file) { 195 | should.exist(file); 196 | should.exist(file.path); 197 | files.push(file); 198 | }); 199 | stream.on('end', function() { 200 | files.length.should.equal(2); 201 | files[0].path.should.equal(globArray[0]); 202 | files[1].path.should.equal(globArray[1]); 203 | cb(); 204 | }); 205 | }); 206 | 207 | it('should return an input stream for multiple globs, with negation', function(cb) { 208 | var expectedPath = path.join(__dirname, 'fixtures/generic/run.dmc'); 209 | var globArray = [ 210 | path.join(__dirname, 'fixtures/generic/*.dmc'), 211 | '!' + path.join(__dirname, 'fixtures/generic/test.dmc'), 212 | ]; 213 | var stream = app.src(globArray); 214 | 215 | var files = []; 216 | stream.on('error', cb); 217 | stream.on('data', function(file) { 218 | should.exist(file); 219 | should.exist(file.path); 220 | files.push(file); 221 | }); 222 | stream.on('end', function() { 223 | files.length.should.equal(1); 224 | files[0].path.should.equal(expectedPath); 225 | cb(); 226 | }); 227 | }); 228 | 229 | it('should return an input stream with no contents when read is false', function(cb) { 230 | var stream = app.src(path.join(__dirname, 'fixtures/*.coffee'), {read: false}); 231 | stream.on('error', cb); 232 | stream.on('data', function(file) { 233 | should.exist(file); 234 | should.exist(file.path); 235 | should.not.exist(file.contents); 236 | path.join(file.path, '').should.equal(path.join(__dirname, 'fixtures/test.coffee')); 237 | }); 238 | stream.on('end', function() { 239 | cb(); 240 | }); 241 | }); 242 | 243 | it('should return an input stream from a deep glob', function(cb) { 244 | app.src(path.join(__dirname, 'fixtures/**/*.jade')) 245 | .on('error', cb) 246 | .on('data', function(file) { 247 | should.exist(file); 248 | should.exist(file.path); 249 | should.exist(file.contents); 250 | path.join(file.path, '').should.equal(path.join(__dirname, 'fixtures/test/run.jade')); 251 | String(file.contents).should.equal('test template'); 252 | }) 253 | .on('end', function() { 254 | cb(); 255 | }); 256 | }); 257 | 258 | it('should return an input stream from a deeper glob', function(cb) { 259 | var stream = app.src(path.join(__dirname, 'fixtures/**/*.dmc')); 260 | var a = 0; 261 | stream.on('error', cb); 262 | stream.on('data', function() { 263 | ++a; 264 | }); 265 | stream.on('end', function() { 266 | a.should.equal(2); 267 | cb(); 268 | }); 269 | }); 270 | 271 | it('should return a file stream from a flat path', function(cb) { 272 | var a = 0; 273 | var stream = app.src(path.join(__dirname, 'fixtures/test.coffee')); 274 | stream.on('error', cb); 275 | stream.on('data', function(file) { 276 | ++a; 277 | should.exist(file); 278 | should.exist(file.path); 279 | should.exist(file.contents); 280 | path.join(file.path, '').should.equal(path.join(__dirname, 'fixtures/test.coffee')); 281 | String(file.contents).should.equal('Hello world!'); 282 | }); 283 | stream.on('end', function() { 284 | a.should.equal(1); 285 | cb(); 286 | }); 287 | }); 288 | }); 289 | -------------------------------------------------------------------------------- /test/fixtures/copy/example.txt: -------------------------------------------------------------------------------- 1 | Hello world! -------------------------------------------------------------------------------- /test/fixtures/generic/run.dmc: -------------------------------------------------------------------------------- 1 | # run.dmc -------------------------------------------------------------------------------- /test/fixtures/generic/test.dmc: -------------------------------------------------------------------------------- 1 | # test.dmc -------------------------------------------------------------------------------- /test/fixtures/test.coffee: -------------------------------------------------------------------------------- 1 | Hello world! -------------------------------------------------------------------------------- /test/fixtures/vinyl/bom-utf16be.txt: -------------------------------------------------------------------------------- 1 | This file is saved as UTF-16-BE. It contains some garbage at the start that looks like a UTF-8-encoded BOM (but isn t). 2 | -------------------------------------------------------------------------------- /test/fixtures/vinyl/bom-utf16le.txt: -------------------------------------------------------------------------------- 1 | This file is saved as UTF-16-LE. It contains some garbage at the start that looks like a UTF-8-encoded BOM (but isn t). 2 | -------------------------------------------------------------------------------- /test/fixtures/vinyl/bom-utf8.txt: -------------------------------------------------------------------------------- 1 | This file is saved as UTF-8 with BOM. 𝌆 2 | -------------------------------------------------------------------------------- /test/fixtures/vinyl/test-symlink: -------------------------------------------------------------------------------- 1 | test.coffee -------------------------------------------------------------------------------- /test/fixtures/vinyl/test-symlink-dir: -------------------------------------------------------------------------------- 1 | wow -------------------------------------------------------------------------------- /test/fixtures/vinyl/test.coffee: -------------------------------------------------------------------------------- 1 | Hello world! -------------------------------------------------------------------------------- /test/fixtures/vinyl/wow/suchempty: -------------------------------------------------------------------------------- 1 | suchempty -------------------------------------------------------------------------------- /test/support/ignore.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | 'addEventListener', 3 | 'removeEventListener', 4 | 'removeAllListeners', 5 | 'removeListener' 6 | ]; -------------------------------------------------------------------------------- /test/support/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var assert = require('assert'); 4 | var ignore = require('./ignore'); 5 | 6 | exports.containEql = function containEql(actual, expected) { 7 | if (Array.isArray(expected)) { 8 | var len = expected.length; 9 | while (len--) { 10 | exports.containEql(actual[len], expected[len]); 11 | } 12 | } else { 13 | for (var key in expected) { 14 | assert.deepEqual(actual[key], expected[key]); 15 | } 16 | } 17 | }; 18 | 19 | exports.keys = function keys(obj) { 20 | var arr = []; 21 | for (var key in obj) { 22 | if (ignore.indexOf(key) === -1) { 23 | arr.push(key); 24 | } 25 | } 26 | return arr; 27 | }; 28 | -------------------------------------------------------------------------------- /test/support/spy.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var sinon = require('sinon'); 3 | 4 | var errorfn = false; 5 | 6 | function maybeCallAsync(module, func) { 7 | var original = module[func]; 8 | return sinon.stub(module, func, function() { 9 | var args = Array.prototype.slice.call(arguments); 10 | args.unshift(module, func); 11 | var err = typeof errorfn === 'function' && 12 | errorfn.apply(this, args); 13 | if (!err) { 14 | original.apply(this, arguments); 15 | } else { 16 | arguments[arguments.length - 1](err); 17 | } 18 | }); 19 | } 20 | 21 | module.exports = { 22 | setError: function(fn) { 23 | errorfn = fn; 24 | }, 25 | chmodSpy: maybeCallAsync(fs, 'chmod'), 26 | statSpy: maybeCallAsync(fs, 'stat') 27 | }; 28 | -------------------------------------------------------------------------------- /utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Lazily required module dependencies 5 | */ 6 | 7 | var utils = require('lazy-cache')(require); 8 | var fn = require; 9 | 10 | require = utils; 11 | require('dest'); 12 | require('is-registered'); 13 | require('is-valid-instance'); 14 | require('stream-exhaust', 'exhaust'); 15 | require('extend-shallow', 'extend'); 16 | require('through2', 'through'); 17 | require('vinyl-fs', 'vfs'); 18 | require = fn; 19 | 20 | /** 21 | * Utils 22 | */ 23 | 24 | utils.isValid = function(app) { 25 | if (!utils.isValidInstance(app, ['app', 'collection', 'list', 'views'])) { 26 | return false; 27 | } 28 | if (utils.isRegistered(app, 'base-fs')) { 29 | return false; 30 | } 31 | return true; 32 | }; 33 | 34 | /** 35 | * Expose `utils` 36 | */ 37 | 38 | module.exports = utils; 39 | --------------------------------------------------------------------------------