UNPKG

5.21 kBJavaScriptView Raw
1"use strict";
2
3const crypto = require("crypto");
4const pathUtil = require("path");
5const inspect = require("./inspect");
6const list = require("./list");
7const validate = require("./utils/validate");
8
9const validateInput = (methodName, path, options) => {
10 const methodSignature = `${methodName}(path, [options])`;
11 validate.argument(methodSignature, "path", path, ["string"]);
12 validate.options(methodSignature, "options", options, {
13 checksum: ["string"],
14 relativePath: ["boolean"],
15 times: ["boolean"],
16 symlinks: ["string"]
17 });
18
19 if (
20 options &&
21 options.checksum !== undefined &&
22 inspect.supportedChecksumAlgorithms.indexOf(options.checksum) === -1
23 ) {
24 throw new Error(
25 `Argument "options.checksum" passed to ${methodSignature} must have one of values: ${inspect.supportedChecksumAlgorithms.join(
26 ", "
27 )}`
28 );
29 }
30
31 if (
32 options &&
33 options.symlinks !== undefined &&
34 inspect.symlinkOptions.indexOf(options.symlinks) === -1
35 ) {
36 throw new Error(
37 `Argument "options.symlinks" passed to ${methodSignature} must have one of values: ${inspect.symlinkOptions.join(
38 ", "
39 )}`
40 );
41 }
42};
43
44const generateTreeNodeRelativePath = (parent, path) => {
45 if (!parent) {
46 return ".";
47 }
48 return `${parent.relativePath}/${pathUtil.basename(path)}`;
49};
50
51// Creates checksum of a directory by using
52// checksums and names of all its children inside.
53const checksumOfDir = (inspectList, algo) => {
54 const hash = crypto.createHash(algo);
55 inspectList.forEach(inspectObj => {
56 hash.update(inspectObj.name + inspectObj[algo]);
57 });
58 return hash.digest("hex");
59};
60
61// ---------------------------------------------------------
62// Sync
63// ---------------------------------------------------------
64
65const inspectTreeNodeSync = (path, options, parent) => {
66 const treeBranch = inspect.sync(path, options);
67
68 if (treeBranch) {
69 if (options.relativePath) {
70 treeBranch.relativePath = generateTreeNodeRelativePath(parent, path);
71 }
72
73 if (treeBranch.type === "dir") {
74 treeBranch.size = 0;
75 treeBranch.children = list.sync(path).map(filename => {
76 const subBranchPath = pathUtil.join(path, filename);
77 const treeSubBranch = inspectTreeNodeSync(
78 subBranchPath,
79 options,
80 treeBranch
81 );
82 // Add together all childrens' size to get directory combined size.
83 treeBranch.size += treeSubBranch.size || 0;
84 return treeSubBranch;
85 });
86
87 if (options.checksum) {
88 treeBranch[options.checksum] = checksumOfDir(
89 treeBranch.children,
90 options.checksum
91 );
92 }
93 }
94 }
95
96 return treeBranch;
97};
98
99const inspectTreeSync = (path, options) => {
100 const opts = options || {};
101 return inspectTreeNodeSync(path, opts, undefined);
102};
103
104// ---------------------------------------------------------
105// Async
106// ---------------------------------------------------------
107
108const inspectTreeNodeAsync = (path, options, parent) => {
109 return new Promise((resolve, reject) => {
110 const inspectAllChildren = treeBranch => {
111 return new Promise((resolve2, reject2) => {
112 list.async(path).then(children => {
113 const doNext = index => {
114 if (index === children.length) {
115 if (options.checksum) {
116 // We are done, but still have to calculate checksum of whole directory.
117 treeBranch[options.checksum] = checksumOfDir(
118 treeBranch.children,
119 options.checksum
120 );
121 }
122 resolve2();
123 } else {
124 const subPath = pathUtil.join(path, children[index]);
125 inspectTreeNodeAsync(subPath, options, treeBranch)
126 .then(treeSubBranch => {
127 children[index] = treeSubBranch;
128 treeBranch.size += treeSubBranch.size || 0;
129 doNext(index + 1);
130 })
131 .catch(reject2);
132 }
133 };
134
135 treeBranch.children = children;
136 treeBranch.size = 0;
137
138 doNext(0);
139 });
140 });
141 };
142
143 inspect
144 .async(path, options)
145 .then(treeBranch => {
146 if (!treeBranch) {
147 // Given path doesn't exist. We are done.
148 resolve(treeBranch);
149 } else {
150 if (options.relativePath) {
151 treeBranch.relativePath = generateTreeNodeRelativePath(
152 parent,
153 path
154 );
155 }
156
157 if (treeBranch.type !== "dir") {
158 resolve(treeBranch);
159 } else {
160 inspectAllChildren(treeBranch)
161 .then(() => {
162 resolve(treeBranch);
163 })
164 .catch(reject);
165 }
166 }
167 })
168 .catch(reject);
169 });
170};
171
172const inspectTreeAsync = (path, options) => {
173 const opts = options || {};
174 return inspectTreeNodeAsync(path, opts);
175};
176
177// ---------------------------------------------------------
178// API
179// ---------------------------------------------------------
180
181exports.validateInput = validateInput;
182exports.sync = inspectTreeSync;
183exports.async = inspectTreeAsync;