@knocklabs/cli 0.1.3 → 0.1.5
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 +416 -9
- package/dist/commands/layout/get.js +98 -0
- package/dist/commands/layout/list.js +86 -0
- package/dist/commands/layout/pull.js +199 -0
- package/dist/commands/layout/push.js +159 -0
- package/dist/commands/layout/validate.js +134 -0
- package/dist/commands/workflow/get.js +39 -7
- package/dist/commands/workflow/list.js +4 -1
- package/dist/commands/workflow/run.js +6 -8
- package/dist/lib/api-v1.js +51 -2
- package/dist/lib/helpers/flag.js +19 -1
- package/dist/lib/helpers/json.js +9 -0
- package/dist/lib/marshal/email-layout/helpers.js +124 -0
- package/dist/lib/marshal/email-layout/index.js +19 -0
- package/dist/lib/marshal/email-layout/reader.js +193 -0
- package/dist/lib/marshal/email-layout/types.js +4 -0
- package/dist/lib/marshal/email-layout/writer.js +240 -0
- package/dist/lib/marshal/shared/helpers.js +135 -0
- package/dist/lib/marshal/workflow/generator.js +4 -2
- package/dist/lib/marshal/workflow/helpers.js +41 -6
- package/dist/lib/marshal/workflow/reader.js +8 -106
- package/dist/lib/marshal/workflow/types.js +2 -0
- package/dist/lib/marshal/workflow/writer.js +76 -40
- package/dist/lib/run-context/loader.js +11 -0
- package/oclif.manifest.json +338 -7
- package/package.json +13 -10
|
@@ -23,26 +23,24 @@ class WorkflowRun extends _baseCommand.default {
|
|
|
23
23
|
action: "‣ Running"
|
|
24
24
|
});
|
|
25
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}
|
|
26
|
+
this.log((0, _string.indentString)(`Workflow run id: ${resp.data.workflow_run_id}`, 4));
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
-
WorkflowRun.summary = "Test run a workflow using the latest version from Knock
|
|
29
|
+
WorkflowRun.summary = "Test run a workflow using the latest version from Knock.";
|
|
30
30
|
WorkflowRun.flags = {
|
|
31
31
|
environment: _core.Flags.string({
|
|
32
32
|
default: "development",
|
|
33
33
|
summary: "The environment in which to run the workflow"
|
|
34
34
|
}),
|
|
35
|
-
recipients:
|
|
35
|
+
recipients: (0, _flag.maybeJsonStrAsList)({
|
|
36
36
|
required: true,
|
|
37
37
|
aliases: [
|
|
38
38
|
"recipient"
|
|
39
39
|
],
|
|
40
|
-
summary: "One or more recipient ids for this workflow run
|
|
41
|
-
multiple: true,
|
|
42
|
-
delimiter: ","
|
|
40
|
+
summary: "One or more recipient user ids separated by comma, or a JSON string containing one or more recipient object references for this workflow run."
|
|
43
41
|
}),
|
|
44
|
-
actor:
|
|
45
|
-
summary: "An actor id for the workflow run."
|
|
42
|
+
actor: (0, _flag.maybeJsonStr)({
|
|
43
|
+
summary: "An actor id, or a JSON string of an actor object reference for the workflow run."
|
|
46
44
|
}),
|
|
47
45
|
tenant: _core.Flags.string({
|
|
48
46
|
summary: "A tenant id for the workflow run."
|
package/dist/lib/api-v1.js
CHANGED
|
@@ -81,13 +81,15 @@ class ApiV1 {
|
|
|
81
81
|
}
|
|
82
82
|
async runWorkflow({ args , flags }) {
|
|
83
83
|
const params = (0, _object.prune)({
|
|
84
|
-
environment: flags.environment
|
|
84
|
+
environment: flags.environment
|
|
85
|
+
});
|
|
86
|
+
const data = (0, _object.prune)({
|
|
85
87
|
recipients: flags.recipients,
|
|
86
88
|
tenant: flags.tenant,
|
|
87
89
|
data: flags.data,
|
|
88
90
|
actor: flags.actor
|
|
89
91
|
});
|
|
90
|
-
return this.put(`/workflows/${args.workflowKey}/run`,
|
|
92
|
+
return this.put(`/workflows/${args.workflowKey}/run`, data, {
|
|
91
93
|
params
|
|
92
94
|
});
|
|
93
95
|
}
|
|
@@ -157,6 +159,53 @@ class ApiV1 {
|
|
|
157
159
|
params
|
|
158
160
|
});
|
|
159
161
|
}
|
|
162
|
+
// By resources: Email layouts
|
|
163
|
+
async listEmailLayouts({ flags }) {
|
|
164
|
+
const params = (0, _object.prune)({
|
|
165
|
+
environment: flags.environment,
|
|
166
|
+
annotate: flags.annotate,
|
|
167
|
+
hide_uncommitted_changes: flags["hide-uncommitted-changes"],
|
|
168
|
+
...(0, _page.toPageParams)(flags)
|
|
169
|
+
});
|
|
170
|
+
return this.get("/email_layouts", {
|
|
171
|
+
params
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
async getEmailLayout({ args , flags }) {
|
|
175
|
+
const params = (0, _object.prune)({
|
|
176
|
+
environment: flags.environment,
|
|
177
|
+
annotate: flags.annotate,
|
|
178
|
+
hide_uncommitted_changes: flags["hide-uncommitted-changes"]
|
|
179
|
+
});
|
|
180
|
+
return this.get(`/email_layouts/${args.emailLayoutKey}`, {
|
|
181
|
+
params
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
async upsertEmailLayout({ flags }, layout) {
|
|
185
|
+
const params = (0, _object.prune)({
|
|
186
|
+
environment: flags.environment,
|
|
187
|
+
annotate: flags.annotate,
|
|
188
|
+
commit: flags.commit,
|
|
189
|
+
commit_message: flags["commit-message"]
|
|
190
|
+
});
|
|
191
|
+
const data = {
|
|
192
|
+
email_layout: layout
|
|
193
|
+
};
|
|
194
|
+
return this.put(`/email_layouts/${layout.key}`, data, {
|
|
195
|
+
params
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
async validateEmailLayout({ flags }, layout) {
|
|
199
|
+
const params = (0, _object.prune)({
|
|
200
|
+
environment: flags.environment
|
|
201
|
+
});
|
|
202
|
+
const data = {
|
|
203
|
+
email_layout: layout
|
|
204
|
+
};
|
|
205
|
+
return this.put(`/email_layouts/${layout.key}/validate`, data, {
|
|
206
|
+
params
|
|
207
|
+
});
|
|
208
|
+
}
|
|
160
209
|
// By methods:
|
|
161
210
|
async get(subpath, config) {
|
|
162
211
|
return this.client.get(`/${API_VERSION}` + subpath, config);
|
package/dist/lib/helpers/flag.js
CHANGED
|
@@ -11,11 +11,14 @@ function _export(target, all) {
|
|
|
11
11
|
_export(exports, {
|
|
12
12
|
booleanStr: ()=>booleanStr,
|
|
13
13
|
dirPath: ()=>dirPath,
|
|
14
|
-
jsonStr: ()=>jsonStr
|
|
14
|
+
jsonStr: ()=>jsonStr,
|
|
15
|
+
maybeJsonStr: ()=>maybeJsonStr,
|
|
16
|
+
maybeJsonStrAsList: ()=>maybeJsonStrAsList
|
|
15
17
|
});
|
|
16
18
|
const _nodePath = /*#__PURE__*/ _interopRequireWildcard(require("node:path"));
|
|
17
19
|
const _core = require("@oclif/core");
|
|
18
20
|
const _fsExtra = /*#__PURE__*/ _interopRequireWildcard(require("fs-extra"));
|
|
21
|
+
const _json = require("./json");
|
|
19
22
|
function _getRequireWildcardCache(nodeInterop) {
|
|
20
23
|
if (typeof WeakMap !== "function") return null;
|
|
21
24
|
var cacheBabelInterop = new WeakMap();
|
|
@@ -85,3 +88,18 @@ const jsonStr = _core.Flags.custom({
|
|
|
85
88
|
}
|
|
86
89
|
}
|
|
87
90
|
});
|
|
91
|
+
const maybeJsonStr = _core.Flags.custom({
|
|
92
|
+
parse: async (input)=>{
|
|
93
|
+
return (0, _json.tryJsonParse)(input);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
const maybeJsonStrAsList = _core.Flags.custom({
|
|
97
|
+
parse: async (input)=>{
|
|
98
|
+
const data = (0, _json.tryJsonParse)(input);
|
|
99
|
+
if (typeof data === "string") return data.split(",");
|
|
100
|
+
if (Array.isArray(data)) return data;
|
|
101
|
+
return [
|
|
102
|
+
data
|
|
103
|
+
];
|
|
104
|
+
}
|
|
105
|
+
});
|
package/dist/lib/helpers/json.js
CHANGED
|
@@ -11,6 +11,7 @@ function _export(target, all) {
|
|
|
11
11
|
_export(exports, {
|
|
12
12
|
DOUBLE_SPACES: ()=>DOUBLE_SPACES,
|
|
13
13
|
parseJson: ()=>parseJson,
|
|
14
|
+
tryJsonParse: ()=>tryJsonParse,
|
|
14
15
|
readJson: ()=>readJson
|
|
15
16
|
});
|
|
16
17
|
const _jsonlint = /*#__PURE__*/ _interopRequireWildcard(require("@prantlf/jsonlint"));
|
|
@@ -71,6 +72,14 @@ const parseJson = (json)=>{
|
|
|
71
72
|
errors
|
|
72
73
|
];
|
|
73
74
|
};
|
|
75
|
+
const tryJsonParse = (maybeJson)=>{
|
|
76
|
+
try {
|
|
77
|
+
const data = JSON.parse(maybeJson);
|
|
78
|
+
return data;
|
|
79
|
+
} catch {
|
|
80
|
+
return maybeJson;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
74
83
|
const readJson = async (filePath)=>{
|
|
75
84
|
const json = await _fsExtra.readFile(filePath, "utf8");
|
|
76
85
|
return parseJson(json);
|
|
@@ -0,0 +1,124 @@
|
|
|
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: all[name]
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
LAYOUT_JSON: ()=>LAYOUT_JSON,
|
|
13
|
+
emailLayoutJsonPath: ()=>emailLayoutJsonPath,
|
|
14
|
+
isEmailLayoutDir: ()=>isEmailLayoutDir,
|
|
15
|
+
lsEmailLayoutJson: ()=>lsEmailLayoutJson,
|
|
16
|
+
ensureValidCommandTarget: ()=>ensureValidCommandTarget
|
|
17
|
+
});
|
|
18
|
+
const _nodePath = /*#__PURE__*/ _interopRequireWildcard(require("node:path"));
|
|
19
|
+
const _core = require("@oclif/core");
|
|
20
|
+
const _fsExtra = /*#__PURE__*/ _interopRequireWildcard(require("fs-extra"));
|
|
21
|
+
function _getRequireWildcardCache(nodeInterop) {
|
|
22
|
+
if (typeof WeakMap !== "function") return null;
|
|
23
|
+
var cacheBabelInterop = new WeakMap();
|
|
24
|
+
var cacheNodeInterop = new WeakMap();
|
|
25
|
+
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
26
|
+
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
27
|
+
})(nodeInterop);
|
|
28
|
+
}
|
|
29
|
+
function _interopRequireWildcard(obj, nodeInterop) {
|
|
30
|
+
if (!nodeInterop && obj && obj.__esModule) {
|
|
31
|
+
return obj;
|
|
32
|
+
}
|
|
33
|
+
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
34
|
+
return {
|
|
35
|
+
default: obj
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
var cache = _getRequireWildcardCache(nodeInterop);
|
|
39
|
+
if (cache && cache.has(obj)) {
|
|
40
|
+
return cache.get(obj);
|
|
41
|
+
}
|
|
42
|
+
var newObj = {};
|
|
43
|
+
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
44
|
+
for(var key in obj){
|
|
45
|
+
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
46
|
+
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
47
|
+
if (desc && (desc.get || desc.set)) {
|
|
48
|
+
Object.defineProperty(newObj, key, desc);
|
|
49
|
+
} else {
|
|
50
|
+
newObj[key] = obj[key];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
newObj.default = obj;
|
|
55
|
+
if (cache) {
|
|
56
|
+
cache.set(obj, newObj);
|
|
57
|
+
}
|
|
58
|
+
return newObj;
|
|
59
|
+
}
|
|
60
|
+
const LAYOUT_JSON = "layout.json";
|
|
61
|
+
const emailLayoutJsonPath = (layoutDirCtx)=>_nodePath.resolve(layoutDirCtx.abspath, LAYOUT_JSON);
|
|
62
|
+
const isEmailLayoutDir = async (dirPath)=>Boolean(await lsEmailLayoutJson(dirPath));
|
|
63
|
+
const lsEmailLayoutJson = async (dirPath)=>{
|
|
64
|
+
const emailLayoutJsonPath = _nodePath.resolve(dirPath, LAYOUT_JSON);
|
|
65
|
+
const exists = await _fsExtra.pathExists(emailLayoutJsonPath);
|
|
66
|
+
return exists ? emailLayoutJsonPath : undefined;
|
|
67
|
+
};
|
|
68
|
+
const ensureValidCommandTarget = async (props, runContext)=>{
|
|
69
|
+
const { args , flags } = props;
|
|
70
|
+
const { commandId , resourceDir: resourceDirCtx , cwd: runCwd } = runContext;
|
|
71
|
+
// If the target resource is a different type than the current resource dir
|
|
72
|
+
// type, error out.
|
|
73
|
+
if (resourceDirCtx && resourceDirCtx.type !== "email_layout") {
|
|
74
|
+
return _core.ux.error(`Cannot run ${commandId} inside a ${resourceDirCtx.type} directory`);
|
|
75
|
+
}
|
|
76
|
+
// Cannot accept both email layout key arg and --all flag.
|
|
77
|
+
if (flags.all && args.emailLayoutKey) {
|
|
78
|
+
return _core.ux.error(`emailLayoutKey arg \`${args.emailLayoutKey}\` cannot also be provided when using --all`);
|
|
79
|
+
}
|
|
80
|
+
// --all flag is given, which means no layout key arg.
|
|
81
|
+
if (flags.all) {
|
|
82
|
+
// If --all flag used inside a layout directory, then require a layouts dir path.
|
|
83
|
+
if (resourceDirCtx && !flags["layouts-dir"]) {
|
|
84
|
+
return _core.ux.error("Missing required flag layouts-dir");
|
|
85
|
+
}
|
|
86
|
+
// Targeting all layout dirs in the layouts index dir.
|
|
87
|
+
// TODO: Default to the knock project config first if present before cwd.
|
|
88
|
+
const defaultToCwd = {
|
|
89
|
+
abspath: runCwd,
|
|
90
|
+
exists: true
|
|
91
|
+
};
|
|
92
|
+
const indexDirCtx = flags["layouts-dir"] || defaultToCwd;
|
|
93
|
+
return {
|
|
94
|
+
type: "emailLayoutsIndexDir",
|
|
95
|
+
context: indexDirCtx
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
// Email layout key arg is given, which means no --all flag.
|
|
99
|
+
if (args.emailLayoutKey) {
|
|
100
|
+
if (resourceDirCtx && resourceDirCtx.key !== args.emailLayoutKey) {
|
|
101
|
+
return _core.ux.error(`Cannot run ${commandId} \`${args.emailLayoutKey}\` inside another layout directory:\n${resourceDirCtx.key}`);
|
|
102
|
+
}
|
|
103
|
+
const targetDirPath = resourceDirCtx ? resourceDirCtx.abspath : _nodePath.resolve(runCwd, args.emailLayoutKey);
|
|
104
|
+
const layoutDirCtx = {
|
|
105
|
+
type: "email_layout",
|
|
106
|
+
key: args.emailLayoutKey,
|
|
107
|
+
abspath: targetDirPath,
|
|
108
|
+
exists: await isEmailLayoutDir(targetDirPath)
|
|
109
|
+
};
|
|
110
|
+
return {
|
|
111
|
+
type: "emailLayoutDir",
|
|
112
|
+
context: layoutDirCtx
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
// From this point on, we have neither an email layout key arg nor --all flag.
|
|
116
|
+
// If running inside a layout directory, then use that.
|
|
117
|
+
if (resourceDirCtx) {
|
|
118
|
+
return {
|
|
119
|
+
type: "emailLayoutDir",
|
|
120
|
+
context: resourceDirCtx
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
return _core.ux.error("Missing 1 required arg:emailLayoutKey");
|
|
124
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
_exportStar(require("./helpers"), exports);
|
|
6
|
+
_exportStar(require("./reader"), exports);
|
|
7
|
+
_exportStar(require("./types"), exports);
|
|
8
|
+
_exportStar(require("./writer"), exports);
|
|
9
|
+
function _exportStar(from, to) {
|
|
10
|
+
Object.keys(from).forEach(function(k) {
|
|
11
|
+
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) Object.defineProperty(to, k, {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: function() {
|
|
14
|
+
return from[k];
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
return from;
|
|
19
|
+
}
|
|
@@ -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: all[name]
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
readAllForCommandTarget: ()=>readAllForCommandTarget,
|
|
13
|
+
readEmailLayoutDir: ()=>readEmailLayoutDir
|
|
14
|
+
});
|
|
15
|
+
const _nodePath = /*#__PURE__*/ _interopRequireDefault(require("node:path"));
|
|
16
|
+
const _core = require("@oclif/core");
|
|
17
|
+
const _fsExtra = /*#__PURE__*/ _interopRequireWildcard(require("fs-extra"));
|
|
18
|
+
const _lodash = require("lodash");
|
|
19
|
+
const _error = require("../../helpers/error");
|
|
20
|
+
const _json = require("../../helpers/json");
|
|
21
|
+
const _object = require("../../helpers/object");
|
|
22
|
+
const _helpers = require("../shared/helpers");
|
|
23
|
+
const _helpers1 = require("./helpers");
|
|
24
|
+
function _interopRequireDefault(obj) {
|
|
25
|
+
return obj && obj.__esModule ? obj : {
|
|
26
|
+
default: obj
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function _getRequireWildcardCache(nodeInterop) {
|
|
30
|
+
if (typeof WeakMap !== "function") return null;
|
|
31
|
+
var cacheBabelInterop = new WeakMap();
|
|
32
|
+
var cacheNodeInterop = new WeakMap();
|
|
33
|
+
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
34
|
+
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
35
|
+
})(nodeInterop);
|
|
36
|
+
}
|
|
37
|
+
function _interopRequireWildcard(obj, nodeInterop) {
|
|
38
|
+
if (!nodeInterop && obj && obj.__esModule) {
|
|
39
|
+
return obj;
|
|
40
|
+
}
|
|
41
|
+
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
42
|
+
return {
|
|
43
|
+
default: obj
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
var cache = _getRequireWildcardCache(nodeInterop);
|
|
47
|
+
if (cache && cache.has(obj)) {
|
|
48
|
+
return cache.get(obj);
|
|
49
|
+
}
|
|
50
|
+
var newObj = {};
|
|
51
|
+
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
52
|
+
for(var key in obj){
|
|
53
|
+
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
54
|
+
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
55
|
+
if (desc && (desc.get || desc.set)) {
|
|
56
|
+
Object.defineProperty(newObj, key, desc);
|
|
57
|
+
} else {
|
|
58
|
+
newObj[key] = obj[key];
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
newObj.default = obj;
|
|
63
|
+
if (cache) {
|
|
64
|
+
cache.set(obj, newObj);
|
|
65
|
+
}
|
|
66
|
+
return newObj;
|
|
67
|
+
}
|
|
68
|
+
const readAllForCommandTarget = async (target, opts = {})=>{
|
|
69
|
+
const { type: targetType , context: targetCtx } = target;
|
|
70
|
+
if (!targetCtx.exists) {
|
|
71
|
+
const subject = targetType === "emailLayoutDir" ? "a layout directory at" : "layout directories in";
|
|
72
|
+
return _core.ux.error(`Cannot locate ${subject} \`${targetCtx.abspath}\``);
|
|
73
|
+
}
|
|
74
|
+
switch(targetType){
|
|
75
|
+
case "emailLayoutDir":
|
|
76
|
+
{
|
|
77
|
+
return readEmailLayoutsDirs([
|
|
78
|
+
targetCtx
|
|
79
|
+
], opts);
|
|
80
|
+
}
|
|
81
|
+
case "emailLayoutsIndexDir":
|
|
82
|
+
{
|
|
83
|
+
const dirents = await _fsExtra.readdir(targetCtx.abspath, {
|
|
84
|
+
withFileTypes: true
|
|
85
|
+
});
|
|
86
|
+
const promises = dirents.map(async (dirent)=>{
|
|
87
|
+
const abspath = _nodePath.default.resolve(targetCtx.abspath, dirent.name);
|
|
88
|
+
const layoutDirCtx = {
|
|
89
|
+
type: "email_layout",
|
|
90
|
+
key: dirent.name,
|
|
91
|
+
abspath,
|
|
92
|
+
exists: await (0, _helpers1.isEmailLayoutDir)(abspath)
|
|
93
|
+
};
|
|
94
|
+
return layoutDirCtx;
|
|
95
|
+
});
|
|
96
|
+
const layoutDirCtxs = (await Promise.all(promises)).filter((layoutDirCtx)=>layoutDirCtx.exists);
|
|
97
|
+
return readEmailLayoutsDirs(layoutDirCtxs, opts);
|
|
98
|
+
}
|
|
99
|
+
default:
|
|
100
|
+
throw new Error(`Invalid layout command target: ${target}`);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
/*
|
|
104
|
+
* For the given list of layout directory contexts, read each layout dir and
|
|
105
|
+
* return layout directory data.
|
|
106
|
+
*/ const readEmailLayoutsDirs = async (layoutDirCtxs, opts = {})=>{
|
|
107
|
+
const layouts = [];
|
|
108
|
+
const errors = [];
|
|
109
|
+
for (const layoutDirCtx of layoutDirCtxs){
|
|
110
|
+
// eslint-disable-next-line no-await-in-loop
|
|
111
|
+
const [layout, readErrors] = await readEmailLayoutDir(layoutDirCtx, opts);
|
|
112
|
+
if (readErrors.length > 0) {
|
|
113
|
+
const layoutJsonPath = _nodePath.default.resolve(layoutDirCtx.abspath, _helpers1.LAYOUT_JSON);
|
|
114
|
+
const e = new _error.SourceError((0, _error.formatErrors)(readErrors), layoutJsonPath);
|
|
115
|
+
errors.push(e);
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
layouts.push({
|
|
119
|
+
...layoutDirCtx,
|
|
120
|
+
content: layout
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
return [
|
|
124
|
+
layouts,
|
|
125
|
+
errors
|
|
126
|
+
];
|
|
127
|
+
};
|
|
128
|
+
const readEmailLayoutDir = async (layoutDirCtx, opts = {})=>{
|
|
129
|
+
const { abspath } = layoutDirCtx;
|
|
130
|
+
const { withExtractedFiles =false , withReadonlyField =false } = opts;
|
|
131
|
+
const dirExists = await _fsExtra.pathExists(abspath);
|
|
132
|
+
if (!dirExists) throw new Error(`${abspath} does not exist`);
|
|
133
|
+
const layoutJsonPath = await (0, _helpers1.lsEmailLayoutJson)(abspath);
|
|
134
|
+
if (!layoutJsonPath) throw new Error(`${abspath} is not a layout directory`);
|
|
135
|
+
const result = await (0, _json.readJson)(layoutJsonPath);
|
|
136
|
+
if (!result[0]) return result;
|
|
137
|
+
let [layoutJson] = result;
|
|
138
|
+
layoutJson = withReadonlyField ? layoutJson : (0, _object.omitDeep)(layoutJson, [
|
|
139
|
+
"__readonly"
|
|
140
|
+
]);
|
|
141
|
+
return withExtractedFiles ? joinExtractedFiles(layoutDirCtx, layoutJson) : [
|
|
142
|
+
layoutJson,
|
|
143
|
+
[]
|
|
144
|
+
];
|
|
145
|
+
};
|
|
146
|
+
/*
|
|
147
|
+
* Given a layout json object, compiles all referenced extracted files from it
|
|
148
|
+
* and returns the updated object with the extracted content joined and inlined.
|
|
149
|
+
*/ const joinExtractedFiles = async (layoutDirCtx, layoutJson)=>{
|
|
150
|
+
// Tracks any errors encountered during traversal. Mutated in place.
|
|
151
|
+
const errors = [];
|
|
152
|
+
// Tracks each new valid extracted file path seen (rebased to be relative to
|
|
153
|
+
// layout.json) in the layout json node. Mutated in place, and used
|
|
154
|
+
// to validate the uniqueness of an extracted path encountered.
|
|
155
|
+
const uniqueFilePaths = {};
|
|
156
|
+
(0, _object.mapValuesDeep)(layoutJson, (relpath, key, parts)=>{
|
|
157
|
+
// If not marked with the @suffix, there's nothing to do.
|
|
158
|
+
if (!_helpers.FILEPATH_MARKED_RE.test(key)) return;
|
|
159
|
+
const objPathToFieldStr = _object.ObjPath.stringify(parts);
|
|
160
|
+
const inlinObjPathStr = objPathToFieldStr.replace(_helpers.FILEPATH_MARKED_RE, "");
|
|
161
|
+
// If there is inlined content present already, then nothing more to do.
|
|
162
|
+
if ((0, _lodash.hasIn)(layoutJson, inlinObjPathStr)) return;
|
|
163
|
+
// Check if the extracted path found at the current field path is valid
|
|
164
|
+
const invalidFilePathError = (0, _helpers.validateExtractedFilePath)(relpath, _nodePath.default.resolve(layoutDirCtx.abspath, _helpers1.LAYOUT_JSON), uniqueFilePaths, objPathToFieldStr);
|
|
165
|
+
if (invalidFilePathError) {
|
|
166
|
+
errors.push(invalidFilePathError);
|
|
167
|
+
// Wipe the invalid file path in the node so the final layout json
|
|
168
|
+
// object ends up with only valid file paths, this way layout writer
|
|
169
|
+
// can see only valid file paths and use those when pulling.
|
|
170
|
+
(0, _lodash.set)(layoutJson, inlinObjPathStr, undefined);
|
|
171
|
+
(0, _lodash.set)(layoutJson, objPathToFieldStr, undefined);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
// By this point we have a valid extracted file path, so attempt to read the file.
|
|
175
|
+
const [content, readExtractedFileError] = (0, _helpers.readExtractedFileSync)(relpath, layoutDirCtx, key);
|
|
176
|
+
if (readExtractedFileError) {
|
|
177
|
+
errors.push(readExtractedFileError);
|
|
178
|
+
// If there's an error, replace the extracted file path with the original one, and set the
|
|
179
|
+
// inlined field path in layout object with empty content, so we know
|
|
180
|
+
// we do not need to try inlining again.
|
|
181
|
+
(0, _lodash.set)(layoutJson, objPathToFieldStr, relpath);
|
|
182
|
+
(0, _lodash.set)(layoutJson, inlinObjPathStr, undefined);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
// Inline the file content and remove the extracted file path.
|
|
186
|
+
(0, _lodash.set)(layoutJson, objPathToFieldStr, relpath);
|
|
187
|
+
(0, _lodash.set)(layoutJson, inlinObjPathStr, content);
|
|
188
|
+
});
|
|
189
|
+
return [
|
|
190
|
+
layoutJson,
|
|
191
|
+
errors
|
|
192
|
+
];
|
|
193
|
+
};
|