@knocklabs/cli 0.1.0-rc.4 → 0.1.3

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.
Files changed (34) hide show
  1. package/README.md +172 -77
  2. package/dist/commands/commit/index.js +6 -3
  3. package/dist/commands/commit/promote.js +5 -2
  4. package/dist/commands/knock.js +102 -0
  5. package/dist/commands/ping.js +2 -4
  6. package/dist/commands/translation/get.js +128 -0
  7. package/dist/commands/translation/list.js +57 -9
  8. package/dist/commands/translation/pull.js +72 -21
  9. package/dist/commands/translation/push.js +23 -12
  10. package/dist/commands/translation/validate.js +12 -8
  11. package/dist/commands/whoami.js +31 -0
  12. package/dist/commands/workflow/activate.js +19 -8
  13. package/dist/commands/workflow/get.js +14 -10
  14. package/dist/commands/workflow/list.js +7 -3
  15. package/dist/commands/workflow/new.js +4 -5
  16. package/dist/commands/workflow/pull.js +18 -10
  17. package/dist/commands/workflow/push.js +60 -47
  18. package/dist/commands/workflow/run.js +58 -0
  19. package/dist/commands/workflow/validate.js +52 -48
  20. package/dist/lib/api-v1.js +32 -5
  21. package/dist/lib/base-command.js +8 -4
  22. package/dist/lib/helpers/flag.js +12 -1
  23. package/dist/lib/helpers/page.js +7 -2
  24. package/dist/lib/helpers/request.js +1 -1
  25. package/dist/lib/helpers/ux.js +2 -2
  26. package/dist/lib/marshal/translation/helpers.js +21 -7
  27. package/dist/lib/marshal/translation/reader.js +17 -14
  28. package/dist/lib/marshal/translation/types.js +1 -0
  29. package/dist/lib/marshal/translation/writer.js +26 -16
  30. package/dist/lib/marshal/workflow/helpers.js +64 -2
  31. package/dist/lib/marshal/workflow/reader.js +62 -0
  32. package/dist/lib/run-context/helpers.js +2 -2
  33. package/oclif.manifest.json +281 -24
  34. package/package.json +25 -19
@@ -2,9 +2,9 @@
2
2
  Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
- Object.defineProperty(exports, "readTranslationFilesForCommandTarget", {
5
+ Object.defineProperty(exports, "readAllForCommandTarget", {
6
6
  enumerable: true,
7
- get: ()=>readTranslationFilesForCommandTarget
7
+ get: ()=>readAllForCommandTarget
8
8
  });
9
9
  const _nodePath = /*#__PURE__*/ _interopRequireWildcard(require("node:path"));
10
10
  const _core = require("@oclif/core");
@@ -56,6 +56,9 @@ function _interopRequireWildcard(obj, nodeInterop) {
56
56
  * translation file data.
57
57
  *
58
58
  * Note, it assumes they are valid file paths to translation files.
59
+ *
60
+ * TODO: Refactor to take translation file contexts instead of raw file paths,
61
+ * to keep things consistent with the workflow reader module.
59
62
  */ const readTranslationFiles = async (filePaths)=>{
60
63
  const translations = [];
61
64
  const errors = [];
@@ -69,27 +72,27 @@ function _interopRequireWildcard(obj, nodeInterop) {
69
72
  if (readJsonErrors.length > 0) {
70
73
  const e = new _error.SourceError((0, _error.formatErrors)(readJsonErrors), abspath);
71
74
  errors.push(e);
75
+ continue;
72
76
  }
73
- if (content) {
74
- translations.push({
75
- ref: translationRef,
76
- localeCode,
77
- namespace,
78
- abspath,
79
- exists: true,
80
- content: JSON.stringify(content)
81
- });
82
- }
77
+ translations.push({
78
+ ref: translationRef,
79
+ localeCode,
80
+ namespace,
81
+ abspath,
82
+ exists: true,
83
+ content: JSON.stringify(content)
84
+ });
83
85
  }
84
86
  return [
85
87
  translations,
86
88
  errors
87
89
  ];
88
90
  };
89
- const readTranslationFilesForCommandTarget = async (target)=>{
91
+ const readAllForCommandTarget = async (target)=>{
90
92
  const { type: targetType , context: targetCtx } = target;
91
93
  if (!targetCtx.exists) {
92
- return _core.CliUx.ux.error(`Cannot locate translation file(s) at \`${targetCtx.abspath}\``);
94
+ const subject = targetType === "translationFile" ? "a translation file at" : "translation files in";
95
+ return _core.ux.error(`Cannot locate ${subject} \`${targetCtx.abspath}\``);
93
96
  }
94
97
  switch(targetType){
95
98
  case "translationFile":
@@ -1,3 +1,4 @@
1
+ // Translation payload data from the API.
1
2
  "use strict";
2
3
  Object.defineProperty(exports, "__esModule", {
3
4
  value: true
@@ -2,9 +2,15 @@
2
2
  Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
- Object.defineProperty(exports, "writeTranslationsIndexDir", {
6
- enumerable: true,
7
- get: ()=>writeTranslationsIndexDir
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: all[name]
9
+ });
10
+ }
11
+ _export(exports, {
12
+ writeTranslationFile: ()=>writeTranslationFile,
13
+ writeTranslationFiles: ()=>writeTranslationFiles
8
14
  });
9
15
  const _nodePath = /*#__PURE__*/ _interopRequireWildcard(require("node:path"));
10
16
  const _fsExtra = /*#__PURE__*/ _interopRequireWildcard(require("fs-extra"));
@@ -51,32 +57,36 @@ function _interopRequireWildcard(obj, nodeInterop) {
51
57
  }
52
58
  return newObj;
53
59
  }
54
- const writeTranslationsIndexDir = async (indexDirCtx, translations)=>{
60
+ const writeTranslationFile = async (translationFileCtx, translation)=>_fsExtra.outputJson(translationFileCtx.abspath, JSON.parse(translation.content), {
61
+ spaces: _json.DOUBLE_SPACES
62
+ });
63
+ const writeTranslationFiles = async (targetDirCtx, translations)=>{
55
64
  const backupDirPath = _nodePath.resolve(_const.sandboxDir, (0, _lodash.uniqueId)("backup"));
56
65
  try {
57
66
  // If the index directory already exists, back it up in the temp sandbox
58
67
  // before wiping it clean.
59
- if (indexDirCtx.exists) {
60
- await _fsExtra.copy(indexDirCtx.abspath, backupDirPath);
61
- await _fsExtra.emptyDir(indexDirCtx.abspath);
68
+ if (targetDirCtx.exists) {
69
+ await _fsExtra.copy(targetDirCtx.abspath, backupDirPath);
70
+ await _fsExtra.emptyDir(targetDirCtx.abspath);
62
71
  }
63
72
  // Write given remote translations into the given translations directory path.
64
73
  const writeTranslationDirPromises = translations.map(async (translation)=>{
65
- const translationDirPath = _nodePath.resolve(indexDirCtx.abspath, translation.locale_code);
66
- const translationFileCtx = await (0, _helpers.buildTranslationFileCtx)(translationDirPath, translation.locale_code, translation.namespace);
67
- return _fsExtra.outputJson(translationFileCtx.abspath, JSON.parse(translation.content), {
68
- spaces: _json.DOUBLE_SPACES
69
- });
74
+ // If TranslationDirContext, then that is the locale directory we want
75
+ // to write translation files in; otherwise for translations index
76
+ // directory, we want to nest translation files under each locale dir.
77
+ const localeDirPath = "key" in targetDirCtx ? targetDirCtx.abspath : _nodePath.resolve(targetDirCtx.abspath, translation.locale_code);
78
+ const translationFileCtx = await (0, _helpers.buildTranslationFileCtx)(localeDirPath, translation.locale_code, translation.namespace);
79
+ return writeTranslationFile(translationFileCtx, translation);
70
80
  });
71
81
  await Promise.all(writeTranslationDirPromises);
72
82
  } catch (error) {
73
83
  // In case of any error, wipe the index directory that is likely in a bad
74
84
  // state then restore the backup if one existed before.
75
- if (indexDirCtx.exists) {
76
- await _fsExtra.emptyDir(indexDirCtx.abspath);
77
- await _fsExtra.copy(backupDirPath, indexDirCtx.abspath);
85
+ if (targetDirCtx.exists) {
86
+ await _fsExtra.emptyDir(targetDirCtx.abspath);
87
+ await _fsExtra.copy(backupDirPath, targetDirCtx.abspath);
78
88
  } else {
79
- await _fsExtra.remove(indexDirCtx.abspath);
89
+ await _fsExtra.remove(targetDirCtx.abspath);
80
90
  }
81
91
  throw error;
82
92
  } finally{
@@ -11,6 +11,7 @@ function _export(target, all) {
11
11
  _export(exports, {
12
12
  WORKFLOW_JSON: ()=>WORKFLOW_JSON,
13
13
  VISUAL_BLOCKS_JSON: ()=>VISUAL_BLOCKS_JSON,
14
+ workflowJsonPath: ()=>workflowJsonPath,
14
15
  FILEPATH_MARKER: ()=>FILEPATH_MARKER,
15
16
  FILEPATH_MARKED_RE: ()=>FILEPATH_MARKED_RE,
16
17
  validateWorkflowKey: ()=>validateWorkflowKey,
@@ -18,9 +19,11 @@ _export(exports, {
18
19
  isWorkflowDir: ()=>isWorkflowDir,
19
20
  formatCategories: ()=>formatCategories,
20
21
  formatStepSummary: ()=>formatStepSummary,
21
- formatStatus: ()=>formatStatus
22
+ formatStatus: ()=>formatStatus,
23
+ ensureValidCommandTarget: ()=>ensureValidCommandTarget
22
24
  });
23
25
  const _nodePath = /*#__PURE__*/ _interopRequireWildcard(require("node:path"));
26
+ const _core = require("@oclif/core");
24
27
  const _fsExtra = /*#__PURE__*/ _interopRequireWildcard(require("fs-extra"));
25
28
  const _lodash = require("lodash");
26
29
  const _string = require("../../helpers/string");
@@ -66,6 +69,7 @@ function _interopRequireWildcard(obj, nodeInterop) {
66
69
  }
67
70
  const WORKFLOW_JSON = "workflow.json";
68
71
  const VISUAL_BLOCKS_JSON = "visual_blocks.json";
72
+ const workflowJsonPath = (workflowDirCtx)=>_nodePath.resolve(workflowDirCtx.abspath, WORKFLOW_JSON);
69
73
  const FILEPATH_MARKER = "@";
70
74
  const FILEPATH_MARKED_RE = new RegExp(`${FILEPATH_MARKER}$`);
71
75
  const validateWorkflowKey = (input)=>{
@@ -77,7 +81,7 @@ const validateWorkflowKey = (input)=>{
77
81
  return undefined;
78
82
  };
79
83
  const lsWorkflowJson = async (dirPath)=>{
80
- const workflowJsonPath = _nodePath.join(dirPath, WORKFLOW_JSON);
84
+ const workflowJsonPath = _nodePath.resolve(dirPath, WORKFLOW_JSON);
81
85
  const exists = await _fsExtra.pathExists(workflowJsonPath);
82
86
  return exists ? workflowJsonPath : undefined;
83
87
  };
@@ -149,3 +153,61 @@ const formatStepSummary = (step)=>{
149
153
  const formatStatus = (workflow)=>{
150
154
  return workflow.active ? "active" : "inactive";
151
155
  };
156
+ const ensureValidCommandTarget = async (props, runContext)=>{
157
+ const { args , flags } = props;
158
+ const { commandId , resourceDir: resourceDirCtx , cwd: runCwd } = runContext;
159
+ // If the target resource is a different type than the current resource dir
160
+ // type, error out.
161
+ if (resourceDirCtx && resourceDirCtx.type !== "workflow") {
162
+ return _core.ux.error(`Cannot run ${commandId} inside a ${resourceDirCtx.type} directory`);
163
+ }
164
+ // Cannot accept both workflow key arg and --all flag.
165
+ if (flags.all && args.workflowKey) {
166
+ return _core.ux.error(`workflowKey arg \`${args.workflowKey}\` cannot also be provided when using --all`);
167
+ }
168
+ // --all flag is given, which means no workflow key arg.
169
+ if (flags.all) {
170
+ // If --all flag used inside a workflow directory, then require a workflows
171
+ // dir path.
172
+ if (resourceDirCtx && !flags["workflows-dir"]) {
173
+ return _core.ux.error("Missing required flag workflows-dir");
174
+ }
175
+ // Targeting all workflow dirs in the workflows index dir.
176
+ // TODO: Default to the knock project config first if present before cwd.
177
+ const defaultToCwd = {
178
+ abspath: runCwd,
179
+ exists: true
180
+ };
181
+ const indexDirCtx = flags["workflows-dir"] || defaultToCwd;
182
+ return {
183
+ type: "workflowsIndexDir",
184
+ context: indexDirCtx
185
+ };
186
+ }
187
+ // Workflow key arg is given, which means no --all flag.
188
+ if (args.workflowKey) {
189
+ if (resourceDirCtx && resourceDirCtx.key !== args.workflowKey) {
190
+ return _core.ux.error(`Cannot run ${commandId} \`${args.workflowKey}\` inside another workflow directory:\n${resourceDirCtx.key}`);
191
+ }
192
+ const targetDirPath = resourceDirCtx ? resourceDirCtx.abspath : _nodePath.resolve(runCwd, args.workflowKey);
193
+ const workflowDirCtx = {
194
+ type: "workflow",
195
+ key: args.workflowKey,
196
+ abspath: targetDirPath,
197
+ exists: await isWorkflowDir(targetDirPath)
198
+ };
199
+ return {
200
+ type: "workflowDir",
201
+ context: workflowDirCtx
202
+ };
203
+ }
204
+ // From this point on, we have neither a workflow key arg nor --all flag.
205
+ // If running inside a workflow directory, then use that workflow directory.
206
+ if (resourceDirCtx) {
207
+ return {
208
+ type: "workflowDir",
209
+ context: resourceDirCtx
210
+ };
211
+ }
212
+ return _core.ux.error("Missing 1 required arg:\nworkflowKey");
213
+ };
@@ -10,10 +10,12 @@ function _export(target, all) {
10
10
  }
11
11
  _export(exports, {
12
12
  readWorkflowDir: ()=>readWorkflowDir,
13
+ readAllForCommandTarget: ()=>readAllForCommandTarget,
13
14
  checkIfValidExtractedFilePathFormat: ()=>checkIfValidExtractedFilePathFormat,
14
15
  readExtractedFileSync: ()=>readExtractedFileSync
15
16
  });
16
17
  const _nodePath = /*#__PURE__*/ _interopRequireWildcard(require("node:path"));
18
+ const _core = require("@oclif/core");
17
19
  const _fsExtra = /*#__PURE__*/ _interopRequireWildcard(require("fs-extra"));
18
20
  const _lodash = require("lodash");
19
21
  const _error = require("../../helpers/error");
@@ -247,3 +249,63 @@ const readWorkflowDir = async (workflowDirCtx, opts = {})=>{
247
249
  []
248
250
  ];
249
251
  };
252
+ /*
253
+ * For the given list of workflow directory contexts, read each workflow dir and
254
+ * return workflow directory data.
255
+ */ const readWorkflowDirs = async (workflowDirCtxs, opts = {})=>{
256
+ const workflows = [];
257
+ const errors = [];
258
+ for (const workflowDirCtx of workflowDirCtxs){
259
+ // eslint-disable-next-line no-await-in-loop
260
+ const [workflow, readErrors] = await readWorkflowDir(workflowDirCtx, opts);
261
+ if (readErrors.length > 0) {
262
+ const workflowJsonPath = _nodePath.resolve(workflowDirCtx.abspath, _helpers.WORKFLOW_JSON);
263
+ const e = new _error.SourceError((0, _error.formatErrors)(readErrors), workflowJsonPath);
264
+ errors.push(e);
265
+ continue;
266
+ }
267
+ workflows.push({
268
+ ...workflowDirCtx,
269
+ content: workflow
270
+ });
271
+ }
272
+ return [
273
+ workflows,
274
+ errors
275
+ ];
276
+ };
277
+ const readAllForCommandTarget = async (target, opts = {})=>{
278
+ const { type: targetType , context: targetCtx } = target;
279
+ if (!targetCtx.exists) {
280
+ const subject = targetType === "workflowDir" ? "a workflow directory at" : "workflow directories in";
281
+ return _core.ux.error(`Cannot locate ${subject} \`${targetCtx.abspath}\``);
282
+ }
283
+ switch(targetType){
284
+ case "workflowDir":
285
+ {
286
+ return readWorkflowDirs([
287
+ targetCtx
288
+ ], opts);
289
+ }
290
+ case "workflowsIndexDir":
291
+ {
292
+ const dirents = await _fsExtra.readdir(targetCtx.abspath, {
293
+ withFileTypes: true
294
+ });
295
+ const promises = dirents.map(async (dirent)=>{
296
+ const abspath = _nodePath.resolve(targetCtx.abspath, dirent.name);
297
+ const workflowDirCtx = {
298
+ type: "workflow",
299
+ key: dirent.name,
300
+ abspath,
301
+ exists: await (0, _helpers.isWorkflowDir)(abspath)
302
+ };
303
+ return workflowDirCtx;
304
+ });
305
+ const workflowDirCtxs = (await Promise.all(promises)).filter((workflowDirCtx)=>workflowDirCtx.exists);
306
+ return readWorkflowDirs(workflowDirCtxs, opts);
307
+ }
308
+ default:
309
+ throw new Error(`Invalid workflow command target: ${target}`);
310
+ }
311
+ };
@@ -11,7 +11,7 @@ const ensureResourceDirForTarget = (resourceDirCtx, target)=>{
11
11
  // If the target resource is a different type than the current resource dir
12
12
  // type, error out.
13
13
  if (resourceDirCtx.type !== target.type) {
14
- return _core.CliUx.ux.error(`Cannot run ${target.commandId} inside a ${resourceDirCtx.type} directory`);
14
+ return _core.ux.error(`Cannot run ${target.commandId} inside a ${resourceDirCtx.type} directory`);
15
15
  }
16
16
  // If the resource key was not provided with the command, then infer from the
17
17
  // current resource directory context.
@@ -23,5 +23,5 @@ const ensureResourceDirForTarget = (resourceDirCtx, target)=>{
23
23
  if (target.key === resourceDirCtx.key) {
24
24
  return resourceDirCtx;
25
25
  }
26
- return _core.CliUx.ux.error(`Cannot run ${target.commandId} \`${target.key}\` inside another ${resourceDirCtx.type} directory:\n${resourceDirCtx.key}`);
26
+ return _core.ux.error(`Cannot run ${target.commandId} \`${target.key}\` inside another ${resourceDirCtx.type} directory:\n${resourceDirCtx.key}`);
27
27
  };