1 | "use strict";
|
2 |
|
3 | const crypto = require("crypto");
|
4 | const pathUtil = require("path");
|
5 | const inspect = require("./inspect");
|
6 | const list = require("./list");
|
7 | const validate = require("./utils/validate");
|
8 |
|
9 | const 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 |
|
44 | const generateTreeNodeRelativePath = (parent, path) => {
|
45 | if (!parent) {
|
46 | return ".";
|
47 | }
|
48 | return `${parent.relativePath}/${pathUtil.basename(path)}`;
|
49 | };
|
50 |
|
51 |
|
52 |
|
53 | const 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 |
|
63 |
|
64 |
|
65 | const 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 |
|
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 |
|
99 | const inspectTreeSync = (path, options) => {
|
100 | const opts = options || {};
|
101 | return inspectTreeNodeSync(path, opts, undefined);
|
102 | };
|
103 |
|
104 |
|
105 |
|
106 |
|
107 |
|
108 | const 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 |
|
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 |
|
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 |
|
172 | const inspectTreeAsync = (path, options) => {
|
173 | const opts = options || {};
|
174 | return inspectTreeNodeAsync(path, opts);
|
175 | };
|
176 |
|
177 |
|
178 |
|
179 |
|
180 |
|
181 | exports.validateInput = validateInput;
|
182 | exports.sync = inspectTreeSync;
|
183 | exports.async = inspectTreeAsync;
|