openmrs 3.1.13-pre.667 → 3.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,16 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
- var __assign = (this && this.__assign) || function () {
4
- __assign = Object.assign || function(t) {
5
- for (var s, i = 1, n = arguments.length; i < n; i++) {
6
- s = arguments[i];
7
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
8
- t[p] = s[p];
9
- }
10
- return t;
11
- };
12
- return __assign.apply(this, arguments);
13
- };
14
3
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
15
4
  if (k2 === undefined) k2 = k;
16
5
  Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
@@ -39,209 +28,161 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
39
28
  step((generator = generator.apply(thisArg, _arguments || [])).next());
40
29
  });
41
30
  };
42
- var __generator = (this && this.__generator) || function (thisArg, body) {
43
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
44
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
45
- function verb(n) { return function (v) { return step([n, v]); }; }
46
- function step(op) {
47
- if (f) throw new TypeError("Generator is already executing.");
48
- while (_) try {
49
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
50
- if (y = 0, t) op = [op[0] & 2, t.value];
51
- switch (op[0]) {
52
- case 0: case 1: t = op; break;
53
- case 4: _.label++; return { value: op[1], done: false };
54
- case 5: _.label++; y = op[1]; op = [0]; continue;
55
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
56
- default:
57
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
58
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
59
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
60
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
61
- if (t[2]) _.ops.pop();
62
- _.trys.pop(); continue;
63
- }
64
- op = body.call(thisArg, _);
65
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
66
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
67
- }
68
- };
69
- exports.__esModule = true;
70
- var yargs = __importStar(require("yargs"));
71
- var child_process_1 = require("child_process");
72
- var path_1 = require("path");
73
- var utils_1 = require("./utils");
74
- var runner = (0, path_1.resolve)(__dirname, "runner.js");
75
- var root = (0, path_1.resolve)(__dirname, "..");
31
+ Object.defineProperty(exports, "__esModule", { value: true });
32
+ const yargs = __importStar(require("yargs"));
33
+ const child_process_1 = require("child_process");
34
+ const path_1 = require("path");
35
+ const utils_1 = require("./utils");
36
+ const runner = (0, path_1.resolve)(__dirname, `runner.js`);
37
+ const root = (0, path_1.resolve)(__dirname, "..");
76
38
  function runCommand(type, args) {
77
- var ps = (0, child_process_1.fork)(runner, [], { cwd: root });
39
+ const ps = (0, child_process_1.fork)(runner, [], { cwd: root });
78
40
  ps.send({
79
- type: type,
80
- args: args
41
+ type,
42
+ args,
81
43
  });
82
- ps.on("exit", function (code) { return process.exit(code || 0); });
44
+ ps.on("exit", (code) => process.exit(code || 0));
83
45
  }
84
- yargs.command("debug", "Starts a new debugging session of the OpenMRS app shell. This uses Webpack as a debug server with proxy middleware.", function (argv) {
85
- return argv
86
- .number("port")["default"]("port", 8080)
87
- .describe("port", "The port where the dev server should run.")
88
- .number("host")["default"]("host", "localhost")
89
- .describe("host", "The host name or IP for the server to use.")
90
- .string("backend")["default"]("backend", "https://openmrs-spa.org/")
91
- .describe("backend", "The backend to proxy API requests to.")
92
- .boolean("support-offline")
93
- .describe("support-offline", "Determines if a service worker should be installed for offline support.")["default"]("support-offline", true)
94
- .string("spa-path")["default"]("spa-path", "/openmrs/spa/")
95
- .describe("spa-path", "The path of the application on the target server.")
96
- .string("api-url")["default"]("api-url", "/openmrs/")
97
- .describe("api-url", "The URL of the API. Can be a path if the API is on the same target server.")
98
- .string("page-title")["default"]("page-title", "OpenMRS")
99
- .describe("page-title", "The title of the web app usually displayed in the browser tab.")
100
- .array("config-url")["default"]("config-url", [])
101
- .describe("config-url", "The URL to a valid frontend configuration. Can be used multiple times.")
102
- .boolean("run-project")["default"]("run-project", false)
103
- .describe("run-project", "Runs the project in the current directory fusing it with the specified import map.")
104
- .array("sources")["default"]("sources", ["."])
105
- .describe("sources", "Runs the projects from the provided source directories. Can be used multiple times.")
106
- .array("shared-dependencies")["default"]("shared-dependencies", [])
107
- .describe("shared-dependencies", "The additional shared dependencies besides the ones from the app shell.")
108
- .string("importmap")["default"]("importmap", "importmap.json")
109
- .describe("importmap", "The import map to use. Can be a path to a valid import map to be taken literally, an URL, or a fixed JSON object.");
110
- }, function (args) { return __awaiter(void 0, void 0, void 0, function () {
111
- var _a, _b, _c, _d, _e, _f, _g;
112
- var _h;
113
- return __generator(this, function (_j) {
114
- switch (_j.label) {
115
- case 0:
116
- _a = runCommand;
117
- _b = ["runDebug"];
118
- _c = [__assign({ apiUrl: args["api-url"], spaPath: args["spa-path"], configUrls: args["config-url"], pageTitle: args["page-title"], supportOffline: args["support-offline"] }, args)];
119
- _h = {};
120
- _d = utils_1.proxyImportmap;
121
- _e = utils_1.mergeImportmap;
122
- return [4 /*yield*/, (0, utils_1.getImportmap)(args.importmap, args.port)];
123
- case 1:
124
- _f = [_j.sent()];
125
- _g = (args["run-project"] || args.runProject);
126
- if (!_g) return [3 /*break*/, 3];
127
- return [4 /*yield*/, (0, utils_1.runProject)(args.port, args["shared-dependencies"], args.sources)];
128
- case 2:
129
- _g = (_j.sent());
130
- _j.label = 3;
131
- case 3: return [4 /*yield*/, _e.apply(void 0, _f.concat([_g]))];
132
- case 4: return [2 /*return*/, _a.apply(void 0, _b.concat([__assign.apply(void 0, _c.concat([(_h.importmap = _d.apply(void 0, [_j.sent(), args.backend,
133
- args.host,
134
- args.port]), _h)]))]))];
135
- }
136
- });
137
- }); });
138
- yargs.command("develop", "Starts a new frontend module development session with the OpenMRS app shell.", function (argv) {
139
- return argv
140
- .number("port")["default"]("port", 8080)
141
- .describe("port", "The port where the dev server should run.")
142
- .number("host")["default"]("host", "localhost")
143
- .describe("host", "The host name or IP for the server to use.")
144
- .string("backend")["default"]("backend", "https://openmrs-spa.org/")
145
- .describe("backend", "The backend to proxy API requests to.")
146
- .string("spa-path")["default"]("spa-path", "/openmrs/spa/")
147
- .describe("spa-path", "The path of the application on the target server.")
148
- .string("api-url")["default"]("api-url", "/openmrs/")
149
- .describe("api-url", "The URL of the API. Can be a path if the API is on the same target server.")
150
- .boolean("open")["default"]("open", true)
151
- .describe("open", "Immediately opens the SPA page URL in the browser.")
152
- .array("config-url")["default"]("config-url", [])
153
- .describe("config-url", "The URL to a valid frontend configuration. Can be used multiple times.")
154
- .array("sources")["default"]("sources", ["."])
155
- .describe("sources", "Runs the projects from the provided source directories. Can be used multiple times.")
156
- .array("shared-dependencies")["default"]("shared-dependencies", [])
157
- .describe("shared-dependencies", "The additional shared dependencies besides the ones from the app shell.")
158
- .string("importmap")["default"]("importmap", "importmap.json")
159
- .describe("importmap", "The import map to use. Can be a path to a valid import map to be taken literally, an URL, or a fixed JSON object.");
160
- }, function (args) { return __awaiter(void 0, void 0, void 0, function () {
161
- var _a, _b, _c, _d, _e, _f, _g;
162
- var _h;
163
- return __generator(this, function (_j) {
164
- switch (_j.label) {
165
- case 0:
166
- _a = runCommand;
167
- _b = ["runDevelop"];
168
- _c = [__assign({ apiUrl: args["api-url"], spaPath: args["spa-path"], configUrls: args["config-url"] }, args)];
169
- _h = {};
170
- _d = utils_1.proxyImportmap;
171
- _e = utils_1.mergeImportmap;
172
- return [4 /*yield*/, (0, utils_1.getImportmap)(args.importmap, args.port)];
173
- case 1:
174
- _f = [_j.sent()];
175
- _g = args.sources[0] !== false;
176
- if (!_g) return [3 /*break*/, 3];
177
- return [4 /*yield*/, (0, utils_1.runProject)(args.port, args["shared-dependencies"], args.sources)];
178
- case 2:
179
- _g = (_j.sent());
180
- _j.label = 3;
181
- case 3: return [4 /*yield*/, _e.apply(void 0, _f.concat([_g]))];
182
- case 4: return [2 /*return*/, _a.apply(void 0, _b.concat([__assign.apply(void 0, _c.concat([(_h.importmap = _d.apply(void 0, [_j.sent(), args.backend,
183
- args.host,
184
- args.port]), _h)]))]))];
185
- }
186
- });
187
- }); });
188
- yargs.command("build", "Builds a new app shell.", function (argv) {
189
- return argv
190
- .string("target")["default"]("target", "dist")
191
- .describe("target", "The target directory where the build artifacts will be stored.")
192
- .string("registry")["default"]("registry", "https://registry.npmjs.org/")
193
- .describe("registry", "The NPM registry used for getting the packages.")
194
- .boolean("fresh")
195
- .describe("fresh", "Determines if the output directory should be cleaned before the run.")
196
- .boolean("support-offline")
197
- .describe("support-offline", "Determines if a service worker should be installed for offline support.")["default"]("support-offline", true)
198
- .string("build-config")
199
- .describe("build-config", "Path to a SPA build config JSON")
200
- .string("spa-path")["default"]("spa-path", "/openmrs/spa/")
201
- .describe("spa-path", "The path of the application on the target server.")
202
- .string("page-title")["default"]("page-title", "OpenMRS")
203
- .describe("page-title", "The title of the web app usually displayed in the browser tab.")
204
- .string("api-url")["default"]("api-url", "/openmrs/")
205
- .describe("api-url", "The URL of the API. Can be a path if the API is on the same target server.")
206
- .array("config-url")["default"]("config-url", [])
207
- .describe("config-url", "The URL to a frontend configuration. Can be used multiple times. Resolved by the client during initialization.")
208
- .array("config-path")["default"]("config-path", [])
209
- .describe("config-path", "The path to a frontend configuration file. Can be used multiple times. The file is copied directly into the build directory.")
210
- .string("importmap")["default"]("importmap", "importmap.json")
211
- .describe("importmap", "The import map to use. Can be a path to an import map to be taken literally, an URL, or a fixed JSON object.")
212
- .boolean("download-coreapps")["default"]("download-coreapps", false)
213
- .describe("download-coreapps", "Downloads and bundles the core apps. For cases where the core apps are not in the import map.");
214
- }, function (args) { return __awaiter(void 0, void 0, void 0, function () {
215
- return __generator(this, function (_a) {
216
- return [2 /*return*/, runCommand("runBuild", __assign(__assign({ apiUrl: args["api-url"], spaPath: args["spa-path"], configUrls: args["config-url"], configPaths: args["config-path"].map(function (p) { return (0, path_1.resolve)(process.cwd(), p); }), pageTitle: args["page-title"], supportOffline: args["support-offline"], downloadCoreapps: args["download-coreapps"] }, args), { importmap: args.importmap, buildConfig: args["build-config"] && (0, path_1.resolve)(process.cwd(), args["build-config"]), target: (0, path_1.resolve)(process.cwd(), args.target) }))];
217
- });
218
- }); });
219
- yargs.command("assemble", "Assembles an import map incl. all required resources.", function (argv) {
220
- return argv
221
- .string("target")["default"]("target", "dist")
222
- .describe("target", "The target directory where the gathered artifacts will be stored.")
223
- .string("registry")["default"]("registry", "https://registry.npmjs.org/")
224
- .describe("registry", "The NPM registry used for getting the packages.")
225
- .string("config")["default"]("config", "spa-build-config.json")
226
- .describe("config", "Path to a SPA build config JSON.")
227
- .boolean("fresh")
228
- .describe("fresh", "Determines if the output directory should be cleaned before the run.")["default"]("fresh", false)
229
- .choices("mode", ["config", "survey"])["default"]("mode", "survey")
230
- .describe("mode", "The source of the frontend modules to assemble. `config` uses a configuration file specified via `--config`. `survey` starts an interactive command-line survey.");
231
- }, function (args) {
232
- return runCommand("runAssemble", __assign(__assign({}, args), { registry: (0, utils_1.trimEnd)(args.registry, "/"), config: (0, path_1.resolve)(process.cwd(), args.config), target: (0, path_1.resolve)(process.cwd(), args.target) }));
233
- });
234
- yargs.command(["start", "$0"], "Starts the app shell using the provided configuration. This uses express for serving static files with some proxy middleware.", function (argv) {
235
- return argv
236
- .number("port")["default"]("port", 8080)
237
- .describe("port", "The port where the dev server should run.")
238
- .number("host")["default"]("host", "localhost")
239
- .describe("host", "The host name or IP for the server to use.")
240
- .string("backend")["default"]("backend", "https://openmrs-spa.org/")
241
- .describe("backend", "The backend to proxy API requests to.")
242
- .boolean("open")["default"]("open", false)
243
- .describe("open", "Immediately opens the SPA page URL in the browser.");
244
- }, function (args) { return runCommand("runStart", __assign({}, args)); });
46
+ yargs.command("debug", "Starts a new debugging session of the OpenMRS app shell. This uses Webpack as a debug server with proxy middleware.", (argv) => argv
47
+ .number("port")
48
+ .default("port", 8080)
49
+ .describe("port", "The port where the dev server should run.")
50
+ .number("host")
51
+ .default("host", "localhost")
52
+ .describe("host", "The host name or IP for the server to use.")
53
+ .string("backend")
54
+ .default("backend", "https://openmrs-spa.org/")
55
+ .describe("backend", "The backend to proxy API requests to.")
56
+ .boolean("support-offline")
57
+ .describe("support-offline", "Determines if a service worker should be installed for offline support.")
58
+ .default("support-offline", true)
59
+ .string("spa-path")
60
+ .default("spa-path", "/openmrs/spa/")
61
+ .describe("spa-path", "The path of the application on the target server.")
62
+ .string("api-url")
63
+ .default("api-url", "/openmrs/")
64
+ .describe("api-url", "The URL of the API. Can be a path if the API is on the same target server.")
65
+ .string("page-title")
66
+ .default("page-title", "OpenMRS")
67
+ .describe("page-title", "The title of the web app usually displayed in the browser tab.")
68
+ .array("config-url")
69
+ .default("config-url", [])
70
+ .describe("config-url", "The URL to a valid frontend configuration. Can be used multiple times.")
71
+ .boolean("run-project")
72
+ .default("run-project", false)
73
+ .describe("run-project", "Runs the project in the current directory fusing it with the specified import map.")
74
+ .array("sources")
75
+ .default("sources", ["."])
76
+ .describe("sources", "Runs the projects from the provided source directories. Can be used multiple times.")
77
+ .array("shared-dependencies")
78
+ .default("shared-dependencies", [])
79
+ .describe("shared-dependencies", "The additional shared dependencies besides the ones from the app shell.")
80
+ .string("importmap")
81
+ .default("importmap", "importmap.json")
82
+ .describe("importmap", "The import map to use. Can be a path to a valid import map to be taken literally, an URL, or a fixed JSON object."), (args) => __awaiter(void 0, void 0, void 0, function* () {
83
+ return runCommand("runDebug", Object.assign(Object.assign({ apiUrl: args["api-url"], spaPath: args["spa-path"], configUrls: args["config-url"], pageTitle: args["page-title"], supportOffline: args["support-offline"] }, args), { importmap: (0, utils_1.proxyImportmap)(yield (0, utils_1.mergeImportmap)(yield (0, utils_1.getImportmap)(args.importmap, args.port), (args["run-project"] || args.runProject) &&
84
+ (yield (0, utils_1.runProject)(args.port, args["shared-dependencies"], args.sources))), args.backend, args.host, args.port) }));
85
+ }));
86
+ yargs.command("develop", "Starts a new frontend module development session with the OpenMRS app shell.", (argv) => argv
87
+ .number("port")
88
+ .default("port", 8080)
89
+ .describe("port", "The port where the dev server should run.")
90
+ .number("host")
91
+ .default("host", "localhost")
92
+ .describe("host", "The host name or IP for the server to use.")
93
+ .string("backend")
94
+ .default("backend", "https://openmrs-spa.org/")
95
+ .describe("backend", "The backend to proxy API requests to.")
96
+ .string("spa-path")
97
+ .default("spa-path", "/openmrs/spa/")
98
+ .describe("spa-path", "The path of the application on the target server.")
99
+ .string("api-url")
100
+ .default("api-url", "/openmrs/")
101
+ .describe("api-url", "The URL of the API. Can be a path if the API is on the same target server.")
102
+ .boolean("open")
103
+ .default("open", true)
104
+ .describe("open", "Immediately opens the SPA page URL in the browser.")
105
+ .array("config-url")
106
+ .default("config-url", [])
107
+ .describe("config-url", "The URL to a valid frontend configuration. Can be used multiple times.")
108
+ .array("sources")
109
+ .default("sources", ["."])
110
+ .describe("sources", "Runs the projects from the provided source directories. Can be used multiple times.")
111
+ .array("shared-dependencies")
112
+ .default("shared-dependencies", [])
113
+ .describe("shared-dependencies", "The additional shared dependencies besides the ones from the app shell.")
114
+ .string("importmap")
115
+ .default("importmap", "importmap.json")
116
+ .describe("importmap", "The import map to use. Can be a path to a valid import map to be taken literally, an URL, or a fixed JSON object."), (args) => __awaiter(void 0, void 0, void 0, function* () {
117
+ return runCommand("runDevelop", Object.assign(Object.assign({ apiUrl: args["api-url"], spaPath: args["spa-path"], configUrls: args["config-url"] }, args), { importmap: (0, utils_1.proxyImportmap)(yield (0, utils_1.mergeImportmap)(yield (0, utils_1.getImportmap)(args.importmap, args.port), args.sources[0] !== false &&
118
+ (yield (0, utils_1.runProject)(args.port, args["shared-dependencies"], args.sources))), args.backend, args.host, args.port) }));
119
+ }));
120
+ yargs.command("build", "Builds a new app shell.", (argv) => argv
121
+ .string("target")
122
+ .default("target", "dist")
123
+ .describe("target", "The target directory where the build artifacts will be stored.")
124
+ .string("registry")
125
+ .default("registry", "https://registry.npmjs.org/")
126
+ .describe("registry", "The NPM registry used for getting the packages.")
127
+ .boolean("fresh")
128
+ .describe("fresh", "Determines if the output directory should be cleaned before the run.")
129
+ .boolean("support-offline")
130
+ .describe("support-offline", "Determines if a service worker should be installed for offline support.")
131
+ .default("support-offline", true)
132
+ .string("build-config")
133
+ .describe("build-config", "Path to a SPA build config JSON")
134
+ .string("spa-path")
135
+ .default("spa-path", "/openmrs/spa/")
136
+ .describe("spa-path", "The path of the application on the target server.")
137
+ .string("page-title")
138
+ .default("page-title", "OpenMRS")
139
+ .describe("page-title", "The title of the web app usually displayed in the browser tab.")
140
+ .string("api-url")
141
+ .default("api-url", "/openmrs/")
142
+ .describe("api-url", "The URL of the API. Can be a path if the API is on the same target server.")
143
+ .array("config-url")
144
+ .default("config-url", [])
145
+ .describe("config-url", "The URL to a frontend configuration. Can be used multiple times. Resolved by the client during initialization.")
146
+ .array("config-path")
147
+ .default("config-path", [])
148
+ .describe("config-path", "The path to a frontend configuration file. Can be used multiple times. The file is copied directly into the build directory.")
149
+ .string("importmap")
150
+ .default("importmap", "importmap.json")
151
+ .describe("importmap", "The import map to use. Can be a path to an import map to be taken literally, an URL, or a fixed JSON object.")
152
+ .boolean("download-coreapps")
153
+ .default("download-coreapps", false)
154
+ .describe("download-coreapps", "Downloads and bundles the core apps. For cases where the core apps are not in the import map."), (args) => __awaiter(void 0, void 0, void 0, function* () {
155
+ return runCommand("runBuild", Object.assign(Object.assign({ apiUrl: args["api-url"], spaPath: args["spa-path"], configUrls: args["config-url"], configPaths: args["config-path"].map((p) => (0, path_1.resolve)(process.cwd(), p)), pageTitle: args["page-title"], supportOffline: args["support-offline"], downloadCoreapps: args["download-coreapps"] }, args), { importmap: args.importmap, buildConfig: args["build-config"] && (0, path_1.resolve)(process.cwd(), args["build-config"]), target: (0, path_1.resolve)(process.cwd(), args.target) }));
156
+ }));
157
+ yargs.command("assemble", "Assembles an import map incl. all required resources.", (argv) => argv
158
+ .string("target")
159
+ .default("target", "dist")
160
+ .describe("target", "The target directory where the gathered artifacts will be stored.")
161
+ .string("registry")
162
+ .default("registry", "https://registry.npmjs.org/")
163
+ .describe("registry", "The NPM registry used for getting the packages.")
164
+ .string("config")
165
+ .default("config", "spa-build-config.json")
166
+ .describe("config", "Path to a SPA build config JSON.")
167
+ .boolean("fresh")
168
+ .describe("fresh", "Determines if the output directory should be cleaned before the run.")
169
+ .default("fresh", false)
170
+ .choices("mode", ["config", "survey"])
171
+ .default("mode", "survey")
172
+ .describe("mode", "The source of the frontend modules to assemble. `config` uses a configuration file specified via `--config`. `survey` starts an interactive command-line survey."), (args) => runCommand("runAssemble", Object.assign(Object.assign({}, args), { registry: (0, utils_1.trimEnd)(args.registry, "/"), config: (0, path_1.resolve)(process.cwd(), args.config), target: (0, path_1.resolve)(process.cwd(), args.target) })));
173
+ yargs.command(["start", "$0"], "Starts the app shell using the provided configuration. This uses express for serving static files with some proxy middleware.", (argv) => argv
174
+ .number("port")
175
+ .default("port", 8080)
176
+ .describe("port", "The port where the dev server should run.")
177
+ .number("host")
178
+ .default("host", "localhost")
179
+ .describe("host", "The host name or IP for the server to use.")
180
+ .string("backend")
181
+ .default("backend", "https://openmrs-spa.org/")
182
+ .describe("backend", "The backend to proxy API requests to.")
183
+ .boolean("open")
184
+ .default("open", false)
185
+ .describe("open", "Immediately opens the SPA page URL in the browser."), (args) => runCommand("runStart", Object.assign({}, args)));
245
186
  yargs
246
187
  .epilog("The SPA build config JSON is a JSON file, typically `frontend.json`, which defines parameters for the `build` and `assemble` " +
247
188
  "commands. The keys used by `build` are:\n" +