UNPKG

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