stepzen 0.15.0 → 0.16.0-beta.2
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 +30 -5
- package/lib/commands/import.d.ts +71 -4
- package/lib/commands/import.js +134 -19
- package/lib/commands/lint.js +1 -1
- package/lib/commands/login.js +1 -1
- package/lib/commands/logout.js +1 -1
- package/lib/commands/start.js +0 -2
- package/lib/commands/upload.js +1 -1
- package/lib/commands/whoami.js +1 -1
- package/lib/generate/curl2sdl.d.ts +48 -1
- package/lib/generate/curl2sdl.js +81 -3
- package/lib/generate/helpers.js +13 -10
- package/lib/generate/index.d.ts +5 -1
- package/lib/generate/index.js +9 -5
- package/lib/shared/constants.d.ts +0 -2
- package/lib/shared/constants.js +2 -7
- package/lib/shared/curl-parser.d.ts +13 -17
- package/lib/shared/curl-parser.js +2 -1
- package/lib/shared/header-params-parser.d.ts +7 -0
- package/lib/shared/header-params-parser.js +108 -0
- package/oclif.manifest.json +1 -1
- package/package.json +5 -4
- package/lib/generate/dashboard-interface.d.ts +0 -7
- package/lib/generate/dashboard-interface.js +0 -42
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ $ npm install -g stepzen
|
|
|
29
29
|
$ stepzen COMMAND
|
|
30
30
|
running command...
|
|
31
31
|
$ stepzen (-v|--version|version)
|
|
32
|
-
stepzen/0.
|
|
32
|
+
stepzen/0.16.0-beta.2 darwin-x64 node-v14.19.1
|
|
33
33
|
$ stepzen --help [COMMAND]
|
|
34
34
|
USAGE
|
|
35
35
|
$ stepzen COMMAND
|
|
@@ -84,7 +84,7 @@ _See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v5.1.1
|
|
|
84
84
|
|
|
85
85
|
## `stepzen import SCHEMAS`
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
import a schema for an external data source or a API endpoint to your GraphQL API
|
|
88
88
|
|
|
89
89
|
```
|
|
90
90
|
USAGE
|
|
@@ -94,9 +94,34 @@ OPTIONS
|
|
|
94
94
|
-h, --help
|
|
95
95
|
show CLI help
|
|
96
96
|
|
|
97
|
+
--db-database=db-database
|
|
98
|
+
[mysql, postgresql] name of database to import
|
|
99
|
+
|
|
100
|
+
--db-host=db-host
|
|
101
|
+
[mysql, postgresql] database host
|
|
102
|
+
|
|
103
|
+
--db-password=db-password
|
|
104
|
+
[mysql, postgresql] database password
|
|
105
|
+
|
|
106
|
+
--db-schema=db-schema
|
|
107
|
+
[postgresql] database schema
|
|
108
|
+
|
|
109
|
+
--db-user=db-user
|
|
110
|
+
[mysql, postgresql] database user name
|
|
111
|
+
|
|
97
112
|
--dir=dir
|
|
98
113
|
working directory
|
|
99
114
|
|
|
115
|
+
--header-param=header-param
|
|
116
|
+
[curl] specifies a parameter in a header value. Can be formed by taking a -H, --header flag and replacing the
|
|
117
|
+
variable part of the header value with a $paramName placeholder. Repeat this flag once for each header with a
|
|
118
|
+
parameter.
|
|
119
|
+
|
|
120
|
+
Example:
|
|
121
|
+
stepzen import curl https://example.com/api/customers \
|
|
122
|
+
-H "Authorization: apikey SecretAPIKeyValue" \
|
|
123
|
+
--header-param 'Authorization: apikey $apikey'
|
|
124
|
+
|
|
100
125
|
--name=name
|
|
101
126
|
subfolder inside the workspace folder to save the imported schema files, defaults to the imported schema name
|
|
102
127
|
|
|
@@ -135,7 +160,7 @@ OPTIONS
|
|
|
135
160
|
|
|
136
161
|
## `stepzen login`
|
|
137
162
|
|
|
138
|
-
|
|
163
|
+
log in to StepZen
|
|
139
164
|
|
|
140
165
|
```
|
|
141
166
|
USAGE
|
|
@@ -150,7 +175,7 @@ OPTIONS
|
|
|
150
175
|
|
|
151
176
|
## `stepzen logout`
|
|
152
177
|
|
|
153
|
-
log out of
|
|
178
|
+
log out of StepZen
|
|
154
179
|
|
|
155
180
|
```
|
|
156
181
|
USAGE
|
|
@@ -177,7 +202,7 @@ OPTIONS
|
|
|
177
202
|
|
|
178
203
|
## `stepzen upload TYPE DESTINATION`
|
|
179
204
|
|
|
180
|
-
upload to
|
|
205
|
+
upload to StepZen
|
|
181
206
|
|
|
182
207
|
```
|
|
183
208
|
USAGE
|
package/lib/commands/import.d.ts
CHANGED
|
@@ -2,15 +2,60 @@ import { flags } from '@oclif/command';
|
|
|
2
2
|
import ZenCommand from '../shared/zen-command';
|
|
3
3
|
export default class Import extends ZenCommand {
|
|
4
4
|
static description: string;
|
|
5
|
+
static curlFlags: {
|
|
6
|
+
prefix: flags.IOptionFlag<string | undefined>;
|
|
7
|
+
'query-name': flags.IOptionFlag<string | undefined>;
|
|
8
|
+
'query-type': flags.IOptionFlag<string | undefined>;
|
|
9
|
+
'path-params': flags.IOptionFlag<string | undefined>;
|
|
10
|
+
'header-param': flags.IOptionFlag<string[]>;
|
|
11
|
+
};
|
|
12
|
+
static sqlFlags: {
|
|
13
|
+
'db-host': flags.IOptionFlag<string | undefined>;
|
|
14
|
+
'db-user': flags.IOptionFlag<string | undefined>;
|
|
15
|
+
'db-password': flags.IOptionFlag<string | undefined>;
|
|
16
|
+
'db-database': flags.IOptionFlag<string | undefined>;
|
|
17
|
+
};
|
|
18
|
+
static postgresqlFlags: {
|
|
19
|
+
'db-schema': flags.IOptionFlag<string | undefined>;
|
|
20
|
+
};
|
|
21
|
+
static flagsForSchemas: ({
|
|
22
|
+
flags: {
|
|
23
|
+
prefix: flags.IOptionFlag<string | undefined>;
|
|
24
|
+
'query-name': flags.IOptionFlag<string | undefined>;
|
|
25
|
+
'query-type': flags.IOptionFlag<string | undefined>;
|
|
26
|
+
'path-params': flags.IOptionFlag<string | undefined>;
|
|
27
|
+
'header-param': flags.IOptionFlag<string[]>;
|
|
28
|
+
};
|
|
29
|
+
schemas: string[];
|
|
30
|
+
} | {
|
|
31
|
+
flags: {
|
|
32
|
+
'db-host': flags.IOptionFlag<string | undefined>;
|
|
33
|
+
'db-user': flags.IOptionFlag<string | undefined>;
|
|
34
|
+
'db-password': flags.IOptionFlag<string | undefined>;
|
|
35
|
+
'db-database': flags.IOptionFlag<string | undefined>;
|
|
36
|
+
};
|
|
37
|
+
schemas: string[];
|
|
38
|
+
} | {
|
|
39
|
+
flags: {
|
|
40
|
+
'db-schema': flags.IOptionFlag<string | undefined>;
|
|
41
|
+
};
|
|
42
|
+
schemas: string[];
|
|
43
|
+
})[];
|
|
5
44
|
static flags: {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
45
|
+
'db-schema': flags.IOptionFlag<string | undefined>;
|
|
46
|
+
'db-host': flags.IOptionFlag<string | undefined>;
|
|
47
|
+
'db-user': flags.IOptionFlag<string | undefined>;
|
|
48
|
+
'db-password': flags.IOptionFlag<string | undefined>;
|
|
49
|
+
'db-database': flags.IOptionFlag<string | undefined>;
|
|
10
50
|
prefix: flags.IOptionFlag<string | undefined>;
|
|
11
51
|
'query-name': flags.IOptionFlag<string | undefined>;
|
|
12
52
|
'query-type': flags.IOptionFlag<string | undefined>;
|
|
13
53
|
'path-params': flags.IOptionFlag<string | undefined>;
|
|
54
|
+
'header-param': flags.IOptionFlag<string[]>;
|
|
55
|
+
dir: flags.IOptionFlag<string | undefined>;
|
|
56
|
+
help: import("@oclif/parser/lib/flags").IBooleanFlag<void>;
|
|
57
|
+
silent: import("@oclif/parser/lib/flags").IBooleanFlag<boolean>;
|
|
58
|
+
name: flags.IOptionFlag<string | undefined>;
|
|
14
59
|
'non-interactive': import("@oclif/parser/lib/flags").IBooleanFlag<boolean>;
|
|
15
60
|
};
|
|
16
61
|
static args: {
|
|
@@ -19,4 +64,26 @@ export default class Import extends ZenCommand {
|
|
|
19
64
|
}[];
|
|
20
65
|
static strict: boolean;
|
|
21
66
|
run(): Promise<void>;
|
|
67
|
+
warnAboutIgnoredFlags: (usedSchemas: readonly string[], usedFlags: {
|
|
68
|
+
[key: string]: any;
|
|
69
|
+
}) => void;
|
|
70
|
+
parseWorkaround(): import("@oclif/parser").Output<{
|
|
71
|
+
'db-schema': string | undefined;
|
|
72
|
+
'db-host': string | undefined;
|
|
73
|
+
'db-user': string | undefined;
|
|
74
|
+
'db-password': string | undefined;
|
|
75
|
+
'db-database': string | undefined;
|
|
76
|
+
prefix: string | undefined;
|
|
77
|
+
'query-name': string | undefined;
|
|
78
|
+
'query-type': string | undefined;
|
|
79
|
+
'path-params': string | undefined;
|
|
80
|
+
'header-param': string[];
|
|
81
|
+
dir: string | undefined;
|
|
82
|
+
help: void;
|
|
83
|
+
silent: boolean;
|
|
84
|
+
name: string | undefined;
|
|
85
|
+
'non-interactive': boolean;
|
|
86
|
+
}, {
|
|
87
|
+
[name: string]: any;
|
|
88
|
+
}>;
|
|
22
89
|
}
|
package/lib/commands/import.js
CHANGED
|
@@ -17,9 +17,27 @@ const zen_command_1 = require("../shared/zen-command");
|
|
|
17
17
|
const init_1 = require("./init");
|
|
18
18
|
const constants_1 = require("../shared/constants");
|
|
19
19
|
const path_params_parser_1 = require("../shared/path-params-parser");
|
|
20
|
+
const header_params_parser_1 = require("../shared/header-params-parser");
|
|
20
21
|
class Import extends zen_command_1.default {
|
|
22
|
+
constructor() {
|
|
23
|
+
super(...arguments);
|
|
24
|
+
// notify the user about any ignored flags
|
|
25
|
+
this.warnAboutIgnoredFlags = (usedSchemas, usedFlags) => {
|
|
26
|
+
Import.flagsForSchemas.forEach(({ flags, schemas }) => {
|
|
27
|
+
if (!usedSchemas.some(usedSchema => schemas.includes(usedSchema))) {
|
|
28
|
+
Object.keys(flags).forEach(flag => {
|
|
29
|
+
if (Object.prototype.hasOwnProperty.call(usedFlags, flag)) {
|
|
30
|
+
this.log(chalk.gray(`The ${chalk.bold(`--${flag}`)} flag only applies when importing ${schemas
|
|
31
|
+
.map(schema => chalk.bold(schema))
|
|
32
|
+
.join(', ')}. It will be ignored now.`));
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
}
|
|
21
39
|
async run() {
|
|
22
|
-
const { args, argv, flags } = this.
|
|
40
|
+
const { args, argv, flags } = this.parseWorkaround();
|
|
23
41
|
// Get a list of schemas you're asking for
|
|
24
42
|
const schemas = helpers_1.getSchemaList(args.schemas);
|
|
25
43
|
if (schemas.length > 1 && flags.name) {
|
|
@@ -41,6 +59,7 @@ class Import extends zen_command_1.default {
|
|
|
41
59
|
throw new errors_1.CLIError(`Could not create a StepZen workspace in the ${flags.dir ? directory : 'current'} directory.\n` + error.message);
|
|
42
60
|
}
|
|
43
61
|
}
|
|
62
|
+
this.warnAboutIgnoredFlags(schemas, flags);
|
|
44
63
|
// Select an import execution flow:
|
|
45
64
|
// - v1 with `stepzen/engines` and cloud function
|
|
46
65
|
// - v2 with the graphqlize service
|
|
@@ -74,7 +93,8 @@ class Import extends zen_command_1.default {
|
|
|
74
93
|
'StepZen API. curl syntax is supported so that you copy and paste a ' +
|
|
75
94
|
'curl command instead of the URL.');
|
|
76
95
|
console.log();
|
|
77
|
-
|
|
96
|
+
const curlAnswers = await curl2sdl_1.askCurlQuestions(editableOptions);
|
|
97
|
+
curl2sdlOptions = Object.assign(Object.assign(Object.assign({}, fixedOptions), curlAnswers), { headers: curlAnswers.curlArgs.headers });
|
|
78
98
|
}
|
|
79
99
|
else {
|
|
80
100
|
// run non-interative
|
|
@@ -86,7 +106,15 @@ class Import extends zen_command_1.default {
|
|
|
86
106
|
if ('error' in parsedPathParamsOrError) {
|
|
87
107
|
throw new errors_1.CLIError(parsedPathParamsOrError.error);
|
|
88
108
|
}
|
|
89
|
-
|
|
109
|
+
const headersOrError = header_params_parser_1.makeHeaders(argsOrError.headers, flags['header-param']);
|
|
110
|
+
if ('error' in headersOrError) {
|
|
111
|
+
throw new errors_1.CLIError(headersOrError.error);
|
|
112
|
+
}
|
|
113
|
+
const maybeDuplicateParamsMessage = curl2sdl_1.makeDuplicateParamsMessage(headersOrError, parsedPathParamsOrError, argsOrError.url);
|
|
114
|
+
if (maybeDuplicateParamsMessage) {
|
|
115
|
+
throw new errors_1.CLIError(maybeDuplicateParamsMessage);
|
|
116
|
+
}
|
|
117
|
+
curl2sdlOptions = Object.assign(Object.assign(Object.assign({}, fixedOptions), editableOptions), { pathParams: parsedPathParamsOrError, headers: headersOrError, curlArgs: argsOrError });
|
|
90
118
|
}
|
|
91
119
|
core_1.CliUx.ux.action.start('Starting');
|
|
92
120
|
const resultOrError = await curl2sdl_1.curl2sdl(curl2sdlOptions);
|
|
@@ -100,14 +128,24 @@ class Import extends zen_command_1.default {
|
|
|
100
128
|
result = resultOrError.outPath;
|
|
101
129
|
}
|
|
102
130
|
else {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
})
|
|
131
|
+
// Map flag names to the properties defined for sql engines in:
|
|
132
|
+
// https://github.com/steprz/generator-engines/blob/main/generator/src/shared/sql.ts
|
|
133
|
+
// If/when the number of property-to-answer mappings increase, create a dictionary
|
|
134
|
+
// { schema: { flag: field } } and build the below map based on this (a
|
|
135
|
+
// dictionary also enables a generic solution to the warning about ignored flags).
|
|
136
|
+
const preAnsweredForDBs = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (flags['db-host'] === undefined ? {} : { host: flags['db-host'] })), (flags['db-user'] === undefined ? {} : { user: flags['db-user'] })), (flags['db-password'] === undefined
|
|
137
|
+
? {}
|
|
138
|
+
: { password: flags['db-password'] })), (flags['db-database'] === undefined
|
|
139
|
+
? {}
|
|
140
|
+
: { database: flags['db-database'] })), (flags['db-schema'] === undefined
|
|
141
|
+
? {}
|
|
142
|
+
: { schema: flags['db-schema'] }));
|
|
143
|
+
const preAnswered = {
|
|
144
|
+
mysql: preAnsweredForDBs,
|
|
145
|
+
postgresql: preAnsweredForDBs,
|
|
146
|
+
};
|
|
109
147
|
// Let's go!
|
|
110
|
-
result = await generate_1.default(schemas, flags.name, workspace.schema);
|
|
148
|
+
result = await generate_1.default(schemas, flags.name, workspace.schema, preAnswered);
|
|
111
149
|
// Validate
|
|
112
150
|
await transpiler_1.validate(result, {
|
|
113
151
|
extensions: await utils_1.getStepZenExtensions(),
|
|
@@ -120,21 +158,58 @@ class Import extends zen_command_1.default {
|
|
|
120
158
|
this;
|
|
121
159
|
this.log(chalk.green(`Successfully imported ${schemas.length} schemas from StepZen`));
|
|
122
160
|
}
|
|
161
|
+
// Correct the value for the 'header-param' flag to work around the oclif's
|
|
162
|
+
// parser issue with multi-value flags: https://github.com/oclif/oclif/issues/261
|
|
163
|
+
parseWorkaround() {
|
|
164
|
+
const argv = this.argv;
|
|
165
|
+
const parsed = this.parse(Import, argv);
|
|
166
|
+
if (!parsed.flags['header-param']) {
|
|
167
|
+
return parsed;
|
|
168
|
+
}
|
|
169
|
+
// Every ['--header-param', value] pair in the argv array should match
|
|
170
|
+
// only one value in the 'header-param' flag's value list.
|
|
171
|
+
const matchedIndices = new Set();
|
|
172
|
+
// For each value in the 'header-param' flag's value list, find the original
|
|
173
|
+
// ['--header-param', value] pair in the argv array.
|
|
174
|
+
for (let i = 0; i < parsed.flags['header-param'].length; i++) {
|
|
175
|
+
const value = parsed.flags['header-param'][i];
|
|
176
|
+
const flagIdx = argv.findIndex((arg, idx) => {
|
|
177
|
+
const spaceDelimMatch = arg === '--header-param' &&
|
|
178
|
+
idx < argv.length &&
|
|
179
|
+
argv[idx + 1] === value;
|
|
180
|
+
const eqlDelimMatch = arg === `--header-param=${value}`;
|
|
181
|
+
return (spaceDelimMatch || eqlDelimMatch) && !matchedIndices.has(idx);
|
|
182
|
+
});
|
|
183
|
+
// If not found, that means the given value was associated with the
|
|
184
|
+
// `--header-param` flag incorrectly. In that case, it's moved from
|
|
185
|
+
// `flags` to `argv` in the parsed output.
|
|
186
|
+
if (flagIdx === -1) {
|
|
187
|
+
parsed.flags['header-param'].splice(i, 1);
|
|
188
|
+
i -= 1; // compensate for the .splice() call above
|
|
189
|
+
parsed.argv.push(value);
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
matchedIndices.add(flagIdx);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return parsed;
|
|
196
|
+
}
|
|
123
197
|
}
|
|
124
198
|
exports.default = Import;
|
|
125
|
-
Import.description = '
|
|
126
|
-
Import.
|
|
127
|
-
|
|
128
|
-
' schema files, defaults to the imported schema name',
|
|
129
|
-
}), prefix: command_1.flags.string({
|
|
199
|
+
Import.description = 'import a schema for an external data source or a API endpoint to your GraphQL API';
|
|
200
|
+
Import.curlFlags = {
|
|
201
|
+
prefix: command_1.flags.string({
|
|
130
202
|
description: '[curl] prefix to add every type in the generated schema.',
|
|
131
|
-
}),
|
|
203
|
+
}),
|
|
204
|
+
'query-name': command_1.flags.string({
|
|
132
205
|
description: '[curl] property name to add to the Query type as a way to' +
|
|
133
206
|
' access the imported cURL endpoint.',
|
|
134
|
-
}),
|
|
207
|
+
}),
|
|
208
|
+
'query-type': command_1.flags.string({
|
|
135
209
|
description: '[curl] name for the type returned by the cURL endpoint in the ' +
|
|
136
210
|
`generated schema. The name specified by ${chalk.bold('--query-type')} is not prefixed by ${chalk.bold('--prefix')} if both flags are present.`,
|
|
137
|
-
}),
|
|
211
|
+
}),
|
|
212
|
+
'path-params': command_1.flags.string({
|
|
138
213
|
description: `[curl] specifies path parameters in the URL path.` +
|
|
139
214
|
` Can be formed by taking the original path and replacing the` +
|
|
140
215
|
` variable segments with ${chalk.bold('$paramName')} placeholders.` +
|
|
@@ -143,7 +218,47 @@ Import.flags = Object.assign(Object.assign({}, zen_command_1.default.flags), { d
|
|
|
143
218
|
`\nstepzen import curl https://example.com/users/jane/posts/12` +
|
|
144
219
|
` --path-params` +
|
|
145
220
|
` '/users/${chalk.bold('$userId')}/posts/${chalk.bold('$postId')}'`,
|
|
146
|
-
})
|
|
221
|
+
}),
|
|
222
|
+
'header-param': command_1.flags.string({
|
|
223
|
+
description: `[curl] specifies a parameter in a header value.` +
|
|
224
|
+
` Can be formed by taking a ${chalk.bold('-H, --header')} flag and replacing the` +
|
|
225
|
+
` variable part of the header value with a ${chalk.bold('$paramName')} placeholder. Repeat this flag once for each header with a parameter.` +
|
|
226
|
+
`\n` +
|
|
227
|
+
`\nExample:` +
|
|
228
|
+
`\nstepzen import curl https://example.com/api/customers \\` +
|
|
229
|
+
`\n\t-H "Authorization: apikey SecretAPIKeyValue" \\` +
|
|
230
|
+
`\n\t--header-param 'Authorization: apikey ${chalk.bold('$apikey')}'`,
|
|
231
|
+
multiple: true,
|
|
232
|
+
}),
|
|
233
|
+
};
|
|
234
|
+
Import.sqlFlags = {
|
|
235
|
+
'db-host': command_1.flags.string({
|
|
236
|
+
description: '[mysql, postgresql] database host',
|
|
237
|
+
}),
|
|
238
|
+
'db-user': command_1.flags.string({
|
|
239
|
+
description: '[mysql, postgresql] database user name',
|
|
240
|
+
}),
|
|
241
|
+
'db-password': command_1.flags.string({
|
|
242
|
+
description: '[mysql, postgresql] database password',
|
|
243
|
+
}),
|
|
244
|
+
'db-database': command_1.flags.string({
|
|
245
|
+
description: '[mysql, postgresql] name of database to import',
|
|
246
|
+
}),
|
|
247
|
+
};
|
|
248
|
+
Import.postgresqlFlags = {
|
|
249
|
+
'db-schema': command_1.flags.string({
|
|
250
|
+
description: '[postgresql] database schema',
|
|
251
|
+
}),
|
|
252
|
+
};
|
|
253
|
+
Import.flagsForSchemas = [
|
|
254
|
+
{ flags: Import.curlFlags, schemas: ['curl'] },
|
|
255
|
+
{ flags: Import.sqlFlags, schemas: ['mysql', 'postgresql'] },
|
|
256
|
+
{ flags: Import.postgresqlFlags, schemas: ['postgresql'] },
|
|
257
|
+
];
|
|
258
|
+
Import.flags = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, zen_command_1.default.flags), { dir: command_1.flags.string({ description: 'working directory' }), help: command_1.flags.help({ char: 'h' }), silent: command_1.flags.boolean({ hidden: true }), name: command_1.flags.string({
|
|
259
|
+
description: 'subfolder inside the workspace folder to save the imported' +
|
|
260
|
+
' schema files, defaults to the imported schema name',
|
|
261
|
+
}) }), Import.curlFlags), Import.sqlFlags), Import.postgresqlFlags);
|
|
147
262
|
Import.args = [
|
|
148
263
|
{
|
|
149
264
|
name: 'schemas',
|
package/lib/commands/lint.js
CHANGED
|
@@ -22,6 +22,6 @@ class Init extends zen_command_1.default {
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
exports.default = Init;
|
|
25
|
-
Init.description = '
|
|
25
|
+
Init.description = 'StepZen lint';
|
|
26
26
|
Init.hidden = true;
|
|
27
27
|
Init.flags = Object.assign(Object.assign({}, zen_command_1.default.flags), { dir: command_1.flags.string({ hidden: true }), help: command_1.flags.help({ char: 'h' }) });
|
package/lib/commands/login.js
CHANGED
|
@@ -54,7 +54,7 @@ class Login extends zen_command_1.default {
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
exports.default = Login;
|
|
57
|
-
Login.description = '
|
|
57
|
+
Login.description = 'log in to StepZen';
|
|
58
58
|
Login.flags = Object.assign(Object.assign({}, zen_command_1.default.flags), { account: command_1.flags.string({
|
|
59
59
|
char: 'a',
|
|
60
60
|
exclusive: ['config', 'public'],
|
package/lib/commands/logout.js
CHANGED
|
@@ -14,5 +14,5 @@ class Logout extends zen_command_1.default {
|
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
exports.default = Logout;
|
|
17
|
-
Logout.description = 'log out of
|
|
17
|
+
Logout.description = 'log out of StepZen';
|
|
18
18
|
Logout.flags = Object.assign(Object.assign({}, zen_command_1.default.flags), { help: command_1.flags.help({ char: 'h' }) });
|
package/lib/commands/start.js
CHANGED
|
@@ -11,7 +11,6 @@ const utils_1 = require("../shared/utils");
|
|
|
11
11
|
const start_1 = require("../start");
|
|
12
12
|
const workspace_1 = require("../shared/workspace");
|
|
13
13
|
const init_1 = require("./init");
|
|
14
|
-
const dashboard_interface_1 = require("../generate/dashboard-interface");
|
|
15
14
|
const constants_1 = require("../shared/constants");
|
|
16
15
|
const zen_command_1 = require("../shared/zen-command");
|
|
17
16
|
const dashboard = require('@stepzen/dashboard');
|
|
@@ -81,7 +80,6 @@ class Start extends zen_command_1.default {
|
|
|
81
80
|
version,
|
|
82
81
|
},
|
|
83
82
|
domain: constants_1.STEPZEN_DOMAIN,
|
|
84
|
-
generators: dashboard_interface_1.createDashboardInterface(workspace),
|
|
85
83
|
predicates: {
|
|
86
84
|
available: true,
|
|
87
85
|
enabled: false,
|
package/lib/commands/upload.js
CHANGED
|
@@ -50,7 +50,7 @@ class Upload extends zen_command_1.default {
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
exports.default = Upload;
|
|
53
|
-
Upload.description = 'upload to
|
|
53
|
+
Upload.description = 'upload to StepZen';
|
|
54
54
|
// The uploaded resource is either a directory or a file. In case it is the former,
|
|
55
55
|
// it will be packaged into a zip archive and transferred.
|
|
56
56
|
Upload.flags = Object.assign(Object.assign({}, zen_command_1.default.flags), { dir: command_1.flags.string({
|
package/lib/commands/whoami.js
CHANGED
|
@@ -51,7 +51,7 @@ class WhoAmI extends zen_command_1.default {
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
exports.default = WhoAmI;
|
|
54
|
-
WhoAmI.description = '
|
|
54
|
+
WhoAmI.description = 'display your credentials with StepZen whoami';
|
|
55
55
|
WhoAmI.hidden = true;
|
|
56
56
|
WhoAmI.flags = Object.assign(Object.assign({}, zen_command_1.default.flags), { help: command_1.flags.help({ char: 'h' }), showkeys: command_1.flags.boolean({
|
|
57
57
|
default: false,
|
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
import { CurlArguments } from '../shared/curl-parser';
|
|
2
2
|
import { PathParam } from '../shared/path-params-parser';
|
|
3
|
+
export declare type NameValueHeaderInput = {
|
|
4
|
+
name: string;
|
|
5
|
+
value: string;
|
|
6
|
+
};
|
|
7
|
+
export declare type NamePartsHeaderInput = {
|
|
8
|
+
name: string;
|
|
9
|
+
parts: HeaderInputValuePart[];
|
|
10
|
+
};
|
|
11
|
+
export declare type HeaderInput = NameValueHeaderInput | NamePartsHeaderInput;
|
|
12
|
+
export declare type HeaderInputConstantValuePart = {
|
|
13
|
+
kind: 'Constant';
|
|
14
|
+
value: string;
|
|
15
|
+
};
|
|
16
|
+
export declare type HeaderInputVariableValuePart = {
|
|
17
|
+
kind: 'Variable';
|
|
18
|
+
value: string;
|
|
19
|
+
name: string;
|
|
20
|
+
};
|
|
21
|
+
export declare type HeaderInputValuePart = HeaderInputConstantValuePart | HeaderInputVariableValuePart;
|
|
3
22
|
export declare type Curl2SdlOptions = {
|
|
4
23
|
curlArgs: CurlArguments;
|
|
5
24
|
name?: string;
|
|
@@ -8,6 +27,7 @@ export declare type Curl2SdlOptions = {
|
|
|
8
27
|
rootType?: string;
|
|
9
28
|
typePrefix?: string;
|
|
10
29
|
pathParams: readonly PathParam[];
|
|
30
|
+
headers: readonly HeaderInput[];
|
|
11
31
|
};
|
|
12
32
|
export declare type EditableCurl2SdlOptions = Pick<Curl2SdlOptions, 'curlArgs' | 'queryName' | 'rootType' | 'typePrefix' | 'pathParams'>;
|
|
13
33
|
export declare type CurlAnswers = {
|
|
@@ -17,8 +37,35 @@ export declare type CurlAnswers = {
|
|
|
17
37
|
typePrefix: string;
|
|
18
38
|
pathParams: string;
|
|
19
39
|
};
|
|
40
|
+
export declare type CurlQueryParameter = {
|
|
41
|
+
name: string;
|
|
42
|
+
value: string;
|
|
43
|
+
context: string;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Collect together all query parameters from HTTP headers and from the
|
|
47
|
+
* pathname, and return them as a uniform list.
|
|
48
|
+
*
|
|
49
|
+
* @param {*} headers list of curl headers, possibly with parameters
|
|
50
|
+
* @param {*} pathParams list of path parameters
|
|
51
|
+
* @param {*} pathname full pathname of the REST endpoint
|
|
52
|
+
* @returns {*} combined list of query parameters in a uniform format
|
|
53
|
+
*/
|
|
54
|
+
export declare const compileParameterList: (headers: HeaderInput[], pathParams: PathParam[], pathname: string) => CurlQueryParameter[];
|
|
55
|
+
/**
|
|
56
|
+
* Check the header and path parameters for duplicates, and construct a
|
|
57
|
+
* user-friendly error message describing identified problems (if any).
|
|
58
|
+
* If no problems are found, return `null`.
|
|
59
|
+
*
|
|
60
|
+
* @param {*} headers list of curl headers, possibly with parameters
|
|
61
|
+
* @param {*} pathParams list of path parameters
|
|
62
|
+
* @param {*} url full URL of the REST endpoint
|
|
63
|
+
* @returns {*} a message describing duplicate query parameters, or null if
|
|
64
|
+
* there are no duplicates
|
|
65
|
+
*/
|
|
66
|
+
export declare const makeDuplicateParamsMessage: (headers: HeaderInput[], pathParams: PathParam[], url: string) => string | null;
|
|
20
67
|
export declare const askCurlQuestions: (defaultAnswers?: Partial<CurlAnswers>) => Promise<EditableCurl2SdlOptions>;
|
|
21
|
-
export declare const curl2sdl: ({ curlArgs, name, source, queryName, rootType, typePrefix, pathParams, }: Curl2SdlOptions) => Promise<{
|
|
68
|
+
export declare const curl2sdl: ({ curlArgs, name, source, queryName, rootType, typePrefix, pathParams, headers, }: Curl2SdlOptions) => Promise<{
|
|
22
69
|
error: string;
|
|
23
70
|
} | {
|
|
24
71
|
outPath: string;
|
package/lib/generate/curl2sdl.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// Copyright (c) 2020,2021,2022, StepZen, Inc.
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.curl2sdl = exports.askCurlQuestions = void 0;
|
|
4
|
+
exports.curl2sdl = exports.askCurlQuestions = exports.makeDuplicateParamsMessage = exports.compileParameterList = void 0;
|
|
5
5
|
const errors_1 = require("@oclif/errors");
|
|
6
6
|
const chalk = require("chalk");
|
|
7
7
|
const fs = require("fs-extra");
|
|
@@ -18,6 +18,84 @@ const curl_parser_1 = require("../shared/curl-parser");
|
|
|
18
18
|
const path_params_parser_1 = require("../shared/path-params-parser");
|
|
19
19
|
const constants_1 = require("../shared/constants");
|
|
20
20
|
const errors_2 = require("../shared/errors");
|
|
21
|
+
/**
|
|
22
|
+
* Collect together all query parameters from HTTP headers and from the
|
|
23
|
+
* pathname, and return them as a uniform list.
|
|
24
|
+
*
|
|
25
|
+
* @param {*} headers list of curl headers, possibly with parameters
|
|
26
|
+
* @param {*} pathParams list of path parameters
|
|
27
|
+
* @param {*} pathname full pathname of the REST endpoint
|
|
28
|
+
* @returns {*} combined list of query parameters in a uniform format
|
|
29
|
+
*/
|
|
30
|
+
exports.compileParameterList = (headers, pathParams, pathname) => {
|
|
31
|
+
// Drop empty segments, including empty string before the leading slash
|
|
32
|
+
const pathSegments = pathname.split('/').filter(Boolean);
|
|
33
|
+
// For each header, make a list of the parameters it contains.
|
|
34
|
+
// `flatMap()` concatenates each header's param lists into a single list.
|
|
35
|
+
return lodash_1.flatMap(headers, header => {
|
|
36
|
+
// skip headers that don't contain parameters
|
|
37
|
+
if (!('parts' in header)) {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
// Reconstruct the full header string (for the context).
|
|
41
|
+
const fullHeader = `${header.name}: ${header.parts
|
|
42
|
+
.map(part => part.value)
|
|
43
|
+
.join('')}`;
|
|
44
|
+
// Filter out the 'Variable' parts of the header value, and convert them
|
|
45
|
+
// to the `CurlyQueryParameter` structure.
|
|
46
|
+
return header.parts
|
|
47
|
+
.map(part => part.kind === 'Variable'
|
|
48
|
+
? {
|
|
49
|
+
name: part.name,
|
|
50
|
+
value: part.value,
|
|
51
|
+
context: `'${header.name}' header ${chalk.dim(`(${fullHeader})`)}`,
|
|
52
|
+
}
|
|
53
|
+
: null)
|
|
54
|
+
.filter(Boolean); // remove nulls
|
|
55
|
+
}).concat(
|
|
56
|
+
// Append the path parameters to the list, converting them to
|
|
57
|
+
// the `CurlyQueryParameter` structure as well.
|
|
58
|
+
pathParams.map(param => ({
|
|
59
|
+
name: param.name,
|
|
60
|
+
value: pathSegments[param.index],
|
|
61
|
+
context: `pathname ${chalk.dim(`(${pathname})`)}`,
|
|
62
|
+
})));
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Check the header and path parameters for duplicates, and construct a
|
|
66
|
+
* user-friendly error message describing identified problems (if any).
|
|
67
|
+
* If no problems are found, return `null`.
|
|
68
|
+
*
|
|
69
|
+
* @param {*} headers list of curl headers, possibly with parameters
|
|
70
|
+
* @param {*} pathParams list of path parameters
|
|
71
|
+
* @param {*} url full URL of the REST endpoint
|
|
72
|
+
* @returns {*} a message describing duplicate query parameters, or null if
|
|
73
|
+
* there are no duplicates
|
|
74
|
+
*/
|
|
75
|
+
exports.makeDuplicateParamsMessage = (headers, pathParams, url) => {
|
|
76
|
+
// Create a uniform list of query parameters from the headers and path
|
|
77
|
+
const parameters = exports.compileParameterList(headers, pathParams, new URL(url).pathname);
|
|
78
|
+
const errors = Object.entries(lodash_1.groupBy(parameters, 'name'))
|
|
79
|
+
// Create groups for each unique parameter name,
|
|
80
|
+
// and then sub-groups for each unique [name, value] tuple.
|
|
81
|
+
.map(([name, group]) => ({
|
|
82
|
+
name,
|
|
83
|
+
values: Object.entries(lodash_1.groupBy(group, 'value')),
|
|
84
|
+
}))
|
|
85
|
+
// ignore the [name, value] tuples that occur only once
|
|
86
|
+
.filter(({ values }) => values.length > 1)
|
|
87
|
+
// for the rest, create a message describing the duplicates
|
|
88
|
+
.map(({ name, values }) => `The parameter ${chalk.bold(`$${name}`)} is used for ${values.length} different values:` +
|
|
89
|
+
`\n${values
|
|
90
|
+
.map(([value, params], i) => `\t${i + 1}: '${value}' in the ${params[0].context}`)
|
|
91
|
+
.join('\n')}`);
|
|
92
|
+
if (errors.length > 0) {
|
|
93
|
+
return ('Could not use the same name for different parameters.\n' +
|
|
94
|
+
errors.join('\n') +
|
|
95
|
+
'\nPlease give a different parameter name for each variable value.');
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
};
|
|
21
99
|
exports.askCurlQuestions = async (defaultAnswers = {}) => {
|
|
22
100
|
let questions = [
|
|
23
101
|
{
|
|
@@ -73,7 +151,7 @@ exports.askCurlQuestions = async (defaultAnswers = {}) => {
|
|
|
73
151
|
pathParams: parsedPathParamsOrError,
|
|
74
152
|
};
|
|
75
153
|
};
|
|
76
|
-
exports.curl2sdl = async ({ curlArgs, name, source, queryName, rootType, typePrefix, pathParams, }) => {
|
|
154
|
+
exports.curl2sdl = async ({ curlArgs, name, source, queryName, rootType, typePrefix, pathParams, headers, }) => {
|
|
77
155
|
let json;
|
|
78
156
|
try {
|
|
79
157
|
const url = `${constants_1.STEPZEN_JSON2SDL_SERVER_URL}/api/graphql`;
|
|
@@ -106,7 +184,7 @@ exports.curl2sdl = async ({ curlArgs, name, source, queryName, rootType, typePre
|
|
|
106
184
|
queryName: queryName || null,
|
|
107
185
|
rootType: rootType || null,
|
|
108
186
|
typePrefix: typePrefix || null,
|
|
109
|
-
headers:
|
|
187
|
+
headers: headers.length > 0 ? headers : null,
|
|
110
188
|
data: curlArgs.data || null,
|
|
111
189
|
method: curlArgs.method,
|
|
112
190
|
pathParams: pathParams.length > 0 ? pathParams : null,
|
package/lib/generate/helpers.js
CHANGED
|
@@ -121,15 +121,13 @@ exports.askGeneratorQuestions = async (id, settings, state) => {
|
|
|
121
121
|
var _a, _b;
|
|
122
122
|
let status = -1;
|
|
123
123
|
do {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
? lodash_1.get(state, question.name)
|
|
132
|
-
: undefined })));
|
|
124
|
+
const questions = settings.questions.map((question) => {
|
|
125
|
+
return Object.assign(Object.assign({ type: 'password' }, question), {
|
|
126
|
+
// set the previous iteration's answer as the default value, except for password fields
|
|
127
|
+
default: question.type && question.type !== 'password'
|
|
128
|
+
? lodash_1.get(state, question.name)
|
|
129
|
+
: undefined });
|
|
130
|
+
});
|
|
133
131
|
// eslint-disable-next-line no-await-in-loop
|
|
134
132
|
const answers = await inquirer.prompt(questions);
|
|
135
133
|
state = lodash_1.merge(state, answers);
|
|
@@ -142,7 +140,12 @@ exports.askGeneratorQuestions = async (id, settings, state) => {
|
|
|
142
140
|
if (result.status === -1 && result.questions.length === 0) {
|
|
143
141
|
console.log();
|
|
144
142
|
console.log(chalk.red(`A problem occurred when running ${id} import${((_a = result.errors) === null || _a === void 0 ? void 0 : _a.error) ? `: "${(_b = result.errors) === null || _b === void 0 ? void 0 : _b.error}"` : '.'}`));
|
|
145
|
-
console.log('Please try again');
|
|
143
|
+
console.log('Please try again and check command-line parameters');
|
|
144
|
+
if (questions.length === 0) {
|
|
145
|
+
// all questions are pre-answered, so there is no chance to save the
|
|
146
|
+
// situation interactively => don't loop
|
|
147
|
+
throw new errors_1.CLIError('Unable to import');
|
|
148
|
+
}
|
|
146
149
|
}
|
|
147
150
|
else {
|
|
148
151
|
settings = {
|
package/lib/generate/index.d.ts
CHANGED
|
@@ -1,2 +1,6 @@
|
|
|
1
|
-
declare const _default: (schemas: any, name: string | undefined, source: string
|
|
1
|
+
declare const _default: (schemas: any, name: string | undefined, source: string, preAnswered?: {
|
|
2
|
+
[schema: string]: {
|
|
3
|
+
[question: string]: string;
|
|
4
|
+
};
|
|
5
|
+
}) => Promise<string>;
|
|
2
6
|
export default _default;
|
package/lib/generate/index.js
CHANGED
|
@@ -10,7 +10,7 @@ const os = require("os");
|
|
|
10
10
|
const path = require("path");
|
|
11
11
|
const transpiler_1 = require("@stepzen/transpiler");
|
|
12
12
|
const helpers_1 = require("./helpers");
|
|
13
|
-
exports.default = async (schemas, name, source) => {
|
|
13
|
+
exports.default = async (schemas, name, source, preAnswered = {}) => {
|
|
14
14
|
var e_1, _a, e_2, _b, e_3, _c, e_4, _d;
|
|
15
15
|
var _e;
|
|
16
16
|
// Store the generators
|
|
@@ -18,16 +18,20 @@ exports.default = async (schemas, name, source) => {
|
|
|
18
18
|
for (const schema of schemas) {
|
|
19
19
|
generators[schema] = null;
|
|
20
20
|
}
|
|
21
|
-
//
|
|
22
|
-
|
|
21
|
+
// Initial answers from flags. Assumption: <schema> -> <schema>_config
|
|
22
|
+
const initialAnswers = {};
|
|
23
|
+
Object.keys(generators).forEach(id => {
|
|
24
|
+
initialAnswers[`${id}_config`] = preAnswered[id] || {};
|
|
25
|
+
});
|
|
26
|
+
let answers = initialAnswers;
|
|
23
27
|
// Start downloading
|
|
24
28
|
core_1.CliUx.ux.action.start('Downloading from StepZen...');
|
|
25
29
|
try {
|
|
26
30
|
// Get all generators from...Generators
|
|
27
31
|
for (var _f = tslib_1.__asyncValues(Object.keys(generators)), _g; _g = await _f.next(), !_g.done;) {
|
|
28
32
|
const id = _g.value;
|
|
29
|
-
const configure = await helpers_1.getConfiguration(id,
|
|
30
|
-
if (configure) {
|
|
33
|
+
const configure = await helpers_1.getConfiguration(id, answers);
|
|
34
|
+
if (configure === null || configure === void 0 ? void 0 : configure.questions.length) {
|
|
31
35
|
generators[id] = {
|
|
32
36
|
questions: configure.questions,
|
|
33
37
|
type: 'generator',
|
|
@@ -3,8 +3,6 @@ export declare const STEPZEN_LAST_UPDATE_CHECK_TIMESTAMP: string;
|
|
|
3
3
|
export declare const STEPZEN_CONFIG_FILE: string;
|
|
4
4
|
export declare const STEPZEN_DOMAIN: string;
|
|
5
5
|
export declare const STEPZEN_SERVER_URL: string;
|
|
6
|
-
export declare const STEPZEN_GENERATOR_ENGINES_SCHEMA: string;
|
|
7
|
-
export declare const STEPZEN_GENERATOR_ENGINES_ENDPOINT = "stepzen-generator/engines";
|
|
8
6
|
export declare const STEPZEN_DIRECT_GENERATOR_ENGINES_URL: string;
|
|
9
7
|
export declare const STEPZEN_API_TEMPLATES_REPOSITORY = "https://github.com/steprz/stepzen-schemas";
|
|
10
8
|
export declare const ADMIN_DEPLOY_URL = "/cli/admin/deploy";
|
package/lib/shared/constants.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// Copyright (c) 2020,2021,2022, StepZen, Inc.
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.STEPZEN_DISCORD_URL = exports.STEPZEN_JSON2SDL_SERVER_URL = exports.ADMIN_ACCOUNT_URL = exports.ADMIN_UPLOAD_URL = exports.ADMIN_LIST_URL = exports.ADMIN_DEPLOY_URL = exports.STEPZEN_API_TEMPLATES_REPOSITORY = exports.STEPZEN_DIRECT_GENERATOR_ENGINES_URL = exports.
|
|
4
|
+
exports.STEPZEN_DISCORD_URL = exports.STEPZEN_JSON2SDL_SERVER_URL = exports.ADMIN_ACCOUNT_URL = exports.ADMIN_UPLOAD_URL = exports.ADMIN_LIST_URL = exports.ADMIN_DEPLOY_URL = exports.STEPZEN_API_TEMPLATES_REPOSITORY = exports.STEPZEN_DIRECT_GENERATOR_ENGINES_URL = exports.STEPZEN_SERVER_URL = exports.STEPZEN_DOMAIN = exports.STEPZEN_CONFIG_FILE = exports.STEPZEN_LAST_UPDATE_CHECK_TIMESTAMP = exports.STEPZEN_CONFIG_DIRECTORY = void 0;
|
|
5
5
|
// This file contains constants and all magic strings
|
|
6
6
|
const dotenv = require("dotenv");
|
|
7
7
|
const os = require("os");
|
|
@@ -9,7 +9,7 @@ const path = require("path");
|
|
|
9
9
|
// This allows you to set environment variables in a `.env` file.
|
|
10
10
|
// This file needs to be in your working directory.
|
|
11
11
|
dotenv.config();
|
|
12
|
-
const { STEPZEN_CONFIG_FILE: ENV_VAR_STEPZEN_CONFIG_FILE, STEPZEN_DOMAIN: ENV_VAR_STEPZEN_DOMAIN,
|
|
12
|
+
const { STEPZEN_CONFIG_FILE: ENV_VAR_STEPZEN_CONFIG_FILE, STEPZEN_DOMAIN: ENV_VAR_STEPZEN_DOMAIN, STEPZEN_SERVER_URL: ENV_VAR_STEPZEN_SERVER_URL, STEPZEN_JSON2SDL_SERVER_URL: ENV_VAR_STEPZEN_JSON2SDL_SERVER_URL, STEPZEN_DIRECT_GENERATOR_ENGINES_URL: ENV_VAR_STEPZEN_DIRECT_GENERATOR_ENGINES_URL, } = process.env;
|
|
13
13
|
// Where your authentication details are stored locally
|
|
14
14
|
exports.STEPZEN_CONFIG_DIRECTORY = path.join(os.homedir(), '.stepzen');
|
|
15
15
|
exports.STEPZEN_LAST_UPDATE_CHECK_TIMESTAMP = path.join(exports.STEPZEN_CONFIG_DIRECTORY, 'last_update_check.timestamp');
|
|
@@ -18,11 +18,6 @@ exports.STEPZEN_CONFIG_FILE = ENV_VAR_STEPZEN_CONFIG_FILE || 'stepzen-config.yam
|
|
|
18
18
|
exports.STEPZEN_DOMAIN = ENV_VAR_STEPZEN_DOMAIN || 'stepzen.io';
|
|
19
19
|
// The zenctl URL. Override with the env var `STEPZEN_SERVER_URL`
|
|
20
20
|
exports.STEPZEN_SERVER_URL = ENV_VAR_STEPZEN_SERVER_URL || 'https://{account}.stepzen.io';
|
|
21
|
-
// Generator Engines schema: folder/name
|
|
22
|
-
// Use 'stepzen/engines-dev' to test the dev instance of https://github.com/steprz/generator-engines
|
|
23
|
-
exports.STEPZEN_GENERATOR_ENGINES_SCHEMA = ENV_VAR_STEPZEN_GENERATOR_ENGINES_SCHEMA || 'stepzen/engines';
|
|
24
|
-
// Generator Engines schema: target API endpoint
|
|
25
|
-
exports.STEPZEN_GENERATOR_ENGINES_ENDPOINT = 'stepzen-generator/engines';
|
|
26
21
|
// If defined, call the generator engines cloud function directly, skipping zenctl
|
|
27
22
|
exports.STEPZEN_DIRECT_GENERATOR_ENGINES_URL = ENV_VAR_STEPZEN_DIRECT_GENERATOR_ENGINES_URL ||
|
|
28
23
|
'https://us-central1-stepzen-functions.cloudfunctions.net/generator-engine';
|
|
@@ -1,30 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
* Parse a header string according to https://curl.se/docs/manpage.html#-H
|
|
3
|
-
* and https://datatracker.ietf.org/doc/html/rfc2616#section-4.2
|
|
4
|
-
*
|
|
5
|
-
* @param {*} header a curl header string, e.g. `"api-key: asfdasdfad"`
|
|
6
|
-
* @returns {*} a name/value record or
|
|
7
|
-
* `null` for the `Header:` notation that means "remove this header" in
|
|
8
|
-
* the cURL spec or a error object if cannot parse the string.
|
|
9
|
-
*/
|
|
10
|
-
export declare const parseCurlHeaderString: (header: string) => {
|
|
1
|
+
export interface CurlHeader {
|
|
11
2
|
name: string;
|
|
12
3
|
value: string;
|
|
13
|
-
}
|
|
14
|
-
error: string;
|
|
15
|
-
};
|
|
4
|
+
}
|
|
16
5
|
export interface CurlArguments {
|
|
17
6
|
url: string;
|
|
18
7
|
method: 'Get' | 'Post';
|
|
19
|
-
headers:
|
|
20
|
-
name: string;
|
|
21
|
-
value: string;
|
|
22
|
-
}>;
|
|
8
|
+
headers: CurlHeader[];
|
|
23
9
|
data?: string;
|
|
24
10
|
}
|
|
25
11
|
export interface ParseError {
|
|
26
12
|
error: string;
|
|
27
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Parse a header string according to https://curl.se/docs/manpage.html#-H
|
|
16
|
+
* and https://datatracker.ietf.org/doc/html/rfc2616#section-4.2
|
|
17
|
+
*
|
|
18
|
+
* @param {*} header a curl header string, e.g. `"api-key: asfdasdfad"`
|
|
19
|
+
* @returns {*} a name/value record or
|
|
20
|
+
* `null` for the `Header:` notation that means "remove this header" in
|
|
21
|
+
* the cURL spec or a error object if cannot parse the string.
|
|
22
|
+
*/
|
|
23
|
+
export declare const parseCurlHeaderString: (header: string) => CurlHeader | null | ParseError;
|
|
28
24
|
/**
|
|
29
25
|
* Parse a curl command line arguments array to a JSON structure consumable by
|
|
30
26
|
* the StepZen introspection service backend.
|
|
@@ -26,7 +26,8 @@ exports.parseCurlHeaderString = (header) => {
|
|
|
26
26
|
return null;
|
|
27
27
|
}
|
|
28
28
|
// Check if it's a `Header;` case
|
|
29
|
-
if (trimmed.indexOf('
|
|
29
|
+
if (trimmed.indexOf(':') === -1 &&
|
|
30
|
+
trimmed.indexOf(';') === trimmed.length - 1) {
|
|
30
31
|
return {
|
|
31
32
|
name: trimmed.substring(0, trimmed.length - 1).trim(),
|
|
32
33
|
value: '',
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { HeaderInput } from '../generate/curl2sdl';
|
|
2
|
+
import { ParseError, CurlHeader } from './curl-parser';
|
|
3
|
+
export declare const parseHeaderParam: (headers: readonly CurlHeader[], headerParam: string) => {
|
|
4
|
+
header: HeaderInput;
|
|
5
|
+
remainingHeaders: CurlHeader[];
|
|
6
|
+
} | ParseError;
|
|
7
|
+
export declare const makeHeaders: (curlHeaders: readonly CurlHeader[], headerParams?: readonly string[]) => ParseError | HeaderInput[];
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright (c) 2020,2021,2022, StepZen, Inc.
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.makeHeaders = exports.parseHeaderParam = void 0;
|
|
5
|
+
const chalk = require("chalk");
|
|
6
|
+
const debug = require("debug");
|
|
7
|
+
const curl_parser_1 = require("./curl-parser");
|
|
8
|
+
const headerParamRegex = /^(?<prefix>([^$]|\$\$)*)(?<param>\$[_A-Za-z]\w*);?(?<suffix>.*)$/;
|
|
9
|
+
exports.parseHeaderParam = (headers, headerParam) => {
|
|
10
|
+
const headerOrError = curl_parser_1.parseCurlHeaderString(headerParam);
|
|
11
|
+
if (!headerOrError || 'error' in headerOrError) {
|
|
12
|
+
if (headerOrError) {
|
|
13
|
+
debug('stepzen:curl2sdl')(`Failed to parse a header param ${headerParam}.` +
|
|
14
|
+
` Error: ${headerOrError.error}`);
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
error: `Could not find a header name in` +
|
|
18
|
+
` ${chalk.bold(`--header-param '${headerParam}'`)}.`,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const { name, value } = headerOrError;
|
|
22
|
+
const paramValueMatches = value.match(headerParamRegex);
|
|
23
|
+
if (!paramValueMatches || !paramValueMatches.groups) {
|
|
24
|
+
return {
|
|
25
|
+
error: `Could not find a $-prefixed parameter name in` +
|
|
26
|
+
` ${chalk.bold(`--header-param '${headerParam}'`)}.` +
|
|
27
|
+
` Did you use single quotes to prevent shell variable expansion?`,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const prefix = paramValueMatches.groups.prefix.replace(/\$\$/g, '$');
|
|
31
|
+
const paramName = paramValueMatches.groups.param.substring(1);
|
|
32
|
+
const suffix = paramValueMatches.groups.suffix.replace(/\$\$/g, '$');
|
|
33
|
+
if (suffix.match(headerParamRegex)) {
|
|
34
|
+
return {
|
|
35
|
+
error: `StepZen CLI currently supports at max 1 parameter per header` +
|
|
36
|
+
` ${chalk.bold(`--header-param '${headerParam}'`)} has several.`,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
const candidates = headers.filter(h => h.name.toLowerCase() === name.toLowerCase());
|
|
40
|
+
if (candidates.length === 0) {
|
|
41
|
+
return {
|
|
42
|
+
error: `Could not find a matching '-H, --header' curl flag for` +
|
|
43
|
+
` ${chalk.bold(`--header-param '${headerParam}'`)}.` +
|
|
44
|
+
` No header matches the name ${name}.`,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const matches = candidates.filter(({ value }) => value.startsWith(prefix) &&
|
|
48
|
+
value.substring(prefix.length).endsWith(suffix));
|
|
49
|
+
if (matches.length === 0) {
|
|
50
|
+
return {
|
|
51
|
+
error: `Could not find a matching '-H, --header' curl flag for` +
|
|
52
|
+
` ${chalk.bold(`--header-param '${headerParam}'`)}.` +
|
|
53
|
+
(candidates.length > 1
|
|
54
|
+
? ` None of the ${name} headers matches the '${value}' pattern.`
|
|
55
|
+
: ` The ${name} header does not match the '${value}' pattern.`),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
if (matches.length > 1) {
|
|
59
|
+
debug('stepzen:curl2sdl')(`Ambiguous --header-param '${headerParam}'. Matched headers:` +
|
|
60
|
+
`\n${matches
|
|
61
|
+
.map(header => `\t-H '${header.name}: ${header.value}'`)
|
|
62
|
+
.join('\n')}` +
|
|
63
|
+
`\nUsing the first match.`);
|
|
64
|
+
}
|
|
65
|
+
const asConstantHeaderValuePart = (value) => ({
|
|
66
|
+
kind: 'Constant',
|
|
67
|
+
value,
|
|
68
|
+
});
|
|
69
|
+
const asVariableHeaderValuePart = (value, name) => ({
|
|
70
|
+
kind: 'Variable',
|
|
71
|
+
value,
|
|
72
|
+
name,
|
|
73
|
+
});
|
|
74
|
+
return {
|
|
75
|
+
header: {
|
|
76
|
+
name: matches[0].name,
|
|
77
|
+
parts: [
|
|
78
|
+
...(prefix
|
|
79
|
+
? [asConstantHeaderValuePart(prefix)]
|
|
80
|
+
: [
|
|
81
|
+
/* spreading an empty array is a no-op */
|
|
82
|
+
]),
|
|
83
|
+
asVariableHeaderValuePart(matches[0].value.substring(prefix.length, matches[0].value.length - suffix.length), paramName),
|
|
84
|
+
...(suffix
|
|
85
|
+
? [asConstantHeaderValuePart(suffix)]
|
|
86
|
+
: [
|
|
87
|
+
/* spreading an empty array is a no-op */
|
|
88
|
+
]),
|
|
89
|
+
],
|
|
90
|
+
},
|
|
91
|
+
// assume each --header is referenced by at most one --header-param
|
|
92
|
+
remainingHeaders: headers.filter(h => h !== matches[0]),
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
exports.makeHeaders = (curlHeaders, headerParams = []) => {
|
|
96
|
+
const headers = [];
|
|
97
|
+
let remainingCurlHeaders = curlHeaders;
|
|
98
|
+
for (const headerParam of headerParams) {
|
|
99
|
+
const resultOrError = exports.parseHeaderParam(remainingCurlHeaders, headerParam);
|
|
100
|
+
if ('error' in resultOrError) {
|
|
101
|
+
return resultOrError;
|
|
102
|
+
}
|
|
103
|
+
headers.push(resultOrError.header);
|
|
104
|
+
remainingCurlHeaders = resultOrError.remainingHeaders;
|
|
105
|
+
}
|
|
106
|
+
headers.push(...remainingCurlHeaders);
|
|
107
|
+
return headers;
|
|
108
|
+
};
|
package/oclif.manifest.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"0.
|
|
1
|
+
{"version":"0.16.0-beta.2","commands":{"deploy":{"id":"deploy","description":"deploy to stepzen","pluginName":"stepzen","pluginType":"core","aliases":[],"flags":{"non-interactive":{"name":"non-interactive","type":"boolean","description":"disable all interactive prompts","hidden":true,"allowNo":false},"configurationsets":{"name":"configurationsets","type":"option","description":"Configurationsets to use","default":""},"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"schema":{"name":"schema","type":"option","description":"Schema to use","required":true},"silent":{"name":"silent","type":"boolean","allowNo":false}},"args":[{"name":"destination","description":"destination","required":true}]},"import":{"id":"import","description":"import a schema for an external data source or a API endpoint to your GraphQL API","pluginName":"stepzen","pluginType":"core","aliases":[],"flags":{"non-interactive":{"name":"non-interactive","type":"boolean","description":"disable all interactive prompts","hidden":true,"allowNo":false},"dir":{"name":"dir","type":"option","description":"working directory"},"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"silent":{"name":"silent","type":"boolean","hidden":true,"allowNo":false},"name":{"name":"name","type":"option","description":"subfolder inside the workspace folder to save the imported schema files, defaults to the imported schema name"},"prefix":{"name":"prefix","type":"option","description":"[curl] prefix to add every type in the generated schema."},"query-name":{"name":"query-name","type":"option","description":"[curl] property name to add to the Query type as a way to access the imported cURL endpoint."},"query-type":{"name":"query-type","type":"option","description":"[curl] name for the type returned by the cURL endpoint in the generated schema. The name specified by --query-type is not prefixed by --prefix if both flags are present."},"path-params":{"name":"path-params","type":"option","description":"[curl] specifies path parameters in the URL path. Can be formed by taking the original path and replacing the variable segments with $paramName placeholders.\n\nExample:\nstepzen import curl https://example.com/users/jane/posts/12 --path-params '/users/$userId/posts/$postId'"},"header-param":{"name":"header-param","type":"option","description":"[curl] specifies a parameter in a header value. Can be formed by taking a -H, --header flag and replacing the variable part of the header value with a $paramName placeholder. Repeat this flag once for each header with a parameter.\n\nExample:\nstepzen import curl https://example.com/api/customers \\\n\t-H \"Authorization: apikey SecretAPIKeyValue\" \\\n\t--header-param 'Authorization: apikey $apikey'"},"db-host":{"name":"db-host","type":"option","description":"[mysql, postgresql] database host"},"db-user":{"name":"db-user","type":"option","description":"[mysql, postgresql] database user name"},"db-password":{"name":"db-password","type":"option","description":"[mysql, postgresql] database password"},"db-database":{"name":"db-database","type":"option","description":"[mysql, postgresql] name of database to import"},"db-schema":{"name":"db-schema","type":"option","description":"[postgresql] database schema"}},"args":[{"name":"schemas","required":true}]},"init":{"id":"init","description":"stepzen init","pluginName":"stepzen","pluginType":"core","hidden":true,"aliases":[],"flags":{"non-interactive":{"name":"non-interactive","type":"boolean","description":"disable all interactive prompts","hidden":true,"allowNo":false},"endpoint":{"name":"endpoint","type":"option","hidden":true},"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"yes":{"name":"yes","type":"boolean","hidden":true,"allowNo":false}},"args":[{"name":"directory","hidden":true}]},"lint":{"id":"lint","description":"StepZen lint","pluginName":"stepzen","pluginType":"core","hidden":true,"aliases":[],"flags":{"non-interactive":{"name":"non-interactive","type":"boolean","description":"disable all interactive prompts","hidden":true,"allowNo":false},"dir":{"name":"dir","type":"option","hidden":true},"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"list":{"id":"list","description":"list your items","pluginName":"stepzen","pluginType":"core","aliases":[],"flags":{"non-interactive":{"name":"non-interactive","type":"boolean","description":"disable all interactive prompts","hidden":true,"allowNo":false},"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[{"name":"type","description":"type","required":true,"options":["configurationsets","schemas"]}]},"login":{"id":"login","description":"log in to StepZen","pluginName":"stepzen","pluginType":"core","aliases":[],"flags":{"non-interactive":{"name":"non-interactive","type":"boolean","description":"disable all interactive prompts","hidden":true,"allowNo":false},"account":{"name":"account","type":"option","char":"a","hidden":true},"adminkey":{"name":"adminkey","type":"option","char":"k","hidden":true},"public":{"name":"public","type":"boolean","description":"Create a public anonymous StepZen account and use it. This is handy for trying StepZen out, but it not suitable for handling private data as all endpoints created with a public account will be public.","allowNo":false},"config":{"name":"config","type":"option","hidden":true},"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"logout":{"id":"logout","description":"log out of StepZen","pluginName":"stepzen","pluginType":"core","aliases":[],"flags":{"non-interactive":{"name":"non-interactive","type":"boolean","description":"disable all interactive prompts","hidden":true,"allowNo":false},"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[]},"start":{"id":"start","description":"upload and deploy your schema","pluginName":"stepzen","pluginType":"core","aliases":[],"flags":{"non-interactive":{"name":"non-interactive","type":"boolean","description":"disable all interactive prompts","hidden":true,"allowNo":false},"dir":{"name":"dir","type":"option","description":"working directory"},"endpoint":{"name":"endpoint","type":"option","description":"Override workspace endpoint"},"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"no-console":{"name":"no-console","type":"boolean","hidden":true,"allowNo":false},"no-dashboard":{"name":"no-dashboard","type":"boolean","hidden":true,"allowNo":false},"no-init":{"name":"no-init","type":"boolean","hidden":true,"allowNo":false},"no-server":{"name":"no-server","type":"boolean","hidden":true,"allowNo":false},"no-validate":{"name":"no-validate","type":"boolean","hidden":true,"allowNo":false},"no-watcher":{"name":"no-watcher","type":"boolean","hidden":true,"allowNo":false},"port":{"name":"port","type":"option","default":5001}},"args":[]},"transpile":{"id":"transpile","description":"transpile a graphql schema","pluginName":"stepzen","pluginType":"core","hidden":true,"aliases":[],"flags":{"non-interactive":{"name":"non-interactive","type":"boolean","description":"disable all interactive prompts","hidden":true,"allowNo":false},"config":{"name":"config","type":"option","hidden":true},"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"hide-output":{"name":"hide-output","type":"boolean","hidden":true,"allowNo":false},"inspect":{"name":"inspect","type":"boolean","char":"i","hidden":true,"allowNo":false},"inspect-after":{"name":"inspect-after","type":"boolean","hidden":true,"allowNo":false},"output-configuration":{"name":"output-configuration","type":"boolean","allowNo":false},"silent":{"name":"silent","type":"boolean","allowNo":false}},"args":[{"name":"folder","required":true}]},"upload":{"id":"upload","description":"upload to StepZen","pluginName":"stepzen","pluginType":"core","aliases":[],"flags":{"non-interactive":{"name":"non-interactive","type":"boolean","description":"disable all interactive prompts","hidden":true,"allowNo":false},"dir":{"name":"dir","type":"option","description":"A directory to upload"},"file":{"name":"file","type":"option","description":"A file to upload"},"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"silent":{"name":"silent","type":"boolean","allowNo":false}},"args":[{"name":"type","description":"type","required":true,"options":["configurationset","schema"]},{"name":"destination","description":"destination","required":true}]},"validate":{"id":"validate","description":"validate a graphql schema","pluginName":"stepzen","pluginType":"core","hidden":true,"aliases":[],"flags":{"non-interactive":{"name":"non-interactive","type":"boolean","description":"disable all interactive prompts","hidden":true,"allowNo":false},"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false}},"args":[{"name":"folder","required":true}]},"whoami":{"id":"whoami","description":"display your credentials with StepZen whoami","pluginName":"stepzen","pluginType":"core","hidden":true,"aliases":[],"flags":{"non-interactive":{"name":"non-interactive","type":"boolean","description":"disable all interactive prompts","hidden":true,"allowNo":false},"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"showkeys":{"name":"showkeys","type":"boolean","allowNo":false},"apikey":{"name":"apikey","type":"boolean","allowNo":false},"adminkey":{"name":"adminkey","type":"boolean","allowNo":false}},"args":[]}}}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stepzen",
|
|
3
3
|
"description": "The StepZen CLI",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.16.0-beta.2",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Darren Waddell <darren@stepzen.com>",
|
|
7
7
|
"contributors": [
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
"@oclif/core": "1.7.0",
|
|
32
32
|
"@oclif/errors": "1.3.5",
|
|
33
33
|
"@oclif/plugin-help": "^5.1.12",
|
|
34
|
-
"@stepzen/dashboard": "0.
|
|
35
|
-
"@stepzen/sdk": "0.11.
|
|
36
|
-
"@stepzen/transpiler": "0.0.
|
|
34
|
+
"@stepzen/dashboard": "0.2.0",
|
|
35
|
+
"@stepzen/sdk": "0.11.2",
|
|
36
|
+
"@stepzen/transpiler": "0.0.39",
|
|
37
37
|
"chalk": "^4.1.1",
|
|
38
38
|
"chokidar": "^3.5.2",
|
|
39
39
|
"compare-versions": "^3.6.0",
|
|
@@ -99,6 +99,7 @@
|
|
|
99
99
|
"semver": "^7.3.7",
|
|
100
100
|
"sinon": "13.0.1",
|
|
101
101
|
"sinon-chai": "3.7.0",
|
|
102
|
+
"strip-ansi": "^6.0.1",
|
|
102
103
|
"ts-node": "^8.10.2",
|
|
103
104
|
"typescript": "^3.9.7"
|
|
104
105
|
},
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// Copyright (c) 2020,2021,2022, StepZen, Inc.
|
|
3
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.createDashboardInterface = void 0;
|
|
5
|
-
const fs = require("fs-extra");
|
|
6
|
-
const os = require("os");
|
|
7
|
-
const path = require("path");
|
|
8
|
-
const deploy_1 = require("../commands/deploy");
|
|
9
|
-
const constants_1 = require("../shared/constants");
|
|
10
|
-
const { merge } = require('@stepzen/transpiler');
|
|
11
|
-
exports.createDashboardInterface = (workspace) => ({
|
|
12
|
-
endpoint: constants_1.STEPZEN_GENERATOR_ENGINES_ENDPOINT,
|
|
13
|
-
onStart: async () => {
|
|
14
|
-
await deploy_1.default.run([
|
|
15
|
-
constants_1.STEPZEN_GENERATOR_ENGINES_ENDPOINT,
|
|
16
|
-
'--schema',
|
|
17
|
-
constants_1.STEPZEN_GENERATOR_ENGINES_SCHEMA,
|
|
18
|
-
'--silent',
|
|
19
|
-
]);
|
|
20
|
-
},
|
|
21
|
-
onImport: async (id, files) => {
|
|
22
|
-
const tmp = path.join(os.tmpdir(), `stepzen-generated-schema-${Date.now()}`);
|
|
23
|
-
fs.ensureDirSync(tmp);
|
|
24
|
-
for (const file of files) {
|
|
25
|
-
const cleaned = file.name.replace(os.tmpdir(), '');
|
|
26
|
-
const dir = path.join(tmp, cleaned);
|
|
27
|
-
fs.writeFileSync(dir, file.content);
|
|
28
|
-
}
|
|
29
|
-
const built = await merge(workspace.schema, {
|
|
30
|
-
name: id,
|
|
31
|
-
source: tmp,
|
|
32
|
-
}, {
|
|
33
|
-
silent: true,
|
|
34
|
-
});
|
|
35
|
-
fs.copySync(built, workspace.schema);
|
|
36
|
-
fs.removeSync(built);
|
|
37
|
-
fs.removeSync(tmp);
|
|
38
|
-
return {
|
|
39
|
-
success: true,
|
|
40
|
-
};
|
|
41
|
-
},
|
|
42
|
-
});
|