@redocly/openapi-core 1.23.1 → 1.25.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 +18 -0
- package/lib/config/all.js +3 -0
- package/lib/config/config-resolvers.d.ts +1 -1
- package/lib/config/config-resolvers.js +42 -26
- package/lib/config/config.js +4 -1
- package/lib/config/minimal.js +3 -0
- package/lib/config/recommended-strict.js +3 -0
- package/lib/config/recommended.js +3 -0
- package/lib/config/types.d.ts +10 -0
- package/lib/rules/arazzo/criteria-unique.d.ts +2 -0
- package/lib/rules/arazzo/criteria-unique.js +65 -0
- package/lib/rules/arazzo/index.js +6 -0
- package/lib/rules/spot/no-actions-type-end.d.ts +2 -0
- package/lib/rules/spot/no-actions-type-end.js +28 -0
- package/lib/rules/spot/no-criteria-xpath.d.ts +2 -0
- package/lib/rules/spot/no-criteria-xpath.js +21 -0
- package/lib/types/arazzo.js +1 -1
- package/lib/types/redocly-yaml.d.ts +1 -1
- package/lib/types/redocly-yaml.js +3 -0
- package/package.json +2 -2
- package/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap +6 -0
- package/src/config/__tests__/config-resolvers.test.ts +54 -0
- package/src/config/__tests__/fixtures/resolve-config/local-config-with-plugin-init.yaml +2 -0
- package/src/config/__tests__/fixtures/resolve-config/local-config-with-realm-plugin.yaml +2 -0
- package/src/config/__tests__/fixtures/resolve-config/plugin-with-init-logic.js +9 -0
- package/src/config/__tests__/fixtures/resolve-config/realm-plugin.js +12 -0
- package/src/config/all.ts +3 -0
- package/src/config/config-resolvers.ts +52 -29
- package/src/config/config.ts +4 -1
- package/src/config/minimal.ts +3 -0
- package/src/config/recommended-strict.ts +3 -0
- package/src/config/recommended.ts +3 -0
- package/src/config/types.ts +16 -0
- package/src/rules/arazzo/__tests__/criteria-unique.test.ts +161 -0
- package/src/rules/arazzo/__tests__/no-actions-type-end.test.ts +122 -0
- package/src/rules/arazzo/__tests__/no-criteria-xpath.test.ts +127 -0
- package/src/rules/arazzo/criteria-unique.ts +63 -0
- package/src/rules/arazzo/index.ts +6 -0
- package/src/rules/spot/no-actions-type-end.ts +27 -0
- package/src/rules/spot/no-criteria-xpath.ts +20 -0
- package/src/types/arazzo.ts +1 -1
- package/src/types/redocly-yaml.ts +3 -0
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @redocly/openapi-core
|
|
2
2
|
|
|
3
|
+
## 1.25.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Added a mechanism that resolves plugin properties specific to the Reunite-hosted product family.
|
|
8
|
+
- Added a cache for resolved plugins to ensure that plugins are only instantiated once during a single execution.
|
|
9
|
+
|
|
10
|
+
## 1.24.0
|
|
11
|
+
|
|
12
|
+
### Minor Changes
|
|
13
|
+
|
|
14
|
+
- Added Spot and Arazzo rules: `no-criteria-xpath`, `no-actions-type-end`, `criteria-unique`.
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- Updated @redocly/ajv to v8.11.2.
|
|
19
|
+
- Fixed an issue where custom rules were not applied to Arazzo descriptions.
|
|
20
|
+
|
|
3
21
|
## 1.23.1
|
|
4
22
|
|
|
5
23
|
## 1.23.0
|
package/lib/config/all.js
CHANGED
|
@@ -139,6 +139,9 @@ const all = {
|
|
|
139
139
|
'step-onSuccess-unique': 'error',
|
|
140
140
|
'step-onFailure-unique': 'error',
|
|
141
141
|
'requestBody-replacements-unique': 'error',
|
|
142
|
+
'no-criteria-xpath': 'error',
|
|
143
|
+
'no-actions-type-end': 'error',
|
|
144
|
+
'criteria-unique': 'error',
|
|
142
145
|
},
|
|
143
146
|
};
|
|
144
147
|
exports.default = all;
|
|
@@ -14,7 +14,7 @@ export declare function resolveConfig({ rawConfig, configPath, externalRefResolv
|
|
|
14
14
|
configPath?: string;
|
|
15
15
|
externalRefResolver?: BaseResolver;
|
|
16
16
|
}): Promise<Config>;
|
|
17
|
-
export declare function resolvePlugins(plugins: (string | Plugin)[] | null,
|
|
17
|
+
export declare function resolvePlugins(plugins: (string | Plugin)[] | null, configDir?: string): Promise<Plugin[]>;
|
|
18
18
|
export declare function resolveApis({ rawConfig, configPath, resolver, }: {
|
|
19
19
|
rawConfig: RawConfig;
|
|
20
20
|
configPath?: string;
|
|
@@ -23,6 +23,8 @@ const redocly_yaml_1 = require("../types/redocly-yaml");
|
|
|
23
23
|
const DEFAULT_PROJECT_PLUGIN_PATHS = ['@theme/plugin.js', '@theme/plugin.cjs', '@theme/plugin.mjs'];
|
|
24
24
|
// Workaround for dynamic imports being transpiled to require by Typescript: https://github.com/microsoft/TypeScript/issues/43329#issuecomment-811606238
|
|
25
25
|
const _importDynamic = new Function('modulePath', 'return import(modulePath)');
|
|
26
|
+
// Cache instantiated plugins during a single execution
|
|
27
|
+
const pluginsCache = new Map();
|
|
26
28
|
async function resolveConfigFileAndRefs({ configPath, externalRefResolver = new resolve_1.BaseResolver(), base = null, }) {
|
|
27
29
|
if (!configPath) {
|
|
28
30
|
throw new Error('Reference to a config is required.\n');
|
|
@@ -60,39 +62,59 @@ async function resolveConfig({ rawConfig, configPath, externalRefResolver, }) {
|
|
|
60
62
|
styleguide,
|
|
61
63
|
}, configPath);
|
|
62
64
|
}
|
|
63
|
-
function getDefaultPluginPath(
|
|
65
|
+
function getDefaultPluginPath(configDir) {
|
|
64
66
|
for (const pluginPath of DEFAULT_PROJECT_PLUGIN_PATHS) {
|
|
65
|
-
const absolutePluginPath = path.resolve(
|
|
67
|
+
const absolutePluginPath = path.resolve(configDir, pluginPath);
|
|
66
68
|
if ((0, fs_1.existsSync)(absolutePluginPath)) {
|
|
67
69
|
return pluginPath;
|
|
68
70
|
}
|
|
69
71
|
}
|
|
70
72
|
return;
|
|
71
73
|
}
|
|
72
|
-
async function resolvePlugins(plugins,
|
|
74
|
+
async function resolvePlugins(plugins, configDir = '') {
|
|
73
75
|
if (!plugins)
|
|
74
76
|
return [];
|
|
75
77
|
// TODO: implement or reuse Resolver approach so it will work in node and browser envs
|
|
76
78
|
const requireFunc = async (plugin) => {
|
|
77
79
|
if ((0, utils_1.isString)(plugin)) {
|
|
78
80
|
try {
|
|
79
|
-
const maybeAbsolutePluginPath = path.resolve(
|
|
81
|
+
const maybeAbsolutePluginPath = path.resolve(configDir, plugin);
|
|
80
82
|
const absolutePluginPath = (0, fs_1.existsSync)(maybeAbsolutePluginPath)
|
|
81
83
|
? maybeAbsolutePluginPath
|
|
82
84
|
: // For plugins imported from packages specifically
|
|
83
85
|
require.resolve(plugin);
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (typeof __webpack_require__ === 'function') {
|
|
86
|
+
if (!pluginsCache.has(absolutePluginPath)) {
|
|
87
|
+
let requiredPlugin;
|
|
87
88
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
88
89
|
// @ts-ignore
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
90
|
+
if (typeof __webpack_require__ === 'function') {
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
92
|
+
// @ts-ignore
|
|
93
|
+
requiredPlugin = __non_webpack_require__(absolutePluginPath);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
// you can import both cjs and mjs
|
|
97
|
+
const mod = await _importDynamic((0, url_1.pathToFileURL)(absolutePluginPath).href);
|
|
98
|
+
requiredPlugin = mod.default || mod;
|
|
99
|
+
}
|
|
100
|
+
const pluginCreatorOptions = { contentDir: configDir };
|
|
101
|
+
const pluginModule = (0, utils_2.isDeprecatedPluginFormat)(requiredPlugin)
|
|
102
|
+
? requiredPlugin
|
|
103
|
+
: (0, utils_2.isCommonJsPlugin)(requiredPlugin)
|
|
104
|
+
? await requiredPlugin(pluginCreatorOptions)
|
|
105
|
+
: await requiredPlugin?.default?.(pluginCreatorOptions);
|
|
106
|
+
if (pluginModule?.id && (0, utils_2.isDeprecatedPluginFormat)(requiredPlugin)) {
|
|
107
|
+
logger_1.logger.info(`Deprecated plugin format detected: ${pluginModule.id}\n`);
|
|
108
|
+
}
|
|
109
|
+
if (pluginModule) {
|
|
110
|
+
pluginsCache.set(absolutePluginPath, {
|
|
111
|
+
...pluginModule,
|
|
112
|
+
path: plugin,
|
|
113
|
+
absolutePath: absolutePluginPath,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
95
116
|
}
|
|
117
|
+
return pluginsCache.get(absolutePluginPath);
|
|
96
118
|
}
|
|
97
119
|
catch (e) {
|
|
98
120
|
throw new Error(`Failed to load plugin "${plugin}": ${e.message}\n\n${e.stack}`);
|
|
@@ -104,7 +126,7 @@ async function resolvePlugins(plugins, configPath = '') {
|
|
|
104
126
|
/**
|
|
105
127
|
* Include the default plugin automatically if it's not in configuration
|
|
106
128
|
*/
|
|
107
|
-
const defaultPluginPath = getDefaultPluginPath(
|
|
129
|
+
const defaultPluginPath = getDefaultPluginPath(configDir);
|
|
108
130
|
if (defaultPluginPath) {
|
|
109
131
|
plugins.push(defaultPluginPath);
|
|
110
132
|
}
|
|
@@ -119,19 +141,10 @@ async function resolvePlugins(plugins, configPath = '') {
|
|
|
119
141
|
}
|
|
120
142
|
resolvedPlugins.add(p);
|
|
121
143
|
}
|
|
122
|
-
const
|
|
123
|
-
const pluginCreatorOptions = { contentDir: path.dirname(configPath) };
|
|
124
|
-
const pluginModule = (0, utils_2.isDeprecatedPluginFormat)(requiredPlugin)
|
|
125
|
-
? requiredPlugin
|
|
126
|
-
: (0, utils_2.isCommonJsPlugin)(requiredPlugin)
|
|
127
|
-
? await requiredPlugin(pluginCreatorOptions)
|
|
128
|
-
: await requiredPlugin?.default?.(pluginCreatorOptions);
|
|
144
|
+
const pluginModule = await requireFunc(p);
|
|
129
145
|
if (!pluginModule) {
|
|
130
146
|
return;
|
|
131
147
|
}
|
|
132
|
-
if ((0, utils_1.isString)(p) && pluginModule.id && (0, utils_2.isDeprecatedPluginFormat)(requiredPlugin)) {
|
|
133
|
-
logger_1.logger.info(`Deprecated plugin format detected: ${pluginModule.id}\n`);
|
|
134
|
-
}
|
|
135
148
|
const id = pluginModule.id;
|
|
136
149
|
if (typeof id !== 'string') {
|
|
137
150
|
throw new Error(logger_1.colorize.red(`Plugin must define \`id\` property in ${logger_1.colorize.blue(p.toString())}.`));
|
|
@@ -220,7 +233,10 @@ async function resolvePlugins(plugins, configPath = '') {
|
|
|
220
233
|
if (pluginModule.assertions) {
|
|
221
234
|
plugin.assertions = pluginModule.assertions;
|
|
222
235
|
}
|
|
223
|
-
return
|
|
236
|
+
return {
|
|
237
|
+
...pluginModule,
|
|
238
|
+
...plugin,
|
|
239
|
+
};
|
|
224
240
|
}));
|
|
225
241
|
return instances.filter(utils_1.isDefined);
|
|
226
242
|
}
|
|
@@ -248,7 +264,7 @@ async function resolveAndMergeNestedStyleguideConfig({ styleguideConfig, configP
|
|
|
248
264
|
const plugins = env_1.isBrowser
|
|
249
265
|
? // In browser, we don't support plugins from config file yet
|
|
250
266
|
[builtIn_1.defaultPlugin]
|
|
251
|
-
: (0, utils_2.getUniquePlugins)(await resolvePlugins([...(styleguideConfig?.plugins || []), builtIn_1.defaultPlugin], configPath));
|
|
267
|
+
: (0, utils_2.getUniquePlugins)(await resolvePlugins([...(styleguideConfig?.plugins || []), builtIn_1.defaultPlugin], path.dirname(configPath)));
|
|
252
268
|
const pluginPaths = styleguideConfig?.plugins
|
|
253
269
|
?.filter(utils_1.isString)
|
|
254
270
|
.map((p) => path.resolve(path.dirname(configPath), p));
|
package/lib/config/config.js
CHANGED
|
@@ -38,7 +38,10 @@ class StyleguideConfig {
|
|
|
38
38
|
[oas_types_1.SpecVersion.OAS3_1]: { ...rawConfig.rules, ...rawConfig.oas3_1Rules },
|
|
39
39
|
[oas_types_1.SpecVersion.Async2]: { ...rawConfig.rules, ...rawConfig.async2Rules },
|
|
40
40
|
[oas_types_1.SpecVersion.Async3]: { ...rawConfig.rules, ...rawConfig.async3Rules },
|
|
41
|
-
[oas_types_1.SpecVersion.Arazzo]: {
|
|
41
|
+
[oas_types_1.SpecVersion.Arazzo]: {
|
|
42
|
+
...rawConfig.arazzoRules,
|
|
43
|
+
...(rawConfig.rules?.assertions ? { assertions: rawConfig.rules.assertions } : {}),
|
|
44
|
+
},
|
|
42
45
|
};
|
|
43
46
|
this.preprocessors = {
|
|
44
47
|
[oas_types_1.SpecVersion.OAS2]: { ...rawConfig.preprocessors, ...rawConfig.oas2Preprocessors },
|
package/lib/config/minimal.js
CHANGED
|
@@ -121,6 +121,9 @@ const minimal = {
|
|
|
121
121
|
'step-onSuccess-unique': 'off',
|
|
122
122
|
'step-onFailure-unique': 'off',
|
|
123
123
|
'requestBody-replacements-unique': 'off',
|
|
124
|
+
'no-criteria-xpath': 'off',
|
|
125
|
+
'no-actions-type-end': 'off',
|
|
126
|
+
'criteria-unique': 'off',
|
|
124
127
|
},
|
|
125
128
|
};
|
|
126
129
|
exports.default = minimal;
|
|
@@ -121,6 +121,9 @@ const recommendedStrict = {
|
|
|
121
121
|
'step-onSuccess-unique': 'error',
|
|
122
122
|
'step-onFailure-unique': 'error',
|
|
123
123
|
'requestBody-replacements-unique': 'error',
|
|
124
|
+
'no-criteria-xpath': 'error',
|
|
125
|
+
'no-actions-type-end': 'error',
|
|
126
|
+
'criteria-unique': 'error',
|
|
124
127
|
},
|
|
125
128
|
};
|
|
126
129
|
exports.default = recommendedStrict;
|
|
@@ -121,6 +121,9 @@ const recommended = {
|
|
|
121
121
|
'step-onSuccess-unique': 'warn',
|
|
122
122
|
'step-onFailure-unique': 'warn',
|
|
123
123
|
'requestBody-replacements-unique': 'warn',
|
|
124
|
+
'no-criteria-xpath': 'warn',
|
|
125
|
+
'no-actions-type-end': 'warn',
|
|
126
|
+
'criteria-unique': 'warn',
|
|
124
127
|
},
|
|
125
128
|
};
|
|
126
129
|
exports.default = recommended;
|
package/lib/config/types.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { Oas3PreprocessorsSet, SpecMajorVersion, Oas3DecoratorsSet, Oas2Rul
|
|
|
4
4
|
import type { NodeType } from '../types';
|
|
5
5
|
import type { SkipFunctionContext } from '../visitors';
|
|
6
6
|
import type { BuiltInAsync2RuleId, BuiltInAsync3RuleId, BuiltInCommonOASRuleId, BuiltInOAS2RuleId, BuiltInOAS3RuleId, BuiltInArazzoRuleId } from '../types/redocly-yaml';
|
|
7
|
+
import type { JSONSchema } from 'json-schema-to-ts';
|
|
7
8
|
export type RuleSeverity = ProblemSeverity | 'off';
|
|
8
9
|
export type RuleSettings = {
|
|
9
10
|
severity: RuleSeverity;
|
|
@@ -91,6 +92,15 @@ export type Plugin = {
|
|
|
91
92
|
decorators?: DecoratorsConfig;
|
|
92
93
|
typeExtension?: TypeExtensionsConfig;
|
|
93
94
|
assertions?: AssertionsConfig;
|
|
95
|
+
path?: string;
|
|
96
|
+
absolutePath?: string;
|
|
97
|
+
processContent?: (actions: any, content: any) => Promise<void> | void;
|
|
98
|
+
afterRoutesCreated?: (actions: any, content: any) => Promise<void> | void;
|
|
99
|
+
loaders?: Record<string, (path: string, context: any, reportError: (error: Error) => void) => Promise<unknown>>;
|
|
100
|
+
requiredEntitlements?: string[];
|
|
101
|
+
ssoConfigSchema?: JSONSchema;
|
|
102
|
+
redoclyConfigSchema?: JSONSchema;
|
|
103
|
+
ejectIgnore?: string[];
|
|
94
104
|
};
|
|
95
105
|
type PluginCreatorOptions = {
|
|
96
106
|
contentDir: string;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CriteriaUnique = void 0;
|
|
4
|
+
const CriteriaUnique = () => {
|
|
5
|
+
return {
|
|
6
|
+
FailureActionObject: {
|
|
7
|
+
enter(action, { report, location }) {
|
|
8
|
+
const criterias = action.criteria;
|
|
9
|
+
const seen = new Set();
|
|
10
|
+
for (const criteria of criterias) {
|
|
11
|
+
const key = JSON.stringify(criteria);
|
|
12
|
+
if (seen.has(key)) {
|
|
13
|
+
report({
|
|
14
|
+
message: 'The FailureAction criteria items must be unique.',
|
|
15
|
+
location: location.child(['criteria', criterias.indexOf(criteria)]),
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
seen.add(key);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
SuccessActionObject: {
|
|
25
|
+
enter(action, { report, location }) {
|
|
26
|
+
const criterias = action.criteria;
|
|
27
|
+
const seen = new Set();
|
|
28
|
+
for (const criteria of criterias) {
|
|
29
|
+
const key = JSON.stringify(criteria);
|
|
30
|
+
if (seen.has(key)) {
|
|
31
|
+
report({
|
|
32
|
+
message: 'The SuccessAction criteria items must be unique.',
|
|
33
|
+
location: location.child(['criteria', criterias.indexOf(criteria)]),
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
seen.add(key);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
Step: {
|
|
43
|
+
enter(step, { report, location }) {
|
|
44
|
+
if (!step.successCriteria) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const successCriterias = step.successCriteria;
|
|
48
|
+
const seen = new Set();
|
|
49
|
+
for (const criteria of successCriterias) {
|
|
50
|
+
const key = JSON.stringify(criteria);
|
|
51
|
+
if (seen.has(key)) {
|
|
52
|
+
report({
|
|
53
|
+
message: 'The Step SuccessCriteria items must be unique.',
|
|
54
|
+
location: location.child(['successCriteria', successCriterias.indexOf(criteria)]),
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
seen.add(key);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
exports.CriteriaUnique = CriteriaUnique;
|
|
@@ -14,6 +14,9 @@ const parameters_unique_1 = require("./parameters-unique");
|
|
|
14
14
|
const step_onSuccess_unique_1 = require("./step-onSuccess-unique");
|
|
15
15
|
const step_onFailure_unique_1 = require("./step-onFailure-unique");
|
|
16
16
|
const requestBody_replacements_unique_1 = require("./requestBody-replacements-unique");
|
|
17
|
+
const no_criteria_xpath_1 = require("../spot/no-criteria-xpath");
|
|
18
|
+
const no_actions_type_end_1 = require("../spot/no-actions-type-end");
|
|
19
|
+
const criteria_unique_1 = require("./criteria-unique");
|
|
17
20
|
exports.rules = {
|
|
18
21
|
spec: spec_1.Spec,
|
|
19
22
|
assertions: assertions_1.Assertions,
|
|
@@ -28,5 +31,8 @@ exports.rules = {
|
|
|
28
31
|
'step-onSuccess-unique': step_onSuccess_unique_1.StepOnSuccessUnique,
|
|
29
32
|
'step-onFailure-unique': step_onFailure_unique_1.StepOnFailureUnique,
|
|
30
33
|
'requestBody-replacements-unique': requestBody_replacements_unique_1.RequestBodyReplacementsUnique,
|
|
34
|
+
'no-criteria-xpath': no_criteria_xpath_1.NoCriteriaXpath,
|
|
35
|
+
'no-actions-type-end': no_actions_type_end_1.NoActionsTypeEnd,
|
|
36
|
+
'criteria-unique': criteria_unique_1.CriteriaUnique,
|
|
31
37
|
};
|
|
32
38
|
exports.preprocessors = {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NoActionsTypeEnd = void 0;
|
|
4
|
+
const NoActionsTypeEnd = () => {
|
|
5
|
+
return {
|
|
6
|
+
FailureActionObject: {
|
|
7
|
+
enter(action, { report, location }) {
|
|
8
|
+
if (action.type === 'end') {
|
|
9
|
+
report({
|
|
10
|
+
message: 'The `end` type action is not supported by Spot.',
|
|
11
|
+
location: location.child(['type']),
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
SuccessActionObject: {
|
|
17
|
+
enter(action, { report, location }) {
|
|
18
|
+
if (action.type === 'end') {
|
|
19
|
+
report({
|
|
20
|
+
message: 'The `end` type action is not supported by Spot.',
|
|
21
|
+
location: location.child(['type']),
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
exports.NoActionsTypeEnd = NoActionsTypeEnd;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NoCriteriaXpath = void 0;
|
|
4
|
+
const NoCriteriaXpath = () => {
|
|
5
|
+
return {
|
|
6
|
+
CriterionObject: {
|
|
7
|
+
enter(criteria, { report, location }) {
|
|
8
|
+
if (!criteria.type) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
if (criteria?.type?.type === 'xpath' || criteria?.type === 'xpath') {
|
|
12
|
+
report({
|
|
13
|
+
message: 'The `xpath` type criteria is not supported by Spot.',
|
|
14
|
+
location: location.child(['type']),
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
exports.NoCriteriaXpath = NoCriteriaXpath;
|
package/lib/types/arazzo.js
CHANGED
|
@@ -212,7 +212,7 @@ const CriterionObject = {
|
|
|
212
212
|
else if (typeof value === 'string') {
|
|
213
213
|
return { enum: ['regex', 'jsonpath', 'simple', 'xpath'] };
|
|
214
214
|
}
|
|
215
|
-
else if (value
|
|
215
|
+
else if (value?.type === 'jsonpath') {
|
|
216
216
|
return 'JSONPathCriterion';
|
|
217
217
|
}
|
|
218
218
|
else {
|
|
@@ -11,7 +11,7 @@ declare const builtInAsync2Rules: readonly ["spec", "info-contact", "info-licens
|
|
|
11
11
|
declare const builtInAsync3Rules: readonly ["spec", "info-contact", "info-license-strict", "operation-operationId", "tag-description", "tags-alphabetical", "channels-kebab-case", "no-channel-trailing-slash"];
|
|
12
12
|
export type BuiltInAsync2RuleId = typeof builtInAsync2Rules[number];
|
|
13
13
|
export type BuiltInAsync3RuleId = typeof builtInAsync3Rules[number];
|
|
14
|
-
declare const builtInArazzoRules: readonly ["spec", "parameters-not-in-body", "sourceDescription-type", "version-enum", "workflowId-unique", "stepId-unique", "sourceDescription-name-unique", "workflow-dependsOn", "parameters-unique", "step-onSuccess-unique", "step-onFailure-unique", "requestBody-replacements-unique"];
|
|
14
|
+
declare const builtInArazzoRules: readonly ["spec", "parameters-not-in-body", "sourceDescription-type", "version-enum", "workflowId-unique", "stepId-unique", "sourceDescription-name-unique", "workflow-dependsOn", "parameters-unique", "step-onSuccess-unique", "step-onFailure-unique", "requestBody-replacements-unique", "no-criteria-xpath", "no-actions-type-end", "criteria-unique"];
|
|
15
15
|
export type BuiltInArazzoRuleId = typeof builtInArazzoRules[number];
|
|
16
16
|
declare const oas2NodeTypesList: readonly ["Root", "Tag", "TagList", "ExternalDocs", "SecurityRequirement", "SecurityRequirementList", "Info", "Contact", "License", "Paths", "PathItem", "Parameter", "ParameterList", "ParameterItems", "Operation", "Example", "ExamplesMap", "Examples", "Header", "Responses", "Response", "Schema", "Xml", "SchemaProperties", "NamedSchemas", "NamedResponses", "NamedParameters", "NamedSecuritySchemes", "SecurityScheme", "TagGroup", "TagGroups", "EnumDescriptions", "Logo", "XCodeSample", "XCodeSampleList", "XServer", "XServerList"];
|
|
17
17
|
export type Oas2NodeType = typeof oas2NodeTypesList[number];
|
|
@@ -106,6 +106,9 @@ const builtInArazzoRules = [
|
|
|
106
106
|
'step-onSuccess-unique',
|
|
107
107
|
'step-onFailure-unique',
|
|
108
108
|
'requestBody-replacements-unique',
|
|
109
|
+
'no-criteria-xpath',
|
|
110
|
+
'no-actions-type-end',
|
|
111
|
+
'criteria-unique',
|
|
109
112
|
];
|
|
110
113
|
const builtInRules = [
|
|
111
114
|
...builtInCommonOASRules,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redocly/openapi-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.25.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"engines": {
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"Roman Hotsiy <roman@redoc.ly> (https://redoc.ly/)"
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@redocly/ajv": "^8.11.
|
|
38
|
+
"@redocly/ajv": "^8.11.2",
|
|
39
39
|
"@redocly/config": "^0.10.1",
|
|
40
40
|
"colorette": "^1.2.0",
|
|
41
41
|
"https-proxy-agent": "^7.0.4",
|
|
@@ -5,6 +5,9 @@ exports[`resolveConfig should ignore minimal from the root and read local file 1
|
|
|
5
5
|
"arazzoDecorators": {},
|
|
6
6
|
"arazzoPreprocessors": {},
|
|
7
7
|
"arazzoRules": {
|
|
8
|
+
"criteria-unique": "warn",
|
|
9
|
+
"no-actions-type-end": "warn",
|
|
10
|
+
"no-criteria-xpath": "warn",
|
|
8
11
|
"parameters-not-in-body": "warn",
|
|
9
12
|
"parameters-unique": "error",
|
|
10
13
|
"requestBody-replacements-unique": "warn",
|
|
@@ -147,6 +150,9 @@ exports[`resolveStyleguideConfig should resolve extends with local file config w
|
|
|
147
150
|
"arazzoDecorators": {},
|
|
148
151
|
"arazzoPreprocessors": {},
|
|
149
152
|
"arazzoRules": {
|
|
153
|
+
"criteria-unique": "warn",
|
|
154
|
+
"no-actions-type-end": "warn",
|
|
155
|
+
"no-criteria-xpath": "warn",
|
|
150
156
|
"parameters-not-in-body": "warn",
|
|
151
157
|
"parameters-unique": "error",
|
|
152
158
|
"requestBody-replacements-unique": "warn",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as util from 'util';
|
|
1
2
|
import { colorize } from '../../logger';
|
|
2
3
|
import { Asserts, asserts } from '../../rules/common/assertions/asserts';
|
|
3
4
|
import { resolveStyleguideConfig, resolveApis, resolveConfig } from '../config-resolvers';
|
|
@@ -91,6 +92,59 @@ describe('resolveStyleguideConfig', () => {
|
|
|
91
92
|
});
|
|
92
93
|
});
|
|
93
94
|
|
|
95
|
+
it('should instantiate the plugin once', async () => {
|
|
96
|
+
// Called by plugin during init
|
|
97
|
+
const deprecateSpy = jest.spyOn(util, 'deprecate');
|
|
98
|
+
|
|
99
|
+
const config = {
|
|
100
|
+
...baseStyleguideConfig,
|
|
101
|
+
extends: ['local-config-with-plugin-init.yaml'],
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
await resolveStyleguideConfig({
|
|
105
|
+
styleguideConfig: config,
|
|
106
|
+
configPath,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
expect(deprecateSpy).toHaveBeenCalledTimes(1);
|
|
110
|
+
|
|
111
|
+
await resolveStyleguideConfig({
|
|
112
|
+
styleguideConfig: config,
|
|
113
|
+
configPath,
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Should not execute the init logic again
|
|
117
|
+
expect(deprecateSpy).toHaveBeenCalledTimes(1);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should resolve realm plugin properties', async () => {
|
|
121
|
+
const config = {
|
|
122
|
+
...baseStyleguideConfig,
|
|
123
|
+
extends: ['local-config-with-realm-plugin.yaml'],
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const { plugins } = await resolveStyleguideConfig({
|
|
127
|
+
styleguideConfig: config,
|
|
128
|
+
configPath,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
const localPlugin = plugins?.find((p) => p.id === 'realm-plugin');
|
|
132
|
+
expect(localPlugin).toBeDefined();
|
|
133
|
+
|
|
134
|
+
expect(localPlugin).toMatchObject({
|
|
135
|
+
id: 'realm-plugin',
|
|
136
|
+
processContent: expect.any(Function),
|
|
137
|
+
afterRoutesCreated: expect.any(Function),
|
|
138
|
+
loaders: {
|
|
139
|
+
'test-loader': expect.any(Function),
|
|
140
|
+
},
|
|
141
|
+
requiredEntitlements: ['test-entitlement'],
|
|
142
|
+
ssoConfigSchema: { type: 'object', additionalProperties: true },
|
|
143
|
+
redoclyConfigSchema: { type: 'object', additionalProperties: false },
|
|
144
|
+
ejectIgnore: ['Navbar.tsx', 'Footer.tsx'],
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
94
148
|
it('should resolve local file config with esm plugin', async () => {
|
|
95
149
|
const config = {
|
|
96
150
|
...baseStyleguideConfig,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module.exports = function realmPlugin() {
|
|
2
|
+
return {
|
|
3
|
+
id: 'realm-plugin',
|
|
4
|
+
processContent: () => {},
|
|
5
|
+
afterRoutesCreated: () => {},
|
|
6
|
+
loaders: { 'test-loader': () => {} },
|
|
7
|
+
requiredEntitlements: ['test-entitlement'],
|
|
8
|
+
ssoConfigSchema: { type: 'object', additionalProperties: true },
|
|
9
|
+
redoclyConfigSchema: { type: 'object', additionalProperties: false },
|
|
10
|
+
ejectIgnore: ['Navbar.tsx', 'Footer.tsx'],
|
|
11
|
+
};
|
|
12
|
+
};
|
package/src/config/all.ts
CHANGED
|
@@ -139,6 +139,9 @@ const all: PluginStyleguideConfig<'built-in'> = {
|
|
|
139
139
|
'step-onSuccess-unique': 'error',
|
|
140
140
|
'step-onFailure-unique': 'error',
|
|
141
141
|
'requestBody-replacements-unique': 'error',
|
|
142
|
+
'no-criteria-xpath': 'error',
|
|
143
|
+
'no-actions-type-end': 'error',
|
|
144
|
+
'criteria-unique': 'error',
|
|
142
145
|
},
|
|
143
146
|
};
|
|
144
147
|
|