-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.js
More file actions
104 lines (95 loc) · 2.37 KB
/
index.js
File metadata and controls
104 lines (95 loc) · 2.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
const fs = require("fs");
const path = require("path");
const {promisify} = require("util");
const yaml = require("js-yaml");
const dedent = require("dedent");
const tmp = require("tmp");
const writeFile = promisify(fs.writeFile);
const mkdir = promisify(fs.mkdir);
function getTmpDir() {
return new Promise((resolve, reject) => {
tmp.dir({unsafeCleanup: true}, (err, path, cleanup) => {
if (err) {
reject(err);
return;
}
resolve({
path,
cleanup: () => new Promise(resolve => cleanup(resolve))
});
});
});
}
function yaml2tree(text) {
const result = yaml.safeLoad(dedent(text));
return [...genChildren(result)];
function* genChildren(children) {
if (!children) {
return;
}
if (!Array.isArray(children)) {
children = Object.entries(children);
}
for (const child of children) {
if (typeof child === "string") {
yield {type: "file", name: child};
} else {
const list = Array.isArray(child) ? [child] : Object.entries(child);
for (const [name, data] of list) {
if (typeof data === "string") {
yield {type: "file", name, data};
} else {
yield {type: "dir", name, children: [...genChildren(data)]};
}
}
}
}
}
}
function tree2dir(base, children) {
return Promise.all(children.map(async child => {
if (child.type === "file") {
const name = path.resolve(base, child.name);
return await writeFile(name, child.data || "");
}
if (child.type === "dir") {
const name = path.resolve(base, child.name);
await mkdir(name);
return await tree2dir(name, child.children);
}
throw new TypeError(`unknown type: '${child.type}'`);
}));
}
async function makeDir(text) {
// text could be null
const children = text && yaml2tree(text);
const {path: base, cleanup} = await getTmpDir();
if (children) {
await tree2dir(base, children);
}
return {
resolve: (...args) => path.resolve(base, ...args),
cleanup
};
}
async function withDir(text, onReady) {
if (typeof text === "function") {
onReady = text;
text = null;
}
let dir;
try {
dir = await makeDir(text);
return await onReady(dir.resolve);
} finally {
if (dir) {
await dir.cleanup();
}
}
}
module.exports = {
makeDir,
withDir,
yaml2tree,
tree2dir
};