@knocklabs/cli 0.3.0 → 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.
- package/README.md +505 -162
- package/dist/commands/branch/create.js +0 -2
- package/dist/commands/branch/delete.js +4 -3
- package/dist/commands/branch/exit.js +0 -2
- package/dist/commands/branch/list.js +0 -2
- package/dist/commands/branch/merge.js +82 -0
- package/dist/commands/branch/switch.js +0 -2
- package/dist/commands/channel/list.js +73 -0
- package/dist/commands/environment/list.js +73 -0
- package/dist/commands/guide/new.js +276 -0
- package/dist/commands/guide/pull.js +5 -6
- package/dist/commands/guide/push.js +1 -1
- package/dist/commands/guide/validate.js +1 -1
- package/dist/commands/init.js +108 -0
- package/dist/commands/layout/new.js +228 -0
- package/dist/commands/layout/pull.js +5 -6
- package/dist/commands/layout/push.js +1 -1
- package/dist/commands/layout/validate.js +1 -1
- package/dist/commands/message-type/new.js +228 -0
- package/dist/commands/message-type/pull.js +5 -6
- package/dist/commands/message-type/push.js +1 -1
- package/dist/commands/message-type/validate.js +1 -1
- package/dist/commands/partial/new.js +274 -0
- package/dist/commands/partial/pull.js +5 -6
- package/dist/commands/partial/push.js +1 -1
- package/dist/commands/partial/validate.js +1 -1
- package/dist/commands/pull.js +7 -2
- package/dist/commands/push.js +6 -4
- package/dist/commands/translation/pull.js +1 -1
- package/dist/commands/translation/push.js +1 -1
- package/dist/commands/translation/validate.js +1 -1
- package/dist/commands/workflow/new.js +179 -54
- package/dist/commands/workflow/pull.js +6 -8
- package/dist/commands/workflow/push.js +1 -1
- package/dist/commands/workflow/validate.js +1 -1
- package/dist/lib/api-v1.js +23 -2
- package/dist/lib/auth.js +1 -1
- package/dist/lib/base-command.js +18 -15
- package/dist/lib/helpers/flag.js +0 -2
- package/dist/lib/helpers/project-config.js +158 -0
- package/dist/lib/helpers/request.js +1 -2
- package/dist/lib/helpers/string.js +4 -4
- package/dist/lib/helpers/typegen.js +1 -1
- package/dist/lib/marshal/email-layout/generator.js +152 -0
- package/dist/lib/marshal/email-layout/helpers.js +6 -9
- package/dist/lib/marshal/email-layout/index.js +1 -0
- package/dist/lib/marshal/email-layout/writer.js +15 -3
- package/dist/lib/marshal/guide/generator.js +163 -0
- package/dist/lib/marshal/guide/helpers.js +6 -10
- package/dist/lib/marshal/guide/index.js +1 -0
- package/dist/lib/marshal/guide/writer.js +5 -9
- package/dist/lib/marshal/message-type/generator.js +139 -0
- package/dist/lib/marshal/message-type/helpers.js +6 -10
- package/dist/lib/marshal/message-type/index.js +1 -0
- package/dist/lib/marshal/message-type/writer.js +5 -1
- package/dist/lib/marshal/partial/generator.js +159 -0
- package/dist/lib/marshal/partial/helpers.js +6 -10
- package/dist/lib/marshal/partial/index.js +1 -0
- package/dist/lib/marshal/partial/writer.js +3 -0
- package/dist/lib/marshal/translation/helpers.js +6 -10
- package/dist/lib/marshal/translation/processor.isomorphic.js +4 -4
- package/dist/lib/marshal/translation/writer.js +2 -2
- package/dist/lib/marshal/workflow/generator.js +175 -19
- package/dist/lib/marshal/workflow/helpers.js +7 -10
- package/dist/lib/run-context/loader.js +5 -0
- package/dist/lib/templates.js +131 -0
- package/oclif.manifest.json +826 -266
- package/package.json +14 -9
|
@@ -0,0 +1,158 @@
|
|
|
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 PROJECT_CONFIG_FILE_NAME () {
|
|
13
|
+
return PROJECT_CONFIG_FILE_NAME;
|
|
14
|
+
},
|
|
15
|
+
get ResourceDirectoriesByType () {
|
|
16
|
+
return ResourceDirectoriesByType;
|
|
17
|
+
},
|
|
18
|
+
get findAndReadProjectConfig () {
|
|
19
|
+
return findAndReadProjectConfig;
|
|
20
|
+
},
|
|
21
|
+
get findProjectConfig () {
|
|
22
|
+
return findProjectConfig;
|
|
23
|
+
},
|
|
24
|
+
get readProjectConfig () {
|
|
25
|
+
return readProjectConfig;
|
|
26
|
+
},
|
|
27
|
+
get resolveKnockDir () {
|
|
28
|
+
return resolveKnockDir;
|
|
29
|
+
},
|
|
30
|
+
get resolveResourceDir () {
|
|
31
|
+
return resolveResourceDir;
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
const _nodepath = /*#__PURE__*/ _interop_require_wildcard(require("node:path"));
|
|
35
|
+
const _findup = /*#__PURE__*/ _interop_require_default(require("find-up"));
|
|
36
|
+
const _fsextra = /*#__PURE__*/ _interop_require_wildcard(require("fs-extra"));
|
|
37
|
+
const _zod = require("zod");
|
|
38
|
+
const _fs = require("./fs");
|
|
39
|
+
function _interop_require_default(obj) {
|
|
40
|
+
return obj && obj.__esModule ? obj : {
|
|
41
|
+
default: obj
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function _getRequireWildcardCache(nodeInterop) {
|
|
45
|
+
if (typeof WeakMap !== "function") return null;
|
|
46
|
+
var cacheBabelInterop = new WeakMap();
|
|
47
|
+
var cacheNodeInterop = new WeakMap();
|
|
48
|
+
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
49
|
+
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
50
|
+
})(nodeInterop);
|
|
51
|
+
}
|
|
52
|
+
function _interop_require_wildcard(obj, nodeInterop) {
|
|
53
|
+
if (!nodeInterop && obj && obj.__esModule) {
|
|
54
|
+
return obj;
|
|
55
|
+
}
|
|
56
|
+
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
57
|
+
return {
|
|
58
|
+
default: obj
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
var cache = _getRequireWildcardCache(nodeInterop);
|
|
62
|
+
if (cache && cache.has(obj)) {
|
|
63
|
+
return cache.get(obj);
|
|
64
|
+
}
|
|
65
|
+
var newObj = {
|
|
66
|
+
__proto__: null
|
|
67
|
+
};
|
|
68
|
+
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
69
|
+
for(var key in obj){
|
|
70
|
+
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
71
|
+
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
72
|
+
if (desc && (desc.get || desc.set)) {
|
|
73
|
+
Object.defineProperty(newObj, key, desc);
|
|
74
|
+
} else {
|
|
75
|
+
newObj[key] = obj[key];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
newObj.default = obj;
|
|
80
|
+
if (cache) {
|
|
81
|
+
cache.set(obj, newObj);
|
|
82
|
+
}
|
|
83
|
+
return newObj;
|
|
84
|
+
}
|
|
85
|
+
const PROJECT_CONFIG_FILE_NAME = "knock.json";
|
|
86
|
+
/**
|
|
87
|
+
* Schema for the project configuration file.
|
|
88
|
+
*/ const projectConfigSchema = _zod.z.object({
|
|
89
|
+
knockDir: _zod.z.string()
|
|
90
|
+
});
|
|
91
|
+
const findProjectConfig = async ()=>{
|
|
92
|
+
const configPath = await (0, _findup.default)(PROJECT_CONFIG_FILE_NAME);
|
|
93
|
+
return configPath;
|
|
94
|
+
};
|
|
95
|
+
const readProjectConfig = async (configPath)=>{
|
|
96
|
+
const rawConfig = await _fsextra.readJSON(configPath);
|
|
97
|
+
const config = projectConfigSchema.parse(rawConfig);
|
|
98
|
+
return config;
|
|
99
|
+
};
|
|
100
|
+
const resolveKnockDir = async (knockDirFlag, projectConfig)=>{
|
|
101
|
+
if (knockDirFlag) {
|
|
102
|
+
return knockDirFlag;
|
|
103
|
+
}
|
|
104
|
+
if (!projectConfig) {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
// Project configuration exists, must is invalid. So we error out.
|
|
108
|
+
if ([
|
|
109
|
+
"",
|
|
110
|
+
undefined,
|
|
111
|
+
null
|
|
112
|
+
].includes(projectConfig.knockDir)) {
|
|
113
|
+
throw new Error("No knock directory specified in the project configuration");
|
|
114
|
+
}
|
|
115
|
+
const abspath = _nodepath.isAbsolute(projectConfig.knockDir) ? projectConfig.knockDir : _nodepath.resolve(process.cwd(), projectConfig.knockDir);
|
|
116
|
+
const exists = await _fsextra.pathExists(abspath);
|
|
117
|
+
if (!exists || !await (0, _fs.isDirectory)(abspath)) {
|
|
118
|
+
throw new Error(`${projectConfig.knockDir} does not exist or is not a directory`);
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
abspath,
|
|
122
|
+
exists
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
const findAndReadProjectConfig = async ()=>{
|
|
126
|
+
const configPath = await findProjectConfig();
|
|
127
|
+
if (!configPath) {
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
return readProjectConfig(configPath);
|
|
131
|
+
};
|
|
132
|
+
const ResourceDirectoriesByType = {
|
|
133
|
+
workflow: "workflows",
|
|
134
|
+
guide: "guides",
|
|
135
|
+
partial: "partials",
|
|
136
|
+
email_layout: "layouts",
|
|
137
|
+
message_type: "message-types",
|
|
138
|
+
translation: "translations"
|
|
139
|
+
};
|
|
140
|
+
const resolveResourceDir = async (projectConfig, resourceType, basePath = process.cwd())=>{
|
|
141
|
+
if (!projectConfig) {
|
|
142
|
+
return {
|
|
143
|
+
abspath: basePath,
|
|
144
|
+
exists: true
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
const absoluteKnockDir = _nodepath.isAbsolute(projectConfig.knockDir) ? projectConfig.knockDir : _nodepath.resolve(basePath, projectConfig.knockDir);
|
|
148
|
+
const resourceDir = ResourceDirectoriesByType[resourceType];
|
|
149
|
+
const absResourceDirPath = _nodepath.resolve(absoluteKnockDir, resourceDir);
|
|
150
|
+
const exists = await _fsextra.pathExists(absResourceDirPath);
|
|
151
|
+
if (exists && !await (0, _fs.isDirectory)(absResourceDirPath)) {
|
|
152
|
+
throw new Error(`${absResourceDirPath} is not a directory`);
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
abspath: absResourceDirPath,
|
|
156
|
+
exists
|
|
157
|
+
};
|
|
158
|
+
};
|
|
@@ -49,14 +49,13 @@ const formatErrorRespMessage = ({ status, data })=>{
|
|
|
49
49
|
return message;
|
|
50
50
|
};
|
|
51
51
|
const formatMgmtError = (apiError)=>{
|
|
52
|
+
var _apiError_error_message, _apiError_error_errors;
|
|
52
53
|
if (apiError.status === 500) {
|
|
53
54
|
return "An internal server error occurred";
|
|
54
55
|
}
|
|
55
|
-
var _apiError_error_message;
|
|
56
56
|
// Prefer the error message from the error object over
|
|
57
57
|
// the error message formatted by the Stainless SDK
|
|
58
58
|
const description = `${(_apiError_error_message = apiError.error.message) !== null && _apiError_error_message !== void 0 ? _apiError_error_message : apiError.message} (status: ${apiError.status})`;
|
|
59
|
-
var _apiError_error_errors;
|
|
60
59
|
const inputErrors = (_apiError_error_errors = apiError.error.errors) !== null && _apiError_error_errors !== void 0 ? _apiError_error_errors : [];
|
|
61
60
|
if (Array.isArray(inputErrors) && inputErrors.length > 0) {
|
|
62
61
|
const errs = inputErrors.map((e)=>new _error.JsonDataError(e.message, e.field));
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* Checks if a given string is in a slugified format.
|
|
3
|
-
*/ "use strict";
|
|
1
|
+
"use strict";
|
|
4
2
|
Object.defineProperty(exports, "__esModule", {
|
|
5
3
|
value: true
|
|
6
4
|
});
|
|
@@ -21,7 +19,9 @@ _export(exports, {
|
|
|
21
19
|
return slugify;
|
|
22
20
|
}
|
|
23
21
|
});
|
|
24
|
-
|
|
22
|
+
/*
|
|
23
|
+
* Checks if a given string is in a slugified format.
|
|
24
|
+
*/ const SLUG_FORMAT_RE = /^[\w-]+$/;
|
|
25
25
|
const SLUG_LOWERCASE_FORMAT_RE = /^[\d_a-z-]+$/;
|
|
26
26
|
const checkSlugifiedFormat = (input, opts = {})=>{
|
|
27
27
|
const { onlyLowerCase = true } = opts;
|
|
@@ -44,10 +44,10 @@ function getLanguageFromExtension(extension) {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
function transformSchema(schema) {
|
|
47
|
+
var _schema_properties;
|
|
47
48
|
if (schema.type === "object" && !schema.additionalProperties) {
|
|
48
49
|
schema.additionalProperties = false;
|
|
49
50
|
}
|
|
50
|
-
var _schema_properties;
|
|
51
51
|
for (const key of Object.keys((_schema_properties = schema.properties) !== null && _schema_properties !== void 0 ? _schema_properties : {})){
|
|
52
52
|
const property = schema.properties[key];
|
|
53
53
|
if (property.type === "object") {
|
|
@@ -0,0 +1,152 @@
|
|
|
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 generateEmailLayoutDir () {
|
|
13
|
+
return generateEmailLayoutDir;
|
|
14
|
+
},
|
|
15
|
+
get generateEmailLayoutFromTemplate () {
|
|
16
|
+
return generateEmailLayoutFromTemplate;
|
|
17
|
+
},
|
|
18
|
+
get scaffoldEmailLayoutDirBundle () {
|
|
19
|
+
return scaffoldEmailLayoutDirBundle;
|
|
20
|
+
},
|
|
21
|
+
get validateEmailLayoutKey () {
|
|
22
|
+
return validateEmailLayoutKey;
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
const _lodash = require("lodash");
|
|
26
|
+
const _string = require("../../helpers/string");
|
|
27
|
+
const _templates = /*#__PURE__*/ _interop_require_wildcard(require("../../templates"));
|
|
28
|
+
const _constisomorphic = require("../shared/const.isomorphic");
|
|
29
|
+
const _processorisomorphic = require("./processor.isomorphic");
|
|
30
|
+
const _reader = require("./reader");
|
|
31
|
+
const _writer = require("./writer");
|
|
32
|
+
function _getRequireWildcardCache(nodeInterop) {
|
|
33
|
+
if (typeof WeakMap !== "function") return null;
|
|
34
|
+
var cacheBabelInterop = new WeakMap();
|
|
35
|
+
var cacheNodeInterop = new WeakMap();
|
|
36
|
+
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
37
|
+
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
38
|
+
})(nodeInterop);
|
|
39
|
+
}
|
|
40
|
+
function _interop_require_wildcard(obj, nodeInterop) {
|
|
41
|
+
if (!nodeInterop && obj && obj.__esModule) {
|
|
42
|
+
return obj;
|
|
43
|
+
}
|
|
44
|
+
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
45
|
+
return {
|
|
46
|
+
default: obj
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
var cache = _getRequireWildcardCache(nodeInterop);
|
|
50
|
+
if (cache && cache.has(obj)) {
|
|
51
|
+
return cache.get(obj);
|
|
52
|
+
}
|
|
53
|
+
var newObj = {
|
|
54
|
+
__proto__: null
|
|
55
|
+
};
|
|
56
|
+
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
57
|
+
for(var key in obj){
|
|
58
|
+
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
59
|
+
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
60
|
+
if (desc && (desc.get || desc.set)) {
|
|
61
|
+
Object.defineProperty(newObj, key, desc);
|
|
62
|
+
} else {
|
|
63
|
+
newObj[key] = obj[key];
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
newObj.default = obj;
|
|
68
|
+
if (cache) {
|
|
69
|
+
cache.set(obj, newObj);
|
|
70
|
+
}
|
|
71
|
+
return newObj;
|
|
72
|
+
}
|
|
73
|
+
const validateEmailLayoutKey = (input)=>{
|
|
74
|
+
if (!(0, _string.checkSlugifiedFormat)(input, {
|
|
75
|
+
onlyLowerCase: true
|
|
76
|
+
})) {
|
|
77
|
+
return "must include only lowercase alphanumeric, dash, or underscore characters";
|
|
78
|
+
}
|
|
79
|
+
return undefined;
|
|
80
|
+
};
|
|
81
|
+
/*
|
|
82
|
+
* Returns the default scaffolded HTML layout content.
|
|
83
|
+
*/ const defaultHtmlLayoutContent = ()=>{
|
|
84
|
+
return `<!DOCTYPE html>
|
|
85
|
+
<html>
|
|
86
|
+
<head>
|
|
87
|
+
<meta charset="utf-8">
|
|
88
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
89
|
+
<title>{{ title }}</title>
|
|
90
|
+
</head>
|
|
91
|
+
<body>
|
|
92
|
+
<div style="max-width: 600px; margin: 0 auto; padding: 20px;">
|
|
93
|
+
{{ content }}
|
|
94
|
+
</div>
|
|
95
|
+
</body>
|
|
96
|
+
</html>`;
|
|
97
|
+
};
|
|
98
|
+
/*
|
|
99
|
+
* Returns the default scaffolded text layout content.
|
|
100
|
+
*/ const defaultTextLayoutContent = ()=>{
|
|
101
|
+
return `{{ content }}`;
|
|
102
|
+
};
|
|
103
|
+
/*
|
|
104
|
+
* Scaffolds a new email layout directory bundle with default content.
|
|
105
|
+
*/ const scaffoldEmailLayoutDirBundle = (attrs)=>{
|
|
106
|
+
const htmlLayoutFilePath = "html_layout.html";
|
|
107
|
+
const textLayoutFilePath = "text_layout.txt";
|
|
108
|
+
const defaultHtmlContent = defaultHtmlLayoutContent();
|
|
109
|
+
const defaultTextContent = defaultTextLayoutContent();
|
|
110
|
+
const layoutJson = {
|
|
111
|
+
name: attrs.name,
|
|
112
|
+
[`html_layout${_constisomorphic.FILEPATH_MARKER}`]: htmlLayoutFilePath,
|
|
113
|
+
[`text_layout${_constisomorphic.FILEPATH_MARKER}`]: textLayoutFilePath
|
|
114
|
+
};
|
|
115
|
+
return {
|
|
116
|
+
[_processorisomorphic.LAYOUT_JSON]: layoutJson,
|
|
117
|
+
[htmlLayoutFilePath]: defaultHtmlContent,
|
|
118
|
+
[textLayoutFilePath]: defaultTextContent
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
const generateEmailLayoutDir = async (emailLayoutDirCtx, attrs)=>{
|
|
122
|
+
const bundle = scaffoldEmailLayoutDirBundle(attrs);
|
|
123
|
+
return (0, _writer.writeEmailLayoutDirFromBundle)(emailLayoutDirCtx, bundle);
|
|
124
|
+
};
|
|
125
|
+
const generateEmailLayoutFromTemplate = async (emailLayoutDirCtx, templateString, attrs)=>{
|
|
126
|
+
let tempDir;
|
|
127
|
+
try {
|
|
128
|
+
// Download the template directory into a temp directory
|
|
129
|
+
tempDir = await _templates.downloadTemplate(templateString);
|
|
130
|
+
// Create an email layout directory context for the temp directory
|
|
131
|
+
const tempEmailLayoutDirCtx = {
|
|
132
|
+
type: "email_layout",
|
|
133
|
+
key: "temp",
|
|
134
|
+
abspath: tempDir,
|
|
135
|
+
exists: true
|
|
136
|
+
};
|
|
137
|
+
// Read the layout.json from the temp directory we downloaded
|
|
138
|
+
const [emailLayout, errors] = await (0, _reader.readEmailLayoutDir)(tempEmailLayoutDirCtx, {
|
|
139
|
+
withExtractedFiles: true
|
|
140
|
+
});
|
|
141
|
+
if (errors.length > 0 || !emailLayout) {
|
|
142
|
+
throw new Error(`Invalid email layout template: ${errors.join(", ")}`);
|
|
143
|
+
}
|
|
144
|
+
// Modify the email layout data with the new attributes
|
|
145
|
+
const emailLayoutData = (0, _lodash.cloneDeep)(emailLayout);
|
|
146
|
+
emailLayoutData.name = attrs.name;
|
|
147
|
+
// Finally, we write the email layout into the target email layout directory
|
|
148
|
+
await (0, _writer.writeEmailLayoutDirFromData)(emailLayoutDirCtx, emailLayoutData);
|
|
149
|
+
} finally{
|
|
150
|
+
await _templates.cleanupTempDir(tempDir);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
@@ -25,6 +25,7 @@ _export(exports, {
|
|
|
25
25
|
const _nodepath = /*#__PURE__*/ _interop_require_wildcard(require("node:path"));
|
|
26
26
|
const _core = require("@oclif/core");
|
|
27
27
|
const _fsextra = /*#__PURE__*/ _interop_require_wildcard(require("fs-extra"));
|
|
28
|
+
const _projectconfig = require("../../helpers/project-config");
|
|
28
29
|
const _processorisomorphic = require("./processor.isomorphic");
|
|
29
30
|
function _getRequireWildcardCache(nodeInterop) {
|
|
30
31
|
if (typeof WeakMap !== "function") return null;
|
|
@@ -74,7 +75,7 @@ const lsEmailLayoutJson = async (dirPath)=>{
|
|
|
74
75
|
const exists = await _fsextra.pathExists(emailLayoutJsonPath);
|
|
75
76
|
return exists ? emailLayoutJsonPath : undefined;
|
|
76
77
|
};
|
|
77
|
-
const ensureValidCommandTarget = async (props, runContext)=>{
|
|
78
|
+
const ensureValidCommandTarget = async (props, runContext, projectConfig)=>{
|
|
78
79
|
const { args, flags } = props;
|
|
79
80
|
const { commandId, resourceDir: resourceDirCtx, cwd: runCwd } = runContext;
|
|
80
81
|
// If the target resource is a different type than the current resource dir
|
|
@@ -86,19 +87,15 @@ const ensureValidCommandTarget = async (props, runContext)=>{
|
|
|
86
87
|
if (flags.all && args.emailLayoutKey) {
|
|
87
88
|
return _core.ux.error(`emailLayoutKey arg \`${args.emailLayoutKey}\` cannot also be provided when using --all`);
|
|
88
89
|
}
|
|
90
|
+
// Default to knock project config first if present, otherwise cwd.
|
|
91
|
+
const layoutsIndexDirCtx = await (0, _projectconfig.resolveResourceDir)(projectConfig, "email_layout", runCwd);
|
|
89
92
|
// --all flag is given, which means no layout key arg.
|
|
90
93
|
if (flags.all) {
|
|
91
94
|
// If --all flag used inside a layout directory, then require a layouts dir path.
|
|
92
95
|
if (resourceDirCtx && !flags["layouts-dir"]) {
|
|
93
96
|
return _core.ux.error("Missing required flag layouts-dir");
|
|
94
97
|
}
|
|
95
|
-
|
|
96
|
-
// TODO: Default to the knock project config first if present before cwd.
|
|
97
|
-
const defaultToCwd = {
|
|
98
|
-
abspath: runCwd,
|
|
99
|
-
exists: true
|
|
100
|
-
};
|
|
101
|
-
const indexDirCtx = flags["layouts-dir"] || defaultToCwd;
|
|
98
|
+
const indexDirCtx = flags["layouts-dir"] || layoutsIndexDirCtx;
|
|
102
99
|
return {
|
|
103
100
|
type: "emailLayoutsIndexDir",
|
|
104
101
|
context: indexDirCtx
|
|
@@ -109,7 +106,7 @@ const ensureValidCommandTarget = async (props, runContext)=>{
|
|
|
109
106
|
if (resourceDirCtx && resourceDirCtx.key !== args.emailLayoutKey) {
|
|
110
107
|
return _core.ux.error(`Cannot run ${commandId} \`${args.emailLayoutKey}\` inside another layout directory:\n${resourceDirCtx.key}`);
|
|
111
108
|
}
|
|
112
|
-
const targetDirPath = resourceDirCtx ? resourceDirCtx.abspath : _nodepath.resolve(
|
|
109
|
+
const targetDirPath = resourceDirCtx ? resourceDirCtx.abspath : _nodepath.resolve(layoutsIndexDirCtx.abspath, args.emailLayoutKey);
|
|
113
110
|
const layoutDirCtx = {
|
|
114
111
|
type: "email_layout",
|
|
115
112
|
key: args.emailLayoutKey,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", {
|
|
3
3
|
value: true
|
|
4
4
|
});
|
|
5
|
+
_export_star(require("./generator"), exports);
|
|
5
6
|
_export_star(require("./helpers"), exports);
|
|
6
7
|
_export_star(require("./processor.isomorphic"), exports);
|
|
7
8
|
_export_star(require("./reader"), exports);
|
|
@@ -12,6 +12,9 @@ _export(exports, {
|
|
|
12
12
|
get pruneLayoutsIndexDir () {
|
|
13
13
|
return pruneLayoutsIndexDir;
|
|
14
14
|
},
|
|
15
|
+
get writeEmailLayoutDirFromBundle () {
|
|
16
|
+
return writeEmailLayoutDirFromBundle;
|
|
17
|
+
},
|
|
15
18
|
get writeEmailLayoutDirFromData () {
|
|
16
19
|
return writeEmailLayoutDirFromData;
|
|
17
20
|
},
|
|
@@ -82,18 +85,27 @@ const writeEmailLayoutDirFromData = async (emailLayoutDirCtx, remoteEmailLayout,
|
|
|
82
85
|
withExtractedFiles: true
|
|
83
86
|
}) : [];
|
|
84
87
|
const bundle = (0, _processorisomorphic.buildEmailLayoutDirBundle)(remoteEmailLayout, localEmailLayout, withSchema ? EMAIL_LAYOUT_SCHEMA : undefined);
|
|
88
|
+
return writeEmailLayoutDirFromBundle(emailLayoutDirCtx, bundle);
|
|
89
|
+
};
|
|
90
|
+
/*
|
|
91
|
+
* A lower level write function that takes a constructed email layout dir bundle
|
|
92
|
+
* and writes it into a layout directory on a local file system.
|
|
93
|
+
*
|
|
94
|
+
* It does not make any assumptions about how the email layout directory bundle was
|
|
95
|
+
* built; for example, it can be from parsing the layout data fetched from
|
|
96
|
+
* the Knock API, or built manually for scaffolding purposes.
|
|
97
|
+
*/ const writeEmailLayoutDirFromBundle = async (emailLayoutDirCtx, emailLayoutDirBundle)=>{
|
|
85
98
|
const backupDirPath = _nodepath.default.resolve(_const.sandboxDir, (0, _lodash.uniqueId)("backup"));
|
|
86
99
|
try {
|
|
87
|
-
// We store a backup in case there's an error.
|
|
88
100
|
if (emailLayoutDirCtx.exists) {
|
|
89
101
|
await _fsextra.copy(emailLayoutDirCtx.abspath, backupDirPath);
|
|
90
102
|
await _fsextra.emptyDir(emailLayoutDirCtx.abspath);
|
|
91
103
|
}
|
|
92
|
-
const promises = Object.entries(
|
|
104
|
+
const promises = Object.entries(emailLayoutDirBundle).map(([relpath, fileContent])=>{
|
|
93
105
|
const filePath = _nodepath.default.resolve(emailLayoutDirCtx.abspath, relpath);
|
|
94
106
|
return relpath === _processorisomorphic.LAYOUT_JSON ? _fsextra.outputJson(filePath, fileContent, {
|
|
95
107
|
spaces: _json.DOUBLE_SPACES
|
|
96
|
-
}) : _fsextra.outputFile(filePath, fileContent);
|
|
108
|
+
}) : _fsextra.outputFile(filePath, fileContent !== null && fileContent !== void 0 ? fileContent : "");
|
|
97
109
|
});
|
|
98
110
|
await Promise.all(promises);
|
|
99
111
|
} catch (error) {
|
|
@@ -0,0 +1,163 @@
|
|
|
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 generateGuideDir () {
|
|
13
|
+
return generateGuideDir;
|
|
14
|
+
},
|
|
15
|
+
get generateGuideFromTemplate () {
|
|
16
|
+
return generateGuideFromTemplate;
|
|
17
|
+
},
|
|
18
|
+
get scaffoldGuideDirBundle () {
|
|
19
|
+
return scaffoldGuideDirBundle;
|
|
20
|
+
},
|
|
21
|
+
get scaffoldValuesFromSchema () {
|
|
22
|
+
return scaffoldValuesFromSchema;
|
|
23
|
+
},
|
|
24
|
+
get validateGuideKey () {
|
|
25
|
+
return validateGuideKey;
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
const _string = require("../../helpers/string");
|
|
29
|
+
const _templates = /*#__PURE__*/ _interop_require_wildcard(require("../../templates"));
|
|
30
|
+
const _processorisomorphic = require("./processor.isomorphic");
|
|
31
|
+
const _reader = require("./reader");
|
|
32
|
+
const _writer = require("./writer");
|
|
33
|
+
function _getRequireWildcardCache(nodeInterop) {
|
|
34
|
+
if (typeof WeakMap !== "function") return null;
|
|
35
|
+
var cacheBabelInterop = new WeakMap();
|
|
36
|
+
var cacheNodeInterop = new WeakMap();
|
|
37
|
+
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
38
|
+
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
39
|
+
})(nodeInterop);
|
|
40
|
+
}
|
|
41
|
+
function _interop_require_wildcard(obj, nodeInterop) {
|
|
42
|
+
if (!nodeInterop && obj && obj.__esModule) {
|
|
43
|
+
return obj;
|
|
44
|
+
}
|
|
45
|
+
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
46
|
+
return {
|
|
47
|
+
default: obj
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
var cache = _getRequireWildcardCache(nodeInterop);
|
|
51
|
+
if (cache && cache.has(obj)) {
|
|
52
|
+
return cache.get(obj);
|
|
53
|
+
}
|
|
54
|
+
var newObj = {
|
|
55
|
+
__proto__: null
|
|
56
|
+
};
|
|
57
|
+
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
58
|
+
for(var key in obj){
|
|
59
|
+
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
60
|
+
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
61
|
+
if (desc && (desc.get || desc.set)) {
|
|
62
|
+
Object.defineProperty(newObj, key, desc);
|
|
63
|
+
} else {
|
|
64
|
+
newObj[key] = obj[key];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
newObj.default = obj;
|
|
69
|
+
if (cache) {
|
|
70
|
+
cache.set(obj, newObj);
|
|
71
|
+
}
|
|
72
|
+
return newObj;
|
|
73
|
+
}
|
|
74
|
+
const validateGuideKey = (input)=>{
|
|
75
|
+
if (!(0, _string.checkSlugifiedFormat)(input, {
|
|
76
|
+
onlyLowerCase: true
|
|
77
|
+
})) {
|
|
78
|
+
return "must include only lowercase alphanumeric, dash, or underscore characters";
|
|
79
|
+
}
|
|
80
|
+
return undefined;
|
|
81
|
+
};
|
|
82
|
+
const scaffoldValuesFromSchema = (fields)=>{
|
|
83
|
+
const values = {};
|
|
84
|
+
for (const field of fields){
|
|
85
|
+
switch(field.type){
|
|
86
|
+
case "text":
|
|
87
|
+
case "textarea":
|
|
88
|
+
case "markdown":
|
|
89
|
+
values[field.key] = "";
|
|
90
|
+
break;
|
|
91
|
+
case "boolean":
|
|
92
|
+
values[field.key] = false;
|
|
93
|
+
break;
|
|
94
|
+
case "select":
|
|
95
|
+
case "multi_select":
|
|
96
|
+
values[field.key] = null;
|
|
97
|
+
break;
|
|
98
|
+
case "button":
|
|
99
|
+
values[field.key] = {
|
|
100
|
+
text: "",
|
|
101
|
+
action: ""
|
|
102
|
+
};
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return values;
|
|
107
|
+
};
|
|
108
|
+
const scaffoldGuideDirBundle = (attrs)=>{
|
|
109
|
+
const { name, messageType, variantKey = "default" } = attrs;
|
|
110
|
+
// Find the selected variant or default to the first one
|
|
111
|
+
const variant = messageType.variants.find((v)=>v.key === variantKey) || messageType.variants[0];
|
|
112
|
+
if (!variant) {
|
|
113
|
+
throw new Error(`Message type ${messageType.key} has no variants available`);
|
|
114
|
+
}
|
|
115
|
+
// Scaffold values from the variant's field schema
|
|
116
|
+
const values = scaffoldValuesFromSchema(variant.fields);
|
|
117
|
+
const guideJson = {
|
|
118
|
+
name,
|
|
119
|
+
steps: [
|
|
120
|
+
{
|
|
121
|
+
ref: "step_1",
|
|
122
|
+
schema_key: messageType.key,
|
|
123
|
+
schema_variant_key: variant.key,
|
|
124
|
+
values
|
|
125
|
+
}
|
|
126
|
+
]
|
|
127
|
+
};
|
|
128
|
+
return {
|
|
129
|
+
[_processorisomorphic.GUIDE_JSON]: guideJson
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
const generateGuideDir = async (guideDirCtx, attrs)=>{
|
|
133
|
+
const bundle = scaffoldGuideDirBundle(attrs);
|
|
134
|
+
return (0, _writer.writeGuideDirFromBundle)(guideDirCtx, bundle);
|
|
135
|
+
};
|
|
136
|
+
const generateGuideFromTemplate = async (guideDirCtx, templateString, attrs)=>{
|
|
137
|
+
let tempDir;
|
|
138
|
+
try {
|
|
139
|
+
// Download the template directory into a temp directory
|
|
140
|
+
tempDir = await _templates.downloadTemplate(templateString);
|
|
141
|
+
// Create a guide directory context for the temp directory
|
|
142
|
+
const tempGuideDirCtx = {
|
|
143
|
+
type: "guide",
|
|
144
|
+
key: "temp",
|
|
145
|
+
abspath: tempDir,
|
|
146
|
+
exists: true
|
|
147
|
+
};
|
|
148
|
+
// Read the guide.json from the temp directory we downloaded
|
|
149
|
+
const [guide, errors] = await (0, _reader.readGuideDir)(tempGuideDirCtx, {
|
|
150
|
+
withExtractedFiles: true
|
|
151
|
+
});
|
|
152
|
+
if (errors.length > 0 || !guide) {
|
|
153
|
+
throw new Error(`Invalid guide template: ${errors.join(", ")}`);
|
|
154
|
+
}
|
|
155
|
+
// Modify the guide data with the new attributes
|
|
156
|
+
guide.name = attrs.name;
|
|
157
|
+
// Finally, we write the guide into the target guide directory
|
|
158
|
+
(0, _writer.writeGuideDirFromData)(guideDirCtx, guide);
|
|
159
|
+
return;
|
|
160
|
+
} finally{
|
|
161
|
+
await _templates.cleanupTempDir(tempDir);
|
|
162
|
+
}
|
|
163
|
+
};
|
|
@@ -42,6 +42,7 @@ const _core = require("@oclif/core");
|
|
|
42
42
|
const _fsextra = /*#__PURE__*/ _interop_require_wildcard(require("fs-extra"));
|
|
43
43
|
const _lodash = require("lodash");
|
|
44
44
|
const _quicktypecore = require("quicktype-core");
|
|
45
|
+
const _projectconfig = require("../../helpers/project-config");
|
|
45
46
|
const _processorisomorphic = require("./processor.isomorphic");
|
|
46
47
|
function _getRequireWildcardCache(nodeInterop) {
|
|
47
48
|
if (typeof WeakMap !== "function") return null;
|
|
@@ -107,7 +108,7 @@ const lsGuideJson = async (dirPath)=>{
|
|
|
107
108
|
return exists ? guideJsonPath : undefined;
|
|
108
109
|
};
|
|
109
110
|
const isGuideDir = async (dirPath)=>Boolean(await lsGuideJson(dirPath));
|
|
110
|
-
const ensureValidCommandTarget = async (props, runContext)=>{
|
|
111
|
+
const ensureValidCommandTarget = async (props, runContext, projectConfig)=>{
|
|
111
112
|
const { args, flags } = props;
|
|
112
113
|
const { commandId, resourceDir: resourceDirCtx, cwd: runCwd } = runContext;
|
|
113
114
|
// If the target resource is a different type than the current resource dir
|
|
@@ -119,6 +120,8 @@ const ensureValidCommandTarget = async (props, runContext)=>{
|
|
|
119
120
|
if (flags.all && args.guideKey) {
|
|
120
121
|
return _core.ux.error(`guideKey arg \`${args.guideKey}\` cannot also be provided when using --all`);
|
|
121
122
|
}
|
|
123
|
+
// Default to knock project config first if present, otherwise cwd.
|
|
124
|
+
const guidesIndexDirCtx = await (0, _projectconfig.resolveResourceDir)(projectConfig, "guide", runCwd);
|
|
122
125
|
// --all flag is given, which means no guide key arg.
|
|
123
126
|
if (flags.all) {
|
|
124
127
|
// If --all flag used inside a guide directory, then require a guides
|
|
@@ -126,16 +129,9 @@ const ensureValidCommandTarget = async (props, runContext)=>{
|
|
|
126
129
|
if (resourceDirCtx && !flags["guides-dir"]) {
|
|
127
130
|
return _core.ux.error("Missing required flag guides-dir");
|
|
128
131
|
}
|
|
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
132
|
return {
|
|
137
133
|
type: "guidesIndexDir",
|
|
138
|
-
context:
|
|
134
|
+
context: flags["guides-dir"] || guidesIndexDirCtx
|
|
139
135
|
};
|
|
140
136
|
}
|
|
141
137
|
// Guide key arg is given, which means no --all flag.
|
|
@@ -143,7 +139,7 @@ const ensureValidCommandTarget = async (props, runContext)=>{
|
|
|
143
139
|
if (resourceDirCtx && resourceDirCtx.key !== args.guideKey) {
|
|
144
140
|
return _core.ux.error(`Cannot run ${commandId} \`${args.guideKey}\` inside another guide directory:\n${resourceDirCtx.key}`);
|
|
145
141
|
}
|
|
146
|
-
const targetDirPath = resourceDirCtx ? resourceDirCtx.abspath : _nodepath.resolve(
|
|
142
|
+
const targetDirPath = resourceDirCtx ? resourceDirCtx.abspath : _nodepath.resolve(guidesIndexDirCtx.abspath, args.guideKey);
|
|
147
143
|
const guideDirCtx = {
|
|
148
144
|
type: "guide",
|
|
149
145
|
key: args.guideKey,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", {
|
|
3
3
|
value: true
|
|
4
4
|
});
|
|
5
|
+
_export_star(require("./generator"), exports);
|
|
5
6
|
_export_star(require("./helpers"), exports);
|
|
6
7
|
_export_star(require("./processor.isomorphic"), exports);
|
|
7
8
|
_export_star(require("./reader"), exports);
|