@redocly/openapi-core 1.0.0-beta.96 → 1.0.0-beta.99

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 (106) hide show
  1. package/lib/bundle.d.ts +2 -0
  2. package/lib/bundle.js +6 -3
  3. package/lib/config/all.js +1 -0
  4. package/lib/config/config-resolvers.d.ts +1 -1
  5. package/lib/config/config-resolvers.js +31 -2
  6. package/lib/config/config.d.ts +4 -1
  7. package/lib/config/config.js +18 -12
  8. package/lib/format/format.js +2 -1
  9. package/lib/redocly/index.js +10 -26
  10. package/lib/redocly/registry-api-types.d.ts +1 -0
  11. package/lib/redocly/registry-api.d.ts +1 -1
  12. package/lib/redocly/registry-api.js +2 -1
  13. package/lib/ref-utils.js +1 -0
  14. package/lib/rules/common/response-contains-header.d.ts +2 -0
  15. package/lib/rules/common/response-contains-header.js +29 -0
  16. package/lib/rules/common/scalar-property-missing-example.d.ts +2 -0
  17. package/lib/rules/common/scalar-property-missing-example.js +41 -0
  18. package/lib/rules/oas2/index.d.ts +3 -0
  19. package/lib/rules/oas2/index.js +6 -0
  20. package/lib/rules/oas2/response-contains-property.d.ts +2 -0
  21. package/lib/rules/oas2/response-contains-property.js +38 -0
  22. package/lib/rules/oas3/index.js +6 -0
  23. package/lib/rules/oas3/response-contains-property.d.ts +2 -0
  24. package/lib/rules/oas3/response-contains-property.js +40 -0
  25. package/lib/types/oas2.js +3 -1
  26. package/lib/types/oas3.js +21 -8
  27. package/lib/types/oas3_1.js +12 -8
  28. package/lib/types/redocly-yaml.js +12 -0
  29. package/lib/typings/openapi.d.ts +5 -2
  30. package/lib/typings/swagger.d.ts +2 -0
  31. package/lib/utils.d.ts +1 -1
  32. package/lib/utils.js +5 -3
  33. package/package.json +3 -3
  34. package/{__tests__ → src/__tests__}/__snapshots__/bundle.test.ts.snap +26 -0
  35. package/{__tests__ → src/__tests__}/bundle.test.ts +30 -6
  36. package/{__tests__ → src/__tests__}/codeframes.test.ts +3 -3
  37. package/{__tests__ → src/__tests__}/fixtures/extension.js +0 -0
  38. package/{__tests__ → src/__tests__}/fixtures/refs/definitions.yaml +0 -0
  39. package/{__tests__ → src/__tests__}/fixtures/refs/examples.yaml +0 -0
  40. package/{__tests__ → src/__tests__}/fixtures/refs/external-request-body.yaml +0 -0
  41. package/{__tests__ → src/__tests__}/fixtures/refs/externalref.yaml +0 -0
  42. package/{__tests__ → src/__tests__}/fixtures/refs/hosted.yaml +0 -0
  43. package/{__tests__ → src/__tests__}/fixtures/refs/openapi-with-external-refs-conflicting-names.yaml +0 -0
  44. package/{__tests__ → src/__tests__}/fixtures/refs/openapi-with-external-refs.yaml +0 -0
  45. package/src/__tests__/fixtures/refs/openapi-with-url-refs.yaml +18 -0
  46. package/{__tests__ → src/__tests__}/fixtures/refs/param-b.yaml +0 -0
  47. package/{__tests__ → src/__tests__}/fixtures/refs/param-c.yaml +0 -0
  48. package/{__tests__ → src/__tests__}/fixtures/refs/rename.yaml +0 -0
  49. package/{__tests__ → src/__tests__}/fixtures/refs/requestBody.yaml +0 -0
  50. package/{__tests__ → src/__tests__}/fixtures/refs/schema-a.yaml +0 -0
  51. package/{__tests__ → src/__tests__}/fixtures/refs/simple.yaml +0 -0
  52. package/{__tests__ → src/__tests__}/fixtures/refs/vendor.schema.yaml +0 -0
  53. package/{__tests__ → src/__tests__}/fixtures/resolve/External.yaml +0 -0
  54. package/{__tests__ → src/__tests__}/fixtures/resolve/External2.yaml +0 -0
  55. package/{__tests__ → src/__tests__}/fixtures/resolve/description.md +0 -0
  56. package/{__tests__ → src/__tests__}/fixtures/resolve/externalInfo.yaml +0 -0
  57. package/{__tests__ → src/__tests__}/fixtures/resolve/externalLicense.yaml +0 -0
  58. package/{__tests__ → src/__tests__}/fixtures/resolve/openapi-with-back.yaml +0 -0
  59. package/{__tests__ → src/__tests__}/fixtures/resolve/openapi-with-md-description.yaml +0 -0
  60. package/{__tests__ → src/__tests__}/fixtures/resolve/openapi.yaml +0 -0
  61. package/{__tests__ → src/__tests__}/fixtures/resolve/schemas/type-a.yaml +0 -0
  62. package/{__tests__ → src/__tests__}/fixtures/resolve/schemas/type-b.yaml +0 -0
  63. package/{__tests__ → src/__tests__}/fixtures/resolve/transitive/a.yaml +0 -0
  64. package/{__tests__ → src/__tests__}/fixtures/resolve/transitive/components.yaml +0 -0
  65. package/{__tests__ → src/__tests__}/fixtures/resolve/transitive/schemas.yaml +0 -0
  66. package/src/__tests__/lint.test.ts +13 -0
  67. package/{__tests__ → src/__tests__}/login.test.ts +1 -1
  68. package/{__tests__ → src/__tests__}/normalizeVisitors.test.ts +4 -4
  69. package/{__tests__ → src/__tests__}/ref-utils.test.ts +5 -5
  70. package/{__tests__ → src/__tests__}/resolve-http.test.ts +4 -4
  71. package/{__tests__ → src/__tests__}/resolve.test.ts +4 -4
  72. package/src/__tests__/utils.test.ts +12 -1
  73. package/{__tests__ → src/__tests__}/walk.test.ts +5 -5
  74. package/src/bundle.ts +18 -3
  75. package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +18 -1
  76. package/src/config/__tests__/config-resolvers.test.ts +32 -1
  77. package/src/config/__tests__/fixtures/resolve-config/api/nested-config.yaml +5 -0
  78. package/src/config/__tests__/fixtures/resolve-config/local-config-with-file.yaml +7 -0
  79. package/src/config/all.ts +1 -0
  80. package/src/config/config-resolvers.ts +58 -3
  81. package/src/config/config.ts +21 -12
  82. package/src/format/format.ts +2 -1
  83. package/src/redocly/index.ts +12 -41
  84. package/src/redocly/registry-api-types.ts +1 -0
  85. package/src/redocly/registry-api.ts +2 -0
  86. package/src/ref-utils.ts +1 -0
  87. package/src/rules/common/__tests__/scalar-property-missing-example.test.ts +207 -0
  88. package/src/rules/common/response-contains-header.ts +30 -0
  89. package/src/rules/common/scalar-property-missing-example.ts +55 -0
  90. package/src/rules/oas2/__tests__/response-contains-header.test.ts +174 -0
  91. package/src/rules/oas2/__tests__/response-contains-property.test.ts +155 -0
  92. package/src/rules/oas2/index.ts +6 -0
  93. package/src/rules/oas2/response-contains-property.ts +36 -0
  94. package/src/rules/oas3/__tests__/response-contains-header.test.ts +273 -0
  95. package/src/rules/oas3/__tests__/response-contains-property.test.ts +403 -0
  96. package/src/rules/oas3/index.ts +6 -0
  97. package/src/rules/oas3/response-contains-property.ts +38 -0
  98. package/src/types/oas2.ts +2 -0
  99. package/src/types/oas3.ts +18 -7
  100. package/src/types/oas3_1.ts +11 -7
  101. package/src/types/redocly-yaml.ts +12 -0
  102. package/src/typings/openapi.ts +4 -1
  103. package/src/typings/swagger.ts +2 -0
  104. package/src/utils.ts +6 -2
  105. package/tsconfig.tsbuildinfo +1 -1
  106. package/__tests__/lint.test.ts +0 -17
package/lib/bundle.d.ts CHANGED
@@ -18,6 +18,7 @@ export declare function bundle(opts: {
18
18
  base?: string;
19
19
  skipRedoclyRegistryRefs?: boolean;
20
20
  removeUnusedComponents?: boolean;
21
+ keepUrlRefs?: boolean;
21
22
  }): Promise<{
22
23
  bundle: Document;
23
24
  problems: import("./walk").NormalizedProblem[];
@@ -34,6 +35,7 @@ export declare function bundleDocument(opts: {
34
35
  dereference?: boolean;
35
36
  skipRedoclyRegistryRefs?: boolean;
36
37
  removeUnusedComponents?: boolean;
38
+ keepUrlRefs?: boolean;
37
39
  }): Promise<{
38
40
  bundle: Document;
39
41
  problems: import("./walk").NormalizedProblem[];
package/lib/bundle.js CHANGED
@@ -48,7 +48,7 @@ function bundle(opts) {
48
48
  exports.bundle = bundle;
49
49
  function bundleDocument(opts) {
50
50
  return __awaiter(this, void 0, void 0, function* () {
51
- const { document, config, customTypes, externalRefResolver, dereference = false, skipRedoclyRegistryRefs = false, removeUnusedComponents = false, } = opts;
51
+ const { document, config, customTypes, externalRefResolver, dereference = false, skipRedoclyRegistryRefs = false, removeUnusedComponents = false, keepUrlRefs = false, } = opts;
52
52
  const oasVersion = oas_types_1.detectOpenAPI(document.parsed);
53
53
  const oasMajorVersion = oas_types_1.openAPIMajor(oasVersion);
54
54
  const rules = config.getRulesForOasVersion(oasMajorVersion);
@@ -84,7 +84,7 @@ function bundleDocument(opts) {
84
84
  {
85
85
  severity: 'error',
86
86
  ruleId: 'bundler',
87
- visitor: makeBundleVisitor(oasMajorVersion, dereference, skipRedoclyRegistryRefs, document, resolvedRefMap),
87
+ visitor: makeBundleVisitor(oasMajorVersion, dereference, skipRedoclyRegistryRefs, document, resolvedRefMap, keepUrlRefs),
88
88
  },
89
89
  ...decorators,
90
90
  ], types);
@@ -146,7 +146,7 @@ function mapTypeToComponent(typeName, version) {
146
146
  }
147
147
  exports.mapTypeToComponent = mapTypeToComponent;
148
148
  // function oas3Move
149
- function makeBundleVisitor(version, dereference, skipRedoclyRegistryRefs, rootDocument, resolvedRefMap) {
149
+ function makeBundleVisitor(version, dereference, skipRedoclyRegistryRefs, rootDocument, resolvedRefMap, keepUrlRefs) {
150
150
  let components;
151
151
  const visitor = {
152
152
  ref: {
@@ -165,6 +165,9 @@ function makeBundleVisitor(version, dereference, skipRedoclyRegistryRefs, rootDo
165
165
  if (skipRedoclyRegistryRefs && redocly_1.isRedoclyRegistryURL(node.$ref)) {
166
166
  return;
167
167
  }
168
+ if (keepUrlRefs && ref_utils_1.isAbsoluteUrl(node.$ref)) {
169
+ return;
170
+ }
168
171
  const componentType = mapTypeToComponent(ctx.type.name, version);
169
172
  if (!componentType) {
170
173
  replaceRef(node, resolved, ctx);
package/lib/config/all.js CHANGED
@@ -41,6 +41,7 @@ exports.default = {
41
41
  spec: 'error',
42
42
  'no-invalid-schema-examples': 'error',
43
43
  'no-invalid-parameter-examples': 'error',
44
+ 'scalar-property-missing-example': 'error',
44
45
  },
45
46
  oas3_0Rules: {
46
47
  'no-invalid-media-type-examples': 'error',
@@ -8,7 +8,7 @@ export declare function resolveApis({ rawConfig, configPath, resolver, }: {
8
8
  configPath?: string;
9
9
  resolver?: BaseResolver;
10
10
  }): Promise<Record<string, ResolvedApi>>;
11
- export declare function resolveLint({ lintConfig, configPath, resolver, }: {
11
+ export declare function resolveLint(lintOpts: {
12
12
  lintConfig?: LintRawConfig;
13
13
  configPath?: string;
14
14
  resolver?: BaseResolver;
@@ -141,7 +141,7 @@ function resolveApis({ rawConfig, configPath = '', resolver, }) {
141
141
  });
142
142
  }
143
143
  exports.resolveApis = resolveApis;
144
- function resolveLint({ lintConfig, configPath = '', resolver = new resolve_1.BaseResolver(), }, parentConfigPaths = [], extendPaths = []) {
144
+ function resolveAndMergeNestedLint({ lintConfig, configPath = '', resolver = new resolve_1.BaseResolver(), }, parentConfigPaths = [], extendPaths = []) {
145
145
  var _a, _b, _c;
146
146
  return __awaiter(this, void 0, void 0, function* () {
147
147
  if (parentConfigPaths.includes(configPath)) {
@@ -162,7 +162,7 @@ function resolveLint({ lintConfig, configPath = '', resolver = new resolve_1.Bas
162
162
  ? new URL(presetItem, configPath).href
163
163
  : path.resolve(path.dirname(configPath), presetItem);
164
164
  const extendedLintConfig = yield loadExtendLintConfig(pathItem, resolver);
165
- return yield resolveLint({
165
+ return yield resolveAndMergeNestedLint({
166
166
  lintConfig: extendedLintConfig,
167
167
  configPath: pathItem,
168
168
  resolver: resolver,
@@ -175,6 +175,12 @@ function resolveLint({ lintConfig, configPath = '', resolver = new resolve_1.Bas
175
175
  return Object.assign(Object.assign({}, lint), { extendPaths: (_c = lint.extendPaths) === null || _c === void 0 ? void 0 : _c.filter((path) => path && !ref_utils_1.isAbsoluteUrl(path)), plugins: utils_1.getUniquePlugins(mergedPlugins), recommendedFallback: lintConfig === null || lintConfig === void 0 ? void 0 : lintConfig.recommendedFallback, doNotResolveExamples: lintConfig === null || lintConfig === void 0 ? void 0 : lintConfig.doNotResolveExamples });
176
176
  });
177
177
  }
178
+ function resolveLint(lintOpts, parentConfigPaths = [], extendPaths = []) {
179
+ return __awaiter(this, void 0, void 0, function* () {
180
+ const resolvedLint = yield resolveAndMergeNestedLint(lintOpts, parentConfigPaths, extendPaths);
181
+ return Object.assign(Object.assign({}, resolvedLint), { rules: resolvedLint.rules && groupLintAssertionRules(resolvedLint.rules) });
182
+ });
183
+ }
178
184
  exports.resolveLint = resolveLint;
179
185
  function resolvePreset(presetName, plugins) {
180
186
  var _a;
@@ -211,3 +217,26 @@ function getMergedLintRawConfig(configLint, apiLint) {
211
217
  const resultLint = Object.assign(Object.assign(Object.assign({}, configLint), apiLint), { rules: Object.assign(Object.assign({}, configLint === null || configLint === void 0 ? void 0 : configLint.rules), apiLint === null || apiLint === void 0 ? void 0 : apiLint.rules), oas2Rules: Object.assign(Object.assign({}, configLint === null || configLint === void 0 ? void 0 : configLint.oas2Rules), apiLint === null || apiLint === void 0 ? void 0 : apiLint.oas2Rules), oas3_0Rules: Object.assign(Object.assign({}, configLint === null || configLint === void 0 ? void 0 : configLint.oas3_0Rules), apiLint === null || apiLint === void 0 ? void 0 : apiLint.oas3_0Rules), oas3_1Rules: Object.assign(Object.assign({}, configLint === null || configLint === void 0 ? void 0 : configLint.oas3_1Rules), apiLint === null || apiLint === void 0 ? void 0 : apiLint.oas3_1Rules), preprocessors: Object.assign(Object.assign({}, configLint === null || configLint === void 0 ? void 0 : configLint.preprocessors), apiLint === null || apiLint === void 0 ? void 0 : apiLint.preprocessors), oas2Preprocessors: Object.assign(Object.assign({}, configLint === null || configLint === void 0 ? void 0 : configLint.oas2Preprocessors), apiLint === null || apiLint === void 0 ? void 0 : apiLint.oas2Preprocessors), oas3_0Preprocessors: Object.assign(Object.assign({}, configLint === null || configLint === void 0 ? void 0 : configLint.oas3_0Preprocessors), apiLint === null || apiLint === void 0 ? void 0 : apiLint.oas3_0Preprocessors), oas3_1Preprocessors: Object.assign(Object.assign({}, configLint === null || configLint === void 0 ? void 0 : configLint.oas3_1Preprocessors), apiLint === null || apiLint === void 0 ? void 0 : apiLint.oas3_1Preprocessors), decorators: Object.assign(Object.assign({}, configLint === null || configLint === void 0 ? void 0 : configLint.decorators), apiLint === null || apiLint === void 0 ? void 0 : apiLint.decorators), oas2Decorators: Object.assign(Object.assign({}, configLint === null || configLint === void 0 ? void 0 : configLint.oas2Decorators), apiLint === null || apiLint === void 0 ? void 0 : apiLint.oas2Decorators), oas3_0Decorators: Object.assign(Object.assign({}, configLint === null || configLint === void 0 ? void 0 : configLint.oas3_0Decorators), apiLint === null || apiLint === void 0 ? void 0 : apiLint.oas3_0Decorators), oas3_1Decorators: Object.assign(Object.assign({}, configLint === null || configLint === void 0 ? void 0 : configLint.oas3_1Decorators), apiLint === null || apiLint === void 0 ? void 0 : apiLint.oas3_1Decorators), recommendedFallback: (apiLint === null || apiLint === void 0 ? void 0 : apiLint.extends) ? false : configLint.recommendedFallback });
212
218
  return resultLint;
213
219
  }
220
+ function groupLintAssertionRules(rules) {
221
+ if (!rules) {
222
+ return rules;
223
+ }
224
+ // Create a new record to avoid mutating original
225
+ const transformedRules = {};
226
+ // Collect assertion rules
227
+ const assertions = [];
228
+ for (const [ruleKey, rule] of Object.entries(rules)) {
229
+ if (ruleKey.startsWith('assert/') && typeof rule === 'object' && rule !== null) {
230
+ const assertion = rule;
231
+ assertions.push(Object.assign(Object.assign({}, assertion), { assertionId: ruleKey.replace('assert/', '') }));
232
+ }
233
+ else {
234
+ // If it's not an assertion, keep it as is
235
+ transformedRules[ruleKey] = rule;
236
+ }
237
+ }
238
+ if (assertions.length > 0) {
239
+ transformedRules.assertions = assertions;
240
+ }
241
+ return transformedRules;
242
+ }
@@ -1,11 +1,14 @@
1
+ /// <reference types="node" />
1
2
  import { NormalizedProblem } from '../walk';
2
3
  import { OasVersion, OasMajorVersion, Oas2RuleSet, Oas3RuleSet } from '../oas-types';
3
4
  import type { NodeType } from '../types';
4
5
  import type { DecoratorConfig, Plugin, PreprocessorConfig, Region, ResolveConfig, ResolvedApi, ResolvedConfig, ResolvedLintConfig, RuleConfig } from './types';
6
+ export declare const env: NodeJS.ProcessEnv;
5
7
  export declare const IGNORE_FILE = ".redocly.lint-ignore.yaml";
6
8
  export declare const DEFAULT_REGION = "us";
7
9
  export declare const DOMAINS: {
8
- [region in Region]: string;
10
+ us: string;
11
+ eu: string;
9
12
  };
10
13
  export declare const AVAILABLE_REGIONS: Region[];
11
14
  export declare class LintConfig {
@@ -1,28 +1,34 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Config = exports.LintConfig = exports.AVAILABLE_REGIONS = exports.DOMAINS = exports.DEFAULT_REGION = exports.IGNORE_FILE = void 0;
3
+ exports.Config = exports.LintConfig = exports.AVAILABLE_REGIONS = exports.DOMAINS = exports.DEFAULT_REGION = exports.IGNORE_FILE = exports.env = void 0;
4
4
  const fs = require("fs");
5
5
  const path = require("path");
6
6
  const js_yaml_1 = require("../js-yaml");
7
7
  const utils_1 = require("../utils");
8
8
  const oas_types_1 = require("../oas-types");
9
9
  const utils_2 = require("./utils");
10
+ // Alias environment here so this file can work in browser environments too.
11
+ exports.env = typeof process !== 'undefined' ? process.env || {} : {};
10
12
  exports.IGNORE_FILE = '.redocly.lint-ignore.yaml';
11
13
  const IGNORE_BANNER = `# This file instructs Redocly's linter to ignore the rules contained for specific parts of your API.\n` +
12
14
  `# See https://redoc.ly/docs/cli/ for more information.\n`;
13
15
  exports.DEFAULT_REGION = 'us';
14
- const REDOCLY_DOMAIN = process.env.REDOCLY_DOMAIN;
15
- exports.DOMAINS = {
16
- us: 'redocly.com',
17
- eu: 'eu.redocly.com',
18
- };
19
- // FIXME: temporary fix for our lab environments
20
- if (REDOCLY_DOMAIN === null || REDOCLY_DOMAIN === void 0 ? void 0 : REDOCLY_DOMAIN.endsWith('.redocly.host')) {
21
- exports.DOMAINS[REDOCLY_DOMAIN.split('.')[0]] = REDOCLY_DOMAIN;
22
- }
23
- if (REDOCLY_DOMAIN === 'redoc.online') {
24
- exports.DOMAINS[REDOCLY_DOMAIN] = REDOCLY_DOMAIN;
16
+ function getDomains() {
17
+ const domains = {
18
+ us: 'redocly.com',
19
+ eu: 'eu.redocly.com',
20
+ };
21
+ // FIXME: temporary fix for our lab environments
22
+ const domain = exports.env.REDOCLY_DOMAIN;
23
+ if (domain === null || domain === void 0 ? void 0 : domain.endsWith('.redocly.host')) {
24
+ domains[domain.split('.')[0]] = domain;
25
+ }
26
+ if (domain === 'redoc.online') {
27
+ domains[domain] = domain;
28
+ }
29
+ return domains;
25
30
  }
31
+ exports.DOMAINS = getDomains();
26
32
  exports.AVAILABLE_REGIONS = Object.keys(exports.DOMAINS);
27
33
  class LintConfig {
28
34
  constructor(rawConfig, configFile) {
@@ -5,6 +5,7 @@ const path = require("path");
5
5
  const colorette_1 = require("colorette");
6
6
  const coreVersion = require('../../package.json').version;
7
7
  const codeframes_1 = require("./codeframes");
8
+ const config_1 = require("../config");
8
9
  const ERROR_MESSAGE = {
9
10
  INVALID_SEVERITY_LEVEL: 'Invalid severity level; accepted values: error or warn',
10
11
  };
@@ -131,7 +132,7 @@ function formatProblems(problems, opts) {
131
132
  ? Object.assign(Object.assign({}, p.from), { source: {
132
133
  ref: path.relative(cwd, ((_a = p.from) === null || _a === void 0 ? void 0 : _a.source.absoluteRef) || cwd),
133
134
  } }) : undefined });
134
- if (process.env.FORMAT_JSON_WITH_CODEFRAMES) {
135
+ if (config_1.env.FORMAT_JSON_WITH_CODEFRAMES) {
135
136
  const location = p.location[0]; // TODO: support multiple locations
136
137
  const loc = codeframes_1.getLineColLocation(location);
137
138
  problem.codeframe = codeframes_1.getCodeframe(loc, color);
@@ -18,27 +18,21 @@ const registry_api_1 = require("./registry-api");
18
18
  const config_1 = require("../config/config");
19
19
  const utils_1 = require("../utils");
20
20
  const TOKEN_FILENAME = '.redocly-config.json';
21
- let REDOCLY_DOMAIN; // workaround for the isRedoclyRegistryURL, see more below
22
21
  class RedoclyClient {
23
22
  constructor(region) {
24
23
  this.accessTokens = {};
25
24
  this.region = this.loadRegion(region);
26
25
  this.loadTokens();
27
- this.domain = region ? config_1.DOMAINS[region] : process.env.REDOCLY_DOMAIN || config_1.DOMAINS[config_1.DEFAULT_REGION];
28
- /*
29
- * We can't use process.env here because it is replaced by a const in some client-side bundles,
30
- * which breaks assignment.
31
- */
32
- REDOCLY_DOMAIN = this.domain; // isRedoclyRegistryURL depends on the value to be set
26
+ this.domain = region ? config_1.DOMAINS[region] : config_1.env.REDOCLY_DOMAIN || config_1.DOMAINS[config_1.DEFAULT_REGION];
27
+ config_1.env.REDOCLY_DOMAIN = this.domain; // isRedoclyRegistryURL depends on the value to be set
33
28
  this.registryApi = new registry_api_1.RegistryApi(this.accessTokens, this.region);
34
29
  }
35
30
  loadRegion(region) {
36
31
  if (region && !config_1.DOMAINS[region]) {
37
- process.stdout.write(colorette_1.red(`Invalid argument: region in config file.\nGiven: ${colorette_1.green(region)}, choices: "us", "eu".\n`));
38
- process.exit(1);
32
+ throw new Error(`Invalid argument: region in config file.\nGiven: ${colorette_1.green(region)}, choices: "us", "eu".`);
39
33
  }
40
- if (process.env.REDOCLY_DOMAIN) {
41
- return (config_1.AVAILABLE_REGIONS.find((region) => config_1.DOMAINS[region] === process.env.REDOCLY_DOMAIN) || config_1.DEFAULT_REGION);
34
+ if (config_1.env.REDOCLY_DOMAIN) {
35
+ return (config_1.AVAILABLE_REGIONS.find((region) => config_1.DOMAINS[region] === config_1.env.REDOCLY_DOMAIN) || config_1.DEFAULT_REGION);
42
36
  }
43
37
  return region || config_1.DEFAULT_REGION;
44
38
  }
@@ -54,13 +48,7 @@ class RedoclyClient {
54
48
  }
55
49
  getAuthorizationHeader() {
56
50
  return __awaiter(this, void 0, void 0, function* () {
57
- const token = this.accessTokens[this.region];
58
- // print this only if there is token but invalid
59
- if (token && !this.isAuthorizedWithRedoclyByRegion()) {
60
- process.stderr.write(`${colorette_1.yellow('Warning:')} invalid Redocly API key. Use "npx @redocly/cli login" to provide your API key\n`);
61
- return undefined;
62
- }
63
- return token;
51
+ return this.accessTokens[this.region];
64
52
  });
65
53
  }
66
54
  // </backward compatibility: portal>
@@ -76,8 +64,8 @@ class RedoclyClient {
76
64
  [this.region]: credentials.token,
77
65
  })));
78
66
  }
79
- if (process.env.REDOCLY_AUTHORIZATION) {
80
- this.setAccessTokens(Object.assign(Object.assign({}, this.accessTokens), { [this.region]: process.env.REDOCLY_AUTHORIZATION }));
67
+ if (config_1.env.REDOCLY_AUTHORIZATION) {
68
+ this.setAccessTokens(Object.assign(Object.assign({}, this.accessTokens), { [this.region]: config_1.env.REDOCLY_AUTHORIZATION }));
81
69
  }
82
70
  }
83
71
  getAllTokens() {
@@ -133,19 +121,16 @@ class RedoclyClient {
133
121
  login(accessToken, verbose = false) {
134
122
  return __awaiter(this, void 0, void 0, function* () {
135
123
  const credentialsPath = path_1.resolve(os_1.homedir(), TOKEN_FILENAME);
136
- process.stdout.write(colorette_1.gray('\n Logging in...\n'));
137
124
  try {
138
125
  yield this.verifyToken(accessToken, this.region, verbose);
139
126
  }
140
127
  catch (err) {
141
- process.stdout.write(colorette_1.red('Authorization failed. Please check if you entered a valid API key.\n'));
142
- process.exit(1);
128
+ throw new Error('Authorization failed. Please check if you entered a valid API key.');
143
129
  }
144
130
  const credentials = Object.assign(Object.assign({}, this.readCredentialsFile(credentialsPath)), { [this.region]: accessToken, token: accessToken });
145
131
  this.accessTokens = credentials;
146
132
  this.registryApi.setAccessTokens(credentials);
147
133
  fs_1.writeFileSync(credentialsPath, JSON.stringify(credentials, null, 2));
148
- process.stdout.write(colorette_1.green(' Authorization confirmed. ✅\n\n'));
149
134
  });
150
135
  }
151
136
  logout() {
@@ -153,12 +138,11 @@ class RedoclyClient {
153
138
  if (fs_1.existsSync(credentialsPath)) {
154
139
  fs_1.unlinkSync(credentialsPath);
155
140
  }
156
- process.stdout.write('Logged out from the Redocly account. ✋\n');
157
141
  }
158
142
  }
159
143
  exports.RedoclyClient = RedoclyClient;
160
144
  function isRedoclyRegistryURL(link) {
161
- const domain = REDOCLY_DOMAIN || process.env.REDOCLY_DOMAIN || config_1.DOMAINS[config_1.DEFAULT_REGION];
145
+ const domain = config_1.env.REDOCLY_DOMAIN || config_1.DOMAINS[config_1.DEFAULT_REGION];
162
146
  const legacyDomain = domain === 'redocly.com' ? 'redoc.ly' : domain;
163
147
  if (!link.startsWith(`https://api.${domain}/registry/`) &&
164
148
  !link.startsWith(`https://api.${legacyDomain}/registry/`)) {
@@ -14,6 +14,7 @@ export declare namespace RegistryApiTypes {
14
14
  filePaths: string[];
15
15
  branch?: string;
16
16
  isUpsert?: boolean;
17
+ isPublic?: boolean;
17
18
  }
18
19
  export interface PrepareFileuploadOKResponse {
19
20
  filePath: string;
@@ -13,5 +13,5 @@ export declare class RegistryApi {
13
13
  organizations: string[];
14
14
  }>;
15
15
  prepareFileUpload({ organizationId, name, version, filesHash, filename, isUpsert, }: RegistryApiTypes.PrepareFileuploadParams): Promise<RegistryApiTypes.PrepareFileuploadOKResponse>;
16
- pushApi({ organizationId, name, version, rootFilePath, filePaths, branch, isUpsert, }: RegistryApiTypes.PushApiParams): Promise<void>;
16
+ pushApi({ organizationId, name, version, rootFilePath, filePaths, branch, isUpsert, isPublic, }: RegistryApiTypes.PushApiParams): Promise<void>;
17
17
  }
@@ -80,7 +80,7 @@ class RegistryApi {
80
80
  throw new Error('Could not prepare file upload');
81
81
  });
82
82
  }
83
- pushApi({ organizationId, name, version, rootFilePath, filePaths, branch, isUpsert, }) {
83
+ pushApi({ organizationId, name, version, rootFilePath, filePaths, branch, isUpsert, isPublic, }) {
84
84
  return __awaiter(this, void 0, void 0, function* () {
85
85
  const response = yield this.request(`/${organizationId}/${name}/${version}`, {
86
86
  method: 'PUT',
@@ -93,6 +93,7 @@ class RegistryApi {
93
93
  filePaths,
94
94
  branch,
95
95
  isUpsert,
96
+ isPublic,
96
97
  }),
97
98
  }, this.region);
98
99
  if (response.ok) {
package/lib/ref-utils.js CHANGED
@@ -67,6 +67,7 @@ function isMappingRef(mapping) {
67
67
  // TODO: proper detection of mapping refs
68
68
  return (mapping.startsWith('#') ||
69
69
  mapping.startsWith('https://') ||
70
+ mapping.startsWith('http://') ||
70
71
  mapping.startsWith('./') ||
71
72
  mapping.startsWith('../') ||
72
73
  mapping.indexOf('/') > -1);
@@ -0,0 +1,2 @@
1
+ import { Oas2Rule, Oas3Rule } from '../../visitors';
2
+ export declare const ResponseContainsHeader: Oas3Rule | Oas2Rule;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ResponseContainsHeader = void 0;
4
+ const utils_1 = require("../../utils");
5
+ const ResponseContainsHeader = (options) => {
6
+ const names = options.names || {};
7
+ return {
8
+ Operation: {
9
+ Response: {
10
+ enter: (response, { report, location, key }) => {
11
+ var _a;
12
+ const expectedHeaders = names[key] ||
13
+ names[utils_1.getMatchingStatusCodeRange(key)] ||
14
+ names[utils_1.getMatchingStatusCodeRange(key).toLowerCase()] ||
15
+ [];
16
+ for (const expectedHeader of expectedHeaders) {
17
+ if (!((_a = response.headers) === null || _a === void 0 ? void 0 : _a[expectedHeader])) {
18
+ report({
19
+ message: `Response object must contain a "${expectedHeader}" header.`,
20
+ location: location.child('headers').key(),
21
+ });
22
+ }
23
+ }
24
+ },
25
+ },
26
+ },
27
+ };
28
+ };
29
+ exports.ResponseContainsHeader = ResponseContainsHeader;
@@ -0,0 +1,2 @@
1
+ import type { Oas2Rule, Oas3Rule } from '../../visitors';
2
+ export declare const ScalarPropertyMissingExample: Oas3Rule | Oas2Rule;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ScalarPropertyMissingExample = void 0;
4
+ const oas_types_1 = require("../../oas-types");
5
+ const SCALAR_TYPES = ['string', 'integer', 'number', 'boolean', 'null'];
6
+ const ScalarPropertyMissingExample = () => {
7
+ return {
8
+ SchemaProperties(properties, { report, location, oasVersion, resolve }) {
9
+ for (const propName of Object.keys(properties)) {
10
+ const propSchema = resolve(properties[propName]).node;
11
+ if (!propSchema || !isScalarSchema(propSchema)) {
12
+ continue;
13
+ }
14
+ if (!propSchema.example && !propSchema.examples) {
15
+ report({
16
+ message: `Scalar property should have "example"${oasVersion === oas_types_1.OasVersion.Version3_1 ? ' or "examples"' : ''} defined.`,
17
+ location: location.child(propName).key(),
18
+ });
19
+ }
20
+ }
21
+ },
22
+ };
23
+ };
24
+ exports.ScalarPropertyMissingExample = ScalarPropertyMissingExample;
25
+ function isScalarSchema(schema) {
26
+ if (!schema.type) {
27
+ return false;
28
+ }
29
+ if (schema.allOf || schema.anyOf || schema.oneOf) {
30
+ // Skip allOf/oneOf/anyOf as it's complicated to validate it right now.
31
+ // We need core support for checking contrstrains through those keywords.
32
+ return false;
33
+ }
34
+ if (schema.format === 'binary') {
35
+ return false;
36
+ }
37
+ if (Array.isArray(schema.type)) {
38
+ return schema.type.every((t) => SCALAR_TYPES.includes(t));
39
+ }
40
+ return SCALAR_TYPES.includes(schema.type);
41
+ }
@@ -39,5 +39,8 @@ export declare const rules: {
39
39
  'request-mime-type': Oas2Rule;
40
40
  'response-mime-type': Oas2Rule;
41
41
  'path-segment-plural': Oas2Rule;
42
+ 'response-contains-header': Oas2Rule;
43
+ 'response-contains-property': Oas2Rule;
44
+ 'scalar-property-missing-example': import("../../visitors").Oas3Rule | Oas2Rule;
42
45
  };
43
46
  export declare const preprocessors: {};
@@ -39,6 +39,9 @@ const path_excludes_patterns_1 = require("../common/path-excludes-patterns");
39
39
  const request_mime_type_1 = require("./request-mime-type");
40
40
  const response_mime_type_1 = require("./response-mime-type");
41
41
  const path_segment_plural_1 = require("../common/path-segment-plural");
42
+ const response_contains_header_1 = require("../common/response-contains-header");
43
+ const response_contains_property_1 = require("./response-contains-property");
44
+ const scalar_property_missing_example_1 = require("../common/scalar-property-missing-example");
42
45
  exports.rules = {
43
46
  spec: spec_1.OasSpec,
44
47
  'no-invalid-schema-examples': no_invalid_schema_examples_1.NoInvalidSchemaExamples,
@@ -79,5 +82,8 @@ exports.rules = {
79
82
  'request-mime-type': request_mime_type_1.RequestMimeType,
80
83
  'response-mime-type': response_mime_type_1.ResponseMimeType,
81
84
  'path-segment-plural': path_segment_plural_1.PathSegmentPlural,
85
+ 'response-contains-header': response_contains_header_1.ResponseContainsHeader,
86
+ 'response-contains-property': response_contains_property_1.ResponseContainsProperty,
87
+ 'scalar-property-missing-example': scalar_property_missing_example_1.ScalarPropertyMissingExample,
82
88
  };
83
89
  exports.preprocessors = {};
@@ -0,0 +1,2 @@
1
+ import { Oas2Rule } from '../../visitors';
2
+ export declare const ResponseContainsProperty: Oas2Rule;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ResponseContainsProperty = void 0;
4
+ const utils_1 = require("../../utils");
5
+ const ResponseContainsProperty = (options) => {
6
+ const names = options.names || {};
7
+ let key;
8
+ return {
9
+ Operation: {
10
+ Response: {
11
+ skip: (_response, key) => {
12
+ return `${key}` === '204';
13
+ },
14
+ enter: (_response, ctx) => {
15
+ key = ctx.key;
16
+ },
17
+ Schema(schema, { report, location }) {
18
+ var _a;
19
+ if (schema.type !== 'object')
20
+ return;
21
+ const expectedProperties = names[key] ||
22
+ names[utils_1.getMatchingStatusCodeRange(key)] ||
23
+ names[utils_1.getMatchingStatusCodeRange(key).toLowerCase()] ||
24
+ [];
25
+ for (const expectedProperty of expectedProperties) {
26
+ if (!((_a = schema.properties) === null || _a === void 0 ? void 0 : _a[expectedProperty])) {
27
+ report({
28
+ message: `Response object must contain a top-level "${expectedProperty}" property.`,
29
+ location: location.child('properties').key(),
30
+ });
31
+ }
32
+ }
33
+ },
34
+ },
35
+ },
36
+ };
37
+ };
38
+ exports.ResponseContainsProperty = ResponseContainsProperty;
@@ -47,6 +47,9 @@ const path_segment_plural_1 = require("../common/path-segment-plural");
47
47
  const path_excludes_patterns_1 = require("../common/path-excludes-patterns");
48
48
  const no_invalid_schema_examples_1 = require("../common/no-invalid-schema-examples");
49
49
  const no_invalid_parameter_examples_1 = require("../common/no-invalid-parameter-examples");
50
+ const response_contains_header_1 = require("../common/response-contains-header");
51
+ const response_contains_property_1 = require("./response-contains-property");
52
+ const scalar_property_missing_example_1 = require("../common/scalar-property-missing-example");
50
53
  exports.rules = {
51
54
  spec: spec_1.OasSpec,
52
55
  'info-description': info_description_1.InfoDescription,
@@ -95,5 +98,8 @@ exports.rules = {
95
98
  'path-segment-plural': path_segment_plural_1.PathSegmentPlural,
96
99
  'no-invalid-schema-examples': no_invalid_schema_examples_1.NoInvalidSchemaExamples,
97
100
  'no-invalid-parameter-examples': no_invalid_parameter_examples_1.NoInvalidParameterExamples,
101
+ 'response-contains-header': response_contains_header_1.ResponseContainsHeader,
102
+ 'response-contains-property': response_contains_property_1.ResponseContainsProperty,
103
+ 'scalar-property-missing-example': scalar_property_missing_example_1.ScalarPropertyMissingExample,
98
104
  };
99
105
  exports.preprocessors = {};
@@ -0,0 +1,2 @@
1
+ import { Oas3Rule } from '../../visitors';
2
+ export declare const ResponseContainsProperty: Oas3Rule;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ResponseContainsProperty = void 0;
4
+ const utils_1 = require("../../utils");
5
+ const ResponseContainsProperty = (options) => {
6
+ const names = options.names || {};
7
+ let key;
8
+ return {
9
+ Operation: {
10
+ Response: {
11
+ skip: (_response, key) => {
12
+ return `${key}` === '204';
13
+ },
14
+ enter: (_response, ctx) => {
15
+ key = ctx.key;
16
+ },
17
+ MediaType: {
18
+ Schema(schema, { report, location }) {
19
+ var _a;
20
+ if (schema.type !== 'object')
21
+ return;
22
+ const expectedProperties = names[key] ||
23
+ names[utils_1.getMatchingStatusCodeRange(key)] ||
24
+ names[utils_1.getMatchingStatusCodeRange(key).toLowerCase()] ||
25
+ [];
26
+ for (const expectedProperty of expectedProperties) {
27
+ if (!((_a = schema.properties) === null || _a === void 0 ? void 0 : _a[expectedProperty])) {
28
+ report({
29
+ message: `Response object must contain a top-level "${expectedProperty}" property.`,
30
+ location: location.child('properties').key(),
31
+ });
32
+ }
33
+ }
34
+ },
35
+ },
36
+ },
37
+ },
38
+ };
39
+ };
40
+ exports.ResponseContainsProperty = ResponseContainsProperty;
package/lib/types/oas2.js CHANGED
@@ -80,7 +80,8 @@ const Operation = {
80
80
  deprecated: { type: 'boolean' },
81
81
  security: _1.listOf('SecurityRequirement'),
82
82
  'x-codeSamples': _1.listOf('XCodeSample'),
83
- 'x-code-samples': _1.listOf('XCodeSample'), // deprecated
83
+ 'x-code-samples': _1.listOf('XCodeSample'),
84
+ 'x-hideTryItPanel': { type: 'boolean' },
84
85
  },
85
86
  required: ['responses'],
86
87
  };
@@ -275,6 +276,7 @@ const Schema = {
275
276
  xml: 'Xml',
276
277
  externalDocs: 'ExternalDocs',
277
278
  example: { isExample: true },
279
+ 'x-tags': { type: 'array', items: { type: 'string' } },
278
280
  },
279
281
  };
280
282
  const SchemaProperties = {