api 6.0.0 → 6.1.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.
Files changed (40) hide show
  1. package/README.md +1 -1
  2. package/dist/cache.d.ts +4 -1
  3. package/dist/cli/codegen/languages/typescript/util.d.ts +0 -1
  4. package/dist/cli/codegen/languages/typescript/util.js +1 -10
  5. package/dist/cli/codegen/languages/typescript.d.ts +22 -5
  6. package/dist/cli/codegen/languages/typescript.js +53 -17
  7. package/dist/cli/commands/install.js +33 -31
  8. package/dist/cli/storage.d.ts +10 -10
  9. package/dist/cli/storage.js +14 -1
  10. package/dist/core/errors/fetchError.d.ts +4 -4
  11. package/dist/core/getJSONSchemaDefaults.d.ts +0 -1
  12. package/dist/core/getJSONSchemaDefaults.js +0 -1
  13. package/dist/core/index.d.ts +1 -1
  14. package/dist/core/prepareAuth.d.ts +1 -1
  15. package/dist/core/prepareParams.js +8 -5
  16. package/dist/core/prepareServer.d.ts +0 -3
  17. package/dist/core/prepareServer.js +0 -3
  18. package/dist/fetcher.js +0 -1
  19. package/dist/index.js +0 -1
  20. package/dist/packageInfo.d.ts +1 -1
  21. package/dist/packageInfo.js +1 -1
  22. package/package.json +9 -22
  23. package/src/cache.ts +4 -1
  24. package/src/cli/codegen/index.ts +1 -1
  25. package/src/cli/codegen/language.ts +1 -1
  26. package/src/cli/codegen/languages/typescript/util.ts +0 -9
  27. package/src/cli/codegen/languages/typescript.ts +89 -27
  28. package/src/cli/commands/install.ts +14 -17
  29. package/src/cli/lib/prompt.ts +1 -1
  30. package/src/cli/storage.ts +27 -10
  31. package/src/core/errors/fetchError.ts +4 -4
  32. package/src/core/getJSONSchemaDefaults.ts +2 -3
  33. package/src/core/index.ts +7 -2
  34. package/src/core/prepareAuth.ts +4 -4
  35. package/src/core/prepareParams.ts +15 -10
  36. package/src/core/prepareServer.ts +0 -3
  37. package/src/fetcher.ts +2 -3
  38. package/src/index.ts +0 -1
  39. package/src/packageInfo.ts +1 -1
  40. package/tsconfig.json +1 -1
package/README.md CHANGED
@@ -40,7 +40,7 @@ Or you can use it dynamically (though you won't have fancy TypeScript types to h
40
40
 
41
41
  ```js
42
42
  const petstore = require('api')(
43
- 'https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/petstore.json'
43
+ 'https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/petstore.json',
44
44
  );
45
45
 
46
46
  petstore.listPets().then(({ data }) => {
package/dist/cache.d.ts CHANGED
@@ -3,8 +3,11 @@ import 'isomorphic-fetch';
3
3
  import Fetcher from './fetcher';
4
4
  type CacheStore = Record<string, {
5
5
  hash: string;
6
- path?: string;
7
6
  original: string | OASDocument;
7
+ /**
8
+ * @deprecated Deprecated in v4.5.0 in favor of `hash`.
9
+ */
10
+ path?: string;
8
11
  title?: string;
9
12
  version?: string;
10
13
  }>;
@@ -1,4 +1,3 @@
1
- export declare function formatter(content: string): string;
2
1
  /**
3
2
  * @see {@link https://www.30secondsofcode.org/js/s/word-wrap}
4
3
  */
@@ -3,11 +3,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  exports.__esModule = true;
6
- exports.generateTypeName = exports.toSafeString = exports.docblockEscape = exports.wordWrap = exports.formatter = void 0;
6
+ exports.generateTypeName = exports.toSafeString = exports.docblockEscape = exports.wordWrap = void 0;
7
7
  var lodash_camelcase_1 = __importDefault(require("lodash.camelcase"));
8
8
  var lodash_deburr_1 = __importDefault(require("lodash.deburr"));
9
9
  var lodash_startcase_1 = __importDefault(require("lodash.startcase"));
10
- var prettier_1 = require("prettier");
11
10
  /**
12
11
  * This is a mix of reserved JS words and keywords in TypeScript that might be reserved or
13
12
  * allowable but functionally confusing (like `let any = 'buster';`)
@@ -103,14 +102,6 @@ var RESERVED_WORDS = [
103
102
  'self',
104
103
  'window',
105
104
  ];
106
- function formatter(content) {
107
- return (0, prettier_1.format)(content, {
108
- parser: 'typescript',
109
- printWidth: 100,
110
- singleQuote: true
111
- });
112
- }
113
- exports.formatter = formatter;
114
105
  /**
115
106
  * @see {@link https://www.30secondsofcode.org/js/s/word-wrap}
116
107
  */
@@ -2,19 +2,22 @@ import type Storage from '../../storage';
2
2
  import type { InstallerOptions } from '../language';
3
3
  import type Oas from 'oas';
4
4
  import type { Operation } from 'oas';
5
- import type { ClassDeclaration } from 'ts-morph';
5
+ import type { ClassDeclaration, JSDocStructure, JSDocTagStructure, OptionalKind } from 'ts-morph';
6
6
  import { Project } from 'ts-morph';
7
7
  import CodeGeneratorLanguage from '../language';
8
8
  export interface TSGeneratorOptions {
9
- outputJS?: boolean;
10
9
  compilerTarget?: 'cjs' | 'esm';
10
+ outputJS?: boolean;
11
11
  }
12
12
  interface OperationTypeHousing {
13
+ operation: Operation;
13
14
  types: {
14
15
  params?: false | Record<'body' | 'formData' | 'metadata', string>;
15
- responses?: Record<string, string>;
16
+ responses?: Record<string | number, {
17
+ description?: string;
18
+ type: string;
19
+ }>;
16
20
  };
17
- operation: Operation;
18
21
  }
19
22
  export default class TSGenerator extends CodeGeneratorLanguage {
20
23
  project: Project;
@@ -57,6 +60,17 @@ export default class TSGenerator extends CodeGeneratorLanguage {
57
60
  * @see {@link https://npm.im/json-schema-to-ts}
58
61
  */
59
62
  createTypesFile(): import("ts-morph").SourceFile;
63
+ /**
64
+ * Add a new JSDoc `@tag` to an existing docblock.
65
+ *
66
+ */
67
+ static addTagToDocblock(docblock: OptionalKind<JSDocStructure>, tag: OptionalKind<JSDocTagStructure>): {
68
+ tags: OptionalKind<JSDocTagStructure>[];
69
+ description?: string | import("ts-morph").WriterFunction;
70
+ leadingTrivia?: string | import("ts-morph").WriterFunction | (string | import("ts-morph").WriterFunction)[];
71
+ trailingTrivia?: string | import("ts-morph").WriterFunction | (string | import("ts-morph").WriterFunction)[];
72
+ kind?: import("ts-morph").StructureKind.JSDoc;
73
+ };
60
74
  /**
61
75
  * Create operation accessors on the SDK.
62
76
  *
@@ -83,7 +97,10 @@ export default class TSGenerator extends CodeGeneratorLanguage {
83
97
  *
84
98
  */
85
99
  prepareResponseTypesForOperation(operation: Operation, operationId: string): {
86
- [x: string]: string;
100
+ [x: string]: {
101
+ type: string;
102
+ description: any;
103
+ };
87
104
  };
88
105
  /**
89
106
  * Add a given schema into our schema dataset that we'll be be exporting as types.
@@ -243,7 +243,7 @@ var TSGenerator = /** @class */ (function (_super) {
243
243
  // user will have `.d.ts` files for them instead.
244
244
  return {};
245
245
  }
246
- var code = (0, util_1.formatter)(sourceFile.text);
246
+ var code = sourceFile.text;
247
247
  if (file === 'index.js' && _this.compilerTarget === 'cjs') {
248
248
  /**
249
249
  * There's an annoying quirk with `ts-morph` where if we're exporting a default export
@@ -268,7 +268,7 @@ var TSGenerator = /** @class */ (function (_super) {
268
268
  return [2 /*return*/, __spreadArray(__spreadArray([], this.project.getSourceFiles().map(function (sourceFile) {
269
269
  var _a;
270
270
  return (_a = {},
271
- _a[sourceFile.getBaseName()] = (0, util_1.formatter)(sourceFile.getFullText()),
271
+ _a[sourceFile.getBaseName()] = sourceFile.getFullText(),
272
272
  _a);
273
273
  }), true), this.project
274
274
  .emitToMemory({ emitOnlyDtsFiles: true })
@@ -276,7 +276,7 @@ var TSGenerator = /** @class */ (function (_super) {
276
276
  .map(function (sourceFile) {
277
277
  var _a;
278
278
  return (_a = {},
279
- _a[path_1["default"].basename(sourceFile.filePath)] = (0, util_1.formatter)(sourceFile.text),
279
+ _a[path_1["default"].basename(sourceFile.filePath)] = sourceFile.text,
280
280
  _a);
281
281
  }), true).reduce(function (prev, next) { return Object.assign(prev, next); })];
282
282
  });
@@ -471,6 +471,16 @@ var TSGenerator = /** @class */ (function (_super) {
471
471
  });
472
472
  return sourceFile;
473
473
  };
474
+ /**
475
+ * Add a new JSDoc `@tag` to an existing docblock.
476
+ *
477
+ */
478
+ TSGenerator.addTagToDocblock = function (docblock, tag) {
479
+ var _a;
480
+ var tags = (_a = docblock.tags) !== null && _a !== void 0 ? _a : [];
481
+ tags.push(tag);
482
+ return __assign(__assign({}, docblock), { tags: tags });
483
+ };
474
484
  /**
475
485
  * Create operation accessors on the SDK.
476
486
  *
@@ -495,7 +505,10 @@ var TSGenerator = /** @class */ (function (_super) {
495
505
  return writer;
496
506
  };
497
507
  if (summary && description) {
498
- docblock.tags = [{ tagName: 'summary', text: (0, util_1.docblockEscape)((0, util_1.wordWrap)(summary)) }];
508
+ docblock = TSGenerator.addTagToDocblock(docblock, {
509
+ tagName: 'summary',
510
+ text: (0, util_1.docblockEscape)((0, util_1.wordWrap)(summary))
511
+ });
499
512
  }
500
513
  }
501
514
  var hasOptionalBody = false;
@@ -523,9 +536,9 @@ var TSGenerator = /** @class */ (function (_super) {
523
536
  }
524
537
  var returnType = 'Promise<FetchResponse<number, unknown>>';
525
538
  if (responseTypes) {
526
- returnType = "Promise<".concat(Object.entries(responseTypes)
539
+ var returnTypes = Object.entries(responseTypes)
527
540
  .map(function (_a) {
528
- var status = _a[0], responseType = _a[1];
541
+ var status = _a[0], _b = _a[1], responseDescription = _b.description, responseType = _b.type;
529
542
  if (status.toLowerCase() === 'default') {
530
543
  return "FetchResponse<number, ".concat(responseType, ">");
531
544
  }
@@ -536,17 +549,42 @@ var TSGenerator = /** @class */ (function (_super) {
536
549
  // it and should instead fall back to treating it as an unknown number.
537
550
  return "FetchResponse<number, ".concat(responseType, ">");
538
551
  }
552
+ if (Number(statusPrefix) >= 4) {
553
+ docblock = TSGenerator.addTagToDocblock(docblock, {
554
+ tagName: 'throws',
555
+ text: "FetchError<".concat(status, ", ").concat(responseType, ">").concat(responseDescription ? (0, util_1.docblockEscape)((0, util_1.wordWrap)(" ".concat(responseDescription))) : '')
556
+ });
557
+ return false;
558
+ }
539
559
  _this.usesHTTPMethodRangeInterface = true;
540
560
  return "FetchResponse<HTTPMethodRange<".concat(statusPrefix, "00, ").concat(statusPrefix, "99>, ").concat(responseType, ">");
541
561
  }
562
+ // 400 and 500 status code families are thrown as exceptions so adding them as a possible
563
+ // return type isn't valid.
564
+ if (Number(status) >= 400) {
565
+ docblock = TSGenerator.addTagToDocblock(docblock, {
566
+ tagName: 'throws',
567
+ text: "FetchError<".concat(status, ", ").concat(responseType, ">").concat(responseDescription ? (0, util_1.docblockEscape)((0, util_1.wordWrap)(" ".concat(responseDescription))) : '')
568
+ });
569
+ return false;
570
+ }
542
571
  return "FetchResponse<".concat(status, ", ").concat(responseType, ">");
543
572
  })
544
- .join(' | '), ">");
573
+ .filter(Boolean)
574
+ .join(' | ');
575
+ // If all of our documented responses are for error status codes then all we can document for
576
+ // anything else that might happen is `unknown`.
577
+ returnType = "Promise<".concat(returnTypes.length ? returnTypes : 'FetchResponse<number, unknown>', ">");
545
578
  }
579
+ var shouldAddAltTypedOverloads = Object.keys(parameters).length === 2 && hasOptionalBody && !hasOptionalMetadata;
546
580
  var operationIdAccessor = this.sdk.addMethod({
547
581
  name: operationId,
548
582
  returnType: returnType,
549
- docs: Object.keys(docblock).length ? [docblock] : null,
583
+ // If we're going to be creating typed method overloads for optional body an metadata handling
584
+ // we should only add a docblock to the first overload we create because IDE Intellisense will
585
+ // always use that and adding a docblock to all three will bloat the SDK with unused and
586
+ // unsurfaced method documentation.
587
+ docs: shouldAddAltTypedOverloads ? null : Object.keys(docblock).length ? [docblock] : null,
550
588
  statements: function (writer) {
551
589
  /**
552
590
  * @example return this.core.fetch('/pet/findByStatus', 'get', body, metadata);
@@ -564,7 +602,7 @@ var TSGenerator = /** @class */ (function (_super) {
564
602
  fetchStmt.write(', ');
565
603
  }
566
604
  fetchStmt.write(arg.name);
567
- if (totalParams > 1 && i !== totalParams) {
605
+ if (i !== totalParams - 1) {
568
606
  fetchStmt.write(', ');
569
607
  }
570
608
  });
@@ -576,10 +614,6 @@ var TSGenerator = /** @class */ (function (_super) {
576
614
  // If we have both body and metadata parameters but only body is optional we need to create
577
615
  // a couple function overloads as Typescript doesn't let us have an optional method parameter
578
616
  // come before one that's required.
579
- //
580
- // None of these accessor overloads will receive a docblock because the original will have
581
- // that covered.
582
- var shouldAddAltTypedOverloads = Object.keys(parameters).length === 2 && hasOptionalBody && !hasOptionalMetadata;
583
617
  if (shouldAddAltTypedOverloads) {
584
618
  // Create an overload that has both `body` and `metadata` parameters as required.
585
619
  operationIdAccessor.addOverload({
@@ -593,8 +627,7 @@ var TSGenerator = /** @class */ (function (_super) {
593
627
  // Create an overload that just has a single `metadata` parameter.
594
628
  operationIdAccessor.addOverload({
595
629
  parameters: [__assign({}, parameters.metadata)],
596
- returnType: returnType,
597
- docs: Object.keys(docblock).length ? [docblock] : null
630
+ returnType: returnType
598
631
  });
599
632
  // Create an overload that has both `body` and `metadata` parameters as optional. Even though
600
633
  // our `metadata` parameter is actually required for this operation this is the only way we're
@@ -746,7 +779,7 @@ var TSGenerator = /** @class */ (function (_super) {
746
779
  var res = Object.entries(schemas)
747
780
  .map(function (_a) {
748
781
  var _b;
749
- var status = _a[0], schema = _a[1].schema;
782
+ var status = _a[0], _c = _a[1], description = _c.description, schema = _c.schema;
750
783
  var typeName;
751
784
  if (typeof schema === 'string' && schema.startsWith('::convert::')) {
752
785
  // If this schema is a string and has our conversion prefix then we've already created
@@ -763,7 +796,10 @@ var TSGenerator = /** @class */ (function (_super) {
763
796
  return _b = {},
764
797
  // Types are prefixed with `types.` because that's how we're importing them from
765
798
  // `types.d.ts`.
766
- _b[status] = "types.".concat(typeName),
799
+ _b[status] = {
800
+ type: "types.".concat(typeName),
801
+ description: description
802
+ },
767
803
  _b;
768
804
  })
769
805
  .reduce(function (prev, next) { return Object.assign(prev, next); }, {});
@@ -43,7 +43,6 @@ var commander_1 = require("commander");
43
43
  var figures_1 = __importDefault(require("figures"));
44
44
  var oas_1 = __importDefault(require("oas"));
45
45
  var ora_1 = __importDefault(require("ora"));
46
- var validate_npm_package_name_1 = __importDefault(require("validate-npm-package-name"));
47
46
  var fetcher_1 = __importDefault(require("../../fetcher"));
48
47
  var codegen_1 = __importDefault(require("../codegen"));
49
48
  var prompt_1 = __importDefault(require("../lib/prompt"));
@@ -55,6 +54,7 @@ cmd
55
54
  .name('install')
56
55
  .description('install an API SDK into your codebase')
57
56
  .argument('<uri>', 'an API to install')
57
+ .option('-i, --identifier <identifier>', 'API identifier (eg. `@api/petstore`)')
58
58
  .addOption(new commander_1.Option('-l, --lang <language>', 'SDK language').choices([
59
59
  'js',
60
60
  'js-cjs',
@@ -107,10 +107,17 @@ cmd
107
107
  // @todo
108
108
  // logger(`It looks like you already have this API installed. Would you like to update it?`);
109
109
  }
110
- if (!fetcher_1["default"].isAPIRegistryUUID(uri)) return [3 /*break*/, 6];
110
+ if (!options.identifier) return [3 /*break*/, 6];
111
+ // `Storage.isIdentifierValid` will throw an exception if an identifier is invalid.
112
+ if (storage_1["default"].isIdentifierValid(options.identifier)) {
113
+ identifier = options.identifier;
114
+ }
115
+ return [3 /*break*/, 9];
116
+ case 6:
117
+ if (!fetcher_1["default"].isAPIRegistryUUID(uri)) return [3 /*break*/, 7];
111
118
  identifier = fetcher_1["default"].getProjectPrefixFromRegistryUUID(uri);
112
- return [3 /*break*/, 8];
113
- case 6: return [4 /*yield*/, (0, prompt_1["default"])({
119
+ return [3 /*break*/, 9];
120
+ case 7: return [4 /*yield*/, (0, prompt_1["default"])({
114
121
  type: 'text',
115
122
  name: 'value',
116
123
  message: 'What would you like to identify this API as? This will be how you import the SDK. (e.g. entering `petstore` would result in `@api/petstore`)',
@@ -118,23 +125,18 @@ cmd
118
125
  if (!value) {
119
126
  return false;
120
127
  }
121
- // Is this identifier already in storage?
122
- if (storage_1["default"].isInLockFile({ identifier: value })) {
123
- return "\"".concat(value, "\" is already taken in your `.api/` directory. Please enter another identifier.");
128
+ try {
129
+ return storage_1["default"].isIdentifierValid(value, true);
124
130
  }
125
- var isValidForNPM = (0, validate_npm_package_name_1["default"])("@api/".concat(value));
126
- if (!isValidForNPM.validForNewPackages) {
127
- // `prompts` doesn't support surfacing multiple errors in a `validate` call so we can
128
- // only surface the first to the user.
129
- return isValidForNPM.errors[0];
131
+ catch (err) {
132
+ return err.message;
130
133
  }
131
- return true;
132
134
  }
133
135
  })];
134
- case 7:
135
- (identifier = (_a.sent()).value);
136
- _a.label = 8;
137
136
  case 8:
137
+ (identifier = (_a.sent()).value);
138
+ _a.label = 9;
139
+ case 9:
138
140
  if (!identifier) {
139
141
  (0, logger_1["default"])('You must tell us what you would like to identify this API as in order to install it.', true);
140
142
  process.exit(1);
@@ -153,7 +155,7 @@ cmd
153
155
  (0, logger_1["default"])(err.message, true);
154
156
  process.exit(1);
155
157
  })];
156
- case 9:
158
+ case 10:
157
159
  oas = _a.sent();
158
160
  // @todo look for a prettier config and if we find one ask them if we should use it
159
161
  spinner = (0, ora_1["default"])('Generating your SDK').start();
@@ -169,7 +171,7 @@ cmd
169
171
  (0, logger_1["default"])(err.message, true);
170
172
  process.exit(1);
171
173
  })];
172
- case 10:
174
+ case 11:
173
175
  sdkSource = _a.sent();
174
176
  spinner = (0, ora_1["default"])('Saving your SDK into your codebase').start();
175
177
  return [4 /*yield*/, storage
@@ -182,15 +184,15 @@ cmd
182
184
  (0, logger_1["default"])(err.message, true);
183
185
  process.exit(1);
184
186
  })];
185
- case 11:
187
+ case 12:
186
188
  _a.sent();
187
- if (!generator.hasRequiredPackages()) return [3 /*break*/, 17];
189
+ if (!generator.hasRequiredPackages()) return [3 /*break*/, 18];
188
190
  (0, logger_1["default"])("".concat(figures_1["default"].warning, " This generator requires some packages to be installed alongside it:"));
189
191
  Object.entries(generator.requiredPackages).forEach(function (_a) {
190
192
  var pkg = _a[0], pkgInfo = _a[1];
191
193
  (0, logger_1["default"])(" ".concat(figures_1["default"].pointerSmall, " ").concat(pkg, ": ").concat(pkgInfo.reason, " ").concat(pkgInfo.url));
192
194
  });
193
- if (!!options.yes) return [3 /*break*/, 13];
195
+ if (!!options.yes) return [3 /*break*/, 14];
194
196
  return [4 /*yield*/, (0, prompt_1["default"])({
195
197
  type: 'confirm',
196
198
  name: 'value',
@@ -204,27 +206,27 @@ cmd
204
206
  process.exit(1);
205
207
  }
206
208
  })];
207
- case 12:
208
- _a.sent();
209
- _a.label = 13;
210
209
  case 13:
211
- spinner = (0, ora_1["default"])('Installing required packages').start();
210
+ _a.sent();
212
211
  _a.label = 14;
213
212
  case 14:
214
- _a.trys.push([14, 16, , 17]);
215
- return [4 /*yield*/, generator.installer(storage)];
213
+ spinner = (0, ora_1["default"])('Installing required packages').start();
214
+ _a.label = 15;
216
215
  case 15:
216
+ _a.trys.push([15, 17, , 18]);
217
+ return [4 /*yield*/, generator.installer(storage)];
218
+ case 16:
217
219
  _a.sent();
218
220
  spinner.succeed(spinner.text);
219
- return [3 /*break*/, 17];
220
- case 16:
221
+ return [3 /*break*/, 18];
222
+ case 17:
221
223
  err_1 = _a.sent();
222
224
  // @todo cleanup installed files
223
225
  spinner.fail(spinner.text);
224
226
  (0, logger_1["default"])(err_1.message, true);
225
227
  process.exit(1);
226
- return [3 /*break*/, 17];
227
- case 17:
228
+ return [3 /*break*/, 18];
229
+ case 18:
228
230
  (0, logger_1["default"])('🚀 All done!');
229
231
  return [2 /*return*/];
230
232
  }
@@ -23,6 +23,7 @@ export default class Storage {
23
23
  static getDefaultLockfile(): Lockfile;
24
24
  static generateIntegrityHash(definition: OASDocument): string;
25
25
  static getLockfile(): Lockfile;
26
+ static isIdentifierValid(identifier: string, prefixWithAPINamespace?: boolean): boolean;
26
27
  static isInLockFile(search: {
27
28
  identifier?: string;
28
29
  source?: string;
@@ -61,17 +62,16 @@ export default class Storage {
61
62
  * ├── openapi.json
62
63
  * └── package.json
63
64
  *
64
- * @param spec
65
65
  */
66
66
  save(spec: OASDocument): OASDocument;
67
67
  }
68
68
  export interface Lockfile {
69
+ apis: LockfileAPI[];
69
70
  /**
70
71
  * The `api.json` schema version. This will only ever change if we introduce breaking changes to
71
72
  * this store.
72
73
  */
73
74
  version: '1.0';
74
- apis: LockfileAPI[];
75
75
  }
76
76
  export interface LockfileAPI {
77
77
  /**
@@ -82,13 +82,11 @@ export interface LockfileAPI {
82
82
  */
83
83
  identifier: string;
84
84
  /**
85
- * The original source that was used to generate the SDK with.
85
+ * The version of `api` that was used to install this SDK.
86
86
  *
87
- * @example https://raw.githubusercontent.com/readmeio/oas-examples/main/3.0/json/petstore-simple.json
88
- * @example ./petstore.json
89
- * @example @developers/v2.0#nysezql0wwo236
87
+ * @example 5.0.0
90
88
  */
91
- source: string;
89
+ installerVersion: string;
92
90
  /**
93
91
  * An integrity hash that will be used to determine on `npx api update` calls if the API has
94
92
  * changed since the SDK was last generated.
@@ -97,9 +95,11 @@ export interface LockfileAPI {
97
95
  */
98
96
  integrity: string;
99
97
  /**
100
- * The version of `api` that was used to install this SDK.
98
+ * The original source that was used to generate the SDK with.
101
99
  *
102
- * @example 5.0.0
100
+ * @example https://raw.githubusercontent.com/readmeio/oas-examples/main/3.0/json/petstore-simple.json
101
+ * @example ./petstore.json
102
+ * @example @developers/v2.0#nysezql0wwo236
103
103
  */
104
- installerVersion: string;
104
+ source: string;
105
105
  }
@@ -43,6 +43,7 @@ var fs_1 = __importDefault(require("fs"));
43
43
  var path_1 = __importDefault(require("path"));
44
44
  var make_dir_1 = __importDefault(require("make-dir"));
45
45
  var ssri_1 = __importDefault(require("ssri"));
46
+ var validate_npm_package_name_1 = __importDefault(require("validate-npm-package-name"));
46
47
  var fetcher_1 = __importDefault(require("../fetcher"));
47
48
  var packageInfo_1 = require("../packageInfo");
48
49
  var Storage = /** @class */ (function () {
@@ -128,6 +129,19 @@ var Storage = /** @class */ (function () {
128
129
  }
129
130
  return Storage.lockfile;
130
131
  };
132
+ Storage.isIdentifierValid = function (identifier, prefixWithAPINamespace) {
133
+ // Is this identifier already in storage?
134
+ if (Storage.isInLockFile({ identifier: identifier })) {
135
+ throw new Error("\"".concat(identifier, "\" is already taken in your `.api/` directory. Please try another identifier."));
136
+ }
137
+ var isValidForNPM = (0, validate_npm_package_name_1["default"])(prefixWithAPINamespace ? "@api/".concat(identifier) : identifier);
138
+ if (!isValidForNPM.validForNewPackages) {
139
+ // `prompts` doesn't support surfacing multiple errors in a `validate` call so we can only
140
+ // surface the first to the user.
141
+ throw new Error("Identifier cannot be used for an NPM package: ".concat(isValidForNPM.errors[0]));
142
+ }
143
+ return true;
144
+ };
131
145
  Storage.isInLockFile = function (search) {
132
146
  // Because this method may run before we initialize a new storage object we should make sure
133
147
  // that we have a storage directory present.
@@ -221,7 +235,6 @@ var Storage = /** @class */ (function () {
221
235
  * ├── openapi.json
222
236
  * └── package.json
223
237
  *
224
- * @param spec
225
238
  */
226
239
  Storage.prototype.save = function (spec) {
227
240
  if (!this.identifier) {
@@ -1,12 +1,12 @@
1
- declare class FetchError extends Error {
1
+ declare class FetchError<Status = number, Data = unknown> extends Error {
2
2
  /** HTTP Status */
3
- status: number;
3
+ status: Status;
4
4
  /** The content of the response. */
5
- data: unknown;
5
+ data: Data;
6
6
  /** The Headers of the response. */
7
7
  headers: Headers;
8
8
  /** The raw `Response` object. */
9
9
  res: Response;
10
- constructor(status: number, data: unknown, headers: Headers, res: Response);
10
+ constructor(status: Status, data: Data, headers: Headers, res: Response);
11
11
  }
12
12
  export default FetchError;
@@ -8,7 +8,6 @@ import type { SchemaWrapper } from 'oas/dist/operation/get-parameters-as-json-sc
8
8
  *
9
9
  * @todo This is a good candidate to be moved into a core `oas` library method.
10
10
  * @see {@link https://github.com/mdornseif/json-schema-default}
11
- * @param jsonSchemas
12
11
  */
13
12
  export default function getJSONSchemaDefaults(jsonSchemas: SchemaWrapper[]): {
14
13
  [x: string]: Record<string, unknown>;
@@ -13,7 +13,6 @@ var json_schema_traverse_1 = __importDefault(require("json-schema-traverse"));
13
13
  *
14
14
  * @todo This is a good candidate to be moved into a core `oas` library method.
15
15
  * @see {@link https://github.com/mdornseif/json-schema-default}
16
- * @param jsonSchemas
17
16
  */
18
17
  function getJSONSchemaDefaults(jsonSchemas) {
19
18
  return jsonSchemas
@@ -16,9 +16,9 @@ export interface ConfigOptions {
16
16
  }
17
17
  export interface FetchResponse<status, data> {
18
18
  data: data;
19
- status: status;
20
19
  headers: Headers;
21
20
  res: Response;
21
+ status: status;
22
22
  }
23
23
  type Enumerate<N extends number, Acc extends number[] = []> = Acc['length'] extends N ? Acc[number] : Enumerate<N, [...Acc, Acc['length']]>;
24
24
  export type HTTPMethodRange<F extends number, T extends number> = Exclude<Enumerate<T>, Enumerate<F>>;
@@ -1,5 +1,5 @@
1
1
  import type { Operation } from 'oas';
2
2
  export default function prepareAuth(authKey: (number | string)[], operation: Operation): Record<string, string | number | {
3
- user: string | number;
4
3
  pass: string | number;
4
+ user: string | number;
5
5
  }>;
@@ -82,7 +82,7 @@ function isObject(thing) {
82
82
  return typeof thing === 'object' && thing !== null && !Array.isArray(thing);
83
83
  }
84
84
  function isPrimitive(obj) {
85
- return typeof obj === null || typeof obj === 'number' || typeof obj === 'string';
85
+ return obj === null || typeof obj === 'number' || typeof obj === 'string';
86
86
  }
87
87
  function merge(src, target) {
88
88
  if (Array.isArray(target)) {
@@ -343,6 +343,7 @@ function prepareParams(operation, body, metadata) {
343
343
  if (typeof metadata === 'object' && !isEmpty(metadata)) {
344
344
  if (paramName in metadata) {
345
345
  value = metadata[paramName];
346
+ metadataHeaderParam = paramName;
346
347
  }
347
348
  else if (param["in"] === 'header') {
348
349
  // Headers are sent case-insensitive so we need to make sure that we're properly
@@ -387,10 +388,7 @@ function prepareParams(operation, body, metadata) {
387
388
  // If there's any leftover metadata that hasn't been moved into form data for this request we
388
389
  // need to move it or else it'll get tossed.
389
390
  if (!isEmpty(metadata)) {
390
- if (operation.isFormUrlEncoded()) {
391
- params.formData = merge(params.formData, metadata);
392
- }
393
- else if (typeof metadata === 'object') {
391
+ if (typeof metadata === 'object') {
394
392
  // If the user supplied an `accept` or `authorization` header themselves we should allow it
395
393
  // through. Normally these headers are automatically handled by `@readme/oas-to-har` but in
396
394
  // the event that maybe the user wants to return XML for an API that normally returns JSON
@@ -400,9 +398,14 @@ function prepareParams(operation, body, metadata) {
400
398
  var headerParam = Object.keys(metadata).find(function (m) { return m.toLowerCase() === headerName; });
401
399
  if (headerParam) {
402
400
  params.header[headerName] = metadata[headerParam];
401
+ // eslint-disable-next-line no-param-reassign
402
+ delete metadata[headerParam];
403
403
  }
404
404
  });
405
405
  }
406
+ if (operation.isFormUrlEncoded()) {
407
+ params.formData = merge(params.formData, metadata);
408
+ }
406
409
  else {
407
410
  // Any other remaining unused metadata will be unused because we don't know where to place
408
411
  // it in the request.
@@ -3,9 +3,6 @@ import type Oas from 'oas';
3
3
  * With an SDK server config and an instance of OAS we should extract and prepare the server and
4
4
  * any server variables to be supplied to `@readme/oas-to-har`.
5
5
  *
6
- * @param spec
7
- * @param url
8
- * @param variables
9
6
  */
10
7
  export default function prepareServer(spec: Oas, url: string, variables?: Record<string, string | number>): false | {
11
8
  selected: number;
@@ -10,9 +10,6 @@ function stripTrailingSlash(url) {
10
10
  * With an SDK server config and an instance of OAS we should extract and prepare the server and
11
11
  * any server variables to be supplied to `@readme/oas-to-har`.
12
12
  *
13
- * @param spec
14
- * @param url
15
- * @param variables
16
13
  */
17
14
  function prepareServer(spec, url, variables) {
18
15
  if (variables === void 0) { variables = {}; }
package/dist/fetcher.js CHANGED
@@ -158,7 +158,6 @@ var Fetcher = /** @class */ (function () {
158
158
  * @example @petstore/v1.0#n6kvf10vakpemvplx
159
159
  * @example @petstore#n6kvf10vakpemvplx
160
160
  */
161
- // eslint-disable-next-line unicorn/no-unsafe-regex
162
161
  Fetcher.registryUUIDRegex = /^@(?<project>[a-zA-Z0-9-_]+)(\/?(?<version>.+))?#(?<uuid>[a-z0-9]+)$/;
163
162
  return Fetcher;
164
163
  }());