@scalar/cli 0.2.141 → 0.2.143

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 (85) hide show
  1. package/dist/commands/bundle/BundleCommand.js +38 -0
  2. package/dist/commands/format/FormatCommand.js +44 -0
  3. package/dist/commands/init/InitCommand.js +145 -0
  4. package/dist/commands/mock/MockCommand.js +124 -0
  5. package/dist/commands/serve/ServeCommand.js +89 -0
  6. package/dist/commands/share/ShareCommand.js +58 -0
  7. package/dist/commands/validate/ValidateCommand.js +47 -0
  8. package/dist/commands/void/VoidCommand.js +38 -0
  9. package/dist/index.js +11 -962
  10. package/dist/package.json.js +3 -0
  11. package/dist/src/commands/bundle/BundleCommand.d.ts +3 -0
  12. package/dist/src/commands/bundle/BundleCommand.d.ts.map +1 -0
  13. package/dist/src/commands/format/FormatCommand.d.ts +3 -0
  14. package/dist/src/commands/format/FormatCommand.d.ts.map +1 -0
  15. package/dist/src/commands/format/format.test.d.ts +2 -0
  16. package/dist/src/commands/format/format.test.d.ts.map +1 -0
  17. package/dist/src/commands/index.d.ts +9 -0
  18. package/dist/src/commands/index.d.ts.map +1 -0
  19. package/dist/src/commands/init/InitCommand.d.ts +33 -0
  20. package/dist/src/commands/init/InitCommand.d.ts.map +1 -0
  21. package/dist/src/commands/init/init.test.d.ts +2 -0
  22. package/dist/src/commands/init/init.test.d.ts.map +1 -0
  23. package/dist/src/commands/mock/MockCommand.d.ts +3 -0
  24. package/dist/src/commands/mock/MockCommand.d.ts.map +1 -0
  25. package/dist/src/commands/mock/mock.test.d.ts +2 -0
  26. package/dist/src/commands/mock/mock.test.d.ts.map +1 -0
  27. package/dist/src/commands/serve/ServeCommand.d.ts +3 -0
  28. package/dist/src/commands/serve/ServeCommand.d.ts.map +1 -0
  29. package/dist/src/commands/share/ShareCommand.d.ts +3 -0
  30. package/dist/src/commands/share/ShareCommand.d.ts.map +1 -0
  31. package/dist/src/commands/validate/ValidateCommand.d.ts +6 -0
  32. package/dist/src/commands/validate/ValidateCommand.d.ts.map +1 -0
  33. package/dist/src/commands/validate/validate.test.d.ts +2 -0
  34. package/dist/src/commands/validate/validate.test.d.ts.map +1 -0
  35. package/dist/src/commands/void/VoidCommand.d.ts +3 -0
  36. package/dist/src/commands/void/VoidCommand.d.ts.map +1 -0
  37. package/dist/src/commands/void/void.test.d.ts +2 -0
  38. package/dist/src/commands/void/void.test.d.ts.map +1 -0
  39. package/dist/src/index.d.ts +3 -0
  40. package/dist/src/index.d.ts.map +1 -0
  41. package/dist/src/options/version/version.test.d.ts +2 -0
  42. package/dist/src/options/version/version.test.d.ts.map +1 -0
  43. package/dist/src/utils/getFileOrUrl.d.ts +5 -0
  44. package/dist/src/utils/getFileOrUrl.d.ts.map +1 -0
  45. package/dist/src/utils/getHtmlDocument.d.ts +3 -0
  46. package/dist/src/utils/getHtmlDocument.d.ts.map +1 -0
  47. package/dist/src/utils/getMethodColor.d.ts +3 -0
  48. package/dist/src/utils/getMethodColor.d.ts.map +1 -0
  49. package/dist/src/utils/getOperationByMethodAndPath.d.ts +3 -0
  50. package/dist/src/utils/getOperationByMethodAndPath.d.ts.map +1 -0
  51. package/dist/src/utils/getOperationByMethodAndPath.test.d.ts +2 -0
  52. package/dist/src/utils/getOperationByMethodAndPath.test.d.ts.map +1 -0
  53. package/dist/src/utils/index.d.ts +9 -0
  54. package/dist/src/utils/index.d.ts.map +1 -0
  55. package/dist/src/utils/isUrl.d.ts +5 -0
  56. package/dist/src/utils/isUrl.d.ts.map +1 -0
  57. package/dist/src/utils/isYamlFileName.d.ts +5 -0
  58. package/dist/src/utils/isYamlFileName.d.ts.map +1 -0
  59. package/dist/src/utils/loadOpenApiFile.d.ts +11 -0
  60. package/dist/src/utils/loadOpenApiFile.d.ts.map +1 -0
  61. package/dist/src/utils/printSpecificationBanner.d.ts +6 -0
  62. package/dist/src/utils/printSpecificationBanner.d.ts.map +1 -0
  63. package/dist/src/utils/readFile.d.ts +2 -0
  64. package/dist/src/utils/readFile.d.ts.map +1 -0
  65. package/dist/src/utils/useGivenFileOrConfiguration.d.ts +3 -0
  66. package/dist/src/utils/useGivenFileOrConfiguration.d.ts.map +1 -0
  67. package/dist/src/utils/watchFile.d.ts +7 -0
  68. package/dist/src/utils/watchFile.d.ts.map +1 -0
  69. package/dist/tests/invoke-cli.d.ts +12 -0
  70. package/dist/tests/invoke-cli.d.ts.map +1 -0
  71. package/dist/tests/matcher.d.ts +10 -0
  72. package/dist/tests/matcher.d.ts.map +1 -0
  73. package/dist/utils/getFileOrUrl.js +23 -0
  74. package/dist/utils/getHtmlDocument.js +37 -0
  75. package/dist/utils/getMethodColor.js +12 -0
  76. package/dist/utils/isUrl.js +9 -0
  77. package/dist/utils/isYamlFileName.js +13 -0
  78. package/dist/utils/loadOpenApiFile.js +41 -0
  79. package/dist/utils/printSpecificationBanner.js +19 -0
  80. package/dist/utils/readFile.js +16 -0
  81. package/dist/utils/useGivenFileOrConfiguration.js +31 -0
  82. package/dist/utils/watchFile.js +33 -0
  83. package/package.json +18 -9
  84. package/dist/package.json +0 -64
  85. package/dist/tsconfig.tsbuildinfo +0 -1
package/dist/index.js CHANGED
@@ -1,967 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from 'commander';
3
- import kleur from 'kleur';
4
- import fs from 'node:fs';
5
- import { validate, load, openapi } from '@scalar/openapi-parser';
6
- import watcher from '@parcel/watcher';
7
- import path from 'node:path';
8
- import { isCancel, text, confirm, cancel } from '@clack/prompts';
9
- import GithubSlugger from 'github-slugger';
10
- import { serve } from '@hono/node-server';
11
- import { createMockServer } from '@scalar/mock-server';
12
- import { Hono } from 'hono';
13
- import { stream } from 'hono/streaming';
14
- import prettyjson from 'prettyjson';
15
- import { createVoidServer } from '@scalar/void-server';
16
-
17
- var version = "0.2.141";
18
-
19
- /******************************************************************************
20
- Copyright (c) Microsoft Corporation.
21
-
22
- Permission to use, copy, modify, and/or distribute this software for any
23
- purpose with or without fee is hereby granted.
24
-
25
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
26
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
27
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
28
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
29
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
30
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
31
- PERFORMANCE OF THIS SOFTWARE.
32
- ***************************************************************************** */
33
- /* global Reflect, Promise, SuppressedError, Symbol */
34
-
35
-
36
- function __awaiter(thisArg, _arguments, P, generator) {
37
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
38
- return new (P || (P = Promise))(function (resolve, reject) {
39
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
40
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
41
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
42
- step((generator = generator.apply(thisArg, _arguments || [])).next());
43
- });
44
- }
45
-
46
- function __generator(thisArg, body) {
47
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
48
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
49
- function verb(n) { return function (v) { return step([n, v]); }; }
50
- function step(op) {
51
- if (f) throw new TypeError("Generator is already executing.");
52
- while (g && (g = 0, op[0] && (_ = 0)), _) try {
53
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
54
- if (y = 0, t) op = [op[0] & 2, t.value];
55
- switch (op[0]) {
56
- case 0: case 1: t = op; break;
57
- case 4: _.label++; return { value: op[1], done: false };
58
- case 5: _.label++; y = op[1]; op = [0]; continue;
59
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
60
- default:
61
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
62
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
63
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
64
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
65
- if (t[2]) _.ops.pop();
66
- _.trys.pop(); continue;
67
- }
68
- op = body.call(thisArg, _);
69
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
70
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
71
- }
72
- }
73
-
74
- typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
75
- var e = new Error(message);
76
- return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
77
- };
78
-
79
- /**
80
- * Check if the input is a URL.
81
- */
82
- function isUrl(text) {
83
- return (typeof text === 'string' &&
84
- (text.startsWith('http://') || text.startsWith('https://')));
85
- }
86
-
87
- /**
88
- * Pass a file path or URL and get the content of the file.
89
- */
90
- function getFileOrUrl(input) {
91
- return __awaiter(this, void 0, void 0, function () {
92
- var response;
93
- return __generator(this, function (_a) {
94
- switch (_a.label) {
95
- case 0:
96
- if (!isUrl(input)) return [3 /*break*/, 3];
97
- return [4 /*yield*/, fetch(input)];
98
- case 1:
99
- response = _a.sent();
100
- if (!response.ok) {
101
- console.error(kleur.bold().red('[ERROR]'), kleur.bold().red('Failed to fetch OpenAPI specification from URL.'));
102
- return [2 /*return*/, ''];
103
- }
104
- return [4 /*yield*/, response.text()];
105
- case 2: return [2 /*return*/, _a.sent()];
106
- case 3:
107
- if (!fs.existsSync(input)) {
108
- throw new Error('File not found');
109
- }
110
- return [2 /*return*/, fs.readFileSync(input, 'utf-8')];
111
- }
112
- });
113
- });
114
- }
115
-
116
- function getHtmlDocument(specification, watch) {
117
- if (watch === void 0) { watch = false; }
118
- return "<!doctype html>\n <html>\n <head>\n <title>Scalar API Reference</title>\n <meta charset=\"utf-8\" />\n <meta\n name=\"viewport\"\n content=\"width=device-width, initial-scale=1\" />\n <style>\n body {\n margin: 0;\n }\n </style>\n ".concat(watch
119
- ? "\n <script>\n const evtSource = new EventSource('__watcher');\n evtSource.onmessage = (event) => {\n console.log(`message: ${event.data}`);\n window.location.reload();\n };\n </script>\n "
120
- : '', "\n </head>\n <body>\n <script\n id=\"api-reference\"\n type=\"application/json\"\n data-proxy-url=\"https://proxy.scalar.com\">").concat(JSON.stringify(specification), "</script>\n <script src=\"https://cdn.jsdelivr.net/npm/@scalar/api-reference\"></script>\n </body>\n </html>");
121
- }
122
-
123
- function getMethodColor(method) {
124
- var _a;
125
- var colors = {
126
- get: 'green',
127
- post: 'cyan',
128
- put: 'yellow',
129
- delete: 'red',
130
- patch: 'magenta',
131
- };
132
- return (_a = colors[method.toLowerCase()]) !== null && _a !== void 0 ? _a : 'grey';
133
- }
134
-
135
- function loadOpenApiFile(input) {
136
- return __awaiter(this, void 0, void 0, function () {
137
- var specification, filesystem, result, error_1;
138
- var _a;
139
- return __generator(this, function (_b) {
140
- switch (_b.label) {
141
- case 0: return [4 /*yield*/, getFileOrUrl(input)];
142
- case 1:
143
- specification = _b.sent();
144
- _b.label = 2;
145
- case 2:
146
- _b.trys.push([2, 5, , 6]);
147
- return [4 /*yield*/, load(specification)];
148
- case 3:
149
- filesystem = (_b.sent()).filesystem;
150
- return [4 /*yield*/, validate(filesystem)
151
- // Invalid specification
152
- ];
153
- case 4:
154
- result = _b.sent();
155
- // Invalid specification
156
- if (!result.valid) {
157
- console.warn(kleur.bold().yellow('[WARN]'), kleur.bold().yellow('File doesn’t match the OpenAPI specification.'));
158
- console.log();
159
- // Output errors
160
- (_a = result.errors) === null || _a === void 0 ? void 0 : _a.forEach(function (error) {
161
- console.warn(kleur.bold().yellow('[WARN]'), kleur.yellow(error.error), kleur.yellow("(".concat(error.path, ")")));
162
- });
163
- console.log();
164
- return [2 /*return*/, result];
165
- }
166
- return [2 /*return*/, result];
167
- case 5:
168
- error_1 = _b.sent();
169
- console.warn(kleur.bold().red('[ERROR]'), kleur.red(error_1));
170
- console.log();
171
- return [2 /*return*/, {
172
- valid: false,
173
- version: undefined,
174
- specification: undefined,
175
- schema: undefined,
176
- errors: [
177
- {
178
- error: error_1.message,
179
- path: '',
180
- },
181
- ],
182
- }];
183
- case 6: return [2 /*return*/];
184
- }
185
- });
186
- });
187
- }
188
-
189
- function readFile(file) {
190
- try {
191
- if (fs.existsSync(file) === false) {
192
- return undefined;
193
- }
194
- return fs.readFileSync(file, 'utf8');
195
- }
196
- catch (err) {
197
- console.error(err);
198
- return undefined;
199
- }
200
- }
201
-
202
- var CONFIG_FILE = 'scalar.config.json';
203
- function useGivenFileOrConfiguration(file) {
204
- var _a;
205
- // If a specific file is given, use it.
206
- if (file) {
207
- return file;
208
- }
209
- // Try to load the configuration
210
- try {
211
- // check if file exists
212
- var content = readFile(CONFIG_FILE);
213
- var configuration = JSON.parse(content);
214
- if ((_a = configuration === null || configuration === void 0 ? void 0 : configuration.reference) === null || _a === void 0 ? void 0 : _a.file) {
215
- return configuration.reference.file;
216
- }
217
- }
218
- catch (_b) {
219
- // Do nothing
220
- }
221
- console.error(kleur.red('No file provided.'));
222
- console.log();
223
- console.log(kleur.white('Try `scalar init` or add the file as an argument. Read `scalar --help` for more information.'));
224
- console.log();
225
- return process.exit(1);
226
- }
227
-
228
- /**
229
- * Watch a foobar for changes and call a callback when it does.
230
- */
231
- function watchFile(file, callback, options) {
232
- return __awaiter(this, void 0, void 0, function () {
233
- var absoluteFilePath, directory;
234
- return __generator(this, function (_a) {
235
- switch (_a.label) {
236
- case 0:
237
- // Poll URLs
238
- if (isUrl(file)) {
239
- setInterval(callback, 5000);
240
- return [2 /*return*/];
241
- }
242
- absoluteFilePath = path.join(process.cwd(), file);
243
- // Check if file exists
244
- if (!fs.existsSync(absoluteFilePath)) {
245
- throw new Error("File ".concat(absoluteFilePath, " does not exist"));
246
- }
247
- // Watch the file for changes
248
- console.log("[INFO] Watch ".concat(file));
249
- directory = path.dirname(absoluteFilePath);
250
- // Start the watcher
251
- return [4 /*yield*/, watcher.subscribe(directory, function (err, events) {
252
- // Match the file path
253
- if (events.some(function (event) { return event.path === absoluteFilePath; })) {
254
- callback();
255
- }
256
- })
257
- // Call the callback immediately
258
- ];
259
- case 1:
260
- // Start the watcher
261
- _a.sent();
262
- return [2 /*return*/];
263
- }
264
- });
265
- });
266
- }
267
-
268
- function BundleCommand() {
269
- var _this = this;
270
- var cmd = new Command('bundle');
271
- cmd.description('Resolve all references in an OpenAPI file');
272
- cmd.argument('[file]', 'file to bundle');
273
- cmd.option('-o, --output <file>', 'output file');
274
- cmd.action(function (fileArgument) { return __awaiter(_this, void 0, void 0, function () {
275
- var output, startTime, file, newContent, cache, json, endTime;
276
- return __generator(this, function (_a) {
277
- switch (_a.label) {
278
- case 0:
279
- output = cmd.opts().output;
280
- startTime = performance.now();
281
- file = useGivenFileOrConfiguration(fileArgument);
282
- return [4 /*yield*/, loadOpenApiFile(file)
283
- // Replace file content with newContent
284
- ];
285
- case 1:
286
- newContent = (_a.sent()).specification;
287
- cache = [];
288
- json = JSON.stringify(newContent, function (key, value) {
289
- if (typeof value === 'object' && value !== null) {
290
- if (cache.indexOf(value) !== -1) {
291
- // Circular reference found, discard key
292
- return;
293
- }
294
- // Store value in our collection
295
- cache.push(value);
296
- }
297
- return value;
298
- }, 2);
299
- fs.writeFileSync(output !== null && output !== void 0 ? output : file, json, 'utf8');
300
- endTime = performance.now();
301
- console.log(kleur.green('OpenAPI Schema bundled'), kleur.grey("in ".concat(kleur.white("".concat(kleur.bold("".concat(Math.round(endTime - startTime))), " ms")))));
302
- console.log();
303
- return [2 /*return*/];
304
- }
305
- });
306
- }); });
307
- return cmd;
308
- }
309
-
310
- /**
311
- * True for all files ending with .yml or .yaml (case-insensitive).
312
- */
313
- function isYamlFileName(fileName) {
314
- if (isUrl(fileName)) {
315
- return false;
316
- }
317
- return /\.ya?ml$/i.test(fileName);
318
- }
319
-
320
- function FormatCommand() {
321
- var _this = this;
322
- var cmd = new Command('format');
323
- cmd.description('Format an OpenAPI file');
324
- cmd.argument('[file|url]', 'File or URL to format');
325
- cmd.option('-o, --output <file>', 'Output file');
326
- cmd.action(function (inputArgument_1, _a) { return __awaiter(_this, [inputArgument_1, _a], void 0, function (inputArgument, _b) {
327
- var startTime, input, specification, newContent, _c, endTime;
328
- var output = _b.output;
329
- return __generator(this, function (_d) {
330
- switch (_d.label) {
331
- case 0:
332
- startTime = performance.now();
333
- input = useGivenFileOrConfiguration(inputArgument);
334
- return [4 /*yield*/, getFileOrUrl(input)];
335
- case 1:
336
- specification = _d.sent();
337
- if (!specification) {
338
- console.error(kleur.bold().red('[ERROR]'), kleur.red('Couldn’t read file.'));
339
- process.exit(1);
340
- }
341
- if (!isYamlFileName(output || input)) return [3 /*break*/, 3];
342
- return [4 /*yield*/, openapi().load(specification).toYaml()];
343
- case 2:
344
- _c = _d.sent();
345
- return [3 /*break*/, 5];
346
- case 3: return [4 /*yield*/, openapi().load(specification).toJson()
347
- // Replace file content with newContent
348
- ];
349
- case 4:
350
- _c = _d.sent();
351
- _d.label = 5;
352
- case 5:
353
- newContent = _c;
354
- // Replace file content with newContent
355
- if (output) {
356
- fs.writeFileSync(output, newContent, 'utf8');
357
- }
358
- else if (!isUrl(input)) {
359
- fs.writeFileSync(input, newContent, 'utf8');
360
- }
361
- else {
362
- console.error(kleur.bold().red('[ERROR]'), kleur.red('Output file is required for URLs. Try passing --output file flag.'));
363
- process.exit(1);
364
- }
365
- endTime = performance.now();
366
- console.log(kleur.green('File formatted'), kleur.grey("in ".concat(kleur.white("".concat(kleur.bold("".concat(Math.round(endTime - startTime))), " ms")))));
367
- console.log();
368
- return [2 /*return*/];
369
- }
370
- });
371
- }); });
372
- return cmd;
373
- }
374
-
375
- function InitCommand() {
376
- var _this = this;
377
- var cmd = new Command('init');
378
- cmd.description('Create a new `scalar.config.json` file to configure where your OpenAPI file is placed.');
379
- cmd.option('-f, --file [file]', 'your OpenAPI file');
380
- cmd.option('-s, --subdomain [url]', 'subdomain to publish on');
381
- cmd.option('--force', 'override existing configuration');
382
- cmd.action(function (_a) { return __awaiter(_this, [_a], void 0, function (_b) {
383
- // Function to validate file extension
384
- function isValidFile(filePath) {
385
- var validExtensions = ['.json', '.yaml', '.yml'];
386
- var extension = path.extname(filePath).toLowerCase();
387
- return validExtensions.includes(extension);
388
- }
389
- var configFile, validInput, input, nextSteps, handleCancel, shouldOverwriteExisting, _c, configuration, response, slugger, slug, validExtensions, extension, response, content;
390
- var file = _b.file, subdomain = _b.subdomain, force = _b.force;
391
- return __generator(this, function (_d) {
392
- switch (_d.label) {
393
- case 0:
394
- configFile = path.resolve(CONFIG_FILE);
395
- input = file;
396
- nextSteps = function () {
397
- console.log('What to do next:');
398
- console.log(" ".concat(kleur.cyan('scalar format'), " ").concat(kleur.gray('[options] [file|url]'), " to format your OpenAPI file"));
399
- console.log(" ".concat(kleur.cyan('scalar validate'), " ").concat(kleur.gray('[file|url]'), " to validate your OpenAPI file"));
400
- console.log(" ".concat(kleur.cyan('scalar bundle'), " ").concat(kleur.gray('[options] [file]'), " to bundle your OpenAPI file"));
401
- console.log(" ".concat(kleur.cyan('scalar serve'), " ").concat(kleur.gray('[options] [file|url]'), " to serve your OpenAPI file"));
402
- console.log();
403
- console.log(kleur.white("Run ".concat(kleur.magenta('scalar --help'), " to see all available commands.")));
404
- };
405
- handleCancel = function () {
406
- cancel('Operation cancelled.');
407
- nextSteps();
408
- process.exit(0);
409
- };
410
- if (!fs.existsSync(configFile)) return [3 /*break*/, 4];
411
- console.log("".concat(kleur.green('⚠'), " Found existing configuration: ").concat(kleur.reset().green("".concat(CONFIG_FILE))));
412
- if (force) {
413
- console.log("".concat(kleur.green('✔'), " Overwriting existing file\u2026"));
414
- }
415
- if (!(force !== null && force !== void 0)) return [3 /*break*/, 1];
416
- _c = force;
417
- return [3 /*break*/, 3];
418
- case 1: return [4 /*yield*/, confirm({
419
- message: 'Do you want to override the file?',
420
- initialValue: false,
421
- })];
422
- case 2:
423
- _c = (_d.sent());
424
- _d.label = 3;
425
- case 3:
426
- shouldOverwriteExisting = _c;
427
- if (isCancel(shouldOverwriteExisting)) {
428
- handleCancel();
429
- }
430
- if (!shouldOverwriteExisting) {
431
- handleCancel();
432
- }
433
- _d.label = 4;
434
- case 4:
435
- configuration = {
436
- subdomain: '',
437
- references: [],
438
- guides: [],
439
- };
440
- // Subdomain
441
- validInput = !!subdomain;
442
- _d.label = 5;
443
- case 5:
444
- if (!!validInput) return [3 /*break*/, 7];
445
- return [4 /*yield*/, text({
446
- message: "What\u2019s the name of your project? We\u2019ll use that to create a custom subdomain for you.",
447
- validate: function (value) {
448
- if (value.trim().length === 0) {
449
- return "You didn\u2019t provide a project name. Please provide a name!";
450
- }
451
- return null;
452
- },
453
- })
454
- // TODO: Check if the subdomain is available
455
- ];
456
- case 6:
457
- response = _d.sent();
458
- // TODO: Check if the subdomain is available
459
- if (isCancel(response)) {
460
- handleCancel();
461
- }
462
- else {
463
- validInput = true;
464
- }
465
- slugger = new GithubSlugger();
466
- slug = slugger.slug(response.toString());
467
- // eslint-disable-next-line no-param-reassign
468
- subdomain = "".concat(slug, ".apidocumentation.com");
469
- console.log("".concat(kleur.green('✔'), " Subdomain: ").concat(kleur.green(subdomain)));
470
- return [3 /*break*/, 5];
471
- case 7:
472
- configuration.subdomain = subdomain.trim();
473
- // Reference
474
- // Check if the file option is provided and valid
475
- if (input) {
476
- validExtensions = ['.json', '.yaml', '.yml'];
477
- extension = path.extname(input).toLowerCase();
478
- if (!validExtensions.includes(extension)) {
479
- console.log(kleur.red('✖'), "Please enter a valid file path ".concat(validExtensions.join(', '), "."));
480
- }
481
- }
482
- // Ask for the file path
483
- validInput = input && isValidFile(input);
484
- _d.label = 8;
485
- case 8:
486
- if (!!validInput) return [3 /*break*/, 10];
487
- return [4 /*yield*/, text({
488
- message: "Where is your OpenAPI file? ".concat(kleur.reset().grey('(Add a path to the file)')),
489
- validate: function (value) {
490
- if (value.length === 0)
491
- return "Value is required!";
492
- return null;
493
- },
494
- })];
495
- case 9:
496
- response = _d.sent();
497
- input = response;
498
- if (isCancel(response)) {
499
- handleCancel();
500
- }
501
- if (isValidFile(input)) {
502
- validInput = true;
503
- }
504
- else {
505
- console.log(kleur.red('✖'), "Invalid file extension. Expected: ".concat(['.json', '.yaml', '.yml'].join(', '), "."));
506
- }
507
- return [3 /*break*/, 8];
508
- case 10:
509
- configuration.references.push({
510
- name: 'API Reference',
511
- path: input,
512
- });
513
- content = JSON.stringify(configuration, null, 2);
514
- // Create `scalar.config.json` file
515
- fs.writeFileSync(configFile, content);
516
- console.log("".concat(kleur.green('✔'), " Configuration stored."));
517
- console.log();
518
- console.log("".concat(kleur.bold().green("".concat(CONFIG_FILE))));
519
- console.log();
520
- console.log("".concat(kleur.grey(content
521
- .split('\n')
522
- .map(function (line) { return " ".concat(line); })
523
- .join('\n'))));
524
- console.log();
525
- nextSteps();
526
- console.log();
527
- return [2 /*return*/];
528
- }
529
- });
530
- }); });
531
- return cmd;
532
- }
533
-
534
- function printSpecificationBanner(result) {
535
- var version = result.version, schema = result.schema;
536
- // Version
537
- console.log(kleur.bold().white('[INFO]'), kleur.bold().white(schema.info.title), kleur.grey("(OpenAPI v".concat(version, ")")));
538
- // Count number of paths
539
- var pathsCount = Object.keys(schema.paths).length;
540
- // Count number of operations
541
- var operationsCount = Object.values(schema.paths).reduce(function (acc, path) { return acc + Object.keys(path).length; }, 0);
542
- // Statistics
543
- console.log(kleur.bold().white('[INFO]'), kleur.grey("".concat(pathsCount, " paths, ").concat(operationsCount, " operations")));
544
- console.log();
545
- }
546
-
547
- function MockCommand() {
548
- var _this = this;
549
- var cmd = new Command('mock');
550
- cmd.description('Mock an API from an OpenAPI file');
551
- cmd.argument('[file|url]', 'OpenAPI file or URL to mock the server for');
552
- cmd.option('-w, --watch', 'watch the file for changes');
553
- cmd.option('-o, --once', 'run the server only once and exit after that');
554
- cmd.option('-p, --port <port>', 'set the HTTP port for the mock server');
555
- cmd.action(function (fileArgument_1, _a) { return __awaiter(_this, [fileArgument_1, _a], void 0, function (fileArgument, _b) {
556
- var server, input, result, specification;
557
- var _this = this;
558
- var watch = _b.watch, once = _b.once, port = _b.port;
559
- return __generator(this, function (_c) {
560
- switch (_c.label) {
561
- case 0:
562
- server = null;
563
- input = useGivenFileOrConfiguration(fileArgument);
564
- return [4 /*yield*/, loadOpenApiFile(input)];
565
- case 1:
566
- result = _c.sent();
567
- if (!result.valid) {
568
- console.warn(kleur.bold().red('[ERROR]'), kleur.red('Invalid OpenAPI specification'));
569
- return [2 /*return*/];
570
- }
571
- printSpecificationBanner({
572
- version: result.version,
573
- schema: result.schema,
574
- });
575
- specification = result.specification;
576
- if (!watch) return [3 /*break*/, 3];
577
- return [4 /*yield*/, watchFile(input, function () { return __awaiter(_this, void 0, void 0, function () {
578
- var newResult, specificationHasChanged;
579
- return __generator(this, function (_a) {
580
- switch (_a.label) {
581
- case 0: return [4 /*yield*/, loadOpenApiFile(input)];
582
- case 1:
583
- newResult = _a.sent();
584
- specificationHasChanged = (newResult === null || newResult === void 0 ? void 0 : newResult.specification) &&
585
- JSON.stringify(specification) !==
586
- JSON.stringify(newResult.specification);
587
- if (!specificationHasChanged) return [3 /*break*/, 3];
588
- console.log(kleur.bold().white('[INFO]'), kleur.grey('OpenAPI file modified'));
589
- printSpecificationBanner({
590
- version: newResult.version,
591
- schema: newResult.schema,
592
- });
593
- specification = newResult.specification;
594
- // Update mock server
595
- server.close();
596
- return [4 /*yield*/, bootServer$1({
597
- specification: specification,
598
- port: port,
599
- })];
600
- case 2:
601
- server = _a.sent();
602
- _a.label = 3;
603
- case 3: return [2 /*return*/];
604
- }
605
- });
606
- }); })];
607
- case 2:
608
- _c.sent();
609
- _c.label = 3;
610
- case 3:
611
- // Show all paths from the specification
612
- printAvailablePaths(specification);
613
- return [4 /*yield*/, bootServer$1({
614
- specification: specification,
615
- port: port,
616
- })
617
- // Exit after the first run
618
- ];
619
- case 4:
620
- // Listen for requests
621
- server = _c.sent();
622
- // Exit after the first run
623
- if (once) {
624
- setTimeout(function () {
625
- server.close();
626
- }, 2000);
627
- }
628
- return [2 /*return*/];
629
- }
630
- });
631
- }); });
632
- return cmd;
633
- }
634
- function bootServer$1(_a) {
635
- return __awaiter(this, arguments, void 0, function (_b) {
636
- var app;
637
- var specification = _b.specification, port = _b.port;
638
- return __generator(this, function (_c) {
639
- switch (_c.label) {
640
- case 0: return [4 /*yield*/, createMockServer({
641
- specification: specification,
642
- onRequest: onRequest,
643
- })];
644
- case 1:
645
- app = _c.sent();
646
- return [2 /*return*/, serve({
647
- fetch: app.fetch,
648
- port: port !== null && port !== void 0 ? port : 3000,
649
- }, function (info) {
650
- console.log("".concat(kleur.bold().green('➜ Mock Server'), " ").concat(kleur.white('listening on'), " ").concat(kleur.cyan("http://localhost:".concat(info.port))));
651
- console.log();
652
- })];
653
- }
654
- });
655
- });
656
- }
657
- function printAvailablePaths(specification) {
658
- var _a, _b;
659
- console.log(kleur.bold().white('Available Paths'));
660
- console.log();
661
- if ((specification === null || specification === void 0 ? void 0 : specification.paths) === undefined ||
662
- Object.keys(specification === null || specification === void 0 ? void 0 : specification.paths).length === 0) {
663
- console.log(kleur.bold().yellow('[WARN]'), kleur.grey('Couldn’t find any paths in the OpenAPI file.'));
664
- }
665
- // loop through all paths
666
- for (var path in (_a = specification === null || specification === void 0 ? void 0 : specification.paths) !== null && _a !== void 0 ? _a : []) {
667
- // loop through all methods
668
- for (var method in (_b = specification.paths) === null || _b === void 0 ? void 0 : _b[path]) {
669
- console.log("".concat(kleur
670
- .bold()[getMethodColor(method)](method.toUpperCase().padEnd(6)), " ").concat(kleur.grey("".concat(path))));
671
- }
672
- }
673
- console.log();
674
- }
675
- function onRequest(_a) {
676
- var context = _a.context, operation = _a.operation;
677
- var method = context.req.method;
678
- console.log("".concat(kleur
679
- .bold()[getMethodColor(method)](method.toUpperCase().padEnd(6)), " ").concat(kleur.grey("".concat(context.req.path))), "".concat(kleur.grey('→'), " ").concat((operation === null || operation === void 0 ? void 0 : operation.operationId)
680
- ? kleur.white(operation.operationId)
681
- : kleur.red('[ERROR] 404 Not Found')));
682
- }
683
-
684
- function ServeCommand() {
685
- var _this = this;
686
- var cmd = new Command('serve');
687
- // Old name for the command
688
- cmd.alias('reference');
689
- cmd.description('Serve an API Reference from an OpenAPI file');
690
- cmd.argument('[file|url]', 'OpenAPI file or URL to show the reference for');
691
- cmd.option('-w, --watch', 'watch the file for changes');
692
- cmd.option('-o, --once', 'run the server only once and exit after that');
693
- cmd.option('-p, --port <port>', 'set the HTTP port for the API reference server');
694
- cmd.action(function (inputArgument_1, _a) { return __awaiter(_this, [inputArgument_1, _a], void 0, function (inputArgument, _b) {
695
- var input, result, specification, app, server;
696
- var _this = this;
697
- var watch = _b.watch, once = _b.once, port = _b.port;
698
- return __generator(this, function (_c) {
699
- switch (_c.label) {
700
- case 0:
701
- input = useGivenFileOrConfiguration(inputArgument);
702
- return [4 /*yield*/, loadOpenApiFile(input)];
703
- case 1:
704
- result = _c.sent();
705
- if (!result.valid) {
706
- return [2 /*return*/];
707
- }
708
- specification = result.specification;
709
- printSpecificationBanner({
710
- version: result.version,
711
- schema: result.schema,
712
- });
713
- if ((specification === null || specification === void 0 ? void 0 : specification.paths) === undefined ||
714
- Object.keys(specification === null || specification === void 0 ? void 0 : specification.paths).length === 0) {
715
- console.log(kleur.bold().yellow('[WARN]'), kleur.grey('Couldn’t find any paths in the OpenAPI file.'));
716
- }
717
- app = new Hono();
718
- app.get('/', function (c) {
719
- return c.html(getHtmlDocument(specification, watch));
720
- });
721
- app.use('/__watcher', function (c, next) { return __awaiter(_this, void 0, void 0, function () {
722
- return __generator(this, function (_a) {
723
- switch (_a.label) {
724
- case 0:
725
- c.header('Content-Type', 'text/event-stream');
726
- c.header('Cache-Control', 'no-cache');
727
- c.header('Connection', 'keep-alive');
728
- return [4 /*yield*/, next()];
729
- case 1:
730
- _a.sent();
731
- return [2 /*return*/];
732
- }
733
- });
734
- }); });
735
- app.get('/__watcher', function (c) {
736
- return stream(c, function (s) { return __awaiter(_this, void 0, void 0, function () {
737
- var _this = this;
738
- return __generator(this, function (_a) {
739
- switch (_a.label) {
740
- case 0:
741
- // watch file for changes
742
- if (watch) {
743
- watchFile(input, function () { return __awaiter(_this, void 0, void 0, function () {
744
- var newResult, specificationHasChanged;
745
- return __generator(this, function (_a) {
746
- switch (_a.label) {
747
- case 0: return [4 /*yield*/, loadOpenApiFile(input)];
748
- case 1:
749
- newResult = _a.sent();
750
- specificationHasChanged = (newResult === null || newResult === void 0 ? void 0 : newResult.specification) &&
751
- JSON.stringify(specification) !==
752
- JSON.stringify(newResult.specification);
753
- if (specificationHasChanged) {
754
- console.log(kleur.bold().white('[INFO]'), kleur.grey('OpenAPI file modified'));
755
- printSpecificationBanner({
756
- version: newResult.version,
757
- schema: newResult.schema,
758
- });
759
- specification = newResult.specification;
760
- s.write('data: file modified\n\n');
761
- }
762
- return [2 /*return*/];
763
- }
764
- });
765
- }); });
766
- }
767
- _a.label = 1;
768
- case 1:
769
- return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, 100); })];
770
- case 2:
771
- _a.sent();
772
- return [3 /*break*/, 1];
773
- case 3: return [2 /*return*/];
774
- }
775
- });
776
- }); });
777
- });
778
- server = serve({
779
- fetch: app.fetch,
780
- port: port !== null && port !== void 0 ? port : 3000,
781
- }, function (info) {
782
- console.log("".concat(kleur.bold().green('➜ API Reference Server'), " ").concat(kleur.white('listening on'), " ").concat(kleur.cyan("http://localhost:".concat(info.port))));
783
- console.log();
784
- });
785
- // Exit after the first run
786
- if (once) {
787
- setTimeout(function () {
788
- server.close();
789
- }, 2000);
790
- }
791
- return [2 /*return*/];
792
- }
793
- });
794
- }); });
795
- return cmd;
796
- }
797
-
798
- function ShareCommand() {
799
- var _this = this;
800
- var cmd = new Command('share');
801
- cmd.description('Share an OpenAPI file');
802
- cmd.argument('[file]', 'file to share');
803
- cmd.option('-t, --token <token>', 'pass a token to update an existing sandbox');
804
- cmd.action(function (fileArgument_1, _a) { return __awaiter(_this, [fileArgument_1, _a], void 0, function (fileArgument, _b) {
805
- var file, url, _c, _d, _e, _f;
806
- var _g, _h;
807
- var token = _b.token;
808
- return __generator(this, function (_j) {
809
- switch (_j.label) {
810
- case 0:
811
- file = useGivenFileOrConfiguration(fileArgument);
812
- url = 'https://sandbox.scalar.com/api/share' + (token ? "?token=".concat(token) : '');
813
- _c = fetch;
814
- _d = [url];
815
- _g = {
816
- method: 'POST',
817
- headers: {
818
- 'Content-Type': 'application/json',
819
- }
820
- };
821
- _f = (_e = JSON).stringify;
822
- _h = {};
823
- return [4 /*yield*/, getFileOrUrl(file)];
824
- case 1:
825
- _c.apply(void 0, _d.concat([(_g.body = _f.apply(_e, [(_h.content = _j.sent(),
826
- _h)]),
827
- _g)]))
828
- .then(function (response) { return response.json(); })
829
- .then(function (data) {
830
- var id = data.id, newToken = data.token;
831
- console.log(kleur.bold().green('Your OpenAPI file is public.'));
832
- console.log();
833
- console.log("".concat(kleur.green('➜'), " ").concat(kleur
834
- .bold()
835
- .white('API Reference:'.padEnd(14)), " ").concat(kleur.cyan("https://sandbox.scalar.com/p/".concat(id))));
836
- console.log("".concat(kleur.grey('➜'), " ").concat(kleur
837
- .bold()
838
- .grey('Editor:'.padEnd(14)), " ").concat(kleur.cyan("https://sandbox.scalar.com/e/".concat(id))));
839
- console.log();
840
- console.log("".concat(kleur.grey('➜'), " ").concat(kleur
841
- .bold()
842
- .grey('OpenAPI JSON:'.padEnd(14)), " ").concat(kleur.cyan("https://sandbox.scalar.com/files/".concat(id, "/openapi.json"))));
843
- console.log("".concat(kleur.grey('➜'), " ").concat(kleur
844
- .bold()
845
- .grey('OpenAPI YAML:'.padEnd(14)), " ").concat(kleur.cyan("https://sandbox.scalar.com/files/".concat(id, "/openapi.yaml"))));
846
- console.log();
847
- console.log(kleur.white('Use the token to update the existing sandbox:'));
848
- console.log();
849
- console.log("".concat(kleur.grey('$'), " ").concat(kleur.bold().white("scalar share --token=")).concat(kleur.bold().cyan("".concat(newToken)), " "));
850
- console.log();
851
- })
852
- .catch(function (error) {
853
- console.error('Failed to share the file.');
854
- console.log();
855
- console.error('Error:', error);
856
- console.log();
857
- process.exit(1);
858
- });
859
- return [2 /*return*/];
860
- }
861
- });
862
- }); });
863
- return cmd;
864
- }
865
-
866
- function ValidateCommand() {
867
- var _this = this;
868
- var cmd = new Command('validate');
869
- cmd.description('Validate an OpenAPI file');
870
- cmd.argument('[file|url]', 'File or URL to validate');
871
- cmd.action(function (inputArgument) { return __awaiter(_this, void 0, void 0, function () {
872
- var startTime, input, specification, result, endTime;
873
- var _a;
874
- return __generator(this, function (_b) {
875
- switch (_b.label) {
876
- case 0:
877
- startTime = performance.now();
878
- input = useGivenFileOrConfiguration(inputArgument);
879
- return [4 /*yield*/, getFileOrUrl(input)
880
- // Validate
881
- ];
882
- case 1:
883
- specification = _b.sent();
884
- return [4 /*yield*/, openapi().load(specification).validate().get()];
885
- case 2:
886
- result = _b.sent();
887
- if (result.valid) {
888
- console.log(kleur.green("Matches the OpenAPI specification".concat(kleur.white(" (OpenAPI ".concat(kleur.bold(result.version), ")")))));
889
- endTime = performance.now();
890
- console.log();
891
- console.log(kleur.green('File validated'), kleur.grey("in ".concat(kleur.white("".concat(kleur.bold("".concat(Math.round(endTime - startTime))), " ms")))));
892
- console.log();
893
- }
894
- else {
895
- console.log(prettyjson.render(result.errors));
896
- console.log();
897
- console.error(kleur.red('File doesn’t match the OpenAPI specification.'));
898
- console.log();
899
- console.error(kleur.red("".concat(kleur.bold("".concat((_a = result.errors) === null || _a === void 0 ? void 0 : _a.length, " error").concat(result.errors && result.errors.length > 1 ? 's' : '')), " found.")));
900
- console.log();
901
- process.exit(1);
902
- }
903
- return [2 /*return*/];
904
- }
905
- });
906
- }); });
907
- return cmd;
908
- }
909
-
910
- function VoidCommand() {
911
- var _this = this;
912
- var cmd = new Command('void');
913
- cmd.description('Boot a server to mirror HTTP requests');
914
- cmd.option('-o, --once', 'run the server only once and exit after that');
915
- cmd.option('-p, --port <port>', 'set the HTTP port for the mock server');
916
- cmd.action(function (_a) { return __awaiter(_this, [_a], void 0, function (_b) {
917
- var server;
918
- var once = _b.once, port = _b.port;
919
- return __generator(this, function (_c) {
920
- switch (_c.label) {
921
- case 0:
922
- server = null;
923
- return [4 /*yield*/, bootServer({
924
- port: port,
925
- })
926
- // Exit after the first run
927
- ];
928
- case 1:
929
- // Listen for requests
930
- server = _c.sent();
931
- // Exit after the first run
932
- if (once) {
933
- setTimeout(function () {
934
- server.close();
935
- }, 2000);
936
- }
937
- return [2 /*return*/];
938
- }
939
- });
940
- }); });
941
- return cmd;
942
- }
943
- function bootServer(_a) {
944
- return __awaiter(this, arguments, void 0, function (_b) {
945
- var app;
946
- var port = _b.port;
947
- return __generator(this, function (_c) {
948
- switch (_c.label) {
949
- case 0: return [4 /*yield*/, createVoidServer()];
950
- case 1:
951
- app = _c.sent();
952
- return [2 /*return*/, serve({
953
- fetch: app.fetch,
954
- port: port !== null && port !== void 0 ? port : 3000,
955
- }, function (info) {
956
- console.log("".concat(kleur.bold().green('➜ Void Server'), " ").concat(kleur.white('listening on'), " ").concat(kleur.cyan("http://localhost:".concat(info.port))));
957
- console.log();
958
- })];
959
- }
960
- });
961
- });
962
- }
963
-
964
- var program = new Command();
3
+ import { version } from './package.json.js';
4
+ import { InitCommand } from './commands/init/InitCommand.js';
5
+ import { FormatCommand } from './commands/format/FormatCommand.js';
6
+ import { ValidateCommand } from './commands/validate/ValidateCommand.js';
7
+ import { BundleCommand } from './commands/bundle/BundleCommand.js';
8
+ import { ServeCommand } from './commands/serve/ServeCommand.js';
9
+ import { MockCommand } from './commands/mock/MockCommand.js';
10
+ import { VoidCommand } from './commands/void/VoidCommand.js';
11
+ import { ShareCommand } from './commands/share/ShareCommand.js';
12
+
13
+ const program = new Command();
965
14
  program
966
15
  .name('@scalar/cli')
967
16
  .description('CLI to work with your OpenAPI files')