diff --git a/.yalc/@stoplight/json/LICENSE b/.yalc/@stoplight/json/LICENSE new file mode 100644 index 00000000..ba50e461 --- /dev/null +++ b/.yalc/@stoplight/json/LICENSE @@ -0,0 +1,190 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2018 Stoplight, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/.yalc/@stoplight/json/README.md b/.yalc/@stoplight/json/README.md new file mode 100644 index 00000000..44f8408e --- /dev/null +++ b/.yalc/@stoplight/json/README.md @@ -0,0 +1,70 @@ +# @stoplight/json + +[![Maintainability](https://api.codeclimate.com/v1/badges/85d2215f8b1e8a15214f/maintainability)](https://codeclimate.com/github/stoplightio/json/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/85d2215f8b1e8a15214f/test_coverage)](https://codeclimate.com/github/stoplightio/json/test_coverage) + +Useful functions when working with JSON. + +- View the changelog: [Releases](https://github.com/stoplightio/json/releases) + +### Installation + +Supported in modern browsers and node. + +```bash +# latest stable version +yarn add @stoplight/json +``` + +### Usage + +- **[parseWithPointers](https://stoplightio.github.io/json/globals.html#parsewithpointers)**: Like `JSON.parse(val)` but also returns parsing errors as well as full ast with line information. +- **[pathToPointer](https://stoplightio.github.io/json/globals.html#pathtopointer)**: Turns an array of path segments into a json pointer IE `['paths', '/user', 'get']` -> `#/paths/~1user/get`. +- **[pointerToPath](https://stoplightio.github.io/json/globals.html#pointertopath)**: Turns a json pointer into an array of path segments IE `#/paths/~1user/get` -> `['paths', '/user', 'get']`. +- **[safeParse](https://stoplightio.github.io/json/globals.html#safeparse)**: Like `JSON.parse(val)` but does not throw on invalid JSON. +- **[safeStringify](https://stoplightio.github.io/json/globals.html#safestringify)**: Like `JSON.stringify(val)` but handles circular references. +- **[startsWith](https://stoplightio.github.io/json/globals.html#startswith)**: Like native JS `x.startsWith(y)` but works with strings AND arrays. +- **[trimStart](https://stoplightio.github.io/json/globals.html#trimstart)**: Like `lodash.startsWith(x, y)` but works with strings AND arrays. +- **[getJsonPathForPosition](https://stoplightio.github.io/json/globals.html#getjsonpathforposition)**: Computes JSON path for given position. +- **[getLocationForJsonPath](https://stoplightio.github.io/json/globals.html#getlocationforjsonpath)**: Retrieves location of node matching given JSON path. + +#### Example `parseWithPointers` + +```ts +import { parseWithPointers } from "@stoplight/json"; + +const result = parseWithPointers('{"foo": "bar"}'); + +console.log(result.data); // => the {foo: "bar"} JS object +console.log(result.pointers); // => the source map with a single "#/foo" pointer that has position info for the foo property +``` + +```ts +// basic example of getJsonPathForPosition and getLocationForJsonPath +import { getJsonPathForPosition, getLocationForJsonPath, parseWithPointers } from "@stoplight/json"; + +const result = parseWithPointers(`{ + "hello": "world", + "address": { + "street": 123 + } +}`); + +const path = getJsonPathForPosition(result, { line: 3, character: 15 }); // line and character are 0-based +console.log(path); // -> ["address", "street"]; + +const position = getLocationForJsonPath(result, ["address"]); +console.log(position.range.start); // { line: 2, character: 13 } line and character are 0-based +console.log(position.range.end); // { line: 4, character: 3 } line and character are 0-based +``` + +### Contributing + +1. Clone repo. +2. Create / checkout `feature/{name}`, `chore/{name}`, or `fix/{name}` branch. +3. Install deps: `yarn`. +4. Make your changes. +5. Run tests: `yarn test.prod`. +6. Stage relevant files to git. +7. Commit: `yarn commit`. _NOTE: Commits that don't follow the [conventional](https://github.com/marionebl/commitlint/tree/master/%40commitlint/config-conventional) format will be rejected. `yarn commit` creates this format for you, or you can put it together manually and then do a regular `git commit`._ +8. Push: `git push`. +9. Open PR targeting the `next` branch. diff --git a/.yalc/@stoplight/json/__tests__/bundle.spec.d.ts b/.yalc/@stoplight/json/__tests__/bundle.spec.d.ts new file mode 100644 index 00000000..509db186 --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/bundle.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/.yalc/@stoplight/json/__tests__/decodePointer.d.ts b/.yalc/@stoplight/json/__tests__/decodePointer.d.ts new file mode 100644 index 00000000..509db186 --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/decodePointer.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/.yalc/@stoplight/json/__tests__/decodePointerFragment.d.ts b/.yalc/@stoplight/json/__tests__/decodePointerFragment.d.ts new file mode 100644 index 00000000..509db186 --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/decodePointerFragment.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/.yalc/@stoplight/json/__tests__/encodePointer.d.ts b/.yalc/@stoplight/json/__tests__/encodePointer.d.ts new file mode 100644 index 00000000..509db186 --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/encodePointer.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/.yalc/@stoplight/json/__tests__/encodePointerFragment.d.ts b/.yalc/@stoplight/json/__tests__/encodePointerFragment.d.ts new file mode 100644 index 00000000..509db186 --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/encodePointerFragment.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/.yalc/@stoplight/json/__tests__/extractPointerFromRef.spec.d.ts b/.yalc/@stoplight/json/__tests__/extractPointerFromRef.spec.d.ts new file mode 100644 index 00000000..509db186 --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/extractPointerFromRef.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/.yalc/@stoplight/json/__tests__/extractSourceFromRef.spec.d.ts b/.yalc/@stoplight/json/__tests__/extractSourceFromRef.spec.d.ts new file mode 100644 index 00000000..509db186 --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/extractSourceFromRef.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/.yalc/@stoplight/json/__tests__/fixtures/json.d.ts b/.yalc/@stoplight/json/__tests__/fixtures/json.d.ts new file mode 100644 index 00000000..808f849d --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/fixtures/json.d.ts @@ -0,0 +1,6 @@ +export declare const small: any; +export declare const smallString: string; +export declare const smallCircular: any; +export declare const large: any; +export declare const largeString: string; +export declare const largeCircular: any; diff --git a/.yalc/@stoplight/json/__tests__/getFirstPrimitiveProperty.d.ts b/.yalc/@stoplight/json/__tests__/getFirstPrimitiveProperty.d.ts new file mode 100644 index 00000000..509db186 --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/getFirstPrimitiveProperty.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/.yalc/@stoplight/json/__tests__/getJsonPathForPosition.spec.d.ts b/.yalc/@stoplight/json/__tests__/getJsonPathForPosition.spec.d.ts new file mode 100644 index 00000000..509db186 --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/getJsonPathForPosition.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/.yalc/@stoplight/json/__tests__/getLastPathSegment.spec.d.ts b/.yalc/@stoplight/json/__tests__/getLastPathSegment.spec.d.ts new file mode 100644 index 00000000..509db186 --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/getLastPathSegment.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/.yalc/@stoplight/json/__tests__/getLocationForJsonPath.spec.d.ts b/.yalc/@stoplight/json/__tests__/getLocationForJsonPath.spec.d.ts new file mode 100644 index 00000000..509db186 --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/getLocationForJsonPath.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/.yalc/@stoplight/json/__tests__/hasRef.spec.d.ts b/.yalc/@stoplight/json/__tests__/hasRef.spec.d.ts new file mode 100644 index 00000000..509db186 --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/hasRef.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/.yalc/@stoplight/json/__tests__/isLocalRef.spec.d.ts b/.yalc/@stoplight/json/__tests__/isLocalRef.spec.d.ts new file mode 100644 index 00000000..509db186 --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/isLocalRef.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/.yalc/@stoplight/json/__tests__/lazyInlineResolver.spec.d.ts b/.yalc/@stoplight/json/__tests__/lazyInlineResolver.spec.d.ts new file mode 100644 index 00000000..509db186 --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/lazyInlineResolver.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/.yalc/@stoplight/json/__tests__/parseWithPointers.d.ts b/.yalc/@stoplight/json/__tests__/parseWithPointers.d.ts new file mode 100644 index 00000000..509db186 --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/parseWithPointers.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/.yalc/@stoplight/json/__tests__/pathToPointer.d.ts b/.yalc/@stoplight/json/__tests__/pathToPointer.d.ts new file mode 100644 index 00000000..509db186 --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/pathToPointer.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/.yalc/@stoplight/json/__tests__/pointerToPath.d.ts b/.yalc/@stoplight/json/__tests__/pointerToPath.d.ts new file mode 100644 index 00000000..509db186 --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/pointerToPath.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/.yalc/@stoplight/json/__tests__/renameObjectKeys.spec.d.ts b/.yalc/@stoplight/json/__tests__/renameObjectKeys.spec.d.ts new file mode 100644 index 00000000..509db186 --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/renameObjectKeys.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/.yalc/@stoplight/json/__tests__/resolveInlineRef.spec.d.ts b/.yalc/@stoplight/json/__tests__/resolveInlineRef.spec.d.ts new file mode 100644 index 00000000..509db186 --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/resolveInlineRef.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/.yalc/@stoplight/json/__tests__/safeParse.d.ts b/.yalc/@stoplight/json/__tests__/safeParse.d.ts new file mode 100644 index 00000000..509db186 --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/safeParse.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/.yalc/@stoplight/json/__tests__/safeStringify.d.ts b/.yalc/@stoplight/json/__tests__/safeStringify.d.ts new file mode 100644 index 00000000..509db186 --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/safeStringify.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/.yalc/@stoplight/json/__tests__/startsWith.spec.d.ts b/.yalc/@stoplight/json/__tests__/startsWith.spec.d.ts new file mode 100644 index 00000000..509db186 --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/startsWith.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/.yalc/@stoplight/json/__tests__/stringify.spec.d.ts b/.yalc/@stoplight/json/__tests__/stringify.spec.d.ts new file mode 100644 index 00000000..509db186 --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/stringify.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/.yalc/@stoplight/json/__tests__/toPropertyPath.spec.d.ts b/.yalc/@stoplight/json/__tests__/toPropertyPath.spec.d.ts new file mode 100644 index 00000000..509db186 --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/toPropertyPath.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/.yalc/@stoplight/json/__tests__/trapAccess.d.ts b/.yalc/@stoplight/json/__tests__/trapAccess.d.ts new file mode 100644 index 00000000..509db186 --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/trapAccess.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/.yalc/@stoplight/json/__tests__/traverse.spec.d.ts b/.yalc/@stoplight/json/__tests__/traverse.spec.d.ts new file mode 100644 index 00000000..509db186 --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/traverse.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/.yalc/@stoplight/json/__tests__/trimStart.spec.d.ts b/.yalc/@stoplight/json/__tests__/trimStart.spec.d.ts new file mode 100644 index 00000000..509db186 --- /dev/null +++ b/.yalc/@stoplight/json/__tests__/trimStart.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/.yalc/@stoplight/json/_utils.d.ts b/.yalc/@stoplight/json/_utils.d.ts new file mode 100644 index 00000000..8e8e9132 --- /dev/null +++ b/.yalc/@stoplight/json/_utils.d.ts @@ -0,0 +1 @@ +export declare const replaceInString: (str: string, find: string, repl: string) => string; diff --git a/.yalc/@stoplight/json/bundle.d.ts b/.yalc/@stoplight/json/bundle.d.ts new file mode 100644 index 00000000..e637a7bd --- /dev/null +++ b/.yalc/@stoplight/json/bundle.d.ts @@ -0,0 +1,6 @@ +export declare const BUNDLE_ROOT = "__bundled__"; +export declare const ERRORS_ROOT = "__errors__"; +export declare const bundleTarget: ({ document, path }: { + document: T; + path: string; +}, cur?: unknown) => any; diff --git a/.yalc/@stoplight/json/decodePointer.d.ts b/.yalc/@stoplight/json/decodePointer.d.ts new file mode 100644 index 00000000..902e610b --- /dev/null +++ b/.yalc/@stoplight/json/decodePointer.d.ts @@ -0,0 +1 @@ +export declare const decodePointer: (value: string) => string; diff --git a/.yalc/@stoplight/json/decodePointerFragment.d.ts b/.yalc/@stoplight/json/decodePointerFragment.d.ts new file mode 100644 index 00000000..0545a4bd --- /dev/null +++ b/.yalc/@stoplight/json/decodePointerFragment.d.ts @@ -0,0 +1 @@ +export declare const decodePointerFragment: (value: string) => string; diff --git a/.yalc/@stoplight/json/encodePointer.d.ts b/.yalc/@stoplight/json/encodePointer.d.ts new file mode 100644 index 00000000..bb35cb48 --- /dev/null +++ b/.yalc/@stoplight/json/encodePointer.d.ts @@ -0,0 +1 @@ +export declare const encodePointer: (value: string) => string; diff --git a/.yalc/@stoplight/json/encodePointerFragment.d.ts b/.yalc/@stoplight/json/encodePointerFragment.d.ts new file mode 100644 index 00000000..b04c3abf --- /dev/null +++ b/.yalc/@stoplight/json/encodePointerFragment.d.ts @@ -0,0 +1,2 @@ +import { Segment } from '@stoplight/types'; +export declare const encodePointerFragment: (value: Segment) => Segment; diff --git a/.yalc/@stoplight/json/extractPointerFromRef.d.ts b/.yalc/@stoplight/json/extractPointerFromRef.d.ts new file mode 100644 index 00000000..4e16f086 --- /dev/null +++ b/.yalc/@stoplight/json/extractPointerFromRef.d.ts @@ -0,0 +1 @@ +export declare const extractPointerFromRef: (ref: string) => string | null; diff --git a/.yalc/@stoplight/json/extractSourceFromRef.d.ts b/.yalc/@stoplight/json/extractSourceFromRef.d.ts new file mode 100644 index 00000000..767c6800 --- /dev/null +++ b/.yalc/@stoplight/json/extractSourceFromRef.d.ts @@ -0,0 +1 @@ +export declare const extractSourceFromRef: (ref: unknown) => string | null; diff --git a/.yalc/@stoplight/json/getFirstPrimitiveProperty.d.ts b/.yalc/@stoplight/json/getFirstPrimitiveProperty.d.ts new file mode 100644 index 00000000..59b1c290 --- /dev/null +++ b/.yalc/@stoplight/json/getFirstPrimitiveProperty.d.ts @@ -0,0 +1,2 @@ +import { Optional } from '@stoplight/types'; +export declare const getFirstPrimitiveProperty: (text: string) => Optional<[string, string | number | boolean | null]>; diff --git a/.yalc/@stoplight/json/getJsonPathForPosition.d.ts b/.yalc/@stoplight/json/getJsonPathForPosition.d.ts new file mode 100644 index 00000000..9f4f508b --- /dev/null +++ b/.yalc/@stoplight/json/getJsonPathForPosition.d.ts @@ -0,0 +1,3 @@ +import { GetJsonPathForPosition } from '@stoplight/types'; +import { JsonParserResult } from './types'; +export declare const getJsonPathForPosition: GetJsonPathForPosition>; diff --git a/.yalc/@stoplight/json/getLastPathSegment.d.ts b/.yalc/@stoplight/json/getLastPathSegment.d.ts new file mode 100644 index 00000000..39b50bf8 --- /dev/null +++ b/.yalc/@stoplight/json/getLastPathSegment.d.ts @@ -0,0 +1 @@ +export declare function getLastPathSegment(path: string): string; diff --git a/.yalc/@stoplight/json/getLocationForJsonPath.d.ts b/.yalc/@stoplight/json/getLocationForJsonPath.d.ts new file mode 100644 index 00000000..a00b8493 --- /dev/null +++ b/.yalc/@stoplight/json/getLocationForJsonPath.d.ts @@ -0,0 +1,3 @@ +import { GetLocationForJsonPath } from '@stoplight/types'; +import { JsonParserResult } from './types'; +export declare const getLocationForJsonPath: GetLocationForJsonPath>; diff --git a/.yalc/@stoplight/json/hasRef.d.ts b/.yalc/@stoplight/json/hasRef.d.ts new file mode 100644 index 00000000..60b2d4a5 --- /dev/null +++ b/.yalc/@stoplight/json/hasRef.d.ts @@ -0,0 +1,3 @@ +export declare const hasRef: (obj: unknown) => obj is object & { + $ref: string; +}; diff --git a/.yalc/@stoplight/json/index.cjs.js b/.yalc/@stoplight/json/index.cjs.js new file mode 100644 index 00000000..ccc614f0 --- /dev/null +++ b/.yalc/@stoplight/json/index.cjs.js @@ -0,0 +1,718 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } + +var lodash = require('lodash'); +var jsoncParser = require('jsonc-parser'); +var createOrderedObject = require('@stoplight/ordered-object-literal'); +var createOrderedObject__default = _interopDefault(createOrderedObject); +var types = require('@stoplight/types'); +var fastStringify = _interopDefault(require('safe-stable-stringify')); + +const hasRef = (obj) => lodash.isObject(obj) && '$ref' in obj && typeof obj.$ref === 'string'; + +const isLocalRef = (pointer) => pointer.length > 0 && pointer[0] === '#'; + +const replaceInString = (str, find, repl) => { + const orig = str.toString(); + let res = ''; + let rem = orig; + let beg = 0; + let end = rem.indexOf(find); + while (end > -1) { + res += orig.substring(beg, beg + end) + repl; + rem = rem.substring(end + find.length, rem.length); + beg += end + find.length; + end = rem.indexOf(find); + } + if (rem.length > 0) { + res += orig.substring(orig.length - rem.length, orig.length); + } + return res; +}; + +const encodePointerFragment = (value) => { + return typeof value === 'number' ? value : replaceInString(replaceInString(value, '~', '~0'), '/', '~1'); +}; + +const pathToPointer = (path) => { + return encodeUriFragmentIdentifier(path); +}; +const encodeUriFragmentIdentifier = (path) => { + if (path && typeof path !== 'object') { + throw new TypeError('Invalid type: path must be an array of segments.'); + } + if (path.length === 0) { + return '#'; + } + return `#/${path.map(encodePointerFragment).join('/')}`; +}; + +const decodePointer = (value) => { + return replaceInString(replaceInString(decodeURIComponent('' + value), '~1', '/'), '~0', '~'); +}; + +const pointerToPath = (pointer) => { + return decodeUriFragmentIdentifier(pointer); +}; +const decodeFragmentSegments = (segments) => { + const len = segments.length; + const res = []; + let i = -1; + while (++i < len) { + res.push(decodePointer(segments[i])); + } + return res; +}; +const decodeUriFragmentIdentifier = (ptr) => { + if (typeof ptr !== 'string') { + throw new TypeError('Invalid type: JSON Pointers are represented as strings.'); + } + if (ptr.length === 0 || ptr[0] !== '#') { + throw new URIError('Invalid JSON Pointer syntax; URI fragment identifiers must begin with a hash.'); + } + if (ptr.length === 1) { + return []; + } + if (ptr[1] !== '/') { + throw new URIError('Invalid JSON Pointer syntax.'); + } + return decodeFragmentSegments(ptr.substring(2).split('/')); +}; + +const traverse = (obj, func, path = []) => { + if (!obj || typeof obj !== 'object') + return; + for (const i in obj) { + if (!obj.hasOwnProperty(i)) + continue; + func({ parent: obj, parentPath: path, property: i, propertyValue: obj[i] }); + if (obj[i] && typeof obj[i] === 'object') { + traverse(obj[i], func, path.concat(i)); + } + } +}; + +const BUNDLE_ROOT = '__bundled__'; +const ERRORS_ROOT = '__errors__'; +const bundleTarget = ({ document, path }, cur) => _bundle(lodash.cloneDeep(document), path, { [path]: true }, cur); +const _bundle = (document, path, stack, cur, bundledRefInventory = {}, bundledObj = {}, errorsObj = {}) => { + const objectToBundle = lodash.get(document, pointerToPath(path)); + traverse(cur ? cur : objectToBundle, ({ parent }) => { + if (hasRef(parent) && isLocalRef(parent.$ref)) { + const $ref = parent.$ref; + if (errorsObj[$ref]) + return; + if (bundledRefInventory[$ref]) { + parent.$ref = bundledRefInventory[$ref]; + return; + } + let _path; + let inventoryPath; + let inventoryRef; + try { + _path = pointerToPath($ref); + inventoryPath = [BUNDLE_ROOT, ..._path]; + inventoryRef = pathToPointer(inventoryPath); + } + catch (error) { + errorsObj[$ref] = error.message; + } + if (!_path || !inventoryPath || !inventoryRef) + return; + const bundled$Ref = lodash.get(document, _path); + if (bundled$Ref) { + const pathProcessed = []; + bundledRefInventory[$ref] = inventoryRef; + parent.$ref = inventoryRef; + for (const key of _path) { + pathProcessed.push(key); + const inventoryPathProcessed = [BUNDLE_ROOT, ...pathProcessed]; + if (lodash.has(bundledObj, inventoryPathProcessed)) + continue; + const target = lodash.get(document, pathProcessed); + if (Array.isArray(target)) { + lodash.set(bundledObj, inventoryPathProcessed, new Array(target.length).fill(null)); + } + else if (typeof target === 'object') { + lodash.set(bundledObj, inventoryPathProcessed, {}); + } + } + lodash.set(bundledObj, inventoryPath, bundled$Ref); + if (!stack[$ref]) { + stack[$ref] = true; + _bundle(document, path, stack, bundled$Ref, bundledRefInventory, bundledObj, errorsObj); + stack[$ref] = false; + } + } + } + }); + lodash.set(objectToBundle, BUNDLE_ROOT, bundledObj[BUNDLE_ROOT]); + if (Object.keys(errorsObj).length) { + lodash.set(objectToBundle, ERRORS_ROOT, errorsObj); + } + return objectToBundle; +}; + +const decodePointerFragment = (value) => { + return replaceInString(replaceInString(value, '~1', '/'), '~0', '~'); +}; + +const encodePointer = (value) => { + return replaceInString(replaceInString(value, '~', '~0'), '//', '/~1'); +}; + +const extractPointerFromRef = (ref) => { + if (typeof ref !== 'string' || ref.length === 0) { + return null; + } + const index = ref.indexOf('#'); + return index === -1 ? null : ref.slice(index); +}; + +const extractSourceFromRef = (ref) => { + if (typeof ref !== 'string' || ref.length === 0 || isLocalRef(ref)) { + return null; + } + const index = ref.indexOf('#'); + return index === -1 ? ref : ref.slice(0, index); +}; + +const getFirstPrimitiveProperty = (text) => { + const scanner = jsoncParser.createScanner(text, true); + scanner.scan(); + if (scanner.getToken() !== 1) { + return; + } + scanner.scan(); + if (scanner.getToken() === 2) { + return; + } + if (scanner.getToken() !== 10) { + throw new SyntaxError('Unexpected character'); + } + const property = scanner.getTokenValue(); + scanner.scan(); + if (scanner.getToken() !== 6) { + throw new SyntaxError('Colon expected'); + } + scanner.scan(); + switch (scanner.getToken()) { + case 10: + return [property, scanner.getTokenValue()]; + case 11: + return [property, Number(scanner.getTokenValue())]; + case 8: + return [property, true]; + case 9: + return [property, false]; + case 7: + return [property, null]; + case 16: + throw new SyntaxError('Unexpected character'); + case 17: + throw new SyntaxError('Unexpected end of file'); + default: + return; + } +}; + +const getJsonPathForPosition = ({ lineMap, ast }, position) => { + const startOffset = lineMap[position.line]; + const endOffset = lineMap[position.line + 1]; + if (startOffset === void 0) { + return; + } + const node = jsoncParser.findNodeAtOffset(ast, endOffset === void 0 ? startOffset + position.character : Math.min(endOffset, startOffset + position.character), true); + if (node === undefined) { + return; + } + const path = jsoncParser.getNodePath(node); + if (path.length === 0) + return; + return path; +}; + +function getLastPathSegment(path) { + return decodePointerFragment(path.split('/').pop() || ''); +} + +const getLocationForJsonPath = ({ lineMap, ast }, path, closest = false) => { + const node = findNodeAtPath(ast, path, closest); + if (node === void 0 || node.range === void 0) { + return; + } + return { range: node.range }; +}; +function findNodeAtPath(node, path, closest) { + pathLoop: for (const part of path) { + const segment = Number.isInteger(Number(part)) ? Number(part) : part; + if (typeof segment === 'string' || (typeof segment === 'number' && node.type !== 'array')) { + if (node.type !== 'object' || !Array.isArray(node.children)) { + return closest ? node : void 0; + } + for (const propertyNode of node.children) { + if (Array.isArray(propertyNode.children) && propertyNode.children[0].value === String(segment)) { + node = propertyNode.children[1]; + continue pathLoop; + } + } + return closest ? node : void 0; + } + else { + if (node.type !== 'array' || segment < 0 || !Array.isArray(node.children) || segment >= node.children.length) { + return closest ? node : void 0; + } + node = node.children[segment]; + } + } + return node; +} + +function isObject(maybeObj) { + return typeof maybeObj === 'object' && maybeObj !== null; +} +function _resolveInlineRef(document, ref, seen) { + const source = extractSourceFromRef(ref); + if (source !== null) { + throw new ReferenceError('Cannot resolve external references'); + } + const path = pointerToPath(ref); + let value = document; + for (const segment of path) { + if (!isObject(value) || !(segment in value)) { + throw new ReferenceError(`Could not resolve '${ref}'`); + } + value = value[segment]; + if (isObject(value) && '$ref' in value) { + if (seen.includes(value)) { + return seen[seen.length - 1]; + } + seen.push(value); + if (typeof value.$ref !== 'string') { + throw new TypeError('$ref should be a string'); + } + value = _resolveInlineRef(document, value.$ref, seen); + } + } + return value; +} +function resolveInlineRef(document, ref) { + return _resolveInlineRef(document, ref, []); +} + +const TMP_MAP = new WeakMap(); +const traps = { + get(target, key, recv) { + const value = Reflect.get(target, key, recv); + if (typeof value === 'object' && value !== null) { + const root = TMP_MAP.get(target); + TMP_MAP.delete(target); + if (!('$ref' in value)) { + return _lazyInlineResolver(value, root); + } + const resolved = resolveInlineRef(root, value.$ref); + if (typeof resolved === 'object' && resolved !== null) { + return _lazyInlineResolver(resolved, root); + } + return resolved; + } + return value; + }, +}; +function _lazyInlineResolver(obj, root) { + TMP_MAP.set(obj, root); + return new Proxy(obj, traps); +} +function lazyInlineResolver(root) { + return _lazyInlineResolver(root, root); +} + +const parseWithPointers = (value, options = { disallowComments: true }) => { + const diagnostics = []; + const { ast, data, lineMap } = parseTree(value, diagnostics, options); + return { + data, + diagnostics, + ast, + lineMap, + }; +}; +function parseTree(text, errors = [], options) { + const lineMap = computeLineMap(text); + let currentParent = { type: 'array', offset: -1, length: -1, children: [], parent: void 0 }; + let currentParsedProperty = null; + let currentParsedParent = []; + const objectKeys = new WeakMap(); + const previousParsedParents = []; + function ensurePropertyComplete(endOffset) { + if (currentParent.type === 'property') { + currentParent.length = endOffset - currentParent.offset; + currentParent = currentParent.parent; + } + } + function calculateRange(startLine, startCharacter, length) { + return { + start: { + line: startLine, + character: startCharacter, + }, + end: { + line: startLine, + character: startCharacter + length, + }, + }; + } + function onValue(valueNode) { + currentParent.children.push(valueNode); + return valueNode; + } + function onParsedValue(value) { + if (Array.isArray(currentParsedParent)) { + currentParsedParent.push(value); + } + else if (currentParsedProperty !== null) { + currentParsedParent[currentParsedProperty] = value; + } + } + function onParsedComplexBegin(value) { + onParsedValue(value); + previousParsedParents.push(currentParsedParent); + currentParsedParent = value; + currentParsedProperty = null; + } + function onParsedComplexEnd() { + currentParsedParent = previousParsedParents.pop(); + } + const visitor = { + onObjectBegin: (offset, length, startLine, startCharacter) => { + currentParent = onValue({ + type: 'object', + offset, + length: -1, + parent: currentParent, + children: [], + range: calculateRange(startLine, startCharacter, length), + }); + if (options.ignoreDuplicateKeys === false) { + objectKeys.set(currentParent, []); + } + onParsedComplexBegin(createObjectLiteral(options.preserveKeyOrder === true)); + }, + onObjectProperty: (name, offset, length, startLine, startCharacter) => { + currentParent = onValue({ type: 'property', offset, length: -1, parent: currentParent, children: [] }); + currentParent.children.push({ type: 'string', value: name, offset, length, parent: currentParent }); + if (options.ignoreDuplicateKeys === false) { + const currentObjectKeys = objectKeys.get(currentParent.parent); + if (currentObjectKeys) { + if (currentObjectKeys.length === 0 || !currentObjectKeys.includes(name)) { + currentObjectKeys.push(name); + } + else { + errors.push({ + range: calculateRange(startLine, startCharacter, length), + message: 'DuplicateKey', + severity: types.DiagnosticSeverity.Error, + path: getJsonPath(currentParent), + code: 20, + }); + } + } + } + if (options.preserveKeyOrder === true) { + swapKey(currentParsedParent, name); + } + currentParsedProperty = name; + }, + onObjectEnd: (offset, length, startLine, startCharacter) => { + if (options.ignoreDuplicateKeys === false) { + objectKeys.delete(currentParent); + } + currentParent.length = offset + length - currentParent.offset; + if (currentParent.range) { + currentParent.range.end.line = startLine; + currentParent.range.end.character = startCharacter + length; + } + currentParent = currentParent.parent; + ensurePropertyComplete(offset + length); + onParsedComplexEnd(); + }, + onArrayBegin: (offset, length, startLine, startCharacter) => { + currentParent = onValue({ + type: 'array', + offset, + length: -1, + parent: currentParent, + children: [], + range: calculateRange(startLine, startCharacter, length), + }); + onParsedComplexBegin([]); + }, + onArrayEnd: (offset, length, startLine, startCharacter) => { + currentParent.length = offset + length - currentParent.offset; + if (currentParent.range) { + currentParent.range.end.line = startLine; + currentParent.range.end.character = startCharacter + length; + } + currentParent = currentParent.parent; + ensurePropertyComplete(offset + length); + onParsedComplexEnd(); + }, + onLiteralValue: (value, offset, length, startLine, startCharacter) => { + onValue({ + type: getLiteralNodeType(value), + offset, + length, + parent: currentParent, + value, + range: calculateRange(startLine, startCharacter, length), + }); + ensurePropertyComplete(offset + length); + onParsedValue(value); + }, + onSeparator: (sep, offset, length) => { + if (currentParent.type === 'property') { + if (sep === ':') { + currentParent.colonOffset = offset; + } + else if (sep === ',') { + ensurePropertyComplete(offset); + } + } + }, + onError: (error, offset, length, startLine, startCharacter) => { + errors.push({ + range: calculateRange(startLine, startCharacter, length), + message: jsoncParser.printParseErrorCode(error), + severity: types.DiagnosticSeverity.Error, + code: error, + }); + }, + }; + jsoncParser.visit(text, visitor, options); + const result = currentParent.children[0]; + if (result) { + delete result.parent; + } + return { + ast: result, + data: currentParsedParent[0], + lineMap, + }; +} +function getLiteralNodeType(value) { + switch (typeof value) { + case 'boolean': + return 'boolean'; + case 'number': + return 'number'; + case 'string': + return 'string'; + default: + return 'null'; + } +} +const computeLineMap = (input) => { + const lineMap = [0]; + let i = 0; + for (; i < input.length; i++) { + if (input[i] === '\n') { + lineMap.push(i + 1); + } + } + lineMap.push(i + 1); + return lineMap; +}; +function getJsonPath(node, path = []) { + if (node.type === 'property') { + path.unshift(node.children[0].value); + } + if (node.parent !== void 0) { + if (node.parent.type === 'array' && node.parent.parent !== void 0) { + path.unshift(node.parent.children.indexOf(node)); + } + return getJsonPath(node.parent, path); + } + return path; +} +function createObjectLiteral(preserveKeyOrder) { + return preserveKeyOrder ? createOrderedObject__default({}) : {}; +} +function swapKey(container, key) { + if (!(key in container)) + return; + const order = createOrderedObject.getOrder(container); + const index = order.indexOf(key); + if (index !== -1) { + order.splice(index, 1); + order.push(key); + } +} + +const renameObjectKey = (obj, oldKey, newKey) => { + if (!obj || !Object.hasOwnProperty.call(obj, oldKey) || oldKey === newKey) { + return obj; + } + const newObj = {}; + for (const [key, value] of Object.entries(obj)) { + if (key === oldKey) { + newObj[newKey] = value; + } + else if (!(key in newObj)) { + newObj[key] = value; + } + } + return newObj; +}; + +const safeParse = (text, reviver) => { + if (typeof text !== 'string') + return text; + try { + const num = parseNumber(text); + if (typeof num === 'string') + return num; + return JSON.parse(text, reviver); + } + catch (e) { + return void 0; + } +}; +const parseNumber = (string) => { + const numVal = Number(string); + if (Number.isFinite(numVal)) { + if (String(numVal) === string) { + return numVal; + } + return string; + } + return NaN; +}; + +const safeStringify = (value, replacer, space) => { + if (typeof value === 'string') { + return value; + } + try { + return JSON.stringify(value, replacer, space); + } + catch (_a) { + return fastStringify(value, replacer, space); + } +}; + +const startsWith = (source, val) => { + if (source instanceof Array) { + if (val instanceof Array) { + if (val.length > source.length) + return false; + for (const i in val) { + if (!val.hasOwnProperty(i)) + continue; + const si = parseInt(source[i]); + const vi = parseInt(val[i]); + if (!isNaN(si) || !isNaN(vi)) { + if (si !== vi) { + return false; + } + } + else if (source[i] !== val[i]) { + return false; + } + } + } + } + else if (typeof source === 'string') { + if (typeof val === 'string') { + return source.startsWith(val); + } + } + else { + return false; + } + return true; +}; + +const stringify = (value, replacer, space) => { + const stringified = safeStringify(value, replacer, space); + if (stringified === void 0) { + throw new Error('The value could not be stringified'); + } + return stringified; +}; + +function toPropertyPath(path) { + return path + .replace(/^(\/|#\/)/, '') + .split('/') + .map(decodePointerFragment) + .map(sanitize) + .join('.'); +} +function sanitize(fragment) { + if (fragment.includes('.')) { + return `["${fragment.replace(/"/g, '\\"')}"]`; + } + else { + return fragment; + } +} + +const KEYS = Symbol.for(createOrderedObject.ORDER_KEY_ID); +const traps$1 = { + ownKeys(target) { + return KEYS in target ? target[KEYS] : Reflect.ownKeys(target); + }, +}; +const trapAccess = (target) => new Proxy(target, traps$1); + +function trimStart(target, elems) { + if (typeof target === 'string' && typeof elems === 'string') { + return lodash.trimStart(target, elems); + } + if (!target || !Array.isArray(target) || !target.length || !elems || !Array.isArray(elems) || !elems.length) + return target; + let toRemove = 0; + for (const i in target) { + if (!target.hasOwnProperty(i)) + continue; + if (target[i] !== elems[i]) + break; + toRemove++; + } + return target.slice(toRemove); +} + +exports.BUNDLE_ROOT = BUNDLE_ROOT; +exports.ERRORS_ROOT = ERRORS_ROOT; +exports.KEYS = KEYS; +exports.bundleTarget = bundleTarget; +exports.decodePointer = decodePointer; +exports.decodePointerFragment = decodePointerFragment; +exports.encodePointer = encodePointer; +exports.encodePointerFragment = encodePointerFragment; +exports.extractPointerFromRef = extractPointerFromRef; +exports.extractSourceFromRef = extractSourceFromRef; +exports.getFirstPrimitiveProperty = getFirstPrimitiveProperty; +exports.getJsonPathForPosition = getJsonPathForPosition; +exports.getLastPathSegment = getLastPathSegment; +exports.getLocationForJsonPath = getLocationForJsonPath; +exports.hasRef = hasRef; +exports.isLocalRef = isLocalRef; +exports.lazyInlineResolver = lazyInlineResolver; +exports.parseTree = parseTree; +exports.parseWithPointers = parseWithPointers; +exports.pathToPointer = pathToPointer; +exports.pointerToPath = pointerToPath; +exports.renameObjectKey = renameObjectKey; +exports.resolveInlineRef = resolveInlineRef; +exports.safeParse = safeParse; +exports.safeStringify = safeStringify; +exports.startsWith = startsWith; +exports.stringify = stringify; +exports.toPropertyPath = toPropertyPath; +exports.trapAccess = trapAccess; +exports.traverse = traverse; +exports.trimStart = trimStart; diff --git a/.yalc/@stoplight/json/index.d.ts b/.yalc/@stoplight/json/index.d.ts new file mode 100644 index 00000000..4ae2983d --- /dev/null +++ b/.yalc/@stoplight/json/index.d.ts @@ -0,0 +1,28 @@ +export * from './bundle'; +export * from './decodePointer'; +export * from './decodePointerFragment'; +export * from './encodePointer'; +export * from './encodePointerFragment'; +export * from './extractPointerFromRef'; +export * from './extractSourceFromRef'; +export * from './getFirstPrimitiveProperty'; +export * from './getJsonPathForPosition'; +export * from './getLastPathSegment'; +export * from './getLocationForJsonPath'; +export * from './hasRef'; +export * from './isLocalRef'; +export * from './lazyInlineResolver'; +export * from './parseWithPointers'; +export * from './pathToPointer'; +export * from './pointerToPath'; +export * from './renameObjectKey'; +export * from './resolveInlineRef'; +export * from './safeParse'; +export * from './safeStringify'; +export * from './startsWith'; +export * from './stringify'; +export * from './toPropertyPath'; +export * from './trapAccess'; +export * from './traverse'; +export * from './trimStart'; +export * from './types'; diff --git a/.yalc/@stoplight/json/index.es.js b/.yalc/@stoplight/json/index.es.js new file mode 100644 index 00000000..333cff52 --- /dev/null +++ b/.yalc/@stoplight/json/index.es.js @@ -0,0 +1,681 @@ +import { isObject as isObject$1, cloneDeep, get, has, set, trimStart as trimStart$1 } from 'lodash'; +import { createScanner, findNodeAtOffset, getNodePath, visit, printParseErrorCode } from 'jsonc-parser'; +import createOrderedObject, { getOrder, ORDER_KEY_ID } from '@stoplight/ordered-object-literal'; +import { DiagnosticSeverity } from '@stoplight/types'; +import fastStringify from 'safe-stable-stringify'; + +const hasRef = (obj) => isObject$1(obj) && '$ref' in obj && typeof obj.$ref === 'string'; + +const isLocalRef = (pointer) => pointer.length > 0 && pointer[0] === '#'; + +const replaceInString = (str, find, repl) => { + const orig = str.toString(); + let res = ''; + let rem = orig; + let beg = 0; + let end = rem.indexOf(find); + while (end > -1) { + res += orig.substring(beg, beg + end) + repl; + rem = rem.substring(end + find.length, rem.length); + beg += end + find.length; + end = rem.indexOf(find); + } + if (rem.length > 0) { + res += orig.substring(orig.length - rem.length, orig.length); + } + return res; +}; + +const encodePointerFragment = (value) => { + return typeof value === 'number' ? value : replaceInString(replaceInString(value, '~', '~0'), '/', '~1'); +}; + +const pathToPointer = (path) => { + return encodeUriFragmentIdentifier(path); +}; +const encodeUriFragmentIdentifier = (path) => { + if (path && typeof path !== 'object') { + throw new TypeError('Invalid type: path must be an array of segments.'); + } + if (path.length === 0) { + return '#'; + } + return `#/${path.map(encodePointerFragment).join('/')}`; +}; + +const decodePointer = (value) => { + return replaceInString(replaceInString(decodeURIComponent('' + value), '~1', '/'), '~0', '~'); +}; + +const pointerToPath = (pointer) => { + return decodeUriFragmentIdentifier(pointer); +}; +const decodeFragmentSegments = (segments) => { + const len = segments.length; + const res = []; + let i = -1; + while (++i < len) { + res.push(decodePointer(segments[i])); + } + return res; +}; +const decodeUriFragmentIdentifier = (ptr) => { + if (typeof ptr !== 'string') { + throw new TypeError('Invalid type: JSON Pointers are represented as strings.'); + } + if (ptr.length === 0 || ptr[0] !== '#') { + throw new URIError('Invalid JSON Pointer syntax; URI fragment identifiers must begin with a hash.'); + } + if (ptr.length === 1) { + return []; + } + if (ptr[1] !== '/') { + throw new URIError('Invalid JSON Pointer syntax.'); + } + return decodeFragmentSegments(ptr.substring(2).split('/')); +}; + +const traverse = (obj, func, path = []) => { + if (!obj || typeof obj !== 'object') + return; + for (const i in obj) { + if (!obj.hasOwnProperty(i)) + continue; + func({ parent: obj, parentPath: path, property: i, propertyValue: obj[i] }); + if (obj[i] && typeof obj[i] === 'object') { + traverse(obj[i], func, path.concat(i)); + } + } +}; + +const BUNDLE_ROOT = '__bundled__'; +const ERRORS_ROOT = '__errors__'; +const bundleTarget = ({ document, path }, cur) => _bundle(cloneDeep(document), path, { [path]: true }, cur); +const _bundle = (document, path, stack, cur, bundledRefInventory = {}, bundledObj = {}, errorsObj = {}) => { + const objectToBundle = get(document, pointerToPath(path)); + traverse(cur ? cur : objectToBundle, ({ parent }) => { + if (hasRef(parent) && isLocalRef(parent.$ref)) { + const $ref = parent.$ref; + if (errorsObj[$ref]) + return; + if (bundledRefInventory[$ref]) { + parent.$ref = bundledRefInventory[$ref]; + return; + } + let _path; + let inventoryPath; + let inventoryRef; + try { + _path = pointerToPath($ref); + inventoryPath = [BUNDLE_ROOT, ..._path]; + inventoryRef = pathToPointer(inventoryPath); + } + catch (error) { + errorsObj[$ref] = error.message; + } + if (!_path || !inventoryPath || !inventoryRef) + return; + const bundled$Ref = get(document, _path); + if (bundled$Ref) { + const pathProcessed = []; + bundledRefInventory[$ref] = inventoryRef; + parent.$ref = inventoryRef; + for (const key of _path) { + pathProcessed.push(key); + const inventoryPathProcessed = [BUNDLE_ROOT, ...pathProcessed]; + if (has(bundledObj, inventoryPathProcessed)) + continue; + const target = get(document, pathProcessed); + if (Array.isArray(target)) { + set(bundledObj, inventoryPathProcessed, new Array(target.length).fill(null)); + } + else if (typeof target === 'object') { + set(bundledObj, inventoryPathProcessed, {}); + } + } + set(bundledObj, inventoryPath, bundled$Ref); + if (!stack[$ref]) { + stack[$ref] = true; + _bundle(document, path, stack, bundled$Ref, bundledRefInventory, bundledObj, errorsObj); + stack[$ref] = false; + } + } + } + }); + set(objectToBundle, BUNDLE_ROOT, bundledObj[BUNDLE_ROOT]); + if (Object.keys(errorsObj).length) { + set(objectToBundle, ERRORS_ROOT, errorsObj); + } + return objectToBundle; +}; + +const decodePointerFragment = (value) => { + return replaceInString(replaceInString(value, '~1', '/'), '~0', '~'); +}; + +const encodePointer = (value) => { + return replaceInString(replaceInString(value, '~', '~0'), '//', '/~1'); +}; + +const extractPointerFromRef = (ref) => { + if (typeof ref !== 'string' || ref.length === 0) { + return null; + } + const index = ref.indexOf('#'); + return index === -1 ? null : ref.slice(index); +}; + +const extractSourceFromRef = (ref) => { + if (typeof ref !== 'string' || ref.length === 0 || isLocalRef(ref)) { + return null; + } + const index = ref.indexOf('#'); + return index === -1 ? ref : ref.slice(0, index); +}; + +const getFirstPrimitiveProperty = (text) => { + const scanner = createScanner(text, true); + scanner.scan(); + if (scanner.getToken() !== 1) { + return; + } + scanner.scan(); + if (scanner.getToken() === 2) { + return; + } + if (scanner.getToken() !== 10) { + throw new SyntaxError('Unexpected character'); + } + const property = scanner.getTokenValue(); + scanner.scan(); + if (scanner.getToken() !== 6) { + throw new SyntaxError('Colon expected'); + } + scanner.scan(); + switch (scanner.getToken()) { + case 10: + return [property, scanner.getTokenValue()]; + case 11: + return [property, Number(scanner.getTokenValue())]; + case 8: + return [property, true]; + case 9: + return [property, false]; + case 7: + return [property, null]; + case 16: + throw new SyntaxError('Unexpected character'); + case 17: + throw new SyntaxError('Unexpected end of file'); + default: + return; + } +}; + +const getJsonPathForPosition = ({ lineMap, ast }, position) => { + const startOffset = lineMap[position.line]; + const endOffset = lineMap[position.line + 1]; + if (startOffset === void 0) { + return; + } + const node = findNodeAtOffset(ast, endOffset === void 0 ? startOffset + position.character : Math.min(endOffset, startOffset + position.character), true); + if (node === undefined) { + return; + } + const path = getNodePath(node); + if (path.length === 0) + return; + return path; +}; + +function getLastPathSegment(path) { + return decodePointerFragment(path.split('/').pop() || ''); +} + +const getLocationForJsonPath = ({ lineMap, ast }, path, closest = false) => { + const node = findNodeAtPath(ast, path, closest); + if (node === void 0 || node.range === void 0) { + return; + } + return { range: node.range }; +}; +function findNodeAtPath(node, path, closest) { + pathLoop: for (const part of path) { + const segment = Number.isInteger(Number(part)) ? Number(part) : part; + if (typeof segment === 'string' || (typeof segment === 'number' && node.type !== 'array')) { + if (node.type !== 'object' || !Array.isArray(node.children)) { + return closest ? node : void 0; + } + for (const propertyNode of node.children) { + if (Array.isArray(propertyNode.children) && propertyNode.children[0].value === String(segment)) { + node = propertyNode.children[1]; + continue pathLoop; + } + } + return closest ? node : void 0; + } + else { + if (node.type !== 'array' || segment < 0 || !Array.isArray(node.children) || segment >= node.children.length) { + return closest ? node : void 0; + } + node = node.children[segment]; + } + } + return node; +} + +function isObject(maybeObj) { + return typeof maybeObj === 'object' && maybeObj !== null; +} +function _resolveInlineRef(document, ref, seen) { + const source = extractSourceFromRef(ref); + if (source !== null) { + throw new ReferenceError('Cannot resolve external references'); + } + const path = pointerToPath(ref); + let value = document; + for (const segment of path) { + if (!isObject(value) || !(segment in value)) { + throw new ReferenceError(`Could not resolve '${ref}'`); + } + value = value[segment]; + if (isObject(value) && '$ref' in value) { + if (seen.includes(value)) { + return seen[seen.length - 1]; + } + seen.push(value); + if (typeof value.$ref !== 'string') { + throw new TypeError('$ref should be a string'); + } + value = _resolveInlineRef(document, value.$ref, seen); + } + } + return value; +} +function resolveInlineRef(document, ref) { + return _resolveInlineRef(document, ref, []); +} + +const TMP_MAP = new WeakMap(); +const traps = { + get(target, key, recv) { + const value = Reflect.get(target, key, recv); + if (typeof value === 'object' && value !== null) { + const root = TMP_MAP.get(target); + TMP_MAP.delete(target); + if (!('$ref' in value)) { + return _lazyInlineResolver(value, root); + } + const resolved = resolveInlineRef(root, value.$ref); + if (typeof resolved === 'object' && resolved !== null) { + return _lazyInlineResolver(resolved, root); + } + return resolved; + } + return value; + }, +}; +function _lazyInlineResolver(obj, root) { + TMP_MAP.set(obj, root); + return new Proxy(obj, traps); +} +function lazyInlineResolver(root) { + return _lazyInlineResolver(root, root); +} + +const parseWithPointers = (value, options = { disallowComments: true }) => { + const diagnostics = []; + const { ast, data, lineMap } = parseTree(value, diagnostics, options); + return { + data, + diagnostics, + ast, + lineMap, + }; +}; +function parseTree(text, errors = [], options) { + const lineMap = computeLineMap(text); + let currentParent = { type: 'array', offset: -1, length: -1, children: [], parent: void 0 }; + let currentParsedProperty = null; + let currentParsedParent = []; + const objectKeys = new WeakMap(); + const previousParsedParents = []; + function ensurePropertyComplete(endOffset) { + if (currentParent.type === 'property') { + currentParent.length = endOffset - currentParent.offset; + currentParent = currentParent.parent; + } + } + function calculateRange(startLine, startCharacter, length) { + return { + start: { + line: startLine, + character: startCharacter, + }, + end: { + line: startLine, + character: startCharacter + length, + }, + }; + } + function onValue(valueNode) { + currentParent.children.push(valueNode); + return valueNode; + } + function onParsedValue(value) { + if (Array.isArray(currentParsedParent)) { + currentParsedParent.push(value); + } + else if (currentParsedProperty !== null) { + currentParsedParent[currentParsedProperty] = value; + } + } + function onParsedComplexBegin(value) { + onParsedValue(value); + previousParsedParents.push(currentParsedParent); + currentParsedParent = value; + currentParsedProperty = null; + } + function onParsedComplexEnd() { + currentParsedParent = previousParsedParents.pop(); + } + const visitor = { + onObjectBegin: (offset, length, startLine, startCharacter) => { + currentParent = onValue({ + type: 'object', + offset, + length: -1, + parent: currentParent, + children: [], + range: calculateRange(startLine, startCharacter, length), + }); + if (options.ignoreDuplicateKeys === false) { + objectKeys.set(currentParent, []); + } + onParsedComplexBegin(createObjectLiteral(options.preserveKeyOrder === true)); + }, + onObjectProperty: (name, offset, length, startLine, startCharacter) => { + currentParent = onValue({ type: 'property', offset, length: -1, parent: currentParent, children: [] }); + currentParent.children.push({ type: 'string', value: name, offset, length, parent: currentParent }); + if (options.ignoreDuplicateKeys === false) { + const currentObjectKeys = objectKeys.get(currentParent.parent); + if (currentObjectKeys) { + if (currentObjectKeys.length === 0 || !currentObjectKeys.includes(name)) { + currentObjectKeys.push(name); + } + else { + errors.push({ + range: calculateRange(startLine, startCharacter, length), + message: 'DuplicateKey', + severity: DiagnosticSeverity.Error, + path: getJsonPath(currentParent), + code: 20, + }); + } + } + } + if (options.preserveKeyOrder === true) { + swapKey(currentParsedParent, name); + } + currentParsedProperty = name; + }, + onObjectEnd: (offset, length, startLine, startCharacter) => { + if (options.ignoreDuplicateKeys === false) { + objectKeys.delete(currentParent); + } + currentParent.length = offset + length - currentParent.offset; + if (currentParent.range) { + currentParent.range.end.line = startLine; + currentParent.range.end.character = startCharacter + length; + } + currentParent = currentParent.parent; + ensurePropertyComplete(offset + length); + onParsedComplexEnd(); + }, + onArrayBegin: (offset, length, startLine, startCharacter) => { + currentParent = onValue({ + type: 'array', + offset, + length: -1, + parent: currentParent, + children: [], + range: calculateRange(startLine, startCharacter, length), + }); + onParsedComplexBegin([]); + }, + onArrayEnd: (offset, length, startLine, startCharacter) => { + currentParent.length = offset + length - currentParent.offset; + if (currentParent.range) { + currentParent.range.end.line = startLine; + currentParent.range.end.character = startCharacter + length; + } + currentParent = currentParent.parent; + ensurePropertyComplete(offset + length); + onParsedComplexEnd(); + }, + onLiteralValue: (value, offset, length, startLine, startCharacter) => { + onValue({ + type: getLiteralNodeType(value), + offset, + length, + parent: currentParent, + value, + range: calculateRange(startLine, startCharacter, length), + }); + ensurePropertyComplete(offset + length); + onParsedValue(value); + }, + onSeparator: (sep, offset, length) => { + if (currentParent.type === 'property') { + if (sep === ':') { + currentParent.colonOffset = offset; + } + else if (sep === ',') { + ensurePropertyComplete(offset); + } + } + }, + onError: (error, offset, length, startLine, startCharacter) => { + errors.push({ + range: calculateRange(startLine, startCharacter, length), + message: printParseErrorCode(error), + severity: DiagnosticSeverity.Error, + code: error, + }); + }, + }; + visit(text, visitor, options); + const result = currentParent.children[0]; + if (result) { + delete result.parent; + } + return { + ast: result, + data: currentParsedParent[0], + lineMap, + }; +} +function getLiteralNodeType(value) { + switch (typeof value) { + case 'boolean': + return 'boolean'; + case 'number': + return 'number'; + case 'string': + return 'string'; + default: + return 'null'; + } +} +const computeLineMap = (input) => { + const lineMap = [0]; + let i = 0; + for (; i < input.length; i++) { + if (input[i] === '\n') { + lineMap.push(i + 1); + } + } + lineMap.push(i + 1); + return lineMap; +}; +function getJsonPath(node, path = []) { + if (node.type === 'property') { + path.unshift(node.children[0].value); + } + if (node.parent !== void 0) { + if (node.parent.type === 'array' && node.parent.parent !== void 0) { + path.unshift(node.parent.children.indexOf(node)); + } + return getJsonPath(node.parent, path); + } + return path; +} +function createObjectLiteral(preserveKeyOrder) { + return preserveKeyOrder ? createOrderedObject({}) : {}; +} +function swapKey(container, key) { + if (!(key in container)) + return; + const order = getOrder(container); + const index = order.indexOf(key); + if (index !== -1) { + order.splice(index, 1); + order.push(key); + } +} + +const renameObjectKey = (obj, oldKey, newKey) => { + if (!obj || !Object.hasOwnProperty.call(obj, oldKey) || oldKey === newKey) { + return obj; + } + const newObj = {}; + for (const [key, value] of Object.entries(obj)) { + if (key === oldKey) { + newObj[newKey] = value; + } + else if (!(key in newObj)) { + newObj[key] = value; + } + } + return newObj; +}; + +const safeParse = (text, reviver) => { + if (typeof text !== 'string') + return text; + try { + const num = parseNumber(text); + if (typeof num === 'string') + return num; + return JSON.parse(text, reviver); + } + catch (e) { + return void 0; + } +}; +const parseNumber = (string) => { + const numVal = Number(string); + if (Number.isFinite(numVal)) { + if (String(numVal) === string) { + return numVal; + } + return string; + } + return NaN; +}; + +const safeStringify = (value, replacer, space) => { + if (typeof value === 'string') { + return value; + } + try { + return JSON.stringify(value, replacer, space); + } + catch (_a) { + return fastStringify(value, replacer, space); + } +}; + +const startsWith = (source, val) => { + if (source instanceof Array) { + if (val instanceof Array) { + if (val.length > source.length) + return false; + for (const i in val) { + if (!val.hasOwnProperty(i)) + continue; + const si = parseInt(source[i]); + const vi = parseInt(val[i]); + if (!isNaN(si) || !isNaN(vi)) { + if (si !== vi) { + return false; + } + } + else if (source[i] !== val[i]) { + return false; + } + } + } + } + else if (typeof source === 'string') { + if (typeof val === 'string') { + return source.startsWith(val); + } + } + else { + return false; + } + return true; +}; + +const stringify = (value, replacer, space) => { + const stringified = safeStringify(value, replacer, space); + if (stringified === void 0) { + throw new Error('The value could not be stringified'); + } + return stringified; +}; + +function toPropertyPath(path) { + return path + .replace(/^(\/|#\/)/, '') + .split('/') + .map(decodePointerFragment) + .map(sanitize) + .join('.'); +} +function sanitize(fragment) { + if (fragment.includes('.')) { + return `["${fragment.replace(/"/g, '\\"')}"]`; + } + else { + return fragment; + } +} + +const KEYS = Symbol.for(ORDER_KEY_ID); +const traps$1 = { + ownKeys(target) { + return KEYS in target ? target[KEYS] : Reflect.ownKeys(target); + }, +}; +const trapAccess = (target) => new Proxy(target, traps$1); + +function trimStart(target, elems) { + if (typeof target === 'string' && typeof elems === 'string') { + return trimStart$1(target, elems); + } + if (!target || !Array.isArray(target) || !target.length || !elems || !Array.isArray(elems) || !elems.length) + return target; + let toRemove = 0; + for (const i in target) { + if (!target.hasOwnProperty(i)) + continue; + if (target[i] !== elems[i]) + break; + toRemove++; + } + return target.slice(toRemove); +} + +export { BUNDLE_ROOT, ERRORS_ROOT, KEYS, bundleTarget, decodePointer, decodePointerFragment, encodePointer, encodePointerFragment, extractPointerFromRef, extractSourceFromRef, getFirstPrimitiveProperty, getJsonPathForPosition, getLastPathSegment, getLocationForJsonPath, hasRef, isLocalRef, lazyInlineResolver, parseTree, parseWithPointers, pathToPointer, pointerToPath, renameObjectKey, resolveInlineRef, safeParse, safeStringify, startsWith, stringify, toPropertyPath, trapAccess, traverse, trimStart }; diff --git a/.yalc/@stoplight/json/isLocalRef.d.ts b/.yalc/@stoplight/json/isLocalRef.d.ts new file mode 100644 index 00000000..97159699 --- /dev/null +++ b/.yalc/@stoplight/json/isLocalRef.d.ts @@ -0,0 +1 @@ +export declare const isLocalRef: (pointer: string) => boolean; diff --git a/.yalc/@stoplight/json/lazyInlineResolver.d.ts b/.yalc/@stoplight/json/lazyInlineResolver.d.ts new file mode 100644 index 00000000..880e634a --- /dev/null +++ b/.yalc/@stoplight/json/lazyInlineResolver.d.ts @@ -0,0 +1,3 @@ +declare type Root = Record; +export declare function lazyInlineResolver(root: Root): object; +export {}; diff --git a/.yalc/@stoplight/json/package.json b/.yalc/@stoplight/json/package.json new file mode 100644 index 00000000..a24f83dd --- /dev/null +++ b/.yalc/@stoplight/json/package.json @@ -0,0 +1,36 @@ +{ + "name": "@stoplight/json", + "version": "0.0.0+dcaea86c", + "description": "Useful functions when working with JSON.", + "keywords": [ + "json", + "json parser", + "json.parse", + "parser", + "sourcemap" + ], + "sideEffects": false, + "files": [ + "**/*" + ], + "author": "Stoplight ", + "repository": { + "type": "git", + "url": "https://github.com/stoplightio/json" + }, + "license": "Apache-2.0", + "engines": { + "node": ">=8.3.0" + }, + "dependencies": { + "@stoplight/ordered-object-literal": "^1.0.1", + "@stoplight/types": "^11.9.0", + "jsonc-parser": "~2.2.1", + "lodash": "^4.17.15", + "safe-stable-stringify": "^1.1" + }, + "main": "index.cjs.js", + "module": "index.es.js", + "typings": "index.d.ts", + "yalcSig": "dcaea86cd500e4737278d6c557d777c7" +} diff --git a/.yalc/@stoplight/json/parseWithPointers.d.ts b/.yalc/@stoplight/json/parseWithPointers.d.ts new file mode 100644 index 00000000..5ef95435 --- /dev/null +++ b/.yalc/@stoplight/json/parseWithPointers.d.ts @@ -0,0 +1,4 @@ +import { IDiagnostic, IParserASTResult } from '@stoplight/types'; +import { IJsonASTNode, IParseOptions } from './types'; +export declare const parseWithPointers: (value: string, options?: IParseOptions) => import("@stoplight/types").IParserResult; +export declare function parseTree(text: string, errors: IDiagnostic[] | undefined, options: IParseOptions): IParserASTResult; diff --git a/.yalc/@stoplight/json/pathToPointer.d.ts b/.yalc/@stoplight/json/pathToPointer.d.ts new file mode 100644 index 00000000..3022e835 --- /dev/null +++ b/.yalc/@stoplight/json/pathToPointer.d.ts @@ -0,0 +1 @@ +export declare const pathToPointer: (path: import("@stoplight/types").Segment[]) => string; diff --git a/.yalc/@stoplight/json/pointerToPath.d.ts b/.yalc/@stoplight/json/pointerToPath.d.ts new file mode 100644 index 00000000..ba7017b1 --- /dev/null +++ b/.yalc/@stoplight/json/pointerToPath.d.ts @@ -0,0 +1 @@ +export declare const pointerToPath: (pointer: string) => import("@stoplight/types").Segment[]; diff --git a/.yalc/@stoplight/json/renameObjectKey.d.ts b/.yalc/@stoplight/json/renameObjectKey.d.ts new file mode 100644 index 00000000..36ea16f1 --- /dev/null +++ b/.yalc/@stoplight/json/renameObjectKey.d.ts @@ -0,0 +1 @@ +export declare const renameObjectKey: (obj: object, oldKey: string, newKey: string) => object; diff --git a/.yalc/@stoplight/json/resolveInlineRef.d.ts b/.yalc/@stoplight/json/resolveInlineRef.d.ts new file mode 100644 index 00000000..e7e2cecd --- /dev/null +++ b/.yalc/@stoplight/json/resolveInlineRef.d.ts @@ -0,0 +1,2 @@ +import { Dictionary } from '@stoplight/types'; +export declare function resolveInlineRef(document: Dictionary, ref: string): unknown; diff --git a/.yalc/@stoplight/json/safeParse.d.ts b/.yalc/@stoplight/json/safeParse.d.ts new file mode 100644 index 00000000..3712ea2e --- /dev/null +++ b/.yalc/@stoplight/json/safeParse.d.ts @@ -0,0 +1 @@ +export declare const safeParse: JSON['parse']; diff --git a/.yalc/@stoplight/json/safeStringify.d.ts b/.yalc/@stoplight/json/safeStringify.d.ts new file mode 100644 index 00000000..a1334d3b --- /dev/null +++ b/.yalc/@stoplight/json/safeStringify.d.ts @@ -0,0 +1,2 @@ +import { Optional } from '@stoplight/types'; +export declare const safeStringify: (value: any, replacer?: ((key: string, value: any) => any) | undefined, space?: string | number | undefined) => Optional; diff --git a/.yalc/@stoplight/json/startsWith.d.ts b/.yalc/@stoplight/json/startsWith.d.ts new file mode 100644 index 00000000..6e12ef52 --- /dev/null +++ b/.yalc/@stoplight/json/startsWith.d.ts @@ -0,0 +1 @@ +export declare const startsWith: (source: string | any[], val: string | any[]) => boolean; diff --git a/.yalc/@stoplight/json/stringify.d.ts b/.yalc/@stoplight/json/stringify.d.ts new file mode 100644 index 00000000..3b6aec50 --- /dev/null +++ b/.yalc/@stoplight/json/stringify.d.ts @@ -0,0 +1 @@ +export declare const stringify: (value: any, replacer?: ((key: string, value: any) => any) | undefined, space?: string | number | undefined) => string; diff --git a/.yalc/@stoplight/json/toPropertyPath.d.ts b/.yalc/@stoplight/json/toPropertyPath.d.ts new file mode 100644 index 00000000..b0fd65b5 --- /dev/null +++ b/.yalc/@stoplight/json/toPropertyPath.d.ts @@ -0,0 +1 @@ +export declare function toPropertyPath(path: string): string; diff --git a/.yalc/@stoplight/json/trapAccess.d.ts b/.yalc/@stoplight/json/trapAccess.d.ts new file mode 100644 index 00000000..80972a8b --- /dev/null +++ b/.yalc/@stoplight/json/trapAccess.d.ts @@ -0,0 +1,2 @@ +export declare const KEYS: unique symbol; +export declare const trapAccess: (target: T) => T; diff --git a/.yalc/@stoplight/json/traverse.d.ts b/.yalc/@stoplight/json/traverse.d.ts new file mode 100644 index 00000000..803c138b --- /dev/null +++ b/.yalc/@stoplight/json/traverse.d.ts @@ -0,0 +1,6 @@ +export declare const traverse: (obj: unknown, func: (opts: { + parent: unknown; + parentPath: import("@stoplight/types").Segment[]; + property: import("@stoplight/types").Segment; + propertyValue: unknown; +}) => void, path?: import("@stoplight/types").Segment[]) => void; diff --git a/.yalc/@stoplight/json/trimStart.d.ts b/.yalc/@stoplight/json/trimStart.d.ts new file mode 100644 index 00000000..67c078ad --- /dev/null +++ b/.yalc/@stoplight/json/trimStart.d.ts @@ -0,0 +1,2 @@ +export declare function trimStart(target: any[], elems: any[]): any[]; +export declare function trimStart(target: string, elems: string): string; diff --git a/.yalc/@stoplight/json/types.d.ts b/.yalc/@stoplight/json/types.d.ts new file mode 100644 index 00000000..4646c6e8 --- /dev/null +++ b/.yalc/@stoplight/json/types.d.ts @@ -0,0 +1,17 @@ +import { IParserResult, IRange } from '@stoplight/types'; +import { Node, NodeType, ParseOptions } from 'jsonc-parser'; +export interface IJsonASTNode extends Node { + type: NodeType; + value?: any; + offset: number; + length: number; + range?: IRange; + colonOffset?: number; + parent?: IJsonASTNode; + children?: IJsonASTNode[]; +} +export interface IParseOptions extends ParseOptions { + ignoreDuplicateKeys?: boolean; + preserveKeyOrder?: boolean; +} +export declare type JsonParserResult = IParserResult; diff --git a/.yalc/@stoplight/json/yalc.sig b/.yalc/@stoplight/json/yalc.sig new file mode 100644 index 00000000..c4a41c1a --- /dev/null +++ b/.yalc/@stoplight/json/yalc.sig @@ -0,0 +1 @@ +dcaea86cd500e4737278d6c557d777c7 \ No newline at end of file diff --git a/jest.config.js b/jest.config.js index 4a5b465e..3508b875 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,4 +1,4 @@ module.exports = { - preset: 'ts-jest', + preset: '@stoplight/scripts', testEnvironment: 'node', }; diff --git a/package.json b/package.json index 967ed198..0b18a8f1 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ }, "dependencies": { "@openapi-contrib/openapi-schema-to-json-schema": "^3.0.4", - "@stoplight/json": "^3.10.2", + "@stoplight/json": "file:.yalc/@stoplight/json", "@stoplight/types": "^11.9.0", "@types/swagger-schema-official": "~2.0.21", "@types/to-json-schema": "^0.2.0", diff --git a/src/__tests__/utils.test.ts b/src/__tests__/utils.test.ts index 12116421..f55a03e0 100644 --- a/src/__tests__/utils.test.ts +++ b/src/__tests__/utils.test.ts @@ -1,6 +1,6 @@ import * as urijs from 'urijs'; -import { maybeResolveLocalRef, URI } from '../utils'; +import { URI } from '../utils'; describe('URI()', () => { it('instantiates from string', () => { @@ -118,38 +118,38 @@ describe('URI()', () => { }); }); -describe('maybeResolveLocalRef()', () => { - it('follows $refs', () => { - expect( - maybeResolveLocalRef( - { - a: { - $ref: '#/b', - }, - b: { - c: 'woo', - }, - }, - { $ref: '#/a/c' }, - ), - ).toEqual('woo'); - }); - - it('handles invalid $refs', () => { - expect(maybeResolveLocalRef({ a: true }, { $ref: '#a' })).toStrictEqual({ $ref: '#a' }); - }); - - it('handles circular references', () => { - const document = { - get a(): unknown { - return this.a; - }, - }; - - expect( - maybeResolveLocalRef(document, { - $ref: '#/a', - }), - ).toStrictEqual({ $ref: '#/a' }); - }); -}); +// describe('maybeResolveLocalRef()', () => { +// it('follows $refs', () => { +// expect( +// maybeResolveLocalRef( +// { +// a: { +// $ref: '#/b', +// }, +// b: { +// c: 'woo', +// }, +// }, +// { $ref: '#/a/c' }, +// ), +// ).toEqual('woo'); +// }); +// +// it('handles invalid $refs', () => { +// expect(maybeResolveLocalRef({ a: true }, { $ref: '#a' })).toStrictEqual({ $ref: '#a' }); +// }); +// +// it('handles circular references', () => { +// const document = { +// get a(): unknown { +// return this.a; +// }, +// }; +// +// expect( +// maybeResolveLocalRef(document, { +// $ref: '#/a', +// }), +// ).toStrictEqual({ $ref: '#/a' }); +// }); +// }); diff --git a/src/oas/__tests__/__snapshots__/operation.test.ts.snap b/src/oas/__tests__/__snapshots__/operation.test.ts.snap index 1f5f4b5f..95ee745e 100644 --- a/src/oas/__tests__/__snapshots__/operation.test.ts.snap +++ b/src/oas/__tests__/__snapshots__/operation.test.ts.snap @@ -15,14 +15,110 @@ Array [ "examples": Array [], "mediaType": "application/json", "schema": Object { - "$ref": "#/definitions/Pet", + "properties": Object { + "category": Object { + "properties": Object { + "name": Object { + "type": "string", + }, + }, + "required": Array [ + "name", + ], + "title": "Category", + "type": "object", + }, + "id": Object { + "format": "int64", + "type": "integer", + }, + "name": Object { + "example": "doggie", + "type": "string", + }, + "photoUrls": Object { + "items": Object { + "type": "string", + }, + "type": "array", + "xml": Object { + "name": "photoUrl", + "wrapped": true, + }, + }, + "status": Object { + "description": "pet status in the store", + "enum": Array [ + "available", + "pending", + "sold", + ], + "type": "string", + }, + }, + "required": Array [ + "name", + "photoUrls", + ], + "type": "object", + "xml": Object { + "name": "Pet", + }, }, }, Object { "examples": Array [], "mediaType": "application/xml", "schema": Object { - "$ref": "#/definitions/Pet", + "properties": Object { + "category": Object { + "properties": Object { + "name": Object { + "type": "string", + }, + }, + "required": Array [ + "name", + ], + "title": "Category", + "type": "object", + }, + "id": Object { + "format": "int64", + "type": "integer", + }, + "name": Object { + "example": "doggie", + "type": "string", + }, + "photoUrls": Object { + "items": Object { + "type": "string", + }, + "type": "array", + "xml": Object { + "name": "photoUrl", + "wrapped": true, + }, + }, + "status": Object { + "description": "pet status in the store", + "enum": Array [ + "available", + "pending", + "sold", + ], + "type": "string", + }, + }, + "required": Array [ + "name", + "photoUrls", + ], + "type": "object", + "xml": Object { + "name": "Pet", + }, }, }, ], @@ -247,14 +343,110 @@ Array [ "examples": Array [], "mediaType": "application/json", "schema": Object { - "$ref": "#/definitions/Pet", + "properties": Object { + "category": Object { + "properties": Object { + "name": Object { + "type": "string", + }, + }, + "required": Array [ + "name", + ], + "title": "Category", + "type": "object", + }, + "id": Object { + "format": "int64", + "type": "integer", + }, + "name": Object { + "example": "doggie", + "type": "string", + }, + "photoUrls": Object { + "items": Object { + "type": "string", + }, + "type": "array", + "xml": Object { + "name": "photoUrl", + "wrapped": true, + }, + }, + "status": Object { + "description": "pet status in the store", + "enum": Array [ + "available", + "pending", + "sold", + ], + "type": "string", + }, + }, + "required": Array [ + "name", + "photoUrls", + ], + "type": "object", + "xml": Object { + "name": "Pet", + }, }, }, Object { "examples": Array [], "mediaType": "application/xml", "schema": Object { - "$ref": "#/definitions/Pet", + "properties": Object { + "category": Object { + "properties": Object { + "name": Object { + "type": "string", + }, + }, + "required": Array [ + "name", + ], + "title": "Category", + "type": "object", + }, + "id": Object { + "format": "int64", + "type": "integer", + }, + "name": Object { + "example": "doggie", + "type": "string", + }, + "photoUrls": Object { + "items": Object { + "type": "string", + }, + "type": "array", + "xml": Object { + "name": "photoUrl", + "wrapped": true, + }, + }, + "status": Object { + "description": "pet status in the store", + "enum": Array [ + "available", + "pending", + "sold", + ], + "type": "string", + }, + }, + "required": Array [ + "name", + "photoUrls", + ], + "type": "object", + "xml": Object { + "name": "Pet", + }, }, }, ], @@ -297,14 +489,36 @@ Array [ "examples": Array [], "mediaType": "application/xml", "schema": Object { - "$ref": "#/definitions/Error", + "properties": Object { + "code": Object { + "type": "string", + }, + "message": Object { + "type": "string", + }, + }, + "required": Array [ + "code", + ], + "type": "object", }, }, Object { "examples": Array [], "mediaType": "application/json", "schema": Object { - "$ref": "#/definitions/Error", + "properties": Object { + "code": Object { + "type": "string", + }, + "message": Object { + "type": "string", + }, + }, + "required": Array [ + "code", + ], + "type": "object", }, }, ], @@ -375,9 +589,128 @@ Array [ "path": "/pets", "request": Object { "body": Object { - "contents": Array [], - "description": undefined, - "required": undefined, + "contents": Array [ + Object { + "encodings": Array [], + "examples": Array [], + "mediaType": "application/json", + "schema": Object { + "$schema": "http://json-schema.org/draft-04/schema#", + "properties": Object { + "category": Object { + "properties": Object { + "name": Object { + "type": "string", + }, + }, + "required": Array [ + "name", + ], + "title": "Category", + "type": "object", + }, + "id": Object { + "format": "int64", + "maximum": 9223372036854776000, + "minimum": -9223372036854776000, + "type": "integer", + }, + "name": Object { + "example": "doggie", + "type": "string", + }, + "photoUrls": Object { + "items": Object { + "type": "string", + }, + "type": "array", + "xml": Object { + "name": "photoUrl", + "wrapped": true, + }, + }, + "status": Object { + "description": "pet status in the store", + "enum": Array [ + "available", + "pending", + "sold", + ], + "type": "string", + }, + }, + "required": Array [ + "name", + "photoUrls", + ], + "type": "object", + "xml": Object { + "name": "Pet", + }, + }, + }, + Object { + "encodings": Array [], + "examples": Array [], + "mediaType": "application/xml", + "schema": Object { + "$schema": "http://json-schema.org/draft-04/schema#", + "properties": Object { + "category": Object { + "properties": Object { + "name": Object { + "type": "string", + }, + }, + "required": Array [ + "name", + ], + "title": "Category", + "type": "object", + }, + "id": Object { + "format": "int64", + "maximum": 9223372036854776000, + "minimum": -9223372036854776000, + "type": "integer", + }, + "name": Object { + "example": "doggie", + "type": "string", + }, + "photoUrls": Object { + "items": Object { + "type": "string", + }, + "type": "array", + "xml": Object { + "name": "photoUrl", + "wrapped": true, + }, + }, + "status": Object { + "description": "pet status in the store", + "enum": Array [ + "available", + "pending", + "sold", + ], + "type": "string", + }, + }, + "required": Array [ + "name", + "photoUrls", + ], + "type": "object", + "xml": Object { + "name": "Pet", + }, + }, + }, + ], + "description": "Pet object that needs to be added to the store", + "required": true, }, "cookie": Array [], "headers": Array [], @@ -498,9 +831,128 @@ Array [ "path": "/pet/{petId}", "request": Object { "body": Object { - "contents": Array [], - "description": undefined, - "required": undefined, + "contents": Array [ + Object { + "encodings": Array [], + "examples": Array [], + "mediaType": "application/json", + "schema": Object { + "$schema": "http://json-schema.org/draft-04/schema#", + "properties": Object { + "category": Object { + "properties": Object { + "name": Object { + "type": "string", + }, + }, + "required": Array [ + "name", + ], + "title": "Category", + "type": "object", + }, + "id": Object { + "format": "int64", + "maximum": 9223372036854776000, + "minimum": -9223372036854776000, + "type": "integer", + }, + "name": Object { + "example": "doggie", + "type": "string", + }, + "photoUrls": Object { + "items": Object { + "type": "string", + }, + "type": "array", + "xml": Object { + "name": "photoUrl", + "wrapped": true, + }, + }, + "status": Object { + "description": "pet status in the store", + "enum": Array [ + "available", + "pending", + "sold", + ], + "type": "string", + }, + }, + "required": Array [ + "name", + "photoUrls", + ], + "type": "object", + "xml": Object { + "name": "Pet", + }, + }, + }, + Object { + "encodings": Array [], + "examples": Array [], + "mediaType": "application/xml", + "schema": Object { + "$schema": "http://json-schema.org/draft-04/schema#", + "properties": Object { + "category": Object { + "properties": Object { + "name": Object { + "type": "string", + }, + }, + "required": Array [ + "name", + ], + "title": "Category", + "type": "object", + }, + "id": Object { + "format": "int64", + "maximum": 9223372036854776000, + "minimum": -9223372036854776000, + "type": "integer", + }, + "name": Object { + "example": "doggie", + "type": "string", + }, + "photoUrls": Object { + "items": Object { + "type": "string", + }, + "type": "array", + "xml": Object { + "name": "photoUrl", + "wrapped": true, + }, + }, + "status": Object { + "description": "pet status in the store", + "enum": Array [ + "available", + "pending", + "sold", + ], + "type": "string", + }, + }, + "required": Array [ + "name", + "photoUrls", + ], + "type": "object", + "xml": Object { + "name": "Pet", + }, + }, + }, + ], + "description": "Pet object that needs to be added to the store", + "required": true, }, "cookie": Array [], "headers": Array [], diff --git a/src/oas/__tests__/operation.test.ts b/src/oas/__tests__/operation.test.ts index b3b760ce..402f32c5 100644 --- a/src/oas/__tests__/operation.test.ts +++ b/src/oas/__tests__/operation.test.ts @@ -4,8 +4,8 @@ import { Spec } from 'swagger-schema-official'; import { transformOas2Operations } from '../../oas2/operation'; import { transformOas3Operations } from '../../oas3/operation'; -const oas2KitchenSinkJson: Spec = require('./fixtures//oas2-kitchen-sink.json'); -const oas3KitchenSinkJson: OpenAPIObject = require('./fixtures//oas3-kitchen-sink.json'); +const oas2KitchenSinkJson: Spec = require('./fixtures/oas2-kitchen-sink.json'); +const oas3KitchenSinkJson: OpenAPIObject = require('./fixtures/oas3-kitchen-sink.json'); describe('oas operation', () => { it('openapi v2', () => { diff --git a/src/oas/accessors.ts b/src/oas/accessors.ts index 5840053b..e69661b6 100644 --- a/src/oas/accessors.ts +++ b/src/oas/accessors.ts @@ -1,16 +1,11 @@ -import { isObject, map, unionBy } from 'lodash'; - -import { maybeResolveLocalRef } from '../utils'; +import { isObject, unionBy } from 'lodash'; export function getValidOasParameters( document: unknown, operationParameters: ParamType[] | undefined, pathParameters: ParamType[] | undefined, ) { - const resolvedOperationParams = map(operationParameters, x => maybeResolveLocalRef(document, x) as ParamType); - const resolvedPathParams = map(pathParameters, x => maybeResolveLocalRef(document, x) as ParamType); - - return unionBy(resolvedOperationParams, resolvedPathParams, (parameter?: ParamType) => { + return unionBy(operationParameters, pathParameters, (parameter?: ParamType) => { return isObject(parameter) ? `${parameter.name}-${parameter.in}` : 'invalid'; }).filter(isObject); } diff --git a/src/oas2/operation.ts b/src/oas2/operation.ts index e398d11b..b1882982 100644 --- a/src/oas2/operation.ts +++ b/src/oas2/operation.ts @@ -1,3 +1,4 @@ +import { lazyInlineResolver } from '@stoplight/json'; import { IHttpOperation } from '@stoplight/types'; import { get, isNil, omitBy } from 'lodash'; import { Operation, Parameter, Path, Response, Spec } from 'swagger-schema-official'; @@ -6,7 +7,6 @@ import { getOasTags, getValidOasParameters } from '../oas/accessors'; import { transformOasOperations } from '../oas/operation'; import { translateToTags } from '../oas/tag'; import { Oas2HttpOperationTransformer } from '../oas/types'; -import { maybeResolveLocalRef } from '../utils'; import { getConsumes, getProduces } from './accessors'; import { translateToRequest } from './transformers/request'; import { translateToResponses } from './transformers/responses'; @@ -14,16 +14,16 @@ import { translateToSecurities } from './transformers/securities'; import { translateToServers } from './transformers/servers'; export function transformOas2Operations(document: Spec): IHttpOperation[] { - return transformOasOperations(document, transformOas2Operation); + return transformOasOperations(lazyInlineResolver(document as any) as any, transformOas2Operation); } export const transformOas2Operation: Oas2HttpOperationTransformer = ({ document, path, method }) => { - const pathObj = maybeResolveLocalRef(document, get(document, ['paths', path])) as Path; + const pathObj = get(document, ['paths', path]) as Path; if (!pathObj) { throw new Error(`Could not find ${['paths', path].join('/')} in the provided spec.`); } - const operation = maybeResolveLocalRef(document, get(document, ['paths', path, method])) as Operation; + const operation = get(document, ['paths', path, method]) as Operation; if (!operation) { throw new Error(`Could not find ${['paths', path, method].join('/')} in the provided spec.`); } diff --git a/src/oas2/transformers/responses.ts b/src/oas2/transformers/responses.ts index 8fbe8da5..3404e69d 100644 --- a/src/oas2/transformers/responses.ts +++ b/src/oas2/transformers/responses.ts @@ -3,7 +3,7 @@ import { JSONSchema4 } from 'json-schema'; import { chain, compact, map, partial } from 'lodash'; import type { Spec } from 'swagger-schema-official'; -import { isDictionary, maybeResolveLocalRef } from '../../utils'; +import { isDictionary } from '../../utils'; import { isResponseObject } from '../guards'; import { getExamplesFromSchema } from './getExamplesFromSchema'; import { translateToHeaderParams } from './params'; @@ -14,12 +14,11 @@ function translateToResponse( response: unknown, statusCode: string, ): Optional { - const resolvedResponse = maybeResolveLocalRef(document, response); - if (!isResponseObject(resolvedResponse)) return; + if (!isResponseObject(response)) return; - const headers = translateToHeaderParams(resolvedResponse.headers || {}); + const headers = translateToHeaderParams(response.headers || {}); const objectifiedExamples = chain( - resolvedResponse.examples || (resolvedResponse.schema ? getExamplesFromSchema(resolvedResponse.schema) : void 0), + response.examples || (response.schema ? getExamplesFromSchema(response.schema) : void 0), ) .mapValues((value, key) => ({ key, value })) .values() @@ -27,13 +26,13 @@ function translateToResponse( const contents = produces.map(produceElement => ({ mediaType: produceElement, - schema: resolvedResponse.schema as JSONSchema4, + schema: response.schema as JSONSchema4, examples: objectifiedExamples.filter(example => example.key === produceElement), })); const translatedResponses = { code: statusCode, - description: resolvedResponse.description, + description: response.description, headers, contents, }; diff --git a/src/oas3/operation.ts b/src/oas3/operation.ts index 02c15e86..e0cee6d8 100644 --- a/src/oas3/operation.ts +++ b/src/oas3/operation.ts @@ -1,3 +1,4 @@ +import { lazyInlineResolver } from '@stoplight/json'; import { IHttpOperation } from '@stoplight/types'; import { get, isNil, omitBy } from 'lodash'; import type { OpenAPIObject, OperationObject, ParameterObject, PathsObject, RequestBodyObject } from 'openapi3-ts'; @@ -6,7 +7,6 @@ import { transformOasOperations } from '../oas'; import { getOasTags, getValidOasParameters } from '../oas/accessors'; import { translateToTags } from '../oas/tag'; import { Oas3HttpOperationTransformer } from '../oas/types'; -import { maybeResolveLocalRef } from '../utils'; import { isServerObject } from './guards'; import { translateToCallbacks } from './transformers/callbacks'; import { translateToRequest } from './transformers/request'; @@ -15,16 +15,16 @@ import { translateToSecurities } from './transformers/securities'; import { translateToServers } from './transformers/servers'; export function transformOas3Operations(document: OpenAPIObject): IHttpOperation[] { - return transformOasOperations(document, transformOas3Operation); + return transformOasOperations(lazyInlineResolver(document as any) as any, transformOas3Operation); } export const transformOas3Operation: Oas3HttpOperationTransformer = ({ document, path, method }) => { - const pathObj = maybeResolveLocalRef(document, get(document, ['paths', path])) as PathsObject; + const pathObj = get(document, ['paths', path]) as PathsObject; if (!pathObj) { throw new Error(`Could not find ${['paths', path].join('/')} in the provided spec.`); } - const operation = maybeResolveLocalRef(document, get(document, ['paths', path, method])) as OperationObject; + const operation = get(document, ['paths', path, method]) as OperationObject; if (!operation) { throw new Error(`Could not find ${['paths', path, method].join('/')} in the provided spec.`); } diff --git a/src/oas3/transformers/__tests__/responses.test.ts b/src/oas3/transformers/__tests__/responses.test.ts index 7e95d6ea..8903cce4 100644 --- a/src/oas3/transformers/__tests__/responses.test.ts +++ b/src/oas3/transformers/__tests__/responses.test.ts @@ -1,3 +1,5 @@ +import { lazyInlineResolver } from '@stoplight/json'; + import { translateToResponses } from '../responses'; describe('translateToOas3Responses', () => { @@ -95,7 +97,7 @@ describe('translateToOas3Responses', () => { }); it('should resolve $refs nullish responses', () => { - const document = { + const document = lazyInlineResolver({ openapi: '3.0.0', paths: { '/user': { @@ -139,7 +141,7 @@ describe('translateToOas3Responses', () => { }, }, }, - }; + }) as any; expect(translateToResponses(document, document.paths['/user'].get.responses)).toEqual([ { diff --git a/src/oas3/transformers/responses.ts b/src/oas3/transformers/responses.ts index 240b0a6d..44c31b50 100644 --- a/src/oas3/transformers/responses.ts +++ b/src/oas3/transformers/responses.ts @@ -6,52 +6,29 @@ import { IMediaTypeContent, Optional, } from '@stoplight/types'; -import { compact, each, map, partial } from 'lodash'; +import { compact, map, partial } from 'lodash'; import { OpenAPIObject } from 'openapi3-ts'; -import { isDictionary, maybeResolveLocalRef } from '../../utils'; +import { isDictionary } from '../../utils'; import { isResponseObject } from '../guards'; import { translateHeaderObject, translateMediaTypeObject } from './content'; -function resolveMediaObject(document: DeepPartial, maybeMediaObject: unknown) { - if (!isDictionary(maybeMediaObject)) { - return null; - } - - const mediaObject = { ...maybeMediaObject }; - if (isDictionary(mediaObject.schema)) { - mediaObject.schema = maybeResolveLocalRef(document, mediaObject.schema); - } - - if (isDictionary(mediaObject.examples)) { - const examples = { ...mediaObject.examples }; - mediaObject.examples = examples; - each(examples, (exampleValue, exampleName) => { - examples[exampleName] = maybeResolveLocalRef(document, exampleValue); - }); - } - - return mediaObject; -} - function translateToResponse( document: DeepPartial, response: unknown, statusCode: string, ): Optional { - const resolvedResponse = maybeResolveLocalRef(document, response); - if (!isResponseObject(resolvedResponse)) return; + if (!isResponseObject(response)) return; return { code: statusCode, - description: resolvedResponse.description, + description: response.description, headers: compact( - map & unknown, Optional>(resolvedResponse.headers, translateHeaderObject), + map & unknown, Optional>(response.headers, translateHeaderObject), ), contents: compact( - map & unknown, Optional>( - resolvedResponse.content, - (mediaObject, mediaType) => translateMediaTypeObject(resolveMediaObject(document, mediaObject), mediaType), + map & unknown, Optional>(response.content, (mediaObject, mediaType) => + translateMediaTypeObject(mediaObject, mediaType), ), ), }; diff --git a/src/utils.ts b/src/utils.ts index e7c55533..73b79a4f 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,4 +1,4 @@ -import { hasRef, isLocalRef, pathToPointer, pointerToPath, resolveInlineRef } from '@stoplight/json'; +import { pathToPointer, pointerToPath } from '@stoplight/json'; import { Dictionary, Optional } from '@stoplight/types'; import { isObjectLike, map } from 'lodash'; import * as URIJS from 'urijs'; @@ -54,15 +54,3 @@ export function URI(url: string | URI = '') { export const isDictionary = (maybeDictionary: unknown): maybeDictionary is Dictionary => isObjectLike(maybeDictionary); - -export const maybeResolveLocalRef = (document: unknown, target: unknown): unknown => { - if (isDictionary(document) && hasRef(target) && isLocalRef(target.$ref)) { - try { - return resolveInlineRef(document, target.$ref); - } catch { - return target; - } - } - - return target; -}; diff --git a/yalc.lock b/yalc.lock new file mode 100644 index 00000000..d77ad002 --- /dev/null +++ b/yalc.lock @@ -0,0 +1,10 @@ +{ + "version": "v1", + "packages": { + "@stoplight/json": { + "signature": "dcaea86cd500e4737278d6c557d777c7", + "file": true, + "replaced": "^3.10.2" + } + } +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index a2fc5e6f..c3f44061 100644 --- a/yarn.lock +++ b/yarn.lock @@ -974,10 +974,8 @@ dependencies: eslint-config-prettier "^6.7.0" -"@stoplight/json@^3.10.2": - version "3.10.2" - resolved "https://registry.yarnpkg.com/@stoplight/json/-/json-3.10.2.tgz#a17463c7576602971edbf6f11d3eaed80db262bb" - integrity sha512-mUf4t2bOBZjVa8KdEI4+EqX/8zXJLfGKv/cj++giLbCkYNGjBgJnmPSDNOOBgJHpocdVml0hK8ZuLADqWVVB2Q== +"@stoplight/json@file:.yalc/@stoplight/json": + version "0.0.0" dependencies: "@stoplight/ordered-object-literal" "^1.0.1" "@stoplight/types" "^11.9.0"