├── .editorconfig ├── .eslintrc ├── .gitattributes ├── .gitignore ├── .travis.yml ├── .verb.md ├── LICENSE ├── README.md ├── bower.json ├── index.js ├── package.json ├── test ├── fixtures │ ├── foo.md │ ├── test.json │ ├── test.txt │ └── test.yaml ├── fs.async.js ├── fs.js ├── mocha.opts └── path.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: -------------------------------------------------------------------------------- 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 | *.css text eol=lf 4 | *.html text eol=lf 5 | *.js text eol=lf 6 | *.json text eol=lf 7 | *.less text eol=lf 8 | *.md text eol=lf 9 | *.yml text eol=lf 10 | 11 | *.jpg binary 12 | *.gif binary 13 | *.png binary 14 | *.jpeg binary -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | 4 | *.rar 5 | *.zip 6 | tmp 7 | temp 8 | TODO.md 9 | 10 | *.sublime-* 11 | lib 12 | vendor -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - "stable" 5 | - "0.12" 6 | - "0.10" 7 | matrix: 8 | fast_finish: true 9 | allow_failures: 10 | - node_js: "0.10" 11 | -------------------------------------------------------------------------------- /.verb.md: -------------------------------------------------------------------------------- 1 | # {%= name %} {%= badge("fury") %} 2 | 3 | > {%= description %} 4 | 5 | ## Install 6 | {%= include("install-npm", {save: true}) %} 7 | 8 | ## Usage 9 | 10 | ```js 11 | var fs = require('{%= name %}'); 12 | ``` 13 | 14 | ## API 15 | {%= apidocs("index.js") %} 16 | 17 | ## Related projects 18 | {%= related(verb.related.list) %} 19 | 20 | ## Running tests 21 | {%= include("tests") %} 22 | 23 | ## Contributing 24 | {%= include("contributing") %} 25 | 26 | ## Author 27 | {%= include("author") %} 28 | 29 | ## License 30 | {%= copyright() %} 31 | {%= license() %} 32 | 33 | *** 34 | 35 | {%= include("footer") %} 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2015, Jon Schlinkert, Brian Woodward. 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 | # fs-utils [![NPM version](https://badge.fury.io/js/fs-utils.svg)](http://badge.fury.io/js/fs-utils) 2 | 3 | > fs extras and utilities to extend the node.js file system module. Used in Assemble and many other projects. 4 | 5 | ## Install 6 | 7 | Install with [npm](https://www.npmjs.com/) 8 | 9 | ```sh 10 | $ npm i fs-utils --save 11 | ``` 12 | 13 | ## Usage 14 | 15 | ```js 16 | var fs = require('fs-utils'); 17 | ``` 18 | 19 | ## API 20 | 21 | ### [.stripCR](index.js#L24) 22 | 23 | Strip carriage returns from a string. 24 | 25 | **Params** 26 | 27 | * `str` **{String}** 28 | * `returns` **{String}** 29 | 30 | ### [.stripBOM](index.js#L38) 31 | 32 | Strip byte order marks from a string. 33 | 34 | See [BOM](http://en.wikipedia.org/wiki/Byte_order_mark) 35 | 36 | **Params** 37 | 38 | * `str` **{String}** 39 | * `returns` **{String}** 40 | 41 | ### [.slashify](index.js#L51) 42 | 43 | Normalize all slashes to forward slashes. 44 | 45 | **Params** 46 | 47 | * `str` **{String}** 48 | * `stripTrailing` **{Boolean}**: False by default. 49 | * `returns` **{String}** 50 | 51 | ### [.isEmptyFile](index.js#L94) 52 | 53 | Return `true` if the file exists and is empty. 54 | 55 | **Params** 56 | 57 | * `filepath` **{String}** 58 | * `returns` **{Boolean}** 59 | 60 | ### [.isEmptyDir](index.js#L110) 61 | 62 | Return `true` if the file exists and is empty. 63 | 64 | **Params** 65 | 66 | * `filepath` **{String}** 67 | * `returns` **{Boolean}** 68 | 69 | ### [.isDir](index.js#L126) 70 | 71 | Return `true` if the filepath is a directory. 72 | 73 | **Params** 74 | 75 | * `filepath` **{String}** 76 | * `returns` **{Boolean}** 77 | 78 | ### [.isLink](index.js#L157) 79 | 80 | True if the filepath is a symbolic link. 81 | 82 | **Params** 83 | 84 | * `filepath` **{String}** 85 | * `returns` **{Boolean}** 86 | 87 | ### [.glob](index.js#L171) 88 | 89 | Glob files using [matched]. Or glob files synchronously 90 | with `glob.sync`. 91 | 92 | **Params** 93 | 94 | * `patterns` **{String|Array}** 95 | * `returns` **{options}** 96 | 97 | ### [.readFileSync](index.js#L182) 98 | 99 | Read a file synchronously. Also strips any byte order 100 | marks. 101 | 102 | **Params** 103 | 104 | * `filepath` **{String}** 105 | * `returns` **{String}** 106 | 107 | ### [readFile](index.js#L202) 108 | 109 | Read a file asynchronously. 110 | 111 | **Params** 112 | 113 | * `filepath` **{String}** 114 | * `options` **{Object}** 115 | * `normalize` **{Boolean}**: Strip carriage returns and BOM. 116 | * `encoding` **{String}**: Default is `utf8` 117 | * `callback` **{Function}** 118 | 119 | ### [.readYAML](index.js#L233) 120 | 121 | Read a YAML file asynchronously and parse its contents as JSON. 122 | 123 | **Params** 124 | 125 | * `filepath` **{String}** 126 | * `returns` **{Object}** `options` 127 | * `returns` **{Function}** `cb`: Callback function 128 | 129 | ### [.readYAMLSync](index.js#L245) 130 | 131 | Read a YAML file synchronously and parse its contents as JSON 132 | 133 | **Params** 134 | 135 | * `filepath` **{String}** 136 | * `returns` **{Object}** 137 | 138 | ### [.readJSON](index.js#L258) 139 | 140 | Read JSON file asynchronously and parse contents as JSON 141 | 142 | **Params** 143 | 144 | * `filepath` **{String}** 145 | * `callback` **{Function}** 146 | * `returns` **{Object}** 147 | 148 | ### [.readJSONSync](index.js#L275) 149 | 150 | Read a file synchronously and parse contents as JSON. 151 | marks. 152 | 153 | **Params** 154 | 155 | * `filepath` **{String}** 156 | * `returns` **{Object}** 157 | 158 | ### [.readData](index.js#L290) 159 | 160 | Read JSON or YAML utils.async. Determins the reader automatically 161 | based on file extension. 162 | 163 | **Params** 164 | 165 | * `filepath` **{String}** 166 | * `options` **{Object}** 167 | * `callback` **{Function}** 168 | * `returns` **{String}** 169 | 170 | ### [.readDataSync](index.js#L304) 171 | 172 | Read JSON or utils.YAML. Determins the reader automatically 173 | based on file extension. 174 | 175 | **Params** 176 | 177 | * `filepath` **{String}** 178 | * `options` **{Object}** 179 | * `returns` **{String}** 180 | 181 | ### [.writeFile](index.js#L358) 182 | 183 | Asynchronously write a file to disk. 184 | 185 | **Params** 186 | 187 | * `dest` **{String}** 188 | * `content` **{String}** 189 | * `callback` **{Function}** 190 | 191 | ### [.writeFileSync](index.js#L372) 192 | 193 | Synchronously write files to disk, creating any 194 | intermediary directories if they don't exist. 195 | 196 | **Params** 197 | 198 | * `dest` **{String}** 199 | * `str` **{String}** 200 | * `options` **{Options}** 201 | 202 | ### [.writeJSONSync](index.js#L386) 203 | 204 | Synchronously write JSON to disk, creating any 205 | intermediary directories if they don't exist. 206 | 207 | **Params** 208 | 209 | * `dest` **{String}** 210 | * `str` **{String}** 211 | * `options` **{Options}** 212 | 213 | ### [.writeJSON](index.js#L400) 214 | 215 | Asynchronously write files to disk, creating any 216 | intermediary directories if they don't exist. 217 | 218 | **Params** 219 | 220 | * `dest` **{String}** 221 | * `str` **{String}** 222 | * `options` **{Options}** 223 | 224 | ### [.writeYAMLSync](index.js#L414) 225 | 226 | Synchronously write YAML to disk, creating any 227 | intermediary directories if they don't exist. 228 | 229 | **Params** 230 | 231 | * `dest` **{String}** 232 | * `str` **{String}** 233 | * `options` **{Options}** 234 | 235 | ### [.writeYAML](index.js#L428) 236 | 237 | Aynchronously write YAML to disk, creating any 238 | intermediary directories if they don't exist. 239 | 240 | **Params** 241 | 242 | * `dest` **{String}** 243 | * `str` **{String}** 244 | * `options` **{Options}** 245 | 246 | ### [.writeDataSync](index.js#L447) 247 | 248 | Synchronously write JSON or YAML to disk, creating any intermediary directories if they don't exist. Data type is determined by the `dest` file extension. 249 | 250 | **Params** 251 | 252 | * `dest` **{String}** 253 | * `str` **{String}** 254 | * `options` **{Options}** 255 | 256 | **Example** 257 | 258 | ```js 259 | writeDataSync('foo.yml', {foo: "bar"}); 260 | ``` 261 | 262 | ### [.writeData](index.js#L467) 263 | 264 | Asynchronously write JSON or YAML to disk, creating any intermediary directories if they don't exist. Data type is determined by the `dest` file extension. 265 | 266 | **Params** 267 | 268 | * `dest` **{String}** 269 | * `data` **{String}** 270 | * `options` **{Options}** 271 | * `cb` **{Function}**: Callback function 272 | 273 | **Example** 274 | 275 | ```js 276 | writeData('foo.yml', {foo: "bar"}); 277 | ``` 278 | 279 | ### [.copyFileSync](index.js#L479) 280 | 281 | Copy files synchronously; 282 | 283 | **Params** 284 | 285 | * `src` **{String}** 286 | * `dest` **{String}** 287 | 288 | ### [.rmdir](index.js#L492) 289 | 290 | Asynchronously remove dirs and child dirs that exist. 291 | 292 | **Params** 293 | 294 | * `dir` **{String}** 295 | * **{Function}**: `cb 296 | * `returns` **{Function}** 297 | 298 | ### [.del](index.js#L529) 299 | 300 | Delete folders and files recursively. Pass a callback 301 | as the last argument to use utils.async. 302 | 303 | **Params** 304 | 305 | * `patterns` **{String}**: Glob patterns to use. 306 | * `options` **{Object}**: Options for matched. 307 | * `cb` **{Function}** 308 | 309 | ### [.ext](index.js#L597) 310 | 311 | Return the file extension. 312 | 313 | **Params** 314 | 315 | * `filepath` **{String}** 316 | * `returns` **{String}** 317 | 318 | ### [.dirname](index.js#L609) 319 | 320 | Directory path excluding filename. 321 | 322 | **Params** 323 | 324 | * `filepath` **{String}** 325 | * `returns` **{String}** 326 | 327 | ### [.last](index.js#L635) 328 | 329 | The last `n` segments of a filepath. If a number 330 | isn't passed for `n`, the last segment is returned. 331 | 332 | **Params** 333 | 334 | * `filepath` **{String}** 335 | * `returns` **{String}** 336 | 337 | ### [.first](index.js#L650) 338 | 339 | The first `n` segments of a filepath. If a number 340 | isn't passed for `n`, the first segment is returned. 341 | 342 | **Params** 343 | 344 | * `filepath` **{String}** 345 | * `returns` **{String}** 346 | 347 | ### [.lastChar](index.js#L669) 348 | 349 | Returns the last character in `filepath` 350 | 351 | **Params** 352 | 353 | * `filepath` **{String}** 354 | * `returns` **{String}** 355 | 356 | **Example** 357 | 358 | ``` 359 | lastChar('foo/bar/baz/'); 360 | //=> '/' 361 | ``` 362 | 363 | ### [.addSlash](index.js#L696) 364 | 365 | Add a trailing slash to the filepath. 366 | 367 | Note, this does _not_ consult the file system 368 | to check if the filepath is file or a directory. 369 | 370 | **Params** 371 | 372 | * `filepath` **{String}** 373 | * `returns` **{String}** 374 | 375 | ### [.normalizePath](index.js#L711) 376 | 377 | Normalize a filepath and remove trailing slashes. 378 | 379 | **Params** 380 | 381 | * `filepath` **{String}** 382 | * `returns` **{String}** 383 | 384 | ### [.relative](index.js#L737) 385 | 386 | Resolve the relative path from `a` to `b. 387 | 388 | **Params** 389 | 390 | * `filepath` **{String}** 391 | * `returns` **{String}** 392 | 393 | ### [.isAbsolute](index.js#L749) 394 | 395 | Return `true` if the path is absolute. 396 | 397 | **Params** 398 | 399 | * **{[type]}**: filepath 400 | * `returns` **{Boolean}** 401 | 402 | ### [.equivalent](index.js#L763) 403 | 404 | Return `true` if path `a` is the same as path `b. 405 | 406 | **Params** 407 | 408 | * `filepath` **{String}** 409 | * `a` **{String}** 410 | * `b` **{String}** 411 | * `returns` **{Boolean}** 412 | 413 | ### [.doesPathContain](index.js#L778) 414 | 415 | True if descendant path(s) contained within ancestor path. Note: does not test if paths actually exist. 416 | 417 | Sourced from [Grunt]. 418 | 419 | **Params** 420 | 421 | * `ancestor` **{String}**: The starting path. 422 | * `returns` **{Boolean}** 423 | 424 | ### [.isPathCwd](index.js#L807) 425 | 426 | True if a filepath is the CWD. 427 | 428 | Sourced from [Grunt]. 429 | 430 | **Params** 431 | 432 | * `filepath` **{String}** 433 | * `returns` **{Boolean}** 434 | 435 | ### [.isPathInCwd](index.js#L824) 436 | 437 | True if a filepath is contained within the CWD. 438 | 439 | **Params** 440 | 441 | * `filepath` **{String}** 442 | * `returns` **{Boolean}** 443 | 444 | ## Related projects 445 | 446 | * [read-data](https://www.npmjs.com/package/read-data): Read JSON or YAML files. | [homepage](https://github.com/jonschlinkert/read-data) 447 | * [read-yaml](https://www.npmjs.com/package/read-yaml): Very thin wrapper around js-yaml for directly reading in YAML files. | [homepage](https://github.com/jonschlinkert/read-yaml) 448 | * [write-data](https://www.npmjs.com/package/write-data): Write a YAML or JSON file to disk. Automatically detects the format to write based… [more](https://www.npmjs.com/package/write-data) | [homepage](https://github.com/jonschlinkert/write-data) 449 | * [write-json](https://www.npmjs.com/package/write-json): Write a JSON file to disk, also creates intermediate directories in the destination path if… [more](https://www.npmjs.com/package/write-json) | [homepage](https://github.com/jonschlinkert/write-json) 450 | * [write-yaml](https://www.npmjs.com/package/write-yaml): Write YAML. Converts JSON to YAML writes it to the specified file. | [homepage](https://github.com/jonschlinkert/write-yaml) 451 | 452 | ## Running tests 453 | 454 | Install dev dependencies: 455 | 456 | ```sh 457 | $ npm i -d && npm test 458 | ``` 459 | 460 | ## Contributing 461 | 462 | Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](https://github.com/assemble/fs-utils/issues/new). 463 | 464 | ## Author 465 | 466 | **Jon Schlinkert** 467 | 468 | + [github/assemble](https://github.com/assemble) 469 | + [twitter/assemble](http://twitter.com/assemble) 470 | 471 | ## License 472 | 473 | Copyright © 2015 Jon Schlinkert 474 | Released under the MIT license. 475 | 476 | *** 477 | 478 | _This file was generated by [verb-cli](https://github.com/assemble/verb-cli) on November 17, 2015._ -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fs-utils", 3 | "description": "fs extras and utilities to extend the node.js file system module. Used in Assemble and many other projects.", 4 | "repository": "assemble/fs-utils", 5 | "license": "MIT", 6 | "homepage": "https://github.com/assemble/fs-utils", 7 | "authors": [ 8 | "Jon Schlinkert (https://github.com/assemble)" 9 | ], 10 | "main": [ 11 | "index.js" 12 | ], 13 | "dependencies": { 14 | "async": "^1.5.0", 15 | "delete": "^0.2.1", 16 | "extend-shallow": "^2.0.1", 17 | "graceful-fs": "^4.1.2", 18 | "is-absolute": "^0.2.2", 19 | "js-yaml": "^3.4.3", 20 | "kind-of": "^2.0.1", 21 | "matched": "^0.3.2", 22 | "normalize-path": "^0.3.0", 23 | "relative": "^0.1.6" 24 | }, 25 | "devDependencies": { 26 | "mocha": "^2.3.3", 27 | "should": "^4.0.4" 28 | }, 29 | "keywords": [ 30 | "file", 31 | "file system", 32 | "fs", 33 | "node", 34 | "node.js", 35 | "path", 36 | "read", 37 | "readFile", 38 | "readFileSync", 39 | "utils" 40 | ] 41 | } -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * fs-utils 3 | * 4 | * Copyright (c) 2014-2015 Jon Schlinkert, Brian Woodward. 5 | * Licensed under the MIT license. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | var fs = require('graceful-fs'); 11 | var path = require('path'); 12 | var EOL = require('os').EOL; 13 | var EOLre = new RegExp(EOL, 'g'); 14 | var utils = require('./utils'); 15 | 16 | /** 17 | * Strip carriage returns from a string. 18 | * 19 | * @param {String} `str` 20 | * @return {String} 21 | * @api public 22 | */ 23 | 24 | exports.stripCR = function(str) { 25 | return str.replace(/\r/g, ''); 26 | }; 27 | 28 | /** 29 | * Strip byte order marks from a string. 30 | * 31 | * See [BOM](http://en.wikipedia.org/wiki/Byte_order_mark) 32 | * 33 | * @param {String} `str` 34 | * @return {String} 35 | * @api public 36 | */ 37 | 38 | exports.stripBOM = function(str) { 39 | return str.replace(/^\uFEFF/, ''); 40 | }; 41 | 42 | /** 43 | * Normalize all slashes to forward slashes. 44 | * 45 | * @param {String} `str` 46 | * @param {Boolean} `stripTrailing` False by default. 47 | * @return {String} 48 | * @api public 49 | */ 50 | 51 | exports.slashify = function(str, trailing) { 52 | return utils.normalize(str, trailing || false); 53 | }; 54 | 55 | /** 56 | * Normalize a string by stripping windows 57 | * carriage returns and byte order marks. 58 | * 59 | * @param {String} `str` 60 | * @return {String} 61 | * @api private 62 | */ 63 | 64 | exports.normalize = function(str){ 65 | if (EOL !== '\n') { 66 | str = str.replace(EOLre, '\n'); 67 | } 68 | return exports.stripBOM(str); 69 | }; 70 | 71 | /** 72 | * True if the filepath actually exist. 73 | * 74 | * @param {String} `filepath` 75 | * @return {Boolean} 76 | */ 77 | 78 | var exists = exports.exists = function(paths) { 79 | var fp = path.join.apply(path, arguments); 80 | try { 81 | return fs.existsSync(fp); 82 | } catch (err) {} 83 | return false; 84 | }; 85 | 86 | /** 87 | * Return `true` if the file exists and is empty. 88 | * 89 | * @param {String} `filepath` 90 | * @return {Boolean} 91 | * @api public 92 | */ 93 | 94 | exports.isEmptyFile = function(fp) { 95 | if (exists(fp) === false) { 96 | return false; 97 | } 98 | var str = exports.readFileSync(fp); 99 | return str.length > 0; 100 | }; 101 | 102 | /** 103 | * Return `true` if the file exists and is empty. 104 | * 105 | * @param {String} `filepath` 106 | * @return {Boolean} 107 | * @api public 108 | */ 109 | 110 | exports.isEmptyDir = function(fp) { 111 | if (exists(fp) === false) { 112 | return false; 113 | } 114 | var files = fs.readdirSync(fp); 115 | return files.length > 0; 116 | }; 117 | 118 | /** 119 | * Return `true` if the filepath is a directory. 120 | * 121 | * @param {String} `filepath` 122 | * @return {Boolean} 123 | * @api public 124 | */ 125 | 126 | exports.isDir = function(filepath) { 127 | if (!exists(filepath)) { 128 | return false; 129 | } 130 | return fs.statSync(filepath) 131 | .isDirectory(); 132 | }; 133 | 134 | /** 135 | * True if the filepath is a file. 136 | * 137 | * @param {String} `filepath` 138 | * @return {Boolean} 139 | */ 140 | 141 | var isFile = exports.isFile = function(filepath) { 142 | if (!exists(filepath)) { 143 | return false; 144 | } 145 | return fs.statSync(filepath) 146 | .isFile(); 147 | }; 148 | 149 | /** 150 | * True if the filepath is a symbolic link. 151 | * 152 | * @param {String} `filepath` 153 | * @return {Boolean} 154 | * @api public 155 | */ 156 | 157 | exports.isLink = function(filepath) { 158 | return exists(filepath) && fs.lstatSync(filepath) 159 | .isSymbolicLink(); 160 | }; 161 | 162 | /** 163 | * Glob files using [matched]. Or glob files synchronously 164 | * with `glob.sync`. 165 | * 166 | * @param {String|Array} `patterns` 167 | * @return {options} 168 | * @api public 169 | */ 170 | 171 | exports.glob = utils.glob; 172 | 173 | /** 174 | * Read a file synchronously. Also strips any byte order 175 | * marks. 176 | * 177 | * @param {String} `filepath` 178 | * @return {String} 179 | * @api public 180 | */ 181 | 182 | exports.readFileSync = function(filepath, options) { 183 | var opts = utils.extend({normalize: true, encoding: 'utf8'}, options); 184 | var str = fs.readFileSync(filepath, opts.encoding); 185 | if (opts.normalize && opts.encoding === 'utf8') { 186 | str = exports.normalize(str); 187 | } 188 | return str; 189 | }; 190 | 191 | /** 192 | * Read a file asynchronously. 193 | * 194 | * @param {String} `filepath` 195 | * @param {Object} `options` 196 | * @param {Boolean} [options] `normalize` Strip carriage returns and BOM. 197 | * @param {String} [options] `encoding` Default is `utf8` 198 | * @param {Function} `callback` 199 | * @api public 200 | */ 201 | 202 | var readFile = exports.readFile = function(filepath, options, cb) { 203 | if (typeof options === 'function') { 204 | cb = options; 205 | options = {}; 206 | } 207 | 208 | if (typeof cb !== 'function') { 209 | throw new TypeError('readfile expects callback to be a function'); 210 | } 211 | 212 | var opts = utils.extend({normalize: true, encoding: 'utf8'}, options); 213 | 214 | fs.readFile(filepath, opts.encoding, function (err, content) { 215 | if (err) return cb(err); 216 | 217 | if (opts.normalize && opts.encoding === 'utf8') { 218 | content = exports.normalize(content); 219 | } 220 | cb(null, content); 221 | }); 222 | }; 223 | 224 | /** 225 | * Read a YAML file asynchronously and parse its contents as JSON. 226 | * 227 | * @param {String} `filepath` 228 | * @return {Object} `options` 229 | * @return {Function} `cb` Callback function 230 | * @api public 231 | */ 232 | 233 | exports.readYAML = function(filepath, options, cb) { 234 | return utils.readYaml.apply(utils.readYaml, arguments); 235 | }; 236 | 237 | /** 238 | * Read a YAML file synchronously and parse its contents as JSON 239 | * 240 | * @param {String} `filepath` 241 | * @return {Object} 242 | * @api public 243 | */ 244 | 245 | exports.readYAMLSync = function(filepath, options) { 246 | return utils.readYaml.sync.apply(utils.readYaml, arguments); 247 | }; 248 | 249 | /** 250 | * Read JSON file asynchronously and parse contents as JSON 251 | * 252 | * @param {String} `filepath` 253 | * @param {Function} `callback` 254 | * @return {Object} 255 | * @api public 256 | */ 257 | 258 | exports.readJSON = function(filepath, cb) { 259 | exports.readFile(filepath, function(err, contents) { 260 | if (err) return cb(err); 261 | 262 | cb(null, JSON.parse(contents.toString())); 263 | }); 264 | }; 265 | 266 | /** 267 | * Read a file synchronously and parse contents as JSON. 268 | * marks. 269 | * 270 | * @param {String} `filepath` 271 | * @return {Object} 272 | * @api public 273 | */ 274 | 275 | exports.readJSONSync = function(filepath, options) { 276 | return JSON.parse(exports.readFileSync(filepath, options)); 277 | }; 278 | 279 | /** 280 | * Read JSON or YAML utils.async. Determins the reader automatically 281 | * based on file extension. 282 | * 283 | * @param {String} `filepath` 284 | * @param {Object} `options` 285 | * @param {Function} `callback` 286 | * @return {String} 287 | * @api public 288 | */ 289 | 290 | exports.readData = function(filepath, options, cb) { 291 | return utils.readData.data.apply(utils.readData, arguments); 292 | }; 293 | 294 | /** 295 | * Read JSON or utils.YAML. Determins the reader automatically 296 | * based on file extension. 297 | * 298 | * @param {String} `filepath` 299 | * @param {Object} `options` 300 | * @return {String} 301 | * @api public 302 | */ 303 | 304 | exports.readDataSync = function(filepath, options) { 305 | return utils.readData.data.sync.apply(utils.readData, arguments); 306 | }; 307 | 308 | /** 309 | * Asynchronously create dirs and any intermediate dirs 310 | * don't exist. 311 | * 312 | * @param {String} `dirpath` 313 | */ 314 | 315 | var mkdir = exports.mkdir = function(dest, cb) { 316 | var dir = path.dirname(dest); 317 | fs.exists(dir, function (exist) { 318 | if (exist) { 319 | fs.mkdir(dest, cb); 320 | } else { 321 | mkdir(dir, function (err) { 322 | if (err) return cb(err); 323 | fs.mkdir(dest, cb); 324 | }); 325 | } 326 | }); 327 | }; 328 | 329 | /** 330 | * Synchronously create dirs and any intermediate dirs 331 | * don't exist. 332 | * 333 | * @param {String} `dirpath` 334 | */ 335 | 336 | var mkdirSync = exports.mkdirSync = function(dirpath, mode) { 337 | mode = mode || parseInt('0777', 8) & (~process.umask()); 338 | if (!exists(dirpath)) { 339 | var parentDir = path.dirname(dirpath); 340 | if (exists(parentDir)) { 341 | fs.mkdirSync(dirpath, mode); 342 | } else { 343 | mkdirSync(parentDir); 344 | fs.mkdirSync(dirpath, mode); 345 | } 346 | } 347 | }; 348 | 349 | /** 350 | * Asynchronously write a file to disk. 351 | * 352 | * @param {String} `dest` 353 | * @param {String} `content` 354 | * @param {Function} `callback` 355 | * @api public 356 | */ 357 | 358 | exports.writeFile = function(dest, content, cb) { 359 | utils.writeFile.apply(utils.writeFile, arguments); 360 | }; 361 | 362 | /** 363 | * Synchronously write files to disk, creating any 364 | * intermediary directories if they don't exist. 365 | * 366 | * @param {String} `dest` 367 | * @param {String} `str` 368 | * @param {Options} `options` 369 | * @api public 370 | */ 371 | 372 | exports.writeFileSync = function(dest, str, options) { 373 | utils.writeFile.sync.apply(utils.writeFile, arguments); 374 | }; 375 | 376 | /** 377 | * Synchronously write JSON to disk, creating any 378 | * intermediary directories if they don't exist. 379 | * 380 | * @param {String} `dest` 381 | * @param {String} `str` 382 | * @param {Options} `options` 383 | * @api public 384 | */ 385 | 386 | exports.writeJSONSync = function(dest, str, options) { 387 | utils.writeJson.sync.apply(utils.writeJson, arguments); 388 | }; 389 | 390 | /** 391 | * Asynchronously write files to disk, creating any 392 | * intermediary directories if they don't exist. 393 | * 394 | * @param {String} `dest` 395 | * @param {String} `str` 396 | * @param {Options} `options` 397 | * @api public 398 | */ 399 | 400 | exports.writeJSON = function(dest, str, options, cb) { 401 | utils.writeJson.apply(utils.writeJson, arguments); 402 | }; 403 | 404 | /** 405 | * Synchronously write YAML to disk, creating any 406 | * intermediary directories if they don't exist. 407 | * 408 | * @param {String} `dest` 409 | * @param {String} `str` 410 | * @param {Options} `options` 411 | * @api public 412 | */ 413 | 414 | exports.writeYAMLSync = function(dest, str, options) { 415 | utils.writeYaml.sync.apply(utils.writeYaml, arguments); 416 | }; 417 | 418 | /** 419 | * Aynchronously write YAML to disk, creating any 420 | * intermediary directories if they don't exist. 421 | * 422 | * @param {String} `dest` 423 | * @param {String} `str` 424 | * @param {Options} `options` 425 | * @api public 426 | */ 427 | 428 | exports.writeYAML = function(dest, data, options, cb) { 429 | utils.writeYaml.apply(utils.writeYaml, arguments); 430 | }; 431 | 432 | /** 433 | * Synchronously write JSON or YAML to disk, creating any 434 | * intermediary directories if they don't exist. Data 435 | * type is determined by the `dest` file extension. 436 | * 437 | * ```js 438 | * writeDataSync('foo.yml', {foo: "bar"}); 439 | * ``` 440 | * 441 | * @param {String} `dest` 442 | * @param {String} `str` 443 | * @param {Options} `options` 444 | * @api public 445 | */ 446 | 447 | exports.writeDataSync = function(dest, data, options) { 448 | utils.writeData.sync.apply(utils.writeData, arguments); 449 | }; 450 | 451 | /** 452 | * Asynchronously write JSON or YAML to disk, creating any 453 | * intermediary directories if they don't exist. Data 454 | * type is determined by the `dest` file extension. 455 | * 456 | * ```js 457 | * writeData('foo.yml', {foo: "bar"}); 458 | * ``` 459 | * 460 | * @param {String} `dest` 461 | * @param {String} `data` 462 | * @param {Options} `options` 463 | * @param {Function} `cb` Callback function 464 | * @api public 465 | */ 466 | 467 | exports.writeData = function(dest, data, options, cb) { 468 | utils.writeData.apply(utils.writeData, arguments); 469 | }; 470 | 471 | /** 472 | * Copy files synchronously; 473 | * 474 | * @param {String} `src` 475 | * @param {String} `dest` 476 | * @api public 477 | */ 478 | 479 | exports.copyFileSync = function(src, dest) { 480 | exports.writeFileSync(dest, exports.readFileSync(src)); 481 | }; 482 | 483 | /** 484 | * Asynchronously remove dirs and child dirs that exist. 485 | * 486 | * @param {String} `dir` 487 | * @param {Function} `cb 488 | * @return {Function} 489 | * @api public 490 | */ 491 | 492 | exports.rmdir = function(dir, cb) { 493 | if (typeof cb !== 'function') { 494 | cb = function () {}; 495 | } 496 | 497 | fs.readdir(dir, function (err, files) { 498 | if (err) { 499 | return cb(err); 500 | } 501 | utils.async.each(files, function (segment, next) { 502 | var dir = path.join(dir, segment); 503 | fs.stat(dir, function (err, stats) { 504 | if (err) { 505 | return cb(err); 506 | } 507 | if (stats.isDirectory()) { 508 | utils.del(dir, next); 509 | } else { 510 | fs.unlink(dir, next); 511 | } 512 | }); 513 | }, function () { 514 | fs.rmdir(dir, cb); 515 | }); 516 | }); 517 | }; 518 | 519 | /** 520 | * Delete folders and files recursively. Pass a callback 521 | * as the last argument to use utils.async. 522 | * 523 | * @param {String} `patterns` Glob patterns to use. 524 | * @param {Object} `options` Options for matched. 525 | * @param {Function} `cb` 526 | * @api public 527 | */ 528 | 529 | exports.del = function(patterns, opts, cb) { 530 | var args = [].slice.call(arguments); 531 | var last = args[args.length - 1]; 532 | 533 | if (typeof last === 'function') { 534 | exports.deleteAsync(patterns, opts); 535 | } else { 536 | exports.deleteSync(patterns, opts); 537 | } 538 | }; 539 | 540 | /** 541 | * Asynchronously delete folders and files. 542 | * 543 | * @param {String} `patterns` Glob patterns to use. 544 | * @param {String} `opts` Options for matched. 545 | * @param {Function} `cb` 546 | * @api private 547 | */ 548 | 549 | exports.deleteAsync = function(patterns, opts, cb) { 550 | if (typeof opts !== 'object') { 551 | cb = opts; 552 | opts = {}; 553 | } 554 | 555 | utils.glob(patterns, opts, function (err, files) { 556 | if (err) { 557 | cb(err); 558 | return; 559 | } 560 | utils.async.each(files, function (filepath, next) { 561 | if (opts.cwd && !exports.isAbsolute(filepath)) { 562 | filepath = path.resolve(opts.cwd, filepath); 563 | } 564 | 565 | utils.del(filepath, next); 566 | }, cb); 567 | }); 568 | }; 569 | 570 | /** 571 | * Synchronously delete folders and files. 572 | * 573 | * @param {String} `patterns` Glob patterns to use. 574 | * @param {Object} `options` Options for matched. 575 | * @param {Function} `cb` 576 | * @api private 577 | */ 578 | 579 | exports.deleteSync = function(patterns, options) { 580 | var opts = utils.extend({cwd: process.cwd()}, options); 581 | utils.glob.sync(patterns, opts).forEach(function (filepath) { 582 | if (opts.cwd) { 583 | filepath = path.resolve(opts.cwd, filepath); 584 | } 585 | utils.del.sync(filepath); 586 | }); 587 | }; 588 | 589 | /** 590 | * Return the file extension. 591 | * 592 | * @param {String} `filepath` 593 | * @return {String} 594 | * @api public 595 | */ 596 | 597 | exports.ext = function(filepath) { 598 | return path.extname(filepath); 599 | }; 600 | 601 | /** 602 | * Directory path excluding filename. 603 | * 604 | * @param {String} `filepath` 605 | * @return {String} 606 | * @api public 607 | */ 608 | 609 | exports.dirname = function(filepath) { 610 | return isFile(filepath) 611 | ? path.dirname(filepath) 612 | : filepath; 613 | }; 614 | 615 | /** 616 | * Return an array of path segments. 617 | * 618 | * @param {String} `filepath` 619 | * @return {Array} 620 | */ 621 | 622 | var segments = exports.segments = function(filepath) { 623 | return filepath.split(/[\\\/]/g); 624 | }; 625 | 626 | /** 627 | * The last `n` segments of a filepath. If a number 628 | * isn't passed for `n`, the last segment is returned. 629 | * 630 | * @param {String} `filepath` 631 | * @return {String} 632 | * @api public 633 | */ 634 | 635 | exports.last = function(filepath, num) { 636 | var seg = segments(filepath); 637 | return seg.slice(-(num || 1)) 638 | .join(path.sep); 639 | }; 640 | 641 | /** 642 | * The first `n` segments of a filepath. If a number 643 | * isn't passed for `n`, the first segment is returned. 644 | * 645 | * @param {String} `filepath` 646 | * @return {String} 647 | * @api public 648 | */ 649 | 650 | exports.first = function(filepath, num) { 651 | var seg = segments(filepath); 652 | return seg.slice(num || 1) 653 | .join(path.sep); 654 | }; 655 | 656 | /** 657 | * Returns the last character in `filepath` 658 | * 659 | * ``` 660 | * lastChar('foo/bar/baz/'); 661 | * //=> '/' 662 | * ``` 663 | * 664 | * @param {String} `filepath` 665 | * @return {String} 666 | * @api public 667 | */ 668 | 669 | exports.lastChar = function(filepath) { 670 | var len = filepath.length; 671 | return filepath[len - 1]; 672 | }; 673 | 674 | /** 675 | * Remove a trailing slash from a filepath 676 | * 677 | * @param {String} `filepath` 678 | * @return {String} 679 | */ 680 | 681 | var removeSlash = exports.removeSlash = function(filepath) { 682 | return filepath.replace(/[\\\/]$/, ''); 683 | }; 684 | 685 | /** 686 | * Add a trailing slash to the filepath. 687 | * 688 | * Note, this does _not_ consult the file system 689 | * to check if the filepath is file or a directory. 690 | * 691 | * @param {String} `filepath` 692 | * @return {String} 693 | * @api public 694 | */ 695 | 696 | exports.addSlash = function(filepath) { 697 | if (!/\./.test(path.basename(filepath))) { 698 | return removeSlash(filepath) + path.sep; 699 | } 700 | return filepath; 701 | }; 702 | 703 | /** 704 | * Normalize a filepath and remove trailing slashes. 705 | * 706 | * @param {String} `filepath` 707 | * @return {String} 708 | * @api public 709 | */ 710 | 711 | exports.normalizePath = function(filepath) { 712 | return removeSlash(path.normalize(filepath)); 713 | }; 714 | 715 | /** 716 | * Resolve a filepath, also normalizes and removes 717 | * trailing slashes. 718 | * 719 | * @param {String} `filepath` 720 | * @return {String} 721 | */ 722 | 723 | var resolve = exports.resolve = function(filepath) { 724 | var args = [].slice.call(arguments); 725 | var paths = path.resolve.apply(path, args); 726 | return exports.normalizePath(paths); 727 | }; 728 | 729 | /** 730 | * Resolve the relative path from `a` to `b. 731 | * 732 | * @param {String} `filepath` 733 | * @return {String} 734 | * @api public 735 | */ 736 | 737 | exports.relative = function(a, b) { 738 | return utils.relative.apply(utils.relative, arguments); 739 | }; 740 | 741 | /** 742 | * Return `true` if the path is absolute. 743 | * 744 | * @param {[type]} filepath 745 | * @return {Boolean} 746 | * @api public 747 | */ 748 | 749 | exports.isAbsolute = function(filepath) { 750 | return utils.isAbs.apply(utils.isAbs, arguments); 751 | }; 752 | 753 | /** 754 | * Return `true` if path `a` is the same as path `b. 755 | * 756 | * @param {String} `filepath` 757 | * @param {String} `a` 758 | * @param {String} `b` 759 | * @return {Boolean} 760 | * @api public 761 | */ 762 | 763 | exports.equivalent = function(a, b) { 764 | return resolve(a) === resolve(b); 765 | }; 766 | 767 | /** 768 | * True if descendant path(s) contained within ancestor path. 769 | * Note: does not test if paths actually exist. 770 | * 771 | * Sourced from [Grunt]. 772 | * 773 | * @param {String} `ancestor` The starting path. 774 | * @return {Boolean} 775 | * @api public 776 | */ 777 | 778 | exports.doesPathContain = function(ancestor) { 779 | ancestor = path.resolve(ancestor); 780 | 781 | var args = [].slice.call(arguments, 1); 782 | var len = arguments.length; 783 | if (len === 0) { 784 | return false; 785 | } 786 | 787 | var rel; 788 | for (var i = 0; i < len; i++) { 789 | rel = path.relative(resolve(args[i]), ancestor); 790 | if (rel === '' || /\w+/.test(rel)) { 791 | return false; 792 | } 793 | } 794 | return true; 795 | }; 796 | 797 | /** 798 | * True if a filepath is the CWD. 799 | * 800 | * Sourced from [Grunt]. 801 | * 802 | * @param {String} `filepath` 803 | * @return {Boolean} 804 | * @api public 805 | */ 806 | 807 | exports.isPathCwd = function(filepath) { 808 | try { 809 | var actual = fs.realpathSync(filepath); 810 | return exports.equivalent(process.cwd(), actual); 811 | } catch (err) { 812 | return false; 813 | } 814 | }; 815 | 816 | /** 817 | * True if a filepath is contained within the CWD. 818 | * 819 | * @param {String} `filepath` 820 | * @return {Boolean} 821 | * @api public 822 | */ 823 | 824 | exports.isPathInCwd = function(filepath) { 825 | try { 826 | var actual = fs.realpathSync(path.resolve(filepath)); 827 | console.log(actual); 828 | return exports.doesPathContain(process.cwd(), actual); 829 | } catch (err) { 830 | return false; 831 | } 832 | }; 833 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fs-utils", 3 | "description": "fs extras and utilities to extend the node.js file system module. Used in Assemble and many other projects.", 4 | "version": "0.7.0", 5 | "homepage": "https://github.com/assemble/fs-utils", 6 | "author": "Jon Schlinkert (https://github.com/assemble)", 7 | "repository": "assemble/fs-utils", 8 | "bugs": { 9 | "url": "https://github.com/assemble/fs-utils/issues" 10 | }, 11 | "license": "MIT", 12 | "files": [ 13 | "index.js", 14 | "utils.js" 15 | ], 16 | "main": "index.js", 17 | "engines": { 18 | "node": ">= 0.8.0" 19 | }, 20 | "scripts": { 21 | "test": "mocha" 22 | }, 23 | "dependencies": { 24 | "async": "^1.5.0", 25 | "delete": "^0.2.1", 26 | "extend-shallow": "^2.0.1", 27 | "graceful-fs": "^4.1.2", 28 | "is-absolute": "^0.2.3", 29 | "js-yaml": "^3.4.3", 30 | "kind-of": "^3.0.0", 31 | "lazy-cache": "^0.2.4", 32 | "matched": "^0.3.2", 33 | "normalize-path": "^2.0.1", 34 | "read-data": "^0.3.0", 35 | "read-yaml": "^1.0.0", 36 | "relative": "^3.0.2", 37 | "write": "^0.2.1", 38 | "write-data": "^0.1.0", 39 | "write-json": "^0.2.2", 40 | "write-yaml": "^0.2.2" 41 | }, 42 | "devDependencies": { 43 | "mocha": "*", 44 | "should": "*" 45 | }, 46 | "keywords": [ 47 | "file", 48 | "file system", 49 | "fs", 50 | "node", 51 | "node.js", 52 | "path", 53 | "read", 54 | "readFile", 55 | "readFileSync", 56 | "utils" 57 | ], 58 | "verb": { 59 | "related": { 60 | "list": [ 61 | "write-data", 62 | "write-json", 63 | "read-data", 64 | "read-yaml", 65 | "write-yaml" 66 | ] 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /test/fixtures/foo.md: -------------------------------------------------------------------------------- 1 | FOOOO! -------------------------------------------------------------------------------- /test/fixtures/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "foo": { 3 | "bar": "baz" 4 | } 5 | } -------------------------------------------------------------------------------- /test/fixtures/test.txt: -------------------------------------------------------------------------------- 1 | FILE CONTENTS!!! -------------------------------------------------------------------------------- /test/fixtures/test.yaml: -------------------------------------------------------------------------------- 1 | foo: 2 | bar: baz -------------------------------------------------------------------------------- /test/fs.async.js: -------------------------------------------------------------------------------- 1 | /** 2 | * fs-utils 3 | * 4 | * Copyright (c) 2014 Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT license. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | require('mocha'); 11 | var should = require('should'); 12 | var path = require('path'); 13 | var file = require('..'); 14 | 15 | describe('fs', function () { 16 | it('should read the file (async)', function (done) { 17 | file.readFile('test/fixtures/test.txt', function (err, contents) { 18 | contents.should.eql('FILE CONTENTS!!!'); 19 | done(); 20 | }); 21 | }); 22 | 23 | it('should read JSON (async)', function (done) { 24 | file.readJSON('test/fixtures/test.json', function (err, contents) { 25 | contents.should.eql({foo: {bar: "baz"} }); 26 | done(); 27 | }); 28 | }); 29 | 30 | it('should read the yaml file (async)', function (done) { 31 | file.readYAML('test/fixtures/test.yaml', function (err, contents) { 32 | contents.should.eql({foo: {bar: "baz"}}); 33 | done(); 34 | }); 35 | }); 36 | 37 | it('should read detect JSON extension automatically (async)', function (done) { 38 | file.readData('test/fixtures/test.json', function (err, actual) { 39 | actual.should.eql({foo: {bar: "baz"} }); 40 | done(); 41 | }); 42 | }); 43 | 44 | it('should read the yaml file automatically (async)', function (done) { 45 | file.readData('test/fixtures/test.yaml', function (err, actual) { 46 | actual.should.eql({foo: {bar: "baz"}}); 47 | done(); 48 | }); 49 | }); 50 | 51 | it('should make a directory, asynchronously', function(done) { 52 | file.mkdir('test/actual/new/folder/async', function(err) { 53 | if (err) return console.log(err); 54 | file.exists('test/actual/new/folder/async').should.be.true; 55 | done(); 56 | }); 57 | }); 58 | 59 | it('should remove a directory, asynchronously', function(done) { 60 | var existingDir = ('test/actual/new/folder/async'); 61 | file.rmdir(existingDir, function(err) { 62 | if (err) return console.log(err); 63 | file.exists('test/actual/new/folder/async').should.be.false; 64 | done(); 65 | }); 66 | }); 67 | 68 | 69 | it('should write a file (async)', function (done) { 70 | file.writeFile('test/actual/test.txt', 'FILE CONTENTS!!!', function () { 71 | file.readFile('test/actual/test.txt', function (err, actual) { 72 | file.del('test/actual/test.txt'); 73 | actual.should.eql('FILE CONTENTS!!!'); 74 | done(); 75 | }); 76 | }); 77 | }); 78 | 79 | 80 | it('should write JSON (async)', function (done) { 81 | var expected = {foo: {bar: "baz"} }; 82 | file.writeJSON('test/actual/test.json', expected, function () { 83 | file.readJSON('test/actual/test.json', function (err, actual) { 84 | file.del('test/actual/test.json'); 85 | actual.should.eql(expected); 86 | done(); 87 | }); 88 | }); 89 | }); 90 | 91 | it('should write the yaml file (async)', function (done) { 92 | var expected = {foo: {bar: "baz"}}; 93 | file.writeYAML('test/actual/test.yaml', expected, function () { 94 | file.readYAML('test/actual/test.yaml', function (err, actual) { 95 | file.del('test/actual/test.yaml'); 96 | actual.should.eql(expected); 97 | done(); 98 | }); 99 | }); 100 | }); 101 | 102 | it('should write JSON automatically (async)', function (done) { 103 | var expected = {foo: {bar: "baz"} }; 104 | file.writeData('test/actual/test.json', expected, function () { 105 | file.readData('test/actual/test.json', function (err, actual) { 106 | file.del('test/actual/test.json'); 107 | actual.should.eql(expected); 108 | done(); 109 | }); 110 | }); 111 | }); 112 | 113 | it('should write the yaml file automatically (async)', function (done) { 114 | var expected = {foo: {bar: "baz"}}; 115 | file.writeData('test/actual/test.yaml', expected, function () { 116 | file.readData('test/actual/test.yaml', function (err, actual) { 117 | file.del('test/actual/test.yaml'); 118 | actual.should.eql(expected); 119 | done(); 120 | }); 121 | }); 122 | }); 123 | 124 | }); -------------------------------------------------------------------------------- /test/fs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * fs-utils 3 | * 4 | * Copyright (c) 2014 Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT license. 6 | */ 7 | 8 | 'use strict'; 9 | 10 | var should = require('should'); 11 | var path = require('path'); 12 | var file = require('..'); 13 | 14 | describe('fs', function () { 15 | it('should return true the path exists', function () { 16 | file.exists('test/fixtures/test.txt').should.be.true; 17 | }); 18 | 19 | it('should return false when path does not exist', function () { 20 | file.exists('./some/random/file.json').should.be.false; 21 | file.exists('.', 'some', 'random', 'file.json').should.be.false; 22 | }); 23 | 24 | it('should return true if a path is a real file', function() { 25 | file.isFile('package.json').should.be.true; 26 | file.isFile('README.md').should.be.true; 27 | }); 28 | 29 | it('should return false if a path is not a real file', function() { 30 | file.isFile('test').should.be.false; 31 | }); 32 | 33 | it('should return true if a path is a real directory', function() { 34 | file.isDir('test').should.be.true; 35 | }); 36 | 37 | it('should return false if a path is not a real directory', function() { 38 | file.isDir('package.json').should.be.false; 39 | file.isDir('README.md').should.be.false; 40 | }); 41 | 42 | it('should read the file', function () { 43 | file.readFileSync('test/fixtures/test.txt').should.eql('FILE CONTENTS!!!'); 44 | }); 45 | 46 | it('should read JSON', function () { 47 | file.readJSONSync('test/fixtures/test.json').should.eql({foo: {bar: "baz"} }); 48 | }); 49 | 50 | it('should read YAML', function () { 51 | file.readYAMLSync('test/fixtures/test.yaml').should.eql({foo: {bar: "baz"}}); 52 | }); 53 | 54 | it('should read detect JSON extension automatically', function () { 55 | file.readDataSync('test/fixtures/test.json').should.eql({foo: {bar: "baz"}}); 56 | }); 57 | 58 | it('should read YAML automatically', function () { 59 | file.readDataSync('test/fixtures/test.yaml').should.eql({foo: {bar: "baz"}}); 60 | }); 61 | 62 | it('should make a directory, synchronously', function() { 63 | file.mkdirSync('test/actual/new/folder/sync'); 64 | file.exists('test/actual/new/folder/sync').should.be.true; 65 | }); 66 | 67 | it('should remove a directory, synchronously', function() { 68 | file.del('test/actual/new/folder/sync'); 69 | file.exists('test/actual/new/folder/sync').should.be.false; 70 | }); 71 | 72 | it('should "delete" a directory, synchronously', function() { 73 | file.mkdirSync('test/actual/new/folder/sync'); 74 | file.del('test/actual/new/folder/sync'); 75 | file.exists('test/actual/new/folder/sync').should.be.false; 76 | }); 77 | 78 | it('should write a file', function () { 79 | file.writeFileSync('test/actual/test.txt', 'FILE CONTENTS!!!'); 80 | file.readFileSync('test/actual/test.txt').should.eql('FILE CONTENTS!!!'); 81 | file.del('test/actual/test.txt'); 82 | }); 83 | 84 | it('should write JSON', function () { 85 | file.writeJSONSync('test/actual/test.json', {foo: {bar: "baz"}}); 86 | file.readJSONSync('test/actual/test.json').should.eql({foo: {bar: "baz"}}); 87 | file.del('test/actual/test.json'); 88 | }); 89 | 90 | it('should write YAML', function () { 91 | file.writeYAMLSync('test/actual/test.yaml', {foo: {bar: "baz"}}); 92 | file.readYAMLSync('test/actual/test.yaml').should.eql({foo: {bar: "baz"}}); 93 | file.del('test/actual/test.yaml'); 94 | }); 95 | 96 | it('should write JSON', function () { 97 | file.writeDataSync('test/actual/test.json', {foo: {bar: "baz"}}); 98 | file.readDataSync('test/actual/test.json').should.eql({foo: {bar: "baz"}}); 99 | file.del('test/actual/test.json'); 100 | }); 101 | 102 | it('should write YAML', function () { 103 | file.writeDataSync('test/actual/test.yaml', {foo: {bar: "baz"}}); 104 | file.readDataSync('test/actual/test.yaml').should.eql({foo: {bar: "baz"}}); 105 | file.del('test/actual/test.yaml'); 106 | }); 107 | 108 | describe('glob', function () { 109 | it('should return an array of files.', function () { 110 | var files = file.glob.sync('test/**/*.js'); 111 | files.should.be.an.array; 112 | (files.length > 2).should.be.true; 113 | }); 114 | }); 115 | }); -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --reporter spec -------------------------------------------------------------------------------- /test/path.js: -------------------------------------------------------------------------------- 1 | /** 2 | * fs-utils 3 | * 4 | * Copyright (c) 2014 Jon Schlinkert, Brian Woodward, contributors. 5 | * Licensed under the MIT license. 6 | */ 7 | 'use strict'; 8 | 9 | var should = require('should'); 10 | var path = require('path'); 11 | var file = require('..'); 12 | 13 | // Normalize slashes in some test results 14 | var normalize = file.slashify; 15 | 16 | describe('Normalize slashes', function() { 17 | it('should normalize slash', function() { 18 | file.slashify('foo\\bar/baz').should.equal('foo/bar/baz'); 19 | }); 20 | }); 21 | 22 | describe('Trailing slashes', function() { 23 | describe('Add trailing slashes', function() { 24 | it('should add a trailing slash when it appears to be a directory', function() { 25 | normalize(file.addSlash('foo/bar/baz')).should.equal('foo/bar/baz/'); 26 | normalize(file.addSlash('/foo/bar/baz')).should.equal('/foo/bar/baz/'); 27 | normalize(file.addSlash('./foo/bar.baz/quux')).should.equal('./foo/bar.baz/quux/'); 28 | normalize(file.addSlash('./foo/bar/baz')).should.equal('./foo/bar/baz/'); 29 | normalize(file.addSlash('\\foo\\bar\\baz')).should.equal('/foo/bar/baz/'); 30 | normalize(file.addSlash('foo\\bar\\baz')).should.equal('foo/bar/baz/'); 31 | }); 32 | 33 | it('should not add a trailing slash when it already has one', function() { 34 | normalize(file.addSlash('foo/bar/baz/')).should.equal('foo/bar/baz/'); 35 | normalize(file.addSlash('/foo/bar/baz/')).should.equal('/foo/bar/baz/'); 36 | }); 37 | 38 | it('should not add a trailing slash when it appears to be a file', function() { 39 | normalize(file.addSlash('./foo/bar/baz.md')).should.equal('./foo/bar/baz.md'); 40 | normalize(file.addSlash('/foo/bar/baz.md')).should.equal('/foo/bar/baz.md'); 41 | normalize(file.addSlash('\\foo\\bar\\baz.md')).should.equal('/foo/bar/baz.md'); 42 | }); 43 | }); 44 | 45 | describe('Remove trailing slashes', function() { 46 | it('should remove a trailing slash from the given file path', function() { 47 | normalize(file.removeSlash('./one/two/')).should.equal('./one/two'); 48 | normalize(file.removeSlash('/three/four/five/')).should.equal('/three/four/five'); 49 | normalize(file.removeSlash('\\six\\seven\\eight\\')).should.equal('/six/seven/eight'); 50 | }); 51 | }); 52 | }); 53 | 54 | describe('lastChar:', function() { 55 | it('should return the last character in the given file path', function() { 56 | file.lastChar('foo/bar/baz/quux/file.ext').should.equal('t'); 57 | file.lastChar('foo/bar/baz/quux').should.equal('x'); 58 | file.lastChar('foo/bar/baz/quux/').should.equal('/'); 59 | }); 60 | }); 61 | 62 | -------------------------------------------------------------------------------- /utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Module dependencies 5 | */ 6 | 7 | var utils = require('lazy-cache')(require); 8 | 9 | /** 10 | * Temporarily re-assign `require` to trick browserify and 11 | * webpack into reconizing lazy dependencies. 12 | * 13 | * This tiny bit of ugliness has the huge dual advantage of 14 | * only loading modules that are actually called at some 15 | * point in the lifecycle of the application, whilst also 16 | * allowing browserify and webpack to find modules that 17 | * are depended on but never actually called. 18 | */ 19 | 20 | var fn = require; 21 | require = utils; 22 | 23 | /** 24 | * Lazily required module dependencies 25 | */ 26 | 27 | require('async'); 28 | require('delete', 'del'); 29 | require('js-yaml', 'YAML'); 30 | require('extend-shallow', 'extend'); 31 | require('is-absolute', 'isAbs'); 32 | require('normalize-path', 'normalize'); 33 | require('write', 'writeFile'); 34 | require('kind-of', 'typeOf'); 35 | require('matched', 'glob'); 36 | require('read-data'); 37 | require('read-yaml'); 38 | require('write-json'); 39 | require('write-yaml'); 40 | require('write-data'); 41 | require('relative'); 42 | 43 | /** 44 | * Restore `require` 45 | */ 46 | 47 | require = fn; 48 | 49 | /** 50 | * Utils 51 | */ 52 | 53 | utils.tryStat = function(fp) { 54 | try { 55 | return fs.statSync(fp); 56 | } catch (err) {} 57 | return null; 58 | }; 59 | 60 | /** 61 | * Expose `utils` modules 62 | */ 63 | 64 | module.exports = utils; 65 | --------------------------------------------------------------------------------