@openfn/cli 0.0.19 → 0.0.20
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/index.js +33 -5
- package/dist/process/runner.js +181 -36
- package/package.json +6 -5
package/dist/index.js
CHANGED
|
@@ -12,13 +12,15 @@ function spawn_default(basePath, opts2) {
|
|
|
12
12
|
];
|
|
13
13
|
const dirname = path.dirname(url.fileURLToPath(import.meta.url));
|
|
14
14
|
const child = fork(`${dirname}/process/runner.js`, [], { execArgv });
|
|
15
|
-
child.on("message", ({ done }) => {
|
|
15
|
+
child.on("message", ({ done, init }) => {
|
|
16
|
+
if (init) {
|
|
17
|
+
child.send({ init: true, basePath, opts: opts2 });
|
|
18
|
+
}
|
|
16
19
|
if (done) {
|
|
17
20
|
child.kill();
|
|
18
21
|
process.exit(0);
|
|
19
22
|
}
|
|
20
23
|
});
|
|
21
|
-
child.send({ init: true, basePath, opts: opts2 });
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
// src/cli.ts
|
|
@@ -81,7 +83,7 @@ var list = {
|
|
|
81
83
|
// src/execute/command.ts
|
|
82
84
|
var executeCommand = {
|
|
83
85
|
command: "execute [path]",
|
|
84
|
-
desc:
|
|
86
|
+
desc: `Run an openfn job. Get more help by running openfn <command> help`,
|
|
85
87
|
aliases: ["$0"],
|
|
86
88
|
handler: (argv) => {
|
|
87
89
|
argv.command = "execute";
|
|
@@ -170,12 +172,38 @@ var command_default3 = {
|
|
|
170
172
|
}).example("test", "run the test script").example("test -S 42", "run the test script with state 42")
|
|
171
173
|
};
|
|
172
174
|
|
|
175
|
+
// src/docgen/command.ts
|
|
176
|
+
var docgenCommand = {
|
|
177
|
+
command: "docgen <specifier>",
|
|
178
|
+
desc: "Generate documentation into the repo. Specifier must include a version number.",
|
|
179
|
+
handler: (argv) => {
|
|
180
|
+
argv.command = "docgen";
|
|
181
|
+
},
|
|
182
|
+
builder: (yargs2) => {
|
|
183
|
+
return yargs2.example("docgen @openfn/language-common@1.7.5", "");
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
var command_default4 = docgenCommand;
|
|
187
|
+
|
|
188
|
+
// src/docs/command.ts
|
|
189
|
+
var command_default5 = {
|
|
190
|
+
command: "docs [adaptor] [operation]",
|
|
191
|
+
desc: "Print help for an adaptor function. You can use short-hand for adaptor names (ie, common instead of @openfn/language-common)",
|
|
192
|
+
handler: (argv) => {
|
|
193
|
+
argv.command = "docs";
|
|
194
|
+
},
|
|
195
|
+
builder: (yargs2) => yargs2.example("docs common fn", "Print help for the common fn operation")
|
|
196
|
+
};
|
|
197
|
+
|
|
173
198
|
// src/cli.ts
|
|
174
|
-
var cmd = yargs(hideBin(process.argv)).command(command_default).command(command_default2).command(install).command(repo).command(command_default3).option("log", {
|
|
199
|
+
var cmd = yargs(hideBin(process.argv)).command(command_default).command(command_default2).command(install).command(repo).command(command_default3).command(command_default5).command(command_default4).option("log", {
|
|
175
200
|
alias: ["l"],
|
|
176
201
|
description: "Set the default log level to none, default, info or debug",
|
|
177
202
|
array: true
|
|
178
|
-
}).
|
|
203
|
+
}).example("openfn execute help", "Show documentation for the execute command").example(
|
|
204
|
+
"openfn docs @openfn/language-common each",
|
|
205
|
+
"Get more help on the common.each command"
|
|
206
|
+
).alias("v", "version").help();
|
|
179
207
|
|
|
180
208
|
// src/index.ts
|
|
181
209
|
var opts = cmd.parse();
|
package/dist/process/runner.js
CHANGED
|
@@ -80,8 +80,10 @@ function ensureOpts(basePath = ".", opts) {
|
|
|
80
80
|
noCompile: Boolean(opts.noCompile),
|
|
81
81
|
expand: opts.expand !== false,
|
|
82
82
|
outputStdout: Boolean(opts.outputStdout),
|
|
83
|
+
operation: opts.operation,
|
|
83
84
|
packages: opts.packages,
|
|
84
85
|
stateStdin: opts.stateStdin,
|
|
86
|
+
specifier: opts.specifier,
|
|
85
87
|
strictOutput: opts.strictOutput ?? true,
|
|
86
88
|
immutable: opts.immutable || false
|
|
87
89
|
};
|
|
@@ -156,11 +158,11 @@ var execute_default = (code, state, opts) => {
|
|
|
156
158
|
function parseAdaptors(opts) {
|
|
157
159
|
const adaptors = {};
|
|
158
160
|
opts.adaptors.reduce((obj, exp) => {
|
|
159
|
-
const [module,
|
|
161
|
+
const [module, path3] = exp.split("=");
|
|
160
162
|
const { name, version } = getNameAndVersion(module);
|
|
161
163
|
const info = {};
|
|
162
|
-
if (
|
|
163
|
-
info.path =
|
|
164
|
+
if (path3) {
|
|
165
|
+
info.path = path3;
|
|
164
166
|
}
|
|
165
167
|
if (version) {
|
|
166
168
|
info.version = version;
|
|
@@ -202,10 +204,10 @@ var stripVersionSpecifier = (specifier) => {
|
|
|
202
204
|
return specifier;
|
|
203
205
|
};
|
|
204
206
|
var resolveSpecifierPath = async (pattern, repoDir, log) => {
|
|
205
|
-
const [specifier,
|
|
206
|
-
if (
|
|
207
|
-
log.debug(`Resolved ${specifier} to path: ${
|
|
208
|
-
return
|
|
207
|
+
const [specifier, path3] = pattern.split("=");
|
|
208
|
+
if (path3) {
|
|
209
|
+
log.debug(`Resolved ${specifier} to path: ${path3}`);
|
|
210
|
+
return path3;
|
|
209
211
|
}
|
|
210
212
|
const repoPath = await getModulePath(specifier, repoDir, log);
|
|
211
213
|
if (repoPath) {
|
|
@@ -223,15 +225,15 @@ var loadTransformOptions = async (opts, log) => {
|
|
|
223
225
|
const [pattern] = opts.adaptors;
|
|
224
226
|
const [specifier] = pattern.split("=");
|
|
225
227
|
log.debug(`Attempting to preload typedefs for ${specifier}`);
|
|
226
|
-
const
|
|
227
|
-
if (
|
|
228
|
+
const path3 = await resolveSpecifierPath(pattern, opts.repoDir, log);
|
|
229
|
+
if (path3) {
|
|
228
230
|
try {
|
|
229
|
-
exports = await preloadAdaptorExports(
|
|
231
|
+
exports = await preloadAdaptorExports(path3);
|
|
230
232
|
if (exports) {
|
|
231
233
|
log.info(`Loaded typedefs for ${specifier}`);
|
|
232
234
|
}
|
|
233
235
|
} catch (e) {
|
|
234
|
-
log.error(`Failed to load adaptor typedefs from path ${
|
|
236
|
+
log.error(`Failed to load adaptor typedefs from path ${path3}`);
|
|
235
237
|
log.error(e);
|
|
236
238
|
}
|
|
237
239
|
}
|
|
@@ -424,7 +426,165 @@ var testHandler = async (options, logger) => {
|
|
|
424
426
|
};
|
|
425
427
|
var handler_default3 = testHandler;
|
|
426
428
|
|
|
429
|
+
// src/docgen/handler.ts
|
|
430
|
+
import { writeFile as writeFile3 } from "node:fs/promises";
|
|
431
|
+
import { readFileSync, writeFileSync, mkdirSync, rmSync } from "node:fs";
|
|
432
|
+
import path2 from "node:path";
|
|
433
|
+
import { describePackage } from "@openfn/describe-package";
|
|
434
|
+
import { getNameAndVersion as getNameAndVersion2 } from "@openfn/runtime";
|
|
435
|
+
var RETRY_DURATION = 500;
|
|
436
|
+
var RETRY_COUNT = 20;
|
|
437
|
+
var TIMEOUT_MS = 1e3 * 60;
|
|
438
|
+
var actualDocGen = (specifier) => describePackage(specifier, {});
|
|
439
|
+
var ensurePath = (filePath) => mkdirSync(path2.dirname(filePath), { recursive: true });
|
|
440
|
+
var generatePlaceholder = (path3) => {
|
|
441
|
+
writeFileSync(path3, `{ "loading": true, "timestamp": ${Date.now()}}`);
|
|
442
|
+
};
|
|
443
|
+
var finish = (logger, resultPath) => {
|
|
444
|
+
logger.success("Done! Docs can be found at:\n");
|
|
445
|
+
logger.print(` ${path2.resolve(resultPath)}`);
|
|
446
|
+
};
|
|
447
|
+
var generateDocs = async (specifier, path3, docgen, logger) => {
|
|
448
|
+
const result = await docgen(specifier);
|
|
449
|
+
await writeFile3(path3, JSON.stringify(result, null, 2));
|
|
450
|
+
finish(logger, path3);
|
|
451
|
+
return path3;
|
|
452
|
+
};
|
|
453
|
+
var waitForDocs = async (docs, path3, logger, retryDuration = RETRY_DURATION) => {
|
|
454
|
+
try {
|
|
455
|
+
if (docs.hasOwnProperty("loading")) {
|
|
456
|
+
logger.info("Docs are being loaded by another process. Waiting.");
|
|
457
|
+
return new Promise((resolve, reject) => {
|
|
458
|
+
let count = 0;
|
|
459
|
+
let i = setInterval(() => {
|
|
460
|
+
logger.info("Waiting..");
|
|
461
|
+
if (count > RETRY_COUNT) {
|
|
462
|
+
clearInterval(i);
|
|
463
|
+
reject(new Error("Timed out waiting for docs to load"));
|
|
464
|
+
}
|
|
465
|
+
const updated = JSON.parse(readFileSync(path3, "utf8"));
|
|
466
|
+
if (!updated.hasOwnProperty("loading")) {
|
|
467
|
+
logger.info("Docs found!");
|
|
468
|
+
clearInterval(i);
|
|
469
|
+
resolve(path3);
|
|
470
|
+
}
|
|
471
|
+
count++;
|
|
472
|
+
}, retryDuration);
|
|
473
|
+
});
|
|
474
|
+
} else {
|
|
475
|
+
logger.info(`Docs already written to cache at ${path3}`);
|
|
476
|
+
finish(logger, path3);
|
|
477
|
+
return path3;
|
|
478
|
+
}
|
|
479
|
+
} catch (e) {
|
|
480
|
+
logger.error("Existing doc JSON corrupt. Aborting");
|
|
481
|
+
throw e;
|
|
482
|
+
}
|
|
483
|
+
};
|
|
484
|
+
var docgenHandler = (options, logger, docgen = actualDocGen, retryDuration = RETRY_DURATION) => {
|
|
485
|
+
const { specifier, repoDir } = options;
|
|
486
|
+
const { version } = getNameAndVersion2(specifier);
|
|
487
|
+
if (!version) {
|
|
488
|
+
logger.error("Error: No version number detected");
|
|
489
|
+
logger.error("eg, @openfn/language-common@1.7.5");
|
|
490
|
+
logger.error("Aborting");
|
|
491
|
+
process.exit(9);
|
|
492
|
+
}
|
|
493
|
+
logger.success(`Generating docs for ${specifier}`);
|
|
494
|
+
const path3 = `${repoDir}/docs/${specifier}.json`;
|
|
495
|
+
ensurePath(path3);
|
|
496
|
+
const handleError = () => {
|
|
497
|
+
logger.info("Removing placeholder");
|
|
498
|
+
rmSync(path3);
|
|
499
|
+
};
|
|
500
|
+
try {
|
|
501
|
+
const existing = readFileSync(path3, "utf8");
|
|
502
|
+
const json = JSON.parse(existing);
|
|
503
|
+
if (json && json.timeout && Date.now() - json.timeout >= TIMEOUT_MS) {
|
|
504
|
+
logger.info(`Expired placeholder found. Removing.`);
|
|
505
|
+
rmSync(path3);
|
|
506
|
+
throw new Error("TIMEOUT");
|
|
507
|
+
}
|
|
508
|
+
return waitForDocs(json, path3, logger, retryDuration);
|
|
509
|
+
} catch (e) {
|
|
510
|
+
if (e.message !== "TIMEOUT") {
|
|
511
|
+
logger.info(`Docs JSON not found at ${path3}`);
|
|
512
|
+
}
|
|
513
|
+
logger.debug("Generating placeholder");
|
|
514
|
+
generatePlaceholder(path3);
|
|
515
|
+
return generateDocs(specifier, path3, docgen, logger).catch((e2) => {
|
|
516
|
+
logger.error("Error generating documentation");
|
|
517
|
+
logger.error(e2);
|
|
518
|
+
handleError();
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
var handler_default4 = docgenHandler;
|
|
523
|
+
|
|
524
|
+
// src/docs/handler.ts
|
|
525
|
+
import { readFile } from "node:fs/promises";
|
|
526
|
+
import { getNameAndVersion as getNameAndVersion3, getLatestVersion } from "@openfn/runtime";
|
|
527
|
+
var describe = (adaptorName, fn) => `## ${fn.name}(${fn.parameters.map(({ name }) => name).join(",")})
|
|
528
|
+
|
|
529
|
+
${fn.description}
|
|
530
|
+
|
|
531
|
+
### Usage Examples
|
|
532
|
+
|
|
533
|
+
${fn.examples.length ? fn.examples.map((eg) => eg).join("\n\n") : "None"}
|
|
534
|
+
|
|
535
|
+
### API Reference
|
|
536
|
+
|
|
537
|
+
https://docs.openfn.org/adaptors/packages/${adaptorName.replace(
|
|
538
|
+
"@openfn/language-",
|
|
539
|
+
""
|
|
540
|
+
)}-docs#${fn.name}
|
|
541
|
+
`;
|
|
542
|
+
var docsHandler = async (options, logger) => {
|
|
543
|
+
const { adaptor, operation, repoDir } = options;
|
|
544
|
+
const [adaptorName] = expand_adaptors_default([adaptor], logger);
|
|
545
|
+
let { name, version } = getNameAndVersion3(adaptorName);
|
|
546
|
+
if (!version) {
|
|
547
|
+
logger.info("No version number provided, looking for latest...");
|
|
548
|
+
version = await getLatestVersion(version);
|
|
549
|
+
logger.info("Found ", version);
|
|
550
|
+
logger.success(`Showing docs for ${adaptorName} v${version}`);
|
|
551
|
+
}
|
|
552
|
+
logger.info("Generating/loading documentation...");
|
|
553
|
+
const path3 = await handler_default4(
|
|
554
|
+
{
|
|
555
|
+
specifier: `${name}@${version}`,
|
|
556
|
+
repoDir
|
|
557
|
+
},
|
|
558
|
+
createNullLogger()
|
|
559
|
+
);
|
|
560
|
+
if (path3) {
|
|
561
|
+
const source = await readFile(path3, "utf8");
|
|
562
|
+
const data = JSON.parse(source);
|
|
563
|
+
const fn = data.functions.find(({ name: name2 }) => name2 === operation);
|
|
564
|
+
logger.debug("Operation schema:", fn);
|
|
565
|
+
logger.success(`Documentation for ${name}.${operation} v${version}:
|
|
566
|
+
`);
|
|
567
|
+
const desc = describe(name, fn);
|
|
568
|
+
logger.print(desc);
|
|
569
|
+
logger.success("Done!");
|
|
570
|
+
} else {
|
|
571
|
+
logger.error("Not found");
|
|
572
|
+
}
|
|
573
|
+
};
|
|
574
|
+
var handler_default5 = docsHandler;
|
|
575
|
+
|
|
427
576
|
// src/commands.ts
|
|
577
|
+
var handlers = {
|
|
578
|
+
execute: handler_default,
|
|
579
|
+
compile: handler_default2,
|
|
580
|
+
test: handler_default3,
|
|
581
|
+
docgen: handler_default4,
|
|
582
|
+
docs: handler_default5,
|
|
583
|
+
["repo-clean"]: clean,
|
|
584
|
+
["repo-install"]: install,
|
|
585
|
+
["repo-pwd"]: pwd,
|
|
586
|
+
["repo-list"]: list
|
|
587
|
+
};
|
|
428
588
|
var parse = async (basePath, options, log) => {
|
|
429
589
|
const opts = ensureOpts(basePath, options);
|
|
430
590
|
const logger = log || logger_default(CLI, opts);
|
|
@@ -439,31 +599,13 @@ var parse = async (basePath, options, log) => {
|
|
|
439
599
|
"You should set OPENFN_REPO_DIR or pass --repoDir=some/path in to the CLI"
|
|
440
600
|
);
|
|
441
601
|
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
break;
|
|
450
|
-
case "repo-pwd":
|
|
451
|
-
handler = pwd;
|
|
452
|
-
break;
|
|
453
|
-
case "repo-list":
|
|
454
|
-
handler = list;
|
|
455
|
-
break;
|
|
456
|
-
case "compile":
|
|
457
|
-
assertPath(basePath);
|
|
458
|
-
handler = handler_default2;
|
|
459
|
-
break;
|
|
460
|
-
case "test":
|
|
461
|
-
handler = handler_default3;
|
|
462
|
-
break;
|
|
463
|
-
case "execute":
|
|
464
|
-
default:
|
|
465
|
-
assertPath(basePath);
|
|
466
|
-
handler = handler_default;
|
|
602
|
+
const handler = options.command ? handlers[options.command] : handler_default;
|
|
603
|
+
if (!opts.command || /^(compile|execute)$/.test(opts.command)) {
|
|
604
|
+
assertPath(basePath);
|
|
605
|
+
}
|
|
606
|
+
if (!handler) {
|
|
607
|
+
logger.error(`Unrecognise command: ${options.command}`);
|
|
608
|
+
process.exit(1);
|
|
467
609
|
}
|
|
468
610
|
return handler(opts, logger);
|
|
469
611
|
};
|
|
@@ -487,3 +629,6 @@ process.on("message", ({ init, basePath, opts }) => {
|
|
|
487
629
|
});
|
|
488
630
|
}
|
|
489
631
|
});
|
|
632
|
+
process.send({
|
|
633
|
+
init: true
|
|
634
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openfn/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.20",
|
|
4
4
|
"description": "CLI devtools for the openfn toolchain.",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=16",
|
|
@@ -30,15 +30,16 @@
|
|
|
30
30
|
"@types/yargs": "^17.0.12",
|
|
31
31
|
"ava": "5.1.0",
|
|
32
32
|
"mock-fs": "^5.1.4",
|
|
33
|
-
"ts-node": "^10.
|
|
33
|
+
"ts-node": "^10.9.1",
|
|
34
34
|
"tslib": "^2.4.0",
|
|
35
35
|
"tsup": "^6.2.3",
|
|
36
36
|
"typescript": "^4.7.4"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@openfn/compiler": "^0.0.
|
|
40
|
-
"@openfn/
|
|
41
|
-
"@openfn/
|
|
39
|
+
"@openfn/compiler": "^0.0.19",
|
|
40
|
+
"@openfn/describe-package": "^0.0.11",
|
|
41
|
+
"@openfn/logger": "^0.0.8",
|
|
42
|
+
"@openfn/runtime": "^0.0.13",
|
|
42
43
|
"fast-safe-stringify": "^2.1.1",
|
|
43
44
|
"rimraf": "^3.0.2",
|
|
44
45
|
"treeify": "^1.1.0",
|