UNPKG

4.06 kBJavaScriptView Raw
1var path = require('path');
2var fs = require('fs');
3var common = require('./common');
4var glob = require('glob');
5
6var globPatternRecursive = path.sep + '**';
7
8common.register('ls', _ls, {
9 cmdOptions: {
10 'R': 'recursive',
11 'A': 'all',
12 'L': 'link',
13 'a': 'all_deprecated',
14 'd': 'directory',
15 'l': 'long',
16 },
17});
18
19//@
20//@ ### ls([options,] [path, ...])
21//@ ### ls([options,] path_array)
22//@ Available options:
23//@
24//@ + `-R`: recursive
25//@ + `-A`: all files (include files beginning with `.`, except for `.` and `..`)
26//@ + `-L`: follow symlinks
27//@ + `-d`: list directories themselves, not their contents
28//@ + `-l`: list objects representing each file, each with fields containing `ls
29//@ -l` output fields. See
30//@ [fs.Stats](https://nodejs.org/api/fs.html#fs_class_fs_stats)
31//@ for more info
32//@
33//@ Examples:
34//@
35//@ ```javascript
36//@ ls('projs/*.js');
37//@ ls('-R', '/users/me', '/tmp');
38//@ ls('-R', ['/users/me', '/tmp']); // same as above
39//@ ls('-l', 'file.txt'); // { name: 'file.txt', mode: 33188, nlink: 1, ...}
40//@ ```
41//@
42//@ Returns array of files in the given path, or in current directory if no path provided.
43function _ls(options, paths) {
44 if (options.all_deprecated) {
45 // We won't support the -a option as it's hard to image why it's useful
46 // (it includes '.' and '..' in addition to '.*' files)
47 // For backwards compatibility we'll dump a deprecated message and proceed as before
48 common.log('ls: Option -a is deprecated. Use -A instead');
49 options.all = true;
50 }
51
52 if (!paths) {
53 paths = ['.'];
54 } else {
55 paths = [].slice.call(arguments, 1);
56 }
57
58 var list = [];
59
60 function pushFile(abs, relName, stat) {
61 if (process.platform === 'win32') {
62 relName = relName.replace(/\\/g, '/');
63 }
64 if (options.long) {
65 stat = stat || (options.link ? common.statFollowLinks(abs) : common.statNoFollowLinks(abs));
66 list.push(addLsAttributes(relName, stat));
67 } else {
68 // list.push(path.relative(rel || '.', file));
69 list.push(relName);
70 }
71 }
72
73 paths.forEach(function (p) {
74 var stat;
75
76 try {
77 stat = options.link ? common.statFollowLinks(p) : common.statNoFollowLinks(p);
78 // follow links to directories by default
79 if (stat.isSymbolicLink()) {
80 try {
81 var _stat = common.statFollowLinks(p);
82 if (_stat.isDirectory()) {
83 stat = _stat;
84 }
85 } catch (_) {} // bad symlink, treat it like a file
86 }
87 } catch (e) {
88 common.error('no such file or directory: ' + p, 2, { continue: true });
89 return;
90 }
91
92 // If the stat succeeded
93 if (stat.isDirectory() && !options.directory) {
94 if (options.recursive) {
95 // use glob, because it's simple
96 glob.sync(p + globPatternRecursive, { dot: options.all, follow: options.link })
97 .forEach(function (item) {
98 // Glob pattern returns the directory itself and needs to be filtered out.
99 if (path.relative(p, item)) {
100 pushFile(item, path.relative(p, item));
101 }
102 });
103 } else if (options.all) {
104 // use fs.readdirSync, because it's fast
105 fs.readdirSync(p).forEach(function (item) {
106 pushFile(path.join(p, item), item);
107 });
108 } else {
109 // use fs.readdirSync and then filter out secret files
110 fs.readdirSync(p).forEach(function (item) {
111 if (item[0] !== '.') {
112 pushFile(path.join(p, item), item);
113 }
114 });
115 }
116 } else {
117 pushFile(p, p, stat);
118 }
119 });
120
121 // Add methods, to make this more compatible with ShellStrings
122 return list;
123}
124
125function addLsAttributes(pathName, stats) {
126 // Note: this object will contain more information than .toString() returns
127 stats.name = pathName;
128 stats.toString = function () {
129 // Return a string resembling unix's `ls -l` format
130 return [this.mode, this.nlink, this.uid, this.gid, this.size, this.mtime, this.name].join(' ');
131 };
132 return stats;
133}
134
135module.exports = _ls;