-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathneeds.js
executable file
·137 lines (122 loc) · 3.69 KB
/
needs.js
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#!/usr/bin/env node
const fs = require("fs")
const { promisify } = require("util")
const readFile = promisify(fs.readFile)
// Note, you can *not* use require("fs").promises, because that messes
// with the pkg's local /snapshot file system.
const path = require("path")
const Types = require("./lib/types.js")
const types = new Types()
const And = types.get("and")
const { check } = require("./cmd/check.js")
async function loadNeedsFromFile(file) {
try {
let raw = await readFile(file)
return new And({
type: "and",
needs: JSON.parse(raw.toString())
}, types)
} catch (err) {
if (err.code === "ENOENT") {
console.error("Needs file not found. Please try again with the \"--file\" option.")
} else if (err.name === "SyntaxError") {
console.error("Needs file was invalid: Invalid JSON")
} else if (err.name === "ValidationError") {
console.error(`Needs file was invalid: ${err.message}`)
console.error(" Details:", err.details)
} else {
console.error(err)
}
process.exit(1)
}
}
async function loadVersion() {
try {
let rawVersion = await readFile(path.join(__dirname, "version"))
return rawVersion.toString()
} catch (err) {
console.error("Failed to load version: ", err)
process.exit(1)
}
}
async function listCommand(args) {
let needs = await loadNeedsFromFile(args.argv.file)
console.log(JSON.stringify(needs.needs, null, 2))
}
async function checkCommandBuilder(yargs) {
return yargs
.option("identify", {
type: "boolean",
default: true,
describe: "Identify the satisfied needs with \"identify\" fields. Disable with --no-identify."
})
.option("colorize", {
type: "boolean",
default: true,
describe: "Use terminal colors",
})
// If stdout is *not* a TTY (e.g. being piped to some other command), disable colors
.coerce("colorize", colorize => colorize && Boolean(process.stdout.isTTY))
.option("satisfied", {
type: "boolean",
describe: "Only list satisfied needs"
})
.option("unsatisfied", {
type: "boolean",
describe: "Only list unsatisfied needs"
})
}
async function checkCommand(args) {
let needs = await loadNeedsFromFile(args.file)
try {
process.exit(await check(needs, args) ? 0 : 1)
} catch (err) {
console.error("Failed to check needs: ", err)
process.exit(1)
}
}
function typesCommand() {
console.log("Supported types:")
types.all().sort().forEach((type) => {
console.log(` ${type}`)
})
}
function typeCommand(args) {
if (types.has(args.typeName)) {
let type = types.get(args.typeName)
console.log(type.info)
} else {
console.error(`Type "${args.typeName}" does not exist`)
console.error(`Use "${args.$0} types" to get the list of installed types`)
process.exit(1)
}
}
function typeCommandBuilder(yargs) {
return yargs.positional("typeName", {
describe: "The name of the type",
type: "string"
})
}
async function run() {
let version = await loadVersion()
require("yargs")
.option("f", {
alias: "file",
default: path.join(process.cwd(), "needs.json"),
describe: "The needs.json file to use",
demandOption: true,
type: "string",
normalize: true,
})
.command("list", "List and validate needs in the needs file", listCommand)
.command("check", "Check if the needs are satisfied", checkCommandBuilder, checkCommand)
.command("types", "List available need types", typesCommand)
.command("type <typeName>", "Describe a given type", typeCommandBuilder, typeCommand)
.demandCommand(1, "Please specify a command")
.strict(true)
.version(version)
.help()
.alias("h", "help")
.argv
}
run()