From d24a4706243f9f49388b150bc2b99851c95cdc29 Mon Sep 17 00:00:00 2001 From: Abhishek Khari <172838872+abhi-03-kh@users.noreply.github.com> Date: Wed, 21 Jan 2026 19:07:24 +0000 Subject: [PATCH 1/2] fix: validate channel address when parameters are defined --- package-lock.json | 96 ++++++++++++++++--- packages/parser/src/ruleset/v3/ruleset.ts | 16 ++-- .../rules/v3/channel-parameters.spec.ts | 62 ++++++++++++ 3 files changed, 154 insertions(+), 20 deletions(-) create mode 100644 packages/parser/test/ruleset/rules/v3/channel-parameters.spec.ts diff --git a/package-lock.json b/package-lock.json index 3b1a2b808..e9bf0b375 100644 --- a/package-lock.json +++ b/package-lock.json @@ -119,6 +119,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", "dev": true, + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.24.7", @@ -1782,6 +1783,7 @@ "integrity": "sha512-+wSycNxOw9QQz81AJAZlNS34EtOIifwUXMPACg05PWjECsjOKDTXLCVPx6J0lRaxhHSGBU2OYs9mRfIvxGt3CA==", "dev": true, "hasInstallScript": true, + "peer": true, "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.12" @@ -1941,18 +1943,6 @@ "@types/node": "*" } }, - "node_modules/@types/eslint": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.0.tgz", - "integrity": "sha512-gi6WQJ7cHRgZxtkQEoyHMppPjq9Kxo5Tjn2prSKDSmZrCz8TZ3jSRCeTJm+WoM+oB0WG37bRqLzaaU3q7JypGg==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, "node_modules/@types/estree": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", @@ -2116,6 +2106,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", "dev": true, + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "5.62.0", "@typescript-eslint/types": "5.62.0", @@ -2492,6 +2483,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2553,6 +2545,7 @@ "version": "8.17.1", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -3343,6 +3336,7 @@ "url": "https://github.com/sponsors/ai" } ], + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001640", "electron-to-chromium": "^1.4.820", @@ -4558,6 +4552,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -4613,6 +4608,7 @@ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", "dev": true, + "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -4790,6 +4786,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", "dev": true, + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "7.18.0", "@typescript-eslint/types": "7.18.0", @@ -7842,6 +7839,7 @@ "version": "1.3.9", "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.3.9.tgz", "integrity": "sha512-i1rBX5N7VPl0eYb6+mHNp52sEuaS2Wi8CDYx1X5sn9naevL78+265XJqy1qENEk7mRKwS06NHpUqiBwR7qeodw==", + "peer": true, "engines": { "node": ">= 10.16.0" } @@ -9215,6 +9213,7 @@ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", "dev": true, + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -9918,6 +9917,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -10960,6 +10960,20 @@ "turbo-windows-arm64": "1.13.3" } }, + "node_modules/turbo-darwin-64": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/turbo-darwin-64/-/turbo-darwin-64-1.13.3.tgz", + "integrity": "sha512-glup8Qx1qEFB5jerAnXbS8WrL92OKyMmg5Hnd4PleLljAeYmx+cmmnsmLT7tpaVZIN58EAAwu8wHC6kIIqhbWA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ] + }, "node_modules/turbo-darwin-arm64": { "version": "1.13.3", "resolved": "https://registry.npmjs.org/turbo-darwin-arm64/-/turbo-darwin-arm64-1.13.3.tgz", @@ -10973,6 +10987,62 @@ "darwin" ] }, + "node_modules/turbo-linux-64": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/turbo-linux-64/-/turbo-linux-64-1.13.3.tgz", + "integrity": "sha512-G+HGrau54iAnbXLfl+N/PynqpDwi/uDzb6iM9hXEDG+yJnSJxaHMShhOkXYJPk9offm9prH33Khx2scXrYVW1g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/turbo-linux-arm64": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/turbo-linux-arm64/-/turbo-linux-arm64-1.13.3.tgz", + "integrity": "sha512-qWwEl5VR02NqRyl68/3pwp3c/olZuSp+vwlwrunuoNTm6JXGLG5pTeme4zoHNnk0qn4cCX7DFrOboArlYxv0wQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/turbo-windows-64": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/turbo-windows-64/-/turbo-windows-64-1.13.3.tgz", + "integrity": "sha512-Nudr4bRChfJzBPzEmpVV85VwUYRCGKecwkBFpbp2a4NtrJ3+UP1VZES653ckqCu2FRyRuS0n03v9euMbAvzH+Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/turbo-windows-arm64": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/turbo-windows-arm64/-/turbo-windows-arm64-1.13.3.tgz", + "integrity": "sha512-ouJCgsVLd3icjRLmRvHQDDZnmGzT64GBupM1Y+TjtYn2LVaEBoV6hicFy8x5DUpnqdLy+YpCzRMkWlwhmkX7sQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -11324,6 +11394,7 @@ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz", "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==", "dev": true, + "peer": true, "dependencies": { "@types/estree": "^1.0.5", "@webassemblyjs/ast": "^1.12.1", @@ -11438,6 +11509,7 @@ "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", "dev": true, + "peer": true, "dependencies": { "@discoveryjs/json-ext": "^0.5.0", "@webpack-cli/configtest": "^1.2.0", diff --git a/packages/parser/src/ruleset/v3/ruleset.ts b/packages/parser/src/ruleset/v3/ruleset.ts index efc719483..6734298af 100644 --- a/packages/parser/src/ruleset/v3/ruleset.ts +++ b/packages/parser/src/ruleset/v3/ruleset.ts @@ -3,7 +3,7 @@ import { AsyncAPIFormats } from '../formats'; import { operationMessagesUnambiguity } from './functions/operationMessagesUnambiguity'; -import { pattern } from '@stoplight/spectral-functions'; +import { pattern, truthy } from '@stoplight/spectral-functions'; import { channelServers } from '../functions/channelServers'; export const v3CoreRuleset = { @@ -13,18 +13,18 @@ export const v3CoreRuleset = { /** * Operation Object rules */ - 'asyncapi3-operation-messages-from-referred-channel': { - description: 'Operation "messages" must be a subset of the messages defined in the channel referenced in this operation.', - message: '{{error}}', + 'channel-parameters-require-address': { + description: 'Channel address must not be null when parameters are defined.', + message: 'Channel address must not be null when parameters are defined.', severity: 'error', recommended: true, - resolved: false, // We use the JSON pointer to match the channel. given: [ - '$.operations.*', - '$.components.operations.*', + '$.channels[?(@.parameters)]', + '$.components.channels[?(@.parameters)]' ], then: { - function: operationMessagesUnambiguity, + field: 'address', + function: truthy, }, }, 'asyncapi3-required-operation-channel-unambiguity': { diff --git a/packages/parser/test/ruleset/rules/v3/channel-parameters.spec.ts b/packages/parser/test/ruleset/rules/v3/channel-parameters.spec.ts new file mode 100644 index 000000000..715d122b8 --- /dev/null +++ b/packages/parser/test/ruleset/rules/v3/channel-parameters.spec.ts @@ -0,0 +1,62 @@ +import { testRule, DiagnosticSeverity } from '../../tester'; + +testRule('channel-parameters-require-address', [ + { + name: 'valid case - no parameters', + document: { + asyncapi: '3.0.0', + channels: { + channel: { + address: null, + }, + }, + }, + errors: [], + }, + + { + name: 'valid case - parameters with address', + document: { + asyncapi: '3.0.0', + channels: { + channel: { + address: 'some/address', + parameters: { + param: { + description: 'test', + }, + }, + }, + }, + }, + errors: [], + }, + + { + name: 'invalid case - parameters but address null', + document: { + asyncapi: '3.0.0', + info: { + title: 'Test', + version: '1.0.0', + }, + channels: { + userSignedup: { + address: null, + parameters: { + test: { + description: 'This should fail validation', + }, + }, + }, + }, + }, + errors: [ + { + message: 'Channel address must not be null when parameters are defined.', + path: ['channels', 'userSignedup', 'address'], + severity: DiagnosticSeverity.Error, + }, +], + }, +]); \ No newline at end of file From 59acc0cd8326dbb514045bef097495e5bbff29c3 Mon Sep 17 00:00:00 2001 From: Abhishek Khari <172838872+abhi-03-kh@users.noreply.github.com> Date: Wed, 21 Jan 2026 19:24:34 +0000 Subject: [PATCH 2/2] chore: add changeset --- .changeset/strict-icons-flash.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/strict-icons-flash.md diff --git a/.changeset/strict-icons-flash.md b/.changeset/strict-icons-flash.md new file mode 100644 index 000000000..1bd755919 --- /dev/null +++ b/.changeset/strict-icons-flash.md @@ -0,0 +1,5 @@ +--- +"@asyncapi/parser": patch +--- + +fix: validate channel address when parameters are defined