From d5ce09e7e1f5006a63d890850f46f4fc3dac0152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ro=C5=BCek?= Date: Fri, 14 Oct 2022 15:51:51 +0200 Subject: [PATCH] feat(ruleset-migrator): relax validation (#2307) --- .../src/__tests__/ruleset.test.ts | 22 +-- .../src/transformers/formats.ts | 29 +++- .../ruleset-migrator/src/validation/schema.ts | 55 ------- .../ruleset-migrator/src/validation/types.ts | 155 +----------------- 4 files changed, 40 insertions(+), 221 deletions(-) diff --git a/packages/ruleset-migrator/src/__tests__/ruleset.test.ts b/packages/ruleset-migrator/src/__tests__/ruleset.test.ts index 4f41b3d7a..71d7a8a01 100644 --- a/packages/ruleset-migrator/src/__tests__/ruleset.test.ts +++ b/packages/ruleset-migrator/src/__tests__/ruleset.test.ts @@ -149,16 +149,18 @@ describe('migrator', () => { `); }); - describe('error handling', () => { - it('given unknown format, should throw', async () => { - await vol.promises.writeFile(path.join(cwd, 'unknown-format.json'), `{ "formats": ["json-schema-draft-2"] }`); - await expect( - migrateRuleset(path.join(cwd, 'unknown-format.json'), { - format: 'esm', - fs: vol as any, - }), - ).rejects.toThrow('Invalid ruleset provided'); - }); + it('given an unknown format, should not throw', async () => { + await vol.promises.writeFile(path.join(cwd, 'unknown-format.json'), `{ "formats": ["json-schema-draft-2"] }`); + await expect( + migrateRuleset(path.join(cwd, 'unknown-format.json'), { + format: 'esm', + fs: vol as any, + }), + ).resolves.toEqual(`import {jsonSchemaDraft2} from "@stoplight/spectral-formats"; +export default { + "formats": [jsonSchemaDraft2] +}; +`); }); it('should follow links correctly', async () => { diff --git a/packages/ruleset-migrator/src/transformers/formats.ts b/packages/ruleset-migrator/src/transformers/formats.ts index decef6352..9a004cdc8 100644 --- a/packages/ruleset-migrator/src/transformers/formats.ts +++ b/packages/ruleset-migrator/src/transformers/formats.ts @@ -2,15 +2,36 @@ import { builders as b, namedTypes } from 'ast-types'; import { Transformer, TransformerCtx } from '../types'; import { assertArray, assertString } from '../validation'; -import schema from '../validation/schema'; - const ALIASES: Record = { 'json-schema-2019-09': 'json-schema-draft-2019-09', 'json-schema-2020-12': 'json-schema-draft-2020-12', }; +const FORMATS = [ + 'oas2', + 'oas3', + 'oas3.0', + 'oas3.1', + 'asyncapi2', + 'json-schema', + 'json-schema-loose', + 'json-schema-draft4', + 'json-schema-draft6', + 'json-schema-draft7', + 'json-schema-draft-2019-09', + 'json-schema-2019-09', + 'json-schema-draft-2020-12', + 'json-schema-2020-12', +]; + +function safeFormat(format: string): string { + return format + .replace(/\.|(?<=[0-9])-(?=[0-9])/g, '_') + .replace(/-([0-9a-z])/g, (match, char) => String(char).toUpperCase()); +} + const REPLACEMENTS = Object.fromEntries( - schema.properties.formats.items.enum.map(format => [ + FORMATS.map(format => [ format, (ALIASES[format] ?? format) .replace(/\.|(?<=[0-9])-(?=[0-9])/g, '_') @@ -26,7 +47,7 @@ function transform(input: unknown, ctx: TransformerCtx): namedTypes.ArrayExpress new Set( input.map(format => { assertString(format); - return ctx.tree.addImport(REPLACEMENTS[format], '@stoplight/spectral-formats'); + return ctx.tree.addImport(REPLACEMENTS[format] ?? safeFormat(format), '@stoplight/spectral-formats'); }), ), ), diff --git a/packages/ruleset-migrator/src/validation/schema.ts b/packages/ruleset-migrator/src/validation/schema.ts index fa80ef69f..6df09a0cc 100644 --- a/packages/ruleset-migrator/src/validation/schema.ts +++ b/packages/ruleset-migrator/src/validation/schema.ts @@ -6,44 +6,6 @@ const schema = { properties: { aliases: { type: 'object', - additionalProperties: { - oneOf: [ - { - type: 'array', - items: { - type: 'string', - }, - }, - { - type: 'object', - properties: { - description: { - type: 'string', - }, - targets: { - type: 'array', - minItems: 1, - items: { - type: 'object', - properties: { - formats: { - $ref: '#/properties/formats', - }, - given: { - type: 'array', - items: { - type: 'string', - }, - }, - }, - required: ['formats', 'given'], - }, - }, - }, - required: ['targets'], - }, - ], - }, }, except: { type: 'object', @@ -85,25 +47,8 @@ const schema = { }, formats: { type: 'array', - minItems: 1, items: { type: 'string', - enum: [ - 'oas2', - 'oas3', - 'oas3.0', - 'oas3.1', - 'asyncapi2', - 'json-schema', - 'json-schema-loose', - 'json-schema-draft4', - 'json-schema-draft6', - 'json-schema-draft7', - 'json-schema-draft-2019-09', - 'json-schema-2019-09', - 'json-schema-draft-2020-12', - 'json-schema-2020-12', - ], }, }, functions: { diff --git a/packages/ruleset-migrator/src/validation/types.ts b/packages/ruleset-migrator/src/validation/types.ts index 7234c9eb8..ae4aa3d12 100644 --- a/packages/ruleset-migrator/src/validation/types.ts +++ b/packages/ruleset-migrator/src/validation/types.ts @@ -2,166 +2,17 @@ export interface Ruleset { aliases?: { - [k: string]: - | string[] - | { - description?: string; - targets: [ - { - formats: [ - ( - | 'oas2' - | 'oas3' - | 'oas3.0' - | 'oas3.1' - | 'asyncapi2' - | 'json-schema' - | 'json-schema-loose' - | 'json-schema-draft4' - | 'json-schema-draft6' - | 'json-schema-draft7' - | 'json-schema-draft-2019-09' - | 'json-schema-2019-09' - | 'json-schema-draft-2020-12' - | 'json-schema-2020-12' - ), - ...( - | 'oas2' - | 'oas3' - | 'oas3.0' - | 'oas3.1' - | 'asyncapi2' - | 'json-schema' - | 'json-schema-loose' - | 'json-schema-draft4' - | 'json-schema-draft6' - | 'json-schema-draft7' - | 'json-schema-draft-2019-09' - | 'json-schema-2019-09' - | 'json-schema-draft-2020-12' - | 'json-schema-2020-12' - )[] - ]; - given: string[]; - [k: string]: unknown; - }, - ...{ - formats: [ - ( - | 'oas2' - | 'oas3' - | 'oas3.0' - | 'oas3.1' - | 'asyncapi2' - | 'json-schema' - | 'json-schema-loose' - | 'json-schema-draft4' - | 'json-schema-draft6' - | 'json-schema-draft7' - | 'json-schema-draft-2019-09' - | 'json-schema-2019-09' - | 'json-schema-draft-2020-12' - | 'json-schema-2020-12' - ), - ...( - | 'oas2' - | 'oas3' - | 'oas3.0' - | 'oas3.1' - | 'asyncapi2' - | 'json-schema' - | 'json-schema-loose' - | 'json-schema-draft4' - | 'json-schema-draft6' - | 'json-schema-draft7' - | 'json-schema-draft-2019-09' - | 'json-schema-2019-09' - | 'json-schema-draft-2020-12' - | 'json-schema-2020-12' - )[] - ]; - given: string[]; - [k: string]: unknown; - }[] - ]; - [k: string]: unknown; - }; + [k: string]: unknown; }; except?: { [k: string]: string[]; }; extends?: string | (string | [string, 'all' | 'recommended' | 'off'])[]; - formats?: [ - ( - | 'oas2' - | 'oas3' - | 'oas3.0' - | 'oas3.1' - | 'asyncapi2' - | 'json-schema' - | 'json-schema-loose' - | 'json-schema-draft4' - | 'json-schema-draft6' - | 'json-schema-draft7' - | 'json-schema-draft-2019-09' - | 'json-schema-2019-09' - | 'json-schema-draft-2020-12' - | 'json-schema-2020-12' - ), - ...( - | 'oas2' - | 'oas3' - | 'oas3.0' - | 'oas3.1' - | 'asyncapi2' - | 'json-schema' - | 'json-schema-loose' - | 'json-schema-draft4' - | 'json-schema-draft6' - | 'json-schema-draft7' - | 'json-schema-draft-2019-09' - | 'json-schema-2019-09' - | 'json-schema-draft-2020-12' - | 'json-schema-2020-12' - )[] - ]; + formats?: string[]; functions?: string[]; functionsDir?: string; rules?: { - formats?: [ - ( - | 'oas2' - | 'oas3' - | 'oas3.0' - | 'oas3.1' - | 'asyncapi2' - | 'json-schema' - | 'json-schema-loose' - | 'json-schema-draft4' - | 'json-schema-draft6' - | 'json-schema-draft7' - | 'json-schema-draft-2019-09' - | 'json-schema-2019-09' - | 'json-schema-draft-2020-12' - | 'json-schema-2020-12' - ), - ...( - | 'oas2' - | 'oas3' - | 'oas3.0' - | 'oas3.1' - | 'asyncapi2' - | 'json-schema' - | 'json-schema-loose' - | 'json-schema-draft4' - | 'json-schema-draft6' - | 'json-schema-draft7' - | 'json-schema-draft-2019-09' - | 'json-schema-2019-09' - | 'json-schema-draft-2020-12' - | 'json-schema-2020-12' - )[] - ]; + formats?: string[]; [k: string]: unknown; }; [k: string]: unknown;