diff --git a/package.json b/package.json index b0faf44..49558e2 100644 --- a/package.json +++ b/package.json @@ -39,9 +39,9 @@ "test.watch": "yarn test --watch" }, "dependencies": { - "@stoplight/ordered-object-literal": "^1.0.1", - "@stoplight/types": "^13.0.0", - "@stoplight/yaml-ast-parser": "0.0.48", + "@stoplight/ordered-object-literal": "^1.0.5", + "@stoplight/types": "^14.1.1", + "@stoplight/yaml-ast-parser": "0.0.50", "tslib": "^2.2.0" }, "devDependencies": { diff --git a/src/__tests__/__snapshots__/parseWithPointers.spec.ts.snap b/src/__tests__/__snapshots__/parseWithPointers.spec.ts.snap index 468fffa..79e355a 100644 --- a/src/__tests__/__snapshots__/parseWithPointers.spec.ts.snap +++ b/src/__tests__/__snapshots__/parseWithPointers.spec.ts.snap @@ -104,6 +104,28 @@ Array [ exports[`yaml parser parse diverse 1`] = ` Object { "ast": Object { + "comments": Array [ + Object { + "endPosition": 46, + "startPosition": 4, + "value": " <- yaml supports comments, json does not", + }, + Object { + "endPosition": 89, + "startPosition": 47, + "value": " did you know you can embed json in yaml?", + }, + Object { + "endPosition": 122, + "startPosition": 90, + "value": " try uncommenting the next line", + }, + Object { + "endPosition": 139, + "startPosition": 123, + "value": " { foo: 'bar' }", + }, + ], "endPosition": 442, "errors": Array [], "kind": 2, @@ -480,6 +502,7 @@ to save space", "parent": null, "startPosition": 141, }, + "comments": Object {}, "data": Object { "content": "Or we can auto diff --git a/src/__tests__/fixtures/openapi-with-comments.yaml b/src/__tests__/fixtures/openapi-with-comments.yaml new file mode 100644 index 0000000..7a80aa8 --- /dev/null +++ b/src/__tests__/fixtures/openapi-with-comments.yaml @@ -0,0 +1,67 @@ +# my openapi document +openapi: 3.0.0 # Specifies the OpenAPI Specification version +info: # Metadata about the API + title: Bookstore Inventory API # The name of your API + description: API for managing a bookstore's inventory. + version: 1.0.0 # API version +servers: # Defines the API server and base URL + - url: 'https://api.bookstore.com/v1' # Base URL for the API endpoints +# Paths section describes the endpoints available in the API +paths: + /books: + get: # Retrieves a list of books from the inventory + summary: List all books + # A more detailed description of the operation + description: Retrieve a list of books available in the bookstore inventory. + responses: # Describes the possible responses + '200': # HTTP status code for a successful response + description: A JSON array of book objects. + content: + application/json: # Media type + schema: + type: array + items: + $ref: '#/components/schemas/Book' # References the Book schema + # Endpoint to create a new book entry + post: + summary: Add a new book + description: Add a new book to the bookstore inventory. + requestBody: # Describes the request body + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/NewBook' # Schema for the new book data + responses: + '201': # Status code for a successful creation + description: Book created successfully. +# Components section for reusable schemas +components: + schemas: + # Schema definition for a book + Book: + type: object + properties: + id: + type: string # Unique identifier for the book + description: The book's unique identifier. + title: + type: string # The title of the book + description: The title of the book. + author: + type: string # The author's name + description: The author of the book. + isbn: + type: string # The ISBN number + description: The International Standard Book Number. + # Indicates if the book is currently available + available: + type: boolean + description: Whether the book is currently available for sale. + # Schema for creating a new book entry + NewBook: # Below the schema definition + type: object + properties: + title: + type: string + description: The title of the book. # Inline comment for diff --git a/src/__tests__/parseWithPointers.spec.ts b/src/__tests__/parseWithPointers.spec.ts index fa4addf..ed11091 100644 --- a/src/__tests__/parseWithPointers.spec.ts +++ b/src/__tests__/parseWithPointers.spec.ts @@ -34,6 +34,180 @@ describe('yaml parser', () => { expect(result.data).toEqual(HugeJSON); }); + test('given attachComments set to true, parse with comments', () => { + const document = fs.readFileSync(path.join(__dirname, './fixtures/openapi-with-comments.yaml'), 'utf8'); + const result = parseWithPointers(document, { attachComments: true }); + + expect(result.comments).toStrictEqual({ + '#': [ + { + placement: 'leading', + value: ' my openapi document', + }, + { + value: ' Paths section describes the endpoints available in the API', + placement: 'between', + between: ['servers', 'paths'], + }, + { + value: ' Components section for reusable schemas', + placement: 'between', + between: ['paths', 'components'], + }, + ], + '#/components/schemas': [ + { + value: ' Schema for creating a new book entry', + placement: 'between', + between: ['Book', 'NewBook'], + }, + { + value: ' Schema definition for a book', + placement: 'leading', + }, + ], + '#/components/schemas/Book/properties': [ + { + value: ' Indicates if the book is currently available', + placement: 'between', + between: ['isbn', 'available'], + }, + ], + '#/components/schemas/Book/properties/author/type': [ + { + value: " The author's name", + placement: 'before-eol', + }, + ], + '#/components/schemas/Book/properties/id/type': [ + { + value: ' Unique identifier for the book', + placement: 'before-eol', + }, + ], + '#/components/schemas/Book/properties/isbn/type': [ + { + value: ' The ISBN number', + placement: 'before-eol', + }, + ], + '#/components/schemas/Book/properties/title/type': [ + { + value: ' The title of the book', + placement: 'before-eol', + }, + ], + '#/components/schemas/NewBook': [ + { + value: ' Below the schema definition', + placement: 'before-eol', + }, + ], + '#/components/schemas/NewBook/properties/title/description': [ + { + value: ' Inline comment for', + placement: 'before-eol', + }, + ], + '#/info': [ + { + value: ' Metadata about the API', + placement: 'before-eol', + }, + ], + '#/info/title': [ + { + value: ' The name of your API', + placement: 'before-eol', + }, + ], + '#/info/version': [ + { + value: ' API version', + placement: 'before-eol', + }, + ], + '#/openapi': [ + { + value: ' Specifies the OpenAPI Specification version', + placement: 'before-eol', + }, + ], + '#/paths/~1books': [ + { + value: ' Endpoint to create a new book entry', + placement: 'between', + between: ['get', 'post'], + }, + ], + '#/paths/~1books/get': [ + { + value: ' A more detailed description of the operation', + placement: 'between', + between: ['summary', 'description'], + }, + { + value: ' Retrieves a list of books from the inventory', + placement: 'before-eol', + }, + ], + '#/paths/~1books/get/responses': [ + { + value: ' Describes the possible responses', + placement: 'before-eol', + }, + ], + '#/paths/~1books/get/responses/200': [ + { + value: ' HTTP status code for a successful response', + placement: 'before-eol', + }, + ], + '#/paths/~1books/get/responses/200/content/application~1json': [ + { + value: ' Media type', + placement: 'before-eol', + }, + ], + '#/paths/~1books/get/responses/200/content/application~1json/schema/items/$ref': [ + { + value: ' References the Book schema', + placement: 'before-eol', + }, + ], + '#/paths/~1books/post/requestBody': [ + { + value: ' Describes the request body', + placement: 'before-eol', + }, + ], + '#/paths/~1books/post/requestBody/content/application~1json/schema/$ref': [ + { + value: ' Schema for the new book data', + placement: 'before-eol', + }, + ], + '#/paths/~1books/post/responses/201': [ + { + value: ' Status code for a successful creation', + placement: 'before-eol', + }, + ], + '#/servers': [ + { + value: ' Defines the API server and base URL', + placement: 'before-eol', + }, + ], + '#/servers/0/url': [ + { + value: ' Base URL for the API endpoints', + placement: 'before-eol', + }, + ], + }); + }); + test('parses string according to YAML 1.2 spec', () => { const { data } = parseWithPointers(spectral481); expect(data).toHaveProperty( diff --git a/src/__tests__/safeStringify.spec.ts b/src/__tests__/safeStringify.spec.ts index cbb80a2..db48596 100644 --- a/src/__tests__/safeStringify.spec.ts +++ b/src/__tests__/safeStringify.spec.ts @@ -1,3 +1,6 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import { parseWithPointers } from '../parseWithPointers'; import { safeStringify } from '../safeStringify'; describe('safeStringify', () => { @@ -16,6 +19,13 @@ describe('safeStringify', () => { expect(safeStringify(value)).toEqual(`${value}\n`); }); + it('should dump comments back', () => { + const document = fs.readFileSync(path.join(__dirname, './fixtures/openapi-with-comments.yaml'), 'utf8'); + const result = parseWithPointers(document, { attachComments: true }); + + expect(safeStringify(result.data, { comments: result.comments })).toEqual(document); + }); + it('should respect lineWidth for multi-line strings', () => { const description = `# API information Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. diff --git a/src/index.ts b/src/index.ts index 06e6677..2fa0a25 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,8 +3,8 @@ export * from './dereferenceAnchor'; export * from './getJsonPathForPosition'; export * from './getLocationForJsonPath'; export * from './lineForPosition'; -export * from './parse'; -export * from './parseWithPointers'; +export { parse } from './parse'; +export { parseWithPointers } from './parseWithPointers'; export * from './safeStringify'; export * from './types'; export * from './trapAccess'; diff --git a/src/parse.ts b/src/parse.ts index 2a806ac..9a5ce42 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -1,5 +1,3 @@ -import { load as loadAST } from '@stoplight/yaml-ast-parser'; -import { walkAST } from './parseWithPointers'; -import { YAMLNode } from './types'; +import { parseWithPointers } from './parseWithPointers'; -export const parse = (value: string): T => walkAST(loadAST(value) as YAMLNode, void 0, [], []) as T; +export const parse = (value: string): T => parseWithPointers(value).data as T; diff --git a/src/parseWithPointers.ts b/src/parseWithPointers.ts index 98f7410..beca204 100644 --- a/src/parseWithPointers.ts +++ b/src/parseWithPointers.ts @@ -1,18 +1,28 @@ import createOrderedObject, { getOrder } from '@stoplight/ordered-object-literal'; -import { DiagnosticSeverity, Dictionary, IDiagnostic, IPosition, IRange, Optional } from '@stoplight/types'; +import { DiagnosticSeverity, Dictionary, IDiagnostic, IPosition, IRange } from '@stoplight/types'; import { determineScalarType, load as loadAST, parseYamlBigInteger, parseYamlBoolean, parseYamlFloat, + YAMLDocument, YAMLException, } from '@stoplight/yaml-ast-parser'; import { buildJsonPath } from './buildJsonPath'; import { SpecialMappingKeys } from './consts'; import { dereferenceAnchor } from './dereferenceAnchor'; import { lineForPosition } from './lineForPosition'; -import { IParseOptions, Kind, ScalarType, YAMLMapping, YAMLNode, YamlParserResult, YAMLScalar } from './types'; +import { + IParseOptions, + Kind, + ScalarType, + YamlComments, + YAMLMapping, + YAMLNode, + YamlParserResult, + YAMLScalar, +} from './types'; import { isObject } from './utils'; export const parseWithPointers = (value: string, options?: IParseOptions): YamlParserResult => { @@ -28,11 +38,27 @@ export const parseWithPointers = (value: string, options?: IParseOptions): Ya data: undefined, diagnostics: [], metadata: options, + comments: {}, }; if (!ast) return parsed; - parsed.data = walkAST(ast, options, lineMap, parsed.diagnostics) as T; + const normalizedOptions = normalizeOptions(options); + + const comments = new Comments( + parsed.comments, + Comments.mapComments(normalizedOptions.attachComments && ast.comments ? ast.comments : [], lineMap), + ast, + lineMap, + '#', + ); + + const ctx = { + lineMap, + diagnostics: parsed.diagnostics, + }; + + parsed.data = walkAST(ctx, ast, comments, normalizedOptions) as T; if (ast.errors) { parsed.diagnostics.push(...transformErrors(ast.errors, lineMap)); @@ -49,27 +75,43 @@ export const parseWithPointers = (value: string, options?: IParseOptions): Ya return parsed; }; -export const walkAST = ( +type WalkContext = { + lineMap: number[]; + diagnostics: IDiagnostic[]; +}; + +const TILDE_REGEXP = /~/g; +const SLASH_REGEXP = /\//g; + +function encodeSegment(input: string) { + return input.replace(TILDE_REGEXP, '~0').replace(SLASH_REGEXP, '~1'); +} + +const walkAST = ( + ctx: WalkContext, node: YAMLNode | null, - options: Optional, - lineMap: number[], - diagnostics: IDiagnostic[], + comments: Comments, + options: ReturnType, ): unknown => { if (node) { switch (node.kind) { case Kind.MAP: { - const preserveKeyOrder = options !== void 0 && options.preserveKeyOrder === true; + const mapComments = comments.enter(node); + + const { lineMap, diagnostics } = ctx; + const { preserveKeyOrder, ignoreDuplicateKeys, json, mergeKeys } = options; const container = createMapContainer(preserveKeyOrder); // note, we don't handle null aka '~' keys on purpose const seenKeys: string[] = []; - const handleMergeKeys = options !== void 0 && options.mergeKeys === true; - const yamlMode = options !== void 0 && options.json === false; - const handleDuplicates = options !== void 0 && options.ignoreDuplicateKeys === false; + const handleMergeKeys = mergeKeys; + const yamlMode = !json; + const handleDuplicates = !ignoreDuplicateKeys; for (const mapping of node.mappings) { if (!validateMappingKey(mapping, lineMap, diagnostics, yamlMode)) continue; const key = String(getScalarValue(mapping.key)); + const mappingComments = mapComments.enter(mapping, encodeSegment(key)); if ((yamlMode || handleDuplicates) && (!handleMergeKeys || key !== SpecialMappingKeys.MergeKey)) { if (seenKeys.includes(key)) { @@ -87,33 +129,49 @@ export const walkAST = ( // https://yaml.org/type/merge.html merge keys, not a part of YAML spec if (handleMergeKeys && key === SpecialMappingKeys.MergeKey) { - const reduced = reduceMergeKeys(walkAST(mapping.value, options, lineMap, diagnostics), preserveKeyOrder); + const reduced = reduceMergeKeys(walkAST(ctx, mapping.value, mappingComments, options), preserveKeyOrder); Object.assign(container, reduced); } else { - container[key] = walkAST(mapping.value, options, lineMap, diagnostics); + container[key] = walkAST(ctx, mapping.value, mappingComments, options); if (preserveKeyOrder) { pushKey(container, key); } } + + mappingComments.attachComments(); } + mapComments.attachComments(); + return container; + } + case Kind.SEQ: { + const nodeComments = comments.enter(node); + const container = node.items.map((item, i) => { + if (item !== null) { + const sequenceItemComments = nodeComments.enter(item, i); + const walked = walkAST(ctx, item, sequenceItemComments, options); + sequenceItemComments.attachComments(); + return walked; + } else { + return null; + } + }); + + nodeComments.attachComments(); return container; } - case Kind.SEQ: - return node.items.map(item => walkAST(item, options, lineMap, diagnostics)); case Kind.SCALAR: { - const bigInt = options !== void 0 && options.bigInt === true; const value = getScalarValue(node); - return !bigInt && typeof value === 'bigint' ? Number(value) : value; + return !options.bigInt && typeof value === 'bigint' ? Number(value) : value; } case Kind.ANCHOR_REF: { if (isObject(node.value)) { node.value = dereferenceAnchor(node.value, node.referencesAnchor)!; } - return walkAST(node.value!, options, lineMap, diagnostics); + return walkAST(ctx, node.value!, comments, options); } default: return null; @@ -298,23 +356,246 @@ function createYAMLIncompatibilityException( } function createYAMLException(node: YAMLNode, lineMap: number[], message: string): IDiagnostic { - const startLine = lineForPosition(node.startPosition, lineMap); - const endLine = lineForPosition(node.endPosition, lineMap); - return { code: 'YAMLException', message, severity: DiagnosticSeverity.Error, path: buildJsonPath(node), - range: { - start: { - line: startLine, - character: startLine === 0 ? node.startPosition : node.startPosition - lineMap[startLine - 1], - }, - end: { - line: endLine, - character: endLine === 0 ? node.endPosition : node.endPosition - lineMap[endLine - 1], - }, + range: getRange(lineMap, node.startPosition, node.endPosition), + }; +} + +function getRange(lineMap: number[], startPosition: number, endPosition: number): IRange { + const startLine = lineForPosition(startPosition, lineMap); + const endLine = lineForPosition(endPosition, lineMap); + + return { + start: { + line: startLine, + character: startLine === 0 ? startPosition : startPosition - lineMap[startLine - 1], }, + end: { + line: endLine, + character: endLine === 0 ? endPosition : endPosition - lineMap[endLine - 1], + }, + }; +} + +type MappedComment = { value: string; range: IRange; startPosition: number; endPosition: number }; +class Comments { + private readonly comments: MappedComment[]; + + constructor( + private readonly attachedComments: YamlComments, + comments: MappedComment[], + private readonly node: YAMLNode, + private readonly lineMap: number[], + private readonly pointer: string, + ) { + if (comments.length === 0) { + this.comments = []; + } else { + const startPosition = this.getStartPosition(node); + const endPosition = this.getEndPosition(node); + const startLine = lineForPosition(startPosition, this.lineMap); + const endLine = lineForPosition(endPosition, this.lineMap); + + const matchingComments = []; + for (let i = comments.length - 1; i >= 0; i--) { + const comment = comments[i]; + if (comment.range.start.line >= startLine && comment.range.end.line <= endLine) { + matchingComments.push(comment); + comments.splice(i, 1); + } + } + + this.comments = matchingComments; + } + } + + protected getStartPosition(node: YAMLNode) { + if (node.parent === null) { + return 0; + } + + return node.kind === Kind.MAPPING ? node.key.startPosition : node.startPosition; + } + + protected getEndPosition(node: YAMLNode): number { + switch (node.kind) { + case Kind.MAPPING: + return node.value === null ? node.endPosition : this.getEndPosition(node.value); + case Kind.MAP: + return node.mappings.length === 0 ? node.endPosition : node.mappings[node.mappings.length - 1].endPosition; + case Kind.SEQ: { + if (node.items.length === 0) { + return node.endPosition; + } + + const lastItem = node.items[node.items.length - 1]; + return lastItem === null ? node.endPosition : lastItem.endPosition; + } + default: + return node.endPosition; + } + } + + public static mapComments(comments: NonNullable, lineMap: number[]) { + return comments.map(comment => ({ + value: comment.value, + range: getRange(lineMap, comment.startPosition, comment.endPosition), + startPosition: comment.startPosition, + endPosition: comment.endPosition, + })); + } + + public enter(node: YAMLNode, key?: string | number) { + return new Comments( + this.attachedComments, + this.comments, + node, + this.lineMap, + key === void 0 ? this.pointer : `${this.pointer}/${key}`, + ); + } + + public static isLeading(node: YAMLNode, startPosition: number) { + switch (node.kind) { + case Kind.MAP: + return node.mappings.length === 0 || node.mappings[0].startPosition > startPosition; + case Kind.SEQ: { + if (node.items.length === 0) { + return true; + } + + const firstItem = node.items[0]; + return firstItem === null || firstItem.startPosition > startPosition; + } + case Kind.MAPPING: + return node.value === null || node.value.startPosition > startPosition; + default: + return false; + } + } + + public static isTrailing(node: YAMLNode, endPosition: number) { + switch (node.kind) { + case Kind.MAP: + return node.mappings.length > 0 && endPosition > node.mappings[node.mappings.length - 1].endPosition; + case Kind.SEQ: + if (node.items.length === 0) { + return false; + } + + const lastItem = node.items[node.items.length - 1]; + return lastItem !== null && endPosition > lastItem.endPosition; + case Kind.MAPPING: + return node.value !== null && endPosition > node.value.endPosition; + default: + return false; + } + } + + public static findBetween(node: YAMLNode, startPosition: number, endPosition: number): [string, string] | null { + switch (node.kind) { + case Kind.MAP: { + let left; + for (const mapping of node.mappings) { + if (startPosition > mapping.startPosition) { + left = mapping.key.value; + } else if (left !== void 0 && mapping.startPosition > endPosition) { + return [left, mapping.key.value]; + } + } + + return null; + } + case Kind.SEQ: { + let left; + for (let i = 0; i < node.items.length; i++) { + const item = node.items[i]; + if (item === null) continue; + if (startPosition > item.startPosition) { + left = String(i); + } else if (left !== void 0 && item.startPosition > endPosition) { + return [left, String(i)]; + } + } + + return null; + } + default: + return null; + } + } + + public isBeforeEOL(comment: MappedComment) { + return ( + this.node.kind === Kind.SCALAR || + (this.node.kind === Kind.MAPPING && + comment.range.end.line === lineForPosition(this.node.key.endPosition, this.lineMap)) + ); + } + + public attachComments() { + if (this.comments.length === 0) return; + + const attachedComments = (this.attachedComments[this.pointer] = this.attachedComments[this.pointer] || []); + + for (const comment of this.comments) { + if (this.isBeforeEOL(comment)) { + attachedComments.push({ + value: comment.value, + placement: 'before-eol', + }); + } else if (Comments.isLeading(this.node, comment.startPosition)) { + attachedComments.push({ + value: comment.value, + placement: 'leading', + }); + } else if (Comments.isTrailing(this.node, comment.endPosition)) { + attachedComments.push({ + value: comment.value, + placement: 'trailing', + }); + } else { + const between = Comments.findBetween(this.node, comment.startPosition, comment.endPosition); + if (between !== null) { + attachedComments.push({ + value: comment.value, + placement: 'between', + between, + }); + } else { + attachedComments.push({ + value: comment.value, + placement: 'trailing', + }); + } + } + } + } +} + +function normalizeOptions(options?: IParseOptions) { + if (options === void 0) { + return { + attachComments: false, + preserveKeyOrder: false, + bigInt: false, + mergeKeys: false, + json: true, + ignoreDuplicateKeys: false, + }; + } + + return { + ...options, + attachComments: options.attachComments === true, + preserveKeyOrder: options.preserveKeyOrder === true, + bigInt: options.bigInt === true, + mergeKeys: options.mergeKeys === true, + json: options.json !== false, + ignoreDuplicateKeys: options.ignoreDuplicateKeys !== false, }; } diff --git a/src/types.ts b/src/types.ts index 2a280d5..9f3cfc7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,12 +1,13 @@ import { IParserResult, Optional } from '@stoplight/types'; import * as YAMLAstParser from '@stoplight/yaml-ast-parser'; -import { Kind, ScalarType } from '@stoplight/yaml-ast-parser'; +import { DumpOptions, Kind, ScalarType } from '@stoplight/yaml-ast-parser'; export interface IParseOptions extends YAMLAstParser.LoadOptions { json?: boolean; // if true, properties can be overridden, otherwise throws bigInt?: boolean; mergeKeys?: boolean; preserveKeyOrder?: boolean; + attachComments?: boolean; } export type YAMLBaseNode = Omit & { @@ -43,6 +44,10 @@ export type YAMLSequence = Omit = IParserResult; +export type YamlComments = NonNullable; + +export type YamlParserResult = IParserResult & { + comments: YamlComments; +}; export { Kind, ScalarType }; diff --git a/yarn.lock b/yarn.lock index 3d3cd67..0671132 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1518,10 +1518,10 @@ lodash "^4.17.4" read-pkg-up "^6.0.0" -"@stoplight/ordered-object-literal@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@stoplight/ordered-object-literal/-/ordered-object-literal-1.0.1.tgz#01ece81ba5dda199ca3dc5ec7464691efa5d5b76" - integrity sha512-kDcBIKwzAXZTkgzaiPXH2I0JXavBkOb3jFzYNFS5cBuvZS3s/K+knpk2wLVt0n8XrnRQsSffzN6XG9HqUhfq6Q== +"@stoplight/ordered-object-literal@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@stoplight/ordered-object-literal/-/ordered-object-literal-1.0.5.tgz#06689095a4f1a53e9d9a5f0055f707c387af966a" + integrity sha512-COTiuCU5bgMUtbIFBuyyh2/yVVzlr5Om0v5utQDgBCuQUOPgU1DwoffkTfg4UBQOvByi5foF4w4T+H9CoRe5wg== "@stoplight/scripts@3.1.0": version "3.1.0" @@ -1580,18 +1580,18 @@ typedoc "0.13.x" typescript-plugin-styled-components "1.0.x" -"@stoplight/types@^13.0.0": - version "13.0.0" - resolved "https://registry.yarnpkg.com/@stoplight/types/-/types-13.0.0.tgz#69a22d57d3a67f623a01929b10e25401c9635154" - integrity sha512-9OTVMiSUz2NlEW14OL6NKOuMTj3dtVVsugRwe3qbq0QnUpx/VLxOuO83n47rXZUTHvk69arOlFrDmRyZMw2DUg== +"@stoplight/types@^14.1.1": + version "14.1.1" + resolved "https://registry.yarnpkg.com/@stoplight/types/-/types-14.1.1.tgz#0dd5761aac25673a951955e984c724c138368b7a" + integrity sha512-/kjtr+0t0tjKr+heVfviO9FrU/uGLc+QNX3fHJc19xsCNYqU7lVhaXxDmEID9BZTjG+/r9pK9xP/xU02XGg65g== dependencies: "@types/json-schema" "^7.0.4" utility-types "^3.10.0" -"@stoplight/yaml-ast-parser@0.0.48": - version "0.0.48" - resolved "https://registry.yarnpkg.com/@stoplight/yaml-ast-parser/-/yaml-ast-parser-0.0.48.tgz#442b21f419427acaa8a3106ebc5d73351c407002" - integrity sha512-sV+51I7WYnLJnKPn2EMWgS4EUfoP4iWEbrWwbXsj0MZCB/xOK8j6+C9fntIdOM50kpx45ZLC3s6kwKivWuqvyg== +"@stoplight/yaml-ast-parser@0.0.50": + version "0.0.50" + resolved "https://registry.yarnpkg.com/@stoplight/yaml-ast-parser/-/yaml-ast-parser-0.0.50.tgz#ed625a1d9ae63eb61980446e058fa745386ab61e" + integrity sha512-Pb6M8TDO9DtSVla9yXSTAxmo9GVEouq5P40DWXdOie69bXogZTkgvopCq+yEvTMA0F6PEvdJmbtTV3ccIp11VQ== "@storybook/addon-actions@4.0.11": version "4.0.11"