@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
@@ -78,7 +78,7 @@ class WorkflowPull extends _baseCommand.default {
78
78
  if (dirContext.exists) {
79
79
  this.log(`‣ Found \`${dirContext.key}\` at ${dirContext.abspath}`);
80
80
  } else {
81
- const prompt = `Create a new workflow directory \`${dirContext.key}\`?`;
81
+ const prompt = `Create a new workflow directory \`${dirContext.key}\` at ${dirContext.abspath}?`;
82
82
  const input = flags.force || await (0, _ux.promptToConfirm)(prompt);
83
83
  if (!input) return;
84
84
  }
@@ -171,22 +171,30 @@ class WorkflowPull extends _baseCommand.default {
171
171
  }, workflows) : workflows;
172
172
  }
173
173
  }
174
+ WorkflowPull.summary = "Pull one or more workflows from an environment into a local file system.";
174
175
  WorkflowPull.flags = {
175
176
  environment: _core.Flags.string({
176
- default: "development"
177
+ default: "development",
178
+ summary: "The environment to use."
179
+ }),
180
+ all: _core.Flags.boolean({
181
+ summary: "Whether to pull all workflows from the specified environment."
177
182
  }),
178
- all: _core.Flags.boolean(),
179
183
  "workflows-dir": _flag.dirPath({
184
+ summary: "The target directory path to pull all workflows into.",
180
185
  dependsOn: [
181
186
  "all"
182
187
  ]
183
188
  }),
184
- "hide-uncommitted-changes": _core.Flags.boolean(),
185
- force: _core.Flags.boolean()
189
+ "hide-uncommitted-changes": _core.Flags.boolean({
190
+ summary: "Hide any uncommitted changes."
191
+ }),
192
+ force: _core.Flags.boolean({
193
+ summary: "Remove the confirmation prompt."
194
+ })
186
195
  };
187
- WorkflowPull.args = [
188
- {
189
- name: "workflowKey",
196
+ WorkflowPull.args = {
197
+ workflowKey: _core.Args.string({
190
198
  required: false
191
- }
192
- ];
199
+ })
200
+ };
@@ -6,15 +6,17 @@ Object.defineProperty(exports, "default", {
6
6
  enumerable: true,
7
7
  get: ()=>WorkflowPush
8
8
  });
9
- const _nodePath = /*#__PURE__*/ _interopRequireWildcard(require("node:path"));
10
9
  const _core = require("@oclif/core");
11
10
  const _baseCommand = /*#__PURE__*/ _interopRequireDefault(require("../../lib/base-command"));
12
11
  const _const = require("../../lib/helpers/const");
13
12
  const _error = require("../../lib/helpers/error");
13
+ const _flag = /*#__PURE__*/ _interopRequireWildcard(require("../../lib/helpers/flag"));
14
14
  const _object = require("../../lib/helpers/object");
15
15
  const _request = require("../../lib/helpers/request");
16
+ const _string = require("../../lib/helpers/string");
17
+ const _ux = require("../../lib/helpers/ux");
16
18
  const _workflow = /*#__PURE__*/ _interopRequireWildcard(require("../../lib/marshal/workflow"));
17
- const _runContext = require("../../lib/run-context");
19
+ const _validate = /*#__PURE__*/ _interopRequireDefault(require("./validate"));
18
20
  function _interopRequireDefault(obj) {
19
21
  return obj && obj.__esModule ? obj : {
20
22
  default: obj
@@ -61,57 +63,60 @@ function _interopRequireWildcard(obj, nodeInterop) {
61
63
  }
62
64
  class WorkflowPush extends _baseCommand.default {
63
65
  async run() {
64
- // 1. Retrieve the target workflow directory context.
65
- const dirContext = await this.getWorkflowDirContext();
66
- this.log(`‣ Reading \`${dirContext.key}\` at ${dirContext.abspath}`);
67
- // 2. Read the workflow.json with its template files.
68
- const [workflow, errors] = await _workflow.readWorkflowDir(dirContext, {
66
+ const { flags } = this.props;
67
+ // 1. First read all workflow directories found for the given command.
68
+ const target = await _workflow.ensureValidCommandTarget(this.props, this.runContext);
69
+ const [workflows, readErrors] = await _workflow.readAllForCommandTarget(target, {
69
70
  withExtractedFiles: true
70
71
  });
71
- if (errors.length > 0) {
72
- this.error(`Found the following errors in \`${dirContext.key}\` ${_workflow.WORKFLOW_JSON}\n\n` + (0, _error.formatErrors)(errors));
72
+ if (readErrors.length > 0) {
73
+ this.error((0, _error.formatErrors)(readErrors, {
74
+ prependBy: "\n\n"
75
+ }));
73
76
  }
74
- // 3. Push up the compiled workflow data.
75
- const resp = await (0, _request.withSpinner)(()=>{
77
+ if (workflows.length === 0) {
78
+ this.error(`No workflow directories found in ${target.context.abspath}`);
79
+ }
80
+ // 2. Then validate them all ahead of pushing them.
81
+ _ux.spinner.start(`‣ Validating`);
82
+ const apiErrors = await _validate.default.validateAll(this.apiV1, this.props, workflows);
83
+ if (apiErrors.length > 0) {
84
+ this.error((0, _error.formatErrors)(apiErrors, {
85
+ prependBy: "\n\n"
86
+ }));
87
+ }
88
+ _ux.spinner.stop();
89
+ // 3. Finally push up each workflow, abort on the first error.
90
+ _ux.spinner.start(`‣ Pushing`);
91
+ for (const workflow of workflows){
76
92
  const props = (0, _object.merge)(this.props, {
77
- args: {
78
- workflowKey: dirContext.key
79
- },
80
93
  flags: {
81
94
  annotate: true
82
95
  }
83
96
  });
84
- return this.apiV1.upsertWorkflow(props, workflow);
85
- });
86
- // 4. Update the workflow directory with the successfully pushed workflow
87
- // payload from the server.
88
- await _workflow.writeWorkflowDirFromData(dirContext, resp.data.workflow);
89
- this.log(`‣ Successfully pushed \`${dirContext.key}\`, and updated ${dirContext.abspath}`);
90
- }
91
- async getWorkflowDirContext() {
92
- const { workflowKey } = this.props.args;
93
- const { resourceDir , cwd: runCwd } = this.runContext;
94
- if (resourceDir) {
95
- const target = {
96
- commandId: _baseCommand.default.id,
97
- type: "workflow",
98
- key: workflowKey
99
- };
100
- return (0, _runContext.ensureResourceDirForTarget)(resourceDir, target);
101
- }
102
- if (workflowKey) {
103
- const dirPath = _nodePath.resolve(runCwd, workflowKey);
104
- const exists = await _workflow.isWorkflowDir(dirPath);
105
- return exists ? {
106
- type: "workflow",
107
- key: workflowKey,
108
- abspath: dirPath,
109
- exists
110
- } : this.error(`Cannot locate a workflow directory for \`${workflowKey}\``);
97
+ // eslint-disable-next-line no-await-in-loop
98
+ const resp = await this.apiV1.upsertWorkflow(props, {
99
+ ...workflow.content,
100
+ key: workflow.key
101
+ });
102
+ if ((0, _request.isSuccessResp)(resp)) {
103
+ // Update the workflow directory with the successfully pushed workflow
104
+ // payload from the server.
105
+ // eslint-disable-next-line no-await-in-loop
106
+ await _workflow.writeWorkflowDirFromData(workflow, resp.data.workflow);
107
+ continue;
108
+ }
109
+ const error = new _error.SourceError((0, _request.formatErrorRespMessage)(resp), _workflow.workflowJsonPath(workflow), "ApiError");
110
+ this.error((0, _error.formatError)(error));
111
111
  }
112
- return this.error("Missing 1 required arg:\nworkflowKey");
112
+ _ux.spinner.stop();
113
+ // 4. Display a success message.
114
+ const workflowKeys = workflows.map((w)=>w.key);
115
+ const actioned = flags.commit ? "pushed and committed" : "pushed";
116
+ this.log(`‣ Successfully ${actioned} ${workflows.length} workflow(s):\n` + (0, _string.indentString)(workflowKeys.join("\n"), 4));
113
117
  }
114
118
  }
119
+ WorkflowPush.summary = "Push one or more workflows from a local file system to Knock.";
115
120
  WorkflowPush.flags = {
116
121
  environment: _core.Flags.string({
117
122
  summary: "Pushing a workflow is only allowed in the development environment",
@@ -120,6 +125,15 @@ WorkflowPush.flags = {
120
125
  _const.KnockEnv.Development
121
126
  ]
122
127
  }),
128
+ all: _core.Flags.boolean({
129
+ summary: "Whether to push all workflows from the target directory."
130
+ }),
131
+ "workflows-dir": _flag.dirPath({
132
+ summary: "The target directory path to find all workflows to push.",
133
+ dependsOn: [
134
+ "all"
135
+ ]
136
+ }),
123
137
  commit: _core.Flags.boolean({
124
138
  summary: "Push and commit the workflow(s) at the same time"
125
139
  }),
@@ -131,9 +145,8 @@ WorkflowPush.flags = {
131
145
  ]
132
146
  })
133
147
  };
134
- WorkflowPush.args = [
135
- {
136
- name: "workflowKey",
148
+ WorkflowPush.args = {
149
+ workflowKey: _core.Args.string({
137
150
  required: false
138
- }
139
- ];
151
+ })
152
+ };
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "default", {
6
+ enumerable: true,
7
+ get: ()=>WorkflowRun
8
+ });
9
+ const _core = require("@oclif/core");
10
+ const _baseCommand = /*#__PURE__*/ _interopRequireDefault(require("../../lib/base-command"));
11
+ const _flag = require("../../lib/helpers/flag");
12
+ const _request = require("../../lib/helpers/request");
13
+ const _string = require("../../lib/helpers/string");
14
+ function _interopRequireDefault(obj) {
15
+ return obj && obj.__esModule ? obj : {
16
+ default: obj
17
+ };
18
+ }
19
+ class WorkflowRun extends _baseCommand.default {
20
+ async run() {
21
+ const { args , flags } = this.props;
22
+ const resp = await (0, _request.withSpinner)(()=>this.apiV1.runWorkflow(this.props), {
23
+ action: "‣ Running"
24
+ });
25
+ this.log(`‣ Successfully ran \`${args.workflowKey}\` workflow in \`${flags.environment}\` environment`);
26
+ this.log((0, _string.indentString)(`Workflow run id: ${resp.data.workflow_run_id}`), 4);
27
+ }
28
+ }
29
+ WorkflowRun.summary = "Test run a workflow using the latest version from Knock, or a local workflow directory.";
30
+ WorkflowRun.flags = {
31
+ environment: _core.Flags.string({
32
+ default: "development",
33
+ summary: "The environment in which to run the workflow"
34
+ }),
35
+ recipients: _core.Flags.string({
36
+ required: true,
37
+ aliases: [
38
+ "recipient"
39
+ ],
40
+ summary: "One or more recipient ids for this workflow run, separated by comma.",
41
+ multiple: true,
42
+ delimiter: ","
43
+ }),
44
+ actor: _core.Flags.string({
45
+ summary: "An actor id for the workflow run."
46
+ }),
47
+ tenant: _core.Flags.string({
48
+ summary: "A tenant id for the workflow run."
49
+ }),
50
+ data: (0, _flag.jsonStr)({
51
+ summary: "A JSON string of the data for this workflow"
52
+ })
53
+ };
54
+ WorkflowRun.args = {
55
+ workflowKey: _core.Args.string({
56
+ required: true
57
+ })
58
+ };
@@ -6,15 +6,15 @@ Object.defineProperty(exports, "default", {
6
6
  enumerable: true,
7
7
  get: ()=>WorkflowValidate
8
8
  });
9
- const _nodePath = /*#__PURE__*/ _interopRequireWildcard(require("node:path"));
10
9
  const _core = require("@oclif/core");
11
10
  const _baseCommand = /*#__PURE__*/ _interopRequireDefault(require("../../lib/base-command"));
12
11
  const _const = require("../../lib/helpers/const");
13
12
  const _error = require("../../lib/helpers/error");
14
- const _object = require("../../lib/helpers/object");
13
+ const _flag = /*#__PURE__*/ _interopRequireWildcard(require("../../lib/helpers/flag"));
15
14
  const _request = require("../../lib/helpers/request");
15
+ const _string = require("../../lib/helpers/string");
16
+ const _ux = require("../../lib/helpers/ux");
16
17
  const _workflow = /*#__PURE__*/ _interopRequireWildcard(require("../../lib/marshal/workflow"));
17
- const _runContext = require("../../lib/run-context");
18
18
  function _interopRequireDefault(obj) {
19
19
  return obj && obj.__esModule ? obj : {
20
20
  default: obj
@@ -61,53 +61,49 @@ function _interopRequireWildcard(obj, nodeInterop) {
61
61
  }
62
62
  class WorkflowValidate extends _baseCommand.default {
63
63
  async run() {
64
- // 1. Retrieve the target workflow directory context.
65
- const dirContext = await this.getWorkflowDirContext();
66
- this.log(`‣ Reading \`${dirContext.key}\` at ${dirContext.abspath}`);
67
- // 2. Read the workflow.json with its template files.
68
- const [workflow, errors] = await _workflow.readWorkflowDir(dirContext, {
64
+ // 1. Read all workflow directories found for the given command.
65
+ const target = await _workflow.ensureValidCommandTarget(this.props, this.runContext);
66
+ const [workflows, readErrors] = await _workflow.readAllForCommandTarget(target, {
69
67
  withExtractedFiles: true
70
68
  });
71
- if (errors.length > 0) {
72
- this.error(`Found the following errors in \`${dirContext.key}\` ${_workflow.WORKFLOW_JSON}\n\n` + (0, _error.formatErrors)(errors));
69
+ if (readErrors.length > 0) {
70
+ this.error((0, _error.formatErrors)(readErrors, {
71
+ prependBy: "\n\n"
72
+ }));
73
73
  }
74
- // 3. Validate the compiled workflow data.
75
- await (0, _request.withSpinner)(()=>{
76
- const props = (0, _object.merge)(this.props, {
77
- args: {
78
- workflowKey: dirContext.key
79
- }
80
- });
81
- return this.apiV1.validateWorkflow(props, workflow);
82
- }, {
83
- action: "‣ Validating"
84
- });
85
- this.log(`‣ Successfully validated \`${dirContext.key}\``);
86
- }
87
- async getWorkflowDirContext() {
88
- const { workflowKey } = this.props.args;
89
- const { resourceDir , cwd: runCwd } = this.runContext;
90
- if (resourceDir) {
91
- const target = {
92
- commandId: _baseCommand.default.id,
93
- type: "workflow",
94
- key: workflowKey
95
- };
96
- return (0, _runContext.ensureResourceDirForTarget)(resourceDir, target);
74
+ if (workflows.length === 0) {
75
+ this.error(`No workflow directories found in ${target.context.abspath}`);
97
76
  }
98
- if (workflowKey) {
99
- const dirPath = _nodePath.resolve(runCwd, workflowKey);
100
- const exists = await _workflow.isWorkflowDir(dirPath);
101
- return exists ? {
102
- type: "workflow",
103
- key: workflowKey,
104
- abspath: dirPath,
105
- exists
106
- } : this.error(`Cannot locate a workflow directory for \`${workflowKey}\``);
77
+ // 2. Validate each workflow data.
78
+ _ux.spinner.start(`‣ Validating`);
79
+ const apiErrors = await WorkflowValidate.validateAll(this.apiV1, this.props, workflows);
80
+ if (apiErrors.length > 0) {
81
+ this.error((0, _error.formatErrors)(apiErrors, {
82
+ prependBy: "\n\n"
83
+ }));
107
84
  }
108
- return this.error("Missing 1 required arg:\nworkflowKey");
85
+ _ux.spinner.stop();
86
+ // 3. Display a success message.
87
+ const workflowKeys = workflows.map((w)=>w.key);
88
+ this.log(`‣ Successfully validated ${workflows.length} workflow(s):\n` + (0, _string.indentString)(workflowKeys.join("\n"), 4));
89
+ }
90
+ static async validateAll(api, props, workflows) {
91
+ // TODO: Throw an error if a non validation error (e.g. authentication error)
92
+ // instead of printing out same error messages repeatedly.
93
+ const errorPromises = workflows.map(async (workflow)=>{
94
+ const resp = await api.validateWorkflow(props, {
95
+ ...workflow.content,
96
+ key: workflow.key
97
+ });
98
+ if ((0, _request.isSuccessResp)(resp)) return;
99
+ const error = new _error.SourceError((0, _request.formatErrorRespMessage)(resp), _workflow.workflowJsonPath(workflow), "ApiError");
100
+ return error;
101
+ });
102
+ const errors = (await Promise.all(errorPromises)).filter((e)=>Boolean(e));
103
+ return errors;
109
104
  }
110
105
  }
106
+ WorkflowValidate.summary = "Validate one or more workflows from a local file system.";
111
107
  WorkflowValidate.flags = {
112
108
  environment: _core.Flags.string({
113
109
  summary: "Validating a workflow is only done in the development environment",
@@ -115,11 +111,19 @@ WorkflowValidate.flags = {
115
111
  options: [
116
112
  _const.KnockEnv.Development
117
113
  ]
114
+ }),
115
+ all: _core.Flags.boolean({
116
+ summary: "Whether to validate all workflows from the target directory."
117
+ }),
118
+ "workflows-dir": _flag.dirPath({
119
+ summary: "The target directory path to find all workflows to validate.",
120
+ dependsOn: [
121
+ "all"
122
+ ]
118
123
  })
119
124
  };
120
- WorkflowValidate.args = [
121
- {
122
- name: "workflowKey",
125
+ WorkflowValidate.args = {
126
+ workflowKey: _core.Args.string({
123
127
  required: false
124
- }
125
- ];
128
+ })
129
+ };
@@ -20,6 +20,9 @@ class ApiV1 {
20
20
  async ping() {
21
21
  return this.get("/ping");
22
22
  }
23
+ async whoami() {
24
+ return this.get("/whoami");
25
+ }
23
26
  // By resources: Workflows
24
27
  async listWorkflows({ flags }) {
25
28
  const params = (0, _object.prune)({
@@ -42,7 +45,7 @@ class ApiV1 {
42
45
  params
43
46
  });
44
47
  }
45
- async upsertWorkflow({ args , flags }, workflow) {
48
+ async upsertWorkflow({ flags }, workflow) {
46
49
  const params = (0, _object.prune)({
47
50
  environment: flags.environment,
48
51
  annotate: flags.annotate,
@@ -52,18 +55,18 @@ class ApiV1 {
52
55
  const data = {
53
56
  workflow
54
57
  };
55
- return this.put(`/workflows/${args.workflowKey}`, data, {
58
+ return this.put(`/workflows/${workflow.key}`, data, {
56
59
  params
57
60
  });
58
61
  }
59
- async validateWorkflow({ args , flags }, workflow) {
62
+ async validateWorkflow({ flags }, workflow) {
60
63
  const params = (0, _object.prune)({
61
64
  environment: flags.environment
62
65
  });
63
66
  const data = {
64
67
  workflow
65
68
  };
66
- return this.put(`/workflows/${args.workflowKey}/validate`, data, {
69
+ return this.put(`/workflows/${workflow.key}/validate`, data, {
67
70
  params
68
71
  });
69
72
  }
@@ -76,6 +79,18 @@ class ApiV1 {
76
79
  params
77
80
  });
78
81
  }
82
+ async runWorkflow({ args , flags }) {
83
+ const params = (0, _object.prune)({
84
+ environment: flags.environment,
85
+ recipients: flags.recipients,
86
+ tenant: flags.tenant,
87
+ data: flags.data,
88
+ actor: flags.actor
89
+ });
90
+ return this.put(`/workflows/${args.workflowKey}/run`, {}, {
91
+ params
92
+ });
93
+ }
79
94
  // By resources: Commits
80
95
  async commitAllChanges({ flags }) {
81
96
  const params = (0, _object.prune)({
@@ -95,16 +110,28 @@ class ApiV1 {
95
110
  });
96
111
  }
97
112
  // By resources: Translations
98
- async listTranslations({ flags }) {
113
+ async listTranslations({ flags }, filters = {}) {
99
114
  const params = (0, _object.prune)({
100
115
  environment: flags.environment,
101
116
  hide_uncommitted_changes: flags["hide-uncommitted-changes"],
117
+ locale_code: filters.localeCode,
118
+ namespace: filters.namespace,
102
119
  ...(0, _page.toPageParams)(flags)
103
120
  });
104
121
  return this.get("/translations", {
105
122
  params
106
123
  });
107
124
  }
125
+ async getTranslation({ flags }, translation) {
126
+ const params = (0, _object.prune)({
127
+ environment: flags.environment,
128
+ hide_uncommitted_changes: flags["hide-uncommitted-changes"],
129
+ namespace: translation.namespace
130
+ });
131
+ return this.get(`/translations/${translation.localeCode}`, {
132
+ params
133
+ });
134
+ }
108
135
  async upsertTranslation({ flags }, translation) {
109
136
  const params = (0, _object.prune)({
110
137
  environment: flags.environment,
@@ -60,21 +60,25 @@ class BaseCommand extends _core.Command {
60
60
  // 1. Load user's config from the config dir, as available.
61
61
  await _userConfig.default.load(this.config.configDir);
62
62
  // 2. Parse flags and args, must come after the user config load.
63
- this.props = await this.parse(this.constructor);
63
+ const { args , flags } = await this.parse(this.ctor);
64
+ this.props = {
65
+ args: args,
66
+ flags: flags
67
+ };
64
68
  // 3. Instantiate a knock api client.
65
69
  this.apiV1 = new _apiV1.default(this.props.flags, this.config);
66
70
  // 4. Load the run context of the invoked command.
67
71
  this.runContext = await _runContext.load(this.id);
68
72
  }
69
73
  }
70
- // Global flags are inherited by any command that extends BaseCommand.
71
- BaseCommand.globalFlags = {
74
+ // Base flags are inherited by any command that extends BaseCommand.
75
+ BaseCommand.baseFlags = {
72
76
  // Evaluated in the following precedence:
73
77
  // - service token flag passed into the command
74
78
  // - if not provided, fall back to env variable
75
79
  // - if not available, fall back to user config
76
80
  "service-token": _core.Flags.string({
77
- summary: "The service token to authenticate with",
81
+ summary: "The service token to authenticate with.",
78
82
  required: true,
79
83
  multiple: false,
80
84
  env: "KNOCK_SERVICE_TOKEN",
@@ -10,7 +10,8 @@ function _export(target, all) {
10
10
  }
11
11
  _export(exports, {
12
12
  booleanStr: ()=>booleanStr,
13
- dirPath: ()=>dirPath
13
+ dirPath: ()=>dirPath,
14
+ jsonStr: ()=>jsonStr
14
15
  });
15
16
  const _nodePath = /*#__PURE__*/ _interopRequireWildcard(require("node:path"));
16
17
  const _core = require("@oclif/core");
@@ -74,3 +75,13 @@ const dirPath = _core.Flags.custom({
74
75
  };
75
76
  }
76
77
  });
78
+ const jsonStr = _core.Flags.custom({
79
+ parse: async (input)=>{
80
+ try {
81
+ const data = JSON.parse(input);
82
+ return data;
83
+ } catch {
84
+ throw new Error(`${input} is not a valid JSON string.`);
85
+ }
86
+ }
87
+ });
@@ -28,9 +28,14 @@ function _interopRequireDefault(obj) {
28
28
  }
29
29
  const MAX_PAGINATION_LIMIT = 100;
30
30
  const pageFlags = {
31
- after: _core.Flags.string(),
32
- before: _core.Flags.string(),
31
+ after: _core.Flags.string({
32
+ summary: "The cursor after which to fetch the next page."
33
+ }),
34
+ before: _core.Flags.string({
35
+ summary: "The cursor before which to fetch the previous page."
36
+ }),
33
37
  limit: _core.Flags.integer({
38
+ summary: "The total number of entries to fetch per page.",
34
39
  max: MAX_PAGINATION_LIMIT
35
40
  })
36
41
  };
@@ -38,7 +38,7 @@ const withSpinner = async (requestFn, opts = {})=>{
38
38
  // Error out before the action stop so the spinner can update accordingly.
39
39
  if (ensureSuccess && !isSuccessResp(resp)) {
40
40
  const message = formatErrorRespMessage(resp);
41
- _core.CliUx.ux.error(new _error.ApiError(message));
41
+ _core.ux.error(new _error.ApiError(message));
42
42
  }
43
43
  _ux.spinner.stop();
44
44
  return resp;
@@ -34,9 +34,9 @@ const promptToConfirm = async (message)=>{
34
34
  };
35
35
  const spinner = {
36
36
  start (action) {
37
- if (!_const.isTestEnv) _core.CliUx.ux.action.start(action);
37
+ if (!_const.isTestEnv) _core.ux.action.start(action);
38
38
  },
39
39
  stop () {
40
- _core.CliUx.ux.action.stop();
40
+ _core.ux.action.stop();
41
41
  }
42
42
  };
@@ -9,6 +9,9 @@ function _export(target, all) {
9
9
  });
10
10
  }
11
11
  _export(exports, {
12
+ translationRefDescription: ()=>translationRefDescription,
13
+ formatLanguage: ()=>formatLanguage,
14
+ formatRef: ()=>formatRef,
12
15
  isValidLocale: ()=>isValidLocale,
13
16
  isTranslationDir: ()=>isTranslationDir,
14
17
  buildTranslationFileCtx: ()=>buildTranslationFileCtx,
@@ -65,6 +68,16 @@ function _interopRequireWildcard(obj, nodeInterop) {
65
68
  }
66
69
  return newObj;
67
70
  }
71
+ const translationRefDescription = `
72
+ Translation ref is a identifier string that refers to a unique translation.
73
+ If a translation has no namespace, it is the same as the locale, e.g. \`en\`.
74
+ If namespaced, it is formatted as namespace.locale, e.g. \`admin.en\`.
75
+ `.trim();
76
+ const formatLanguage = (translation)=>{
77
+ const lang = _localeCodes.default.getByTag(translation.locale_code);
78
+ return lang.location ? `${lang.name}, ${lang.location}` : lang.name;
79
+ };
80
+ const formatRef = ({ locale_code , namespace })=>namespace ? `${namespace}.${locale_code}` : locale_code;
68
81
  const isValidLocale = (localeCode)=>Boolean(_localeCodes.default.getByTag(localeCode));
69
82
  const isTranslationDir = (dirPath)=>{
70
83
  const locale = _nodePath.basename(dirPath);
@@ -87,7 +100,8 @@ const parseTranslationRef = (reference)=>{
87
100
  // Locale code only (e.g. `en`)
88
101
  if (strings.length === 1) {
89
102
  return {
90
- localeCode: strings[0]
103
+ localeCode: strings[0],
104
+ namespace: undefined
91
105
  };
92
106
  }
93
107
  // Locale code prefixed with a namespace (e.g. `admin.en`)
@@ -105,16 +119,16 @@ const ensureValidCommandTarget = async (props, runContext)=>{
105
119
  const { commandId , resourceDir: resourceDirCtx , cwd: runCwd } = runContext;
106
120
  // Error, trying to run the command not in a translation directory.
107
121
  if (resourceDirCtx && resourceDirCtx.type !== "translation") {
108
- return _core.CliUx.ux.error(`Cannot run ${commandId} inside a ${resourceDirCtx.type} directory`);
122
+ return _core.ux.error(`Cannot run ${commandId} inside a ${resourceDirCtx.type} directory`);
109
123
  }
110
124
  // Error, got neither the translationRef arg nor the --all flag.
111
125
  if (!args.translationRef && !flags.all) {
112
- _core.CliUx.ux.error("At least one of translation ref arg or --all flag must be given");
126
+ _core.ux.error("At least one of translation ref arg or --all flag must be given");
113
127
  }
114
128
  // No translationRef arg, which means --all flag is used.
115
129
  if (!args.translationRef) {
116
130
  // Targeting all translation files in the current locale directory.
117
- if (resourceDirCtx) {
131
+ if (resourceDirCtx && !flags["translations-dir"]) {
118
132
  return {
119
133
  type: "translationDir",
120
134
  context: resourceDirCtx
@@ -135,12 +149,12 @@ const ensureValidCommandTarget = async (props, runContext)=>{
135
149
  // From this point on, we have translationRef so parse and validate the format.
136
150
  const parsedRef = parseTranslationRef(args.translationRef);
137
151
  if (!parsedRef) {
138
- return _core.CliUx.ux.error(`Invalid translationRef arg \`${args.translationRef}\`, use valid <locale> or <namespace>.<locale> for namespaced translations`);
152
+ return _core.ux.error(`Invalid translation ref \`${args.translationRef}\`, use valid <locale> or <namespace>.<locale> for namespaced translations`);
139
153
  }
140
154
  const { localeCode , namespace } = parsedRef;
141
155
  // If we are in the translation dir, make sure the locale matches.
142
156
  if (resourceDirCtx && resourceDirCtx.key !== localeCode) {
143
- return _core.CliUx.ux.error(`Cannot run ${commandId} with \`${args.translationRef}\` inside a ${resourceDirCtx.key} directory`);
157
+ return _core.ux.error(`Cannot run ${commandId} with \`${args.translationRef}\` inside a ${resourceDirCtx.key} directory`);
144
158
  }
145
159
  const targetDirPath = resourceDirCtx ? resourceDirCtx.abspath : _nodePath.resolve(runCwd, localeCode);
146
160
  // Got translationRef arg but no --all flag, which means target only a single
@@ -155,7 +169,7 @@ const ensureValidCommandTarget = async (props, runContext)=>{
155
169
  // From this point on, we have both translationRef and --all flag used
156
170
  // together, so make sure we are targeting a non-namespaced top-level locale.
157
171
  if (namespace) {
158
- return _core.CliUx.ux.error(`Cannot use --all with a namespaced translation \`${args.translationRef}\``);
172
+ return _core.ux.error(`Cannot use --all with a namespaced translation \`${args.translationRef}\``);
159
173
  }
160
174
  const translationDirCtx = {
161
175
  type: "translation",