@scalar/cli 0.1.0 → 0.2.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/dist/index.js CHANGED
@@ -1,18 +1,19 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from 'commander';
3
- import fs from 'node:fs';
4
3
  import kleur from 'kleur';
4
+ import fs from 'node:fs';
5
+ import { openapi } from '@scalar/openapi-parser';
6
+ import watcher from '@parcel/watcher';
7
+ import path from 'node:path';
5
8
  import { format } from 'prettier';
6
- import { Validator } from '@seriousme/openapi-schema-validator';
7
- import toml from 'toml-js';
8
9
  import prompts from 'prompts';
9
10
  import { serve } from '@hono/node-server';
10
- import { getExampleFromSchema } from '@scalar/api-reference';
11
+ import { createMockServer } from '@scalar/mock-server';
11
12
  import { Hono } from 'hono';
12
13
  import { stream } from 'hono/streaming';
13
14
  import prettyjson from 'prettyjson';
14
15
 
15
- var version = "0.1.0";
16
+ var version = "0.2.1";
16
17
 
17
18
  /******************************************************************************
18
19
  Copyright (c) Microsoft Corporation.
@@ -93,49 +94,19 @@ function getMethodColor(method) {
93
94
  return (_a = colors[method.toLowerCase()]) !== null && _a !== void 0 ? _a : 'grey';
94
95
  }
95
96
 
96
- function getOperationByMethodAndPath(schema, method, path) {
97
- var _a, _b, _c, _d, _e, _f, _g;
98
- // Compare just the strings
99
- if ((_b = (_a = schema.paths) === null || _a === void 0 ? void 0 : _a[path]) === null || _b === void 0 ? void 0 : _b[method.toLowerCase()]) {
100
- return (_d = (_c = schema.paths) === null || _c === void 0 ? void 0 : _c[path]) === null || _d === void 0 ? void 0 : _d[method.toLowerCase()];
101
- }
102
- // Loop through all pathRegex and find the one where the regex matches the path
103
- // Create a Regex for all paths with variables
104
- var pathRegex = Object.keys((_e = schema.paths) !== null && _e !== void 0 ? _e : {})
105
- .filter(function (path) {
106
- return path.includes('{');
107
- })
108
- .map(function (operationPath) {
109
- return {
110
- path: operationPath,
111
- regex: new RegExp(operationPath.replace(/{([^}]+)}/g, function (_, name) { return "(?<".concat(name, ">[^/]+)"); })),
112
- };
113
- });
114
- // Find a Regex that matches the given path
115
- var matchedPath = pathRegex.find(function (_a) {
116
- var regex = _a.regex;
117
- return regex.test(path);
118
- });
119
- // Return the operation
120
- if (matchedPath === null || matchedPath === void 0 ? void 0 : matchedPath.path) {
121
- return (_g = (_f = schema.paths) === null || _f === void 0 ? void 0 : _f[matchedPath === null || matchedPath === void 0 ? void 0 : matchedPath.path]) === null || _g === void 0 ? void 0 : _g[method.toLowerCase()];
122
- }
123
- return null;
124
- }
125
-
126
97
  function loadOpenApiFile(file) {
127
98
  return __awaiter(this, void 0, void 0, function () {
128
- var validator, result, schema, pathsCount, operationsCount, path, method;
99
+ var specification, result, valid, version, schema, pathsCount, operationsCount, path, method;
129
100
  return __generator(this, function (_a) {
130
101
  switch (_a.label) {
131
102
  case 0:
132
- validator = new Validator();
133
- return [4 /*yield*/, validator.validate(file)];
103
+ specification = fs.readFileSync(file, 'utf8');
104
+ return [4 /*yield*/, openapi().load(specification).resolve()];
134
105
  case 1:
135
106
  result = _a.sent();
136
- if (result.valid) {
137
- schema = validator.resolveRefs();
138
- console.log(kleur.bold().white('[INFO]'), kleur.bold().white(schema.info.title), kleur.grey("(OpenAPI v".concat(validator.version, ")")));
107
+ valid = result.valid, version = result.version, schema = result.schema;
108
+ if (valid) {
109
+ console.log(kleur.bold().white('[INFO]'), kleur.bold().white(schema.info.title), kleur.grey("(OpenAPI v".concat(version, ")")));
139
110
  pathsCount = Object.keys(schema.paths).length;
140
111
  operationsCount = 0;
141
112
  for (path in schema.paths) {
@@ -150,7 +121,7 @@ function loadOpenApiFile(file) {
150
121
  console.warn(kleur.bold().yellow('[WARN]'), kleur.yellow('File doesn’t match the OpenAPI specification.'));
151
122
  console.log();
152
123
  }
153
- return [2 /*return*/, validator];
124
+ return [2 /*return*/, result];
154
125
  }
155
126
  });
156
127
  });
@@ -158,6 +129,9 @@ function loadOpenApiFile(file) {
158
129
 
159
130
  function readFile(file) {
160
131
  try {
132
+ if (fs.existsSync(file) === false) {
133
+ return undefined;
134
+ }
161
135
  return fs.readFileSync(file, 'utf8');
162
136
  }
163
137
  catch (err) {
@@ -165,6 +139,7 @@ function readFile(file) {
165
139
  }
166
140
  }
167
141
 
142
+ var CONFIG_FILE = 'scalar.config.json';
168
143
  function useGivenFileOrConfiguration(file) {
169
144
  var _a;
170
145
  // If a specific file is given, use it.
@@ -173,7 +148,9 @@ function useGivenFileOrConfiguration(file) {
173
148
  }
174
149
  // Try to load the configuration
175
150
  try {
176
- var configuration = toml.parse(readFile('scalar.toml'));
151
+ // check if file exists
152
+ var content = readFile(CONFIG_FILE);
153
+ var configuration = JSON.parse(content);
177
154
  if ((_a = configuration === null || configuration === void 0 ? void 0 : configuration.reference) === null || _a === void 0 ? void 0 : _a.file) {
178
155
  return configuration.reference.file;
179
156
  }
@@ -186,6 +163,86 @@ function useGivenFileOrConfiguration(file) {
186
163
  process.exit(1);
187
164
  }
188
165
 
166
+ /**
167
+ * Watch a foobar for changes and call a callback when it does.
168
+ */
169
+ function watchFile(file, callback, options) {
170
+ return __awaiter(this, void 0, void 0, function () {
171
+ var absoluteFilePath;
172
+ return __generator(this, function (_a) {
173
+ switch (_a.label) {
174
+ case 0:
175
+ absoluteFilePath = path.join(process.cwd(), file);
176
+ // Check if file exists
177
+ if (!fs.existsSync(absoluteFilePath)) {
178
+ throw new Error("File ".concat(absoluteFilePath, " does not exist"));
179
+ }
180
+ // Watch the file for changes
181
+ console.log("[INFO] Watch ".concat(file));
182
+ // Start the watcher
183
+ return [4 /*yield*/, watcher.subscribe(process.cwd(), function (err, events) {
184
+ // Match the file path
185
+ if (events.some(function (event) { return event.path === absoluteFilePath; })) {
186
+ callback();
187
+ }
188
+ })
189
+ // Call the callback immediately
190
+ ];
191
+ case 1:
192
+ // Start the watcher
193
+ _a.sent();
194
+ // Call the callback immediately
195
+ if (options === null || options === void 0 ? void 0 : options.immediate) {
196
+ callback();
197
+ }
198
+ return [2 /*return*/];
199
+ }
200
+ });
201
+ });
202
+ }
203
+
204
+ function BundleCommand() {
205
+ var _this = this;
206
+ var cmd = new Command('bundle');
207
+ cmd.description('Resolve all references in an OpenAPI file');
208
+ cmd.argument('[file]', 'file to bundle');
209
+ cmd.option('-o, --output <file>', 'output file');
210
+ cmd.action(function (fileArgument) { return __awaiter(_this, void 0, void 0, function () {
211
+ var output, startTime, file, newContent, cache, json, endTime;
212
+ return __generator(this, function (_a) {
213
+ switch (_a.label) {
214
+ case 0:
215
+ output = cmd.opts().output;
216
+ startTime = performance.now();
217
+ file = useGivenFileOrConfiguration(fileArgument);
218
+ return [4 /*yield*/, loadOpenApiFile(file)
219
+ // Replace file content with newContent
220
+ ];
221
+ case 1:
222
+ newContent = (_a.sent()).specification;
223
+ cache = [];
224
+ json = JSON.stringify(newContent, function (key, value) {
225
+ if (typeof value === 'object' && value !== null) {
226
+ if (cache.indexOf(value) !== -1) {
227
+ // Circular reference found, discard key
228
+ return;
229
+ }
230
+ // Store value in our collection
231
+ cache.push(value);
232
+ }
233
+ return value;
234
+ }, 2);
235
+ fs.writeFileSync(output !== null && output !== void 0 ? output : file, json, 'utf8');
236
+ endTime = performance.now();
237
+ console.log(kleur.green('OpenAPI Schema bundled'), kleur.grey("in ".concat(kleur.white("".concat(kleur.bold("".concat(Math.round(endTime - startTime))), " ms")))));
238
+ console.log();
239
+ return [2 /*return*/];
240
+ }
241
+ });
242
+ }); });
243
+ return cmd;
244
+ }
245
+
189
246
  function FormatCommand() {
190
247
  var _this = this;
191
248
  var cmd = new Command('format');
@@ -226,79 +283,81 @@ function FormatCommand() {
226
283
  function InitCommand() {
227
284
  var _this = this;
228
285
  var cmd = new Command('init');
229
- cmd.description('Create a new `scalar.toml` file');
286
+ cmd.description('Create a new `scalar.config.json` file to configure where your OpenAPI file is placed.');
230
287
  cmd.option('-f, --file [file]', 'your OpenAPI file');
231
- cmd.action(function (_a) {
232
- var file = _a.file;
233
- return __awaiter(_this, void 0, void 0, function () {
234
- var overwrite, configuration, input, _b, content;
235
- return __generator(this, function (_c) {
236
- switch (_c.label) {
237
- case 0:
238
- if (!fs.existsSync('scalar.toml')) return [3 /*break*/, 2];
239
- console.warn(kleur.yellow('A `scalar.toml` file already exists.'));
240
- console.log();
241
- return [4 /*yield*/, prompts({
242
- type: 'toggle',
243
- name: 'overwrite',
244
- message: 'Do you want to override the file?',
245
- initial: false,
246
- active: 'yes',
247
- inactive: 'no',
248
- })];
249
- case 1:
250
- overwrite = (_c.sent()).overwrite;
251
- if (overwrite === false) {
252
- console.log();
253
- process.exit(1);
254
- }
255
- _c.label = 2;
256
- case 2:
257
- configuration = {
258
- reference: { file: '' },
259
- };
260
- if (!file) return [3 /*break*/, 3];
261
- _b = {
262
- input: file,
263
- };
264
- return [3 /*break*/, 5];
265
- case 3: return [4 /*yield*/, prompts({
266
- type: 'text',
267
- name: 'input',
268
- message: 'Where is your OpenAPI file?',
269
- initial: './openapi.json',
270
- validate: function (input) {
271
- return fs.existsSync(input) ? true : 'File doesn’t exist.';
272
- },
288
+ cmd.action(function (_a) { return __awaiter(_this, [_a], void 0, function (_b) {
289
+ var configFile, overwrite, configuration, input, _c, content;
290
+ var file = _b.file;
291
+ return __generator(this, function (_d) {
292
+ switch (_d.label) {
293
+ case 0:
294
+ configFile = path.resolve(CONFIG_FILE);
295
+ if (!fs.existsSync(configFile)) return [3 /*break*/, 2];
296
+ console.warn(kleur.yellow("A ".concat(CONFIG_FILE, " file already exists.")));
297
+ console.log();
298
+ return [4 /*yield*/, prompts({
299
+ type: 'toggle',
300
+ name: 'overwrite',
301
+ message: 'Do you want to override the file?',
302
+ initial: false,
303
+ active: 'yes',
304
+ inactive: 'no',
273
305
  })];
274
- case 4:
275
- _b = _c.sent();
276
- _c.label = 5;
277
- case 5:
278
- input = (_b).input;
279
- configuration.reference.file = input;
280
- content = toml.dump(configuration);
281
- console.log();
282
- console.log(kleur.bold().white(' scalar.toml'));
283
- console.log();
284
- console.log(content
285
- .trim()
286
- .split('\n')
287
- .map(function (line) { return kleur.grey(" ".concat(line)); })
288
- .join('\n'));
289
- console.log();
290
- // Create `scalar.toml` file
291
- fs.writeFileSync('scalar.toml', content);
292
- console.log(kleur.green('Created a new project configuration.'));
293
- console.log(kleur.white("Run ".concat(kleur
294
- .grey()
295
- .bold('scalar --help'), " to see all available commands.")));
306
+ case 1:
307
+ overwrite = (_d.sent()).overwrite;
308
+ if (overwrite === false) {
296
309
  console.log();
297
- return [2 /*return*/];
298
- }
299
- });
310
+ process.exit(1);
311
+ }
312
+ _d.label = 2;
313
+ case 2:
314
+ configuration = {
315
+ references: [],
316
+ };
317
+ if (!file) return [3 /*break*/, 3];
318
+ _c = {
319
+ input: file,
320
+ };
321
+ return [3 /*break*/, 5];
322
+ case 3: return [4 /*yield*/, prompts({
323
+ type: 'text',
324
+ name: 'input',
325
+ message: 'Where is your OpenAPI file?',
326
+ initial: './openapi.json',
327
+ validate: function (input) {
328
+ return fs.existsSync(input) ? true : 'File doesn’t exist.';
329
+ },
330
+ })];
331
+ case 4:
332
+ _c = _d.sent();
333
+ _d.label = 5;
334
+ case 5:
335
+ input = (_c).input;
336
+ configuration.references.push({
337
+ name: 'API Reference',
338
+ path: input,
339
+ });
340
+ content = JSON.stringify(configuration, null, 2);
341
+ console.log();
342
+ console.log(kleur.bold().white(" ".concat(CONFIG_FILE)));
343
+ console.log();
344
+ console.log(content
345
+ .trim()
346
+ .split('\n')
347
+ .map(function (line) { return kleur.grey(" ".concat(line)); })
348
+ .join('\n'));
349
+ console.log();
350
+ // Create `scalar.config.json` file
351
+ fs.writeFileSync(configFile, content);
352
+ console.log(kleur.green('Created a new project configuration.'));
353
+ console.log(kleur.white("Run ".concat(kleur
354
+ .grey()
355
+ .bold('scalar --help'), " to see all available commands.")));
356
+ console.log();
357
+ return [2 /*return*/];
358
+ }
300
359
  });
301
- });
360
+ }); });
302
361
  return cmd;
303
362
  }
304
363
 
@@ -309,87 +368,107 @@ function MockCommand() {
309
368
  cmd.argument('[file]', 'OpenAPI file to mock the server for');
310
369
  cmd.option('-w, --watch', 'watch the file for changes');
311
370
  cmd.option('-p, --port <port>', 'set the HTTP port for the mock server');
312
- cmd.action(function (fileArgument, _a) {
313
- var watch = _a.watch, port = _a.port;
314
- return __awaiter(_this, void 0, void 0, function () {
315
- var file, schema, path, method, app;
316
- var _this = this;
317
- var _b, _c;
318
- return __generator(this, function (_d) {
319
- switch (_d.label) {
320
- case 0:
321
- file = useGivenFileOrConfiguration(fileArgument);
322
- return [4 /*yield*/, loadOpenApiFile(file)];
323
- case 1:
324
- schema = (_d.sent())
325
- .specification;
326
- // watch file for changes
327
- if (watch) {
328
- fs.watchFile(file, function () { return __awaiter(_this, void 0, void 0, function () {
329
- return __generator(this, function (_a) {
330
- switch (_a.label) {
331
- case 0:
332
- console.log(kleur.bold().white('[INFO]'), kleur.grey('Mock Server was updated.'));
333
- return [4 /*yield*/, loadOpenApiFile(file)];
334
- case 1:
335
- schema = (_a.sent()).resolveRefs();
336
- return [2 /*return*/];
337
- }
338
- });
339
- }); });
340
- }
341
- console.log(kleur.bold().white('Available Paths'));
342
- console.log();
343
- if ((schema === null || schema === void 0 ? void 0 : schema.paths) === undefined ||
344
- Object.keys(schema === null || schema === void 0 ? void 0 : schema.paths).length === 0) {
345
- console.log(kleur.bold().yellow('[WARN]'), kleur.grey('Couldn’t find any paths in the OpenAPI file.'));
346
- }
347
- // loop through all paths
348
- for (path in (_b = schema === null || schema === void 0 ? void 0 : schema.paths) !== null && _b !== void 0 ? _b : []) {
349
- // loop through all methods
350
- for (method in (_c = schema.paths) === null || _c === void 0 ? void 0 : _c[path]) {
351
- console.log("".concat(kleur
352
- .bold()[getMethodColor(method)](method.toUpperCase().padEnd(6)), " ").concat(kleur.grey("".concat(path))));
353
- }
354
- }
355
- console.log();
356
- app = new Hono();
357
- app.all('/*', function (c) {
358
- var _a = c.req, method = _a.method, path = _a.path;
359
- var operation = getOperationByMethodAndPath(schema, method, path);
360
- console.log("".concat(kleur
361
- .bold()[getMethodColor(method)](method.toUpperCase().padEnd(6)), " ").concat(kleur.grey("".concat(path))), "".concat(kleur.grey('→'), " ").concat((operation === null || operation === void 0 ? void 0 : operation.operationId)
362
- ? kleur.white(operation.operationId)
363
- : kleur.red('[ERROR] 404 Not Found')));
364
- if (!operation) {
365
- return c.text('Not found', 404);
366
- }
367
- // if (!operation) {
368
- // return c.text('Method not allowed', 405)
369
- // }
370
- var jsonResponseConfiguration = operation.responses['200'].content['application/json'];
371
- var response = jsonResponseConfiguration.example
372
- ? jsonResponseConfiguration.example
373
- : jsonResponseConfiguration.schema
374
- ? getExampleFromSchema(jsonResponseConfiguration.schema, {
375
- emptyString: '…',
376
- })
377
- : null;
378
- return c.json(response);
379
- });
380
- serve({
371
+ cmd.action(function (fileArgument_1, _a) { return __awaiter(_this, [fileArgument_1, _a], void 0, function (fileArgument, _b) {
372
+ var server, file, specification;
373
+ var _this = this;
374
+ var watch = _b.watch, port = _b.port;
375
+ return __generator(this, function (_c) {
376
+ switch (_c.label) {
377
+ case 0:
378
+ server = null;
379
+ file = useGivenFileOrConfiguration(fileArgument);
380
+ return [4 /*yield*/, loadOpenApiFile(file)
381
+ // Watch OpenAPI file for changes
382
+ ];
383
+ case 1:
384
+ specification = (_c.sent()).specification;
385
+ if (!watch) return [3 /*break*/, 3];
386
+ return [4 /*yield*/, watchFile(file, function () { return __awaiter(_this, void 0, void 0, function () {
387
+ return __generator(this, function (_a) {
388
+ switch (_a.label) {
389
+ case 0:
390
+ console.log(kleur.bold().white('[INFO]'), kleur.grey('Mock Server was updated.'));
391
+ return [4 /*yield*/, loadOpenApiFile(file)];
392
+ case 1:
393
+ specification = (_a.sent()).specification;
394
+ server.close();
395
+ return [4 /*yield*/, bootServer({
396
+ specification: specification,
397
+ port: port,
398
+ })];
399
+ case 2:
400
+ server = _a.sent();
401
+ return [2 /*return*/];
402
+ }
403
+ });
404
+ }); })];
405
+ case 2:
406
+ _c.sent();
407
+ _c.label = 3;
408
+ case 3:
409
+ // Show all paths from the specification
410
+ printAvailablePaths(specification);
411
+ return [4 /*yield*/, bootServer({
412
+ specification: specification,
413
+ port: port,
414
+ })];
415
+ case 4:
416
+ // Listen for requests
417
+ server = _c.sent();
418
+ return [2 /*return*/];
419
+ }
420
+ });
421
+ }); });
422
+ return cmd;
423
+ }
424
+ function bootServer(_a) {
425
+ return __awaiter(this, arguments, void 0, function (_b) {
426
+ var app;
427
+ var specification = _b.specification, port = _b.port;
428
+ return __generator(this, function (_c) {
429
+ switch (_c.label) {
430
+ case 0: return [4 /*yield*/, createMockServer({
431
+ specification: specification,
432
+ onRequest: onRequest,
433
+ })];
434
+ case 1:
435
+ app = _c.sent();
436
+ return [2 /*return*/, serve({
381
437
  fetch: app.fetch,
382
438
  port: port !== null && port !== void 0 ? port : 3000,
383
439
  }, function (info) {
384
440
  console.log("".concat(kleur.bold().green('➜ Mock Server'), " ").concat(kleur.white('listening on'), " ").concat(kleur.cyan("http://localhost:".concat(info.port))));
385
441
  console.log();
386
- });
387
- return [2 /*return*/];
388
- }
389
- });
442
+ })];
443
+ }
390
444
  });
391
445
  });
392
- return cmd;
446
+ }
447
+ function printAvailablePaths(specification) {
448
+ var _a, _b;
449
+ console.log(kleur.bold().white('Available Paths'));
450
+ console.log();
451
+ if ((specification === null || specification === void 0 ? void 0 : specification.paths) === undefined ||
452
+ Object.keys(specification === null || specification === void 0 ? void 0 : specification.paths).length === 0) {
453
+ console.log(kleur.bold().yellow('[WARN]'), kleur.grey('Couldn’t find any paths in the OpenAPI file.'));
454
+ }
455
+ // loop through all paths
456
+ for (var path in (_a = specification === null || specification === void 0 ? void 0 : specification.paths) !== null && _a !== void 0 ? _a : []) {
457
+ // loop through all methods
458
+ for (var method in (_b = specification.paths) === null || _b === void 0 ? void 0 : _b[path]) {
459
+ console.log("".concat(kleur
460
+ .bold()[getMethodColor(method)](method.toUpperCase().padEnd(6)), " ").concat(kleur.grey("".concat(path))));
461
+ }
462
+ }
463
+ console.log();
464
+ }
465
+ function onRequest(_a) {
466
+ var context = _a.context, operation = _a.operation;
467
+ var method = context.req.method;
468
+ console.log("".concat(kleur
469
+ .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)
470
+ ? kleur.white(operation.operationId)
471
+ : kleur.red('[ERROR] 404 Not Found')));
393
472
  }
394
473
 
395
474
  function ReferenceCommand() {
@@ -399,88 +478,83 @@ function ReferenceCommand() {
399
478
  cmd.argument('[file]', 'OpenAPI file to show the reference for');
400
479
  cmd.option('-w, --watch', 'watch the file for changes');
401
480
  cmd.option('-p, --port <port>', 'set the HTTP port for the API reference server');
402
- cmd.action(function (fileArgument, _a) {
403
- var watch = _a.watch, port = _a.port;
404
- return __awaiter(_this, void 0, void 0, function () {
405
- var file, specification, app;
406
- var _this = this;
407
- return __generator(this, function (_b) {
408
- switch (_b.label) {
409
- case 0:
410
- file = useGivenFileOrConfiguration(fileArgument);
411
- return [4 /*yield*/, loadOpenApiFile(file)];
412
- case 1:
413
- specification = (_b.sent())
414
- .specification;
415
- if ((specification === null || specification === void 0 ? void 0 : specification.paths) === undefined ||
416
- Object.keys(specification === null || specification === void 0 ? void 0 : specification.paths).length === 0) {
417
- console.log(kleur.bold().yellow('[WARN]'), kleur.grey('Couldn’t find any paths in the OpenAPI file.'));
418
- }
419
- app = new Hono();
420
- app.get('/', function (c) {
421
- return c.html(getHtmlDocument(specification, watch));
481
+ cmd.action(function (fileArgument_1, _a) { return __awaiter(_this, [fileArgument_1, _a], void 0, function (fileArgument, _b) {
482
+ var file, specification, app;
483
+ var _this = this;
484
+ var watch = _b.watch, port = _b.port;
485
+ return __generator(this, function (_c) {
486
+ switch (_c.label) {
487
+ case 0:
488
+ file = useGivenFileOrConfiguration(fileArgument);
489
+ return [4 /*yield*/, loadOpenApiFile(file)];
490
+ case 1:
491
+ specification = (_c.sent()).specification;
492
+ if ((specification === null || specification === void 0 ? void 0 : specification.paths) === undefined ||
493
+ Object.keys(specification === null || specification === void 0 ? void 0 : specification.paths).length === 0) {
494
+ console.log(kleur.bold().yellow('[WARN]'), kleur.grey('Couldn’t find any paths in the OpenAPI file.'));
495
+ }
496
+ app = new Hono();
497
+ app.get('/', function (c) {
498
+ return c.html(getHtmlDocument(specification, watch));
499
+ });
500
+ app.use('/__watcher', function (c, next) { return __awaiter(_this, void 0, void 0, function () {
501
+ return __generator(this, function (_a) {
502
+ switch (_a.label) {
503
+ case 0:
504
+ c.header('Content-Type', 'text/event-stream');
505
+ c.header('Cache-Control', 'no-cache');
506
+ c.header('Connection', 'keep-alive');
507
+ return [4 /*yield*/, next()];
508
+ case 1:
509
+ _a.sent();
510
+ return [2 /*return*/];
511
+ }
422
512
  });
423
- app.use('/__watcher', function (c, next) { return __awaiter(_this, void 0, void 0, function () {
513
+ }); });
514
+ app.get('/__watcher', function (c) {
515
+ return stream(c, function (stream) { return __awaiter(_this, void 0, void 0, function () {
516
+ var _this = this;
424
517
  return __generator(this, function (_a) {
425
518
  switch (_a.label) {
426
519
  case 0:
427
- c.header('Content-Type', 'text/event-stream');
428
- c.header('Cache-Control', 'no-cache');
429
- c.header('Connection', 'keep-alive');
430
- return [4 /*yield*/, next()];
520
+ // watch file for changes
521
+ if (watch) {
522
+ watchFile(file, function () { return __awaiter(_this, void 0, void 0, function () {
523
+ return __generator(this, function (_a) {
524
+ switch (_a.label) {
525
+ case 0:
526
+ console.log(kleur.bold().white('[INFO]'), kleur.grey('OpenAPI file modified'));
527
+ return [4 /*yield*/, loadOpenApiFile(file)];
528
+ case 1:
529
+ specification = (_a.sent()).specification;
530
+ stream.write('data: file modified\n\n');
531
+ return [2 /*return*/];
532
+ }
533
+ });
534
+ }); });
535
+ }
536
+ _a.label = 1;
431
537
  case 1:
538
+ return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, 100); })];
539
+ case 2:
432
540
  _a.sent();
433
- return [2 /*return*/];
541
+ return [3 /*break*/, 1];
542
+ case 3: return [2 /*return*/];
434
543
  }
435
544
  });
436
545
  }); });
437
- app.get('/__watcher', function (c) {
438
- return stream(c, function (stream) { return __awaiter(_this, void 0, void 0, function () {
439
- var _this = this;
440
- return __generator(this, function (_a) {
441
- switch (_a.label) {
442
- case 0:
443
- // watch file for changes
444
- if (watch) {
445
- console.log("Watch ".concat(file));
446
- fs.watchFile(file, function () { return __awaiter(_this, void 0, void 0, function () {
447
- return __generator(this, function (_a) {
448
- switch (_a.label) {
449
- case 0:
450
- console.log(kleur.bold().white('[INFO]'), kleur.grey('OpenAPI file modified'));
451
- return [4 /*yield*/, loadOpenApiFile(file)];
452
- case 1:
453
- specification = (_a.sent())
454
- .specification;
455
- stream.write('data: file modified\n\n');
456
- return [2 /*return*/];
457
- }
458
- });
459
- }); });
460
- }
461
- _a.label = 1;
462
- case 1:
463
- return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, 100); })];
464
- case 2:
465
- _a.sent();
466
- return [3 /*break*/, 1];
467
- case 3: return [2 /*return*/];
468
- }
469
- });
470
- }); });
471
- });
472
- serve({
473
- fetch: app.fetch,
474
- port: port !== null && port !== void 0 ? port : 3000,
475
- }, function (info) {
476
- console.log("".concat(kleur.bold().green('➜ API Reference Server'), " ").concat(kleur.white('listening on'), " ").concat(kleur.cyan("http://localhost:".concat(info.port))));
477
- console.log();
478
- });
479
- return [2 /*return*/];
480
- }
481
- });
546
+ });
547
+ serve({
548
+ fetch: app.fetch,
549
+ port: port !== null && port !== void 0 ? port : 3000,
550
+ }, function (info) {
551
+ console.log("".concat(kleur.bold().green('➜ API Reference Server'), " ").concat(kleur.white('listening on'), " ").concat(kleur.cyan("http://localhost:".concat(info.port))));
552
+ console.log();
553
+ });
554
+ return [2 /*return*/];
555
+ }
482
556
  });
483
- });
557
+ }); });
484
558
  return cmd;
485
559
  }
486
560
 
@@ -541,19 +615,19 @@ function ValidateCommand() {
541
615
  cmd.description('Validate an OpenAPI file');
542
616
  cmd.argument('[file]', 'file to validate');
543
617
  cmd.action(function (fileArgument) { return __awaiter(_this, void 0, void 0, function () {
544
- var startTime, file, validator, result, endTime;
618
+ var startTime, file, specification, result, endTime;
545
619
  var _a;
546
620
  return __generator(this, function (_b) {
547
621
  switch (_b.label) {
548
622
  case 0:
549
623
  startTime = performance.now();
550
624
  file = useGivenFileOrConfiguration(fileArgument);
551
- validator = new Validator();
552
- return [4 /*yield*/, validator.validate(file)];
625
+ specification = fs.readFileSync(file, 'utf8');
626
+ return [4 /*yield*/, openapi().load(specification).validate()];
553
627
  case 1:
554
628
  result = _b.sent();
555
629
  if (result.valid) {
556
- console.log(kleur.green("Matches the OpenAPI specification".concat(kleur.white(" (OpenAPI ".concat(kleur.bold(validator.version), ")")))));
630
+ console.log(kleur.green("Matches the OpenAPI specification".concat(kleur.white(" (OpenAPI ".concat(kleur.bold(result.version), ")")))));
557
631
  endTime = performance.now();
558
632
  console.log();
559
633
  console.log(kleur.green('File validated'), kleur.grey("in ".concat(kleur.white("".concat(kleur.bold("".concat(Math.round(endTime - startTime))), " ms")))));
@@ -585,6 +659,7 @@ program.addCommand(InitCommand(), {
585
659
  });
586
660
  program.addCommand(FormatCommand());
587
661
  program.addCommand(ValidateCommand());
662
+ program.addCommand(BundleCommand());
588
663
  program.addCommand(ReferenceCommand());
589
664
  program.addCommand(MockCommand());
590
665
  program.addCommand(ShareCommand());