From 0ea1b59f7ee4887ef8387abf28ab4c9b94236323 Mon Sep 17 00:00:00 2001 From: Andrew Tatomyr Date: Thu, 14 Sep 2023 11:38:57 +0300 Subject: [PATCH] fix: update redocly.yaml validation (#1259) --- .changeset/long-rabbits-camp.md | 6 + .../deprecated-apiDefinitions/snapshot.js | 2 + __tests__/lint/deprecated-lint/snapshot.js | 2 + packages/core/src/__tests__/lint.test.ts | 2 + .../core/src/types/portal-config-schema.ts | 343 +++++++++++++++++ packages/core/src/types/redocly-yaml.ts | 54 +-- ...ig-external-schemas.ts => theme-config.ts} | 354 +++--------------- 7 files changed, 435 insertions(+), 328 deletions(-) create mode 100644 .changeset/long-rabbits-camp.md create mode 100644 packages/core/src/types/portal-config-schema.ts rename packages/core/src/types/{config-external-schemas.ts => theme-config.ts} (65%) diff --git a/.changeset/long-rabbits-camp.md b/.changeset/long-rabbits-camp.md new file mode 100644 index 000000000..8a8f8f56a --- /dev/null +++ b/.changeset/long-rabbits-camp.md @@ -0,0 +1,6 @@ +--- +'@redocly/openapi-core': patch +'@redocly/cli': patch +--- + +Updated Redocly config validation. diff --git a/__tests__/lint/deprecated-apiDefinitions/snapshot.js b/__tests__/lint/deprecated-apiDefinitions/snapshot.js index e09d2edd1..efd0848a8 100644 --- a/__tests__/lint/deprecated-apiDefinitions/snapshot.js +++ b/__tests__/lint/deprecated-apiDefinitions/snapshot.js @@ -18,6 +18,8 @@ Warning was generated by the configuration spec rule. Property \`lint\` is not expected here. +Did you mean: env ? + 1 | apiDefinitions: 2 | main: ./openapi.yaml 3 | lint: diff --git a/__tests__/lint/deprecated-lint/snapshot.js b/__tests__/lint/deprecated-lint/snapshot.js index 464b2942b..d9924ab4c 100644 --- a/__tests__/lint/deprecated-lint/snapshot.js +++ b/__tests__/lint/deprecated-lint/snapshot.js @@ -6,6 +6,8 @@ exports[`E2E lint deprecated-lint 1`] = ` Property \`lint\` is not expected here. +Did you mean: env ? + 5 | rules: 6 | operation-4xx-response: error 7 | lint: diff --git a/packages/core/src/__tests__/lint.test.ts b/packages/core/src/__tests__/lint.test.ts index 8a885bab4..fb3575bb4 100644 --- a/packages/core/src/__tests__/lint.test.ts +++ b/packages/core/src/__tests__/lint.test.ts @@ -111,6 +111,7 @@ describe('lint', () => { "severity": "error", "suggest": Array [ "theme", + "env", "seo", "sso", ], @@ -178,6 +179,7 @@ describe('lint', () => { "apis", "seo", "sso", + "env", ], }, ] diff --git a/packages/core/src/types/portal-config-schema.ts b/packages/core/src/types/portal-config-schema.ts new file mode 100644 index 000000000..182d51087 --- /dev/null +++ b/packages/core/src/types/portal-config-schema.ts @@ -0,0 +1,343 @@ +import { + ApigeeDevOnboardingIntegrationAuthType, + AuthProviderType, + DEFAULT_TEAM_CLAIM_NAME, +} from '../config'; + +const oidcIssuerMetadataSchema = { + type: 'object', + properties: { + end_session_endpoint: { type: 'string' }, + token_endpoint: { type: 'string' }, + authorization_endpoint: { type: 'string' }, + jwks_uri: { type: 'string' }, + }, + required: ['token_endpoint', 'authorization_endpoint'], + additionalProperties: true, +} as const; + +const oidcProviderConfigSchema = { + type: 'object', + properties: { + type: { type: 'string', const: AuthProviderType.OIDC }, + title: { type: 'string' }, + configurationUrl: { type: 'string', minLength: 1 }, + configuration: oidcIssuerMetadataSchema, + clientId: { type: 'string', minLength: 1 }, + clientSecret: { type: 'string', minLength: 1 }, + teamsClaimName: { type: 'string' }, + teamsClaimMap: { type: 'object', additionalProperties: { type: 'string' } }, + defaultTeams: { type: 'array', items: { type: 'string' } }, + scopes: { type: 'array', items: { type: 'string' } }, + tokenExpirationTime: { type: 'number' }, + authorizationRequestCustomParams: { type: 'object', additionalProperties: { type: 'string' } }, + tokenRequestCustomParams: { type: 'object', additionalProperties: { type: 'string' } }, + audience: { type: 'array', items: { type: 'string' } }, + }, + required: ['type', 'clientId', 'clientSecret'], + oneOf: [{ required: ['configurationUrl'] }, { required: ['configuration'] }], + additionalProperties: false, +} as const; + +const saml2ProviderConfigSchema = { + type: 'object', + properties: { + type: { type: 'string', const: AuthProviderType.SAML2 }, + title: { type: 'string' }, + issuerId: { type: 'string' }, + entityId: { type: 'string' }, + ssoUrl: { type: 'string' }, + x509PublicCert: { type: 'string' }, + teamsAttributeName: { type: 'string', default: DEFAULT_TEAM_CLAIM_NAME }, + teamsAttributeMap: { type: 'object', additionalProperties: { type: 'string' } }, + defaultTeams: { type: 'array', items: { type: 'string' } }, + }, + additionalProperties: false, + required: ['type', 'issuerId', 'ssoUrl', 'x509PublicCert'], +} as const; + +const basicAuthProviderConfigSchema = { + type: 'object', + properties: { + type: { type: 'string', const: AuthProviderType.BASIC }, + title: { type: 'string' }, + credentials: { + type: 'array', + items: { + type: 'object', + properties: { + username: { type: 'string' }, + password: { type: 'string' }, + passwordHash: { type: 'string' }, + teams: { type: 'array', items: { type: 'string' } }, + }, + required: ['username'], + additionalProperties: false, + }, + }, + }, + required: ['type', 'credentials'], + additionalProperties: false, +} as const; + +const authProviderConfigSchema = { + oneOf: [oidcProviderConfigSchema, saml2ProviderConfigSchema, basicAuthProviderConfigSchema], + discriminator: { propertyName: 'type' }, +} as const; + +export const ssoConfigSchema = { + type: 'object', + additionalProperties: authProviderConfigSchema, +} as const; + +const redirectConfigSchema = { + type: 'object', + properties: { + to: { type: 'string' }, + type: { type: 'number', default: 301 }, + }, + required: ['to'], + additionalProperties: false, +} as const; + +export const apiConfigSchema = { + type: 'object', + properties: { + root: { type: 'string' }, + rbac: { type: 'object', additionalProperties: true }, + theme: { + type: 'object', + properties: { + openapi: { type: 'object', additionalProperties: true }, + }, + additionalProperties: false, + }, + title: { type: 'string' }, + metadata: { type: 'object', additionalProperties: true }, + }, + additionalProperties: true, + required: ['root'], +} as const; + +const metadataConfigSchema = { + type: 'object', + additionalProperties: true, +} as const; + +const seoConfigSchema = { + type: 'object', + properties: { + title: { type: 'string' }, + description: { type: 'string' }, + siteUrl: { type: 'string' }, + image: { type: 'string' }, + keywords: { type: 'array', items: { type: 'string' } }, + lang: { type: 'string' }, + jsonLd: { type: 'object' }, + meta: { + type: 'array', + items: { + type: 'object', + properties: { + name: { type: 'string' }, + content: { type: 'string' }, + }, + required: ['name', 'content'], + additionalProperties: false, + }, + }, + }, + additionalProperties: false, +} as const; + +const rbacScopeItemsSchema = { type: 'object', additionalProperties: { type: 'string' } } as const; + +const rbacConfigSchema = { + type: 'object', + properties: { + defaults: rbacScopeItemsSchema, + }, + additionalProperties: rbacScopeItemsSchema, +} as const; + +const graviteeAdapterConfigSchema = { + type: 'object', + properties: { + type: { type: 'string', const: 'GRAVITEE' }, + apiBaseUrl: { type: 'string' }, + env: { type: 'string' }, + allowApiProductsOutsideCatalog: { type: 'boolean', default: false }, + stage: { type: 'string', default: 'non-production' }, + + auth: { type: 'object', properties: { static: { type: 'string' } } }, + }, + additionalProperties: false, + required: ['type', 'apiBaseUrl'], +} as const; + +const apigeeAdapterAuthOauth2Schema = { + type: 'object', + properties: { + type: { type: 'string', const: ApigeeDevOnboardingIntegrationAuthType.OAUTH2 }, + tokenEndpoint: { type: 'string' }, + clientId: { type: 'string' }, + clientSecret: { type: 'string' }, + }, + additionalProperties: false, + required: ['type', 'tokenEndpoint', 'clientId', 'clientSecret'], +} as const; + +const apigeeAdapterAuthServiceAccountSchema = { + type: 'object', + properties: { + type: { type: 'string', const: ApigeeDevOnboardingIntegrationAuthType.SERVICE_ACCOUNT }, + serviceAccountEmail: { type: 'string' }, + serviceAccountPrivateKey: { type: 'string' }, + }, + additionalProperties: false, + required: ['type', 'serviceAccountEmail', 'serviceAccountPrivateKey'], +} as const; + +const apigeeXAdapterConfigSchema = { + type: 'object', + properties: { + type: { type: 'string', const: 'APIGEE_X' }, + apiUrl: { type: 'string' }, + stage: { type: 'string', default: 'non-production' }, + organizationName: { type: 'string' }, + ignoreApiProducts: { type: 'array', items: { type: 'string' } }, + allowApiProductsOutsideCatalog: { type: 'boolean', default: false }, + auth: { + type: 'object', + oneOf: [apigeeAdapterAuthOauth2Schema, apigeeAdapterAuthServiceAccountSchema], + discriminator: { propertyName: 'type' }, + }, + }, + additionalProperties: false, + required: ['type', 'organizationName', 'auth'], +} as const; + +const apigeeEdgeAdapterConfigSchema = { + ...apigeeXAdapterConfigSchema, + properties: { + ...apigeeXAdapterConfigSchema.properties, + type: { type: 'string', const: 'APIGEE_EDGE' }, + }, +} as const; + +const devOnboardingAdapterConfigSchema = { + type: 'object', + oneOf: [apigeeXAdapterConfigSchema, apigeeEdgeAdapterConfigSchema, graviteeAdapterConfigSchema], + discriminator: { propertyName: 'type' }, +} as const; + +const devOnboardingConfigSchema = { + type: 'object', + required: ['adapters'], + additionalProperties: false, + properties: { + adapters: { + type: 'array', + items: devOnboardingAdapterConfigSchema, + }, + }, +} as const; + +const responseHeaderSchema = { + type: 'object', + properties: { + name: { type: 'string' }, + value: { type: 'string' }, + }, + additionalProperties: false, + required: ['name', 'value'], +} as const; + +export const redoclyConfigSchema = { + type: 'object', + properties: { + licenseKey: { type: 'string' }, + theme: { type: 'object', default: {} }, // ThemeConfig + redirects: { type: 'object', additionalProperties: redirectConfigSchema, default: {} }, + seo: seoConfigSchema, + rbac: rbacConfigSchema, + responseHeaders: { + type: 'object', + additionalProperties: { + type: 'array', + items: responseHeaderSchema, + }, + }, + mockServer: { + type: 'object', + properties: { + off: { type: 'boolean', default: false }, + position: { type: 'string', enum: ['first', 'last', 'replace', 'off'], default: 'first' }, + strictExamples: { type: 'boolean', default: false }, + errorIfForcedExampleNotFound: { type: 'boolean', default: false }, + description: { type: 'string' }, + }, + }, + apis: { + type: 'object', + additionalProperties: apiConfigSchema, + }, + sso: ssoConfigSchema, + developerOnboarding: devOnboardingConfigSchema, + i18n: { + type: 'object', + properties: { + defaultLocale: { + type: 'string', + }, + locales: { + type: 'array', + items: { + type: 'object', + properties: { + code: { + type: 'string', + }, + name: { + type: 'string', + }, + }, + required: ['code'], + }, + }, + }, + additionalProperties: false, + required: ['defaultLocale', 'locales'], + }, + metadata: metadataConfigSchema, + }, + default: {}, + additionalProperties: true, +} as const; + +export const environmentSchema = { + oneOf: [ + { ...redoclyConfigSchema, additionalProperties: false }, + { + type: 'object', + properties: { + $ref: { type: 'string' }, + }, + required: ['$ref'], + additionalProperties: false, + }, + ], +} as const; + +export const rootRedoclyConfigSchema = { + ...redoclyConfigSchema, + properties: { + ...redoclyConfigSchema.properties, + env: { + type: 'object', + additionalProperties: environmentSchema, + }, + }, + default: {}, + required: ['redirects'], +} as const; diff --git a/packages/core/src/types/redocly-yaml.ts b/packages/core/src/types/redocly-yaml.ts index e19dd277b..ee20912e3 100644 --- a/packages/core/src/types/redocly-yaml.ts +++ b/packages/core/src/types/redocly-yaml.ts @@ -1,15 +1,7 @@ -import { - devOnboardingConfigSchema, - i18nConfigSchema, - mockServerConfigSchema, - rbacConfigSchema, - redirectConfigSchema, - responseHeaderSchema, - seoConfigSchema, - ssoConfigSchema, - themeConfigSchema, -} from './config-external-schemas'; +import { rootRedoclyConfigSchema, apiConfigSchema } from './portal-config-schema'; +import { themeConfigSchema } from './theme-config'; import { NodeType, listOf } from '.'; +import { Oas3_1Types } from './oas3_1'; import { omitObjectProps, pickObjectProps, isCustomRuleId } from '../utils'; const builtInRulesList = [ @@ -68,6 +60,7 @@ const builtInRulesList = [ 'spec-strict-refs', 'component-name-unique', ]; + const nodeTypesList = [ 'any', 'Root', @@ -165,12 +158,13 @@ const RootConfigStyleguide: NodeType = { const ConfigRoot: NodeType = { properties: { - organization: { type: 'string' }, - apis: 'ConfigApis', + ...rootRedoclyConfigSchema.properties, ...RootConfigStyleguide.properties, + apis: 'ConfigApis', theme: 'ConfigRootTheme', 'features.openapi': 'ConfigReferenceDocs', // deprecated 'features.mockServer': 'ConfigMockServer', // deprecated + organization: { type: 'string' }, region: { enum: ['us', 'eu'] }, telemetry: { enum: ['on', 'off'] }, resolve: { @@ -185,15 +179,6 @@ const ConfigRoot: NodeType = { type: 'string', }, }, - redirects: { type: 'object', additionalProperties: redirectConfigSchema }, - licenseKey: { type: 'string' }, - seo: seoConfigSchema, - rbac: rbacConfigSchema, - responseHeaders: responseHeaderSchema, - mockServer: mockServerConfigSchema, - sso: ssoConfigSchema, - developerOnboarding: devOnboardingConfigSchema, - i18n: i18nConfigSchema, }, }; @@ -204,6 +189,7 @@ const ConfigApis: NodeType = { const ConfigApisProperties: NodeType = { properties: { + ...apiConfigSchema.properties, root: { type: 'string' }, labels: { type: 'array', @@ -223,9 +209,6 @@ const ConfigApisProperties: NodeType = { type: 'string', }, }, - title: { type: 'string' }, - rbac: { type: 'object' }, - metadata: { type: 'object' }, }, required: ['root'], }; @@ -263,6 +246,8 @@ const Rules: NodeType = { } else { return 'ObjectRule'; } + } else if (key === 'metadata-schema' || key === 'custom-fields-schema') { + return 'Schema'; } // Otherwise is considered as invalid return; @@ -572,7 +557,7 @@ const TryItButton: NodeType = { }, }; -const Components: NodeType = { +const ConfigThemeComponents: NodeType = { properties: { buttons: 'ButtonsConfig', httpBadges: 'HttpBadgesConfig', @@ -619,7 +604,7 @@ const SchemaColorsConfig: NodeType = { }, }; -const Schema: NodeType = { +const ConfigThemeSchema: NodeType = { properties: { breakFieldNames: { type: 'boolean' }, caretColor: { type: 'string' }, @@ -759,7 +744,7 @@ const CodeBlock: NodeType = { }, }; -const Logo: NodeType = { +const ConfigThemeLogo: NodeType = { properties: { gutter: { type: 'string' }, maxHeight: { type: 'string' }, @@ -815,13 +800,13 @@ const ConfigTheme: NodeType = { breakpoints: 'Breakpoints', codeBlock: 'CodeBlock', colors: 'ThemeColors', - components: 'Components', + components: 'ConfigThemeComponents', layout: 'Layout', - logo: 'Logo', + logo: 'ConfigThemeLogo', fab: 'Fab', overrides: 'Overrides', rightPanel: 'RightPanel', - schema: 'Schema', + schema: 'ConfigThemeSchema', shape: 'Shape', sidebar: 'Sidebar', spacing: 'ThemeSpacing', @@ -973,6 +958,7 @@ const ConfigMockServer: NodeType = { }; export const ConfigTypes: Record = { + ...Oas3_1Types, Assert, ConfigRoot, ConfigApis, @@ -1018,7 +1004,7 @@ export const ConfigTypes: Record = { LinksConfig, TokenProps, CodeBlock, - Logo, + ConfigThemeLogo, Fab, ButtonOverrides, Overrides, @@ -1029,9 +1015,9 @@ export const ConfigTypes: Record = { ThemeSpacing, GenerateCodeSamples, GroupItemsConfig, - Components, + ConfigThemeComponents, Layout, - Schema, + ConfigThemeSchema, Sidebar, Heading, Typography, diff --git a/packages/core/src/types/config-external-schemas.ts b/packages/core/src/types/theme-config.ts similarity index 65% rename from packages/core/src/types/config-external-schemas.ts rename to packages/core/src/types/theme-config.ts index 7c0a97002..f679b7552 100644 --- a/packages/core/src/types/config-external-schemas.ts +++ b/packages/core/src/types/theme-config.ts @@ -1,271 +1,8 @@ -import { - ApigeeDevOnboardingIntegrationAuthType, - AuthProviderType, - DEFAULT_TEAM_CLAIM_NAME, -} from '../config'; - -const oidcIssuerMetadataSchema = { - type: 'object', - properties: { - end_session_endpoint: { type: 'string' }, - token_endpoint: { type: 'string' }, - authorization_endpoint: { type: 'string' }, - }, - required: ['token_endpoint', 'authorization_endpoint'], - additionalProperties: true, -} as const; - -const oidcProviderConfigSchema = { - type: 'object', - properties: { - type: { type: 'string', const: AuthProviderType.OIDC }, - title: { type: 'string' }, - configurationUrl: { type: 'string', minLength: 1 }, - configuration: oidcIssuerMetadataSchema, - clientId: { type: 'string', minLength: 1 }, - clientSecret: { type: 'string', minLength: 1 }, - teamsClaimName: { type: 'string' }, - defaultTeams: { type: 'array', items: { type: 'string' } }, - scopes: { type: 'array', items: { type: 'string' } }, - tokenExpirationTime: { type: 'number' }, - authorizationRequestCustomParams: { type: 'object', additionalProperties: { type: 'string' } }, - tokenRequestCustomParams: { type: 'object', additionalProperties: { type: 'string' } }, - }, - required: ['type', 'clientId', 'clientSecret'], - oneOf: [{ required: ['configurationUrl'] }, { required: ['configuration'] }], - additionalProperties: false, -} as const; - -const saml2ProviderConfigSchema = { - type: 'object', - properties: { - type: { type: 'string', const: AuthProviderType.SAML2 }, - title: { type: 'string' }, - issuerId: { type: 'string' }, - entityId: { type: 'string' }, - ssoUrl: { type: 'string' }, - x509PublicCert: { type: 'string' }, - teamsAttributeName: { type: 'string', default: DEFAULT_TEAM_CLAIM_NAME }, - teamsAttributeMap: { type: 'object', additionalProperties: { type: 'string' } }, - defaultTeams: { type: 'array', items: { type: 'string' } }, - }, - additionalProperties: false, - required: ['type', 'issuerId', 'ssoUrl', 'x509PublicCert'], -} as const; - -const basicAuthProviderConfigSchema = { - type: 'object', - properties: { - type: { type: 'string', const: AuthProviderType.BASIC }, - title: { type: 'string' }, - credentials: { - type: 'array', - items: { - type: 'object', - properties: { - username: { type: 'string' }, - password: { type: 'string' }, - passwordHash: { type: 'string' }, - teams: { type: 'array', items: { type: 'string' } }, - }, - required: ['username'], - additionalProperties: false, - }, - }, - }, - required: ['type', 'credentials'], - additionalProperties: false, -} as const; - -const authProviderConfigSchema = { - oneOf: [oidcProviderConfigSchema, saml2ProviderConfigSchema, basicAuthProviderConfigSchema], - discriminator: { propertyName: 'type' }, -} as const; - -const rbacScopeItemsSchema = { type: 'object', additionalProperties: { type: 'string' } } as const; - -export const rbacConfigSchema = { - type: 'object', - properties: { - defaults: rbacScopeItemsSchema, - }, - additionalProperties: rbacScopeItemsSchema, -} as const; - -export const ssoConfigSchema = { - type: 'object', - additionalProperties: authProviderConfigSchema, -} as const; - -export const redirectConfigSchema = { - type: 'object', - properties: { - to: { type: 'string' }, - type: { type: 'number', default: 301 }, - }, - required: ['to'], - additionalProperties: false, -} as const; - -export const seoConfigSchema = { - type: 'object', - properties: { - title: { type: 'string' }, - description: { type: 'string' }, - siteUrl: { type: 'string' }, - image: { type: 'string' }, - keywords: { type: 'array', items: { type: 'string' } }, - lang: { type: 'string' }, - jsonLd: { type: 'object' }, - meta: { - type: 'array', - items: { - type: 'object', - properties: { - name: { type: 'string' }, - content: { type: 'string' }, - }, - required: ['name', 'content'], - additionalProperties: false, - }, - }, - }, - additionalProperties: false, -} as const; - -const apigeeAdapterAuthOauth2Schema = { - type: 'object', - properties: { - type: { type: 'string', const: ApigeeDevOnboardingIntegrationAuthType.OAUTH2 }, - tokenEndpoint: { type: 'string' }, - clientId: { type: 'string' }, - clientSecret: { type: 'string' }, - }, - additionalProperties: false, - required: ['type', 'tokenEndpoint', 'clientId', 'clientSecret'], -} as const; - -const apigeeAdapterAuthServiceAccountSchema = { - type: 'object', - properties: { - type: { type: 'string', const: ApigeeDevOnboardingIntegrationAuthType.SERVICE_ACCOUNT }, - serviceAccountEmail: { type: 'string' }, - serviceAccountPrivateKey: { type: 'string' }, - }, - additionalProperties: false, - required: ['type', 'serviceAccountEmail', 'serviceAccountPrivateKey'], -} as const; - -const apigeeXAdapterConfigSchema = { - type: 'object', - properties: { - type: { type: 'string', const: 'APIGEE_X' }, - apiUrl: { type: 'string' }, - stage: { type: 'string', default: 'non-production' }, - organizationName: { type: 'string' }, - ignoreApiProducts: { type: 'array', items: { type: 'string' } }, - allowApiProductsOutsideCatalog: { type: 'boolean', default: false }, - auth: { - type: 'object', - oneOf: [apigeeAdapterAuthOauth2Schema, apigeeAdapterAuthServiceAccountSchema], - discriminator: { propertyName: 'type' }, - }, - }, - additionalProperties: false, - required: ['type', 'organizationName', 'auth'], -} as const; - -const apigeeEdgeAdapterConfigSchema = { - ...apigeeXAdapterConfigSchema, - properties: { - ...apigeeXAdapterConfigSchema.properties, - type: { type: 'string', const: 'APIGEE_EDGE' }, - }, -} as const; - -const graviteeAdapterConfigSchema = { - type: 'object', - properties: { - type: { type: 'string', const: 'GRAVITEE' }, - apiBaseUrl: { type: 'string' }, - env: { type: 'string' }, - allowApiProductsOutsideCatalog: { type: 'boolean', default: false }, - stage: { type: 'string', default: 'non-production' }, - - auth: { type: 'object', properties: { static: { type: 'string' } } }, - }, - additionalProperties: false, - required: ['type', 'apiBaseUrl'], -} as const; - -const devOnboardingAdapterConfigSchema = { - type: 'object', - oneOf: [apigeeXAdapterConfigSchema, apigeeEdgeAdapterConfigSchema, graviteeAdapterConfigSchema], - discriminator: { propertyName: 'type' }, -} as const; - -export const devOnboardingConfigSchema = { - type: 'object', - required: ['adapters'], - additionalProperties: false, - properties: { - adapters: { - type: 'array', - items: devOnboardingAdapterConfigSchema, - }, - }, -} as const; - -export const responseHeaderSchema = { - type: 'object', - properties: { - name: { type: 'string' }, - value: { type: 'string' }, - }, - additionalProperties: false, - required: ['name', 'value'], -} as const; - -export const i18nConfigSchema = { - type: 'object', - properties: { - defaultLocale: { - type: 'string', - }, - locales: { - type: 'array', - items: { - type: 'object', - properties: { - code: { - type: 'string', - }, - name: { - type: 'string', - }, - }, - required: ['code'], - }, - }, - }, - required: ['defaultLocale', 'locales'], -} as const; - -export const mockServerConfigSchema = { - type: 'object', - properties: { - off: { type: 'boolean', default: false }, - position: { type: 'string', enum: ['first', 'last', 'replace', 'off'], default: 'first' }, - strictExamples: { type: 'boolean', default: false }, - errorIfForcedExampleNotFound: { type: 'boolean', default: false }, - description: { type: 'string' }, - }, -} as const; - const logoConfigSchema = { type: 'object', properties: { image: { type: 'string' }, + srcSet: { type: 'string' }, altText: { type: 'string' }, link: { type: 'string' }, favicon: { type: 'string' }, @@ -359,8 +96,6 @@ const markdownConfigSchema = { type: 'object', properties: { baseUrl: { type: 'string' }, - icon: { type: 'string' }, - text: { type: 'string', default: 'Edit this page' }, ...hideConfigSchema.properties, }, additionalProperties: false, @@ -457,37 +192,17 @@ const googleAnalyticsConfigSchema = { properties: { includeInDevelopment: { type: 'boolean' }, trackingId: { type: 'string' }, + + conversionId: { type: 'string' }, + floodlightId: { type: 'string' }, + head: { type: 'boolean' }, respectDNT: { type: 'boolean' }, - anonymize: { type: 'boolean' }, exclude: { type: 'array', items: { type: 'string' } }, - optimizeId: { type: 'string' }, - experimentId: { type: 'string' }, - variationId: { type: 'string' }, - enableWebVitalsTracking: { type: 'boolean' }, - defer: { type: 'boolean' }, - sampleRate: { type: 'number' }, - name: { type: 'string' }, - clientId: { type: 'string' }, - siteSpeedSampleRate: { type: 'number' }, - alwaysSendReferrer: { type: 'boolean' }, - allowAnchor: { type: 'boolean' }, - cookieName: { type: 'string' }, - cookieFlags: { type: 'string' }, - cookieDomain: { type: 'string' }, + optimizeId: { type: 'string' }, + anonymizeIp: { type: 'boolean' }, cookieExpires: { type: 'number' }, - storeGac: { type: 'boolean' }, - legacyCookieDomain: { type: 'string' }, - legacyHistoryImport: { type: 'boolean' }, - allowLinker: { type: 'boolean' }, - storage: { type: 'string' }, - - allowAdFeatures: { type: 'boolean' }, - dataSource: { type: 'string' }, - queueTime: { type: 'number' }, - forceSSL: { type: 'boolean' }, - transport: { type: 'string' }, }, additionalProperties: false, required: ['trackingId'], @@ -513,6 +228,11 @@ const navItemSchema = { label: { type: 'string' }, separator: { type: 'string' }, separatorLine: { type: 'boolean' }, + linePosition: { + type: 'string', + enum: ['top', 'bottom'], + default: 'top', + }, version: { type: 'string' }, menuStyle: { type: 'string', enum: ['drilldown'] }, expanded: { type: 'string', const: 'always' }, @@ -579,6 +299,14 @@ const scorecardConfigSchema = { required: ['levels'], properties: { failBuildIfBelowMinimum: { type: 'boolean', default: false }, + teamMetadataProperty: { + type: 'object', + properties: { + property: { type: 'string' }, + label: { type: 'string' }, + default: { type: 'string' }, + }, + }, levels: { type: 'array', items: { @@ -622,11 +350,15 @@ const scorecardConfigSchema = { const catalogSchema = { type: 'object', additionalProperties: true, - required: ['slug', 'filters', 'groupByFirstFilter', 'items'], + required: ['slug', 'items'], properties: { slug: { type: 'string' }, filters: { type: 'array', items: catalogFilterSchema }, groupByFirstFilter: { type: 'boolean' }, + filterValuesCasing: { + type: 'string', + enum: ['sentence', 'original', 'lowercase', 'uppercase'], + }, items: navItemsSchema, requiredPermission: { type: 'string' }, separateVersions: { type: 'boolean' }, @@ -670,11 +402,30 @@ export const themeConfigSchema = { properties: { items: navItemsSchema, copyrightText: { type: 'string' }, + logo: hideConfigSchema, ...hideConfigSchema.properties, }, additionalProperties: false, }, - sidebar: hideConfigSchema, + sidebar: { + type: 'object', + properties: { + separatorLine: { type: 'boolean' }, + linePosition: { + type: 'string', + enum: ['top', 'bottom'], + default: 'bottom', + }, + ...hideConfigSchema.properties, + }, + additionalProperties: false, + }, + seo: { + type: 'object', + properties: { + title: { type: 'string' }, + }, + }, scripts: { type: 'object', properties: { @@ -873,6 +624,15 @@ export const themeConfigSchema = { additionalProperties: false, default: {}, }, + versionPicker: { + type: 'object', + properties: { + hide: { type: 'boolean' }, + showForUnversioned: { + type: 'boolean', + }, + }, + }, breadcrumbs: { type: 'object', properties: { @@ -915,3 +675,9 @@ export const productThemeOverrideSchema = { additionalProperties: true, default: {}, } as const; + +export enum ScorecardStatus { + BelowMinimum = 'Below minimum', + Highest = 'Highest', + Minimum = 'Minimum', +}