@knocklabs/cli 0.3.1 → 1.0.0-rc.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.
Files changed (63) hide show
  1. package/README.md +258 -55
  2. package/dist/commands/branch/delete.js +4 -1
  3. package/dist/commands/branch/merge.js +82 -0
  4. package/dist/commands/channel/list.js +73 -0
  5. package/dist/commands/environment/list.js +73 -0
  6. package/dist/commands/guide/new.js +276 -0
  7. package/dist/commands/guide/pull.js +5 -6
  8. package/dist/commands/guide/push.js +1 -1
  9. package/dist/commands/guide/validate.js +1 -1
  10. package/dist/commands/init.js +108 -0
  11. package/dist/commands/layout/new.js +228 -0
  12. package/dist/commands/layout/pull.js +5 -6
  13. package/dist/commands/layout/push.js +1 -1
  14. package/dist/commands/layout/validate.js +1 -1
  15. package/dist/commands/message-type/new.js +228 -0
  16. package/dist/commands/message-type/pull.js +5 -6
  17. package/dist/commands/message-type/push.js +1 -1
  18. package/dist/commands/message-type/validate.js +1 -1
  19. package/dist/commands/partial/new.js +274 -0
  20. package/dist/commands/partial/pull.js +5 -6
  21. package/dist/commands/partial/push.js +1 -1
  22. package/dist/commands/partial/validate.js +1 -1
  23. package/dist/commands/pull.js +7 -2
  24. package/dist/commands/push.js +6 -4
  25. package/dist/commands/translation/pull.js +1 -1
  26. package/dist/commands/translation/push.js +1 -1
  27. package/dist/commands/translation/validate.js +1 -1
  28. package/dist/commands/workflow/new.js +179 -54
  29. package/dist/commands/workflow/pull.js +6 -8
  30. package/dist/commands/workflow/push.js +1 -1
  31. package/dist/commands/workflow/validate.js +1 -1
  32. package/dist/lib/api-v1.js +23 -2
  33. package/dist/lib/auth.js +1 -1
  34. package/dist/lib/base-command.js +18 -15
  35. package/dist/lib/helpers/project-config.js +158 -0
  36. package/dist/lib/helpers/request.js +1 -2
  37. package/dist/lib/helpers/string.js +4 -4
  38. package/dist/lib/helpers/typegen.js +1 -1
  39. package/dist/lib/marshal/email-layout/generator.js +152 -0
  40. package/dist/lib/marshal/email-layout/helpers.js +6 -9
  41. package/dist/lib/marshal/email-layout/index.js +1 -0
  42. package/dist/lib/marshal/email-layout/writer.js +15 -3
  43. package/dist/lib/marshal/guide/generator.js +163 -0
  44. package/dist/lib/marshal/guide/helpers.js +6 -10
  45. package/dist/lib/marshal/guide/index.js +1 -0
  46. package/dist/lib/marshal/guide/writer.js +5 -9
  47. package/dist/lib/marshal/message-type/generator.js +139 -0
  48. package/dist/lib/marshal/message-type/helpers.js +6 -10
  49. package/dist/lib/marshal/message-type/index.js +1 -0
  50. package/dist/lib/marshal/message-type/writer.js +5 -1
  51. package/dist/lib/marshal/partial/generator.js +159 -0
  52. package/dist/lib/marshal/partial/helpers.js +6 -10
  53. package/dist/lib/marshal/partial/index.js +1 -0
  54. package/dist/lib/marshal/partial/writer.js +3 -0
  55. package/dist/lib/marshal/translation/helpers.js +6 -10
  56. package/dist/lib/marshal/translation/processor.isomorphic.js +4 -4
  57. package/dist/lib/marshal/translation/writer.js +2 -2
  58. package/dist/lib/marshal/workflow/generator.js +175 -19
  59. package/dist/lib/marshal/workflow/helpers.js +7 -10
  60. package/dist/lib/run-context/loader.js +5 -0
  61. package/dist/lib/templates.js +131 -0
  62. package/oclif.manifest.json +1075 -471
  63. package/package.json +10 -8
@@ -0,0 +1,274 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "default", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return PartialNew;
9
+ }
10
+ });
11
+ const _nodepath = /*#__PURE__*/ _interop_require_wildcard(require("node:path"));
12
+ const _core = require("@oclif/core");
13
+ const _enquirer = require("enquirer");
14
+ const _basecommand = /*#__PURE__*/ _interop_require_default(require("../../lib/base-command"));
15
+ const _const = require("../../lib/helpers/const");
16
+ const _flag = /*#__PURE__*/ _interop_require_wildcard(require("../../lib/helpers/flag"));
17
+ const _projectconfig = require("../../lib/helpers/project-config");
18
+ const _string = require("../../lib/helpers/string");
19
+ const _ux = require("../../lib/helpers/ux");
20
+ const _partial = /*#__PURE__*/ _interop_require_wildcard(require("../../lib/marshal/partial"));
21
+ const _runcontext = require("../../lib/run-context");
22
+ const _push = /*#__PURE__*/ _interop_require_default(require("./push"));
23
+ function _define_property(obj, key, value) {
24
+ if (key in obj) {
25
+ Object.defineProperty(obj, key, {
26
+ value: value,
27
+ enumerable: true,
28
+ configurable: true,
29
+ writable: true
30
+ });
31
+ } else {
32
+ obj[key] = value;
33
+ }
34
+ return obj;
35
+ }
36
+ function _interop_require_default(obj) {
37
+ return obj && obj.__esModule ? obj : {
38
+ default: obj
39
+ };
40
+ }
41
+ function _getRequireWildcardCache(nodeInterop) {
42
+ if (typeof WeakMap !== "function") return null;
43
+ var cacheBabelInterop = new WeakMap();
44
+ var cacheNodeInterop = new WeakMap();
45
+ return (_getRequireWildcardCache = function(nodeInterop) {
46
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
47
+ })(nodeInterop);
48
+ }
49
+ function _interop_require_wildcard(obj, nodeInterop) {
50
+ if (!nodeInterop && obj && obj.__esModule) {
51
+ return obj;
52
+ }
53
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
54
+ return {
55
+ default: obj
56
+ };
57
+ }
58
+ var cache = _getRequireWildcardCache(nodeInterop);
59
+ if (cache && cache.has(obj)) {
60
+ return cache.get(obj);
61
+ }
62
+ var newObj = {
63
+ __proto__: null
64
+ };
65
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
66
+ for(var key in obj){
67
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
68
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
69
+ if (desc && (desc.get || desc.set)) {
70
+ Object.defineProperty(newObj, key, desc);
71
+ } else {
72
+ newObj[key] = obj[key];
73
+ }
74
+ }
75
+ }
76
+ newObj.default = obj;
77
+ if (cache) {
78
+ cache.set(obj, newObj);
79
+ }
80
+ return newObj;
81
+ }
82
+ const PARTIAL_TYPE_CHOICES = [
83
+ {
84
+ name: _partial.PartialType.Html,
85
+ message: "HTML"
86
+ },
87
+ {
88
+ name: _partial.PartialType.Json,
89
+ message: "JSON"
90
+ },
91
+ {
92
+ name: _partial.PartialType.Markdown,
93
+ message: "Markdown"
94
+ },
95
+ {
96
+ name: _partial.PartialType.Text,
97
+ message: "Text"
98
+ }
99
+ ];
100
+ class PartialNew extends _basecommand.default {
101
+ async run() {
102
+ const { flags } = this.props;
103
+ const { resourceDir } = this.runContext;
104
+ // 1. Ensure we aren't in any existing resource directory already.
105
+ if (resourceDir) {
106
+ return this.error(`Cannot create a new partial inside an existing ${resourceDir.type} directory`);
107
+ }
108
+ // 2. Prompt for name and key if not provided
109
+ let name = flags.name;
110
+ let key = flags.key;
111
+ if (!name) {
112
+ const nameResponse = await (0, _enquirer.prompt)({
113
+ type: "input",
114
+ name: "name",
115
+ message: "Partial name",
116
+ validate: (value)=>{
117
+ if (!value || value.trim().length === 0) {
118
+ return "Partial name is required";
119
+ }
120
+ return true;
121
+ }
122
+ });
123
+ name = nameResponse.name;
124
+ }
125
+ if (!key) {
126
+ const keyResponse = await (0, _enquirer.prompt)({
127
+ type: "input",
128
+ name: "key",
129
+ message: "Partial key (immutable slug)",
130
+ initial: (0, _string.slugify)(name),
131
+ validate: (value)=>{
132
+ if (!value || value.trim().length === 0) {
133
+ return "Partial key is required";
134
+ }
135
+ const keyError = _partial.validatePartialKey(value);
136
+ if (keyError) {
137
+ return `Invalid partial key: ${keyError}`;
138
+ }
139
+ return true;
140
+ }
141
+ });
142
+ key = keyResponse.key;
143
+ }
144
+ // Validate the partial key
145
+ const partialKeyError = _partial.validatePartialKey(key);
146
+ if (partialKeyError) {
147
+ return this.error(`Invalid partial key \`${key}\` (${partialKeyError})`);
148
+ }
149
+ const partialDirCtx = await this.getPartialDirContext(key);
150
+ const promptMessage = partialDirCtx.exists ? `Found \`${partialDirCtx.key}\` at ${partialDirCtx.abspath}, overwrite?` : `Create a new partial directory \`${partialDirCtx.key}\` at ${partialDirCtx.abspath}?`;
151
+ // Check if the partial directory already exists, and prompt to confirm if not.
152
+ const input = flags.force || await (0, _ux.promptToConfirm)(promptMessage);
153
+ if (!input) return;
154
+ // Generate the partial either from a template or from scratch
155
+ await (flags.template ? this.fromTemplate(partialDirCtx, name, flags.template) : this.fromType(partialDirCtx, name, flags.type));
156
+ if (flags.push) {
157
+ _ux.spinner.start("‣ Pushing partial to Knock");
158
+ try {
159
+ await _push.default.run([
160
+ key
161
+ ]);
162
+ } catch (error) {
163
+ this.error(`Failed to push partial to Knock: ${error}`);
164
+ } finally{
165
+ _ux.spinner.stop();
166
+ }
167
+ }
168
+ this.log(`‣ Successfully created partial \`${key}\``);
169
+ }
170
+ async fromTemplate(partialDirCtx, name, templateString) {
171
+ // When being called from the template string, we want to try and generate
172
+ // the partial from the provided template.
173
+ _ux.spinner.start(`‣ Generating partial from template \`${templateString}\``);
174
+ try {
175
+ await _partial.generatePartialFromTemplate(partialDirCtx, templateString, {
176
+ name
177
+ });
178
+ } catch (error) {
179
+ this.error(`Failed to generate partial from template: ${error}`);
180
+ } finally{
181
+ _ux.spinner.stop();
182
+ }
183
+ _ux.spinner.stop();
184
+ }
185
+ async fromType(partialDirCtx, name, type) {
186
+ let partialType;
187
+ if (type) {
188
+ partialType = type;
189
+ } else {
190
+ // Prompt for type with select
191
+ const typeResponse = await (0, _enquirer.prompt)({
192
+ type: "select",
193
+ name: "type",
194
+ message: "Select partial type",
195
+ choices: PARTIAL_TYPE_CHOICES.map((choice)=>({
196
+ name: choice.name,
197
+ message: choice.message
198
+ }))
199
+ });
200
+ partialType = typeResponse.type;
201
+ }
202
+ // Generate the partial directory with scaffolded content
203
+ await _partial.generatePartialDir(partialDirCtx, {
204
+ name,
205
+ type: partialType
206
+ });
207
+ }
208
+ async getPartialDirContext(partialKey) {
209
+ const { resourceDir, cwd: runCwd } = this.runContext;
210
+ // Inside an existing resource dir, use it if valid for the target partial.
211
+ if (resourceDir) {
212
+ const target = {
213
+ commandId: _basecommand.default.id,
214
+ type: "partial",
215
+ key: partialKey
216
+ };
217
+ return (0, _runcontext.ensureResourceDirForTarget)(resourceDir, target);
218
+ }
219
+ // Default to knock project config first if present, otherwise cwd.
220
+ const dirCtx = await (0, _projectconfig.resolveResourceDir)(this.projectConfig, "partial", runCwd);
221
+ // Not inside any existing partial directory, which means either create a
222
+ // new partial directory in the cwd, or update it if there is one already.
223
+ if (partialKey) {
224
+ const dirPath = _nodepath.resolve(dirCtx.abspath, partialKey);
225
+ const exists = await _partial.isPartialDir(dirPath);
226
+ return {
227
+ type: "partial",
228
+ key: partialKey,
229
+ abspath: dirPath,
230
+ exists
231
+ };
232
+ }
233
+ // Not in any partial directory, nor a partial key arg was given so error.
234
+ return this.error("Missing 1 required arg:\npartialKey");
235
+ }
236
+ }
237
+ _define_property(PartialNew, "summary", "Create a new partial with a minimal configuration.");
238
+ _define_property(PartialNew, "flags", {
239
+ name: _core.Flags.string({
240
+ summary: "The name of the partial",
241
+ char: "n"
242
+ }),
243
+ key: _core.Flags.string({
244
+ summary: "The key of the partial",
245
+ char: "k"
246
+ }),
247
+ type: _core.Flags.string({
248
+ summary: "The type of the partial (html, json, markdown, text). You cannot use this flag with --template.",
249
+ char: "t",
250
+ options: [
251
+ _partial.PartialType.Html,
252
+ _partial.PartialType.Json,
253
+ _partial.PartialType.Markdown,
254
+ _partial.PartialType.Text
255
+ ]
256
+ }),
257
+ environment: _core.Flags.string({
258
+ summary: "The environment to create the partial in. Defaults to development.",
259
+ default: _const.KnockEnv.Development
260
+ }),
261
+ branch: _flag.branch,
262
+ force: _core.Flags.boolean({
263
+ summary: "Force the creation of the partial directory without confirmation."
264
+ }),
265
+ push: _core.Flags.boolean({
266
+ summary: "Whether or not to push the partial to Knock after creation.",
267
+ default: false,
268
+ char: "p"
269
+ }),
270
+ template: _core.Flags.string({
271
+ summary: "The template to use for the partial. Should be `partials/{key}`. You cannot use this flag with --type."
272
+ })
273
+ });
274
+ _define_property(PartialNew, "args", {});
@@ -16,6 +16,7 @@ const _error = require("../../lib/helpers/error");
16
16
  const _flag = /*#__PURE__*/ _interop_require_wildcard(require("../../lib/helpers/flag"));
17
17
  const _objectisomorphic = require("../../lib/helpers/object.isomorphic");
18
18
  const _page = require("../../lib/helpers/page");
19
+ const _projectconfig = require("../../lib/helpers/project-config");
19
20
  const _request = require("../../lib/helpers/request");
20
21
  const _ux = require("../../lib/helpers/ux");
21
22
  const _partial = /*#__PURE__*/ _interop_require_wildcard(require("../../lib/marshal/partial"));
@@ -119,11 +120,8 @@ class PartialPull extends _basecommand.default {
119
120
  // Pull all partials
120
121
  async pullAllPartials() {
121
122
  const { flags } = this.props;
122
- const defaultToCwd = {
123
- abspath: this.runContext.cwd,
124
- exists: true
125
- };
126
- const targetDirCtx = flags["partials-dir"] || defaultToCwd;
123
+ const partialsIndexDirCtx = await (0, _projectconfig.resolveResourceDir)(this.projectConfig, "partial", this.runContext.cwd);
124
+ const targetDirCtx = flags["partials-dir"] || partialsIndexDirCtx;
127
125
  const prompt = targetDirCtx.exists ? `Pull latest partials into ${targetDirCtx.abspath}?\n This will overwrite the contents of this directory.` : `Create a new partials directory at ${targetDirCtx.abspath}?`;
128
126
  const input = flags.force || await (0, _ux.promptToConfirm)(prompt);
129
127
  if (!input) return;
@@ -171,10 +169,11 @@ class PartialPull extends _basecommand.default {
171
169
  };
172
170
  return (0, _runcontext.ensureResourceDirForTarget)(resourceDir, target);
173
171
  }
172
+ const partialsIndexDirCtx = await (0, _projectconfig.resolveResourceDir)(this.projectConfig, "partial", runCwd);
174
173
  // Not inside any existing partial directory, which means either create a
175
174
  // new partial directory in the cwd, or update it if there is one already.
176
175
  if (partialKey) {
177
- const dirPath = _nodepath.resolve(runCwd, partialKey);
176
+ const dirPath = _nodepath.resolve(partialsIndexDirCtx.abspath, partialKey);
178
177
  const exists = await _partial.isPartialDir(dirPath);
179
178
  return {
180
179
  type: "partial",
@@ -83,7 +83,7 @@ class PartialPush extends _basecommand.default {
83
83
  async run() {
84
84
  const { flags } = this.props;
85
85
  // 1. First read all partial directories found for the given command.
86
- const target = await _partial.ensureValidCommandTarget(this.props, this.runContext);
86
+ const target = await _partial.ensureValidCommandTarget(this.props, this.runContext, this.projectConfig);
87
87
  const [partials, readErrors] = await _partial.readAllForCommandTarget(target, {
88
88
  withExtractedFiles: true
89
89
  });
@@ -80,7 +80,7 @@ function _interop_require_wildcard(obj, nodeInterop) {
80
80
  class PartialValidate extends _basecommand.default {
81
81
  async run() {
82
82
  // 1. Read all partial directories found for the given command.
83
- const target = await _partial.ensureValidCommandTarget(this.props, this.runContext);
83
+ const target = await _partial.ensureValidCommandTarget(this.props, this.runContext, this.projectConfig);
84
84
  const [partials, readErrors] = await _partial.readAllForCommandTarget(target, {
85
85
  withExtractedFiles: true
86
86
  });
@@ -12,6 +12,7 @@ const _nodepath = /*#__PURE__*/ _interop_require_wildcard(require("node:path"));
12
12
  const _core = require("@oclif/core");
13
13
  const _basecommand = /*#__PURE__*/ _interop_require_default(require("../lib/base-command"));
14
14
  const _flag = /*#__PURE__*/ _interop_require_wildcard(require("../lib/helpers/flag"));
15
+ const _projectconfig = require("../lib/helpers/project-config");
15
16
  const _ux = require("../lib/helpers/ux");
16
17
  const _resources = require("../lib/resources");
17
18
  const _pull = /*#__PURE__*/ _interop_require_default(require("./guide/pull"));
@@ -82,7 +83,11 @@ function _interop_require_wildcard(obj, nodeInterop) {
82
83
  class Pull extends _basecommand.default {
83
84
  async run() {
84
85
  const { flags } = this.props;
85
- const targetDirCtx = flags["knock-dir"];
86
+ // Resolve knock directory: flag takes precedence, otherwise use knock.json
87
+ const targetDirCtx = await (0, _projectconfig.resolveKnockDir)(flags["knock-dir"], this.projectConfig);
88
+ if (!targetDirCtx) {
89
+ this.error("No knock directory specified. Either provide --knock-dir flag or run `knock init` to create a knock.json configuration file.");
90
+ }
86
91
  const prompt = targetDirCtx.exists ? `Pull latest resources into ${targetDirCtx.abspath}?\n This will overwrite the contents of this directory.` : `Create a new resources directory at ${targetDirCtx.abspath}?`;
87
92
  const input = flags.force || await (0, _ux.promptToConfirm)(prompt);
88
93
  if (!input) return;
@@ -123,7 +128,7 @@ _define_property(Pull, "flags", {
123
128
  branch: _flag.branch,
124
129
  "knock-dir": _flag.dirPath({
125
130
  summary: "The target directory path to pull all resources into.",
126
- required: true
131
+ required: false
127
132
  }),
128
133
  "hide-uncommitted-changes": _core.Flags.boolean({
129
134
  summary: "Hide any uncommitted changes."
@@ -14,6 +14,7 @@ const _fsextra = /*#__PURE__*/ _interop_require_wildcard(require("fs-extra"));
14
14
  const _basecommand = /*#__PURE__*/ _interop_require_default(require("../lib/base-command"));
15
15
  const _const = require("../lib/helpers/const");
16
16
  const _flag = /*#__PURE__*/ _interop_require_wildcard(require("../lib/helpers/flag"));
17
+ const _projectconfig = require("../lib/helpers/project-config");
17
18
  const _resources = require("../lib/resources");
18
19
  const _push = /*#__PURE__*/ _interop_require_default(require("./guide/push"));
19
20
  const _push1 = /*#__PURE__*/ _interop_require_default(require("./layout/push"));
@@ -83,9 +84,10 @@ function _interop_require_wildcard(obj, nodeInterop) {
83
84
  class Push extends _basecommand.default {
84
85
  async run() {
85
86
  const { flags } = this.props;
86
- const targetDirCtx = flags["knock-dir"];
87
- if (!targetDirCtx.exists) {
88
- this.error(`Directory ${targetDirCtx.abspath} does not exist`);
87
+ // Resolve knock directory: flag takes precedence, otherwise use knock.json
88
+ const targetDirCtx = await (0, _projectconfig.resolveKnockDir)(flags["knock-dir"], this.projectConfig);
89
+ if (!targetDirCtx) {
90
+ this.error("No knock directory specified. Either provide --knock-dir flag or run `knock init` to create a knock.json configuration file.");
89
91
  }
90
92
  const args = [
91
93
  "--all",
@@ -133,7 +135,7 @@ _define_property(Push, "flags", {
133
135
  branch: _flag.branch,
134
136
  "knock-dir": _flag.dirPath({
135
137
  summary: "The target directory path to find all resources to push.",
136
- required: true
138
+ required: false
137
139
  }),
138
140
  commit: _core.Flags.boolean({
139
141
  summary: "Push and commit the resource(s) at the same time"
@@ -79,7 +79,7 @@ function _interop_require_wildcard(obj, nodeInterop) {
79
79
  }
80
80
  class TranslationPull extends _basecommand.default {
81
81
  async run() {
82
- const target = await _translation.ensureValidCommandTarget(this.props, this.runContext);
82
+ const target = await _translation.ensureValidCommandTarget(this.props, this.runContext, this.projectConfig);
83
83
  switch(target.type){
84
84
  case "translationFile":
85
85
  return this.pullOneTranslation(target.context);
@@ -82,7 +82,7 @@ class TranslationPush extends _basecommand.default {
82
82
  async run() {
83
83
  const { flags } = this.props;
84
84
  // 1. First read all translation files found for the given command.
85
- const target = await _translation.ensureValidCommandTarget(this.props, this.runContext);
85
+ const target = await _translation.ensureValidCommandTarget(this.props, this.runContext, this.projectConfig);
86
86
  const [translations, readErrors] = await _translation.readAllForCommandTarget(target);
87
87
  if (readErrors.length > 0) {
88
88
  this.error((0, _error.formatErrors)(readErrors, {
@@ -79,7 +79,7 @@ function _interop_require_wildcard(obj, nodeInterop) {
79
79
  }
80
80
  class TranslationValidate extends _basecommand.default {
81
81
  async run() {
82
- const target = await _translation.ensureValidCommandTarget(this.props, this.runContext);
82
+ const target = await _translation.ensureValidCommandTarget(this.props, this.runContext, this.projectConfig);
83
83
  const [translations, readErrors] = await _translation.readAllForCommandTarget(target);
84
84
  if (readErrors.length > 0) {
85
85
  this.error((0, _error.formatErrors)(readErrors, {