@knocklabs/cli 0.1.21 → 0.1.23

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 (57) hide show
  1. package/README.md +141 -41
  2. package/dist/commands/commit/list.js +21 -1
  3. package/dist/commands/guide/activate.js +121 -0
  4. package/dist/commands/guide/generate-types.js +148 -0
  5. package/dist/commands/guide/get.js +139 -0
  6. package/dist/commands/guide/list.js +112 -0
  7. package/dist/commands/guide/pull.js +209 -0
  8. package/dist/commands/guide/push.js +171 -0
  9. package/dist/commands/guide/validate.js +148 -0
  10. package/dist/commands/pull.js +157 -0
  11. package/dist/commands/push.js +175 -0
  12. package/dist/commands/workflow/generate-types.js +6 -5
  13. package/dist/lib/api-v1.js +61 -0
  14. package/dist/lib/helpers/const.js +4 -4
  15. package/dist/lib/helpers/date.js +3 -3
  16. package/dist/lib/helpers/error.js +8 -8
  17. package/dist/lib/helpers/flag.js +7 -7
  18. package/dist/lib/helpers/json.js +5 -5
  19. package/dist/lib/helpers/object.isomorphic.js +8 -8
  20. package/dist/lib/helpers/page.js +9 -9
  21. package/dist/lib/helpers/request.js +4 -4
  22. package/dist/lib/helpers/string.js +3 -3
  23. package/dist/lib/helpers/typegen.js +59 -0
  24. package/dist/lib/helpers/ux.js +3 -3
  25. package/dist/lib/marshal/email-layout/helpers.js +5 -5
  26. package/dist/lib/marshal/email-layout/processor.isomorphic.js +3 -3
  27. package/dist/lib/marshal/email-layout/reader.js +5 -5
  28. package/dist/lib/marshal/email-layout/writer.js +4 -4
  29. package/dist/lib/marshal/guide/helpers.js +283 -0
  30. package/dist/lib/marshal/guide/index.js +3 -0
  31. package/dist/lib/marshal/guide/processor.isomorphic.js +3 -3
  32. package/dist/lib/marshal/guide/reader.js +193 -0
  33. package/dist/lib/marshal/guide/writer.js +175 -0
  34. package/dist/lib/marshal/index.isomorphic.js +7 -7
  35. package/dist/lib/marshal/message-type/helpers.js +5 -5
  36. package/dist/lib/marshal/message-type/processor.isomorphic.js +3 -3
  37. package/dist/lib/marshal/message-type/reader.js +5 -5
  38. package/dist/lib/marshal/message-type/writer.js +4 -4
  39. package/dist/lib/marshal/partial/helpers.js +5 -5
  40. package/dist/lib/marshal/partial/processor.isomorphic.js +3 -3
  41. package/dist/lib/marshal/partial/reader.js +5 -5
  42. package/dist/lib/marshal/partial/writer.js +4 -4
  43. package/dist/lib/marshal/shared/const.isomorphic.js +3 -3
  44. package/dist/lib/marshal/shared/helpers.isomorphic.js +9 -2
  45. package/dist/lib/marshal/shared/helpers.js +4 -4
  46. package/dist/lib/marshal/translation/helpers.js +10 -10
  47. package/dist/lib/marshal/translation/processor.isomorphic.js +6 -6
  48. package/dist/lib/marshal/translation/writer.js +3 -3
  49. package/dist/lib/marshal/workflow/generator.js +4 -4
  50. package/dist/lib/marshal/workflow/helpers.js +53 -10
  51. package/dist/lib/marshal/workflow/processor.isomorphic.js +5 -5
  52. package/dist/lib/marshal/workflow/reader.js +5 -5
  53. package/dist/lib/marshal/workflow/writer.js +5 -5
  54. package/dist/lib/resources.js +32 -0
  55. package/oclif.manifest.json +961 -260
  56. package/package.json +8 -8
  57. package/dist/lib/type-generator.js +0 -100
@@ -0,0 +1,283 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
+ });
10
+ }
11
+ _export(exports, {
12
+ get ensureValidCommandTarget () {
13
+ return ensureValidCommandTarget;
14
+ },
15
+ get formatActivationRules () {
16
+ return formatActivationRules;
17
+ },
18
+ get formatStatusWithSchedule () {
19
+ return formatStatusWithSchedule;
20
+ },
21
+ get formatStep () {
22
+ return formatStep;
23
+ },
24
+ get generateIndexTypeTS () {
25
+ return generateIndexTypeTS;
26
+ },
27
+ get generateTypes () {
28
+ return generateTypes;
29
+ },
30
+ get guideJsonPath () {
31
+ return guideJsonPath;
32
+ },
33
+ get isGuideDir () {
34
+ return isGuideDir;
35
+ },
36
+ get lsGuideJson () {
37
+ return lsGuideJson;
38
+ }
39
+ });
40
+ const _nodepath = /*#__PURE__*/ _interop_require_wildcard(require("node:path"));
41
+ const _core = require("@oclif/core");
42
+ const _fsextra = /*#__PURE__*/ _interop_require_wildcard(require("fs-extra"));
43
+ const _lodash = require("lodash");
44
+ const _quicktypecore = require("quicktype-core");
45
+ const _processorisomorphic = require("./processor.isomorphic");
46
+ function _getRequireWildcardCache(nodeInterop) {
47
+ if (typeof WeakMap !== "function") return null;
48
+ var cacheBabelInterop = new WeakMap();
49
+ var cacheNodeInterop = new WeakMap();
50
+ return (_getRequireWildcardCache = function(nodeInterop) {
51
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
52
+ })(nodeInterop);
53
+ }
54
+ function _interop_require_wildcard(obj, nodeInterop) {
55
+ if (!nodeInterop && obj && obj.__esModule) {
56
+ return obj;
57
+ }
58
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
59
+ return {
60
+ default: obj
61
+ };
62
+ }
63
+ var cache = _getRequireWildcardCache(nodeInterop);
64
+ if (cache && cache.has(obj)) {
65
+ return cache.get(obj);
66
+ }
67
+ var newObj = {
68
+ __proto__: null
69
+ };
70
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
71
+ for(var key in obj){
72
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
73
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
74
+ if (desc && (desc.get || desc.set)) {
75
+ Object.defineProperty(newObj, key, desc);
76
+ } else {
77
+ newObj[key] = obj[key];
78
+ }
79
+ }
80
+ }
81
+ newObj.default = obj;
82
+ if (cache) {
83
+ cache.set(obj, newObj);
84
+ }
85
+ return newObj;
86
+ }
87
+ const formatStatusWithSchedule = (guide)=>{
88
+ const baseStatus = guide.active ? "Active" : "Inactive";
89
+ if (guide.active_from || guide.active_until) {
90
+ const fromText = guide.active_from ? `from ${guide.active_from}` : "immediately";
91
+ const untilText = guide.active_until ? `until ${guide.active_until}` : "with no end time";
92
+ return `${baseStatus} (${fromText} ${untilText})`;
93
+ }
94
+ return baseStatus;
95
+ };
96
+ const formatStep = (step)=>{
97
+ return `${step.schema_key} (${step.schema_variant_key})`;
98
+ };
99
+ const formatActivationRules = (rules)=>{
100
+ if (!rules || !Array.isArray(rules)) return "-";
101
+ return rules.map(({ directive, pathname })=>`${directive} ${pathname}`).join(", ");
102
+ };
103
+ const guideJsonPath = (guideDirCtx)=>_nodepath.resolve(guideDirCtx.abspath, _processorisomorphic.GUIDE_JSON);
104
+ const lsGuideJson = async (dirPath)=>{
105
+ const guideJsonPath = _nodepath.resolve(dirPath, _processorisomorphic.GUIDE_JSON);
106
+ const exists = await _fsextra.pathExists(guideJsonPath);
107
+ return exists ? guideJsonPath : undefined;
108
+ };
109
+ const isGuideDir = async (dirPath)=>Boolean(await lsGuideJson(dirPath));
110
+ const ensureValidCommandTarget = async (props, runContext)=>{
111
+ const { args, flags } = props;
112
+ const { commandId, resourceDir: resourceDirCtx, cwd: runCwd } = runContext;
113
+ // If the target resource is a different type than the current resource dir
114
+ // type, error out.
115
+ if (resourceDirCtx && resourceDirCtx.type !== "guide") {
116
+ return _core.ux.error(`Cannot run ${commandId} inside a ${resourceDirCtx.type} directory`);
117
+ }
118
+ // Cannot accept both guide key arg and --all flag.
119
+ if (flags.all && args.guideKey) {
120
+ return _core.ux.error(`guideKey arg \`${args.guideKey}\` cannot also be provided when using --all`);
121
+ }
122
+ // --all flag is given, which means no guide key arg.
123
+ if (flags.all) {
124
+ // If --all flag used inside a guide directory, then require a guides
125
+ // dir path.
126
+ if (resourceDirCtx && !flags["guides-dir"]) {
127
+ return _core.ux.error("Missing required flag guides-dir");
128
+ }
129
+ // Targeting all guide dirs in the guides index dir.
130
+ // TODO: Default to the knock project config first if present before cwd.
131
+ const defaultToCwd = {
132
+ abspath: runCwd,
133
+ exists: true
134
+ };
135
+ const indexDirCtx = flags["guides-dir"] || defaultToCwd;
136
+ return {
137
+ type: "guidesIndexDir",
138
+ context: indexDirCtx
139
+ };
140
+ }
141
+ // Guide key arg is given, which means no --all flag.
142
+ if (args.guideKey) {
143
+ if (resourceDirCtx && resourceDirCtx.key !== args.guideKey) {
144
+ return _core.ux.error(`Cannot run ${commandId} \`${args.guideKey}\` inside another guide directory:\n${resourceDirCtx.key}`);
145
+ }
146
+ const targetDirPath = resourceDirCtx ? resourceDirCtx.abspath : _nodepath.resolve(runCwd, args.guideKey);
147
+ const guideDirCtx = {
148
+ type: "guide",
149
+ key: args.guideKey,
150
+ abspath: targetDirPath,
151
+ exists: await isGuideDir(targetDirPath)
152
+ };
153
+ return {
154
+ type: "guideDir",
155
+ context: guideDirCtx
156
+ };
157
+ }
158
+ // From this point on, we have neither a guide key arg nor --all flag.
159
+ // If running inside a guide directory, then use that guide directory.
160
+ if (resourceDirCtx) {
161
+ return {
162
+ type: "guideDir",
163
+ context: resourceDirCtx
164
+ };
165
+ }
166
+ return _core.ux.error("Missing 1 required arg:\nguideKey");
167
+ };
168
+ /*
169
+ * Takes an array of guides and generate types from its content json schemas.
170
+ */ const SCHEMA_TITLE_PREFIX = "Guide";
171
+ async function generateTypes(guides, targetLanguage) {
172
+ const schemaInput = new _quicktypecore.JSONSchemaInput(new _quicktypecore.FetchingJSONSchemaStore());
173
+ let processedCount = 0;
174
+ const mapping = {
175
+ key: {},
176
+ type: {}
177
+ };
178
+ for (const guide of guides){
179
+ if (!guide.type) {
180
+ continue;
181
+ }
182
+ // We only support single step guides at the moment.
183
+ const step = (guide.steps || []).find((s)=>s.json_schema);
184
+ if (!step) {
185
+ continue;
186
+ }
187
+ // Format the type name that quicktype can output exactly. It's important
188
+ // that the names we format are used/preserved by quicktype as we create the
189
+ // final mapping referencing these type names.
190
+ // Example: `GuideBannerFourStep1Banner001Default`
191
+ const typeName = [
192
+ SCHEMA_TITLE_PREFIX,
193
+ startCaseNoSpace(guide.key),
194
+ startCaseNoSpace(step.ref),
195
+ startCaseNoSpace(step.schema_key),
196
+ startCaseNoSpace(step.schema_semver),
197
+ startCaseNoSpace(step.schema_variant_key)
198
+ ].join("");
199
+ schemaInput.addSource({
200
+ name: typeName,
201
+ schema: JSON.stringify({
202
+ ...step.json_schema,
203
+ title: typeName
204
+ })
205
+ });
206
+ mapping.key[guide.key] = typeName;
207
+ mapping.type[guide.type] = [
208
+ ...mapping.type[guide.type] || [],
209
+ typeName
210
+ ];
211
+ processedCount++;
212
+ }
213
+ if (processedCount === 0) {
214
+ return {
215
+ result: undefined,
216
+ count: 0,
217
+ mapping
218
+ };
219
+ }
220
+ const inputData = new _quicktypecore.InputData();
221
+ inputData.addInput(schemaInput);
222
+ const result = await (0, _quicktypecore.quicktype)({
223
+ inputData,
224
+ lang: targetLanguage,
225
+ allPropertiesOptional: false,
226
+ alphabetizeProperties: true,
227
+ rendererOptions: {
228
+ "just-types": true,
229
+ "no-extra-properties": true,
230
+ "no-optional-null": true
231
+ }
232
+ });
233
+ return {
234
+ result,
235
+ count: processedCount,
236
+ mapping
237
+ };
238
+ }
239
+ const startCaseNoSpace = (key)=>(0, _lodash.startCase)(key).replace(/\s/g, "");
240
+ /*
241
+ * For typescript, this writes a root type that maps out all guide types by
242
+ * guide type and key.
243
+ *
244
+ * For example:
245
+ * type GuideContentByType = {
246
+ * "banner-one": GuideBannerOneStep1Banner001Default;
247
+ * "banner-two": GuideBannerTwoStep1Banner001Default;
248
+ * "card-one": GuideCardOneStep1Card001Default;
249
+ * "card-two": GuideCardTwoStep1Card001SingleAction;
250
+ * "changelog-card": GuideChangelogCardStep1ChangelogCard001SingleAction;
251
+ * "modal-one": GuideModalOneStep1Modal001MultiAction;
252
+ * };
253
+ *
254
+ * type GuideContentByKey = {
255
+ * "banner": GuideBannerOneStep1Banner001Default | GuideBannerTwoStep1Banner001Default;
256
+ * "card": GuideCardOneStep1Card001Default | GuideCardTwoStep1Card001SingleAction;
257
+ * "changelog-card": GuideChangelogCardStep1ChangelogCard001SingleAction;
258
+ * "modal": GuideModalOneStep1Modal001MultiAction;
259
+ * };
260
+ *
261
+ * export type GuideContentIndex = {
262
+ * key: GuideContentByType;
263
+ * type: GuideContentByKey;
264
+ * };
265
+ */ const TS_INDEX_TYPE_PREFIX = "GuideContent";
266
+ const generateIndexTypeTS = (mapping)=>{
267
+ const lines = [];
268
+ // Define the type for sub index by guide key.
269
+ const byKey = `${TS_INDEX_TYPE_PREFIX}ByKey`;
270
+ lines.push(`\ntype ${byKey} = {`);
271
+ for (const [key, val] of Object.entries(mapping.key)){
272
+ lines.push(` "${key}": ${val};`);
273
+ }
274
+ lines.push("};");
275
+ // Define the type for sub index by guide type.
276
+ const byType = `${TS_INDEX_TYPE_PREFIX}ByType`;
277
+ lines.push(`\ntype ${byType} = {`);
278
+ for (const [key, val] of Object.entries(mapping.type)){
279
+ lines.push(` "${key}": ${(val || []).join(" | ")};`);
280
+ }
281
+ lines.push("};", `\nexport type ${TS_INDEX_TYPE_PREFIX}Index = {`, ` key: ${byKey};`, ` type: ${byType};`, "};");
282
+ return lines;
283
+ };
@@ -2,8 +2,11 @@
2
2
  Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
+ _export_star(require("./helpers"), exports);
5
6
  _export_star(require("./processor.isomorphic"), exports);
7
+ _export_star(require("./reader"), exports);
6
8
  _export_star(require("./types"), exports);
9
+ _export_star(require("./writer"), exports);
7
10
  function _export_star(from, to) {
8
11
  Object.keys(from).forEach(function(k) {
9
12
  if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
@@ -12,14 +12,14 @@ Object.defineProperty(exports, "__esModule", {
12
12
  function _export(target, all) {
13
13
  for(var name in all)Object.defineProperty(target, name, {
14
14
  enumerable: true,
15
- get: all[name]
15
+ get: Object.getOwnPropertyDescriptor(all, name).get
16
16
  });
17
17
  }
18
18
  _export(exports, {
19
- GUIDE_JSON: function() {
19
+ get GUIDE_JSON () {
20
20
  return GUIDE_JSON;
21
21
  },
22
- buildGuideDirBundle: function() {
22
+ get buildGuideDirBundle () {
23
23
  return buildGuideDirBundle;
24
24
  }
25
25
  });
@@ -0,0 +1,193 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
+ });
10
+ }
11
+ _export(exports, {
12
+ get readAllForCommandTarget () {
13
+ return readAllForCommandTarget;
14
+ },
15
+ get readGuideDir () {
16
+ return readGuideDir;
17
+ }
18
+ });
19
+ const _nodepath = /*#__PURE__*/ _interop_require_wildcard(require("node:path"));
20
+ const _core = require("@oclif/core");
21
+ const _fsextra = /*#__PURE__*/ _interop_require_wildcard(require("fs-extra"));
22
+ const _lodash = require("lodash");
23
+ const _error = require("../../helpers/error");
24
+ const _json = require("../../helpers/json");
25
+ const _objectisomorphic = require("../../helpers/object.isomorphic");
26
+ const _constisomorphic = require("../shared/const.isomorphic");
27
+ const _helpers = require("../shared/helpers");
28
+ const _helpers1 = require("./helpers");
29
+ const _processorisomorphic = require("./processor.isomorphic");
30
+ function _getRequireWildcardCache(nodeInterop) {
31
+ if (typeof WeakMap !== "function") return null;
32
+ var cacheBabelInterop = new WeakMap();
33
+ var cacheNodeInterop = new WeakMap();
34
+ return (_getRequireWildcardCache = function(nodeInterop) {
35
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
36
+ })(nodeInterop);
37
+ }
38
+ function _interop_require_wildcard(obj, nodeInterop) {
39
+ if (!nodeInterop && obj && obj.__esModule) {
40
+ return obj;
41
+ }
42
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
43
+ return {
44
+ default: obj
45
+ };
46
+ }
47
+ var cache = _getRequireWildcardCache(nodeInterop);
48
+ if (cache && cache.has(obj)) {
49
+ return cache.get(obj);
50
+ }
51
+ var newObj = {
52
+ __proto__: null
53
+ };
54
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
55
+ for(var key in obj){
56
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
57
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
58
+ if (desc && (desc.get || desc.set)) {
59
+ Object.defineProperty(newObj, key, desc);
60
+ } else {
61
+ newObj[key] = obj[key];
62
+ }
63
+ }
64
+ }
65
+ newObj.default = obj;
66
+ if (cache) {
67
+ cache.set(obj, newObj);
68
+ }
69
+ return newObj;
70
+ }
71
+ /*
72
+ * For the given list of guide directory contexts, read each guide dir and
73
+ * return guide directory data.
74
+ */ const readGuideDirs = async (guideDirCtxs, opts = {})=>{
75
+ const guides = [];
76
+ const errors = [];
77
+ for (const guideDirCtx of guideDirCtxs){
78
+ // eslint-disable-next-line no-await-in-loop
79
+ const [guide, readErrors] = await readGuideDir(guideDirCtx, opts);
80
+ if (readErrors.length > 0) {
81
+ const guideJsonPath = _nodepath.resolve(guideDirCtx.abspath, _processorisomorphic.GUIDE_JSON);
82
+ const e = new _error.SourceError((0, _error.formatErrors)(readErrors), guideJsonPath);
83
+ errors.push(e);
84
+ continue;
85
+ }
86
+ guides.push({
87
+ ...guideDirCtx,
88
+ content: guide
89
+ });
90
+ }
91
+ return [
92
+ guides,
93
+ errors
94
+ ];
95
+ };
96
+ const readGuideDir = async (guideDirCtx, opts = {})=>{
97
+ const { abspath } = guideDirCtx;
98
+ const { withExtractedFiles = false } = opts;
99
+ const dirExists = await _fsextra.pathExists(abspath);
100
+ if (!dirExists) throw new Error(`${abspath} does not exist`);
101
+ const guideJsonPath = await (0, _helpers1.lsGuideJson)(abspath);
102
+ if (!guideJsonPath) throw new Error(`${abspath} is not a guide directory`);
103
+ const result = await (0, _json.readJson)(guideJsonPath);
104
+ if (!result[0]) return result;
105
+ let [guideJson] = result;
106
+ guideJson = (0, _objectisomorphic.omitDeep)(guideJson, [
107
+ "__readonly"
108
+ ]);
109
+ return withExtractedFiles ? joinExtractedFiles(guideDirCtx, guideJson) : [
110
+ guideJson,
111
+ []
112
+ ];
113
+ };
114
+ const joinExtractedFiles = async (guideDirCtx, guideJson)=>{
115
+ // Tracks any errors encountered during traversal. Mutated in place.
116
+ const errors = [];
117
+ // Tracks each new valid extracted file path seen (rebased to be relative to
118
+ // guide.json) in the guide json node. Mutated in place, and used
119
+ // to validate the uniqueness of an extracted path encountered.
120
+ const uniqueFilePaths = {};
121
+ (0, _objectisomorphic.mapValuesDeep)(guideJson, (relpath, key, parts)=>{
122
+ // If not marked with the @suffix, there's nothing to do.
123
+ if (!_constisomorphic.FILEPATH_MARKED_RE.test(key)) return;
124
+ const objPathToFieldStr = _objectisomorphic.ObjPath.stringify(parts);
125
+ const inlinObjPathStr = objPathToFieldStr.replace(_constisomorphic.FILEPATH_MARKED_RE, "");
126
+ // If there is inlined content present already, then nothing more to do.
127
+ if ((0, _lodash.hasIn)(guideJson, inlinObjPathStr)) return;
128
+ // Check if the extracted path found at the current field path is valid
129
+ const invalidFilePathError = (0, _helpers.validateExtractedFilePath)(relpath, _nodepath.resolve(guideDirCtx.abspath, _processorisomorphic.GUIDE_JSON), uniqueFilePaths, objPathToFieldStr);
130
+ if (invalidFilePathError) {
131
+ errors.push(invalidFilePathError);
132
+ // Wipe the invalid file path in the node so the final guide json
133
+ // object ends up with only valid file paths, this way guide writer
134
+ // can see only valid file paths and use those when pulling.
135
+ (0, _lodash.set)(guideJson, inlinObjPathStr, undefined);
136
+ (0, _lodash.set)(guideJson, objPathToFieldStr, undefined);
137
+ return;
138
+ }
139
+ // By this point we have a valid extracted file path, so attempt to read the file.
140
+ const [content, readExtractedFileError] = (0, _helpers.readExtractedFileSync)(relpath, guideDirCtx, key);
141
+ if (readExtractedFileError) {
142
+ errors.push(readExtractedFileError);
143
+ // If there's an error, replace the extracted file path with the original one, and set the
144
+ // inlined field path in guide object with empty content, so we know
145
+ // we do not need to try inlining again.
146
+ (0, _lodash.set)(guideJson, objPathToFieldStr, relpath);
147
+ (0, _lodash.set)(guideJson, inlinObjPathStr, undefined);
148
+ return;
149
+ }
150
+ // Inline the file content and remove the extracted file path.
151
+ (0, _lodash.set)(guideJson, objPathToFieldStr, relpath);
152
+ (0, _lodash.set)(guideJson, inlinObjPathStr, content);
153
+ });
154
+ return [
155
+ guideJson,
156
+ errors
157
+ ];
158
+ };
159
+ const readAllForCommandTarget = async (target, opts = {})=>{
160
+ const { type: targetType, context: targetCtx } = target;
161
+ if (!targetCtx.exists) {
162
+ const subject = targetType === "guideDir" ? "a guide directory at" : "guide directories in";
163
+ return _core.ux.error(`Cannot locate ${subject} \`${targetCtx.abspath}\``);
164
+ }
165
+ switch(targetType){
166
+ case "guideDir":
167
+ {
168
+ return readGuideDirs([
169
+ targetCtx
170
+ ], opts);
171
+ }
172
+ case "guidesIndexDir":
173
+ {
174
+ const dirents = await _fsextra.readdir(targetCtx.abspath, {
175
+ withFileTypes: true
176
+ });
177
+ const promises = dirents.map(async (dirent)=>{
178
+ const abspath = _nodepath.resolve(targetCtx.abspath, dirent.name);
179
+ const guideDirCtx = {
180
+ type: "guide",
181
+ key: dirent.name,
182
+ abspath,
183
+ exists: await (0, _helpers1.isGuideDir)(abspath)
184
+ };
185
+ return guideDirCtx;
186
+ });
187
+ const guideDirCtxs = (await Promise.all(promises)).filter((guideDirCtx)=>guideDirCtx.exists);
188
+ return readGuideDirs(guideDirCtxs, opts);
189
+ }
190
+ default:
191
+ throw new Error(`Invalid guide command target: ${target}`);
192
+ }
193
+ };
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
+ });
10
+ }
11
+ _export(exports, {
12
+ get pruneGuidesIndexDir () {
13
+ return pruneGuidesIndexDir;
14
+ },
15
+ get writeGuideDirFromData () {
16
+ return writeGuideDirFromData;
17
+ },
18
+ get writeGuidesIndexDir () {
19
+ return writeGuidesIndexDir;
20
+ }
21
+ });
22
+ const _nodepath = /*#__PURE__*/ _interop_require_wildcard(require("node:path"));
23
+ const _fsextra = /*#__PURE__*/ _interop_require_wildcard(require("fs-extra"));
24
+ const _lodash = require("lodash");
25
+ const _const = require("../../helpers/const");
26
+ const _json = require("../../helpers/json");
27
+ const _helpers = require("./helpers");
28
+ const _processorisomorphic = require("./processor.isomorphic");
29
+ const _reader = require("./reader");
30
+ function _getRequireWildcardCache(nodeInterop) {
31
+ if (typeof WeakMap !== "function") return null;
32
+ var cacheBabelInterop = new WeakMap();
33
+ var cacheNodeInterop = new WeakMap();
34
+ return (_getRequireWildcardCache = function(nodeInterop) {
35
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
36
+ })(nodeInterop);
37
+ }
38
+ function _interop_require_wildcard(obj, nodeInterop) {
39
+ if (!nodeInterop && obj && obj.__esModule) {
40
+ return obj;
41
+ }
42
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
43
+ return {
44
+ default: obj
45
+ };
46
+ }
47
+ var cache = _getRequireWildcardCache(nodeInterop);
48
+ if (cache && cache.has(obj)) {
49
+ return cache.get(obj);
50
+ }
51
+ var newObj = {
52
+ __proto__: null
53
+ };
54
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
55
+ for(var key in obj){
56
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
57
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
58
+ if (desc && (desc.get || desc.set)) {
59
+ Object.defineProperty(newObj, key, desc);
60
+ } else {
61
+ newObj[key] = obj[key];
62
+ }
63
+ }
64
+ }
65
+ newObj.default = obj;
66
+ if (cache) {
67
+ cache.set(obj, newObj);
68
+ }
69
+ return newObj;
70
+ }
71
+ const writeGuideDirFromData = async (guideDirCtx, remoteGuide)=>{
72
+ // If the guide directory exists on the file system (i.e. previously
73
+ // pulled before), then read the guide file to use as a reference.
74
+ const [localGuide] = guideDirCtx.exists ? await (0, _reader.readGuideDir)(guideDirCtx, {
75
+ withExtractedFiles: true
76
+ }) : [];
77
+ const bundle = (0, _processorisomorphic.buildGuideDirBundle)(remoteGuide, localGuide);
78
+ return writeGuideDirFromBundle(guideDirCtx, bundle);
79
+ };
80
+ /*
81
+ * A lower level write function that takes a constructed guide dir bundle
82
+ * and writes it into a guide directory on a local file system.
83
+ *
84
+ * It does not make any assumptions about how the guide directory bundle was
85
+ * built; for example, it can be from parsing the guide data fetched from
86
+ * the Knock API, or built manually for scaffolding purposes.
87
+ */ const writeGuideDirFromBundle = async (guideDirCtx, guideDirBundle)=>{
88
+ const backupDirPath = _nodepath.resolve(_const.sandboxDir, (0, _lodash.uniqueId)("backup"));
89
+ try {
90
+ if (guideDirCtx.exists) {
91
+ await _fsextra.copy(guideDirCtx.abspath, backupDirPath);
92
+ await _fsextra.emptyDir(guideDirCtx.abspath);
93
+ }
94
+ const promises = Object.entries(guideDirBundle).map(([relpath, fileContent])=>{
95
+ const filePath = _nodepath.resolve(guideDirCtx.abspath, relpath);
96
+ return relpath === _processorisomorphic.GUIDE_JSON ? _fsextra.outputJson(filePath, fileContent, {
97
+ spaces: _json.DOUBLE_SPACES
98
+ }) : _fsextra.outputFile(filePath, fileContent !== null && fileContent !== void 0 ? fileContent : "");
99
+ });
100
+ await Promise.all(promises);
101
+ } catch (error) {
102
+ // In case of any error, wipe the target directory that is likely in a bad
103
+ // state then restore the backup if one existed before.
104
+ if (guideDirCtx.exists) {
105
+ await _fsextra.emptyDir(guideDirCtx.abspath);
106
+ await _fsextra.copy(backupDirPath, guideDirCtx.abspath);
107
+ } else {
108
+ await _fsextra.remove(guideDirCtx.abspath);
109
+ }
110
+ throw error;
111
+ } finally{
112
+ // Always clean up the backup directory in the temp sandbox.
113
+ await _fsextra.remove(backupDirPath);
114
+ }
115
+ };
116
+ /*
117
+ * Prunes the index directory by removing any files, or directories that aren't
118
+ * guide dirs found in fetched guides. We want to preserve any guide
119
+ * dirs that are going to be updated with remote guides, so extracted links
120
+ * can be respected.
121
+ */ const pruneGuidesIndexDir = async (indexDirCtx, remoteGuides)=>{
122
+ const guidesByKey = Object.fromEntries(remoteGuides.map((w)=>[
123
+ w.key.toLowerCase(),
124
+ w
125
+ ]));
126
+ const dirents = await _fsextra.readdir(indexDirCtx.abspath, {
127
+ withFileTypes: true
128
+ });
129
+ const promises = dirents.map(async (dirent)=>{
130
+ const direntName = dirent.name.toLowerCase();
131
+ const direntPath = _nodepath.resolve(indexDirCtx.abspath, direntName);
132
+ if (await (0, _helpers.isGuideDir)(direntPath) && guidesByKey[direntName]) {
133
+ return;
134
+ }
135
+ await _fsextra.remove(direntPath);
136
+ });
137
+ await Promise.all(promises);
138
+ };
139
+ const writeGuidesIndexDir = async (indexDirCtx, remoteGuides)=>{
140
+ const backupDirPath = _nodepath.resolve(_const.sandboxDir, (0, _lodash.uniqueId)("backup"));
141
+ try {
142
+ // If the index directory already exists, back it up in the temp sandbox
143
+ // before wiping it clean.
144
+ if (indexDirCtx.exists) {
145
+ await _fsextra.copy(indexDirCtx.abspath, backupDirPath);
146
+ await pruneGuidesIndexDir(indexDirCtx, remoteGuides);
147
+ }
148
+ // Write given remote guides into the given guides directory path.
149
+ const writeGuideDirPromises = remoteGuides.map(async (guide)=>{
150
+ const guideDirPath = _nodepath.resolve(indexDirCtx.abspath, guide.key);
151
+ const guideDirCtx = {
152
+ type: "guide",
153
+ key: guide.key,
154
+ abspath: guideDirPath,
155
+ exists: indexDirCtx.exists ? await (0, _helpers.isGuideDir)(guideDirPath) : false
156
+ };
157
+ return writeGuideDirFromData(guideDirCtx, guide);
158
+ });
159
+ await Promise.all(writeGuideDirPromises);
160
+ } catch (error) {
161
+ console.log(error);
162
+ // In case of any error, wipe the index directory that is likely in a bad
163
+ // state then restore the backup if one existed before.
164
+ if (indexDirCtx.exists) {
165
+ await _fsextra.emptyDir(indexDirCtx.abspath);
166
+ await _fsextra.copy(backupDirPath, indexDirCtx.abspath);
167
+ } else {
168
+ await _fsextra.remove(indexDirCtx.abspath);
169
+ }
170
+ throw error;
171
+ } finally{
172
+ // Always clean up the backup directory in the temp sandbox.
173
+ await _fsextra.remove(backupDirPath);
174
+ }
175
+ };