@openfn/cli 0.0.11 → 0.0.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.
@@ -1,364 +1,447 @@
1
- import fs from 'node:fs/promises';
2
- import actualCreateLogger, { isValidLogLevel, printDuration } from '@openfn/logger';
3
- import path from 'node:path';
4
- import compile$1, { preloadAdaptorExports } from '@openfn/compiler';
5
- import run from '@openfn/runtime';
6
-
7
- // Wrapper around the logger API to load a namespaced logger with the right options
8
- // All known loggers
9
- const CLI = 'cli';
10
- const COMPILER = 'compiler';
11
- const RUNTIME = 'runtime';
12
- const JOB = 'job';
13
- const namespaces = {
14
- [CLI]: 'CLI',
15
- [RUNTIME]: 'R/T',
16
- [COMPILER]: 'CMP',
17
- [JOB]: 'JOB'
1
+ // src/util/logger.ts
2
+ import actualCreateLogger, { printDuration } from "@openfn/logger";
3
+ import { isValidLogLevel, defaultLogger } from "@openfn/logger";
4
+ var CLI = "cli";
5
+ var COMPILER = "compiler";
6
+ var RUNTIME = "runtime";
7
+ var JOB = "job";
8
+ var namespaces = {
9
+ [CLI]: "CLI",
10
+ [RUNTIME]: "R/T",
11
+ [COMPILER]: "CMP",
12
+ [JOB]: "JOB"
18
13
  };
19
- const createLogger = (name = '', options) => {
20
- const logOptions = options.log || {};
21
- let level = logOptions[name] || logOptions.default || 'default';
22
- return actualCreateLogger(namespaces[name] || name, {
23
- level,
24
- ...logOptions,
25
- });
14
+ var createLogger = (name = "", options) => {
15
+ const logOptions = options.log || {};
16
+ let level = logOptions[name] || logOptions.default || "default";
17
+ return actualCreateLogger(namespaces[name] || name, {
18
+ level,
19
+ ...logOptions
20
+ });
26
21
  };
27
- const createNullLogger = () => createLogger(undefined, { log: { default: 'none' } });
22
+ var logger_default = createLogger;
23
+ var createNullLogger = () => createLogger(void 0, { log: { default: "none" } });
28
24
 
29
- const defaultLoggerOptions = {
30
- default: 'default',
31
- // TODO fix to lower case
32
- job: 'debug',
25
+ // src/util/ensure-opts.ts
26
+ import path from "node:path";
27
+ var defaultLoggerOptions = {
28
+ default: "default",
29
+ job: "debug"
33
30
  };
34
- const ERROR_MESSAGE_LOG_LEVEL = 'Unknown log level. Valid levels are none, debug, info and default.';
35
- const ERROR_MESSAGE_LOG_COMPONENT = 'Unknown log component. Valid components are cli, compiler, runtime and job.';
36
- const componentShorthands = {
37
- cmp: 'compiler',
38
- rt: 'runtime',
39
- 'r/t': 'runtime',
31
+ var ERROR_MESSAGE_LOG_LEVEL = "Unknown log level. Valid levels are none, debug, info and default.";
32
+ var ERROR_MESSAGE_LOG_COMPONENT = "Unknown log component. Valid components are cli, compiler, runtime and job.";
33
+ var componentShorthands = {
34
+ cmp: "compiler",
35
+ rt: "runtime",
36
+ "r/t": "runtime"
40
37
  };
41
- // TODO what about shorthands?
42
- const isValidComponent = (v) => /^(cli|runtime|compiler|job|default)$/i.test(v);
43
- const ensureLogOpts = (opts) => {
44
- const components = {};
45
- if (opts.log) {
46
- // Parse and validate each incoming log argument
47
- opts.log.forEach((l) => {
48
- let component = '';
49
- let level = '';
50
- if (l.match(/=/)) {
51
- const parts = l.split('=');
52
- component = parts[0].toLowerCase();
53
- if (componentShorthands[component]) {
54
- component = componentShorthands[component];
55
- }
56
- level = parts[1].toLowerCase();
57
- }
58
- else {
59
- component = 'default';
60
- level = l.toLowerCase();
61
- }
62
- if (!isValidComponent(component)) {
63
- throw new Error(ERROR_MESSAGE_LOG_COMPONENT);
64
- }
65
- level = level.toLowerCase();
66
- if (!isValidLogLevel(level)) {
67
- // TODO need to think about how the CLI frontend handles these errors
68
- // But this is fine for now
69
- throw new Error(ERROR_MESSAGE_LOG_LEVEL);
70
- }
71
- components[component] = level;
72
- });
73
- // TODO what if other log options are passed? Not really a concern right now
74
- }
75
- else if (opts.test) {
76
- // In test mode, log at info level by default
77
- components.default = 'info';
78
- }
79
- return {
80
- ...defaultLoggerOptions,
81
- ...components,
82
- };
38
+ var isValidComponent = (v) => /^(cli|runtime|compiler|job|default)$/i.test(v);
39
+ var ensureLogOpts = (opts) => {
40
+ const components = {};
41
+ if (opts.log) {
42
+ opts.log.forEach((l) => {
43
+ let component = "";
44
+ let level = "";
45
+ if (l.match(/=/)) {
46
+ const parts = l.split("=");
47
+ component = parts[0].toLowerCase();
48
+ if (componentShorthands[component]) {
49
+ component = componentShorthands[component];
50
+ }
51
+ level = parts[1].toLowerCase();
52
+ } else {
53
+ component = "default";
54
+ level = l.toLowerCase();
55
+ }
56
+ if (!isValidComponent(component)) {
57
+ throw new Error(ERROR_MESSAGE_LOG_COMPONENT);
58
+ }
59
+ level = level.toLowerCase();
60
+ if (!isValidLogLevel(level)) {
61
+ throw new Error(ERROR_MESSAGE_LOG_LEVEL);
62
+ }
63
+ components[component] = level;
64
+ });
65
+ }
66
+ return {
67
+ ...defaultLoggerOptions,
68
+ ...components
69
+ };
83
70
  };
84
- function ensureOpts(basePath = '.', opts) {
85
- const newOpts = {
86
- compileOnly: Boolean(opts.compileOnly),
87
- modulesHome: opts.modulesHome || process.env.OPENFN_MODULES_HOME,
88
- noCompile: Boolean(opts.noCompile),
89
- outputStdout: Boolean(opts.outputStdout),
90
- stateStdin: opts.stateStdin,
91
- test: opts.test,
92
- };
93
- const set = (key, value) => {
94
- // @ts-ignore TODO
95
- newOpts[key] = opts.hasOwnProperty(key) ? opts[key] : value;
96
- };
97
- let baseDir = basePath;
98
- if (basePath.endsWith('.js')) {
99
- baseDir = path.dirname(basePath);
100
- set('jobPath', basePath);
101
- }
102
- else {
103
- set('jobPath', `${baseDir}/job.js`);
104
- }
105
- set('statePath', `${baseDir}/state.json`);
106
- if (!opts.outputStdout) {
107
- set('outputPath', newOpts.compileOnly ? `${baseDir}/output.js` : `${baseDir}/output.json`);
108
- }
109
- newOpts.log = ensureLogOpts(opts);
110
- // TODO if no adaptor is provided, default to language common
111
- // Should we go further and bundle language-common?
112
- // But 90% of jobs use something else. Better to use auto loading.
113
- if (opts.adaptors) {
114
- newOpts.adaptors = opts.adaptors;
115
- // newOpts.adaptors = opts.adaptors.map((adaptor) => {
116
- // if (!adaptor.startsWith('@openfn/')) {
117
- // return `@openfn/${adaptor}`
118
- // }
119
- // return adaptor
120
- // });
121
- }
122
- return newOpts;
71
+ function ensureOpts(basePath = ".", opts) {
72
+ const newOpts = {
73
+ adaptor: opts.adaptor,
74
+ adaptors: opts.adaptors,
75
+ autoinstall: opts.autoinstall,
76
+ command: opts.command,
77
+ force: opts.force || false,
78
+ repoDir: opts.repoDir || process.env.OPENFN_REPO_DIR,
79
+ noCompile: Boolean(opts.noCompile),
80
+ expand: Boolean(opts.expand),
81
+ outputStdout: Boolean(opts.outputStdout),
82
+ packages: opts.packages,
83
+ stateStdin: opts.stateStdin,
84
+ immutable: opts.immutable || false
85
+ };
86
+ const set = (key, value) => {
87
+ newOpts[key] = opts.hasOwnProperty(key) ? opts[key] : value;
88
+ };
89
+ let baseDir = basePath;
90
+ if (basePath.endsWith(".js")) {
91
+ baseDir = path.dirname(basePath);
92
+ set("jobPath", basePath);
93
+ } else {
94
+ set("jobPath", `${baseDir}/job.js`);
95
+ }
96
+ set("statePath", `${baseDir}/state.json`);
97
+ if (!opts.outputStdout) {
98
+ set(
99
+ "outputPath",
100
+ newOpts.command === "compile" ? `${baseDir}/output.js` : `${baseDir}/output.json`
101
+ );
102
+ }
103
+ newOpts.log = ensureLogOpts(opts);
104
+ return newOpts;
123
105
  }
124
106
 
125
- // Load and compile a job from a file
126
- var compile = async (opts, log) => {
127
- log.debug('Loading job...');
128
- let job;
129
- if (opts.noCompile) {
130
- log.info('Skipping compilation as noCompile is set');
131
- job = fs.readFile(opts.jobPath, 'utf8');
132
- log.success(`Loaded job from ${opts.jobPath} (no compilation)`);
133
- }
134
- else {
135
- const complilerOptions = await loadTransformOptions(opts, log);
136
- complilerOptions.logger = createLogger(COMPILER, opts);
137
- job = compile$1(opts.jobPath, complilerOptions);
138
- log.success(`Compiled job from ${opts.jobPath}`);
107
+ // src/execute/handler.ts
108
+ import { writeFile } from "node:fs/promises";
109
+
110
+ // src/execute/load-state.ts
111
+ import fs from "node:fs/promises";
112
+ var load_state_default = async (opts, log) => {
113
+ log.debug("Load state...");
114
+ if (opts.stateStdin) {
115
+ try {
116
+ const json = JSON.parse(opts.stateStdin);
117
+ log.success("Read state from stdin");
118
+ log.debug("state:", json);
119
+ return json;
120
+ } catch (e) {
121
+ log.error("Failed to load state from stdin");
122
+ log.error(opts.stateStdin);
123
+ log.error(e);
124
+ process.exit(1);
139
125
  }
140
- return job;
126
+ }
127
+ try {
128
+ const str = await fs.readFile(opts.statePath, "utf8");
129
+ const json = JSON.parse(str);
130
+ log.success(`Loaded state from ${opts.statePath}`);
131
+ log.debug("state:", json);
132
+ return json;
133
+ } catch (e) {
134
+ log.warn(`Error loading state from ${opts.statePath}`);
135
+ log.warn(e);
136
+ }
137
+ log.warn("Using default state { data: {}, configuration: {}");
138
+ return {
139
+ data: {},
140
+ configuration: {}
141
+ };
141
142
  };
142
- // TODO this is a bit of a temporary solution
143
- // Adaptors need a version specifier right now to load type definitions for auto import
144
- // But that specifier must be excluded in the actual import by the adaptor
145
- const stripVersionSpecifier = (specifier) => {
146
- const idx = specifier.lastIndexOf('@');
147
- if (idx > 0) {
148
- return specifier.substring(0, idx);
143
+
144
+ // src/execute/execute.ts
145
+ import run from "@openfn/runtime";
146
+ var execute_default = (code, state, opts) => {
147
+ return run(code, state, {
148
+ immutableState: opts.immutable,
149
+ logger: logger_default(RUNTIME, opts),
150
+ jobLogger: logger_default(JOB, opts),
151
+ linker: {
152
+ repo: opts.repoDir,
153
+ modulePaths: parseAdaptors(opts)
149
154
  }
150
- return specifier;
155
+ });
151
156
  };
152
- // Mutate the opts object to write export information for the add-imports transformer
153
- const loadTransformOptions = async (opts, log) => {
154
- const options = {
155
- logger: log
156
- };
157
- // If an adaptor is passed in, we need to look up its declared exports
158
- // and pass them along to the compiler
159
- if (opts.adaptors) {
160
- const [pattern] = opts.adaptors; // TODO add-imports only takes on adaptor, but the cli can take multiple
161
- const [specifier, path] = pattern.split('=');
162
- // Preload exports from a path, optionally logging errors in case of a failure
163
- const doPreload = async (path, logError = true) => {
164
- try {
165
- const result = await preloadAdaptorExports(path);
166
- if (result) {
167
- log.info(`Pre-loaded typedefs for ${specifier} from ${path}`);
168
- }
169
- return result;
170
- }
171
- catch (e) {
172
- if (logError) {
173
- log.error(`Failed to load adaptor typedefs from path ${path}`);
174
- log.error(e);
175
- }
176
- }
177
- };
178
- // TODO need better trace/debug output on this I think
179
- // Looking up the adaptor's type definition is complex. In this order, we should use:
180
- const exports =
181
- // 1) An explicit file path
182
- (path && await doPreload(path)) ||
183
- // 2) A module defined in the opts.modulesHome folder
184
- (opts.modulesHome && await doPreload(`${opts.modulesHome}/${specifier}`, false)) ||
185
- // 3) An npm module specifier
186
- await doPreload(specifier)
187
- || [];
188
- if (exports.length === 0) {
189
- console.warn(`WARNING: no module exports loaded for ${pattern}`);
190
- console.log(' automatic imports will be skipped');
191
- }
192
- options['add-imports'] = {
193
- adaptor: {
194
- name: stripVersionSpecifier(specifier),
195
- exports,
196
- exportAll: true,
197
- }
198
- };
157
+ function parseAdaptors(opts) {
158
+ var _a;
159
+ const adaptors = {};
160
+ (_a = opts.adaptors) == null ? void 0 : _a.reduce((obj, exp) => {
161
+ const [module, path2] = exp.split("=");
162
+ obj[module] = path2;
163
+ return obj;
164
+ }, adaptors);
165
+ return adaptors;
166
+ }
167
+
168
+ // src/compile/compile.ts
169
+ import fs2 from "node:fs/promises";
170
+ import compile, { preloadAdaptorExports } from "@openfn/compiler";
171
+ import { getModulePath } from "@openfn/runtime";
172
+ var compile_default = async (opts, log) => {
173
+ log.debug("Loading job...");
174
+ let job;
175
+ if (opts.noCompile) {
176
+ log.info("Skipping compilation as noCompile is set");
177
+ job = fs2.readFile(opts.jobPath, "utf8");
178
+ log.success(`Loaded job from ${opts.jobPath} (no compilation)`);
179
+ } else {
180
+ const complilerOptions = await loadTransformOptions(opts, log);
181
+ complilerOptions.logger = logger_default(COMPILER, opts);
182
+ job = compile(opts.jobPath, complilerOptions);
183
+ if (opts.jobPath) {
184
+ log.success(`Compiled job from ${opts.jobPath}`);
185
+ } else {
186
+ log.success("Compiled job");
199
187
  }
200
- return options;
188
+ }
189
+ return job;
201
190
  };
202
-
203
- var loadState = async (opts, log) => {
204
- log.debug('Load state...');
205
- if (opts.stateStdin) {
206
- try {
207
- const json = JSON.parse(opts.stateStdin);
208
- log.success('Read state from stdin');
209
- log.debug('state:', json);
210
- return json;
211
- }
212
- catch (e) {
213
- log.error("Failed to load state from stdin");
214
- log.error(opts.stateStdin);
215
- log.error(e);
216
- process.exit(1);
191
+ var stripVersionSpecifier = (specifier) => {
192
+ const idx = specifier.lastIndexOf("@");
193
+ if (idx > 0) {
194
+ return specifier.substring(0, idx);
195
+ }
196
+ return specifier;
197
+ };
198
+ var resolveSpecifierPath = async (pattern, repoDir, log) => {
199
+ const [specifier, path2] = pattern.split("=");
200
+ if (path2) {
201
+ log.debug(`Resolved ${specifier} to path: ${path2}`);
202
+ return path2;
203
+ }
204
+ const repoPath = await getModulePath(specifier, repoDir);
205
+ if (repoPath) {
206
+ log.debug(`Resolved ${specifier} to repo module`);
207
+ return repoPath;
208
+ }
209
+ return null;
210
+ };
211
+ var loadTransformOptions = async (opts, log) => {
212
+ const options = {
213
+ logger: log
214
+ };
215
+ if (opts.adaptors) {
216
+ let exports;
217
+ const [pattern] = opts.adaptors;
218
+ const [specifier] = pattern.split("=");
219
+ log.debug(`Attempting to preload typedefs for ${specifier}`);
220
+ const path2 = await resolveSpecifierPath(pattern, opts.repoDir, log);
221
+ if (path2) {
222
+ try {
223
+ exports = await preloadAdaptorExports(path2);
224
+ if (exports) {
225
+ log.info(`Loaded typedefs for ${specifier}`);
217
226
  }
227
+ } catch (e) {
228
+ log.error(`Failed to load adaptor typedefs from path ${path2}`);
229
+ log.error(e);
230
+ }
218
231
  }
219
- try {
220
- const str = await fs.readFile(opts.statePath, 'utf8');
221
- const json = JSON.parse(str);
222
- log.success(`Loaded state from ${opts.statePath}`);
223
- log.debug('state:', json);
224
- return json;
232
+ if (!exports || exports.length === 0) {
233
+ console.warn(`WARNING: no module exports found for ${pattern}`);
225
234
  }
226
- catch (e) {
227
- log.warn(`Error loading state from ${opts.statePath}`);
228
- log.warn(e);
229
- }
230
- log.warn('Using default state { data: {}, configuration: {}');
231
- return {
232
- data: {},
233
- configuration: {}
235
+ options["add-imports"] = {
236
+ adaptor: {
237
+ name: stripVersionSpecifier(specifier),
238
+ exports,
239
+ exportAll: true
240
+ }
234
241
  };
242
+ }
243
+ return options;
235
244
  };
236
245
 
237
- var execute = (code, state, opts) => {
238
- // TODO listen to runtime events and log them
239
- // events appeal because we don't have to pass two loggers into the runtime
240
- // we can just listen to runtime events and do the logging ourselves here
241
- // Then again, maybe that doesn't make sense
242
- // Maybe we have to feed a job logger in?
243
- return run(code, state, {
244
- logger: createLogger(RUNTIME, opts),
245
- jobLogger: createLogger(JOB, opts),
246
- linker: {
247
- modulesHome: opts.modulesHome,
248
- modulePaths: parseAdaptors(opts),
249
- }
250
- });
251
- };
252
- // TODO we should throw if the adaptor strings are invalid for any reason
253
- function parseAdaptors(opts) {
254
- const adaptors = {};
255
- opts.adaptors?.reduce((obj, exp) => {
256
- const [module, path] = exp.split('=');
257
- obj[module] = path;
258
- return obj;
259
- }, adaptors);
260
- return adaptors;
261
- }
246
+ // src/repo/handler.ts
247
+ import { exec } from "node:child_process";
248
+ import treeify from "treeify";
249
+ import { install as rtInstall, loadRepoPkg } from "@openfn/runtime";
262
250
 
263
- // Top level command parser
264
- const parse = async (basePath, options, log) => {
265
- // TODO allow a logger to be passed in for test purposes
266
- // I THINK I need this but tbh not sure yet!
267
- const opts = ensureOpts(basePath, options);
268
- const logger = log || createLogger(CLI, opts);
269
- if (opts.test) {
270
- return runTest(opts, logger);
271
- }
272
- assertPath(basePath);
273
- if (opts.compileOnly) {
274
- return runCompile(opts, logger);
251
+ // src/util/expand-adaptors.ts
252
+ var nullLogger = createNullLogger();
253
+ var expand_adaptors_default = (names, log = nullLogger) => names == null ? void 0 : names.map((name) => {
254
+ if (name.startsWith("@openfn/language-")) {
255
+ return name;
256
+ }
257
+ const expanded = `@openfn/language-${name}`;
258
+ log.info(`Expanded adaptor ${name} to ${expanded}`);
259
+ return expanded;
260
+ });
261
+
262
+ // src/repo/handler.ts
263
+ var install = async (opts, log = defaultLogger) => {
264
+ log.timer("install");
265
+ let { packages, adaptor, repoDir } = opts;
266
+ log.success("Installing packages...");
267
+ if (packages) {
268
+ log.debug("repoDir is set to:", repoDir);
269
+ if (adaptor) {
270
+ packages = expand_adaptors_default(packages, log);
275
271
  }
276
- return runExecute(opts, logger);
272
+ await rtInstall(packages, repoDir, log);
273
+ }
274
+ const duration = log.timer("install");
275
+ log.success(`Installation complete in ${duration}`);
277
276
  };
278
- // TODO probably this isn't neccessary and we just use cwd?
279
- const assertPath = (basePath) => {
280
- if (!basePath) {
281
- console.error('ERROR: no path provided!');
282
- console.error('\nUsage:');
283
- console.error(' open path/to/job.js');
284
- console.error('\nFor more help do:');
285
- console.error(' openfn --help ');
286
- process.exit(1);
277
+ var clean = async (options, logger) => {
278
+ if (options.repoDir) {
279
+ const doIt = await logger.confirm(
280
+ `This will remove everything at ${options.repoDir}. Do you wish to proceed?`,
281
+ options.force
282
+ );
283
+ if (doIt) {
284
+ return new Promise((resolve) => {
285
+ logger.info(`Cleaning repo at ${options.repoDir} `);
286
+ exec(`npm exec rimraf ${options.repoDir}`, () => {
287
+ logger.success("Repo cleaned");
288
+ resolve();
289
+ });
290
+ });
287
291
  }
292
+ } else {
293
+ logger.error("Clean failed");
294
+ logger.error("No repoDir path detected");
295
+ }
288
296
  };
289
- const runExecute = async (options, logger) => {
290
- const start = new Date().getTime();
291
- const state = await loadState(options, logger);
292
- const code = await compile(options, logger);
293
- const result = await execute(code, state, options);
294
- if (options.outputStdout) {
295
- // TODO Log this even if in silent mode
296
- logger.success(`Result: `);
297
- logger.success(result);
298
- }
299
- else {
300
- logger.success(`Writing output to ${options.outputPath}`);
301
- await fs.writeFile(options.outputPath, JSON.stringify(result, null, 4));
302
- }
303
- const duration = printDuration(new Date().getTime() - start);
304
- logger.success(`Done in ${duration}! ✨`);
297
+ var pwd = async (options, logger) => {
298
+ logger.info(`OPENFN_REPO_DIR is set to ${process.env.OPENFN_REPO_DIR}`);
299
+ logger.success(`Repo working directory is: ${options.repoDir}`);
305
300
  };
306
- const runCompile = async (options, logger) => {
307
- const code = await compile(options, logger);
308
- if (options.outputStdout) {
309
- // TODO log this even if in silent mode
310
- logger.success('Compiled code:');
311
- console.log(code);
312
- }
313
- else {
314
- await fs.writeFile(options.outputPath, code);
315
- logger.success(`Compiled to ${options.outputPath}`);
301
+ var getDependencyList = async (options, _logger) => {
302
+ const pkg = await loadRepoPkg(options.repoDir);
303
+ const result = {};
304
+ Object.keys(pkg.dependencies).forEach((key) => {
305
+ const [name, version] = key.split("_");
306
+ if (!result[name]) {
307
+ result[name] = [];
316
308
  }
309
+ result[name].push(version);
310
+ });
311
+ return result;
317
312
  };
318
- const runTest = async (options, logger) => {
319
- logger.log('Running test job...');
320
- // This is a bit weird but it'll actually work!
321
- options.jobPath = `const fn = () => state => state * 2; fn()`;
322
- if (!options.stateStdin) {
323
- logger.warn('No state detected: pass -S <number> to provide some state');
324
- options.stateStdin = "21";
325
- }
326
- const silentLogger = createNullLogger();
327
- const state = await loadState(options, silentLogger);
328
- const code = await compile(options, logger);
329
- logger.break();
330
- logger.info('Compiled job:', '\n', code); // TODO there's an ugly intend here
331
- logger.break();
332
- logger.info('Running job...');
333
- const result = await execute(code, state, options);
334
- logger.success(`Result: ${result}`);
335
- return result;
313
+ var list = async (options, logger) => {
314
+ const tree = await getDependencyList(options, logger);
315
+ await pwd(options, logger);
316
+ const output = {};
317
+ Object.keys(tree).forEach((key) => {
318
+ const versions = tree[key];
319
+ output[key] = {};
320
+ versions.forEach((v) => {
321
+ output[key][v] = null;
322
+ });
323
+ });
324
+ logger.success("Installed packages:\n\n" + treeify.asTree(output));
336
325
  };
337
- // This is disabled for now because
338
- // 1) Resolving paths relative to the install location of the module is tricky
339
- // 2) yargs does a pretty good job of reporting the CLI's version
340
- // export const version = async (options: Opts) => {
341
- // // Note that this should ignore silent
342
- // const logger = options.logger || console;
343
- // const src = await fs.readFile(path.resolve('package.json'), 'utf8')
344
- // const pkg = JSON.parse(src);
345
- // logger.log(`@openfn/cli ${pkg.version}`)
346
- // for (const d in pkg.dependencies) {
347
- // if (d.startsWith('@openfn')) {
348
- // const pkgpath = path.resolve(`node_modules/${d}/package.json`)
349
- // const s = await fs.readFile(pkgpath, 'utf8')
350
- // const p = JSON.parse(s);
351
- // logger.log(` - ${d} ${p.version}`)
352
- // }
353
- // }
354
- // }
355
326
 
356
- // When receiving a message as a child process, we pull out the args and run
357
- process.on('message', ({ init, basePath, opts }) => {
358
- if (init) {
359
- parse(basePath, opts).then(() => {
360
- process.send({ done: true });
361
- });
362
- }
327
+ // src/execute/handler.ts
328
+ var executeHandler = async (options, logger) => {
329
+ const start = new Date().getTime();
330
+ if (options.autoinstall) {
331
+ const { repoDir } = options;
332
+ logger.info("Auto-installing language adaptors");
333
+ await install({ packages: options.adaptors, repoDir }, logger);
334
+ }
335
+ const state = await load_state_default(options, logger);
336
+ const code = await compile_default(options, logger);
337
+ const result = await execute_default(code, state, options);
338
+ if (options.outputStdout) {
339
+ logger.success(`Result: `);
340
+ logger.success(result);
341
+ } else {
342
+ logger.success(`Writing output to ${options.outputPath}`);
343
+ await writeFile(options.outputPath, JSON.stringify(result, null, 4));
344
+ }
345
+ const duration = printDuration(new Date().getTime() - start);
346
+ logger.success(`Done in ${duration}! \u2728`);
347
+ };
348
+ var handler_default = executeHandler;
349
+
350
+ // src/compile/handler.ts
351
+ import { writeFile as writeFile2 } from "node:fs/promises";
352
+ var compileHandler = async (options, logger) => {
353
+ const code = await compile_default(options, logger);
354
+ if (options.outputStdout) {
355
+ logger.success("Compiled code:");
356
+ logger.success("\n" + code);
357
+ } else {
358
+ await writeFile2(options.outputPath, code);
359
+ logger.success(`Compiled to ${options.outputPath}`);
360
+ }
361
+ };
362
+ var handler_default2 = compileHandler;
363
+
364
+ // src/test/handler.ts
365
+ var testHandler = async (options, logger) => {
366
+ logger.log("Running test job...");
367
+ options.jobPath = `const fn = () => state => state * 2; fn()`;
368
+ if (!options.stateStdin) {
369
+ logger.warn("No state detected: pass -S <number> to provide some state");
370
+ options.stateStdin = "21";
371
+ }
372
+ const silentLogger = createNullLogger();
373
+ const state = await load_state_default(options, silentLogger);
374
+ const code = await compile_default(options, logger);
375
+ logger.break();
376
+ logger.info("Compiled job:", "\n", code);
377
+ logger.break();
378
+ logger.info("Running job...");
379
+ const result = await execute_default(code, state, options);
380
+ logger.success(`Result: ${result}`);
381
+ return result;
382
+ };
383
+ var handler_default3 = testHandler;
384
+
385
+ // src/commands.ts
386
+ var parse = async (basePath, options, log) => {
387
+ const opts = ensureOpts(basePath, options);
388
+ const logger = log || logger_default(CLI, opts);
389
+ if (opts.adaptors && opts.expand) {
390
+ opts.adaptors = expand_adaptors_default(opts.adaptors, logger);
391
+ }
392
+ if (opts.command == "test" && !opts.repoDir) {
393
+ logger.warn(
394
+ "WARNING: no repo module dir found! Using the default (/tmp/repo)"
395
+ );
396
+ logger.warn(
397
+ "You should set OPENFN_REPO_DIR or pass --repoDir=some/path in to the CLI"
398
+ );
399
+ }
400
+ let handler = () => null;
401
+ switch (options.command) {
402
+ case "repo-install":
403
+ handler = install;
404
+ break;
405
+ case "repo-clean":
406
+ handler = clean;
407
+ break;
408
+ case "repo-pwd":
409
+ handler = pwd;
410
+ break;
411
+ case "repo-list":
412
+ handler = list;
413
+ break;
414
+ case "compile":
415
+ assertPath(basePath);
416
+ handler = handler_default2;
417
+ break;
418
+ case "test":
419
+ handler = handler_default3;
420
+ break;
421
+ case "execute":
422
+ default:
423
+ assertPath(basePath);
424
+ handler = handler_default;
425
+ }
426
+ return handler(opts, logger);
427
+ };
428
+ var commands_default = parse;
429
+ var assertPath = (basePath) => {
430
+ if (!basePath) {
431
+ console.error("ERROR: no path provided!");
432
+ console.error("\nUsage:");
433
+ console.error(" open path/to/job");
434
+ console.error("\nFor more help do:");
435
+ console.error(" openfn --help ");
436
+ process.exit(1);
437
+ }
438
+ };
439
+
440
+ // src/process/runner.ts
441
+ process.on("message", ({ init, basePath, opts }) => {
442
+ if (init) {
443
+ commands_default(basePath, opts).then(() => {
444
+ process.send({ done: true });
445
+ });
446
+ }
363
447
  });
364
- //# sourceMappingURL=runner.js.map