From b4e8afbc5120621a0de91b9fdd03f0fce78efa33 Mon Sep 17 00:00:00 2001 From: Oliwia Rogala Date: Thu, 23 Jan 2025 09:31:50 +0100 Subject: [PATCH 1/5] feat: implement YAML parser adapter for JSON Schema 2020-12 Refs #1868 --- .../.eslintignore | 8 + .../.gitignore | 7 + .../.mocharc.json | 6 + .../.npmrc | 2 + .../README.md | 90 +++++++ .../config/api-extractor/api-extractor.json | 5 + .../config/webpack/browser.config.js | 92 +++++++ .../config/webpack/traits.config.js | 32 +++ .../package.json | 63 +++++ .../src/adapter.ts | 48 ++++ .../src/media-types.ts | 11 + .../test/.eslintrc | 55 +++++ .../test/__snapshots__/adapter.mjs.snap | 226 ++++++++++++++++++ .../test/adapter.ts | 104 ++++++++ .../test/fixtures/json-schema-2020-12.json | 103 ++++++++ .../test/fixtures/json-schema-2020-12.yaml | 75 ++++++ .../test/media-types.ts | 18 ++ .../test/mocha-bootstrap.ts | 11 + .../test/tsconfig.json | 10 + .../tsconfig.declaration.json | 9 + .../tsconfig.json | 6 + 21 files changed, 981 insertions(+) create mode 100644 packages/apidom-parser-adapter-json-schema-yaml-2020-12/.eslintignore create mode 100644 packages/apidom-parser-adapter-json-schema-yaml-2020-12/.gitignore create mode 100644 packages/apidom-parser-adapter-json-schema-yaml-2020-12/.mocharc.json create mode 100644 packages/apidom-parser-adapter-json-schema-yaml-2020-12/.npmrc create mode 100644 packages/apidom-parser-adapter-json-schema-yaml-2020-12/README.md create mode 100644 packages/apidom-parser-adapter-json-schema-yaml-2020-12/config/api-extractor/api-extractor.json create mode 100644 packages/apidom-parser-adapter-json-schema-yaml-2020-12/config/webpack/browser.config.js create mode 100644 packages/apidom-parser-adapter-json-schema-yaml-2020-12/config/webpack/traits.config.js create mode 100644 packages/apidom-parser-adapter-json-schema-yaml-2020-12/package.json create mode 100644 packages/apidom-parser-adapter-json-schema-yaml-2020-12/src/adapter.ts create mode 100644 packages/apidom-parser-adapter-json-schema-yaml-2020-12/src/media-types.ts create mode 100644 packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/.eslintrc create mode 100644 packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/__snapshots__/adapter.mjs.snap create mode 100644 packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/adapter.ts create mode 100644 packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/fixtures/json-schema-2020-12.json create mode 100644 packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/fixtures/json-schema-2020-12.yaml create mode 100644 packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/media-types.ts create mode 100644 packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/mocha-bootstrap.ts create mode 100644 packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/tsconfig.json create mode 100644 packages/apidom-parser-adapter-json-schema-yaml-2020-12/tsconfig.declaration.json create mode 100644 packages/apidom-parser-adapter-json-schema-yaml-2020-12/tsconfig.json diff --git a/packages/apidom-parser-adapter-json-schema-yaml-2020-12/.eslintignore b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/.eslintignore new file mode 100644 index 0000000000..23853b909a --- /dev/null +++ b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/.eslintignore @@ -0,0 +1,8 @@ +/**/*.js +/**/*.mjs +/**/*.cjs +/dist +/types +/config +/.nyc_output +/node_modules diff --git a/packages/apidom-parser-adapter-json-schema-yaml-2020-12/.gitignore b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/.gitignore new file mode 100644 index 0000000000..9b4533537e --- /dev/null +++ b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/.gitignore @@ -0,0 +1,7 @@ +/src/**/*.mjs +/src/**/*.cjs +/test/**/*.mjs +/dist +/types +/NOTICE +/swagger-api-apidom-parser-adapter-json-schema-yaml-2020-12-*.tgz diff --git a/packages/apidom-parser-adapter-json-schema-yaml-2020-12/.mocharc.json b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/.mocharc.json new file mode 100644 index 0000000000..edb4cc79f2 --- /dev/null +++ b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/.mocharc.json @@ -0,0 +1,6 @@ +{ + "recursive": true, + "spec": "test/**/*.mjs", + "file": ["test/mocha-bootstrap.mjs"], + "ignore": ["test/perf/**/*.mjs"] +} diff --git a/packages/apidom-parser-adapter-json-schema-yaml-2020-12/.npmrc b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/.npmrc new file mode 100644 index 0000000000..4b82d2e7bb --- /dev/null +++ b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/.npmrc @@ -0,0 +1,2 @@ +save-prefix="=" +save=false diff --git a/packages/apidom-parser-adapter-json-schema-yaml-2020-12/README.md b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/README.md new file mode 100644 index 0000000000..9b5e63605e --- /dev/null +++ b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/README.md @@ -0,0 +1,90 @@ +# @swagger-api/apidom-parser-adapter-json-schema-yaml-2020-12 + +`@swagger-api/apidom-parser-adapter-json-schema-yaml-2020-12` is a parser adapter for the [JSON Schema 2020-12](https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-01) in [YAML format](https://yaml.org/spec/1.2/spec.html). +Under the hood this adapter uses [apidom-parser-adapter-yaml-1-2](https://github.com/swagger-api/apidom/tree/main/packages/apidom-parser-adapter-yaml-1-2) +to parse a source string into generic ApiDOM in [base ApiDOM namespace](https://github.com/swagger-api/apidom/tree/main/packages/apidom#base-namespace) +which is then refracted with [JSON Schema 2020-12 Refractors](https://github.com/swagger-api/apidom/tree/main/packages/apidom-ns-json-schema-2020-12#refractors). + +## Installation + +After [prerequisites](https://github.com/swagger-api/apidom/blob/main/README.md#prerequisites) for installing this package are satisfied, you can install it +via [npm CLI](https://docs.npmjs.com/cli) by running the following command: + +```sh + $ npm install @swagger-api/apidom-parser-adapter-json-schema-yaml-2020-12 +``` + +## Parser adapter API + +This parser adapter is fully compatible with parser adapter interface required by [@swagger-api/apidom-parser](https://github.com/swagger-api/apidom/tree/main/packages/apidom-parser#mounting-parser-adapters) +and implements all required properties. + +### mediaTypes + +Defines list of media types that this parser adapter recognizes. + +```js +[ + 'application/schema;version=2020-12', + 'application/schema+yaml;version=2020-12', +] +``` + +### detect + +[Detection](https://github.com/swagger-api/apidom/blob/main/packages/apidom-parser-adapter-json-schema-yaml-2020-12/src/adapter.ts#L13) is based on a regular expression matching required JSON Schema 2020-12 symbols in YAML format. + +### namespace + +This adapter exposes an instance of [JSON Schema 2020-12 ApiDOM namespace](https://github.com/swagger-api/apidom/tree/main/packages/apidom-ns-json-schema-2020-12#json-schema-2020-12-namespace). + +### parse + +`parse` function consumes various options as a second argument. Here is a list of these options: + +Option | Type | Default | Description +--- | --- | --- | --- +`specObj` | `Object` | [Specification Object](https://github.com/swagger-api/apidom/blob/main/packages/apidom-ns-json-schema-2020-12/src/refractor/specification.ts) | This specification object drives the YAML AST transformation to JSON Schema 2020-12 ApiDOM namespace. +`sourceMap` | `Boolean` | `false` | Indicate whether to generate source maps. +`refractorOpts` | `Object` | `{}` | Refractor options are [passed to refractors](https://github.com/swagger-api/apidom/tree/main/packages/apidom-ns-json-schema-2020-12#refractor-plugins) during refracting phase. + +All unrecognized arbitrary options will be ignored. + +## Usage + +This parser adapter can be used directly or indirectly via [apidom-parser](https://github.com/swagger-api/apidom/tree/main/packages/apidom-parser). + +### Direct usage + +During direct usage you don't need to provide `mediaType` as the `parse` function is already pre-bound +with [supported media types](#mediatypes). + +```js +import { parse, detect } from '@swagger-api/apidom-parser-adapter-json-schema-yaml-2020-12'; + +// detecting +await detect('$schema: https://json-schema.org/draft/2020-12/schema'); // => true +await detect('test'); // => false + +// parsing +const parseResult = await parse('$schema: https://json-schema.org/draft/2020-12/schema', { + sourceMap: true, +}); +``` + +### Indirect usage + +You can omit the `mediaType` option here, but please read [Word on detect vs mediaTypes](https://github.com/swagger-api/apidom/tree/main/packages/apidom-parser#word-on-detect-vs-mediatypes) before you do so. + +```js +import ApiDOMParser from '@swagger-api/apidom-parser'; +import * as jsonSchemaYamlAdapter from '@swagger-api/apidom-parser-adapter-json-schema-yaml-2020-12'; + +const parser = new ApiDOMParser(); + +parser.use(jsonSchemaYamlAdapter); + +const parseResult = await parser.parse('$schema: https://json-schema.org/draft/2020-12/schema', { + mediaType: jsonSchemaYamlAdapter.mediaTypes.latest('yaml'), +}); +``` diff --git a/packages/apidom-parser-adapter-json-schema-yaml-2020-12/config/api-extractor/api-extractor.json b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/config/api-extractor/api-extractor.json new file mode 100644 index 0000000000..40bee5b261 --- /dev/null +++ b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/config/api-extractor/api-extractor.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "extends": "../../../../api-extractor.json", + "mainEntryPointFilePath": "../../types/adapter.d.ts" +} diff --git a/packages/apidom-parser-adapter-json-schema-yaml-2020-12/config/webpack/browser.config.js b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/config/webpack/browser.config.js new file mode 100644 index 0000000000..79e933394c --- /dev/null +++ b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/config/webpack/browser.config.js @@ -0,0 +1,92 @@ +import path from 'node:path'; +import { nonMinimizeTrait, minimizeTrait } from './traits.config.js'; + +const browser = { + mode: 'production', + entry: ['./src/adapter.ts'], + target: 'web', + performance: { + maxEntrypointSize: 2100000, + maxAssetSize: 2100000, + }, + output: { + path: path.resolve('./dist'), + filename: 'apidom-parser-adapter-json-schema-yaml-2020-12.browser.js', + libraryTarget: 'umd', + library: 'apidomParserAdapterJSONSchemaYAML202012', + }, + resolve: { + extensions: ['.ts', '.mjs', '.js', '.json'], + fallback: { + fs: false, + path: false, + }, + }, + module: { + rules: [ + { + test: /\.wasm$/, + loader: 'file-loader', + type: 'javascript/auto', + }, + { + test: /\.(ts|js)?$/, + exclude: /node_modules/, + use: { + loader: 'babel-loader', + options: { + babelrc: true, + rootMode: 'upward', + }, + }, + }, + ], + }, + ...nonMinimizeTrait, +}; + +const browserMin = { + mode: 'production', + entry: ['./src/adapter.ts'], + target: 'web', + performance: { + maxEntrypointSize: 310000, + maxAssetSize: 310000, + }, + output: { + path: path.resolve('./dist'), + filename: 'apidom-parser-adapter-json-schema-yaml-2020-12.browser.min.js', + libraryTarget: 'umd', + library: 'apidomParserAdapterJSONSchemaYAML202012', + }, + resolve: { + extensions: ['.ts', '.mjs', '.js', '.json'], + fallback: { + fs: false, + path: false, + }, + }, + module: { + rules: [ + { + test: /\.wasm$/, + loader: 'file-loader', + type: 'javascript/auto', + }, + { + test: /\.(ts|js)?$/, + exclude: /node_modules/, + use: { + loader: 'babel-loader', + options: { + babelrc: true, + rootMode: 'upward', + }, + }, + }, + ], + }, + ...minimizeTrait, +}; + +export default [browser, browserMin]; diff --git a/packages/apidom-parser-adapter-json-schema-yaml-2020-12/config/webpack/traits.config.js b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/config/webpack/traits.config.js new file mode 100644 index 0000000000..9043521175 --- /dev/null +++ b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/config/webpack/traits.config.js @@ -0,0 +1,32 @@ +import webpack from 'webpack'; +import TerserPlugin from 'terser-webpack-plugin'; + +export const nonMinimizeTrait = { + optimization: { + minimize: false, + usedExports: false, + concatenateModules: false, + }, +}; + +export const minimizeTrait = { + plugins: [ + new webpack.LoaderOptionsPlugin({ + minimize: true, + }), + ], + optimization: { + minimizer: [ + new TerserPlugin({ + terserOptions: { + compress: { + warnings: false, + }, + output: { + comments: false, + }, + }, + }), + ], + }, +}; diff --git a/packages/apidom-parser-adapter-json-schema-yaml-2020-12/package.json b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/package.json new file mode 100644 index 0000000000..4e74c21439 --- /dev/null +++ b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/package.json @@ -0,0 +1,63 @@ +{ + "name": "@swagger-api/apidom-parser-adapter-json-schema-yaml-2020-12", + "version": "1.0.0-beta.7", + "description": "Parser adapter for parsing YAML documents into JSON Schema 2020-12 namespace.", + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org" + }, + "type": "module", + "sideEffects": false, + "unpkg": "./dist/apidom-parser-apdater-json-schema-yaml-2020-12.browser.min.js", + "main": "./src/adapter.cjs", + "exports": { + "types": "./types/apidom-parser-adapter-json-schema-yaml-2020-12.d.ts", + "import": "./src/adapter.mjs", + "require": "./src/adapter.cjs" + }, + "types": "./types/apidom-parser-adapter-json-schema-yaml-2020-12.d.ts", + "scripts": { + "build": "npm run clean && run-p --max-parallel ${CPU_CORES:-2} typescript:declaration build:es build:cjs build:umd:browser", + "build:es": "cross-env BABEL_ENV=es babel src --out-dir src --extensions '.ts' --out-file-extension '.mjs' --root-mode 'upward'", + "build:cjs": "cross-env BABEL_ENV=cjs babel src --out-dir src --extensions '.ts' --out-file-extension '.cjs' --root-mode 'upward'", + "build:umd:browser": "cross-env BABEL_ENV=browser webpack --config config/webpack/browser.config.js --progress", + "lint": "eslint ./", + "lint:fix": "eslint ./ --fix", + "clean": "rimraf --glob 'src/**/*.mjs' 'src/**/*.cjs' 'test/**/*.mjs' ./dist ./types", + "typescript:check-types": "tsc --noEmit && tsc -p ./test/tsconfig.json --noEmit", + "typescript:declaration": "tsc -p tsconfig.declaration.json && api-extractor run -l -c ./config/api-extractor/api-extractor.json", + "test": "npm run build:es && cross-env BABEL_ENV=es babel test --out-dir test --extensions '.ts' --out-file-extension '.mjs' --root-mode 'upward' && cross-env NODE_ENV=test mocha", + "perf": "cross-env BABEL_ENV=es babel ./test/perf/index.ts --out-file ./test/perf/index.mjs --root-mode 'upward' && cross-env NODE_ENV=test node ./test/perf/index.mjs", + "perf:lexical-analysis": "cross-env BABEL_ENV=es babel ./test/perf/lexical-analysis.ts --out-file ./test/perf/lexical-analysis.mjs --root-mode 'upward' && cross-env NODE_ENV=test node ./test/perf/lexical-analysis.mjs", + "perf:syntactic-analysis": "cross-env BABEL_ENV=es babel ./test/perf/syntactic-analysis.ts --out-file ./test/perf/syntactic-analysis.mjs --root-mode 'upward' && cross-env NODE_ENV=test node ./test/perf/syntactic-analysis.mjs", + "perf:refract": "cross-env BABEL_ENV=es babel ./test/perf/refract.ts --out-file ./test/perf/refract.mjs --root-mode 'upward' && cross-env NODE_ENV=test node ./test/perf/refract.mjs", + "perf:parse": "cross-env BABEL_ENV=es babel ./test/perf/parse.ts --out-file ./test/perf/parse.mjs --root-mode 'upward' && cross-env NODE_ENV=test node ./test/perf/parse.mjs", + "prepack": "copyfiles -u 3 ../../LICENSES/* LICENSES && copyfiles -u 2 ../../NOTICE .", + "postpack": "rimraf NOTICE LICENSES" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/swagger-api/apidom.git" + }, + "author": "Vladimir Gorej", + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime-corejs3": "^7.20.7", + "@swagger-api/apidom-core": "^1.0.0-beta.7", + "@swagger-api/apidom-ns-json-schema-2020-12": "^1.0.0-beta.7", + "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.0.0-beta.7", + "@types/ramda": "~0.30.0", + "ramda": "~0.30.0", + "ramda-adjunct": "^5.0.0" + }, + "files": [ + "src/**/*.mjs", + "src/**/*.cjs", + "dist/", + "types/apidom-parser-adapter-json-schema-yaml-2020-12.d.ts", + "LICENSES", + "NOTICE", + "README.md", + "CHANGELOG.md" + ] +} diff --git a/packages/apidom-parser-adapter-json-schema-yaml-2020-12/src/adapter.ts b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/src/adapter.ts new file mode 100644 index 0000000000..4bd1e7aac6 --- /dev/null +++ b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/src/adapter.ts @@ -0,0 +1,48 @@ +import { propOr, omit } from 'ramda'; +import { isNotUndefined } from 'ramda-adjunct'; +import { ParseResultElement, createNamespace } from '@swagger-api/apidom-core'; +import { + parse as parseYAML, + detect as detectYAML, +} from '@swagger-api/apidom-parser-adapter-yaml-1-2'; +import jsonSchemaNamespace, { JSONSchemaElement } from '@swagger-api/apidom-ns-json-schema-2020-12'; + +export { default as mediaTypes } from './media-types.ts'; + +/** + * @public + */ +export const detectionRegExp = + /(?^(["']?)\$schema\2\s*:\s*(["']?)https:\/\/json-schema\.org\/draft\/(?2020-12)\/schema\3)|(?"\$schema"\s*:\s*"https:\/\/json-schema\.org\/draft\/(?2020-12)\/schema")/m; + +/** + * @public + */ +export const detect = async (source: string): Promise => + detectionRegExp.test(source) && (await detectYAML(source)); + +/** + * @public + */ +export const parse = async ( + source: string, + options: Record = {}, +): Promise => { + const refractorOpts: Record = propOr({}, 'refractorOpts', options); + const parserOpts = omit(['refractorOpts'], options); + const parseResultElement = await parseYAML(source, parserOpts); + const { result } = parseResultElement; + + if (isNotUndefined(result)) { + const jsonSchemaElement = JSONSchemaElement.refract(result, refractorOpts); + jsonSchemaElement.classes.push('result'); + parseResultElement.replaceResult(jsonSchemaElement); + } + + return parseResultElement; +}; + +/** + * @public + */ +export const namespace = createNamespace(jsonSchemaNamespace); diff --git a/packages/apidom-parser-adapter-json-schema-yaml-2020-12/src/media-types.ts b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/src/media-types.ts new file mode 100644 index 0000000000..bc67ec716e --- /dev/null +++ b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/src/media-types.ts @@ -0,0 +1,11 @@ +import { mediaTypes, JSONSchema202012MediaTypes } from '@swagger-api/apidom-ns-json-schema-2020-12'; + +/** + * @public + */ +const yamlMediaTypes = new JSONSchema202012MediaTypes( + ...mediaTypes.filterByFormat('generic'), + ...mediaTypes.filterByFormat('yaml'), +); + +export default yamlMediaTypes; diff --git a/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/.eslintrc b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/.eslintrc new file mode 100644 index 0000000000..c47eea4f48 --- /dev/null +++ b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/.eslintrc @@ -0,0 +1,55 @@ +{ + "env": { + "mocha": true + }, + "globals": { + "document": true + }, + "plugins": [ + "mocha" + ], + "rules": { + "no-void": 0, + "func-names": 0, + "prefer-arrow-callback": 0, + "no-array-constructor": 0, + "prefer-rest-params": 0, + "no-new-wrappers": 0, + "mocha/no-skipped-tests": 2, + "mocha/handle-done-callback": 2, + "mocha/valid-suite-description": 2, + "mocha/no-mocha-arrows": 2, + "mocha/no-hooks-for-single-case": 2, + "mocha/no-sibling-hooks": 2, + "mocha/no-top-level-hooks": 2, + "mocha/no-identical-title": 2, + "mocha/no-nested-tests": 2, + "mocha/no-exclusive-tests": 2, + "no-underscore-dangle": 0, + "import/no-relative-packages": 0, + "@typescript-eslint/naming-convention": [ + "error", + { + "selector": "variable", + "format": ["camelCase", "PascalCase", "UPPER_CASE"], + "leadingUnderscore": "forbid" + }, + { + "selector": "variable", + "format": null, + "filter": { + "regex": "^__dirname$", + "match": true + } + }, + { + "selector": "variable", + "format": null, + "filter": { + "regex": "^__filename$", + "match": true + } + } + ] + } +} diff --git a/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/__snapshots__/adapter.mjs.snap b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/__snapshots__/adapter.mjs.snap new file mode 100644 index 0000000000..b7901cf9d9 --- /dev/null +++ b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/__snapshots__/adapter.mjs.snap @@ -0,0 +1,226 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`adapter should parse 1`] = ` +(ParseResultElement + (JSONSchema202012Element + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (ObjectElement + (MemberElement + (StringElement) + (JSONSchema202012Element + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (ArrayElement + (NumberElement))))) + (MemberElement + (StringElement) + (JSONSchema202012Element + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (ArrayElement + (StringElement))))) + (MemberElement + (StringElement) + (JSONSchema202012Element + (MemberElement + (StringElement) + (StringElement)))) + (MemberElement + (StringElement) + (JSONSchema202012Element + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (ObjectElement + (MemberElement + (StringElement) + (BooleanElement)))) + (MemberElement + (StringElement) + (JSONSchema202012Element + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (ObjectElement + (MemberElement + (StringElement) + (StringElement)))))))) + (MemberElement + (StringElement) + (JSONSchema202012Element + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (ObjectElement + (MemberElement + (StringElement) + (BooleanElement)))) + (MemberElement + (StringElement) + (JSONSchema202012Element + (MemberElement + (StringElement) + (StringElement)))))) + (MemberElement + (StringElement) + (JSONSchema202012Element + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (ArrayElement + (StringElement) + (StringElement) + (StringElement))))))) + (MemberElement + (StringElement) + (ArrayElement + (StringElement) + (StringElement))) + (MemberElement + (StringElement) + (ObjectElement + (MemberElement + (StringElement) + (StringElement)))) + (MemberElement + (StringElement) + (JSONSchema202012Element + (MemberElement + (StringElement) + (ObjectElement + (MemberElement + (StringElement) + (JSONSchema202012Element + (MemberElement + (StringElement) + (StringElement)))))))) + (MemberElement + (StringElement) + (JSONSchema202012Element + (MemberElement + (StringElement) + (ObjectElement + (MemberElement + (StringElement) + (JSONSchema202012Element + (MemberElement + (StringElement) + (NumberElement)))))))) + (MemberElement + (StringElement) + (ObjectElement + (MemberElement + (StringElement) + (ArrayElement + (StringElement))))) + (MemberElement + (StringElement) + (ObjectElement + (MemberElement + (StringElement) + (JSONSchema202012Element + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (ObjectElement + (MemberElement + (StringElement) + (JSONSchema202012Element + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (ArrayElement + (NumberElement))))) + (MemberElement + (StringElement) + (JSONSchema202012Element + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (ArrayElement + (StringElement))))))) + (MemberElement + (StringElement) + (ObjectElement + (MemberElement + (StringElement) + (StringElement)))))) + (MemberElement + (StringElement) + (JSONSchema202012Element + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (ObjectElement + (MemberElement + (StringElement) + (JSONSchema202012Element + (MemberElement + (StringElement) + (StringElement)) + (MemberElement + (StringElement) + (StringElement)))) + (MemberElement + (StringElement) + (JSONSchema202012Element + (MemberElement + (StringElement) + (StringElement)))))) + (MemberElement + (StringElement) + (ObjectElement + (MemberElement + (StringElement) + (StringElement)))))))))) +`; diff --git a/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/adapter.ts b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/adapter.ts new file mode 100644 index 0000000000..400f8d6fe1 --- /dev/null +++ b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/adapter.ts @@ -0,0 +1,104 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { assert, expect } from 'chai'; +import dedent from 'dedent'; +import { isParseResultElement, SourceMapElement, sexprs } from '@swagger-api/apidom-core'; +import { isJSONSchemaElement } from '@swagger-api/apidom-ns-json-schema-2020-12'; + +import * as adapter from '../src/adapter.ts'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const jsonSpec = fs + .readFileSync(path.join(__dirname, 'fixtures', 'json-schema-2020-12.json')) + .toString(); +const yamlSpec = fs + .readFileSync(path.join(__dirname, 'fixtures', 'json-schema-2020-12.yaml')) + .toString(); + +describe('adapter', function () { + context('given definition in YAML 1.2 format', function () { + specify('should detect proper media type', async function () { + assert.isTrue(await adapter.detect(yamlSpec)); + }); + }); + + context('given definition in JSON format', function () { + specify('should detect proper media type', async function () { + assert.isTrue(await adapter.detect(jsonSpec)); + }); + }); + + context('given definition of unknown type', function () { + specify('should detect proper media type', async function () { + assert.isFalse(await adapter.detect('"asyncapi": "2.6.0"')); + }); + }); + + it('should parse', async function () { + const parseResult = await adapter.parse(yamlSpec, { sourceMap: true }); + + assert.isTrue(isParseResultElement(parseResult)); + assert.isTrue(isJSONSchemaElement(parseResult.content[0])); // ---- CHECK THIS LINE ---- + expect(sexprs(parseResult)).toMatchSnapshot(); + }); + + context('given zero byte empty file', function () { + specify('should return empty parse result', async function () { + const parseResult = await adapter.parse('', { sourceMap: true }); + + assert.isTrue(parseResult.isEmpty); + }); + }); + + context('given non-zero byte empty file', function () { + specify('should return empty parser result', async function () { + const parseResult = await adapter.parse(' ', { sourceMap: true }); + + assert.isTrue(parseResult.isEmpty); + }); + }); + + context('given invalid yaml file', function () { + specify('should return empty parser result', async function () { + const parseResult = await adapter.parse(' %YAML x ', { sourceMap: true }); + + assert.isTrue(parseResult.isEmpty); + }); + }); + + context('given YAML with empty node', function () { + specify('should generate source maps', async function () { + const yamlSource = dedent` + mapping: + sub-mapping: + `; + + const { result } = await adapter.parse(yamlSource, { sourceMap: true }); + // @ts-ignore + const subMappingValue = result.get('mapping').get('sub-mapping'); + + assert.instanceOf(subMappingValue.meta.get('sourceMap'), SourceMapElement); + }); + }); + + context('detectionRegExp', function () { + specify('should reject invalid schema versions', function () { + assert.isFalse( + adapter.detectionRegExp.test('$schema: http://json-schema.org/draft-04/schema#'), + ); + assert.isFalse( + adapter.detectionRegExp.test('$schema: http://json-schema.org/draft-06/schema#'), + ); + assert.isFalse( + adapter.detectionRegExp.test('openapi: http://json-schema.org/draft-07/schema#'), + ); + assert.isFalse( + adapter.detectionRegExp.test('openapi: https://json-schema.org/draft/07/schema'), + ); + assert.isFalse( + adapter.detectionRegExp.test('$schema: https://json-schema.org/draft/2019-09/schema'), + ); + }); + }); +}); diff --git a/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/fixtures/json-schema-2020-12.json b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/fixtures/json-schema-2020-12.json new file mode 100644 index 0000000000..a9e376f18c --- /dev/null +++ b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/fixtures/json-schema-2020-12.json @@ -0,0 +1,103 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://example.com/json-schema-2020-12", + "title": "JSON Schema 2020-12 Example", + "description": "Example JSON Schema 2020-12 document", + "version": "1.0.0", + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64", + "examples": [10] + }, + "name": { + "type": "string", + "examples": ["doggie"] + }, + "category": { + "$ref": "#/$defs/Category" + }, + "photoUrls": { + "type": "array", + "xml": { + "wrapped": true + }, + "items": { + "type": "string", + "xml": { + "name": "photoUrl" + } + } + }, + "tags": { + "type": "array", + "xml": { + "wrapped": true + }, + "items": { + "$ref": "#/$defs/Tag" + } + }, + "status": { + "type": "string", + "description": "pet status in the store", + "enum": ["available", "pending", "sold"] + } + }, + "required": ["name", "photoUrls"], + "xml": { + "name": "pet" + }, + "if": { + "properties": { + "status": { + "const": "available" + } + } + }, + "then": { + "properties": { + "photoUrls": { + "minItems": 1 + } + } + }, + "dependentRequired": { + "category": ["tags"] + }, + "$defs": { + "Category": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64", + "examples": [1] + }, + "name": { + "type": "string", + "examples": ["Dogs"] + } + }, + "xml": { + "name": "category" + } + }, + "Tag": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + } + }, + "xml": { + "name": "tag" + } + } + } +} diff --git a/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/fixtures/json-schema-2020-12.yaml b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/fixtures/json-schema-2020-12.yaml new file mode 100644 index 0000000000..f8a514597b --- /dev/null +++ b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/fixtures/json-schema-2020-12.yaml @@ -0,0 +1,75 @@ +$schema: https://json-schema.org/draft/2020-12/schema +$id: https://example.com/json-schema-2020-12 +title: JSON Schema 2020-12 Example +description: Example JSON Schema 2020-12 document +version: 1.0.0 +type: object +properties: + id: + type: integer + format: int64 + examples: [10] + name: + type: string + examples: [doggie] + category: + $ref: '#/$defs/Category' + photoUrls: + type: array + xml: + wrapped: true + items: + type: string + xml: + name: photoUrl + tags: + type: array + xml: + wrapped: true + items: + $ref: '#/$defs/Tag' + status: + type: string + description: pet status in the store + enum: + - available + - pending + - sold +required: + - name + - photoUrls +xml: + name: pet +if: + properties: + status: + const: available +then: + properties: + photoUrls: + minItems: 1 +dependentRequired: + category: [tags] +$defs: + Category: + type: object + properties: + id: + type: integer + format: int64 + examples: [1] + name: + type: string + examples: [Dogs] + xml: + name: category + Tag: + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + xml: + name: tag diff --git a/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/media-types.ts b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/media-types.ts new file mode 100644 index 0000000000..d036db9db6 --- /dev/null +++ b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/media-types.ts @@ -0,0 +1,18 @@ +import { assert } from 'chai'; +import ApiDOMParser from '@swagger-api/apidom-parser'; + +import * as jsonSchemaYamlAdapter from '../src/adapter.ts'; + +describe('given adapter is used in parser', function () { + const parser = new ApiDOMParser().use(jsonSchemaYamlAdapter); + + context('given JSON Schema 2020-12 definition in YAML format', function () { + specify('should find appropriate media type', async function () { + const mediaType = await parser.findMediaType( + '$schema: https://json-schema.org/draft/2020-12/schema', + ); + + assert.strictEqual(mediaType, 'application/schema+yaml;version=2020-12'); + }); + }); +}); diff --git a/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/mocha-bootstrap.ts b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/mocha-bootstrap.ts new file mode 100644 index 0000000000..aec560d03f --- /dev/null +++ b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/mocha-bootstrap.ts @@ -0,0 +1,11 @@ +import * as chai from 'chai'; +import { jestSnapshotPlugin, addSerializer } from 'mocha-chai-jest-snapshot'; + +// @ts-ignore +import * as jestApiDOMSerializer from '../../../scripts/jest-serializer-apidom.mjs'; +// @ts-ignore +import * as jestStringSerializer from '../../../scripts/jest-serializer-string.mjs'; + +chai.use(jestSnapshotPlugin()); +addSerializer(jestApiDOMSerializer); +addSerializer(jestStringSerializer); diff --git a/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/tsconfig.json b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/tsconfig.json new file mode 100644 index 0000000000..405aae2d2f --- /dev/null +++ b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "module": "esnext", + "moduleResolution": "node" + }, + "include": [ + "." + ] +} diff --git a/packages/apidom-parser-adapter-json-schema-yaml-2020-12/tsconfig.declaration.json b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/tsconfig.declaration.json new file mode 100644 index 0000000000..82d128fa80 --- /dev/null +++ b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/tsconfig.declaration.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "declaration": true, + "declarationDir": "types", + "noEmit": false, + "emitDeclarationOnly": true + } +} diff --git a/packages/apidom-parser-adapter-json-schema-yaml-2020-12/tsconfig.json b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/tsconfig.json new file mode 100644 index 0000000000..5cc50cd885 --- /dev/null +++ b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "../../tsconfig.json", + "include": [ + "src/**/*" + ] +} From 1074ac09e5040a78cd2d9d5ad6673334d3fa3b2d Mon Sep 17 00:00:00 2001 From: Oliwia Rogala Date: Thu, 23 Jan 2025 09:33:55 +0100 Subject: [PATCH 2/5] refactor: remove unnecessary comment --- .../test/adapter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/adapter.ts b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/adapter.ts index 400f8d6fe1..5058e8ccc9 100644 --- a/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/adapter.ts +++ b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/adapter.ts @@ -39,7 +39,7 @@ describe('adapter', function () { const parseResult = await adapter.parse(yamlSpec, { sourceMap: true }); assert.isTrue(isParseResultElement(parseResult)); - assert.isTrue(isJSONSchemaElement(parseResult.content[0])); // ---- CHECK THIS LINE ---- + assert.isTrue(isJSONSchemaElement(parseResult.content[0])); expect(sexprs(parseResult)).toMatchSnapshot(); }); From 6e5e85af63f6fdbf4124c7b3911bc22b508203ba Mon Sep 17 00:00:00 2001 From: Oliwia Rogala Date: Thu, 23 Jan 2025 10:33:19 +0100 Subject: [PATCH 3/5] fix: update package-lock and docs --- README.md | 1 + package-lock.json | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/README.md b/README.md index 9f45a37a32..91b47d0b64 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ You can install ApiDOM packages using [npm CLI](https://docs.npmjs.com/cli): $ npm install @swagger-api/apidom-parser-adapter-asyncapi-json-2 $ npm install @swagger-api/apidom-parser-adapter-asyncapi-yaml-2 $ npm install @swagger-api/apidom-parser-adapter-json + $ npm install @swagger-api/apidom-parser-adapter-json-schema-yaml-2020-12 $ npm install @swagger-api/apidom-parser-adapter-openapi-json-2 $ npm install @swagger-api/apidom-parser-adapter-openapi-json-3-0 $ npm install @swagger-api/apidom-parser-adapter-openapi-json-3-1 diff --git a/package-lock.json b/package-lock.json index 2a7e9b4d97..31514435c1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6811,6 +6811,10 @@ "resolved": "packages/apidom-parser-adapter-json", "link": true }, + "node_modules/@swagger-api/apidom-parser-adapter-json-schema-yaml-2020-12": { + "resolved": "packages/apidom-parser-adapter-json-schema-yaml-2020-12", + "link": true + }, "node_modules/@swagger-api/apidom-parser-adapter-openapi-json-2": { "resolved": "packages/apidom-parser-adapter-openapi-json-2", "link": true @@ -25720,6 +25724,19 @@ "tree-sitter-cli": "=0.24.5" } }, + "packages/apidom-parser-adapter-json-schema-yaml-2020-12": { + "version": "1.0.0-beta.7", + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime-corejs3": "^7.20.7", + "@swagger-api/apidom-core": "^1.0.0-beta.7", + "@swagger-api/apidom-ns-json-schema-2020-12": "^1.0.0-beta.7", + "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.0.0-beta.7", + "@types/ramda": "~0.30.0", + "ramda": "~0.30.0", + "ramda-adjunct": "^5.0.0" + } + }, "packages/apidom-parser-adapter-openapi-json-2": { "name": "@swagger-api/apidom-parser-adapter-openapi-json-2", "version": "1.0.0-beta.8", From 4c4feb56f80579a1a22a5a82b8539335e6b17570 Mon Sep 17 00:00:00 2001 From: Oliwia Rogala Date: Thu, 23 Jan 2025 15:21:14 +0100 Subject: [PATCH 4/5] test: use parseResult.result --- .../test/adapter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/adapter.ts b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/adapter.ts index 5058e8ccc9..1c880a4fef 100644 --- a/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/adapter.ts +++ b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/test/adapter.ts @@ -39,7 +39,7 @@ describe('adapter', function () { const parseResult = await adapter.parse(yamlSpec, { sourceMap: true }); assert.isTrue(isParseResultElement(parseResult)); - assert.isTrue(isJSONSchemaElement(parseResult.content[0])); + assert.isTrue(isJSONSchemaElement(parseResult.result)); expect(sexprs(parseResult)).toMatchSnapshot(); }); From 54f94e2aa858759cf51ac1c8a73e33ff867df810 Mon Sep 17 00:00:00 2001 From: Vladimir Gorej Date: Sat, 25 Jan 2025 21:46:41 +0100 Subject: [PATCH 5/5] fix: deps --- package-lock.json | 6 +++--- .../package.json | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8de8aabaf8..3f4e7c4187 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25750,9 +25750,9 @@ "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^1.0.0-beta.7", - "@swagger-api/apidom-ns-json-schema-2020-12": "^1.0.0-beta.7", - "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.0.0-beta.7", + "@swagger-api/apidom-core": "^1.0.0-beta.9", + "@swagger-api/apidom-ns-json-schema-2020-12": "^1.0.0-beta.9", + "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.0.0-beta.9", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0" diff --git a/packages/apidom-parser-adapter-json-schema-yaml-2020-12/package.json b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/package.json index 632a976770..c6e70d3310 100644 --- a/packages/apidom-parser-adapter-json-schema-yaml-2020-12/package.json +++ b/packages/apidom-parser-adapter-json-schema-yaml-2020-12/package.json @@ -43,9 +43,9 @@ "license": "Apache-2.0", "dependencies": { "@babel/runtime-corejs3": "^7.20.7", - "@swagger-api/apidom-core": "^1.0.0-beta.7", - "@swagger-api/apidom-ns-json-schema-2020-12": "^1.0.0-beta.7", - "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.0.0-beta.7", + "@swagger-api/apidom-core": "^1.0.0-beta.9", + "@swagger-api/apidom-ns-json-schema-2020-12": "^1.0.0-beta.9", + "@swagger-api/apidom-parser-adapter-yaml-1-2": "^1.0.0-beta.9", "@types/ramda": "~0.30.0", "ramda": "~0.30.0", "ramda-adjunct": "^5.0.0"