@openfn/project 0.7.0 → 0.7.1

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 CHANGED
@@ -37,16 +37,16 @@ declare class Workflow {
37
37
  canMergeInto(target: Workflow): boolean;
38
38
  }
39
39
 
40
- type FileFormats$1 = 'yaml' | 'json';
40
+ type FileFormats = 'yaml' | 'json';
41
41
  interface WorkspaceConfig {
42
42
  dirs: {
43
43
  workflows: string;
44
44
  projects: string;
45
45
  };
46
46
  formats: {
47
- openfn: FileFormats$1;
48
- project: FileFormats$1;
49
- workflow: FileFormats$1;
47
+ openfn: FileFormats;
48
+ project: FileFormats;
49
+ workflow: FileFormats;
50
50
  };
51
51
  }
52
52
 
@@ -66,13 +66,14 @@ type MergeProjectOptions = Partial<{
66
66
 
67
67
  declare class Workspace {
68
68
  config?: WorkspaceConfig;
69
- projectMeta: ProjectMeta;
69
+ activeProject: ProjectMeta;
70
70
  private projects;
71
71
  private projectPaths;
72
72
  private isValid;
73
73
  constructor(workspacePath: string);
74
74
  loadProject(): void;
75
75
  list(): Project[];
76
+ /** Get a project by its id or UUID */
76
77
  get(id: string): Project | undefined;
77
78
  getProjectPath(id: string): string | undefined;
78
79
  getActiveProject(): Project | undefined;
@@ -81,18 +82,11 @@ declare class Workspace {
81
82
  get valid(): boolean;
82
83
  }
83
84
 
84
- type RepoOptions = {
85
- /**default workflow root when serializing to fs (relative to openfn.yaml) */
86
- workflowRoot?: string;
87
- formats: {
88
- openfn: FileFormats;
89
- workflow: FileFormats;
90
- project: FileFormats;
91
- };
92
- };
93
85
  declare class Project {
94
- /** project name */
86
+ /** Human readable project name. This corresponds to the label in Lightning */
95
87
  name?: string;
88
+ /** Project id. Must be url safe. May be derived from the name. NOT a UUID */
89
+ id: string;
96
90
  description?: string;
97
91
  history: string[];
98
92
  workflows: Workflow[];
@@ -109,10 +103,9 @@ declare class Project {
109
103
  }): Project;
110
104
  static diff(a: Project, b: Project): void;
111
105
  static merge(source: Project, target: Project, options: MergeProjectOptions): Project;
112
- constructor(data: l.Project, repoConfig?: RepoOptions);
106
+ constructor(data: l.Project, config?: RepoOptions);
113
107
  setConfig(config: Partial<WorkspaceConfig>): void;
114
108
  serialize(type?: 'json' | 'yaml' | 'fs' | 'state', options?: any): any;
115
- getVersionHash(): void;
116
109
  getWorkflow(idOrName: string): Workflow | undefined;
117
110
  getIdentifier(): string;
118
111
  compare(proj: Project): void;
package/dist/index.js CHANGED
@@ -4,6 +4,9 @@ var __export = (target, all) => {
4
4
  __defProp(target, name, { get: all[name], enumerable: true });
5
5
  };
6
6
 
7
+ // src/Project.ts
8
+ import { humanId } from "human-id";
9
+
7
10
  // src/util/slugify.ts
8
11
  function slugify(text) {
9
12
  return text?.replace(/\W/g, " ").trim().replace(/\s+/g, "-").toLowerCase();
@@ -384,7 +387,8 @@ var buildConfig = (config = {}) => ({
384
387
  });
385
388
  var extractConfig = (source) => {
386
389
  const project = {
387
- ...source.openfn || {}
390
+ ...source.openfn || {},
391
+ id: source.id
388
392
  };
389
393
  const workspace = {
390
394
  ...source.config
@@ -438,13 +442,10 @@ var loadWorkspaceFile = (contents, format = "yaml") => {
438
442
  return { project, workspace };
439
443
  };
440
444
  var findWorkspaceFile = (dir = ".") => {
441
- console.log({ dir });
442
445
  let content, type;
443
446
  try {
444
447
  type = "yaml";
445
- console.log(path.resolve(path.join(dir, "openfn.yaml")));
446
448
  content = readFileSync(path.resolve(path.join(dir, "openfn.yaml")), "utf8");
447
- console.log({ content });
448
449
  } catch (e) {
449
450
  try {
450
451
  type = "json";
@@ -710,6 +711,7 @@ var parseProject = async (options = {}) => {
710
711
  console.warn(`Failed to find state file for ${identifier}`);
711
712
  }
712
713
  const proj = {
714
+ name: state?.name,
713
715
  openfn: context.project,
714
716
  config,
715
717
  workflows: []
@@ -729,7 +731,7 @@ var parseProject = async (options = {}) => {
729
731
  const wfState = (state && state.getWorkflow(wf.id)) ?? {};
730
732
  wf.openfn = {
731
733
  uuid: wfState.openfn?.uuid ?? null
732
- // TODO do we need to transfer more stuff?
734
+ // TODO do we need to transfer more stuff? Options maybe?
733
735
  };
734
736
  for (const step of wf.steps) {
735
737
  if (step.expression && step.expression.endsWith(".js")) {
@@ -1175,10 +1177,12 @@ var Project = class {
1175
1177
  // what schema version is this?
1176
1178
  // And how are we tracking this?
1177
1179
  // version;
1178
- /** project name */
1180
+ /** Human readable project name. This corresponds to the label in Lightning */
1179
1181
  name;
1182
+ /** Project id. Must be url safe. May be derived from the name. NOT a UUID */
1183
+ id;
1180
1184
  description;
1181
- // array of version shas
1185
+ // array of version hashes
1182
1186
  history = [];
1183
1187
  workflows;
1184
1188
  // option strings saved by the app
@@ -1191,11 +1195,6 @@ var Project = class {
1191
1195
  openfn;
1192
1196
  workspace;
1193
1197
  config;
1194
- // load a project from a state file (project.json)
1195
- // or from a path (the file system)
1196
- // TODO presumably we can detect a state file? Not a big deal?
1197
- // collections for the project
1198
- // TODO to be well typed
1199
1198
  collections;
1200
1199
  static from(type, data, options = {}) {
1201
1200
  if (type === "state") {
@@ -1221,8 +1220,9 @@ var Project = class {
1221
1220
  // maybe this second arg is config - like env, branch rules, serialisation rules
1222
1221
  // stuff that's external to the actual project and managed by the repo
1223
1222
  // TODO maybe the constructor is (data, Workspace)
1224
- constructor(data, repoConfig = {}) {
1225
- this.setConfig(repoConfig);
1223
+ constructor(data, config = {}) {
1224
+ this.setConfig(config);
1225
+ this.id = data.id ?? data.name ? slugify(data.name) : humanId({ separator: "-", capitalize: false });
1226
1226
  this.name = data.name;
1227
1227
  this.description = data.description;
1228
1228
  this.openfn = data.openfn;
@@ -1241,16 +1241,9 @@ var Project = class {
1241
1241
  }
1242
1242
  throw new Error(`Cannot serialize ${type}`);
1243
1243
  }
1244
- // would like a better name for this
1245
- // stamp? id? sha?
1246
- // this builds a version string for the current state
1247
- getVersionHash() {
1248
- }
1249
- // what else might we need?
1250
- // get workflow by name or id
1251
- // this is fuzzy, but is that wrong?
1244
+ // get workflow by name, id or uuid
1252
1245
  getWorkflow(idOrName) {
1253
- return this.workflows.find((wf) => wf.id == idOrName) || this.workflows.find((wf) => wf.name === idOrName);
1246
+ return this.workflows.find((wf) => wf.id == idOrName) || this.workflows.find((wf) => wf.name === idOrName) || this.workflows.find((wf) => wf.openfn?.uuid === idOrName);
1254
1247
  }
1255
1248
  // it's the name of the project.yaml file
1256
1249
  // qualified name? Remote name? App name?
@@ -1308,7 +1301,7 @@ function pathExists(fpath, type) {
1308
1301
  var PROJECT_EXTENSIONS = [".yaml", ".yml"];
1309
1302
  var Workspace = class {
1310
1303
  config;
1311
- projectMeta;
1304
+ activeProject;
1312
1305
  projects = [];
1313
1306
  projectPaths = /* @__PURE__ */ new Map();
1314
1307
  isValid = false;
@@ -1316,7 +1309,6 @@ var Workspace = class {
1316
1309
  let context;
1317
1310
  try {
1318
1311
  const { type, content } = findWorkspaceFile(workspacePath);
1319
- console.log(content);
1320
1312
  context = loadWorkspaceFile(content, type);
1321
1313
  this.isValid = true;
1322
1314
  } catch (e) {
@@ -1324,7 +1316,7 @@ var Workspace = class {
1324
1316
  return;
1325
1317
  }
1326
1318
  this.config = buildConfig(context.workspace);
1327
- this.projectMeta = context.project;
1319
+ this.activeProject = context.project;
1328
1320
  const projectsPath = path3.join(workspacePath, this.config.dirs.projects);
1329
1321
  if (this.isValid && pathExists(projectsPath, "directory")) {
1330
1322
  const stateFiles = fs3.readdirSync(projectsPath).filter(
@@ -1334,7 +1326,7 @@ var Workspace = class {
1334
1326
  const stateFilePath = path3.join(projectsPath, file);
1335
1327
  const data = fs3.readFileSync(stateFilePath, "utf-8");
1336
1328
  const project = from_app_state_default(data, { format: "yaml" });
1337
- this.projectPaths.set(project.name, stateFilePath);
1329
+ this.projectPaths.set(project.id, stateFilePath);
1338
1330
  return project;
1339
1331
  }).filter((s) => s);
1340
1332
  }
@@ -1349,15 +1341,15 @@ var Workspace = class {
1349
1341
  list() {
1350
1342
  return this.projects;
1351
1343
  }
1352
- // TODO clear up name/id confusion
1344
+ /** Get a project by its id or UUID */
1353
1345
  get(id) {
1354
- return this.projects.find((p) => p.name === id);
1346
+ return this.projects.find((p) => p.id === id) ?? this.projects.find((p) => p.openfn?.uuid === id);
1355
1347
  }
1356
1348
  getProjectPath(id) {
1357
1349
  return this.projectPaths.get(id);
1358
1350
  }
1359
1351
  getActiveProject() {
1360
- return this.projects.find((p) => p.name === this.projectMeta?.name);
1352
+ return this.projects.find((p) => p.id === this.activeProject?.id) ?? this.projects.find((p) => p.openfn?.uuid === this.activeProject?.id);
1361
1353
  }
1362
1354
  // TODO this needs to return default values
1363
1355
  // We should always rely on the workspace to load these values
@@ -1365,7 +1357,7 @@ var Workspace = class {
1365
1357
  return this.config;
1366
1358
  }
1367
1359
  get activeProjectId() {
1368
- return this.projectMeta?.name;
1360
+ return this.activeProject?.id;
1369
1361
  }
1370
1362
  get valid() {
1371
1363
  return this.isValid;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openfn/project",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "Read, serialize, replicate and sync OpenFn projects",
5
5
  "type": "module",
6
6
  "exports": {
@@ -28,6 +28,7 @@
28
28
  },
29
29
  "dependencies": {
30
30
  "glob": "^11.0.2",
31
+ "human-id": "^4.1.1",
31
32
  "lodash": "^4.17.21",
32
33
  "lodash-es": "^4.17.21",
33
34
  "ohm-js": "^17.2.1",