mirror of
https://github.com/atom/atom.git
synced 2026-01-23 22:08:08 -05:00
📝 Provide detailed docs on fsUtils
This commit is contained in:
@@ -7,9 +7,22 @@ rimraf = require 'rimraf'
|
||||
path = require 'path'
|
||||
|
||||
# Public: Useful extensions to node's built-in fs module
|
||||
#
|
||||
# Important, this extends Node's builtin in ['fs' module][fs], which means that you
|
||||
# can do anything that you can do with Node's 'fs' module plus a few extra
|
||||
# functions that we've found to be helpful.
|
||||
#
|
||||
# [fs]: http://nodejs.org/api/fs.html
|
||||
fsExtensions =
|
||||
# Make the given path absolute by resolving it against the
|
||||
# current working directory.
|
||||
# Public: Make the given path absolute by resolving it against the current
|
||||
# working directory.
|
||||
#
|
||||
# * relativePath:
|
||||
# The String containing the relative path. If the path is prefixed with
|
||||
# '~', it will be expanded to the current user's home directory.
|
||||
#
|
||||
# Returns the absolute path or the relative path if it's unable to determine
|
||||
# it's realpath.
|
||||
absolute: (relativePath) ->
|
||||
return null unless relativePath?
|
||||
|
||||
@@ -25,11 +38,12 @@ fsExtensions =
|
||||
catch e
|
||||
relativePath
|
||||
|
||||
# Returns true if a file or folder at the specified path exists.
|
||||
# Public: Returns true if a file or folder at the specified path exists.
|
||||
exists: (pathToCheck) ->
|
||||
# TODO: rename to existsSync
|
||||
pathToCheck? and fs.statSyncNoException(pathToCheck) isnt false
|
||||
|
||||
# Returns true if the specified path is a directory that exists.
|
||||
# Public: Returns true if the given path exists and is a directory.
|
||||
isDirectorySync: (directoryPath) ->
|
||||
return false unless directoryPath?.length > 0
|
||||
if stat = fs.statSyncNoException(directoryPath)
|
||||
@@ -37,6 +51,7 @@ fsExtensions =
|
||||
else
|
||||
false
|
||||
|
||||
# Public: Asynchronously checks that the given path exists and is a directory.
|
||||
isDirectory: (directoryPath, done) ->
|
||||
return done(false) unless directoryPath?.length > 0
|
||||
fs.exists directoryPath, (exists) ->
|
||||
@@ -49,7 +64,7 @@ fsExtensions =
|
||||
else
|
||||
done(false)
|
||||
|
||||
# Returns true if the specified path is a regular file that exists.
|
||||
# Public: Returns true if the specified path exists and is a file.
|
||||
isFileSync: (filePath) ->
|
||||
return false unless filePath?.length > 0
|
||||
if stat = fs.statSyncNoException(filePath)
|
||||
@@ -57,7 +72,7 @@ fsExtensions =
|
||||
else
|
||||
false
|
||||
|
||||
# Returns true if the specified path is executable.
|
||||
# Public: Returns true if the specified path is executable.
|
||||
isExecutableSync: (pathToCheck) ->
|
||||
return false unless pathToCheck?.length > 0
|
||||
if stat = fs.statSyncNoException(pathToCheck)
|
||||
@@ -65,8 +80,14 @@ fsExtensions =
|
||||
else
|
||||
false
|
||||
|
||||
# Returns an array with the paths of the files and folders
|
||||
# contained in the directory path.
|
||||
# Public: Returns an Array with the paths of the files and directories
|
||||
# contained within the directory path. It is not recursive.
|
||||
#
|
||||
# * rootPath:
|
||||
# The absolute path to the directory to list.
|
||||
# * extensions:
|
||||
# An array of extensions to filter the results by. If none are given, none
|
||||
# are filtered (optional).
|
||||
listSync: (rootPath, extensions) ->
|
||||
return [] unless @isDirectorySync(rootPath)
|
||||
paths = fs.readdirSync(rootPath)
|
||||
@@ -74,6 +95,16 @@ fsExtensions =
|
||||
paths = paths.map (childPath) -> path.join(rootPath, childPath)
|
||||
paths
|
||||
|
||||
# Public: Asynchronously lists the files and directories in the given path.
|
||||
# The listing is not recursive.
|
||||
#
|
||||
# * rootPath:
|
||||
# The absolute path to the directory to list.
|
||||
# * extensions:
|
||||
# An array of extensions to filter the results by. If none are given, none
|
||||
# are filtered (optional)
|
||||
# * callback:
|
||||
# The function to call
|
||||
list: (rootPath, rest...) ->
|
||||
extensions = rest.shift() if rest.length > 1
|
||||
done = rest.shift()
|
||||
@@ -85,6 +116,7 @@ fsExtensions =
|
||||
paths = paths.map (childPath) -> path.join(rootPath, childPath)
|
||||
done(null, paths)
|
||||
|
||||
# Private: Returns only the paths which end with one of the given extensions.
|
||||
filterExtensions: (paths, extensions) ->
|
||||
extensions = extensions.map (ext) ->
|
||||
if ext is ''
|
||||
@@ -93,6 +125,7 @@ fsExtensions =
|
||||
'.' + ext.replace(/^\./, '')
|
||||
paths.filter (pathToCheck) -> _.include(extensions, path.extname(pathToCheck))
|
||||
|
||||
# Deprecated: No one currently uses this.
|
||||
listTreeSync: (rootPath) ->
|
||||
paths = []
|
||||
onPath = (childPath) ->
|
||||
@@ -101,22 +134,34 @@ fsExtensions =
|
||||
@traverseTreeSync(rootPath, onPath, onPath)
|
||||
paths
|
||||
|
||||
# Public: Moves the file or directory to the target synchronously.
|
||||
move: (source, target) ->
|
||||
# TODO: This should be renamed to moveSync
|
||||
fs.renameSync(source, target)
|
||||
|
||||
# Remove the file or directory at the given path.
|
||||
# Public: Removes the file or directory at the given path synchronously.
|
||||
remove: (pathToRemove) ->
|
||||
# TODO: This should be renamed to removeSync
|
||||
rimraf.sync(pathToRemove)
|
||||
|
||||
# Open, read, and close a file, returning the file's contents.
|
||||
# Public: Open, read, and close a file, returning the file's contents
|
||||
# synchronously.
|
||||
read: (filePath) ->
|
||||
# TODO: This should be renamed to readSync
|
||||
fs.readFileSync(filePath, 'utf8')
|
||||
|
||||
# Open, write, flush, and close a file, writing the given content.
|
||||
# Public: Open, write, flush, and close a file, writing the given content
|
||||
# synchronously.
|
||||
#
|
||||
# It also creates the necessary parent directories.
|
||||
writeSync: (filePath, content) ->
|
||||
mkdirp.sync(path.dirname(filePath))
|
||||
fs.writeFileSync(filePath, content)
|
||||
|
||||
# Public: Open, write, flush, and close a file, writing the given content
|
||||
# asynchronously.
|
||||
#
|
||||
# It also creates the necessary parent directories.
|
||||
write: (filePath, content, callback) ->
|
||||
mkdirp path.dirname(filePath), (error) ->
|
||||
if error?
|
||||
@@ -124,6 +169,7 @@ fsExtensions =
|
||||
else
|
||||
fs.writeFile(filePath, content, callback)
|
||||
|
||||
# Public: Copies the given path asynchronously.
|
||||
copy: (sourcePath, destinationPath, done) ->
|
||||
mkdirp path.dirname(destinationPath), (error) ->
|
||||
if error?
|
||||
@@ -145,11 +191,23 @@ fsExtensions =
|
||||
|
||||
sourceStream.pipe(destinationStream)
|
||||
|
||||
# Create a directory at the specified path including any missing parent
|
||||
# directories.
|
||||
# Public: Create a directory at the specified path including any missing
|
||||
# parent directories synchronously.
|
||||
makeTree: (directoryPath) ->
|
||||
# TODO: rename to makeTreeSync
|
||||
mkdirp.sync(directoryPath) if directoryPath and not @exists(directoryPath)
|
||||
|
||||
# Public: Recursively walk the given path and execute the given functions
|
||||
# synchronously.
|
||||
#
|
||||
# * rootPath:
|
||||
# The String containing the directory to recurse into.
|
||||
# * onFile:
|
||||
# The function to execute on each file, receives a single argument the
|
||||
# absolute path.
|
||||
# * onDirectory:
|
||||
# The function to execute on each directory, receives a single argument the
|
||||
# absolute path (defaults to onFile)
|
||||
traverseTreeSync: (rootPath, onFile, onDirectory=onFile) ->
|
||||
return unless @isDirectorySync(rootPath)
|
||||
|
||||
@@ -167,6 +225,17 @@ fsExtensions =
|
||||
|
||||
traverse(rootPath, onFile, onDirectory)
|
||||
|
||||
# Public: Recursively walk the given path and execute the given functions
|
||||
# asynchronously.
|
||||
#
|
||||
# * rootPath:
|
||||
# The String containing the directory to recurse into.
|
||||
# * onFile:
|
||||
# The function to execute on each file, receives a single argument the
|
||||
# absolute path.
|
||||
# * onDirectory:
|
||||
# The function to execute on each directory, receives a single argument the
|
||||
# absolute path (defaults to onFile)
|
||||
traverseTree: (rootPath, onFile, onDirectory, onDone) ->
|
||||
fs.readdir rootPath, (error, files) ->
|
||||
if error
|
||||
@@ -194,10 +263,28 @@ fsExtensions =
|
||||
queue.drain = onDone
|
||||
queue.push(path.join(rootPath, file)) for file in files
|
||||
|
||||
# Public: Hashes the contents of the given file.
|
||||
#
|
||||
# * pathToDigest:
|
||||
# The String containing the absolute path.
|
||||
#
|
||||
# Returns a String containing the MD5 hexadecimal hash.
|
||||
md5ForPath: (pathToDigest) ->
|
||||
contents = fs.readFileSync(pathToDigest)
|
||||
require('crypto').createHash('md5').update(contents).digest('hex')
|
||||
|
||||
# Public: Finds a relative path among the given array of paths.
|
||||
#
|
||||
# * loadPaths:
|
||||
# An Array of absolute and relative paths to search.
|
||||
# * pathToResolve:
|
||||
# The string containing the path to resolve.
|
||||
# * extensions:
|
||||
# An array of extensions to pass to {resolveExtensions} in which case
|
||||
# pathToResolve should not contain an extension (optional).
|
||||
#
|
||||
# Returns the absolute path of the file to be resolved if it's found and
|
||||
# undefined otherwise.
|
||||
resolve: (args...) ->
|
||||
extensions = args.pop() if _.isArray(_.last(args))
|
||||
pathToResolve = args.pop()
|
||||
@@ -218,10 +305,22 @@ fsExtensions =
|
||||
return @absolute(candidatePath) if @exists(candidatePath)
|
||||
undefined
|
||||
|
||||
# Deprecated:
|
||||
resolveOnLoadPath: (args...) ->
|
||||
loadPaths = Module.globalPaths.concat(module.paths)
|
||||
@resolve(loadPaths..., args...)
|
||||
|
||||
# Public: Finds the first file in the given path which matches the extension
|
||||
# in the order given.
|
||||
#
|
||||
# * pathToResolve:
|
||||
# The String containing relative or absolute path of the file in question
|
||||
# without the extension or '.'.
|
||||
# * extensions:
|
||||
# The ordered Array of extensions to try.
|
||||
#
|
||||
# Returns the absolute path of the file if it exists with any of the given
|
||||
# extensions, otherwise it's undefined.
|
||||
resolveExtension: (pathToResolve, extensions) ->
|
||||
for extension in extensions
|
||||
if extension == ""
|
||||
@@ -231,6 +330,7 @@ fsExtensions =
|
||||
return @absolute(pathWithExtension) if @exists(pathWithExtension)
|
||||
undefined
|
||||
|
||||
# Public: Returns true for extensions associated with compressed files.
|
||||
isCompressedExtension: (ext) ->
|
||||
_.indexOf([
|
||||
'.gz'
|
||||
@@ -240,6 +340,7 @@ fsExtensions =
|
||||
'.zip'
|
||||
], ext, true) >= 0
|
||||
|
||||
# Public: Returns true for extensions associated with image files.
|
||||
isImageExtension: (ext) ->
|
||||
_.indexOf([
|
||||
'.gif'
|
||||
@@ -249,9 +350,27 @@ fsExtensions =
|
||||
'.tiff'
|
||||
], ext, true) >= 0
|
||||
|
||||
# Public: Returns true for extensions associated with pdf files.
|
||||
isPdfExtension: (ext) ->
|
||||
ext is '.pdf'
|
||||
|
||||
# Public: Returns true for extensions associated with binary files.
|
||||
isBinaryExtension: (ext) ->
|
||||
_.indexOf([
|
||||
'.DS_Store'
|
||||
'.a'
|
||||
'.o'
|
||||
'.so'
|
||||
'.woff'
|
||||
], ext, true) >= 0
|
||||
|
||||
# Public: Returns true for files named similarily to 'README'
|
||||
isReadmePath: (readmePath) ->
|
||||
extension = path.extname(readmePath)
|
||||
base = path.basename(readmePath, extension).toLowerCase()
|
||||
base is 'readme' and (extension is '' or @isMarkdownExtension(extension))
|
||||
|
||||
# Private: Used by isReadmePath.
|
||||
isMarkdownExtension: (ext) ->
|
||||
_.indexOf([
|
||||
'.markdown'
|
||||
@@ -262,24 +381,30 @@ fsExtensions =
|
||||
'.ron'
|
||||
], ext, true) >= 0
|
||||
|
||||
isBinaryExtension: (ext) ->
|
||||
_.indexOf([
|
||||
'.DS_Store'
|
||||
'.a'
|
||||
'.o'
|
||||
'.so'
|
||||
'.woff'
|
||||
], ext, true) >= 0
|
||||
# Public: Reads and returns CSON, JSON or Plist files and returns the
|
||||
# corresponding Object.
|
||||
readObjectSync: (objectPath) ->
|
||||
CSON = require 'season'
|
||||
if CSON.isObjectPath(objectPath)
|
||||
CSON.readFileSync(objectPath)
|
||||
else
|
||||
@readPlistSync(objectPath)
|
||||
|
||||
isReadmePath: (readmePath) ->
|
||||
extension = path.extname(readmePath)
|
||||
base = path.basename(readmePath, extension).toLowerCase()
|
||||
base is 'readme' and (extension is '' or @isMarkdownExtension(extension))
|
||||
# Public: Reads and returns CSON, JSON or Plist files and calls the specified
|
||||
# callback with the corresponding Object.
|
||||
readObject: (objectPath, done) ->
|
||||
CSON = require 'season'
|
||||
if CSON.isObjectPath(objectPath)
|
||||
CSON.readFile(objectPath, done)
|
||||
else
|
||||
@readPlist(objectPath, done)
|
||||
|
||||
# Private: Used by readObjectSync.
|
||||
readPlistSync: (plistPath) ->
|
||||
plist = require 'plist'
|
||||
plist.parseStringSync(@read(plistPath))
|
||||
|
||||
# Private: Used by readObject.
|
||||
readPlist: (plistPath, done) ->
|
||||
plist = require 'plist'
|
||||
fs.readFile plistPath, 'utf8', (error, contents) ->
|
||||
@@ -291,18 +416,4 @@ fsExtensions =
|
||||
catch parseError
|
||||
done(parseError)
|
||||
|
||||
readObjectSync: (objectPath) ->
|
||||
CSON = require 'season'
|
||||
if CSON.isObjectPath(objectPath)
|
||||
CSON.readFileSync(objectPath)
|
||||
else
|
||||
@readPlistSync(objectPath)
|
||||
|
||||
readObject: (objectPath, done) ->
|
||||
CSON = require 'season'
|
||||
if CSON.isObjectPath(objectPath)
|
||||
CSON.readFile(objectPath, done)
|
||||
else
|
||||
@readPlist(objectPath, done)
|
||||
|
||||
module.exports = _.extend({}, fs, fsExtensions)
|
||||
|
||||
Reference in New Issue
Block a user