@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.
- package/README.md +141 -41
- package/dist/commands/commit/list.js +21 -1
- package/dist/commands/guide/activate.js +121 -0
- package/dist/commands/guide/generate-types.js +148 -0
- package/dist/commands/guide/get.js +139 -0
- package/dist/commands/guide/list.js +112 -0
- package/dist/commands/guide/pull.js +209 -0
- package/dist/commands/guide/push.js +171 -0
- package/dist/commands/guide/validate.js +148 -0
- package/dist/commands/pull.js +157 -0
- package/dist/commands/push.js +175 -0
- package/dist/commands/workflow/generate-types.js +6 -5
- package/dist/lib/api-v1.js +61 -0
- package/dist/lib/helpers/const.js +4 -4
- package/dist/lib/helpers/date.js +3 -3
- package/dist/lib/helpers/error.js +8 -8
- package/dist/lib/helpers/flag.js +7 -7
- package/dist/lib/helpers/json.js +5 -5
- package/dist/lib/helpers/object.isomorphic.js +8 -8
- package/dist/lib/helpers/page.js +9 -9
- package/dist/lib/helpers/request.js +4 -4
- package/dist/lib/helpers/string.js +3 -3
- package/dist/lib/helpers/typegen.js +59 -0
- package/dist/lib/helpers/ux.js +3 -3
- package/dist/lib/marshal/email-layout/helpers.js +5 -5
- package/dist/lib/marshal/email-layout/processor.isomorphic.js +3 -3
- package/dist/lib/marshal/email-layout/reader.js +5 -5
- package/dist/lib/marshal/email-layout/writer.js +4 -4
- package/dist/lib/marshal/guide/helpers.js +283 -0
- package/dist/lib/marshal/guide/index.js +3 -0
- package/dist/lib/marshal/guide/processor.isomorphic.js +3 -3
- package/dist/lib/marshal/guide/reader.js +193 -0
- package/dist/lib/marshal/guide/writer.js +175 -0
- package/dist/lib/marshal/index.isomorphic.js +7 -7
- package/dist/lib/marshal/message-type/helpers.js +5 -5
- package/dist/lib/marshal/message-type/processor.isomorphic.js +3 -3
- package/dist/lib/marshal/message-type/reader.js +5 -5
- package/dist/lib/marshal/message-type/writer.js +4 -4
- package/dist/lib/marshal/partial/helpers.js +5 -5
- package/dist/lib/marshal/partial/processor.isomorphic.js +3 -3
- package/dist/lib/marshal/partial/reader.js +5 -5
- package/dist/lib/marshal/partial/writer.js +4 -4
- package/dist/lib/marshal/shared/const.isomorphic.js +3 -3
- package/dist/lib/marshal/shared/helpers.isomorphic.js +9 -2
- package/dist/lib/marshal/shared/helpers.js +4 -4
- package/dist/lib/marshal/translation/helpers.js +10 -10
- package/dist/lib/marshal/translation/processor.isomorphic.js +6 -6
- package/dist/lib/marshal/translation/writer.js +3 -3
- package/dist/lib/marshal/workflow/generator.js +4 -4
- package/dist/lib/marshal/workflow/helpers.js +53 -10
- package/dist/lib/marshal/workflow/processor.isomorphic.js +5 -5
- package/dist/lib/marshal/workflow/reader.js +5 -5
- package/dist/lib/marshal/workflow/writer.js +5 -5
- package/dist/lib/resources.js +32 -0
- package/oclif.manifest.json +961 -260
- package/package.json +8 -8
- 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
|
|
15
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
18
|
_export(exports, {
|
|
19
|
-
GUIDE_JSON
|
|
19
|
+
get GUIDE_JSON () {
|
|
20
20
|
return GUIDE_JSON;
|
|
21
21
|
},
|
|
22
|
-
buildGuideDirBundle
|
|
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
|
+
};
|