@openfn/project 0.7.1 → 0.7.2
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.d.ts +48 -59
- package/dist/index.js +181 -143
- package/package.json +4 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,72 +1,56 @@
|
|
|
1
|
-
import * as l
|
|
1
|
+
import * as l from '@openfn/lexicon';
|
|
2
|
+
import l__default, { WorkspaceConfig, UUID } from '@openfn/lexicon';
|
|
3
|
+
import { Provisioner } from '@openfn/lexicon/lightning';
|
|
2
4
|
|
|
3
|
-
type OpenfnMeta = {
|
|
4
|
-
uuid?: string;
|
|
5
|
-
};
|
|
6
5
|
type WithMeta<T> = T & {
|
|
7
|
-
openfn?:
|
|
6
|
+
openfn?: l.NodeMeta;
|
|
8
7
|
};
|
|
9
8
|
declare class Workflow {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
index: {
|
|
13
|
-
steps: {};
|
|
14
|
-
edges: {};
|
|
15
|
-
uuid: {};
|
|
16
|
-
id: {};
|
|
17
|
-
};
|
|
9
|
+
workflow: l.Workflow;
|
|
10
|
+
index: any;
|
|
18
11
|
name?: string;
|
|
19
12
|
id: string;
|
|
20
|
-
openfn
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
13
|
+
openfn?: l.WorkflowMeta;
|
|
14
|
+
options: any;
|
|
15
|
+
constructor(workflow: l.Workflow);
|
|
16
|
+
get steps(): WithMeta<l.Job & l.Trigger>[];
|
|
17
|
+
_buildIndex(): void;
|
|
18
|
+
set(id: string, props: Partial<l.Job | l.StepEdge>): this;
|
|
19
|
+
get(id: string): WithMeta<l.Step | l.Trigger | l.StepEdge>;
|
|
20
|
+
meta(id: string): l.WorkflowMeta;
|
|
21
|
+
getEdge(from: string, to: string): WithMeta<l.ConditionalStepEdge>;
|
|
27
22
|
getAllEdges(): Record<string, string[]>;
|
|
28
23
|
getStep(id: string): Workflow["steps"][number];
|
|
29
|
-
getRoot():
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
getUUID(id: any): string;
|
|
33
|
-
toJSON(): JSON.Object;
|
|
24
|
+
getRoot(): WithMeta<l.Job & l.Trigger> | undefined;
|
|
25
|
+
getUUID(id: string): string;
|
|
26
|
+
toJSON(): Object;
|
|
34
27
|
getUUIDMap(): Record<string, string>;
|
|
35
28
|
getVersionHash(): string;
|
|
36
29
|
pushHistory(versionHash: string): void;
|
|
37
30
|
canMergeInto(target: Workflow): boolean;
|
|
38
31
|
}
|
|
39
32
|
|
|
40
|
-
type
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
workflows: string;
|
|
44
|
-
projects: string;
|
|
45
|
-
};
|
|
46
|
-
formats: {
|
|
47
|
-
openfn: FileFormats;
|
|
48
|
-
project: FileFormats;
|
|
49
|
-
workflow: FileFormats;
|
|
50
|
-
};
|
|
51
|
-
}
|
|
33
|
+
type fromAppStateConfig = Partial<l.WorkspaceConfig> & {
|
|
34
|
+
format?: 'yaml' | 'json';
|
|
35
|
+
};
|
|
52
36
|
|
|
53
|
-
type FromPathConfig = {
|
|
54
|
-
|
|
37
|
+
type FromPathConfig = l.WorkspaceConfig & {
|
|
38
|
+
format: 'json' | 'yaml';
|
|
55
39
|
};
|
|
56
40
|
|
|
57
41
|
type FromFsConfig = {
|
|
58
42
|
root: string;
|
|
59
43
|
};
|
|
60
44
|
|
|
61
|
-
type MergeProjectOptions =
|
|
45
|
+
type MergeProjectOptions = {
|
|
62
46
|
workflowMappings: Record<string, string>;
|
|
63
47
|
removeUnmapped: boolean;
|
|
64
48
|
force: boolean;
|
|
65
|
-
}
|
|
49
|
+
};
|
|
66
50
|
|
|
67
51
|
declare class Workspace {
|
|
68
|
-
config
|
|
69
|
-
activeProject
|
|
52
|
+
config: l.WorkspaceConfig;
|
|
53
|
+
activeProject?: l.ProjectMeta;
|
|
70
54
|
private projects;
|
|
71
55
|
private projectPaths;
|
|
72
56
|
private isValid;
|
|
@@ -77,11 +61,19 @@ declare class Workspace {
|
|
|
77
61
|
get(id: string): Project | undefined;
|
|
78
62
|
getProjectPath(id: string): string | undefined;
|
|
79
63
|
getActiveProject(): Project | undefined;
|
|
80
|
-
getConfig(): Partial<WorkspaceConfig>;
|
|
81
|
-
get activeProjectId():
|
|
64
|
+
getConfig(): Partial<l.WorkspaceConfig>;
|
|
65
|
+
get activeProjectId(): unknown;
|
|
82
66
|
get valid(): boolean;
|
|
83
67
|
}
|
|
84
68
|
|
|
69
|
+
type UUIDMap = {
|
|
70
|
+
[workflowId: string]: {
|
|
71
|
+
self?: UUID;
|
|
72
|
+
children: {
|
|
73
|
+
[nodeId: string]: UUID;
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
};
|
|
85
77
|
declare class Project {
|
|
86
78
|
/** Human readable project name. This corresponds to the label in Lightning */
|
|
87
79
|
name?: string;
|
|
@@ -92,35 +84,31 @@ declare class Project {
|
|
|
92
84
|
workflows: Workflow[];
|
|
93
85
|
options: any;
|
|
94
86
|
meta: any;
|
|
95
|
-
openfn?:
|
|
87
|
+
openfn?: l__default.ProjectMeta;
|
|
96
88
|
workspace?: Workspace;
|
|
97
|
-
config: WorkspaceConfig;
|
|
89
|
+
config: l__default.WorkspaceConfig;
|
|
98
90
|
collections: any;
|
|
99
|
-
|
|
100
|
-
static from(type: '
|
|
91
|
+
credentials: string[];
|
|
92
|
+
static from(type: 'state', data: Provisioner.Project, meta?: Partial<l__default.ProjectMeta>, config?: fromAppStateConfig): Promise<Project>;
|
|
93
|
+
static from(type: 'fs', options: FromFsConfig): Promise<Project>;
|
|
101
94
|
static from(type: 'path', data: string, options?: {
|
|
102
95
|
config?: FromPathConfig;
|
|
103
|
-
}): Project
|
|
104
|
-
static
|
|
105
|
-
|
|
106
|
-
constructor(data: l.Project, config?: RepoOptions);
|
|
96
|
+
}): Promise<Project>;
|
|
97
|
+
static merge(source: Project, target: Project, options?: Partial<MergeProjectOptions>): Project;
|
|
98
|
+
constructor(data: Partial<l__default.Project>, config?: Partial<l__default.WorkspaceConfig>);
|
|
107
99
|
setConfig(config: Partial<WorkspaceConfig>): void;
|
|
108
100
|
serialize(type?: 'json' | 'yaml' | 'fs' | 'state', options?: any): any;
|
|
109
101
|
getWorkflow(idOrName: string): Workflow | undefined;
|
|
110
102
|
getIdentifier(): string;
|
|
111
|
-
compare(proj: Project): void;
|
|
112
103
|
getUUID(workflow: string | Workflow, stepId: string, otherStep?: string): any;
|
|
113
104
|
/**
|
|
114
105
|
* Returns a map of ids:uuids for everything in the project
|
|
115
106
|
*/
|
|
116
|
-
getUUIDMap(
|
|
117
|
-
workflows: boolean;
|
|
118
|
-
project: false;
|
|
119
|
-
}): {};
|
|
107
|
+
getUUIDMap(): UUIDMap;
|
|
120
108
|
}
|
|
121
109
|
|
|
122
110
|
declare function yamlToJson(y: string): any;
|
|
123
|
-
declare function jsonToYaml(json: string |
|
|
111
|
+
declare function jsonToYaml(json: string | Object): string;
|
|
124
112
|
|
|
125
113
|
type GenerateWorkflowOptions = {
|
|
126
114
|
name: string;
|
|
@@ -131,6 +119,7 @@ type GenerateWorkflowOptions = {
|
|
|
131
119
|
};
|
|
132
120
|
type GenerateProjectOptions = GenerateWorkflowOptions & {
|
|
133
121
|
uuidMap: Array<Record<string, string>>;
|
|
122
|
+
uuid?: string | number;
|
|
134
123
|
};
|
|
135
124
|
/**
|
|
136
125
|
* Generate a Workflow from a simple text based representation
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import { humanId } from "human-id";
|
|
|
9
9
|
|
|
10
10
|
// src/util/slugify.ts
|
|
11
11
|
function slugify(text) {
|
|
12
|
-
return text?.replace(/\W/g, " ").trim().replace(/\s+/g, "-").toLowerCase();
|
|
12
|
+
return text?.replace(/\W/g, " ").trim().replace(/\s+/g, "-").toLowerCase() ?? "";
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
// src/util/version.ts
|
|
@@ -25,7 +25,7 @@ var generateHash = (workflow, source = "cli") => {
|
|
|
25
25
|
"name",
|
|
26
26
|
"adaptors",
|
|
27
27
|
"adaptor",
|
|
28
|
-
// there's
|
|
28
|
+
// there's both adaptor & adaptors key in steps somehow
|
|
29
29
|
"expression",
|
|
30
30
|
"configuration",
|
|
31
31
|
// assumes a string credential id
|
|
@@ -55,12 +55,13 @@ var generateHash = (workflow, source = "cli") => {
|
|
|
55
55
|
}
|
|
56
56
|
});
|
|
57
57
|
if (step.next && Array.isArray(step.next)) {
|
|
58
|
-
const
|
|
58
|
+
const steps2 = step.next.slice();
|
|
59
|
+
steps2.slice().sort((a, b) => {
|
|
59
60
|
const aLabel = a.label || "";
|
|
60
61
|
const bLabel = b.label || "";
|
|
61
62
|
return aLabel.localeCompare(bLabel);
|
|
62
63
|
});
|
|
63
|
-
for (const edge of
|
|
64
|
+
for (const edge of step.next) {
|
|
64
65
|
edgeKeys.forEach((key) => {
|
|
65
66
|
if (isDefined(edge[key])) {
|
|
66
67
|
parts.push(key, serializeValue(edge[key]));
|
|
@@ -89,6 +90,8 @@ var Workflow = class {
|
|
|
89
90
|
name;
|
|
90
91
|
id;
|
|
91
92
|
openfn;
|
|
93
|
+
options;
|
|
94
|
+
// TODO
|
|
92
95
|
constructor(workflow) {
|
|
93
96
|
this.index = {
|
|
94
97
|
steps: {},
|
|
@@ -114,13 +117,14 @@ var Workflow = class {
|
|
|
114
117
|
}
|
|
115
118
|
this.openfn = openfn;
|
|
116
119
|
this.options = options;
|
|
117
|
-
this
|
|
120
|
+
this._buildIndex();
|
|
118
121
|
}
|
|
119
122
|
get steps() {
|
|
120
123
|
return this.workflow.steps;
|
|
121
124
|
}
|
|
122
|
-
|
|
123
|
-
for (const
|
|
125
|
+
_buildIndex() {
|
|
126
|
+
for (const step of this.workflow.steps) {
|
|
127
|
+
const s = step;
|
|
124
128
|
this.index.steps[s.id] = s;
|
|
125
129
|
this.index.uuid[s.id] = s.openfn?.uuid;
|
|
126
130
|
if (s.openfn?.uuid) {
|
|
@@ -174,7 +178,8 @@ var Workflow = class {
|
|
|
174
178
|
}
|
|
175
179
|
getAllEdges() {
|
|
176
180
|
const edges = {};
|
|
177
|
-
for (const
|
|
181
|
+
for (const s of this.steps) {
|
|
182
|
+
const step = s;
|
|
178
183
|
const next = typeof step.next === "string" ? { [step.next]: true } : step.next || {};
|
|
179
184
|
for (const toNode of Object.keys(next)) {
|
|
180
185
|
if (!Array.isArray(edges[step.id]))
|
|
@@ -218,14 +223,10 @@ var Workflow = class {
|
|
|
218
223
|
}
|
|
219
224
|
// return true if the current workflow can be merged into the target workflow without losing any changes
|
|
220
225
|
canMergeInto(target) {
|
|
221
|
-
const thisHistory = this.workflow.history?.concat(this.getVersionHash());
|
|
222
|
-
const targetHistory = target.workflow.history?.concat(
|
|
223
|
-
target.getVersionHash()
|
|
224
|
-
);
|
|
226
|
+
const thisHistory = this.workflow.history?.concat(this.getVersionHash()) ?? [];
|
|
227
|
+
const targetHistory = target.workflow.history?.concat(target.getVersionHash()) ?? [];
|
|
225
228
|
const targetHead = targetHistory[targetHistory.length - 1];
|
|
226
|
-
|
|
227
|
-
return true;
|
|
228
|
-
return false;
|
|
229
|
+
return thisHistory.indexOf(targetHead) > -1;
|
|
229
230
|
}
|
|
230
231
|
};
|
|
231
232
|
var Workflow_default = Workflow;
|
|
@@ -243,11 +244,12 @@ function to_json_default(project) {
|
|
|
243
244
|
return {
|
|
244
245
|
// There must be a better way to do this?
|
|
245
246
|
// Do we just serialize all public fields?
|
|
247
|
+
id: project.id,
|
|
246
248
|
name: project.name,
|
|
247
249
|
description: project.description,
|
|
248
250
|
config: project.config,
|
|
249
251
|
meta: project.meta,
|
|
250
|
-
workflows: project.workflows,
|
|
252
|
+
workflows: project.workflows.map((w) => w.toJSON()),
|
|
251
253
|
collections: project.collections,
|
|
252
254
|
credentials: project.credentials,
|
|
253
255
|
openfn: project.openfn,
|
|
@@ -255,6 +257,10 @@ function to_json_default(project) {
|
|
|
255
257
|
};
|
|
256
258
|
}
|
|
257
259
|
|
|
260
|
+
// src/serialize/to-app-state.ts
|
|
261
|
+
import { pick, omitBy, isNil } from "lodash-es";
|
|
262
|
+
import { randomUUID } from "node:crypto";
|
|
263
|
+
|
|
258
264
|
// src/util/rename-keys.ts
|
|
259
265
|
function renameKeys(props = {}, keyMap) {
|
|
260
266
|
return Object.fromEntries(
|
|
@@ -280,19 +286,16 @@ function jsonToYaml(json) {
|
|
|
280
286
|
}
|
|
281
287
|
|
|
282
288
|
// src/serialize/to-app-state.ts
|
|
283
|
-
import { randomUUID } from "node:crypto";
|
|
284
289
|
function to_app_state_default(project, options = {}) {
|
|
285
|
-
const { uuid
|
|
286
|
-
const state =
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
workflows: project.workflows.map(mapWorkflow)
|
|
295
|
-
};
|
|
290
|
+
const { uuid, endpoint, env, ...rest } = project.openfn ?? {};
|
|
291
|
+
const state = omitBy(
|
|
292
|
+
pick(project, ["name", "description", "collections"]),
|
|
293
|
+
isNil
|
|
294
|
+
);
|
|
295
|
+
state.id = uuid;
|
|
296
|
+
Object.assign(state, rest, project.options);
|
|
297
|
+
state.project_credentials = project.credentials ?? [];
|
|
298
|
+
state.workflows = project.workflows.map(mapWorkflow);
|
|
296
299
|
const shouldReturnYaml = options.format === "yaml" || !options.format && project.config.formats.project === "yaml";
|
|
297
300
|
if (shouldReturnYaml) {
|
|
298
301
|
return jsonToYaml(state);
|
|
@@ -307,11 +310,15 @@ var mapWorkflow = (workflow) => {
|
|
|
307
310
|
const wfState = {
|
|
308
311
|
...originalOpenfnProps,
|
|
309
312
|
id: workflow.openfn?.uuid ?? randomUUID(),
|
|
310
|
-
name: workflow.name,
|
|
311
313
|
jobs: [],
|
|
312
314
|
triggers: [],
|
|
313
|
-
edges: []
|
|
315
|
+
edges: [],
|
|
316
|
+
lock_version: workflow.openfn?.lock_version ?? null
|
|
317
|
+
// TODO needs testing
|
|
314
318
|
};
|
|
319
|
+
if (workflow.name) {
|
|
320
|
+
wfState.name = workflow.name;
|
|
321
|
+
}
|
|
315
322
|
const lookup = workflow.steps.reduce((obj, next) => {
|
|
316
323
|
if (!next.openfn?.uuid) {
|
|
317
324
|
next.openfn ??= {};
|
|
@@ -321,7 +328,7 @@ var mapWorkflow = (workflow) => {
|
|
|
321
328
|
return obj;
|
|
322
329
|
}, {});
|
|
323
330
|
workflow.steps.forEach((s) => {
|
|
324
|
-
let isTrigger;
|
|
331
|
+
let isTrigger = false;
|
|
325
332
|
let node;
|
|
326
333
|
if (s.type && !s.expression) {
|
|
327
334
|
isTrigger = true;
|
|
@@ -331,23 +338,28 @@ var mapWorkflow = (workflow) => {
|
|
|
331
338
|
};
|
|
332
339
|
wfState.triggers.push(node);
|
|
333
340
|
} else {
|
|
334
|
-
node =
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
341
|
+
node = omitBy(pick(s, ["name", "adaptor"]), isNil);
|
|
342
|
+
const { uuid: uuid2, ...otherOpenFnProps } = s.openfn ?? {};
|
|
343
|
+
node.id = uuid2;
|
|
344
|
+
Object.assign(node, otherOpenFnProps);
|
|
345
|
+
if (s.expression) {
|
|
346
|
+
node.body = s.expression;
|
|
347
|
+
}
|
|
348
|
+
node.project_credential_id = s.openfn?.project_credential_id ?? null;
|
|
349
|
+
node.keychain_credential_id = null;
|
|
340
350
|
wfState.jobs.push(node);
|
|
341
351
|
}
|
|
342
352
|
Object.keys(s.next ?? {}).forEach((next) => {
|
|
343
353
|
const rules = s.next[next];
|
|
354
|
+
const { uuid: uuid2, ...otherOpenFnProps } = rules.openfn ?? {};
|
|
344
355
|
const e = {
|
|
345
|
-
id:
|
|
356
|
+
id: uuid2 ?? randomUUID(),
|
|
346
357
|
target_job_id: lookup[next],
|
|
347
358
|
enabled: !rules.disabled,
|
|
348
359
|
source_trigger_id: null
|
|
349
360
|
// lightning complains if this isn't set, even if its falsy :(
|
|
350
361
|
};
|
|
362
|
+
Object.assign(e, otherOpenFnProps);
|
|
351
363
|
if (isTrigger) {
|
|
352
364
|
e.source_trigger_id = node.id;
|
|
353
365
|
} else {
|
|
@@ -371,13 +383,12 @@ import nodepath from "path";
|
|
|
371
383
|
// src/util/config.ts
|
|
372
384
|
import { readFileSync } from "node:fs";
|
|
373
385
|
import path from "node:path";
|
|
374
|
-
import { pickBy, isNil } from "lodash-es";
|
|
386
|
+
import { pickBy, isNil as isNil2 } from "lodash-es";
|
|
375
387
|
var buildConfig = (config = {}) => ({
|
|
376
388
|
...config,
|
|
377
389
|
dirs: {
|
|
378
|
-
projects: ".projects",
|
|
379
|
-
|
|
380
|
-
workflows: "workflows"
|
|
390
|
+
projects: config.dirs?.projects ?? ".projects",
|
|
391
|
+
workflows: config.dirs?.workflows ?? "workflows"
|
|
381
392
|
},
|
|
382
393
|
formats: {
|
|
383
394
|
openfn: config.formats?.openfn ?? "yaml",
|
|
@@ -433,7 +444,7 @@ var loadWorkspaceFile = (contents, format = "yaml") => {
|
|
|
433
444
|
formats,
|
|
434
445
|
dirs
|
|
435
446
|
},
|
|
436
|
-
(value) => !
|
|
447
|
+
(value) => !isNil2(value)
|
|
437
448
|
);
|
|
438
449
|
} else {
|
|
439
450
|
project = json.project ?? {};
|
|
@@ -454,7 +465,6 @@ var findWorkspaceFile = (dir = ".") => {
|
|
|
454
465
|
content = JSON.parse(file);
|
|
455
466
|
}
|
|
456
467
|
} catch (e2) {
|
|
457
|
-
console.log(e2);
|
|
458
468
|
throw e2;
|
|
459
469
|
}
|
|
460
470
|
}
|
|
@@ -480,13 +490,13 @@ function to_fs_default(project) {
|
|
|
480
490
|
}
|
|
481
491
|
return files;
|
|
482
492
|
}
|
|
483
|
-
var extractWorkflow = (project,
|
|
493
|
+
var extractWorkflow = (project, workflowId) => {
|
|
484
494
|
const format = project.config.formats.workflow;
|
|
485
|
-
const workflow = project.getWorkflow(
|
|
495
|
+
const workflow = project.getWorkflow(workflowId);
|
|
486
496
|
if (!workflow) {
|
|
487
|
-
throw new Error(`workflow not found: ${
|
|
497
|
+
throw new Error(`workflow not found: ${workflowId}`);
|
|
488
498
|
}
|
|
489
|
-
const root = project.config.dirs.
|
|
499
|
+
const root = project.config.dirs.workflows ?? project.config.workflowRoot ?? "workflows/";
|
|
490
500
|
const path5 = nodepath.join(root, workflow.id, workflow.id);
|
|
491
501
|
const wf = {
|
|
492
502
|
id: workflow.id,
|
|
@@ -504,17 +514,17 @@ var extractWorkflow = (project, workflowId2) => {
|
|
|
504
514
|
};
|
|
505
515
|
return handleOutput(wf, path5, format);
|
|
506
516
|
};
|
|
507
|
-
var extractStep = (project,
|
|
508
|
-
const workflow = project.getWorkflow(
|
|
517
|
+
var extractStep = (project, workflowId, stepId) => {
|
|
518
|
+
const workflow = project.getWorkflow(workflowId);
|
|
509
519
|
if (!workflow) {
|
|
510
|
-
throw new Error(`workflow not found: ${
|
|
520
|
+
throw new Error(`workflow not found: ${workflowId}`);
|
|
511
521
|
}
|
|
512
522
|
const step = workflow.steps.find((s) => s.id === stepId);
|
|
513
523
|
if (!step) {
|
|
514
524
|
throw new Error(`step not found: ${stepId}`);
|
|
515
525
|
}
|
|
516
526
|
if (step.expression) {
|
|
517
|
-
const root = project.config?.workflowRoot ?? "workflows/";
|
|
527
|
+
const root = project.config?.dirs.workflows ?? project.config?.workflowRoot ?? "workflows/";
|
|
518
528
|
const path5 = nodepath.join(root, `${workflow.id}/${step.id}.js`);
|
|
519
529
|
const content = step.expression;
|
|
520
530
|
return { path: path5, content };
|
|
@@ -534,17 +544,18 @@ var handleOutput = (data, filePath, format) => {
|
|
|
534
544
|
};
|
|
535
545
|
|
|
536
546
|
// src/parse/from-app-state.ts
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
}
|
|
540
|
-
var from_app_state_default = (state, config) => {
|
|
547
|
+
var from_app_state_default = (state, meta, config = {}) => {
|
|
548
|
+
let stateJson;
|
|
541
549
|
if (typeof state === "string") {
|
|
542
|
-
if (config
|
|
543
|
-
|
|
550
|
+
if (config.format === "yaml") {
|
|
551
|
+
stateJson = yamlToJson(state);
|
|
544
552
|
} else {
|
|
545
|
-
|
|
553
|
+
stateJson = JSON.parse(state);
|
|
546
554
|
}
|
|
555
|
+
} else {
|
|
556
|
+
stateJson = state;
|
|
547
557
|
}
|
|
558
|
+
delete config.format;
|
|
548
559
|
const {
|
|
549
560
|
id,
|
|
550
561
|
name,
|
|
@@ -555,27 +566,25 @@ var from_app_state_default = (state, config) => {
|
|
|
555
566
|
inserted_at,
|
|
556
567
|
updated_at,
|
|
557
568
|
...options
|
|
558
|
-
} =
|
|
569
|
+
} = stateJson;
|
|
559
570
|
const proj = {
|
|
560
571
|
name,
|
|
561
|
-
description,
|
|
572
|
+
description: description ?? void 0,
|
|
562
573
|
collections,
|
|
563
574
|
credentials,
|
|
564
|
-
options
|
|
575
|
+
options,
|
|
576
|
+
config
|
|
565
577
|
};
|
|
578
|
+
const { id: _ignore, ...restMeta } = meta;
|
|
566
579
|
proj.openfn = {
|
|
580
|
+
// @ts-ignore
|
|
567
581
|
uuid: id,
|
|
568
|
-
|
|
569
|
-
endpoint: config.endpoint,
|
|
570
|
-
env: config.env,
|
|
582
|
+
...restMeta,
|
|
571
583
|
inserted_at,
|
|
572
584
|
updated_at
|
|
573
585
|
};
|
|
574
|
-
proj.
|
|
575
|
-
|
|
576
|
-
};
|
|
577
|
-
proj.workflows = state.workflows.map(mapWorkflow2);
|
|
578
|
-
return new Project(proj, config?.config);
|
|
586
|
+
proj.workflows = stateJson.workflows.map(mapWorkflow2);
|
|
587
|
+
return new Project(proj, config);
|
|
579
588
|
};
|
|
580
589
|
var mapTriggerEdgeCondition = (edge) => {
|
|
581
590
|
const e = {
|
|
@@ -601,7 +610,7 @@ var mapWorkflow2 = (workflow) => {
|
|
|
601
610
|
openfn: renameKeys(remoteProps, { id: "uuid" })
|
|
602
611
|
};
|
|
603
612
|
if (workflow.name) {
|
|
604
|
-
mapped.id =
|
|
613
|
+
mapped.id = slugify(workflow.name);
|
|
605
614
|
}
|
|
606
615
|
workflow.triggers.forEach((trigger) => {
|
|
607
616
|
const { type, ...otherProps } = trigger;
|
|
@@ -617,7 +626,7 @@ var mapWorkflow2 = (workflow) => {
|
|
|
617
626
|
if (!target) {
|
|
618
627
|
throw new Error(`Failed to find ${edge.target_job_id}`);
|
|
619
628
|
}
|
|
620
|
-
obj[
|
|
629
|
+
obj[slugify(target.name)] = mapTriggerEdgeCondition(edge);
|
|
621
630
|
return obj;
|
|
622
631
|
}, {})
|
|
623
632
|
});
|
|
@@ -628,16 +637,17 @@ var mapWorkflow2 = (workflow) => {
|
|
|
628
637
|
);
|
|
629
638
|
const { body: expression, name: name2, adaptor, ...remoteProps2 } = step;
|
|
630
639
|
const s = {
|
|
631
|
-
id:
|
|
640
|
+
id: slugify(name2),
|
|
632
641
|
name: name2,
|
|
633
642
|
expression,
|
|
634
643
|
adaptor,
|
|
644
|
+
// TODO is this wrong?
|
|
635
645
|
openfn: renameKeys(remoteProps2, { id: "uuid" })
|
|
636
646
|
};
|
|
637
647
|
if (outboundEdges.length) {
|
|
638
648
|
s.next = outboundEdges.reduce((next, edge) => {
|
|
639
649
|
const target = jobs.find((j) => j.id === edge.target_job_id);
|
|
640
|
-
next[
|
|
650
|
+
next[slugify(target.name)] = mapTriggerEdgeCondition(edge);
|
|
641
651
|
return next;
|
|
642
652
|
}, {});
|
|
643
653
|
}
|
|
@@ -649,13 +659,10 @@ var mapWorkflow2 = (workflow) => {
|
|
|
649
659
|
// src/parse/from-path.ts
|
|
650
660
|
import { extname } from "node:path";
|
|
651
661
|
import { readFile } from "node:fs/promises";
|
|
652
|
-
|
|
662
|
+
import { omit } from "lodash-es";
|
|
663
|
+
var from_path_default = async (path5, config = {}) => {
|
|
653
664
|
const ext = extname(path5).toLowerCase();
|
|
654
665
|
const source = await readFile(path5, "utf8");
|
|
655
|
-
const config = {
|
|
656
|
-
format: null,
|
|
657
|
-
config: options.config
|
|
658
|
-
};
|
|
659
666
|
let state;
|
|
660
667
|
if (ext === ".json") {
|
|
661
668
|
config.format = "json";
|
|
@@ -666,7 +673,8 @@ var from_path_default = async (path5, options = {}) => {
|
|
|
666
673
|
} else {
|
|
667
674
|
throw new Error(`Cannot load a project from a ${ext} file`);
|
|
668
675
|
}
|
|
669
|
-
|
|
676
|
+
const meta = {};
|
|
677
|
+
return from_app_state_default(state, meta, omit(config, ["format"]));
|
|
670
678
|
};
|
|
671
679
|
|
|
672
680
|
// src/parse/from-fs.ts
|
|
@@ -688,18 +696,18 @@ var get_identifier_default = (config = {}) => {
|
|
|
688
696
|
};
|
|
689
697
|
|
|
690
698
|
// src/parse/from-fs.ts
|
|
691
|
-
var parseProject = async (options
|
|
699
|
+
var parseProject = async (options) => {
|
|
692
700
|
const { root } = options;
|
|
693
701
|
const { type, content } = findWorkspaceFile(root);
|
|
694
702
|
const context = loadWorkspaceFile(content, type);
|
|
695
703
|
const config = buildConfig(context.workspace);
|
|
696
|
-
let state;
|
|
704
|
+
let state = null;
|
|
697
705
|
const identifier = get_identifier_default({
|
|
698
706
|
endpoint: context.project?.endpoint,
|
|
699
707
|
env: context.project?.env
|
|
700
708
|
});
|
|
701
709
|
try {
|
|
702
|
-
const format = config.formats?.project ?? config.formats?.
|
|
710
|
+
const format = config.formats?.project ?? config.formats?.project ?? "yaml";
|
|
703
711
|
const statePath = path2.join(
|
|
704
712
|
root,
|
|
705
713
|
config.dirs?.projects ?? ".projects",
|
|
@@ -722,7 +730,6 @@ var parseProject = async (options = {}) => {
|
|
|
722
730
|
const candidateWfs = await glob(pattern, {
|
|
723
731
|
ignore: ["**node_modules/**", "**tmp**"]
|
|
724
732
|
});
|
|
725
|
-
const workflows = [];
|
|
726
733
|
for (const filePath of candidateWfs) {
|
|
727
734
|
const candidate = await fs.readFile(filePath, "utf-8");
|
|
728
735
|
try {
|
|
@@ -783,9 +790,7 @@ var getUuidForStep = (project, workflow, stepId) => {
|
|
|
783
790
|
var getUuidForEdge = (project, workflow, from, to) => {
|
|
784
791
|
const wf = typeof workflow === "string" ? project.getWorkflow(workflow) : workflow;
|
|
785
792
|
if (!wf) {
|
|
786
|
-
throw new Error(
|
|
787
|
-
`Workflow "${workflowId} not found in project ${project.id}`
|
|
788
|
-
);
|
|
793
|
+
throw new Error(`Workflow "${workflow} not found in project ${project.id}`);
|
|
789
794
|
}
|
|
790
795
|
for (const step of wf.steps) {
|
|
791
796
|
if (step.id === from) {
|
|
@@ -804,43 +809,48 @@ var getUuidForEdge = (project, workflow, from, to) => {
|
|
|
804
809
|
import { defaultsDeep, isEmpty } from "lodash-es";
|
|
805
810
|
|
|
806
811
|
// src/util/base-merge.ts
|
|
807
|
-
import { pick, assign } from "lodash-es";
|
|
812
|
+
import { pick as pick2, assign } from "lodash-es";
|
|
808
813
|
function baseMerge(target, source, sourceKeys, assigns = {}) {
|
|
809
|
-
const pickedSource = sourceKeys ?
|
|
814
|
+
const pickedSource = sourceKeys ? pick2(source, sourceKeys) : source;
|
|
810
815
|
return assign(target, { ...pickedSource, ...assigns });
|
|
811
816
|
}
|
|
812
817
|
|
|
813
818
|
// src/merge/merge-node.ts
|
|
819
|
+
var clone2 = (obj) => JSON.parse(JSON.stringify(obj));
|
|
814
820
|
function mergeWorkflows(source, target, mappings) {
|
|
815
821
|
const targetNodes = {};
|
|
816
|
-
for (const
|
|
817
|
-
targetNodes[
|
|
822
|
+
for (const targetStep of target.steps) {
|
|
823
|
+
targetNodes[targetStep.openfn?.uuid || targetStep.id] = targetStep;
|
|
824
|
+
}
|
|
818
825
|
const steps = [];
|
|
819
|
-
for (const
|
|
820
|
-
let newNode =
|
|
821
|
-
if (
|
|
822
|
-
const preservedId = mappings.nodes[
|
|
823
|
-
const
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
)
|
|
827
|
-
const key =
|
|
828
|
-
if (
|
|
826
|
+
for (const sourceStep of source.steps) {
|
|
827
|
+
let newNode = clone2(sourceStep);
|
|
828
|
+
if (sourceStep.id in mappings.nodes) {
|
|
829
|
+
const preservedId = mappings.nodes[sourceStep.id];
|
|
830
|
+
const toNodeIds = Object.keys(
|
|
831
|
+
typeof sourceStep.next === "string" ? { [sourceStep.next]: true } : sourceStep.next || {}
|
|
832
|
+
);
|
|
833
|
+
for (const toNode of toNodeIds) {
|
|
834
|
+
const key = sourceStep.id + "-" + toNode;
|
|
835
|
+
if (key in mappings.edges) {
|
|
829
836
|
const preservedEdgeId = mappings.edges[key];
|
|
830
|
-
const
|
|
831
|
-
|
|
832
|
-
...
|
|
833
|
-
openfn: {
|
|
837
|
+
const edge = sourceStep.next?.[toNode] || {};
|
|
838
|
+
sourceStep.next[toNode] = {
|
|
839
|
+
...edge,
|
|
840
|
+
openfn: Object.assign({}, edge?.openfn, {
|
|
841
|
+
uuid: preservedEdgeId
|
|
842
|
+
})
|
|
834
843
|
};
|
|
835
844
|
}
|
|
836
845
|
}
|
|
837
|
-
newNode = baseMerge(targetNodes[preservedId],
|
|
846
|
+
newNode = baseMerge(targetNodes[preservedId], sourceStep, [
|
|
838
847
|
"id",
|
|
839
848
|
"name",
|
|
849
|
+
// @ts-ignore
|
|
840
850
|
"adaptor",
|
|
851
|
+
"adaptors",
|
|
841
852
|
"expression",
|
|
842
|
-
"next"
|
|
843
|
-
"previous"
|
|
853
|
+
"next"
|
|
844
854
|
]);
|
|
845
855
|
} else {
|
|
846
856
|
}
|
|
@@ -964,7 +974,7 @@ function findBestMatch(sourceStep, candidates, sourceEdges, targetEdges, getMapp
|
|
|
964
974
|
}
|
|
965
975
|
return null;
|
|
966
976
|
}
|
|
967
|
-
function mapEdges(sourceEdges,
|
|
977
|
+
function mapEdges(sourceEdges, _targetEdges, idMap, getTargetUUID) {
|
|
968
978
|
const edgeMapping = {};
|
|
969
979
|
for (const [parentId, children] of Object.entries(sourceEdges)) {
|
|
970
980
|
for (const childId of children) {
|
|
@@ -980,7 +990,7 @@ function mapEdges(sourceEdges, targetEdges, idMap, getTargetUUID) {
|
|
|
980
990
|
return edgeMapping;
|
|
981
991
|
}
|
|
982
992
|
function getStepUuid(step) {
|
|
983
|
-
return step?.openfn?.uuid
|
|
993
|
+
return step?.openfn?.uuid;
|
|
984
994
|
}
|
|
985
995
|
function mapStepsById(source, target) {
|
|
986
996
|
const targetIndex = {};
|
|
@@ -1085,8 +1095,7 @@ function mapStepByChildren(sourceStep, candidates, sourceEdges, targetEdges, get
|
|
|
1085
1095
|
};
|
|
1086
1096
|
}
|
|
1087
1097
|
function mapStepByExpression(sourceStep, candidates) {
|
|
1088
|
-
|
|
1089
|
-
return findByExpression(expression, candidates);
|
|
1098
|
+
return findByExpression(sourceStep.expression, candidates);
|
|
1090
1099
|
}
|
|
1091
1100
|
|
|
1092
1101
|
// src/util/get-duplicates.ts
|
|
@@ -1104,15 +1113,20 @@ function getDuplicates(arr) {
|
|
|
1104
1113
|
}
|
|
1105
1114
|
|
|
1106
1115
|
// src/merge/merge-project.ts
|
|
1107
|
-
|
|
1116
|
+
var UnsafeMergeError = class extends Error {
|
|
1117
|
+
};
|
|
1118
|
+
function merge(source, target, opts) {
|
|
1108
1119
|
const defaultOptions = {
|
|
1109
1120
|
workflowMappings: {},
|
|
1110
1121
|
removeUnmapped: false,
|
|
1111
1122
|
force: true
|
|
1112
1123
|
};
|
|
1113
|
-
options = defaultsDeep(
|
|
1124
|
+
const options = defaultsDeep(
|
|
1125
|
+
opts,
|
|
1126
|
+
defaultOptions
|
|
1127
|
+
);
|
|
1114
1128
|
const dupTargetMappings = getDuplicates(
|
|
1115
|
-
Object.values(options
|
|
1129
|
+
Object.values(options.workflowMappings ?? {})
|
|
1116
1130
|
);
|
|
1117
1131
|
if (dupTargetMappings.length) {
|
|
1118
1132
|
throw new Error(
|
|
@@ -1134,11 +1148,11 @@ function merge(source, target, options) {
|
|
|
1134
1148
|
const targetId = options.workflowMappings?.[sourceWorkflow.id] ?? sourceWorkflow.id;
|
|
1135
1149
|
const targetWorkflow = target.getWorkflow(targetId);
|
|
1136
1150
|
if (targetWorkflow && !sourceWorkflow.canMergeInto(targetWorkflow)) {
|
|
1137
|
-
potentialConflicts[sourceWorkflow.
|
|
1151
|
+
potentialConflicts[sourceWorkflow.id] = targetWorkflow?.id;
|
|
1138
1152
|
}
|
|
1139
1153
|
}
|
|
1140
1154
|
if (Object.keys(potentialConflicts).length && !options?.force) {
|
|
1141
|
-
throw new
|
|
1155
|
+
throw new UnsafeMergeError(
|
|
1142
1156
|
`The below workflows can't be merged directly without losing data
|
|
1143
1157
|
${Object.entries(
|
|
1144
1158
|
potentialConflicts
|
|
@@ -1153,6 +1167,7 @@ Pass --force to force the merge anyway`
|
|
|
1153
1167
|
usedTargetIds.add(targetWorkflow.id);
|
|
1154
1168
|
const mappings = map_uuids_default(sourceWorkflow, targetWorkflow);
|
|
1155
1169
|
finalWorkflows.push(
|
|
1170
|
+
// @ts-ignore
|
|
1156
1171
|
mergeWorkflows(sourceWorkflow, targetWorkflow, mappings)
|
|
1157
1172
|
);
|
|
1158
1173
|
} else {
|
|
@@ -1167,7 +1182,9 @@ Pass --force to force the merge anyway`
|
|
|
1167
1182
|
}
|
|
1168
1183
|
}
|
|
1169
1184
|
return new Project(
|
|
1170
|
-
baseMerge(target, source, ["collections"], {
|
|
1185
|
+
baseMerge(target, source, ["collections"], {
|
|
1186
|
+
workflows: finalWorkflows
|
|
1187
|
+
})
|
|
1171
1188
|
);
|
|
1172
1189
|
}
|
|
1173
1190
|
|
|
@@ -1196,19 +1213,19 @@ var Project = class {
|
|
|
1196
1213
|
workspace;
|
|
1197
1214
|
config;
|
|
1198
1215
|
collections;
|
|
1199
|
-
|
|
1216
|
+
credentials;
|
|
1217
|
+
static async from(type, data, ...rest) {
|
|
1200
1218
|
if (type === "state") {
|
|
1201
|
-
return from_app_state_default(data,
|
|
1219
|
+
return from_app_state_default(data, rest[0], rest[1]);
|
|
1202
1220
|
} else if (type === "fs") {
|
|
1203
|
-
return parseProject(data
|
|
1221
|
+
return parseProject(data);
|
|
1204
1222
|
} else if (type === "path") {
|
|
1205
|
-
return from_path_default(data,
|
|
1223
|
+
return from_path_default(data, rest[0]);
|
|
1206
1224
|
}
|
|
1207
1225
|
throw new Error(`Didn't recognize type ${type}`);
|
|
1208
1226
|
}
|
|
1209
1227
|
// Diff two projects
|
|
1210
|
-
static diff(a, b) {
|
|
1211
|
-
}
|
|
1228
|
+
// /static diff(a: Project, b: Project) {}
|
|
1212
1229
|
// Merge a source project (staging) into the target project (main)
|
|
1213
1230
|
// Returns a new Project
|
|
1214
1231
|
// TODO: throw if histories have diverged
|
|
@@ -1220,17 +1237,16 @@ var Project = class {
|
|
|
1220
1237
|
// maybe this second arg is config - like env, branch rules, serialisation rules
|
|
1221
1238
|
// stuff that's external to the actual project and managed by the repo
|
|
1222
1239
|
// TODO maybe the constructor is (data, Workspace)
|
|
1223
|
-
constructor(data, config
|
|
1224
|
-
this.
|
|
1225
|
-
this.id = data.id ?? data.name ? slugify(data.name) : humanId({ separator: "-", capitalize: false });
|
|
1240
|
+
constructor(data, config) {
|
|
1241
|
+
this.config = buildConfig(config);
|
|
1242
|
+
this.id = data.id ?? (data.name ? slugify(data.name) : humanId({ separator: "-", capitalize: false }));
|
|
1226
1243
|
this.name = data.name;
|
|
1227
|
-
this.description = data.description;
|
|
1244
|
+
this.description = data.description ?? void 0;
|
|
1228
1245
|
this.openfn = data.openfn;
|
|
1229
1246
|
this.options = data.options;
|
|
1230
1247
|
this.workflows = data.workflows?.map(maybeCreateWorkflow) ?? [];
|
|
1231
1248
|
this.collections = data.collections;
|
|
1232
1249
|
this.credentials = data.credentials;
|
|
1233
|
-
this.meta = data.meta;
|
|
1234
1250
|
}
|
|
1235
1251
|
setConfig(config) {
|
|
1236
1252
|
this.config = buildConfig(config);
|
|
@@ -1252,8 +1268,7 @@ var Project = class {
|
|
|
1252
1268
|
return get_identifier_default(this.openfn);
|
|
1253
1269
|
}
|
|
1254
1270
|
// Compare this project with another and return a diff
|
|
1255
|
-
compare(proj) {
|
|
1256
|
-
}
|
|
1271
|
+
// compare(proj: Project) {}
|
|
1257
1272
|
// find the UUID for a given node or edge
|
|
1258
1273
|
// returns null if it doesn't exist
|
|
1259
1274
|
getUUID(workflow, stepId, otherStep) {
|
|
@@ -1265,7 +1280,7 @@ var Project = class {
|
|
|
1265
1280
|
/**
|
|
1266
1281
|
* Returns a map of ids:uuids for everything in the project
|
|
1267
1282
|
*/
|
|
1268
|
-
getUUIDMap(
|
|
1283
|
+
getUUIDMap() {
|
|
1269
1284
|
const result = {};
|
|
1270
1285
|
for (const wf of this.workflows) {
|
|
1271
1286
|
result[wf.id] = {
|
|
@@ -1298,8 +1313,8 @@ function pathExists(fpath, type) {
|
|
|
1298
1313
|
}
|
|
1299
1314
|
|
|
1300
1315
|
// src/Workspace.ts
|
|
1301
|
-
var PROJECT_EXTENSIONS = [".yaml", ".yml"];
|
|
1302
1316
|
var Workspace = class {
|
|
1317
|
+
// @ts-ignore config not defininitely assigned - it sure is
|
|
1303
1318
|
config;
|
|
1304
1319
|
activeProject;
|
|
1305
1320
|
projects = [];
|
|
@@ -1312,22 +1327,35 @@ var Workspace = class {
|
|
|
1312
1327
|
context = loadWorkspaceFile(content, type);
|
|
1313
1328
|
this.isValid = true;
|
|
1314
1329
|
} catch (e) {
|
|
1315
|
-
console.
|
|
1330
|
+
console.error(e);
|
|
1316
1331
|
return;
|
|
1317
1332
|
}
|
|
1318
1333
|
this.config = buildConfig(context.workspace);
|
|
1319
1334
|
this.activeProject = context.project;
|
|
1320
1335
|
const projectsPath = path3.join(workspacePath, this.config.dirs.projects);
|
|
1321
1336
|
if (this.isValid && pathExists(projectsPath, "directory")) {
|
|
1337
|
+
const ext = `.${this.config.formats.project}`;
|
|
1322
1338
|
const stateFiles = fs3.readdirSync(projectsPath).filter(
|
|
1323
|
-
(fileName) =>
|
|
1339
|
+
(fileName) => path3.extname(fileName) === ext && path3.parse(fileName).name !== "openfn"
|
|
1324
1340
|
);
|
|
1325
1341
|
this.projects = stateFiles.map((file) => {
|
|
1326
1342
|
const stateFilePath = path3.join(projectsPath, file);
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1343
|
+
try {
|
|
1344
|
+
const data = fs3.readFileSync(stateFilePath, "utf-8");
|
|
1345
|
+
const project = from_app_state_default(
|
|
1346
|
+
data,
|
|
1347
|
+
{},
|
|
1348
|
+
{
|
|
1349
|
+
...this.config,
|
|
1350
|
+
format: this.config?.formats.project
|
|
1351
|
+
}
|
|
1352
|
+
);
|
|
1353
|
+
this.projectPaths.set(project.id, stateFilePath);
|
|
1354
|
+
return project;
|
|
1355
|
+
} catch (e) {
|
|
1356
|
+
console.warn(`Failed to load project from ${stateFilePath}`);
|
|
1357
|
+
console.warn(e);
|
|
1358
|
+
}
|
|
1331
1359
|
}).filter((s) => s);
|
|
1332
1360
|
}
|
|
1333
1361
|
}
|
|
@@ -1349,7 +1377,7 @@ var Workspace = class {
|
|
|
1349
1377
|
return this.projectPaths.get(id);
|
|
1350
1378
|
}
|
|
1351
1379
|
getActiveProject() {
|
|
1352
|
-
return this.projects.find((p) => p.id === this.activeProject?.id) ?? this.projects.find((p) => p.openfn?.uuid === this.activeProject?.
|
|
1380
|
+
return this.projects.find((p) => p.id === this.activeProject?.id) ?? this.projects.find((p) => p.openfn?.uuid === this.activeProject?.uuid);
|
|
1353
1381
|
}
|
|
1354
1382
|
// TODO this needs to return default values
|
|
1355
1383
|
// We should always rely on the workspace to load these values
|
|
@@ -1369,6 +1397,7 @@ import { randomUUID as randomUUID2 } from "node:crypto";
|
|
|
1369
1397
|
import path4 from "node:path";
|
|
1370
1398
|
import { readFileSync as readFileSync2 } from "node:fs";
|
|
1371
1399
|
import { grammar } from "ohm-js";
|
|
1400
|
+
import { isNil as isNil3 } from "lodash-es";
|
|
1372
1401
|
var parser;
|
|
1373
1402
|
var initOperations = (options = {}) => {
|
|
1374
1403
|
let nodes = {};
|
|
@@ -1488,6 +1517,10 @@ function generateWorkflow(def, options = {}) {
|
|
|
1488
1517
|
if (!parser) {
|
|
1489
1518
|
parser = createParser();
|
|
1490
1519
|
}
|
|
1520
|
+
let uuid;
|
|
1521
|
+
if (options.openfnUuid) {
|
|
1522
|
+
uuid = options.uuidSeed ? options.uuidSeed++ : randomUUID2();
|
|
1523
|
+
}
|
|
1491
1524
|
const raw = parser.parse(def, options);
|
|
1492
1525
|
if (!raw.name) {
|
|
1493
1526
|
raw.name = "Workflow";
|
|
@@ -1495,9 +1528,12 @@ function generateWorkflow(def, options = {}) {
|
|
|
1495
1528
|
if (!raw.id) {
|
|
1496
1529
|
raw.id = "workflow";
|
|
1497
1530
|
}
|
|
1498
|
-
if (options.
|
|
1531
|
+
if (options.uuidMap && raw.id in options.uuidMap) {
|
|
1532
|
+
uuid = options.uuidMap[raw.id];
|
|
1533
|
+
}
|
|
1534
|
+
if (!isNil3(uuid) && options.openfnUuid) {
|
|
1499
1535
|
raw.openfn ??= {};
|
|
1500
|
-
raw.openfn.uuid =
|
|
1536
|
+
raw.openfn.uuid = uuid;
|
|
1501
1537
|
}
|
|
1502
1538
|
const wf = new Workflow_default(raw);
|
|
1503
1539
|
return wf;
|
|
@@ -1512,7 +1548,9 @@ function generateProject(name, workflowDefs, options = {}) {
|
|
|
1512
1548
|
return new Project_default({
|
|
1513
1549
|
name,
|
|
1514
1550
|
workflows,
|
|
1515
|
-
openfn:
|
|
1551
|
+
openfn: {
|
|
1552
|
+
uuid: options.uuid ?? (options.openfnUuid ? randomUUID2() : void 0)
|
|
1553
|
+
}
|
|
1516
1554
|
});
|
|
1517
1555
|
}
|
|
1518
1556
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openfn/project",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "Read, serialize, replicate and sync OpenFn projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -27,14 +27,15 @@
|
|
|
27
27
|
"typescript": "^5.9.2"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
+
"@types/lodash-es": "^4.17.12",
|
|
30
31
|
"glob": "^11.0.2",
|
|
31
32
|
"human-id": "^4.1.1",
|
|
32
33
|
"lodash": "^4.17.21",
|
|
33
34
|
"lodash-es": "^4.17.21",
|
|
34
35
|
"ohm-js": "^17.2.1",
|
|
35
36
|
"yaml": "^2.2.2",
|
|
36
|
-
"@openfn/
|
|
37
|
-
"@openfn/
|
|
37
|
+
"@openfn/logger": "1.0.6",
|
|
38
|
+
"@openfn/lexicon": "^1.2.6"
|
|
38
39
|
},
|
|
39
40
|
"files": [
|
|
40
41
|
"dist",
|