stepzen 0.15.0-beta.2 → 0.16.0-beta.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 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.15.0-beta.2 darwin-x64 node-v14.19.1
32
+ stepzen/0.16.0-beta.1 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
- Import a schema for an external data source or a API endpoint to your GraphQL API.
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
- Log in to StepZen
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 stepzen
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 stepzen
205
+ upload to StepZen
181
206
 
182
207
  ```
183
208
  USAGE
@@ -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
- dir: flags.IOptionFlag<string | undefined>;
7
- help: import("@oclif/parser/lib/flags").IBooleanFlag<void>;
8
- silent: import("@oclif/parser/lib/flags").IBooleanFlag<boolean>;
9
- name: flags.IOptionFlag<string | undefined>;
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
  }
@@ -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.parse(Import);
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
- curl2sdlOptions = Object.assign(Object.assign({}, fixedOptions), (await curl2sdl_1.askCurlQuestions(editableOptions)));
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
- curl2sdlOptions = Object.assign(Object.assign(Object.assign({}, fixedOptions), editableOptions), { pathParams: parsedPathParamsOrError, curlArgs: argsOrError });
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
- ['prefix', 'query-type', 'query-name', 'path-params'].forEach(flag => {
105
- if (flag in flags) {
106
- this.log(chalk.gray(`The ${chalk.bold(`--${flag}`)} flag only applies when importing ${chalk.bold('curl')}. It will be ignored now.`));
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 = 'Import a schema for an external data source or a API endpoint to your GraphQL API.';
126
- Import.flags = 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({
127
- description: 'subfolder inside the workspace folder to save the imported' +
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
- }), 'query-name': command_1.flags.string({
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
- }), 'query-type': command_1.flags.string({
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
- }), 'path-params': command_1.flags.string({
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',
@@ -22,6 +22,6 @@ class Init extends zen_command_1.default {
22
22
  }
23
23
  }
24
24
  exports.default = Init;
25
- Init.description = 'stepzen lint';
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' }) });
@@ -54,7 +54,7 @@ class Login extends zen_command_1.default {
54
54
  }
55
55
  }
56
56
  exports.default = Login;
57
- Login.description = 'Log in to StepZen';
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'],
@@ -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 stepzen';
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' }) });
@@ -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,
@@ -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 stepzen';
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({
@@ -51,7 +51,7 @@ class WhoAmI extends zen_command_1.default {
51
51
  }
52
52
  }
53
53
  exports.default = WhoAmI;
54
- WhoAmI.description = 'stepzen whoami';
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;
@@ -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: curlArgs.headers.length > 0 ? curlArgs.headers : null,
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,
@@ -121,15 +121,13 @@ exports.askGeneratorQuestions = async (id, settings, state) => {
121
121
  var _a, _b;
122
122
  let status = -1;
123
123
  do {
124
- if (settings.questions.length === 0) {
125
- // would cause a hot loop, so it's an error
126
- throw new errors_1.CLIError(errors_2.PERMANENT_STEPZEN_ERROR);
127
- }
128
- const questions = settings.questions.map((question) => (Object.assign(Object.assign({ type: 'password' }, question), {
129
- // set the previous iteration's answer as the default value, except for password fields
130
- default: question.type && question.type !== 'password'
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 = {
@@ -1,2 +1,6 @@
1
- declare const _default: (schemas: any, name: string | undefined, source: string) => Promise<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;
@@ -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
- // Store the answers
22
- let answers = {};
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";
@@ -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.STEPZEN_GENERATOR_ENGINES_ENDPOINT = exports.STEPZEN_GENERATOR_ENGINES_SCHEMA = exports.STEPZEN_SERVER_URL = exports.STEPZEN_DOMAIN = exports.STEPZEN_CONFIG_FILE = exports.STEPZEN_LAST_UPDATE_CHECK_TIMESTAMP = exports.STEPZEN_CONFIG_DIRECTORY = void 0;
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, STEPZEN_GENERATOR_ENGINES_SCHEMA: ENV_VAR_STEPZEN_GENERATOR_ENGINES_SCHEMA, 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;
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
- } | null | {
14
- error: string;
15
- };
4
+ }
16
5
  export interface CurlArguments {
17
6
  url: string;
18
7
  method: 'Get' | 'Post';
19
- headers: Array<{
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(';') === trimmed.length - 1) {
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
+ };
@@ -1 +1 @@
1
- {"version":"0.15.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'"}},"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":"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":[]}}}
1
+ {"version":"0.16.0-beta.1","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.15.0-beta.2",
4
+ "version": "0.16.0-beta.1",
5
5
  "license": "MIT",
6
6
  "author": "Darren Waddell <darren@stepzen.com>",
7
7
  "contributors": [
@@ -31,7 +31,7 @@
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.1.37",
34
+ "@stepzen/dashboard": "0.2.0",
35
35
  "@stepzen/sdk": "0.11.0",
36
36
  "@stepzen/transpiler": "0.0.38",
37
37
  "chalk": "^4.1.1",
@@ -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,7 +0,0 @@
1
- export declare const createDashboardInterface: (workspace: any) => {
2
- endpoint: string;
3
- onStart: () => Promise<void>;
4
- onImport: (id: string, files: any) => Promise<{
5
- success: boolean;
6
- }>;
7
- };
@@ -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
- });