@redocly/openapi-core 1.5.0 → 1.6.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @redocly/openapi-core
2
2
 
3
+ ## 1.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Added the ability to use `$ref` in the Redocly config file. This ability allows users to split up big config files and maintain their constituent parts independently.
8
+
3
9
  ## 1.5.0
4
10
 
5
11
  ### Minor Changes
package/lib/bundle.d.ts CHANGED
@@ -1,9 +1,10 @@
1
- import { BaseResolver, Document } from './resolve';
2
- import { Oas3Rule } from './visitors';
3
- import { NormalizedNodeType, NodeType } from './types';
4
- import { NormalizedProblem } from './walk';
1
+ import { BaseResolver } from './resolve';
5
2
  import { SpecMajorVersion } from './oas-types';
3
+ import type { Oas3Rule } from './visitors';
4
+ import type { NormalizedNodeType, NodeType } from './types';
5
+ import type { NormalizedProblem } from './walk';
6
6
  import type { Config, StyleguideConfig } from './config';
7
+ import type { Document, ResolvedRefMap } from './resolve';
7
8
  export type Oas3RuleSet = Record<string, Oas3Rule>;
8
9
  export declare enum OasVersion {
9
10
  Version2 = "oas2",
@@ -14,11 +15,12 @@ export type BundleOptions = {
14
15
  externalRefResolver?: BaseResolver;
15
16
  config: Config;
16
17
  dereference?: boolean;
17
- base?: string;
18
+ base?: string | null;
18
19
  skipRedoclyRegistryRefs?: boolean;
19
20
  removeUnusedComponents?: boolean;
20
21
  keepUrlRefs?: boolean;
21
22
  };
23
+ export declare function bundleConfig(document: Document, resolvedRefMap: ResolvedRefMap): Promise<any>;
22
24
  export declare function bundle(opts: {
23
25
  ref?: string;
24
26
  doc?: Document;
@@ -45,4 +47,4 @@ export declare function bundleDocument(opts: {
45
47
  removeUnusedComponents?: boolean;
46
48
  keepUrlRefs?: boolean;
47
49
  }): Promise<BundleResult>;
48
- export declare function mapTypeToComponent(typeName: string, version: SpecMajorVersion): "responses" | "links" | "parameters" | "examples" | "headers" | "schemas" | "requestBodies" | "securitySchemes" | "callbacks" | "definitions" | null;
50
+ export declare function mapTypeToComponent(typeName: string, version: SpecMajorVersion): "responses" | "parameters" | "examples" | "headers" | "schemas" | "requestBodies" | "securitySchemes" | "links" | "callbacks" | "definitions" | null;
package/lib/bundle.js CHANGED
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.mapTypeToComponent = exports.bundleDocument = exports.bundleFromString = exports.bundle = exports.OasVersion = void 0;
12
+ exports.mapTypeToComponent = exports.bundleDocument = exports.bundleFromString = exports.bundle = exports.bundleConfig = exports.OasVersion = void 0;
13
13
  const isEqual = require("lodash.isequal");
14
14
  const resolve_1 = require("./resolve");
15
15
  const visitors_1 = require("./visitors");
@@ -23,12 +23,47 @@ const utils_1 = require("./utils");
23
23
  const redocly_1 = require("./redocly");
24
24
  const remove_unused_components_1 = require("./decorators/oas2/remove-unused-components");
25
25
  const remove_unused_components_2 = require("./decorators/oas3/remove-unused-components");
26
+ const redocly_yaml_1 = require("./types/redocly-yaml");
26
27
  var OasVersion;
27
28
  (function (OasVersion) {
28
29
  OasVersion["Version2"] = "oas2";
29
30
  OasVersion["Version3_0"] = "oas3_0";
30
31
  OasVersion["Version3_1"] = "oas3_1";
31
32
  })(OasVersion || (exports.OasVersion = OasVersion = {}));
33
+ function bundleConfig(document, resolvedRefMap) {
34
+ var _a;
35
+ return __awaiter(this, void 0, void 0, function* () {
36
+ const types = (0, types_1.normalizeTypes)(redocly_yaml_1.ConfigTypes);
37
+ const ctx = {
38
+ problems: [],
39
+ oasVersion: oas_types_1.SpecVersion.OAS3_0,
40
+ refTypes: new Map(),
41
+ visitorsData: {},
42
+ };
43
+ const bundleVisitor = (0, visitors_1.normalizeVisitors)([
44
+ {
45
+ severity: 'error',
46
+ ruleId: 'configBundler',
47
+ visitor: {
48
+ ref: {
49
+ leave(node, ctx, resolved) {
50
+ replaceRef(node, resolved, ctx);
51
+ },
52
+ },
53
+ },
54
+ },
55
+ ], types);
56
+ (0, walk_1.walkDocument)({
57
+ document,
58
+ rootType: types.ConfigRoot,
59
+ normalizedVisitors: bundleVisitor,
60
+ resolvedRefMap,
61
+ ctx,
62
+ });
63
+ return (_a = document.parsed) !== null && _a !== void 0 ? _a : {};
64
+ });
65
+ }
66
+ exports.bundleConfig = bundleConfig;
32
67
  function bundle(opts) {
33
68
  return __awaiter(this, void 0, void 0, function* () {
34
69
  const { ref, doc, externalRefResolver = new resolve_1.BaseResolver(opts.config.resolve), base = null, } = opts;
@@ -169,6 +204,18 @@ function mapTypeToComponent(typeName, version) {
169
204
  }
170
205
  }
171
206
  exports.mapTypeToComponent = mapTypeToComponent;
207
+ function replaceRef(ref, resolved, ctx) {
208
+ if (!(0, utils_1.isPlainObject)(resolved.node)) {
209
+ ctx.parent[ctx.key] = resolved.node;
210
+ }
211
+ else {
212
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
213
+ // @ts-ignore
214
+ delete ref.$ref;
215
+ const obj = Object.assign({}, resolved.node, ref);
216
+ Object.assign(ref, obj); // assign ref itself again so ref fields take precedence
217
+ }
218
+ }
172
219
  // function oas3Move
173
220
  function makeBundleVisitor(version, dereference, skipRedoclyRegistryRefs, rootDocument, resolvedRefMap, keepUrlRefs) {
174
221
  let components;
@@ -252,19 +299,6 @@ function makeBundleVisitor(version, dereference, skipRedoclyRegistryRefs, rootDo
252
299
  resolved: true,
253
300
  });
254
301
  }
255
- function replaceRef(ref, resolved, ctx) {
256
- if (!(0, utils_1.isPlainObject)(resolved.node)) {
257
- ctx.parent[ctx.key] = resolved.node;
258
- }
259
- else {
260
- // TODO: why $ref isn't optional in OasRef?
261
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
262
- // @ts-ignore
263
- delete ref.$ref;
264
- const obj = Object.assign({}, resolved.node, ref);
265
- Object.assign(ref, obj); // assign ref itself again so ref fields take precedence
266
- }
267
- }
268
302
  function saveComponent(componentType, target, ctx) {
269
303
  components[componentType] = components[componentType] || {};
270
304
  const name = getComponentName(target, componentType, ctx);
@@ -1,6 +1,14 @@
1
1
  import { BaseResolver } from '../resolve';
2
- import type { StyleguideRawConfig, Plugin, RawConfig, ResolvedApi, ResolvedStyleguideConfig } from './types';
3
2
  import { Config } from './config';
3
+ import type { StyleguideRawConfig, Plugin, RawConfig, ResolvedApi, ResolvedStyleguideConfig } from './types';
4
+ import type { BundleOptions } from '../bundle';
5
+ import type { Document, ResolvedRefMap } from '../resolve';
6
+ export declare function resolveConfigFileAndRefs({ configPath, externalRefResolver, base, }: Omit<BundleOptions, 'config'> & {
7
+ configPath?: string;
8
+ }): Promise<{
9
+ document: Document;
10
+ resolvedRefMap: ResolvedRefMap;
11
+ }>;
4
12
  export declare function resolveConfig(rawConfig: RawConfig, configPath?: string): Promise<Config>;
5
13
  export declare function resolvePlugins(plugins: (string | Plugin)[] | null, configPath?: string): Plugin[];
6
14
  export declare function resolveApis({ rawConfig, configPath, resolver, }: {
@@ -20,7 +20,7 @@ var __rest = (this && this.__rest) || function (s, e) {
20
20
  return t;
21
21
  };
22
22
  Object.defineProperty(exports, "__esModule", { value: true });
23
- exports.resolvePreset = exports.resolveStyleguideConfig = exports.resolveApis = exports.resolvePlugins = exports.resolveConfig = void 0;
23
+ exports.resolvePreset = exports.resolveStyleguideConfig = exports.resolveApis = exports.resolvePlugins = exports.resolveConfig = exports.resolveConfigFileAndRefs = void 0;
24
24
  const path = require("path");
25
25
  const ref_utils_1 = require("../ref-utils");
26
26
  const utils_1 = require("../utils");
@@ -32,6 +32,27 @@ const utils_3 = require("../utils");
32
32
  const config_1 = require("./config");
33
33
  const logger_1 = require("../logger");
34
34
  const asserts_1 = require("../rules/common/assertions/asserts");
35
+ const types_1 = require("../types");
36
+ const redocly_yaml_1 = require("../types/redocly-yaml");
37
+ function resolveConfigFileAndRefs({ configPath, externalRefResolver = new resolve_1.BaseResolver(), base = null, }) {
38
+ return __awaiter(this, void 0, void 0, function* () {
39
+ if (!configPath) {
40
+ throw new Error('Reference to a config is required.\n');
41
+ }
42
+ const document = yield externalRefResolver.resolveDocument(base, configPath, true);
43
+ if (document instanceof Error) {
44
+ throw document;
45
+ }
46
+ const types = (0, types_1.normalizeTypes)(redocly_yaml_1.ConfigTypes);
47
+ const resolvedRefMap = yield (0, resolve_1.resolveDocument)({
48
+ rootDocument: document,
49
+ rootType: types.ConfigRoot,
50
+ externalRefResolver,
51
+ });
52
+ return { document, resolvedRefMap };
53
+ });
54
+ }
55
+ exports.resolveConfigFileAndRefs = resolveConfigFileAndRefs;
35
56
  function resolveConfig(rawConfig, configPath) {
36
57
  var _a, _b;
37
58
  return __awaiter(this, void 0, void 0, function* () {
@@ -1,16 +1,24 @@
1
1
  import { Config } from './config';
2
+ import type { Document } from '../resolve';
3
+ import type { RegionalTokenWithValidity } from '../redocly/redocly-client-types';
2
4
  import type { RawConfig, RawUniversalConfig, Region } from './types';
3
- import { RegionalTokenWithValidity } from '../redocly/redocly-client-types';
5
+ import type { BaseResolver, ResolvedRefMap } from '../resolve';
6
+ export type RawConfigProcessor = (rawConfig: Document, resolvedRefMap: ResolvedRefMap) => void | Promise<void>;
4
7
  export declare function loadConfig(options?: {
5
8
  configPath?: string;
6
9
  customExtends?: string[];
7
- processRawConfig?: (rawConfig: RawConfig) => void | Promise<void>;
10
+ processRawConfig?: RawConfigProcessor;
11
+ externalRefResolver?: BaseResolver;
8
12
  files?: string[];
9
13
  region?: Region;
10
14
  }): Promise<Config>;
11
15
  export declare const CONFIG_FILE_NAMES: string[];
12
16
  export declare function findConfig(dir?: string): string | undefined;
13
- export declare function getConfig(configPath?: string | undefined, processRawConfig?: (rawConfig: RawConfig) => void | Promise<void>): Promise<RawConfig>;
17
+ export declare function getConfig(options?: {
18
+ configPath?: string;
19
+ processRawConfig?: RawConfigProcessor;
20
+ externalRefResolver?: BaseResolver;
21
+ }): Promise<RawConfig>;
14
22
  type CreateConfigOptions = {
15
23
  extends?: string[];
16
24
  tokens?: RegionalTokenWithValidity[];
@@ -18,6 +18,7 @@ const js_yaml_1 = require("../js-yaml");
18
18
  const config_1 = require("./config");
19
19
  const utils_2 = require("./utils");
20
20
  const config_resolvers_1 = require("./config-resolvers");
21
+ const bundle_1 = require("../bundle");
21
22
  function addConfigMetadata({ rawConfig, customExtends, configPath, tokens, files, region, }) {
22
23
  var _a;
23
24
  return __awaiter(this, void 0, void 0, function* () {
@@ -60,8 +61,8 @@ function addConfigMetadata({ rawConfig, customExtends, configPath, tokens, files
60
61
  }
61
62
  function loadConfig(options = {}) {
62
63
  return __awaiter(this, void 0, void 0, function* () {
63
- const { configPath = findConfig(), customExtends, processRawConfig, files, region } = options;
64
- const rawConfig = yield getConfig(configPath, processRawConfig);
64
+ const { configPath = findConfig(), customExtends, processRawConfig, files, region, externalRefResolver, } = options;
65
+ const rawConfig = yield getConfig({ configPath, processRawConfig, externalRefResolver });
65
66
  const redoclyClient = new redocly_1.RedoclyClient();
66
67
  const tokens = yield redoclyClient.getTokens();
67
68
  return addConfigMetadata({
@@ -90,16 +91,21 @@ function findConfig(dir) {
90
91
  return existingConfigFiles[0];
91
92
  }
92
93
  exports.findConfig = findConfig;
93
- function getConfig(configPath = findConfig(), processRawConfig) {
94
+ function getConfig(options = {}) {
94
95
  return __awaiter(this, void 0, void 0, function* () {
96
+ const { configPath = findConfig(), processRawConfig, externalRefResolver } = options;
95
97
  if (!configPath || !(0, utils_1.doesYamlFileExist)(configPath))
96
98
  return {};
97
99
  try {
98
- const rawConfig = (yield (0, utils_1.loadYaml)(configPath)) || {};
100
+ const { document, resolvedRefMap } = yield (0, config_resolvers_1.resolveConfigFileAndRefs)({
101
+ configPath,
102
+ externalRefResolver,
103
+ });
99
104
  if (typeof processRawConfig === 'function') {
100
- yield processRawConfig(rawConfig);
105
+ yield processRawConfig(document, resolvedRefMap);
101
106
  }
102
- return (0, utils_2.transformConfig)(rawConfig);
107
+ const bundledConfig = yield (0, bundle_1.bundleConfig)(document, resolvedRefMap);
108
+ return (0, utils_2.transformConfig)(bundledConfig);
103
109
  }
104
110
  catch (e) {
105
111
  if (e instanceof utils_2.ConfigValidationError) {
package/lib/lint.d.ts CHANGED
@@ -1,7 +1,8 @@
1
- import { BaseResolver, Document } from './resolve';
2
- import { NodeType } from './types';
3
- import { ProblemSeverity } from './walk';
1
+ import { BaseResolver } from './resolve';
4
2
  import { StyleguideConfig, Config } from './config';
3
+ import type { Document, ResolvedRefMap } from './resolve';
4
+ import type { ProblemSeverity } from './walk';
5
+ import type { NodeType } from './types';
5
6
  export declare function lint(opts: {
6
7
  ref: string;
7
8
  config: Config;
@@ -21,5 +22,7 @@ export declare function lintDocument(opts: {
21
22
  }): Promise<import("./walk").NormalizedProblem[]>;
22
23
  export declare function lintConfig(opts: {
23
24
  document: Document;
25
+ resolvedRefMap?: ResolvedRefMap;
24
26
  severity?: ProblemSeverity;
27
+ externalRefResolver?: BaseResolver;
25
28
  }): Promise<import("./walk").NormalizedProblem[]>;
package/lib/lint.js CHANGED
@@ -19,6 +19,7 @@ const ajv_1 = require("./rules/ajv");
19
19
  const oas_types_1 = require("./oas-types");
20
20
  const redocly_yaml_1 = require("./types/redocly-yaml");
21
21
  const spec_1 = require("./rules/common/spec");
22
+ const no_unresolved_refs_1 = require("./rules/no-unresolved-refs");
22
23
  function lint(opts) {
23
24
  return __awaiter(this, void 0, void 0, function* () {
24
25
  const { ref, externalRefResolver = new resolve_1.BaseResolver(opts.config.resolve) } = opts;
@@ -84,7 +85,7 @@ function lintDocument(opts) {
84
85
  exports.lintDocument = lintDocument;
85
86
  function lintConfig(opts) {
86
87
  return __awaiter(this, void 0, void 0, function* () {
87
- const { document, severity } = opts;
88
+ const { document, severity, externalRefResolver = new resolve_1.BaseResolver() } = opts;
88
89
  const ctx = {
89
90
  problems: [],
90
91
  oasVersion: oas_types_1.SpecVersion.OAS3_0,
@@ -102,14 +103,24 @@ function lintConfig(opts) {
102
103
  ruleId: 'configuration spec',
103
104
  visitor: (0, spec_1.Spec)({ severity: 'error' }),
104
105
  },
106
+ {
107
+ severity: severity || 'error',
108
+ ruleId: 'configuration no-unresolved-refs',
109
+ visitor: (0, no_unresolved_refs_1.NoUnresolvedRefs)({ severity: 'error' }),
110
+ },
105
111
  ];
106
- // TODO: check why any is needed
107
112
  const normalizedVisitors = (0, visitors_1.normalizeVisitors)(rules, types);
113
+ const resolvedRefMap = opts.resolvedRefMap ||
114
+ (yield (0, resolve_1.resolveDocument)({
115
+ rootDocument: document,
116
+ rootType: types.ConfigRoot,
117
+ externalRefResolver,
118
+ }));
108
119
  (0, walk_1.walkDocument)({
109
120
  document,
110
121
  rootType: types.ConfigRoot,
111
122
  normalizedVisitors,
112
- resolvedRefMap: new Map(),
123
+ resolvedRefMap,
113
124
  ctx,
114
125
  });
115
126
  return ctx.problems;