@openfn/project 0.9.1 → 0.9.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 +18 -13
- package/dist/index.js +63 -22
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,18 +1,8 @@
|
|
|
1
1
|
import * as l from '@openfn/lexicon';
|
|
2
2
|
import l__default, { WorkspaceConfig, UUID } from '@openfn/lexicon';
|
|
3
|
+
import { Logger } from '@openfn/logger';
|
|
3
4
|
import { Provisioner } from '@openfn/lexicon/lightning';
|
|
4
5
|
|
|
5
|
-
type SerializedProject = Omit<Partial<l.Project>, 'workflows'> & {
|
|
6
|
-
version: number;
|
|
7
|
-
workflows: SerializedWorkflow[];
|
|
8
|
-
};
|
|
9
|
-
type SerializedWorkflow = {
|
|
10
|
-
id: string;
|
|
11
|
-
name: string;
|
|
12
|
-
steps: l.Step[];
|
|
13
|
-
openfn?: l.ProjectMeta;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
6
|
type WithMeta<T> = T & {
|
|
17
7
|
openfn?: l.NodeMeta;
|
|
18
8
|
};
|
|
@@ -53,6 +43,17 @@ type FromFsConfig = {
|
|
|
53
43
|
root: string;
|
|
54
44
|
};
|
|
55
45
|
|
|
46
|
+
type SerializedProject = Omit<Partial<l.Project>, 'workflows'> & {
|
|
47
|
+
version: number;
|
|
48
|
+
workflows: SerializedWorkflow[];
|
|
49
|
+
};
|
|
50
|
+
type SerializedWorkflow = {
|
|
51
|
+
id: string;
|
|
52
|
+
name: string;
|
|
53
|
+
steps: WithMeta<l.Step[]>;
|
|
54
|
+
openfn?: l.ProjectMeta;
|
|
55
|
+
};
|
|
56
|
+
|
|
56
57
|
type MergeProjectOptions = {
|
|
57
58
|
workflowMappings: Record<string, string>;
|
|
58
59
|
removeUnmapped: boolean;
|
|
@@ -65,7 +66,8 @@ declare class Workspace {
|
|
|
65
66
|
private projects;
|
|
66
67
|
private projectPaths;
|
|
67
68
|
private isValid;
|
|
68
|
-
|
|
69
|
+
private logger;
|
|
70
|
+
constructor(workspacePath: string, logger?: Logger);
|
|
69
71
|
loadProject(): void;
|
|
70
72
|
list(): Project[];
|
|
71
73
|
/** Get a project by its id or UUID */
|
|
@@ -109,7 +111,9 @@ declare class Project {
|
|
|
109
111
|
static merge(source: Project, target: Project, options?: Partial<MergeProjectOptions>): Project;
|
|
110
112
|
constructor(data: Partial<l__default.Project>, config?: Partial<l__default.WorkspaceConfig>);
|
|
111
113
|
setConfig(config: Partial<WorkspaceConfig>): void;
|
|
112
|
-
serialize(type
|
|
114
|
+
serialize(type: 'project', options?: any): SerializedProject | string;
|
|
115
|
+
serialize(type: 'state', options?: any): Provisioner.Project | string;
|
|
116
|
+
serialize(type: 'fs', options?: any): Record<string, string>;
|
|
113
117
|
getWorkflow(idOrName: string): Workflow | undefined;
|
|
114
118
|
getIdentifier(): string;
|
|
115
119
|
getUUID(workflow: string | Workflow, stepId: string, otherStep?: string): any;
|
|
@@ -117,6 +121,7 @@ declare class Project {
|
|
|
117
121
|
* Returns a map of ids:uuids for everything in the project
|
|
118
122
|
*/
|
|
119
123
|
getUUIDMap(): UUIDMap;
|
|
124
|
+
canMergeInto(target: Project): boolean;
|
|
120
125
|
}
|
|
121
126
|
|
|
122
127
|
declare function yamlToJson(y: string): any;
|
package/dist/index.js
CHANGED
|
@@ -105,7 +105,7 @@ var Workflow = class {
|
|
|
105
105
|
};
|
|
106
106
|
this.workflow = clone(workflow);
|
|
107
107
|
this.workflow.history = workflow.history?.length ? workflow.history : [];
|
|
108
|
-
const { id, name, openfn, steps, ...options } = workflow;
|
|
108
|
+
const { id, name, openfn, steps, history, ...options } = workflow;
|
|
109
109
|
if (!(id || name)) {
|
|
110
110
|
throw new Error("A Workflow MUST have a name or id");
|
|
111
111
|
}
|
|
@@ -151,7 +151,7 @@ var Workflow = class {
|
|
|
151
151
|
Object.assign(item, props);
|
|
152
152
|
return this;
|
|
153
153
|
}
|
|
154
|
-
// Get properties on any step or edge by id
|
|
154
|
+
// Get properties on any step or edge by id or uuid
|
|
155
155
|
get(id) {
|
|
156
156
|
const item = this.index.edges[id] || this.index.steps[id];
|
|
157
157
|
if (!item) {
|
|
@@ -555,13 +555,32 @@ var to_project_default = (project, options = {}) => {
|
|
|
555
555
|
description: project.description,
|
|
556
556
|
collections: project.collections,
|
|
557
557
|
credentials: project.credentials,
|
|
558
|
-
openfn: project.openfn,
|
|
558
|
+
openfn: omitBy2(project.openfn, isNil3),
|
|
559
559
|
meta: project.meta,
|
|
560
560
|
options: omitBy2(project.options, isNil3),
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
(
|
|
564
|
-
|
|
561
|
+
workflows: project.workflows.map((w) => {
|
|
562
|
+
const obj = w.toJSON();
|
|
563
|
+
if (obj.openfn) {
|
|
564
|
+
obj.openfn = omitBy2(obj.openfn, isNil3);
|
|
565
|
+
}
|
|
566
|
+
if (obj.steps) {
|
|
567
|
+
obj.steps = obj.steps.sort((a, b) => {
|
|
568
|
+
return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
|
|
569
|
+
});
|
|
570
|
+
obj.steps.forEach((s) => {
|
|
571
|
+
s.openfn = omitBy2(s.openfn, isNil3);
|
|
572
|
+
if (s.next && typeof s.next !== "string") {
|
|
573
|
+
for (const id in s.next) {
|
|
574
|
+
const edge = s.next[id];
|
|
575
|
+
if (edge.openfn) {
|
|
576
|
+
edge.openfn = omitBy2(edge.openfn, isNil3);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
return obj;
|
|
583
|
+
})
|
|
565
584
|
},
|
|
566
585
|
isNil3
|
|
567
586
|
);
|
|
@@ -636,10 +655,11 @@ var mapTriggerEdgeCondition = (edge) => {
|
|
|
636
655
|
return e;
|
|
637
656
|
};
|
|
638
657
|
var mapWorkflow2 = (workflow) => {
|
|
639
|
-
const { jobs, edges, triggers, name, ...remoteProps } = workflow;
|
|
658
|
+
const { jobs, edges, triggers, name, version_history, ...remoteProps } = workflow;
|
|
640
659
|
const mapped = {
|
|
641
660
|
name: workflow.name,
|
|
642
661
|
steps: [],
|
|
662
|
+
history: workflow.version_history ?? [],
|
|
643
663
|
openfn: renameKeys(remoteProps, { id: "uuid" })
|
|
644
664
|
};
|
|
645
665
|
if (workflow.name) {
|
|
@@ -777,12 +797,12 @@ var parseProject = async (options) => {
|
|
|
777
797
|
try {
|
|
778
798
|
const wf = fileType === "yaml" ? yamlToJson(candidate) : JSON.parse(candidate);
|
|
779
799
|
if (wf.id && Array.isArray(wf.steps)) {
|
|
780
|
-
const wfState =
|
|
781
|
-
wf.openfn = {
|
|
782
|
-
uuid: wfState
|
|
783
|
-
|
|
784
|
-
};
|
|
800
|
+
const wfState = state?.getWorkflow(wf.id);
|
|
801
|
+
wf.openfn = Object.assign({}, wfState?.openfn, {
|
|
802
|
+
uuid: wfState?.openfn?.uuid ?? null
|
|
803
|
+
});
|
|
785
804
|
for (const step of wf.steps) {
|
|
805
|
+
const stateStep = wfState?.get(step.id);
|
|
786
806
|
if (step.expression && step.expression.endsWith(".js")) {
|
|
787
807
|
const dir = path2.dirname(filePath);
|
|
788
808
|
const exprPath = path2.join(dir, step.expression);
|
|
@@ -793,15 +813,14 @@ var parseProject = async (options) => {
|
|
|
793
813
|
console.error(`Error loading expression from ${exprPath}`);
|
|
794
814
|
}
|
|
795
815
|
}
|
|
796
|
-
|
|
797
|
-
step.openfn = { uuid };
|
|
816
|
+
step.openfn = Object.assign({}, stateStep?.openfn);
|
|
798
817
|
for (const target in step.next || {}) {
|
|
799
818
|
if (typeof step.next[target] === "boolean") {
|
|
800
819
|
const bool = step.next[target];
|
|
801
820
|
step.next[target] = { condition: bool };
|
|
802
821
|
}
|
|
803
|
-
const
|
|
804
|
-
step.next[target].openfn = { uuid
|
|
822
|
+
const uuid = state?.getUUID(wf.id, step.id, target) ?? null;
|
|
823
|
+
step.next[target].openfn = { uuid };
|
|
805
824
|
}
|
|
806
825
|
}
|
|
807
826
|
proj.workflows.push(wf);
|
|
@@ -1339,10 +1358,25 @@ var Project = class {
|
|
|
1339
1358
|
}
|
|
1340
1359
|
return result;
|
|
1341
1360
|
}
|
|
1361
|
+
canMergeInto(target) {
|
|
1362
|
+
const potentialConflicts = {};
|
|
1363
|
+
for (const sourceWorkflow of this.workflows) {
|
|
1364
|
+
const targetId = sourceWorkflow.id;
|
|
1365
|
+
const targetWorkflow = target.getWorkflow(targetId);
|
|
1366
|
+
if (targetWorkflow && !sourceWorkflow.canMergeInto(targetWorkflow)) {
|
|
1367
|
+
potentialConflicts[sourceWorkflow.id] = targetWorkflow?.id;
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
if (Object.keys(potentialConflicts).length) {
|
|
1371
|
+
return false;
|
|
1372
|
+
}
|
|
1373
|
+
return true;
|
|
1374
|
+
}
|
|
1342
1375
|
};
|
|
1343
1376
|
var Project_default = Project;
|
|
1344
1377
|
|
|
1345
1378
|
// src/Workspace.ts
|
|
1379
|
+
import createLogger from "@openfn/logger";
|
|
1346
1380
|
import path3 from "node:path";
|
|
1347
1381
|
import fs3 from "node:fs";
|
|
1348
1382
|
|
|
@@ -1369,20 +1403,23 @@ var Workspace = class {
|
|
|
1369
1403
|
projects = [];
|
|
1370
1404
|
projectPaths = /* @__PURE__ */ new Map();
|
|
1371
1405
|
isValid = false;
|
|
1372
|
-
|
|
1373
|
-
|
|
1406
|
+
logger;
|
|
1407
|
+
constructor(workspacePath, logger) {
|
|
1408
|
+
this.logger = logger ?? createLogger("Workspace", { level: "info" });
|
|
1409
|
+
let context = { workspace: void 0, project: void 0 };
|
|
1374
1410
|
try {
|
|
1375
1411
|
const { type, content } = findWorkspaceFile(workspacePath);
|
|
1376
1412
|
context = loadWorkspaceFile(content, type);
|
|
1377
1413
|
this.isValid = true;
|
|
1378
1414
|
} catch (e) {
|
|
1379
|
-
|
|
1380
|
-
|
|
1415
|
+
this.logger.warn(
|
|
1416
|
+
`Could not find openfn.yaml at ${workspacePath}. Using default values.`
|
|
1417
|
+
);
|
|
1381
1418
|
}
|
|
1382
1419
|
this.config = buildConfig(context.workspace);
|
|
1383
1420
|
this.activeProject = context.project;
|
|
1384
1421
|
const projectsPath = path3.join(workspacePath, this.config.dirs.projects);
|
|
1385
|
-
if (
|
|
1422
|
+
if (pathExists(projectsPath, "directory")) {
|
|
1386
1423
|
const ext = `.${this.config.formats.project}`;
|
|
1387
1424
|
const stateFiles = fs3.readdirSync(projectsPath).filter(
|
|
1388
1425
|
(fileName) => path3.extname(fileName) === ext && path3.parse(fileName).name !== "openfn"
|
|
@@ -1401,6 +1438,10 @@ var Workspace = class {
|
|
|
1401
1438
|
console.warn(e);
|
|
1402
1439
|
}
|
|
1403
1440
|
}).filter((s) => s);
|
|
1441
|
+
} else {
|
|
1442
|
+
this.logger.warn(
|
|
1443
|
+
`No projects found: directory at ${projectsPath} does not exist`
|
|
1444
|
+
);
|
|
1404
1445
|
}
|
|
1405
1446
|
}
|
|
1406
1447
|
// TODO
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openfn/project",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.2",
|
|
4
4
|
"description": "Read, serialize, replicate and sync OpenFn projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"lodash-es": "^4.17.21",
|
|
35
35
|
"ohm-js": "^17.2.1",
|
|
36
36
|
"yaml": "^2.2.2",
|
|
37
|
-
"@openfn/lexicon": "^1.
|
|
37
|
+
"@openfn/lexicon": "^1.3.0",
|
|
38
38
|
"@openfn/logger": "1.1.0"
|
|
39
39
|
},
|
|
40
40
|
"files": [
|