diff --git a/.gitignore b/.gitignore index 9c908952d..70f71a941 100644 --- a/.gitignore +++ b/.gitignore @@ -8,42 +8,4 @@ node_modules /cjs /browser *.tgz -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# Dependencies -node_modules -.pnp -.pnp.js - -# Local env files -.env -.env.local -.env.development.local -.env.test.local -.env.production.local - -# Testing -coverage - -# Turbo -.turbo - -# Vercel -.vercel - -# Build Outputs -.next/ -out/ -build -dist - - -# Debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# Misc -.DS_Store -*.pem .turbo diff --git a/apps/parser/CODEOWNERS b/CODEOWNERS similarity index 100% rename from apps/parser/CODEOWNERS rename to CODEOWNERS diff --git a/apps/parser/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md similarity index 100% rename from apps/parser/CODE_OF_CONDUCT.md rename to CODE_OF_CONDUCT.md diff --git a/apps/parser/CONTRIBUTING.md b/CONTRIBUTING.md similarity index 100% rename from apps/parser/CONTRIBUTING.md rename to CONTRIBUTING.md diff --git a/README.md b/README.md index 7a4658aa8..b51837688 100644 --- a/README.md +++ b/README.md @@ -1,81 +1,539 @@ -# Turborepo starter +[![AsyncAPI JavaScript Parser](./assets/logo.png)](https://www.asyncapi.com) -This is an official starter Turborepo. +Use this package to validate and parse AsyncAPI documents —either YAML or JSON— in your Node.js or browser application. +Validation is powered by [Spectral](https://github.com/stoplightio/spectral). +Updated bundle for the browser is always attached to the GitHub Release. -## Using this example +![npm](https://img.shields.io/npm/v/@asyncapi/parser?style=for-the-badge) ![npm](https://img.shields.io/npm/dt/@asyncapi/parser?style=for-the-badge) -Run the following command: +> **Warning** +> This package doesn't support AsyncAPI 1.x anymore. We recommend to upgrade to the latest AsyncAPI version using the [AsyncAPI converter](https://github.com/asyncapi/converter-js). If you need to convert documents on the fly, you may use the [Node.js](https://github.com/asyncapi/converter-js) or [Go](https://github.com/asyncapi/converter-go) converters. -```sh -npx create-turbo@latest +> **Warning** +> This package has rewrote the Model API (old one) to [Intent API](https://github.com/asyncapi/parser-api). If you still need to use the old API, read the [Convert to the old API](#convert-to-the-old-api) section. + +> **Note** +> Read the [migration guide from v2 to v3](./docs/migrations/v2-to-v3.md). + + + + + +- [Installation](#installation) +- [Usage](#usage) +- [Examples](#examples) + - [Example with parsing](#example-with-parsing) + - [Example with validation](#example-with-validation) + - [Example using Avro schemas](#example-using-avro-schemas) + - [Example using OpenAPI schemas](#example-using-openapi-schemas) + - [Example using RAML data types](#example-using-raml-data-types) + - [Example with performing actions on HTTP source](#example-with-performing-actions-on-http-source) + - [Example with performing actions on file source](#example-with-performing-actions-on-file-source) + - [Example with stringify and unstringify parsed document](#example-with-stringify-and-unstringify-parsed-document) +- [API documentation](#api-documentation) +- [Spectral rulesets](#spectral-rulesets) +- [Using in the browser/SPA applications](#using-in-the-browserspa-applications) +- [Custom schema parsers](#custom-schema-parsers) + - [Official supported custom schema parsers](#official-supported-custom-schema-parsers) +- [Custom extensions](#custom-extensions) +- [Circular references](#circular-references) +- [Stringify](#stringify) +- [Convert to the old API](#convert-to-the-old-api) +- [Notes](#notes) + - [Using with Webpack](#using-with-webpack) + - [Testing with [Jest](https://jestjs.io/)](#testing-with-jesthttpsjestjsio) +- [Develop](#develop) +- [Contributing](#contributing) +- [Contributors](#contributors) + + + +## Installation + +```bash +npm install @asyncapi/parser +yarn add @asyncapi/parser +``` + +The parser by default supports AsyncAPI Schema Format and JSON Schema Format for schemas. For additional formats, check [Custom schema parsers](#custom-schema-parsers) section. + +## Usage + +The package exposes the main class `Parser`, which has two main functions: + +- `validate()` - function that validates the passed AsyncAPI document. Returns array of all possible errors against the validation conditions. +- `parse()` - function that validates the passed AsyncAPI document, and then if it's valid, parses the input. It returns an object that contains: + - `document` object, which is an parsed AsyncAPI document with [`AsyncAPIDocumentInterface`](./src/models/asyncapi.ts) API. If the schema is invalid against the validation conditions, the field has `undefined` value. + - `diagnostics` array that contains all possible errors against the validation conditions. +- `registerSchemaParser()` - function that registers custom schema parsers. For more info, please check [Custom schema parsers](#custom-schema-parsers) section. + +Natively `Parser` class does not contain methods that operate on the source (AsyncAPI document) from a file or URL. However, the package exposes utils that make this possible: + +```ts +import { fromURL, fromFile } from "@asyncapi/parser"; +``` + +Check out the [examples](#examples) of using the above mentioned functionalities. + +## Examples + +### Example with parsing + +```ts +import { Parser } from "@asyncapi/parser"; +const parser = new Parser(); +const { document } = await parser.parse(` + asyncapi: '2.4.0' + info: + title: Example AsyncAPI specification + version: '0.1.0' + channels: + example-channel: + subscribe: + message: + payload: + type: object + properties: + exampleField: + type: string + exampleNumber: + type: number + exampleDate: + type: string + format: date-time +`); + +if (document) { + // => Example AsyncAPI specification + console.log(document.info().title()); +} +``` + +### Example with validation + +```ts +import { Parser } from "@asyncapi/parser"; + +const parser = new Parser(); + +// One of the diagnostics will contain an error regarding an unsupported version of AsyncAPI (2.1.37) +const diagnostics = await parser.validate(` + asyncapi: '2.1.37' + info: + title: Example AsyncAPI specification + version: '0.1.0' + channels: + example-channel: + subscribe: + message: + payload: + type: object + properties: + exampleField: + type: string + exampleNumber: + type: number + exampleDate: + type: string + format: date-time +`); +``` + +### [Example using Avro schemas](#custom-schema-parsers) + +Head over to [asyncapi/avro-schema-parser](https://www.github.com/asyncapi/avro-schema-parser) for more information. + +### [Example using OpenAPI schemas](#custom-schema-parsers) + +Head over to [asyncapi/openapi-schema-parser](https://www.github.com/asyncapi/openapi-schema-parser) for more information. + +### [Example using RAML data types](#custom-schema-parsers) + +Head over to [asyncapi/raml-dt-schema-parser](https://www.github.com/asyncapi/raml-dt-schema-parser) for more information. + +### Example with performing actions on HTTP source + +```ts +import { Parser, fromURL } from "@asyncapi/parser"; + +const parser = new Parser(); + +const { document, diagnostics } = await fromURL( + parser, + "https://example.com/", +).parse(); +``` + +### Example with performing actions on file source + +```ts +import { Parser, fromFile } from "@asyncapi/parser"; + +const parser = new Parser(); + +const { document, diagnostics } = await fromFile( + parser, + "./asyncapi.yaml", +).parse(); +``` + +### [Example with stringify and unstringify parsed document](#stringify) + +```ts +import { Parser, stringify, unstringify } from "@asyncapi/parser"; + +const parser = new Parser(); + +const { document } = await parser.parse(` + asyncapi: '2.4.0' + info: + title: Example AsyncAPI specification + version: '0.1.0' + channels: + example-channel: + subscribe: + message: + payload: + type: object + properties: + exampleField: + type: string + exampleNumber: + type: number + exampleDate: + type: string + format: date-time +`); + +if (document) { + // stringify function returns string type + const stringifiedDocument = stringify(document); + // unstringify function returns new AsyncAPIDocument instance + const unstringifiedDocument = unstringify(stringifiedDocument); +} ``` -## What's inside? +## API documentation + +Parser-JS API implements a global API definition for all AsyncAPI parser implementations known as the [Parser-API](https://github.com/asyncapi/parser-api). This API is designed having in mind developer experience and resiliency to breaking changes. + +The following table shows a compatibility matrix between this parser, and the [Parser-API](https://github.com/asyncapi/parser-api), as well as the AsyncAPI spec version supported by each release of this parser. -This Turborepo includes the following packages/apps: +| Parser-JS | Parser-API | Spec 2.x | Spec 3.x | +| --------- | --------------------------------------------------------------------- | -------- | -------- | +| 2.x | [1.x](https://github.com/asyncapi/parser-api/blob/v1.0.0/docs/v1.md) | ✓ | | +| 3.x | [3.x](https://github.com/asyncapi/parser-api/blob/v3.0.0/docs/api.md) | ✓ | ✓ | -### Apps and Packages +- `✓` Fully supported version. +- `-` The AsyncAPI Spec version has features the Parser-JS can't use but the rest are fully supported. +- Empty means not supported version. -- `docs`: a [Next.js](https://nextjs.org/) app -- `web`: another [Next.js](https://nextjs.org/) app -- `@repo/ui`: a stub React component library shared by both `web` and `docs` applications -- `@repo/eslint-config`: `eslint` configurations (includes `eslint-config-next` and `eslint-config-prettier`) -- `@repo/typescript-config`: `tsconfig.json`s used throughout the monorepo +Additionally to all the methods declared in the [Parser-API](https://github.com/asyncapi/parser-api), this parser might introduce some helper functions like: -Each package/app is 100% [TypeScript](https://www.typescriptlang.org/). +- `json()` which returns the JSON object of the given object. It is possible to pass as an argument the name of a field in an object and retrieve corresponding value. +- `jsonPath()` which returns the JSON Path of the given object. +- `meta()` which returns the metadata of a given object, like a parsed AsyncAPI Document. -### Utilities +## Spectral rulesets -This Turborepo has some additional tools already setup for you: +[Spectral](https://github.com/stoplightio/spectral) powers the validation of AsyncAPI documents within ParserJS. For this reason, it is possible to use your rulesets/rules or overwrite existing ones, passing the `ruleset` option to the Parser instance: -- [TypeScript](https://www.typescriptlang.org/) for static type checking -- [ESLint](https://eslint.org/) for code linting -- [Prettier](https://prettier.io) for code formatting +```ts +import { Parser, stringify, unstringify } from "@asyncapi/parser"; +const parser = new Parser({ + ruleset: { + extends: [], + rules: { + "asyncapi-defaultContentType": "off", + "asyncapi-termsOfService": { + description: + 'Info "termsOfService" should be present and non-empty string.', + recommended: true, + given: "$", + then: { + field: "info.termsOfService", + function: "truthy", + }, + }, + }, + }, +}); +// The returned diagnostics object will include `asyncapi-termsOfService` diagnostic with `warning` (`recommended: true`) severity because `$.info.termsOfService` is not defined in the following AsyncAPI document. +// On the other hand, since we turned it off, we won't see the diagnostics related to the `defaultContentType` field. +const diagnostics = await parser.validate(` + asyncapi: '2.0.0' + info: + title: Example AsyncAPI specification + version: '0.1.0' + channels: {} +`); +``` + +[ParserJS has some built-in Spectral rulesets](./docs/ruleset) that validate AsyncAPI documents and inform on good practices. + +## Using in the browser/SPA applications + +The package contains a built-in version of the parser. To use it, you need to import the parser into the HTML file as below: + +```html + + + +``` -### Build +Or, if you want to use the parser in a JS SPA-type application where you have a predefined bundler configuration that is difficult to change (e.g. you use [`create-react-app`](https://github.com/facebook/create-react-app)) then you can import the parser as below: -To build all apps and packages, run the following command: +```js +import Parser from '@asyncapi/parser/browser'; +const parser = new Parser(); +const { document, diagnostics } = parser.parse(...); ``` -cd my-turborepo -pnpm build + +> **Note** +> Using the above code, we import the entire bundled parser into application. This may result in a duplicate code in the final application bundle, only if the application uses the same dependencies what the parser. If, on the other hand, you want to have the smallest bundle as possible, we recommend using the following import and properly configure bundler. + +Otherwise, if your application is bundled via bundlers like `webpack` and you can configure it, you can import the parser like a regular package: + +```js +import { Parser } from '@asyncapi/parser'; + +const parser = new Parser(); +const { document, diagnostics } = parser.parse(...); ``` -### Develop +> **Note** +> The package uses some native NodeJS modules underneath. If you are building a front-end application you can find more information about the correct configuration for Webpack [here](#webpack). + +In case you just want to check out the latest `bundle.js` without installing the package, we publish one on each GitHub release. You can find it under [this link to the latest release](https://github.com/asyncapi/parser-js/releases/latest/download/bundle.js). + +## Custom schema parsers + +AsyncAPI doesn't enforce one schema format. The payload of the messages can be described with OpenAPI (3.0.0), Avro, etc. This parser by default parses only [AsyncAPI Schema Format](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#schemaObject) (superset of JSON Schema Format). We can extend it by creating a custom parser and registering it within the parser: + +1. Create custom parser module that exports three functions: + + - `validate` - function that validates (its syntax) used schema. + - `parse` - function that parses the given schema to the [AsyncAPI Schema Format](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#schemaObject). + - `getMimeTypes` - function that returns the list of mime types that will be used as the `schemaFormat` property to determine the mime type of a given schema. + + Example: + + ```ts + export default { + validate(input) { ... }, + parse(input) { ... }, + getMimeTypes() { + return [ + 'application/vnd.custom.type;version=1.0.0', + 'application/vnd.custom.type+json;version=1.0.0', + ] + } + } + ``` + +2. Before parsing/validating an AsyncAPI document with a parser, register the additional custom schema parser: + + ```ts + import { Parser } from "@asyncapi/parser"; + import myCustomSchemaParser from "./my-custom-schema-parser"; + + const parser = new Parser(); + parser.registerSchemaParser(myCustomSchemaParser); + ``` + +### Official supported custom schema parsers + +In AsyncAPI Initiative we support below custom schema parsers. To install them, run below comamnds: + +- [Avro schema](https://www.github.com/asyncapi/avro-schema-parser): + + ```bash + npm install @asyncapi/avro-schema-parser + yarn add @asyncapi/avro-schema-parser + ``` + +- [OpenAPI (3.0.0) Schema Object](https://www.github.com/asyncapi/openapi-schema-parser): + + ```bash + npm install @asyncapi/openapi-schema-parser + yarn add @asyncapi/openapi-schema-parser + ``` + +- [RAML data type](https://www.github.com/asyncapi/raml-dt-schema-parser): + + ```bash + npm install @asyncapi/raml-dt-schema-parser + yarn add @asyncapi/raml-dt-schema-parser + ``` + + > **Note** + > That custom parser works only in the NodeJS environment. Do not use it in browser applications! + +## Custom extensions + +The parser uses custom extensions to define additional information about the spec. Each has a different purpose but all of them are there to make it much easier to work with the AsyncAPI document. These extensions are prefixed with `x-parser-`. The following extensions are used: + +- `x-parser-spec-parsed` is used to specify if the AsyncAPI document is already parsed by the parser. Property `x-parser-spec-parsed` is added to the root of the document with the `true` value. +- `x-parser-api-version` is used to specify which version of the [Parser-API](https://github.com/asyncapi/parser-api) the parsed AsyncAPI document uses. Property `x-parser-api-version` is added to the root of the document with the `1` value if the parsed document uses [Parser-API](https://github.com/asyncapi/parser-api) in the `v1` version or `0` if document uses old `parser-js` API. +- `x-parser-message-name` is used to specify the name of the message if it is not provided. For messages without names, the parser generates anonymous names. Property `x-parser-message-name` is added to a message object with a value that follows this pattern: ``. This value is returned by `message.id()` (`message.uid()` in the [old API](#convert-to-the-old-api)) when regular `name` property is not present. +- `x-parser-original-payload` holds the original payload of the message. You can use different formats for payloads with the AsyncAPI documents and the parser converts them to. For example, it converts payload described with Avro schema to AsyncAPI schema. The original payload is preserved in the extension. +- [`x-parser-circular`](#circular-references). + +In addition, the [`convertToOldAPI()` function](#convert-to-the-old-api) which converts new API to an old one adds additional extensions: + +- `x-parser-message-parsed` is used to specify if the message is already parsed by the message parser. Property `x-parser-message-parsed` is added to the message object with the `true` value. +- `x-parser-schema-id` is used to specify the ID of the schema if it is not provided. For schemas without IDs, the parser generates anonymous names. Property `x-parser-schema-id` is added to every object of a schema with a value that follows this pattern: ``. This value is returned by `schema.uid()` when regular `$id` property is not present. +- `x-parser-original-traits` is where traits are stored after they are applied on the AsyncAPI document. The reason is because the original `traits` property is removed. +- `x-parser-original-schema-format` holds information about the original schema format of the payload. You can use different schema formats with the AsyncAPI documents and the parser converts them to AsyncAPI schema. This is why different schema format is set, and the original one is preserved in the extension. -To develop all apps and packages, run the following command: +> **Warning** +> All extensions added by the parser (including all properties) should be retrieved using special functions. Names of extensions and their location may change, and their eventual changes will not be announced. +## Circular references + +Parser dereferences all circular references by default. In addition, to simplify interactions with the parser, the following is added: + +- `x-parser-circular` property is added to the root of the AsyncAPI document to indicate that the document contains circular references. In old API the Parser exposes `hasCircular()` function to check if given AsyncAPI document has circular references. +- `isCircular()` function is added to the [Schema Model](./src/models/schema.ts) to determine if a given schema is circular with respect to previously occurring schemas in the JSON tree. + +## Stringify + +Converting a parsed document to a string may be necessary when saving the parsed document to a database, or similar situations where you need to parse the document just once and then reuse it, for optimisation cases. + +For that, the Parser supports the ability to stringify a parsed AsyncAPI document through the `stringify` function exposed by package. This method differs from the native `JSON.stringify(...json)` implementation, in that every reference that occurs (at least twice throughout the document) is converted into a [JSON Pointer](https://datatracker.ietf.org/doc/html/rfc6901) path with a `$ref:` prefix: + +```json +{ + "foo": "$ref:$.some.path.to.the.bar" +} ``` -cd my-turborepo -pnpm dev + +To parse a stringified document into an AsyncAPIDocument instance, you must use the `unstringify` function (also exposed by package). It isn't compatible with the native `JSON.parse()` method. It replaces the given references pointed by the [JSON Pointer](https://datatracker.ietf.org/doc/html/rfc6901) path, with an `$ref:` prefix to the original objects. + +A few advantages of this solution: + +- The string remains as small as possible due to the use of [JSON Pointers](https://datatracker.ietf.org/doc/html/rfc6901). +- All references (also circular) are preserved. + +Check [example](#example-with-stringify-and-unstringify-parsed-documentstringify). + +## Convert to the old API + +Version `2.0.0` of package introduced a lot of breaking changes, including changing the API of the returned parsed document (parser uses [New API](https://github.com/asyncapi/parser-api)). Due to the fact that a large part of the AsyncAPI tooling ecosystem uses a Parser with the old API and rewriting the tool for the new one can be time-consuming and difficult, the package exposes the `convertToOldAPI()` function to convert new API to old one: + +```js +import { Parser, convertToOldAPI } from '@asyncapi/parser'; + +const parser = new Parser(); +const { document } = parser.parse(...); +const oldAsyncAPIDocument = convertToOldAPI(document); ``` -### Remote Caching +> **Warning** +> The old api will be supported only for a certain period of time. The target date for turning off support of the old API is around the end of January 2023. -Turborepo can use a technique known as [Remote Caching](https://turbo.build/repo/docs/core-concepts/remote-caching) to share cache artifacts across machines, enabling you to share build caches with your team and CI/CD pipelines. +## Notes -By default, Turborepo will cache locally. To enable Remote Caching you will need an account with Vercel. If you don't have an account you can [create one](https://vercel.com/signup), then enter the following commands: +### Using with Webpack +Versions `<5` of Webpack should handle bundling without problems. Due to the fact that Webpack 5 no longer does fallbacks to native NodeJS modules by default we need to install `buffer` package and add fallbacks: + +```js +{ + resolve: { + fallback: { + "fs": false, + "path": false, + "util": false, + "buffer": require.resolve("buffer/"), + } + } +} ``` -cd my-turborepo -npx turbo login + +### Testing with [Jest](https://jestjs.io/) + +Using a Parser in an application that is tested using [Jest](https://jestjs.io/), there will probably an error like: + +```bash +Cannot find module 'nimma/legacy' from 'node_modules/@stoplight/spectral-core/dist/runner/runner.js +``` + +It's a problem with Jest, which cannot understand [NodeJS's package exports](https://nodejs.org/api/packages.html). To fix that, should be [enabled ESM support in Jest](https://jestjs.io/docs/ecmascript-modules) or set an appropriate Jest's `moduleNameMapper` config: + +```js +moduleNameMapper: { + '^nimma/legacy$': '/node_modules/nimma/dist/legacy/cjs/index.js', + '^nimma/(.*)': '/node_modules/nimma/dist/cjs/$1', +}, ``` -This will authenticate the Turborepo CLI with your [Vercel account](https://vercel.com/docs/concepts/personal-accounts/overview). +## Develop -Next, you can link your Turborepo to your Remote Cache by running the following command from the root of your Turborepo: +1. Make sure you are using Node.js 16 or higher and npm 8 or higher +2. Write code and tests. +3. Make sure all tests pass `npm test` + +For Windows environments, some tests might still fail randomly during local development even when you made no changes to the tests. The reason for this from file endings are different than expected and this comes from Git defaulting to an unexpected file ending. If you encounter this issue you can run the following commands to set Git to use the expected one: ``` -npx turbo link +git config --global core.autocrlf false +git config --global core.eol lf ``` -## Useful Links +4. Make sure code is well formatted and secure `npm run lint` + +## Contributing + +Read [CONTRIBUTING](https://github.com/asyncapi/.github/blob/master/CONTRIBUTING.md) guide. + +## Contributors + +Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Fran Méndez
Fran Méndez

💬 🐛 💻 📖 🤔 🚧 🔌 👀 ⚠️
Lukasz Gornicki
Lukasz Gornicki

💬 🐛 💻 📖 🤔 🚧 👀 ⚠️
Jonas Lagoni
Jonas Lagoni

💬 🐛 💻 🤔 👀
Maciej Urbańczyk
Maciej Urbańczyk

🐛 💻 👀
Juan Mellado
Juan Mellado

💻
James Crowley
James Crowley

💻
raisel melian
raisel melian

💻
danielchu
danielchu

🚇 💻
Jürgen B.
Jürgen B.

💻
Viacheslav Turovskyi
Viacheslav Turovskyi

⚠️ 💻
Khuda Dad Nomani
Khuda Dad Nomani

💻 🐛 ⚠️
Aayush Kumar Sahu
Aayush Kumar Sahu

⚠️
Jordan Tucker
Jordan Tucker

⚠️ 💻
vishesh13byte
vishesh13byte

⚠️
Elakya
Elakya

💻
Dominik Schwank
Dominik Schwank

🐛 💻
Ruchi Pakhle
Ruchi Pakhle

📖
Đỗ Trọng Hải
Đỗ Trọng Hải

🛡️
+ + + -Learn more about the power of Turborepo: + -- [Tasks](https://turbo.build/repo/docs/core-concepts/monorepos/running-tasks) -- [Caching](https://turbo.build/repo/docs/core-concepts/caching) -- [Remote Caching](https://turbo.build/repo/docs/core-concepts/remote-caching) -- [Filtering](https://turbo.build/repo/docs/core-concepts/monorepos/filtering) -- [Configuration Options](https://turbo.build/repo/docs/reference/configuration) -- [CLI Usage](https://turbo.build/repo/docs/reference/command-line-reference) +This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! diff --git a/apps/parser/.gitignore b/apps/parser/.gitignore index 9c908952d..70f71a941 100644 --- a/apps/parser/.gitignore +++ b/apps/parser/.gitignore @@ -8,42 +8,4 @@ node_modules /cjs /browser *.tgz -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# Dependencies -node_modules -.pnp -.pnp.js - -# Local env files -.env -.env.local -.env.development.local -.env.test.local -.env.production.local - -# Testing -coverage - -# Turbo -.turbo - -# Vercel -.vercel - -# Build Outputs -.next/ -out/ -build -dist - - -# Debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# Misc -.DS_Store -*.pem .turbo diff --git a/apps/parser/LICENSE b/apps/parser/LICENSE index ebfe05f22..829968f80 100644 --- a/apps/parser/LICENSE +++ b/apps/parser/LICENSE @@ -2,180 +2,180 @@ 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 - - APPENDIX: How to apply the Apache License to your work. +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 + +APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" @@ -186,16 +186,16 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright The Linux Foundation +Copyright The Linux Foundation - 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 +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. +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/apps/parser/README.md b/apps/parser/README.md deleted file mode 100644 index 1e322c366..000000000 --- a/apps/parser/README.md +++ /dev/null @@ -1,533 +0,0 @@ -[![AsyncAPI JavaScript Parser](./assets/logo.png)](https://www.asyncapi.com) - -Use this package to validate and parse AsyncAPI documents —either YAML or JSON— in your Node.js or browser application. -Validation is powered by [Spectral](https://github.com/stoplightio/spectral). -Updated bundle for the browser is always attached to the GitHub Release. - -![npm](https://img.shields.io/npm/v/@asyncapi/parser?style=for-the-badge) ![npm](https://img.shields.io/npm/dt/@asyncapi/parser?style=for-the-badge) - -> **Warning** -> This package doesn't support AsyncAPI 1.x anymore. We recommend to upgrade to the latest AsyncAPI version using the [AsyncAPI converter](https://github.com/asyncapi/converter-js). If you need to convert documents on the fly, you may use the [Node.js](https://github.com/asyncapi/converter-js) or [Go](https://github.com/asyncapi/converter-go) converters. - -> **Warning** -> This package has rewrote the Model API (old one) to [Intent API](https://github.com/asyncapi/parser-api). If you still need to use the old API, read the [Convert to the old API](#convert-to-the-old-api) section. - -> **Note** -> Read the [migration guide from v2 to v3](./docs/migrations/v2-to-v3.md). - - - - - - -- [Installation](#installation) -- [Usage](#usage) -- [Examples](#examples) - * [Example with parsing](#example-with-parsing) - * [Example with validation](#example-with-validation) - * [Example using Avro schemas](#example-using-avro-schemas) - * [Example using OpenAPI schemas](#example-using-openapi-schemas) - * [Example using RAML data types](#example-using-raml-data-types) - * [Example with performing actions on HTTP source](#example-with-performing-actions-on-http-source) - * [Example with performing actions on file source](#example-with-performing-actions-on-file-source) - * [Example with stringify and unstringify parsed document](#example-with-stringify-and-unstringify-parsed-document) -- [API documentation](#api-documentation) -- [Spectral rulesets](#spectral-rulesets) -- [Using in the browser/SPA applications](#using-in-the-browserspa-applications) -- [Custom schema parsers](#custom-schema-parsers) - * [Official supported custom schema parsers](#official-supported-custom-schema-parsers) -- [Custom extensions](#custom-extensions) -- [Circular references](#circular-references) -- [Stringify](#stringify) -- [Convert to the old API](#convert-to-the-old-api) -- [Notes](#notes) - * [Using with Webpack](#using-with-webpack) - * [Testing with [Jest](https://jestjs.io/)](#testing-with-jesthttpsjestjsio) -- [Develop](#develop) -- [Contributing](#contributing) -- [Contributors](#contributors) - - - -## Installation - -```bash -npm install @asyncapi/parser -yarn add @asyncapi/parser -``` - -The parser by default supports AsyncAPI Schema Format and JSON Schema Format for schemas. For additional formats, check [Custom schema parsers](#custom-schema-parsers) section. - -## Usage - -The package exposes the main class `Parser`, which has two main functions: - -- `validate()` - function that validates the passed AsyncAPI document. Returns array of all possible errors against the validation conditions. -- `parse()` - function that validates the passed AsyncAPI document, and then if it's valid, parses the input. It returns an object that contains: - - `document` object, which is an parsed AsyncAPI document with [`AsyncAPIDocumentInterface`](./src/models/asyncapi.ts) API. If the schema is invalid against the validation conditions, the field has `undefined` value. - - `diagnostics` array that contains all possible errors against the validation conditions. -- `registerSchemaParser()` - function that registers custom schema parsers. For more info, please check [Custom schema parsers](#custom-schema-parsers) section. - -Natively `Parser` class does not contain methods that operate on the source (AsyncAPI document) from a file or URL. However, the package exposes utils that make this possible: - -```ts -import { fromURL, fromFile } from '@asyncapi/parser'; -``` - -Check out the [examples](#examples) of using the above mentioned functionalities. - -## Examples - -### Example with parsing - -```ts -import { Parser } from '@asyncapi/parser'; -const parser = new Parser(); -const { document } = await parser.parse(` - asyncapi: '2.4.0' - info: - title: Example AsyncAPI specification - version: '0.1.0' - channels: - example-channel: - subscribe: - message: - payload: - type: object - properties: - exampleField: - type: string - exampleNumber: - type: number - exampleDate: - type: string - format: date-time -`); - -if (document) { - // => Example AsyncAPI specification - console.log(document.info().title()); -} -``` - -### Example with validation - -```ts -import { Parser } from '@asyncapi/parser'; - -const parser = new Parser(); - -// One of the diagnostics will contain an error regarding an unsupported version of AsyncAPI (2.1.37) -const diagnostics = await parser.validate(` - asyncapi: '2.1.37' - info: - title: Example AsyncAPI specification - version: '0.1.0' - channels: - example-channel: - subscribe: - message: - payload: - type: object - properties: - exampleField: - type: string - exampleNumber: - type: number - exampleDate: - type: string - format: date-time -`); -``` - -### [Example using Avro schemas](#custom-schema-parsers) - -Head over to [asyncapi/avro-schema-parser](https://www.github.com/asyncapi/avro-schema-parser) for more information. - -### [Example using OpenAPI schemas](#custom-schema-parsers) - -Head over to [asyncapi/openapi-schema-parser](https://www.github.com/asyncapi/openapi-schema-parser) for more information. - -### [Example using RAML data types](#custom-schema-parsers) - -Head over to [asyncapi/raml-dt-schema-parser](https://www.github.com/asyncapi/raml-dt-schema-parser) for more information. - -### Example with performing actions on HTTP source - -```ts -import { Parser, fromURL } from '@asyncapi/parser'; - -const parser = new Parser(); - -const { document, diagnostics } = await fromURL(parser, 'https://example.com/').parse(); -``` - -### Example with performing actions on file source - -```ts -import { Parser, fromFile } from '@asyncapi/parser'; - -const parser = new Parser(); - -const { document, diagnostics } = await fromFile(parser, './asyncapi.yaml').parse(); -``` - -### [Example with stringify and unstringify parsed document](#stringify) - -```ts -import { Parser, stringify, unstringify } from '@asyncapi/parser'; - -const parser = new Parser(); - -const { document } = await parser.parse(` - asyncapi: '2.4.0' - info: - title: Example AsyncAPI specification - version: '0.1.0' - channels: - example-channel: - subscribe: - message: - payload: - type: object - properties: - exampleField: - type: string - exampleNumber: - type: number - exampleDate: - type: string - format: date-time -`); - -if (document) { - // stringify function returns string type - const stringifiedDocument = stringify(document); - // unstringify function returns new AsyncAPIDocument instance - const unstringifiedDocument = unstringify(stringifiedDocument); -} -``` - -## API documentation - -Parser-JS API implements a global API definition for all AsyncAPI parser implementations known as the [Parser-API](https://github.com/asyncapi/parser-api). This API is designed having in mind developer experience and resiliency to breaking changes. - -The following table shows a compatibility matrix between this parser, and the [Parser-API](https://github.com/asyncapi/parser-api), as well as the AsyncAPI spec version supported by each release of this parser. - -| Parser-JS | Parser-API | Spec 2.x | Spec 3.x | -|-----------|-----------------------------------------------------------------------|----------|----------| -| 2.x | [1.x](https://github.com/asyncapi/parser-api/blob/v1.0.0/docs/v1.md) | ✓ | | -| 3.x | [3.x](https://github.com/asyncapi/parser-api/blob/v3.0.0/docs/api.md) | ✓ | ✓ | - -- `✓` Fully supported version. -- `-` The AsyncAPI Spec version has features the Parser-JS can't use but the rest are fully supported. -- Empty means not supported version. - -Additionally to all the methods declared in the [Parser-API](https://github.com/asyncapi/parser-api), this parser might introduce some helper functions like: - -- `json()` which returns the JSON object of the given object. It is possible to pass as an argument the name of a field in an object and retrieve corresponding value. -- `jsonPath()` which returns the JSON Path of the given object. -- `meta()` which returns the metadata of a given object, like a parsed AsyncAPI Document. - -## Spectral rulesets - -[Spectral](https://github.com/stoplightio/spectral) powers the validation of AsyncAPI documents within ParserJS. For this reason, it is possible to use your rulesets/rules or overwrite existing ones, passing the `ruleset` option to the Parser instance: - -```ts -import { Parser, stringify, unstringify } from '@asyncapi/parser'; -const parser = new Parser({ - ruleset: { - extends: [], - rules: { - 'asyncapi-defaultContentType': 'off', - 'asyncapi-termsOfService': { - description: 'Info "termsOfService" should be present and non-empty string.', - recommended: true, - given: '$', - then: { - field: 'info.termsOfService', - function: 'truthy', - }, - }, - } - } -}); -// The returned diagnostics object will include `asyncapi-termsOfService` diagnostic with `warning` (`recommended: true`) severity because `$.info.termsOfService` is not defined in the following AsyncAPI document. -// On the other hand, since we turned it off, we won't see the diagnostics related to the `defaultContentType` field. -const diagnostics = await parser.validate(` - asyncapi: '2.0.0' - info: - title: Example AsyncAPI specification - version: '0.1.0' - channels: {} -`); -``` - -[ParserJS has some built-in Spectral rulesets](./docs/ruleset) that validate AsyncAPI documents and inform on good practices. - - -## Using in the browser/SPA applications - -The package contains a built-in version of the parser. To use it, you need to import the parser into the HTML file as below: - -```html - - - -``` - -Or, if you want to use the parser in a JS SPA-type application where you have a predefined bundler configuration that is difficult to change (e.g. you use [`create-react-app`](https://github.com/facebook/create-react-app)) then you can import the parser as below: - -```js -import Parser from '@asyncapi/parser/browser'; - -const parser = new Parser(); -const { document, diagnostics } = parser.parse(...); -``` - -> **Note** -> Using the above code, we import the entire bundled parser into application. This may result in a duplicate code in the final application bundle, only if the application uses the same dependencies what the parser. If, on the other hand, you want to have the smallest bundle as possible, we recommend using the following import and properly configure bundler. - -Otherwise, if your application is bundled via bundlers like `webpack` and you can configure it, you can import the parser like a regular package: - -```js -import { Parser } from '@asyncapi/parser'; - -const parser = new Parser(); -const { document, diagnostics } = parser.parse(...); -``` - -> **Note** -> The package uses some native NodeJS modules underneath. If you are building a front-end application you can find more information about the correct configuration for Webpack [here](#webpack). - -In case you just want to check out the latest `bundle.js` without installing the package, we publish one on each GitHub release. You can find it under [this link to the latest release](https://github.com/asyncapi/parser-js/releases/latest/download/bundle.js). - -## Custom schema parsers - -AsyncAPI doesn't enforce one schema format. The payload of the messages can be described with OpenAPI (3.0.0), Avro, etc. This parser by default parses only [AsyncAPI Schema Format](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#schemaObject) (superset of JSON Schema Format). We can extend it by creating a custom parser and registering it within the parser: - -1. Create custom parser module that exports three functions: - - - `validate` - function that validates (its syntax) used schema. - - `parse` - function that parses the given schema to the [AsyncAPI Schema Format](https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md#schemaObject). - - `getMimeTypes` - function that returns the list of mime types that will be used as the `schemaFormat` property to determine the mime type of a given schema. - - Example: - - ```ts - export default { - validate(input) { ... }, - parse(input) { ... }, - getMimeTypes() { - return [ - 'application/vnd.custom.type;version=1.0.0', - 'application/vnd.custom.type+json;version=1.0.0', - ] - } - } - ``` - -2. Before parsing/validating an AsyncAPI document with a parser, register the additional custom schema parser: - - ```ts - import { Parser } from '@asyncapi/parser'; - import myCustomSchemaParser from './my-custom-schema-parser'; - - const parser = new Parser(); - parser.registerSchemaParser(myCustomSchemaParser); - ``` - -### Official supported custom schema parsers - -In AsyncAPI Initiative we support below custom schema parsers. To install them, run below comamnds: - -- [Avro schema](https://www.github.com/asyncapi/avro-schema-parser): - - ```bash - npm install @asyncapi/avro-schema-parser - yarn add @asyncapi/avro-schema-parser - ``` - -- [OpenAPI (3.0.0) Schema Object](https://www.github.com/asyncapi/openapi-schema-parser): - - ```bash - npm install @asyncapi/openapi-schema-parser - yarn add @asyncapi/openapi-schema-parser - ``` - -- [RAML data type](https://www.github.com/asyncapi/raml-dt-schema-parser): - - ```bash - npm install @asyncapi/raml-dt-schema-parser - yarn add @asyncapi/raml-dt-schema-parser - ``` - - > **Note** - > That custom parser works only in the NodeJS environment. Do not use it in browser applications! - -## Custom extensions - -The parser uses custom extensions to define additional information about the spec. Each has a different purpose but all of them are there to make it much easier to work with the AsyncAPI document. These extensions are prefixed with `x-parser-`. The following extensions are used: - -- `x-parser-spec-parsed` is used to specify if the AsyncAPI document is already parsed by the parser. Property `x-parser-spec-parsed` is added to the root of the document with the `true` value. -- `x-parser-api-version` is used to specify which version of the [Parser-API](https://github.com/asyncapi/parser-api) the parsed AsyncAPI document uses. Property `x-parser-api-version` is added to the root of the document with the `1` value if the parsed document uses [Parser-API](https://github.com/asyncapi/parser-api) in the `v1` version or `0` if document uses old `parser-js` API. -- `x-parser-message-name` is used to specify the name of the message if it is not provided. For messages without names, the parser generates anonymous names. Property `x-parser-message-name` is added to a message object with a value that follows this pattern: ``. This value is returned by `message.id()` (`message.uid()` in the [old API](#convert-to-the-old-api)) when regular `name` property is not present. -- `x-parser-original-payload` holds the original payload of the message. You can use different formats for payloads with the AsyncAPI documents and the parser converts them to. For example, it converts payload described with Avro schema to AsyncAPI schema. The original payload is preserved in the extension. -- [`x-parser-circular`](#circular-references). - -In addition, the [`convertToOldAPI()` function](#convert-to-the-old-api) which converts new API to an old one adds additional extensions: - -- `x-parser-message-parsed` is used to specify if the message is already parsed by the message parser. Property `x-parser-message-parsed` is added to the message object with the `true` value. -- `x-parser-schema-id` is used to specify the ID of the schema if it is not provided. For schemas without IDs, the parser generates anonymous names. Property `x-parser-schema-id` is added to every object of a schema with a value that follows this pattern: ``. This value is returned by `schema.uid()` when regular `$id` property is not present. -- `x-parser-original-traits` is where traits are stored after they are applied on the AsyncAPI document. The reason is because the original `traits` property is removed. -- `x-parser-original-schema-format` holds information about the original schema format of the payload. You can use different schema formats with the AsyncAPI documents and the parser converts them to AsyncAPI schema. This is why different schema format is set, and the original one is preserved in the extension. - -> **Warning** -> All extensions added by the parser (including all properties) should be retrieved using special functions. Names of extensions and their location may change, and their eventual changes will not be announced. - -## Circular references - -Parser dereferences all circular references by default. In addition, to simplify interactions with the parser, the following is added: - -- `x-parser-circular` property is added to the root of the AsyncAPI document to indicate that the document contains circular references. In old API the Parser exposes `hasCircular()` function to check if given AsyncAPI document has circular references. -- `isCircular()` function is added to the [Schema Model](./src/models/schema.ts) to determine if a given schema is circular with respect to previously occurring schemas in the JSON tree. - -## Stringify - -Converting a parsed document to a string may be necessary when saving the parsed document to a database, or similar situations where you need to parse the document just once and then reuse it, for optimisation cases. - -For that, the Parser supports the ability to stringify a parsed AsyncAPI document through the `stringify` function exposed by package. This method differs from the native `JSON.stringify(...json)` implementation, in that every reference that occurs (at least twice throughout the document) is converted into a [JSON Pointer](https://datatracker.ietf.org/doc/html/rfc6901) path with a `$ref:` prefix: - -```json -{ - "foo": "$ref:$.some.path.to.the.bar" -} -``` - -To parse a stringified document into an AsyncAPIDocument instance, you must use the `unstringify` function (also exposed by package). It isn't compatible with the native `JSON.parse()` method. It replaces the given references pointed by the [JSON Pointer](https://datatracker.ietf.org/doc/html/rfc6901) path, with an `$ref:` prefix to the original objects. - -A few advantages of this solution: - -- The string remains as small as possible due to the use of [JSON Pointers](https://datatracker.ietf.org/doc/html/rfc6901). -- All references (also circular) are preserved. - -Check [example](#example-with-stringify-and-unstringify-parsed-documentstringify). - -## Convert to the old API - -Version `2.0.0` of package introduced a lot of breaking changes, including changing the API of the returned parsed document (parser uses [New API](https://github.com/asyncapi/parser-api)). Due to the fact that a large part of the AsyncAPI tooling ecosystem uses a Parser with the old API and rewriting the tool for the new one can be time-consuming and difficult, the package exposes the `convertToOldAPI()` function to convert new API to old one: - -```js -import { Parser, convertToOldAPI } from '@asyncapi/parser'; - -const parser = new Parser(); -const { document } = parser.parse(...); -const oldAsyncAPIDocument = convertToOldAPI(document); -``` - -> **Warning** -> The old api will be supported only for a certain period of time. The target date for turning off support of the old API is around the end of January 2023. - -## Notes - -### Using with Webpack -Versions `<5` of Webpack should handle bundling without problems. Due to the fact that Webpack 5 no longer does fallbacks to native NodeJS modules by default we need to install `buffer` package and add fallbacks: - -```js -{ - resolve: { - fallback: { - "fs": false, - "path": false, - "util": false, - "buffer": require.resolve("buffer/"), - } - } -} -``` - -### Testing with [Jest](https://jestjs.io/) - -Using a Parser in an application that is tested using [Jest](https://jestjs.io/), there will probably an error like: - -```bash -Cannot find module 'nimma/legacy' from 'node_modules/@stoplight/spectral-core/dist/runner/runner.js -``` - -It's a problem with Jest, which cannot understand [NodeJS's package exports](https://nodejs.org/api/packages.html). To fix that, should be [enabled ESM support in Jest](https://jestjs.io/docs/ecmascript-modules) or set an appropriate Jest's `moduleNameMapper` config: - -```js -moduleNameMapper: { - '^nimma/legacy$': '/node_modules/nimma/dist/legacy/cjs/index.js', - '^nimma/(.*)': '/node_modules/nimma/dist/cjs/$1', -}, -``` - -## Develop - -1. Make sure you are using Node.js 16 or higher and npm 8 or higher -2. Write code and tests. -3. Make sure all tests pass `npm test` - -For Windows environments, some tests might still fail randomly during local development even when you made no changes to the tests. The reason for this from file endings are different than expected and this comes from Git defaulting to an unexpected file ending. If you encounter this issue you can run the following commands to set Git to use the expected one: -``` -git config --global core.autocrlf false -git config --global core.eol lf -``` - -4. Make sure code is well formatted and secure `npm run lint` - - -## Contributing - -Read [CONTRIBUTING](https://github.com/asyncapi/.github/blob/master/CONTRIBUTING.md) guide. - -## Contributors - -Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Fran Méndez
Fran Méndez

💬 🐛 💻 📖 🤔 🚧 🔌 👀 ⚠️
Lukasz Gornicki
Lukasz Gornicki

💬 🐛 💻 📖 🤔 🚧 👀 ⚠️
Jonas Lagoni
Jonas Lagoni

💬 🐛 💻 🤔 👀
Maciej Urbańczyk
Maciej Urbańczyk

🐛 💻 👀
Juan Mellado
Juan Mellado

💻
James Crowley
James Crowley

💻
raisel melian
raisel melian

💻
danielchu
danielchu

🚇 💻
Jürgen B.
Jürgen B.

💻
Viacheslav Turovskyi
Viacheslav Turovskyi

⚠️ 💻
Khuda Dad Nomani
Khuda Dad Nomani

💻 🐛 ⚠️
Aayush Kumar Sahu
Aayush Kumar Sahu

⚠️
Jordan Tucker
Jordan Tucker

⚠️ 💻
vishesh13byte
vishesh13byte

⚠️
Elakya
Elakya

💻
Dominik Schwank
Dominik Schwank

🐛 💻
Ruchi Pakhle
Ruchi Pakhle

📖
Đỗ Trọng Hải
Đỗ Trọng Hải

🛡️
- - - - - - -This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! diff --git a/package-lock.json b/package-lock.json index 87bcf3a07..b65eccd70 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,6 +41,7 @@ } }, "apps/parser": { + "name": "@asyncapi/parser", "version": "3.0.14", "license": "Apache-2.0", "dependencies": { diff --git a/turbo.json b/turbo.json index 2c2fa1430..5000aa3a4 100644 --- a/turbo.json +++ b/turbo.json @@ -1,10 +1,6 @@ { "$schema": "https://turbo.build/schema.json", - "globalDependencies": ["**/.env.*local"], "pipeline": { - "build": { - "outputs": [".next/**", "!.next/cache/**"] - }, "test": {}, "test:unit": {}, "test:integration": {},