Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@redocly/openapi-core

Package Overview
Dependencies
Maintainers
9
Versions
178
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@redocly/openapi-core - npm Package Compare versions

Comparing version 1.9.0 to 1.9.1

lib/types/json-schema-adapter.d.ts

6

CHANGELOG.md
# @redocly/openapi-core
## 1.9.1
### Patch Changes
- Fixed a bug with resolving $refs to file names that contain the hash symbol.
## 1.9.0

@@ -4,0 +10,0 @@

2

lib/bundle.d.ts

@@ -50,2 +50,2 @@ import { BaseResolver } from './resolve';

}): Promise<BundleResult>;
export declare function mapTypeToComponent(typeName: string, version: SpecMajorVersion): "responses" | "parameters" | "examples" | "headers" | "schemas" | "requestBodies" | "securitySchemes" | "links" | "callbacks" | "definitions" | null;
export declare function mapTypeToComponent(typeName: string, version: SpecMajorVersion): "parameters" | "examples" | "headers" | "schemas" | "responses" | "requestBodies" | "securitySchemes" | "links" | "callbacks" | "definitions" | null;

@@ -28,2 +28,3 @@ import { BaseResolver } from './resolve';

externalRefResolver?: BaseResolver;
externalConfigTypes?: Record<string, NodeType>;
}): Promise<import("./walk").NormalizedProblem[]>;

@@ -99,3 +99,3 @@ "use strict";

});
const types = (0, types_1.normalizeTypes)(redocly_yaml_1.ConfigTypes, config);
const types = (0, types_1.normalizeTypes)(opts.externalConfigTypes || redocly_yaml_1.ConfigTypes, config);
const rules = [

@@ -102,0 +102,0 @@ {

@@ -27,2 +27,2 @@ import { Oas3Rule, Oas3Preprocessor, Oas2Rule, Oas2Preprocessor, Async2Preprocessor, Async2Rule } from './visitors';

export declare function getMajorSpecVersion(version: SpecVersion): SpecMajorVersion;
export declare function getTypes(spec: SpecVersion): Record<string, import("./types").NodeType>;
export declare function getTypes(spec: SpecVersion): Record<string, import("./types").NodeType> | Record<"Root" | "Tag" | "ExternalDocs" | "SecurityRequirement" | "Info" | "Contact" | "License" | "Paths" | "PathItem" | "Parameter" | "Operation" | "Example" | "Header" | "Responses" | "Response" | "Schema" | "Xml" | "SchemaProperties" | "NamedSchemas" | "NamedResponses" | "NamedParameters" | "NamedSecuritySchemes" | "SecurityScheme" | "Examples" | "ExamplesMap" | "TagList" | "SecurityRequirementList" | "ParameterList" | "ParameterItems" | "TagGroup" | "TagGroups" | "EnumDescriptions" | "Logo" | "XCodeSample" | "XCodeSampleList" | "XServer" | "XServerList", import("./types").NodeType> | Record<"Root" | "Tag" | "ExternalDocs" | "Server" | "ServerVariable" | "SecurityRequirement" | "Info" | "Contact" | "License" | "Paths" | "PathItem" | "Callback" | "CallbacksMap" | "Parameter" | "Operation" | "RequestBody" | "MediaTypesMap" | "MediaType" | "Example" | "Encoding" | "Header" | "Responses" | "Response" | "Link" | "Schema" | "Xml" | "SchemaProperties" | "DiscriminatorMapping" | "Discriminator" | "Components" | "NamedSchemas" | "NamedResponses" | "NamedParameters" | "NamedExamples" | "NamedRequestBodies" | "NamedHeaders" | "NamedSecuritySchemes" | "NamedLinks" | "NamedCallbacks" | "ImplicitFlow" | "PasswordFlow" | "ClientCredentials" | "AuthorizationCode" | "OAuth2Flows" | "SecurityScheme" | "ServerVariablesMap" | "ExamplesMap" | "EncodingMap" | "HeadersMap" | "LinksMap" | "WebhooksMap" | "TagList" | "SecurityRequirementList" | "ParameterList" | "TagGroup" | "TagGroups" | "EnumDescriptions" | "Logo" | "XCodeSample" | "XCodeSampleList" | "ServerList" | "XUsePkce", import("./types").NodeType> | Record<"Root" | "Info" | "License" | "Operation" | "Schema" | "SchemaProperties" | "Components" | "SecurityScheme" | "NamedPathItems", import("./types").NodeType>;

@@ -42,5 +42,5 @@ "use strict";

function parseRef(ref) {
const [uri, pointer = ''] = ref.split('#');
const [uri, pointer = ''] = ref.split('#/');
return {
uri: uri || null,
uri: (uri.endsWith('#') ? uri.slice(0, -1) : uri) || null,
pointer: parsePointer(pointer),

@@ -47,0 +47,0 @@ };

@@ -214,4 +214,12 @@ "use strict";

}
const isTypeAFunction = typeof itemsType === 'function';
for (let i = 0; i < node.length; i++) {
walk(node[i], itemsType || unknownType, (0, ref_utils_1.joinPointer)(nodeAbsoluteRef, i));
const itemType = isTypeAFunction
? itemsType(node[i], (0, ref_utils_1.joinPointer)(nodeAbsoluteRef, i))
: itemsType;
// we continue resolving unknown types, but stop early on known scalars
if (itemType === undefined && type !== unknownType && type !== types_1.SpecExtension) {
continue;
}
walk(node[i], (0, types_1.isNamedType)(itemType) ? itemType : unknownType, (0, ref_utils_1.joinPointer)(nodeAbsoluteRef, i));
}

@@ -218,0 +226,0 @@ return;

@@ -22,3 +22,3 @@ export type ScalarSchema = {

additionalProperties?: PropType | ResolveTypeFn;
items?: string;
items?: PropType | ResolveTypeFn;
required?: string[] | ((value: any, key: string | number | undefined) => string[]);

@@ -29,4 +29,4 @@ requiredOneOf?: string[];

};
type PropType = string | NodeType | ScalarSchema | undefined | null;
type ResolveTypeFn = (value: any, key: string) => string | PropType;
export type PropType = string | NodeType | ScalarSchema | undefined | null;
export type ResolveTypeFn = (value: any, key: string) => string | PropType;
export type NormalizedNodeType = {

@@ -36,3 +36,3 @@ name: string;

additionalProperties?: NormalizedPropType | NormalizedResolveTypeFn;
items?: NormalizedNodeType;
items?: NormalizedPropType | NormalizedResolveTypeFn;
required?: string[] | ((value: any, key: string | number | undefined) => string[]);

@@ -43,4 +43,4 @@ requiredOneOf?: string[];

};
type NormalizedPropType = NormalizedNodeType | NormalizedScalarSchema | undefined | null;
type NormalizedResolveTypeFn = (value: any, key: string) => NormalizedNodeType | NormalizedScalarSchema | undefined | null;
type NormalizedPropType = NormalizedNodeType | NormalizedScalarSchema | null | undefined;
type NormalizedResolveTypeFn = (value: any, key: string) => NormalizedPropType;
export declare function listOf(typeName: string): {

@@ -60,3 +60,3 @@ name: string;

}): Record<string, NormalizedNodeType>;
export declare function isNamedType(t: NormalizedNodeType | NormalizedScalarSchema | null | undefined): t is NormalizedNodeType;
export declare function isNamedType(t: NormalizedPropType): t is NormalizedNodeType;
export {};

@@ -1,2 +0,3 @@

import { NodeType } from '.';
export declare const Oas2Types: Record<string, NodeType>;
import type { NodeType } from '.';
import type { Oas2NodeType } from './redocly-yaml';
export declare const Oas2Types: Record<Oas2NodeType, NodeType>;

@@ -1,2 +0,3 @@

import { NodeType } from '.';
export declare const Oas3_1Types: Record<string, NodeType>;
import type { NodeType } from '.';
import type { Oas3_1NodeType } from './redocly-yaml';
export declare const Oas3_1Types: Record<Oas3_1NodeType, NodeType>;

@@ -1,2 +0,3 @@

import { NodeType } from '.';
export declare const Oas3Types: Record<string, NodeType>;
import type { NodeType } from '.';
import type { Oas3NodeType } from './redocly-yaml';
export declare const Oas3Types: Record<Oas3NodeType, NodeType>;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.rootRedoclyConfigSchema = exports.environmentSchema = exports.redoclyConfigSchema = exports.PortalConfigNodeTypes = exports.apiConfigSchema = exports.ssoConfigSchema = void 0;
exports.rootRedoclyConfigSchema = void 0;
const config_1 = require("../config");
const theme_config_1 = require("./theme-config");
const oidcIssuerMetadataSchema = {

@@ -21,6 +22,7 @@ type: 'object',

title: { type: 'string' },
pkce: { type: 'boolean', default: false },
configurationUrl: { type: 'string', minLength: 1 },
configuration: oidcIssuerMetadataSchema,
clientId: { type: 'string', minLength: 1 },
clientSecret: { type: 'string', minLength: 1 },
clientSecret: { type: 'string', minLength: 0 },
teamsClaimName: { type: 'string' },

@@ -35,3 +37,3 @@ teamsClaimMap: { type: 'object', additionalProperties: { type: 'string' } },

},
required: ['type', 'clientId', 'clientSecret'],
required: ['type', 'clientId'],
oneOf: [{ required: ['configurationUrl'] }, { required: ['configuration'] }],

@@ -83,7 +85,22 @@ additionalProperties: false,

};
exports.ssoConfigSchema = {
const ssoOnPremConfigSchema = {
type: 'object',
properties: {},
additionalProperties: authProviderConfigSchema,
};
const ssoConfigSchema = {
oneOf: [
{
type: 'array',
items: {
type: 'string',
enum: ['REDOCLY', 'CORPORATE', 'GUEST'],
},
uniqueItems: true,
},
{
type: 'string',
enum: ['REDOCLY', 'CORPORATE', 'GUEST'],
},
],
};
const redirectConfigSchema = {

@@ -95,14 +112,14 @@ type: 'object',

},
required: ['to'],
additionalProperties: false,
};
const redirectsConfigSchema = {
type: 'object',
properties: {},
additionalProperties: 'redirectConfigSchema',
additionalProperties: redirectConfigSchema,
default: {},
};
exports.apiConfigSchema = {
const apiConfigSchema = {
type: 'object',
properties: {
root: { type: 'string' },
output: { type: 'string', pattern: '(.ya?ml|.json)$' },
rbac: { type: 'object', additionalProperties: true },

@@ -112,3 +129,4 @@ theme: {

properties: {
openapi: { type: 'object', additionalProperties: true },
openapi: theme_config_1.themeConfigSchema.properties.openapi,
graphql: theme_config_1.themeConfigSchema.properties.graphql,
},

@@ -119,4 +137,5 @@ additionalProperties: false,

metadata: { type: 'object', additionalProperties: true },
rules: { type: 'object', additionalProperties: true },
decorators: { type: 'object', additionalProperties: true },
},
additionalProperties: true,
required: ['root'],

@@ -135,3 +154,5 @@ };

image: { type: 'string' },
keywords: { type: 'array', items: { type: 'string' } },
keywords: {
oneOf: [{ type: 'array', items: { type: 'string' } }, { type: 'string' }],
},
lang: { type: 'string' },

@@ -152,12 +173,16 @@ jsonLd: { type: 'object' },

},
additionalProperties: false,
};
const rbacScopeItemsSchema = {
type: 'object',
properties: {},
additionalProperties: { type: 'string' },
};
const rbacScopeItemsSchema = { type: 'object', additionalProperties: { type: 'string' } };
const rbacConfigSchema = {
type: 'object',
properties: {
defaults: 'rbacScopeItemsSchema',
cms: rbacScopeItemsSchema,
content: {
type: 'object',
properties: {
'**': rbacScopeItemsSchema,
},
additionalProperties: rbacScopeItemsSchema,
},
},

@@ -227,2 +252,3 @@ additionalProperties: rbacScopeItemsSchema,

required: ['adapters'],
additionalProperties: false,
properties: {

@@ -257,3 +283,4 @@ adapters: {

},
required: ['defaultLocale', 'locales'],
additionalProperties: false,
required: ['defaultLocale'],
};

@@ -269,20 +296,9 @@ const responseHeaderSchema = {

};
exports.PortalConfigNodeTypes = {
seoConfigSchema,
rbacConfigSchema,
rbacScopeItemsSchema,
ssoConfigSchema: exports.ssoConfigSchema,
devOnboardingConfigSchema,
i18ConfigSchema,
redirectsConfigSchema,
redirectConfigSchema,
// TODO: Extract other types that need to be linted in the config
};
exports.redoclyConfigSchema = {
const redoclyConfigSchema = {
type: 'object',
properties: {
licenseKey: { type: 'string' },
redirects: 'redirectsConfigSchema',
seo: 'seoConfigSchema',
rbac: 'rbacConfigSchema',
redirects: redirectsConfigSchema,
seo: seoConfigSchema,
rbac: rbacConfigSchema,
responseHeaders: {

@@ -307,28 +323,28 @@ type: 'object',

type: 'object',
additionalProperties: exports.apiConfigSchema,
additionalProperties: apiConfigSchema,
},
sso: 'ssoConfigSchema',
developerOnboarding: 'devOnboardingConfigSchema',
i18n: 'i18ConfigSchema',
ssoOnPrem: ssoOnPremConfigSchema,
sso: ssoConfigSchema,
residency: { type: 'string' },
developerOnboarding: devOnboardingConfigSchema,
i18n: i18ConfigSchema,
metadata: metadataConfigSchema,
},
default: {},
};
exports.environmentSchema = {
oneOf: [
Object.assign(Object.assign({}, exports.redoclyConfigSchema), { additionalProperties: false }),
{
type: 'object',
properties: {
$ref: { type: 'string' },
ignore: {
type: 'array',
items: {
type: 'string',
},
required: ['$ref'],
additionalProperties: false,
},
],
theme: theme_config_1.themeConfigSchema,
},
default: { redirects: {} },
additionalProperties: true,
};
exports.rootRedoclyConfigSchema = Object.assign(Object.assign({}, exports.redoclyConfigSchema), { properties: Object.assign(Object.assign({}, exports.redoclyConfigSchema.properties), { env: {
const environmentSchema = Object.assign(Object.assign({}, redoclyConfigSchema), { additionalProperties: false });
exports.rootRedoclyConfigSchema = Object.assign(Object.assign({}, redoclyConfigSchema), { properties: Object.assign(Object.assign({ plugins: {
type: 'array',
items: { type: 'string' },
} }, redoclyConfigSchema.properties), { env: {
type: 'object',
properties: {},
additionalProperties: exports.environmentSchema,
} }), default: {}, required: ['redirects'] });
additionalProperties: environmentSchema, // TODO: if we want full validation we need to override apis, theme and the root
} }), default: {}, additionalProperties: false });

@@ -1,2 +0,3 @@

import { NodeType } from '.';
import type { NodeType } from '.';
import type { JSONSchema } from 'json-schema-to-ts';
declare const builtInCommonRules: readonly ["spec", "info-contact", "operation-operationId", "tag-description", "tags-alphabetical"];

@@ -12,3 +13,14 @@ export type BuiltInCommonRuleId = typeof builtInCommonRules[number];

export type BuiltInAsync2RuleId = typeof builtInAsync2Rules[number];
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"];
export type Oas2NodeType = typeof oas2NodeTypesList[number];
declare const oas3NodeTypesList: readonly ["Root", "Tag", "TagList", "ExternalDocs", "Server", "ServerList", "ServerVariable", "ServerVariablesMap", "SecurityRequirement", "SecurityRequirementList", "Info", "Contact", "License", "Paths", "PathItem", "Parameter", "ParameterList", "Operation", "Callback", "CallbacksMap", "RequestBody", "MediaTypesMap", "MediaType", "Example", "ExamplesMap", "Encoding", "EncodingMap", "Header", "HeadersMap", "Responses", "Response", "Link", "LinksMap", "Schema", "Xml", "SchemaProperties", "DiscriminatorMapping", "Discriminator", "Components", "NamedSchemas", "NamedResponses", "NamedParameters", "NamedExamples", "NamedRequestBodies", "NamedHeaders", "NamedSecuritySchemes", "NamedLinks", "NamedCallbacks", "ImplicitFlow", "PasswordFlow", "ClientCredentials", "AuthorizationCode", "OAuth2Flows", "SecurityScheme", "TagGroup", "TagGroups", "EnumDescriptions", "Logo", "XCodeSample", "XCodeSampleList", "XUsePkce", "WebhooksMap"];
export type Oas3NodeType = typeof oas3NodeTypesList[number];
declare const oas3_1NodeTypesList: readonly ["Root", "Schema", "SchemaProperties", "Info", "License", "Components", "NamedPathItems", "SecurityScheme", "Operation"];
export type Oas3_1NodeType = typeof oas3_1NodeTypesList[number];
export declare const createConfigTypes: (extraSchemas: JSONSchema) => {
ConfigRoot: NodeType;
ConfigApisProperties: NodeType;
ConfigRootTheme: NodeType;
};
export declare const ConfigTypes: Record<string, NodeType>;
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConfigTypes = void 0;
exports.ConfigTypes = exports.createConfigTypes = void 0;
const portal_config_schema_1 = require("./portal-config-schema");
const theme_config_1 = require("./theme-config");
const _1 = require(".");
const utils_1 = require("../utils");
const portal_config_schema_2 = require("./portal-config-schema");
const json_schema_adapter_1 = require("./json-schema-adapter");
const builtInCommonRules = [

@@ -84,4 +83,3 @@ 'spec',

];
const nodeTypesList = [
'any',
const oas2NodeTypesList = [
'Root',

@@ -91,2 +89,41 @@ 'Tag',

'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',
];
const oas3NodeTypesList = [
'Root',
'Tag',
'TagList',
'ExternalDocs',
'Server',

@@ -142,8 +179,23 @@ 'ServerList',

'SecurityScheme',
'TagGroup',
'TagGroups',
'EnumDescriptions',
'Logo',
'XCodeSample',
'XCodeSampleList',
'XUsePkce',
'WebhooksMap',
'SpecExtension',
'Message',
];
const oas3_1NodeTypesList = [
'Root',
'Schema',
'SchemaProperties',
'Info',
'License',
'Components',
'NamedPathItems',
'SecurityScheme',
'Operation',
];
const asyncNodeTypesList = ['Message'];
const ConfigStyleguide = {

@@ -174,10 +226,3 @@ properties: {

};
const RootConfigStyleguide = {
properties: Object.assign({ plugins: {
type: 'array',
items: { type: 'string' },
} }, ConfigStyleguide.properties),
};
const ConfigRoot = {
properties: Object.assign(Object.assign(Object.assign({}, portal_config_schema_1.rootRedoclyConfigSchema.properties), RootConfigStyleguide.properties), { apis: 'ConfigApis', theme: 'ConfigRootTheme', 'features.openapi': 'ConfigReferenceDocs', 'features.mockServer': 'ConfigMockServer', organization: { type: 'string' }, region: { enum: ['us', 'eu'] }, telemetry: { enum: ['on', 'off'] }, resolve: {
const createConfigRoot = (nodeTypes) => (Object.assign(Object.assign({}, nodeTypes.rootRedoclyConfigSchema), { properties: Object.assign(Object.assign(Object.assign({}, nodeTypes.rootRedoclyConfigSchema.properties), ConfigStyleguide.properties), { apis: 'ConfigApis', theme: 'ConfigRootTheme', 'features.openapi': 'ConfigReferenceDocs', 'features.mockServer': 'ConfigMockServer', organization: { type: 'string' }, region: { enum: ['us', 'eu'] }, telemetry: { enum: ['on', 'off'] }, resolve: {
properties: {

@@ -192,4 +237,3 @@ http: 'ConfigHTTP',

},
} }),
};
} }) }));
const ConfigApis = {

@@ -199,15 +243,15 @@ properties: {},

};
const ConfigApisProperties = {
properties: Object.assign(Object.assign(Object.assign(Object.assign({}, portal_config_schema_1.apiConfigSchema.properties), { root: { type: 'string' }, labels: {
type: 'array',
items: {
type: 'string',
},
} }), ConfigStyleguide.properties), { 'features.openapi': 'ConfigReferenceDocs', 'features.mockServer': 'ConfigMockServer', theme: 'ConfigRootTheme', files: {
type: 'array',
items: {
type: 'string',
},
} }),
required: ['root'],
const createConfigApisProperties = (nodeTypes) => {
var _a;
return (Object.assign(Object.assign({}, nodeTypes['rootRedoclyConfigSchema.apis_additionalProperties']), { properties: Object.assign(Object.assign(Object.assign(Object.assign({}, (_a = nodeTypes['rootRedoclyConfigSchema.apis_additionalProperties']) === null || _a === void 0 ? void 0 : _a.properties), { labels: {
type: 'array',
items: {
type: 'string',
},
} }), ConfigStyleguide.properties), { 'features.openapi': 'ConfigReferenceDocs', 'features.mockServer': 'ConfigMockServer', files: {
type: 'array',
items: {
type: 'string',
},
} }) }));
};

@@ -224,4 +268,5 @@ const ConfigHTTP = {

};
const ConfigRootTheme = {
properties: Object.assign(Object.assign({}, theme_config_1.themeConfigSchema.properties), { openapi: 'ConfigReferenceDocs', mockServer: 'ConfigMockServer' }),
const createConfigRootTheme = (nodeTypes) => {
var _a;
return (Object.assign(Object.assign({}, nodeTypes['rootRedoclyConfigSchema.theme']), { properties: Object.assign(Object.assign({}, (_a = nodeTypes['rootRedoclyConfigSchema.theme']) === null || _a === void 0 ? void 0 : _a.properties), { openapi: 'ConfigReferenceDocs' }) }));
};

@@ -262,3 +307,14 @@ const Rules = {

properties: {
type: { enum: nodeTypesList },
type: {
enum: [
...new Set([
'any',
...oas2NodeTypesList,
...oas3NodeTypesList,
...oas3_1NodeTypesList,
...asyncNodeTypesList,
'SpecExtension',
]),
],
},
property: (value) => {

@@ -716,2 +772,3 @@ if (Array.isArray(value)) {

const ConfigReferenceDocs = {
// TODO: partially invalid @Viacheslav
properties: {

@@ -851,7 +908,11 @@ theme: 'ConfigTheme',

};
exports.ConfigTypes = Object.assign({ Assert,
ConfigRoot,
const createConfigTypes = (extraSchemas) => {
// Create types based on external schemas
const nodeTypes = (0, json_schema_adapter_1.getNodeTypesFromJSONSchema)('rootRedoclyConfigSchema', extraSchemas);
return Object.assign(Object.assign(Object.assign({}, CoreConfigTypes), { ConfigRoot: createConfigRoot(nodeTypes), ConfigApisProperties: createConfigApisProperties(nodeTypes), ConfigRootTheme: createConfigRootTheme(nodeTypes) }), nodeTypes);
};
exports.createConfigTypes = createConfigTypes;
const CoreConfigTypes = {
Assert,
ConfigApis,
ConfigApisProperties,
RootConfigStyleguide,
ConfigStyleguide,

@@ -866,3 +927,2 @@ ConfigReferenceDocs,

ConfigTheme,
ConfigRootTheme,
AssertDefinition,

@@ -916,2 +976,4 @@ ThemeColors,

AssertionDefinitionAssertions,
AssertionDefinitionSubject }, portal_config_schema_2.PortalConfigNodeTypes);
AssertionDefinitionSubject,
};
exports.ConfigTypes = (0, exports.createConfigTypes)(portal_config_schema_1.rootRedoclyConfigSchema);
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ScorecardStatus = exports.productThemeOverrideSchema = exports.themeConfigSchema = void 0;
exports.productThemeOverrideSchema = exports.themeConfigSchema = void 0;
const logoConfigSchema = {

@@ -70,2 +70,7 @@ type: 'object',

},
partialsFolders: {
type: 'array',
items: { type: 'string' },
default: ['_partials'],
},
lastUpdatedBlock: {

@@ -77,3 +82,3 @@ type: 'object',

default: 'timeago',
}, locale: { type: 'string', default: 'en-US' } }, hideConfigSchema.properties),
}, locale: { type: 'string' } }, hideConfigSchema.properties),
additionalProperties: false,

@@ -173,2 +178,15 @@ default: {},

};
const productGoogleAnalyticsConfigSchema = {
type: 'object',
properties: {
includeInDevelopment: { type: 'boolean' },
trackingId: { type: 'string' },
conversionId: { type: 'string' },
floodlightId: { type: 'string' },
optimizeId: { type: 'string' },
exclude: { type: 'array', items: { type: 'string' } },
},
additionalProperties: false,
required: ['trackingId'],
};
const googleAnalyticsConfigSchema = {

@@ -187,2 +205,7 @@ type: 'object',

cookieExpires: { type: 'number' },
// All enabled tracking configs
trackers: {
type: 'object',
additionalProperties: productGoogleAnalyticsConfigSchema,
},
},

@@ -207,2 +230,3 @@ additionalProperties: false,

directory: { type: 'string' },
disconnect: { type: 'boolean', default: false },
group: { type: 'string' },

@@ -240,3 +264,3 @@ label: { type: 'string' },

additionalProperties: false,
required: ['name', 'icon', 'folder'],
required: ['name', 'folder'],
};

@@ -262,2 +286,3 @@ const suggestedPageSchema = {

parentFilter: { type: 'string' },
valuesMapping: { type: 'object', additionalProperties: { type: 'string' } },
missingCategoryName: { type: 'string' },

@@ -271,5 +296,5 @@ missingCategoryNameTranslationKey: { type: 'string' },

additionalProperties: true,
required: ['levels'],
required: [],
properties: {
failBuildIfBelowMinimum: { type: 'boolean', default: false },
ignoreNonCompliant: { type: 'boolean', default: false },
teamMetadataProperty: {

@@ -290,2 +315,3 @@ type: 'object',

name: { type: 'string' },
color: { type: 'string' },
extends: { type: 'array', items: { type: 'string' } },

@@ -295,3 +321,3 @@ rules: {

additionalProperties: {
type: ['object', 'string'],
oneOf: [{ type: 'string' }, { type: 'object' }],
},

@@ -383,8 +409,2 @@ },

},
seo: {
type: 'object',
properties: {
title: { type: 'string' },
},
},
scripts: {

@@ -408,3 +428,3 @@ type: 'object',

type: 'string',
enum: ['rating', 'sentiment', 'comment', 'reasons'],
enum: ['rating', 'sentiment', 'comment', 'reasons', 'mood', 'scale'],
default: 'sentiment',

@@ -415,11 +435,23 @@ },

submitText: { type: 'string' },
max: { type: 'number' },
buttonText: { type: 'string' },
multi: { type: 'boolean' },
component: {
type: 'string',
enum: ['radio', 'checkbox'],
default: 'checkbox',
},
items: { type: 'array', items: { type: 'string' }, minItems: 1 },
leftScaleLabel: { type: 'string' },
rightScaleLabel: { type: 'string' },
reasons: {
type: 'object',
properties: {
enable: { type: 'boolean', default: true },
multi: { type: 'boolean' },
hide: {
type: 'boolean',
default: false,
},
component: {
type: 'string',
enum: ['radio', 'checkbox'],
default: 'checkbox',
},
label: { type: 'string' },

@@ -433,6 +465,12 @@ items: { type: 'array', items: { type: 'string' } },

properties: {
enable: { type: 'boolean', default: true },
hide: {
type: 'boolean',
default: false,
},
label: { type: 'string' },
likeLabel: { type: 'string' },
dislikeLabel: { type: 'string' },
satisfiedLabel: { type: 'string' },
neutralLabel: { type: 'string' },
dissatisfiedLabel: { type: 'string' },
},

@@ -477,3 +515,3 @@ additionalProperties: false,

type: 'object',
properties: Object.assign({ text: { type: 'string', default: 'Next to {label}' } }, hideConfigSchema.properties),
properties: Object.assign({ text: { type: 'string', default: 'Next to {{label}}' } }, hideConfigSchema.properties),
additionalProperties: false,

@@ -484,3 +522,3 @@ default: {},

type: 'object',
properties: Object.assign({ text: { type: 'string', default: 'Back to {label}' } }, hideConfigSchema.properties),
properties: Object.assign({ text: { type: 'string', default: 'Back to {{label}}' } }, hideConfigSchema.properties),
additionalProperties: false,

@@ -496,3 +534,3 @@ default: {},

properties: {
controlsStyle: { type: 'string', default: 'icon' },
elementFormat: { type: 'string', default: 'icon' },
copy: {

@@ -506,5 +544,5 @@ type: 'object',

type: 'object',
properties: Object.assign({}, hideConfigSchema.properties),
properties: Object.assign({ tooltipText: { type: 'string' }, buttonText: { type: 'string' }, label: { type: 'string' } }, hideConfigSchema.properties),
additionalProperties: false,
default: { hide: true },
default: { hide: false },
},

@@ -608,2 +646,8 @@ expand: {

breadcrumbs: exports.themeConfigSchema.properties.breadcrumbs,
analytics: {
type: 'object',
properties: {
ga: productGoogleAnalyticsConfigSchema,
},
},
},

@@ -613,7 +657,1 @@ additionalProperties: true,

};
var ScorecardStatus;
(function (ScorecardStatus) {
ScorecardStatus["BelowMinimum"] = "Below minimum";
ScorecardStatus["Highest"] = "Highest";
ScorecardStatus["Minimum"] = "Minimum";
})(ScorecardStatus || (exports.ScorecardStatus = ScorecardStatus = {}));

@@ -18,4 +18,4 @@ import { UserContext } from './walk';

export declare function isDefined<T>(x: T | undefined): x is T;
export declare function isPlainObject(value: any): value is object;
export declare function isEmptyObject(value: any): value is object;
export declare function isPlainObject(value: any): value is Record<string, unknown>;
export declare function isEmptyObject(value: any): value is Record<string, unknown>;
export declare function isEmptyArray(value: any): boolean;

@@ -22,0 +22,0 @@ export declare function readFileFromUrl(url: string, config: HttpResolveConfig): Promise<{

@@ -64,3 +64,3 @@ "use strict";

}
if (from.items) {
if (from.items && typeof from.items !== 'function') {
if (from.items === to) {

@@ -67,0 +67,0 @@ addWeakFromStack(ruleConf, stack);

@@ -143,4 +143,10 @@ "use strict";

if (itemsType !== undefined) {
const isTypeAFunction = typeof itemsType === 'function';
for (let i = 0; i < resolvedNode.length; i++) {
walkNode(resolvedNode[i], itemsType, resolvedLocation.child([i]), resolvedNode, i);
const itemType = isTypeAFunction
? itemsType(resolvedNode[i], resolvedLocation.child([i]).absolutePointer)
: itemsType;
if ((0, types_1.isNamedType)(itemType)) {
walkNode(resolvedNode[i], itemType, resolvedLocation.child([i]), resolvedNode, i);
}
}

@@ -147,0 +153,0 @@ }

{
"name": "@redocly/openapi-core",
"version": "1.9.0",
"version": "1.9.1",
"description": "",

@@ -5,0 +5,0 @@ "main": "lib/index.js",

@@ -9,3 +9,273 @@ import * as path from 'path';

import { detectSpec } from '../oas-types';
import { themeConfigSchema } from '../types/theme-config';
import { createConfigTypes } from '../types/redocly-yaml';
const testPortalConfig = parseYamlToDocument(
outdent`
licenseKey: 123 # Must be a string
apis:
without-root:
foo: Not expected!
output: file.json
with-wrong-root:
root: 456 # Must be a string
with-theme:
root: ./openapi.yaml
theme:
openapi: wrong, must be an object
not-expected: Must fail
seo:
keywords: 789 # Must be an array
redirects:
some-redirect:
t1o: Wrong name, should be 'two'
type: wrong type, must be a number
rbac:
'team-b.md':
TeamB: read
team-c.md:
TeamC: read
/blog/*:
anonymous: none
authenticated: read
/blogpost/:
TeamD: none
'**/*.md':
TeamA: none
authenticated: none
'*': read
'blog/april-2022.md':
TeamA: none
TeamC: read
test.md:
TeamC: none
TeamB: none
authenticated: none
'*': read
test/**:
TeamB: read
TeamC: read
authenticated: read
anonymous: read
additional-property:
something: 123 # Must be a string
content:
'**':
additionalProp: 456 # Must be a stirng
foo:
additionalProp2: 789 # Must be a stirng
responseHeaders:
some-header: wrong, must be an array
some-header2:
- wrong, must be an object
- unexpected-property: Should fail
# name: Must be reported as a missing required prop
value: 123 # Must be a string
ssoOnPrem:
oidc:
title: 456 # Must be a string
type: OIDC
configurationUrl: http://localhost/oidc/.well-known/openid-configuration
clientId: '{{ process.env.public }}'
clientSecret: '{{ process.env.secret }}'
teamsClaimName: https://test.com
scopes:
- openid
audience:
- default
authorizationRequestCustomParams:
login_hint: 789 # Must be a string
prompt: login
configuration:
token_endpoint: 123 # Must be a string
# authorization_endpoint: Must be reported as a missing required prop
additional-propery: Must be allowed
defaultTeams:
- 456 # Must be a string
sso-config-schema-without-configurationUrl:
type: OIDC
# clientId: Must be reported as a missing required prop
# configurationUrl: Must be reported as a missing required prop
clientSecret: '{{ process.env.secret }}'
basic:
type: BASIC
credentials:
- teams:
- 789 # Must be a string
- correct
# username: Must be reported as a missing required prop
sso:
- WRONG # Does not match allowed options
developerOnboarding:
wrong: A not allowed field
adapters:
- should be object
- type: 123 # Must be a string
- type: APIGEE_X
# organizationName: Must be reported as a missing required prop
auth:
type: OAUTH2
# tokenEndpoint: Must be reported as a missing required prop
clientId: 456 # Must be a string
clientSecret: '{{ process.env.secret }}'
not-expected: Must fail
- type: APIGEE_X
organizationName: Test
auth:
type: SERVICE_ACCOUNT
# serviceAccountPrivateKey: Must be reported as a missing required prop
serviceAccountEmail: 789 # Must be a string
i18n:
defaultLocale: en-US
locales:
- code: 123 # Must be a string
name: English
- code: es-ES
name: Spanish
metadata:
test: anything
not-listed-filed: Must be reported as not expected
env:
some-env:
mockServer:
off: must be boolean
not-expected: Must fail
apis:
no-root:
# root: Must be defined
rules: {}
wrong-root:
root: 789 # Must be a string
theme:
breadcrumbs:
hide: false
prefixItems:
- label: Home
page: '/'
imports:
- '@redocly/theme-experimental'
logo:
srcSet: './images/redocly-black-logo.svg light, ./images/redocly-brand-logo.svg dark'
altText: Test
link: /
asyncapi:
hideInfo: false
expandSchemas:
root: true
elements: true
navbar:
items:
- label: Markdown
page: /markdown/
search:
shortcuts:
- ctrl+f
- cmd+k
- /
suggestedPages:
- label: TSX page
page: tsx.page.tsx
- page: /my-catalog/
footer:
copyrightText: Copyright © Test 2019-2020.
items:
- group: Legal
items:
- label: Terms of Use
href: 'https://test.com/' # Not expected
markdown:
lastUpdatedBlock:
format: 'long'
editPage:
baseUrl: https://test.com
graphql:
pagination: section
menu:
{
initialLoadState: 'default',
requireExactGroups: false,
groups:
[
{
name: 'GraphQL custom group',
directives: { includeByName: ['cacheControl', 'typeDirective'] },
},
],
otherItemsGroupName: 'Other',
}
sidebar:
separatorLine: true
linePosition: top
catalog:
main:
title: API Catalog
description: 'This is a description of the API Catalog'
slug: /my-catalog/
filters:
- title: Domain
property: domain
missingCategoryName: Other
- title: API Category
property: category
missingCategoryName: Other
groupByFirstFilter: false
items:
- directory: ./
flatten: true
includeByMetadata:
type: [openapi]
scorecard:
ignoreNonCompliant: true
levels:
- name: Baseline
extends:
- minimal
- name: Silver
extends:
- recommended
rules:
info-description: off
- name: Gold
rules:
rule/path-item-get-required:
severity: warn
subject:
type: PathItem
message: Every path item must have a GET operation.
assertions:
required:
- get
operation-4xx-response: warn
targets:
- where:
metadata:
l0: Distribution
publishDateRange: 2021-01-01T00:00:00Z/2022-01-01
minimumLevel: Silver
`,
''
);
describe('lint', () => {

@@ -101,24 +371,24 @@ it('lintFromString should work', async () => {

min: 3
theme:
openapi:
showConsole: true
layout:
scope: section
routingStrategy: browser
theme:
rightPanel:
backgroundColor: '#263238'
links:
color: '#6CC496'
theme:
openapi:
showConsole: true
layout:
scope: section
routingStrategy: browser
theme:
openapi:
showConsole: true
layout:
scope: section
routingStrategy: browser
rightPanel:
backgroundColor: '#263238'
links:
color: '#6CC496'
theme:
rightPanel:
backgroundColor: '#263238'
links:
color: '#6CC496'
openapi:
showConsole: true
layout:
scope: section
routingStrategy: browser
theme:
rightPanel:
backgroundColor: '#263238'
links:
color: '#6CC496'
`,

@@ -135,16 +405,11 @@ ''

{
"pointer": "#/eme",
"reportOnKey": true,
"pointer": "#/apis",
"reportOnKey": false,
"source": "",
},
],
"message": "Property \`eme\` is not expected here.",
"message": "Expected type \`ConfigApis\` (object) but got \`string\`",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [
"env",
"theme",
"seo",
"sso",
],
"suggest": [],
},

@@ -155,8 +420,8 @@ {

{
"pointer": "#/openapi",
"reportOnKey": true,
"pointer": "#/theme/openapi/layout",
"reportOnKey": false,
"source": "",
},
],
"message": "Property \`openapi\` is not expected here.",
"message": "\`layout\` can be one of the following only: "stacked", "three-panel".",
"ruleId": "configuration spec",

@@ -170,11 +435,14 @@ "severity": "error",

{
"pointer": "#/apis",
"reportOnKey": false,
"pointer": "#/theme/openapi/theme/theme",
"reportOnKey": true,
"source": "",
},
],
"message": "Expected type \`ConfigApis\` (object) but got \`string\`",
"message": "Property \`theme\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
"suggest": [
"schema",
"shape",
],
},

@@ -293,2 +561,916 @@ ]

it('lintConfig should detect wrong fields in the default configuration after merging with the portal config schema', async () => {
const document = testPortalConfig;
const results = await lintConfig({ document });
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
[
{
"from": undefined,
"location": [
{
"pointer": "#/licenseKey",
"reportOnKey": false,
"source": "",
},
],
"message": "Expected type \`string\` but got \`integer\`.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/sso/0",
"reportOnKey": false,
"source": "",
},
],
"message": "\`sso\` can be one of the following only: "REDOCLY", "CORPORATE", "GUEST".",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/not-listed-filed",
"reportOnKey": true,
"source": "",
},
],
"message": "Property \`not-listed-filed\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/redirects/some-redirect/t1o",
"reportOnKey": true,
"source": "",
},
],
"message": "Property \`t1o\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [
"to",
"type",
],
},
{
"from": undefined,
"location": [
{
"pointer": "#/redirects/some-redirect/type",
"reportOnKey": false,
"source": "",
},
],
"message": "Expected type \`number\` but got \`string\`.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/seo/keywords",
"reportOnKey": false,
"source": "",
},
],
"message": "Expected type \`array\` but got \`integer\`.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/rbac/content/**/additionalProp",
"reportOnKey": false,
"source": "",
},
],
"message": "Expected type \`string\` but got \`integer\`.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/rbac/content/foo/additionalProp2",
"reportOnKey": false,
"source": "",
},
],
"message": "Expected type \`string\` but got \`integer\`.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/rbac/additional-property/something",
"reportOnKey": false,
"source": "",
},
],
"message": "Expected type \`string\` but got \`integer\`.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/responseHeaders/some-header",
"reportOnKey": false,
"source": "",
},
],
"message": "Expected type \`rootRedoclyConfigSchema.responseHeaders_additionalProperties\` (array) but got \`string\`",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/responseHeaders/some-header2/0",
"reportOnKey": false,
"source": "",
},
],
"message": "Expected type \`rootRedoclyConfigSchema.responseHeaders_additionalProperties_items\` (object) but got \`string\`",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/responseHeaders/some-header2/1",
"reportOnKey": true,
"source": "",
},
],
"message": "The field \`name\` must be present on this level.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/responseHeaders/some-header2/1/unexpected-property",
"reportOnKey": true,
"source": "",
},
],
"message": "Property \`unexpected-property\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/responseHeaders/some-header2/1/value",
"reportOnKey": false,
"source": "",
},
],
"message": "Expected type \`string\` but got \`integer\`.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/apis/without-root",
"reportOnKey": true,
"source": "",
},
],
"message": "The field \`root\` must be present on this level.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/apis/without-root/foo",
"reportOnKey": true,
"source": "",
},
],
"message": "Property \`foo\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [
"root",
],
},
{
"from": undefined,
"location": [
{
"pointer": "#/apis/with-wrong-root/root",
"reportOnKey": false,
"source": "",
},
],
"message": "Expected type \`string\` but got \`integer\`.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/apis/with-theme/theme/openapi",
"reportOnKey": false,
"source": "",
},
],
"message": "Expected type \`object\` but got \`string\`.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/apis/with-theme/theme/not-expected",
"reportOnKey": true,
"source": "",
},
],
"message": "Property \`not-expected\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/ssoOnPrem/oidc/title",
"reportOnKey": false,
"source": "",
},
],
"message": "Expected type \`string\` but got \`integer\`.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/ssoOnPrem/oidc/defaultTeams/0",
"reportOnKey": false,
"source": "",
},
],
"message": "Expected type \`string\` but got \`integer\`.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/ssoOnPrem/oidc/configuration",
"reportOnKey": true,
"source": "",
},
],
"message": "The field \`authorization_endpoint\` must be present on this level.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/ssoOnPrem/oidc/configuration/token_endpoint",
"reportOnKey": false,
"source": "",
},
],
"message": "Expected type \`string\` but got \`integer\`.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/ssoOnPrem/oidc/authorizationRequestCustomParams/login_hint",
"reportOnKey": false,
"source": "",
},
],
"message": "Expected type \`string\` but got \`integer\`.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/ssoOnPrem/sso-config-schema-without-configurationUrl",
"reportOnKey": true,
"source": "",
},
],
"message": "The field \`clientId\` must be present on this level.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/ssoOnPrem/sso-config-schema-without-configurationUrl",
"reportOnKey": true,
"source": "",
},
],
"message": "The field \`configurationUrl\` must be present on this level.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/ssoOnPrem/basic/credentials/0",
"reportOnKey": true,
"source": "",
},
],
"message": "The field \`username\` must be present on this level.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/ssoOnPrem/basic/credentials/0/teams/0",
"reportOnKey": false,
"source": "",
},
],
"message": "Expected type \`string\` but got \`integer\`.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/developerOnboarding/wrong",
"reportOnKey": true,
"source": "",
},
],
"message": "Property \`wrong\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/developerOnboarding/adapters/0",
"reportOnKey": false,
"source": "",
},
],
"message": "Expected type \`APIGEE_X\` (object) but got \`string\`",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/developerOnboarding/adapters/1",
"reportOnKey": true,
"source": "",
},
],
"message": "The field \`organizationName\` must be present on this level.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/developerOnboarding/adapters/1",
"reportOnKey": true,
"source": "",
},
],
"message": "The field \`auth\` must be present on this level.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/developerOnboarding/adapters/1/type",
"reportOnKey": false,
"source": "",
},
],
"message": "Expected type \`string\` but got \`integer\`.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/developerOnboarding/adapters/2",
"reportOnKey": true,
"source": "",
},
],
"message": "The field \`organizationName\` must be present on this level.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/developerOnboarding/adapters/2/auth",
"reportOnKey": true,
"source": "",
},
],
"message": "The field \`tokenEndpoint\` must be present on this level.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/developerOnboarding/adapters/2/auth/clientId",
"reportOnKey": false,
"source": "",
},
],
"message": "Expected type \`string\` but got \`integer\`.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/developerOnboarding/adapters/2/auth/not-expected",
"reportOnKey": true,
"source": "",
},
],
"message": "Property \`not-expected\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/developerOnboarding/adapters/3/auth",
"reportOnKey": true,
"source": "",
},
],
"message": "The field \`serviceAccountPrivateKey\` must be present on this level.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/developerOnboarding/adapters/3/auth/serviceAccountEmail",
"reportOnKey": false,
"source": "",
},
],
"message": "Expected type \`string\` but got \`integer\`.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/i18n/locales/0/code",
"reportOnKey": false,
"source": "",
},
],
"message": "Expected type \`string\` but got \`integer\`.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/theme/footer/items/0/items/0/href",
"reportOnKey": true,
"source": "",
},
],
"message": "Property \`href\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/env/some-env/mockServer/off",
"reportOnKey": false,
"source": "",
},
],
"message": "Expected type \`boolean\` but got \`string\`.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/env/some-env/mockServer/not-expected",
"reportOnKey": true,
"source": "",
},
],
"message": "Property \`not-expected\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/env/some-env/apis/no-root",
"reportOnKey": true,
"source": "",
},
],
"message": "The field \`root\` must be present on this level.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/env/some-env/apis/wrong-root/root",
"reportOnKey": false,
"source": "",
},
],
"message": "Expected type \`string\` but got \`integer\`.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
]
`);
});
it('lintConfig should alternate its behavior when supplied externalConfigTypes', async () => {
const document = testPortalConfig;
const results = await lintConfig({
document,
externalConfigTypes: createConfigTypes({
type: 'object',
properties: { theme: themeConfigSchema },
additionalProperties: false,
}),
});
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
[
{
"from": undefined,
"location": [
{
"pointer": "#/licenseKey",
"reportOnKey": true,
"source": "",
},
],
"message": "Property \`licenseKey\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/seo",
"reportOnKey": true,
"source": "",
},
],
"message": "Property \`seo\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/redirects",
"reportOnKey": true,
"source": "",
},
],
"message": "Property \`redirects\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/rbac",
"reportOnKey": true,
"source": "",
},
],
"message": "Property \`rbac\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/responseHeaders",
"reportOnKey": true,
"source": "",
},
],
"message": "Property \`responseHeaders\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/ssoOnPrem",
"reportOnKey": true,
"source": "",
},
],
"message": "Property \`ssoOnPrem\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/sso",
"reportOnKey": true,
"source": "",
},
],
"message": "Property \`sso\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/developerOnboarding",
"reportOnKey": true,
"source": "",
},
],
"message": "Property \`developerOnboarding\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/i18n",
"reportOnKey": true,
"source": "",
},
],
"message": "Property \`i18n\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/metadata",
"reportOnKey": true,
"source": "",
},
],
"message": "Property \`metadata\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/not-listed-filed",
"reportOnKey": true,
"source": "",
},
],
"message": "Property \`not-listed-filed\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/env",
"reportOnKey": true,
"source": "",
},
],
"message": "Property \`env\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/theme/footer/items/0/items/0/href",
"reportOnKey": true,
"source": "",
},
],
"message": "Property \`href\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/apis/without-root/foo",
"reportOnKey": true,
"source": "",
},
],
"message": "Property \`foo\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/apis/without-root/output",
"reportOnKey": true,
"source": "",
},
],
"message": "Property \`output\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/apis/with-wrong-root/root",
"reportOnKey": true,
"source": "",
},
],
"message": "Property \`root\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/apis/with-theme/root",
"reportOnKey": true,
"source": "",
},
],
"message": "Property \`root\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
{
"from": undefined,
"location": [
{
"pointer": "#/apis/with-theme/theme",
"reportOnKey": true,
"source": "",
},
],
"message": "Property \`theme\` is not expected here.",
"ruleId": "configuration spec",
"severity": "error",
"suggest": [],
},
]
`);
});
it("'const' can have any type", async () => {

@@ -295,0 +1477,0 @@ const document = parseYamlToDocument(

@@ -99,2 +99,24 @@ import outdent from 'outdent';

it('should parse a ref correctly', () => {
expect(parseRef('./info.yaml#/description')).toEqual({
uri: './info.yaml',
pointer: ['description'],
});
});
it('should parse a ref which contain a hash in the middle', () => {
// Here `info#description.md` is a file name
expect(parseRef('./info#description.md')).toEqual({
uri: './info#description.md',
pointer: [],
});
});
it('should parse a ref which ends with a hash', () => {
expect(parseRef('./info.yaml#')).toEqual({
uri: './info.yaml',
pointer: [],
});
});
describe('refBaseName', () => {

@@ -101,0 +123,0 @@ it('returns base name for file reference', () => {

@@ -141,2 +141,15 @@ import { loadConfig, findConfig, getConfig, createConfig } from '../load';

{
"location": [
{
"pointer": "#/theme",
"reportOnKey": false,
"source": "fixtures/resolve-refs-in-config/config-with-refs.yaml",
},
],
"message": "Can't resolve $ref: ENOENT: no such file or directory 'fixtures/resolve-refs-in-config/wrong-ref.yaml'",
"ruleId": "configuration no-unresolved-refs",
"severity": "warn",
"suggest": [],
},
{
"from": {

@@ -158,15 +171,2 @@ "pointer": "#/rules",

},
{
"location": [
{
"pointer": "#/theme",
"reportOnKey": false,
"source": "fixtures/resolve-refs-in-config/config-with-refs.yaml",
},
],
"message": "Can't resolve $ref: ENOENT: no such file or directory 'fixtures/resolve-refs-in-config/wrong-ref.yaml'",
"ruleId": "configuration no-unresolved-refs",
"severity": "warn",
"suggest": [],
},
]

@@ -173,0 +173,0 @@ `);

@@ -1,6 +0,7 @@

import type { Oas2Decorator } from '../../visitors';
import { Location } from '../../ref-utils';
import type { Oas2Components } from '../../typings/swagger';
import { isEmptyObject } from '../../utils';
import type { Oas2Decorator } from '../../visitors';
import type { Oas2Components } from '../../typings/swagger';
export const RemoveUnusedComponents: Oas2Decorator = () => {

@@ -7,0 +8,0 @@ const components = new Map<

@@ -1,6 +0,7 @@

import type { Oas3Decorator } from '../../visitors';
import { Location } from '../../ref-utils';
import type { Oas3Components } from '../../typings/openapi';
import { isEmptyObject } from '../../utils';
import type { Oas3Decorator } from '../../visitors';
import type { Oas3Components } from '../../typings/openapi';
export const RemoveUnusedComponents: Oas3Decorator = () => {

@@ -7,0 +8,0 @@ const components = new Map<

@@ -115,2 +115,3 @@ import { BaseResolver, resolveDocument, makeDocumentFromString } from './resolve';

externalRefResolver?: BaseResolver;
externalConfigTypes?: Record<string, NodeType>;
}) {

@@ -130,3 +131,3 @@ const { document, severity, externalRefResolver = new BaseResolver() } = opts;

const types = normalizeTypes(ConfigTypes, config);
const types = normalizeTypes(opts.externalConfigTypes || ConfigTypes, config);
const rules: (RuleInstanceConfig & {

@@ -133,0 +134,0 @@ visitor: NestedVisitObject<unknown, Oas3Visitor | Oas3Visitor[]>;

@@ -46,5 +46,5 @@ import { Source } from './resolve';

export function parseRef(ref: string): { uri: string | null; pointer: string[] } {
const [uri, pointer = ''] = ref.split('#');
const [uri, pointer = ''] = ref.split('#/');
return {
uri: uri || null,
uri: (uri.endsWith('#') ? uri.slice(0, -1) : uri) || null,
pointer: parsePointer(pointer),

@@ -51,0 +51,0 @@ };

@@ -272,4 +272,16 @@ import * as fs from 'fs';

}
const isTypeAFunction = typeof itemsType === 'function';
for (let i = 0; i < node.length; i++) {
walk(node[i], itemsType || unknownType, joinPointer(nodeAbsoluteRef, i));
const itemType = isTypeAFunction
? itemsType(node[i], joinPointer(nodeAbsoluteRef, i))
: itemsType;
// we continue resolving unknown types, but stop early on known scalars
if (itemType === undefined && type !== unknownType && type !== SpecExtension) {
continue;
}
walk(
node[i],
isNamedType(itemType) ? itemType : unknownType,
joinPointer(nodeAbsoluteRef, i)
);
}

@@ -276,0 +288,0 @@ return;

@@ -24,3 +24,3 @@ export type ScalarSchema = {

additionalProperties?: PropType | ResolveTypeFn;
items?: string;
items?: PropType | ResolveTypeFn;
required?: string[] | ((value: any, key: string | number | undefined) => string[]);

@@ -31,4 +31,4 @@ requiredOneOf?: string[];

};
type PropType = string | NodeType | ScalarSchema | undefined | null;
type ResolveTypeFn = (value: any, key: string) => string | PropType;
export type PropType = string | NodeType | ScalarSchema | undefined | null;
export type ResolveTypeFn = (value: any, key: string) => string | PropType;

@@ -39,3 +39,3 @@ export type NormalizedNodeType = {

additionalProperties?: NormalizedPropType | NormalizedResolveTypeFn;
items?: NormalizedNodeType;
items?: NormalizedPropType | NormalizedResolveTypeFn;
required?: string[] | ((value: any, key: string | number | undefined) => string[]);

@@ -47,7 +47,4 @@ requiredOneOf?: string[];

type NormalizedPropType = NormalizedNodeType | NormalizedScalarSchema | undefined | null;
type NormalizedResolveTypeFn = (
value: any,
key: string
) => NormalizedNodeType | NormalizedScalarSchema | undefined | null;
type NormalizedPropType = NormalizedNodeType | NormalizedScalarSchema | null | undefined;
type NormalizedResolveTypeFn = (value: any, key: string) => NormalizedPropType;

@@ -149,6 +146,4 @@ export function listOf(typeName: string) {

export function isNamedType(
t: NormalizedNodeType | NormalizedScalarSchema | null | undefined
): t is NormalizedNodeType {
export function isNamedType(t: NormalizedPropType): t is NormalizedNodeType {
return typeof t?.name === 'string';
}

@@ -1,3 +0,6 @@

import { NodeType, listOf, mapOf } from '.';
import { listOf, mapOf } from '.';
import type { NodeType } from '.';
import type { Oas2NodeType } from './redocly-yaml';
const responseCodeRegexp = /^[0-9][0-9Xx]{2}$/;

@@ -440,3 +443,3 @@

export const Oas2Types: Record<string, NodeType> = {
export const Oas2Types: Record<Oas2NodeType, NodeType> = {
Root,

@@ -443,0 +446,0 @@ Tag,

@@ -1,4 +0,7 @@

import { NodeType, listOf, mapOf } from '.';
import { listOf, mapOf } from '.';
import { Oas3Types } from './oas3';
import type { NodeType } from '.';
import type { Oas3_1NodeType } from './redocly-yaml';
const Root: NodeType = {

@@ -265,3 +268,3 @@ properties: {

export const Oas3_1Types: Record<string, NodeType> = {
export const Oas3_1Types: Record<Oas3_1NodeType, NodeType> = {
...Oas3Types,

@@ -268,0 +271,0 @@ Info,

@@ -1,3 +0,7 @@

import { NodeType, listOf, mapOf } from '.';
import { listOf, mapOf } from '.';
import { isMappingRef } from '../ref-utils';
import type { NodeType } from '.';
import type { Oas3NodeType } from './redocly-yaml';
const responseCodeRegexp = /^[0-9][0-9Xx]{2}$/;

@@ -534,3 +538,3 @@

export const Oas3Types: Record<string, NodeType> = {
export const Oas3Types: Record<Oas3NodeType, NodeType> = {
Root,

@@ -537,0 +541,0 @@ Tag,

@@ -6,4 +6,6 @@ import {

} from '../config';
import { themeConfigSchema } from './theme-config';
import type { NodeType } from '.';
import type { FromSchema } from 'json-schema-to-ts';
import type { ThemeConfig } from './theme-config';

@@ -27,6 +29,7 @@ const oidcIssuerMetadataSchema = {

title: { type: 'string' },
pkce: { type: 'boolean', default: false },
configurationUrl: { type: 'string', minLength: 1 },
configuration: oidcIssuerMetadataSchema,
clientId: { type: 'string', minLength: 1 },
clientSecret: { type: 'string', minLength: 1 },
clientSecret: { type: 'string', minLength: 0 },
teamsClaimName: { type: 'string' },

@@ -41,3 +44,3 @@ teamsClaimMap: { type: 'object', additionalProperties: { type: 'string' } },

},
required: ['type', 'clientId', 'clientSecret'],
required: ['type', 'clientId'],
oneOf: [{ required: ['configurationUrl'] }, { required: ['configuration'] }],

@@ -93,8 +96,24 @@ additionalProperties: false,

export const ssoConfigSchema = {
const ssoOnPremConfigSchema = {
type: 'object',
properties: {},
additionalProperties: authProviderConfigSchema,
} as NodeType;
} as const;
const ssoConfigSchema = {
oneOf: [
{
type: 'array',
items: {
type: 'string',
enum: ['REDOCLY', 'CORPORATE', 'GUEST'],
},
uniqueItems: true,
},
{
type: 'string',
enum: ['REDOCLY', 'CORPORATE', 'GUEST'],
},
],
} as const;
const redirectConfigSchema = {

@@ -106,16 +125,16 @@ type: 'object',

},
required: ['to'],
} as NodeType;
additionalProperties: false,
} as const;
const redirectsConfigSchema = {
type: 'object',
properties: {},
additionalProperties: 'redirectConfigSchema',
additionalProperties: redirectConfigSchema,
default: {},
} as NodeType;
} as const;
export const apiConfigSchema = {
const apiConfigSchema = {
type: 'object',
properties: {
root: { type: 'string' },
output: { type: 'string', pattern: '(.ya?ml|.json)$' },
rbac: { type: 'object', additionalProperties: true },

@@ -125,3 +144,4 @@ theme: {

properties: {
openapi: { type: 'object', additionalProperties: true },
openapi: themeConfigSchema.properties.openapi,
graphql: themeConfigSchema.properties.graphql,
},

@@ -132,4 +152,5 @@ additionalProperties: false,

metadata: { type: 'object', additionalProperties: true },
rules: { type: 'object', additionalProperties: true },
decorators: { type: 'object', additionalProperties: true },
},
additionalProperties: true,
required: ['root'],

@@ -150,3 +171,5 @@ } as const;

image: { type: 'string' },
keywords: { type: 'array', items: { type: 'string' } },
keywords: {
oneOf: [{ type: 'array', items: { type: 'string' } }, { type: 'string' }],
},
lang: { type: 'string' },

@@ -167,9 +190,6 @@ jsonLd: { type: 'object' },

},
additionalProperties: false,
} as const;
const rbacScopeItemsSchema = {
type: 'object',
properties: {},
additionalProperties: { type: 'string' },
} as NodeType;
const rbacScopeItemsSchema = { type: 'object', additionalProperties: { type: 'string' } } as const;

@@ -179,6 +199,13 @@ const rbacConfigSchema = {

properties: {
defaults: 'rbacScopeItemsSchema',
cms: rbacScopeItemsSchema,
content: {
type: 'object',
properties: {
'**': rbacScopeItemsSchema,
},
additionalProperties: rbacScopeItemsSchema,
},
},
additionalProperties: rbacScopeItemsSchema,
} as NodeType;
} as const;

@@ -259,2 +286,3 @@ const graviteeAdapterConfigSchema = {

required: ['adapters'],
additionalProperties: false,
properties: {

@@ -266,3 +294,3 @@ adapters: {

},
} as NodeType;
} as const;

@@ -291,4 +319,5 @@ const i18ConfigSchema = {

},
required: ['defaultLocale', 'locales'],
} as NodeType;
additionalProperties: false,
required: ['defaultLocale'],
} as const;

@@ -305,21 +334,9 @@ const responseHeaderSchema = {

export const PortalConfigNodeTypes: Record<string, NodeType> = {
seoConfigSchema,
rbacConfigSchema,
rbacScopeItemsSchema,
ssoConfigSchema,
devOnboardingConfigSchema,
i18ConfigSchema,
redirectsConfigSchema,
redirectConfigSchema,
// TODO: Extract other types that need to be linted in the config
};
export const redoclyConfigSchema = {
const redoclyConfigSchema = {
type: 'object',
properties: {
licenseKey: { type: 'string' },
redirects: 'redirectsConfigSchema',
seo: 'seoConfigSchema',
rbac: 'rbacConfigSchema',
redirects: redirectsConfigSchema,
seo: seoConfigSchema,
rbac: rbacConfigSchema,
responseHeaders: {

@@ -346,36 +363,69 @@ type: 'object',

},
sso: 'ssoConfigSchema',
developerOnboarding: 'devOnboardingConfigSchema',
i18n: 'i18ConfigSchema',
ssoOnPrem: ssoOnPremConfigSchema,
sso: ssoConfigSchema,
residency: { type: 'string' },
developerOnboarding: devOnboardingConfigSchema,
i18n: i18ConfigSchema,
metadata: metadataConfigSchema,
},
default: {},
} as NodeType;
export const environmentSchema = {
oneOf: [
{ ...redoclyConfigSchema, additionalProperties: false },
{
type: 'object',
properties: {
$ref: { type: 'string' },
ignore: {
type: 'array',
items: {
type: 'string',
},
required: ['$ref'],
additionalProperties: false,
},
],
theme: themeConfigSchema,
},
default: { redirects: {} },
additionalProperties: true,
} as const;
const environmentSchema = {
...redoclyConfigSchema,
additionalProperties: false,
} as const;
export const rootRedoclyConfigSchema = {
...redoclyConfigSchema,
properties: {
plugins: {
type: 'array',
items: { type: 'string' },
},
...redoclyConfigSchema.properties,
env: {
type: 'object',
properties: {},
additionalProperties: environmentSchema,
additionalProperties: environmentSchema, // TODO: if we want full validation we need to override apis, theme and the root
},
},
default: {},
required: ['redirects'],
additionalProperties: false,
} as const;
export type RedoclyConfig<T = ThemeConfig> = FromSchema<typeof rootRedoclyConfigSchema> & {
theme?: T;
};
export type RedirectConfig = FromSchema<typeof redirectConfigSchema>;
export type RedirectsConfig = FromSchema<typeof redirectsConfigSchema>;
export type AuthProviderConfig = FromSchema<typeof authProviderConfigSchema>;
export type BasicAuthProviderConfig = FromSchema<typeof basicAuthProviderConfigSchema>;
export type OidcProviderConfig = FromSchema<typeof oidcProviderConfigSchema>;
export type Saml2ProviderConfig = FromSchema<typeof saml2ProviderConfigSchema>;
export type SeoConfig = FromSchema<typeof seoConfigSchema>;
export type RbacConfig = FromSchema<typeof rbacConfigSchema>;
export type RbacScopeItems = FromSchema<typeof rbacScopeItemsSchema>;
export type OidcIssuerMetadata = FromSchema<typeof oidcIssuerMetadataSchema>;
export type DevOnboardingAdapterConfig = FromSchema<typeof devOnboardingAdapterConfigSchema>;
export type GraviteeAdapterConfig = FromSchema<typeof graviteeAdapterConfigSchema>;
export type ApigeeAdapterConfig = FromSchema<
typeof apigeeXAdapterConfigSchema | typeof apigeeEdgeAdapterConfigSchema
>;
export type ApigeeAdapterAuthOauth2 = FromSchema<typeof apigeeAdapterAuthOauth2Schema>;
export type ApigeeAdapterAuthServiceAccount = FromSchema<
typeof apigeeAdapterAuthServiceAccountSchema
>;
export type SsoConfig = FromSchema<typeof ssoOnPremConfigSchema>;
export type I18nConfig = FromSchema<typeof i18ConfigSchema>;
export type ApiConfig = FromSchema<typeof apiConfigSchema>;

@@ -1,7 +0,9 @@

import { rootRedoclyConfigSchema, apiConfigSchema } from './portal-config-schema';
import { themeConfigSchema } from './theme-config';
import { NodeType, listOf } from '.';
import { rootRedoclyConfigSchema } from './portal-config-schema';
import { listOf } from '.';
import { omitObjectProps, pickObjectProps, isCustomRuleId } from '../utils';
import { PortalConfigNodeTypes } from './portal-config-schema';
import { getNodeTypesFromJSONSchema } from './json-schema-adapter';
import type { NodeType } from '.';
import type { JSONSchema } from 'json-schema-to-ts';
const builtInCommonRules = [

@@ -100,4 +102,3 @@ 'spec',

const nodeTypesList = [
'any',
const oas2NodeTypesList = [
'Root',

@@ -107,2 +108,44 @@ 'Tag',

'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',
] as const;
export type Oas2NodeType = typeof oas2NodeTypesList[number];
const oas3NodeTypesList = [
'Root',
'Tag',
'TagList',
'ExternalDocs',
'Server',

@@ -158,9 +201,30 @@ 'ServerList',

'SecurityScheme',
'TagGroup',
'TagGroups',
'EnumDescriptions',
'Logo',
'XCodeSample',
'XCodeSampleList',
'XUsePkce',
'WebhooksMap',
'SpecExtension',
'Message',
];
] as const;
export type Oas3NodeType = typeof oas3NodeTypesList[number];
const oas3_1NodeTypesList = [
'Root',
'Schema',
'SchemaProperties',
'Info',
'License',
'Components',
'NamedPathItems',
'SecurityScheme',
'Operation',
] as const;
export type Oas3_1NodeType = typeof oas3_1NodeTypesList[number];
const asyncNodeTypesList = ['Message'] as const;
const ConfigStyleguide: NodeType = {

@@ -192,18 +256,9 @@ properties: {

const RootConfigStyleguide: NodeType = {
const createConfigRoot = (nodeTypes: Record<string, NodeType>): NodeType => ({
...nodeTypes.rootRedoclyConfigSchema,
properties: {
plugins: {
type: 'array',
items: { type: 'string' },
},
...nodeTypes.rootRedoclyConfigSchema.properties,
...ConfigStyleguide.properties,
},
};
const ConfigRoot: NodeType = {
properties: {
...rootRedoclyConfigSchema.properties,
...RootConfigStyleguide.properties,
apis: 'ConfigApis',
theme: 'ConfigRootTheme',
apis: 'ConfigApis', // Override apis with internal format
theme: 'ConfigRootTheme', // Override theme with internal format
'features.openapi': 'ConfigReferenceDocs', // deprecated

@@ -227,3 +282,3 @@ 'features.mockServer': 'ConfigMockServer', // deprecated

},
};
});

@@ -235,6 +290,6 @@ const ConfigApis: NodeType = {

const ConfigApisProperties: NodeType = {
const createConfigApisProperties = (nodeTypes: Record<string, NodeType>): NodeType => ({
...nodeTypes['rootRedoclyConfigSchema.apis_additionalProperties'],
properties: {
...apiConfigSchema.properties,
root: { type: 'string' },
...nodeTypes['rootRedoclyConfigSchema.apis_additionalProperties']?.properties,
labels: {

@@ -249,3 +304,2 @@ type: 'array',

'features.mockServer': 'ConfigMockServer', // deprecated
theme: 'ConfigRootTheme',
files: {

@@ -258,4 +312,3 @@ type: 'array',

},
required: ['root'],
};
});

@@ -273,9 +326,9 @@ const ConfigHTTP: NodeType = {

const ConfigRootTheme: NodeType = {
const createConfigRootTheme = (nodeTypes: Record<string, NodeType>): NodeType => ({
...nodeTypes['rootRedoclyConfigSchema.theme'],
properties: {
...themeConfigSchema.properties,
openapi: 'ConfigReferenceDocs',
mockServer: 'ConfigMockServer',
...nodeTypes['rootRedoclyConfigSchema.theme']?.properties,
openapi: 'ConfigReferenceDocs', // Override theme.openapi with internal format
},
};
});

@@ -314,3 +367,14 @@ const Rules: NodeType = {

properties: {
type: { enum: nodeTypesList },
type: {
enum: [
...new Set([
'any',
...oas2NodeTypesList,
...oas3NodeTypesList,
...oas3_1NodeTypesList,
...asyncNodeTypesList,
'SpecExtension',
]),
],
},
property: (value: unknown) => {

@@ -876,4 +940,5 @@ if (Array.isArray(value)) {

const ConfigReferenceDocs: NodeType = {
// TODO: partially invalid @Viacheslav
properties: {
theme: 'ConfigTheme',
theme: 'ConfigTheme', // TODO: deprecated @Viacheslav
corsProxyUrl: { type: 'string' },

@@ -1009,8 +1074,18 @@ ctrlFHijack: { type: 'boolean' },

export const ConfigTypes: Record<string, NodeType> = {
export const createConfigTypes = (extraSchemas: JSONSchema) => {
// Create types based on external schemas
const nodeTypes = getNodeTypesFromJSONSchema('rootRedoclyConfigSchema', extraSchemas);
return {
...CoreConfigTypes,
ConfigRoot: createConfigRoot(nodeTypes),
ConfigApisProperties: createConfigApisProperties(nodeTypes),
ConfigRootTheme: createConfigRootTheme(nodeTypes),
...nodeTypes,
};
};
const CoreConfigTypes: Record<string, NodeType> = {
Assert,
ConfigRoot,
ConfigApis,
ConfigApisProperties,
RootConfigStyleguide,
ConfigStyleguide,

@@ -1025,3 +1100,2 @@ ConfigReferenceDocs,

ConfigTheme,
ConfigRootTheme,
AssertDefinition,

@@ -1076,3 +1150,4 @@ ThemeColors,

AssertionDefinitionSubject,
...PortalConfigNodeTypes,
};
export const ConfigTypes: Record<string, NodeType> = createConfigTypes(rootRedoclyConfigSchema);

@@ -0,1 +1,3 @@

import type { FromSchema } from 'json-schema-to-ts';
const logoConfigSchema = {

@@ -71,2 +73,7 @@ type: 'object',

},
partialsFolders: {
type: 'array',
items: { type: 'string' },
default: ['_partials'],
},
lastUpdatedBlock: {

@@ -80,3 +87,3 @@ type: 'object',

},
locale: { type: 'string', default: 'en-US' },
locale: { type: 'string' },
...hideConfigSchema.properties,

@@ -192,2 +199,17 @@ },

const productGoogleAnalyticsConfigSchema = {
type: 'object',
properties: {
includeInDevelopment: { type: 'boolean' },
trackingId: { type: 'string' },
conversionId: { type: 'string' },
floodlightId: { type: 'string' },
optimizeId: { type: 'string' },
exclude: { type: 'array', items: { type: 'string' } },
},
additionalProperties: false,
required: ['trackingId'],
} as const;
const googleAnalyticsConfigSchema = {

@@ -209,2 +231,8 @@ type: 'object',

cookieExpires: { type: 'number' },
// All enabled tracking configs
trackers: {
type: 'object',
additionalProperties: productGoogleAnalyticsConfigSchema,
},
},

@@ -231,2 +259,3 @@ additionalProperties: false,

directory: { type: 'string' },
disconnect: { type: 'boolean', default: false },
group: { type: 'string' },

@@ -272,3 +301,3 @@ label: { type: 'string' },

additionalProperties: false,
required: ['name', 'icon', 'folder'],
required: ['name', 'folder'],
} as const;

@@ -296,2 +325,3 @@

parentFilter: { type: 'string' },
valuesMapping: { type: 'object', additionalProperties: { type: 'string' } },
missingCategoryName: { type: 'string' },

@@ -306,5 +336,5 @@ missingCategoryNameTranslationKey: { type: 'string' },

additionalProperties: true,
required: ['levels'],
required: [],
properties: {
failBuildIfBelowMinimum: { type: 'boolean', default: false },
ignoreNonCompliant: { type: 'boolean', default: false },
teamMetadataProperty: {

@@ -325,2 +355,3 @@ type: 'object',

name: { type: 'string' },
color: { type: 'string' },
extends: { type: 'array', items: { type: 'string' } },

@@ -330,3 +361,3 @@ rules: {

additionalProperties: {
type: ['object', 'string'],
oneOf: [{ type: 'string' }, { type: 'object' }],
},

@@ -433,8 +464,2 @@ },

},
seo: {
type: 'object',
properties: {
title: { type: 'string' },
},
},
scripts: {

@@ -458,3 +483,3 @@ type: 'object',

type: 'string',
enum: ['rating', 'sentiment', 'comment', 'reasons'],
enum: ['rating', 'sentiment', 'comment', 'reasons', 'mood', 'scale'],
default: 'sentiment',

@@ -467,11 +492,23 @@ },

submitText: { type: 'string' },
max: { type: 'number' },
buttonText: { type: 'string' },
multi: { type: 'boolean' },
component: {
type: 'string',
enum: ['radio', 'checkbox'],
default: 'checkbox',
},
items: { type: 'array', items: { type: 'string' }, minItems: 1 },
leftScaleLabel: { type: 'string' },
rightScaleLabel: { type: 'string' },
reasons: {
type: 'object',
properties: {
enable: { type: 'boolean', default: true },
multi: { type: 'boolean' },
hide: {
type: 'boolean',
default: false,
},
component: {
type: 'string',
enum: ['radio', 'checkbox'],
default: 'checkbox',
},
label: { type: 'string' },

@@ -485,6 +522,12 @@ items: { type: 'array', items: { type: 'string' } },

properties: {
enable: { type: 'boolean', default: true },
hide: {
type: 'boolean',
default: false,
},
label: { type: 'string' },
likeLabel: { type: 'string' },
dislikeLabel: { type: 'string' },
satisfiedLabel: { type: 'string' },
neutralLabel: { type: 'string' },
dissatisfiedLabel: { type: 'string' },
},

@@ -542,3 +585,3 @@ additionalProperties: false,

properties: {
text: { type: 'string', default: 'Next to {label}' },
text: { type: 'string', default: 'Next to {{label}}' },
...hideConfigSchema.properties,

@@ -552,3 +595,3 @@ },

properties: {
text: { type: 'string', default: 'Back to {label}' },
text: { type: 'string', default: 'Back to {{label}}' },
...hideConfigSchema.properties,

@@ -566,3 +609,3 @@ },

properties: {
controlsStyle: { type: 'string', default: 'icon' },
elementFormat: { type: 'string', default: 'icon' },
copy: {

@@ -579,6 +622,9 @@ type: 'object',

properties: {
tooltipText: { type: 'string' },
buttonText: { type: 'string' },
label: { type: 'string' },
...hideConfigSchema.properties,
},
additionalProperties: false,
default: { hide: true },
default: { hide: false },
},

@@ -606,3 +652,3 @@ expand: {

markdown: markdownConfigSchema,
openapi: { type: 'object', additionalProperties: true },
openapi: { type: 'object', additionalProperties: true }, // TODO: put the real schema here @Viacheslav
graphql: { type: 'object', additionalProperties: true },

@@ -693,2 +739,8 @@ analytics: {

breadcrumbs: themeConfigSchema.properties.breadcrumbs,
analytics: {
type: 'object',
properties: {
ga: productGoogleAnalyticsConfigSchema,
},
},
},

@@ -699,6 +751,52 @@ additionalProperties: true,

export enum ScorecardStatus {
BelowMinimum = 'Below minimum',
Highest = 'Highest',
Minimum = 'Minimum',
}
export type ThemeConfig = FromSchema<typeof themeConfigSchema>;
// TODO: cannot export as it relies on external types
// export type ThemeUIConfig = ThemeConfig & {
// auth?: {
// // used by portal dev login emulator
// idpsInfo?: {
// idpId: string;
// type: string; // AuthProviderType
// title: string | undefined;
// }[];
// devLogin?: boolean;
// loginUrls?: Record<string, string>;
// };
// search?: {
// shortcuts?: string[];
// suggestedPages?: any[];
// };
// breadcrumbs?: {
// prefixItems?: ResolvedNavLinkItem[];
// };
// products?: {
// [key: string]: ProductUiConfig;
// };
// };
export type ProductConfig = FromSchema<typeof productConfigSchema>;
export type ProductGoogleAnalyticsConfig = FromSchema<typeof productGoogleAnalyticsConfigSchema>;
// TODO: cannot export as it relies on external types
// export type ProductThemeOverrideConfig = Pick<
// ThemeUIConfig,
// 'logo' | 'navbar' | 'footer' | 'sidebar' | 'search' | 'codeSnippet' | 'breadcrumbs'
// > & { analytics?: { ga?: ProductGoogleAnalyticsConfig } };
// export type ProductUiConfig = ProductConfig & {
// slug: string;
// link: string;
// [REDOCLY_TEAMS_RBAC]?: { [key: string]: string };
// themeOverride?: ProductThemeOverrideConfig;
// };
export type MarkdownConfig = FromSchema<typeof markdownConfigSchema>;
export type AmplitudeAnalyticsConfig = FromSchema<typeof amplitudeAnalyticsConfigSchema>;
export type RudderstackAnalyticsConfig = FromSchema<typeof rudderstackAnalyticsConfigSchema>;
export type SegmentAnalyticsConfig = FromSchema<typeof segmentAnalyticsConfigSchema>;
export type GtmAnalyticsConfig = FromSchema<typeof gtmAnalyticsConfigSchema>;
export type GoogleAnalyticsConfig = FromSchema<typeof googleAnalyticsConfigSchema>;
export type CatalogConfig = FromSchema<typeof catalogSchema>;
export type CatalogFilterConfig = FromSchema<typeof catalogFilterSchema>;
export type ScorecardConfig = FromSchema<typeof scorecardConfigSchema>;

@@ -40,7 +40,7 @@ import * as fs from 'fs';

export function isPlainObject(value: any): value is object {
export function isPlainObject(value: any): value is Record<string, unknown> {
return value !== null && typeof value === 'object' && !Array.isArray(value);
}
export function isEmptyObject(value: any): value is object {
export function isEmptyObject(value: any): value is Record<string, unknown> {
return isPlainObject(value) && Object.keys(value).length === 0;

@@ -47,0 +47,0 @@ }

@@ -362,3 +362,3 @@ import { SpecExtension } from './types';

}
if (from.items) {
if (from.items && typeof from.items !== 'function') {
if (from.items === to) {

@@ -365,0 +365,0 @@ addWeakFromStack(ruleConf, stack);

@@ -274,4 +274,10 @@ import { Location, isRef } from './ref-utils';

if (itemsType !== undefined) {
const isTypeAFunction = typeof itemsType === 'function';
for (let i = 0; i < resolvedNode.length; i++) {
walkNode(resolvedNode[i], itemsType, resolvedLocation.child([i]), resolvedNode, i);
const itemType = isTypeAFunction
? itemsType(resolvedNode[i], resolvedLocation.child([i]).absolutePointer)
: itemsType;
if (isNamedType(itemType)) {
walkNode(resolvedNode[i], itemType, resolvedLocation.child([i]), resolvedNode, i);
}
}

@@ -278,0 +284,0 @@ }

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc