Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ GET /self/v1/api/schemas/dependents/{path}
|----------|------|----------|-------------|
| `/*/from` | String | Yes | The absolute URL of the schema that originates the dependency |
| `/*/to` | String | Yes | The absolute URL of the schema being referenced |
| `/*/at` | String | Yes | The JSON Pointer to the schema location where the dependency originates |

=== "404"

Expand Down
138 changes: 138 additions & 0 deletions enterprise/e2e/html/hurl/mcp-2025-11-25-get_schema_dependents.all.hurl
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,11 @@ jsonpath "$.result.content[2].mimeType" == "application/schema+json"
jsonpath "$.result.structuredContent.results" count == 1
jsonpath "$.result.structuredContent.results[0].from" == "{{base}}/self/v1/schemas/mcp/response"
jsonpath "$.result.structuredContent.results[0].to" == "{{base}}/self/v1/schemas/mcp/error"
jsonpath "$.result.structuredContent.results[0].at" == "/$defs/single/anyOf/2/$ref"
variable "text" jsonpath "$.results" count == 1
variable "text" jsonpath "$.results[0].from" == "{{base}}/self/v1/schemas/mcp/response"
variable "text" jsonpath "$.results[0].to" == "{{base}}/self/v1/schemas/mcp/error"
variable "text" jsonpath "$.results[0].at" == "/$defs/single/anyOf/2/$ref"

POST {{base}}/self/v1/api/schemas/evaluate{{schema_path}}
```
Expand Down Expand Up @@ -296,9 +298,11 @@ jsonpath "$.result.content[2].mimeType" == "application/schema+json"
jsonpath "$.result.structuredContent.results" count == 1
jsonpath "$.result.structuredContent.results[0].from" == "{{base}}/self/v1/schemas/mcp/response"
jsonpath "$.result.structuredContent.results[0].to" == "{{base}}/self/v1/schemas/mcp/error"
jsonpath "$.result.structuredContent.results[0].at" == "/$defs/single/anyOf/2/$ref"
variable "text" jsonpath "$.results" count == 1
variable "text" jsonpath "$.results[0].from" == "{{base}}/self/v1/schemas/mcp/response"
variable "text" jsonpath "$.results[0].to" == "{{base}}/self/v1/schemas/mcp/error"
variable "text" jsonpath "$.results[0].at" == "/$defs/single/anyOf/2/$ref"

POST {{base}}/self/v1/api/schemas/evaluate{{schema_path}}
```
Expand Down Expand Up @@ -1233,3 +1237,137 @@ HTTP 200
header "Referrer-Policy" not exists
header "Date" matches /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), (0[1-9]|[12][0-9]|3[01]) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) [0-9]{4} ([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9] GMT$/
jsonpath "$.valid" == true

POST {{base}}/self/v1/mcp
MCP-Protocol-Version: 2025-11-25
Content-Type: application/json
```
{
"jsonrpc": "2.0",
"id": 360,
"method": "tools/call",
"params": {
"name": "get_schema_dependents",
"arguments": { "schema": "{{base}}/test/schemas/custom-meta-draft7" }
}
}
```
HTTP 200
Content-Type: application/json
Access-Control-Allow-Origin: {{base}}
Link: </self/v1/schemas/mcp/response>; rel="describedby"
MCP-Protocol-Version: 2025-11-25
[Captures]
last_response: body
schema_path: header "Link" regex "<([^>]+)>"
text: jsonpath "$.result.content[0].text"
structured_content: body regex "(?s)\"structuredContent\": ((?:\\{.*?\n \\})|(?:\\[.*?\n \\]))"
[Asserts]
header "Referrer-Policy" not exists
header "Date" matches /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), (0[1-9]|[12][0-9]|3[01]) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) [0-9]{4} ([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9] GMT$/
jsonpath "$.jsonrpc" == "2.0"
jsonpath "$.id" == 360
jsonpath "$.result.isError" == false
jsonpath "$.result.content" count == 3
jsonpath "$.result.content[0].type" == "text"
jsonpath "$.result.content[1].type" == "resource_link"
jsonpath "$.result.content[1].uri" == "{{base}}/test/schemas/custom-meta-draft7"
jsonpath "$.result.content[1].mimeType" == "application/schema+json"
jsonpath "$.result.content[2].type" == "resource_link"
jsonpath "$.result.content[2].uri" == "{{base}}/test/schemas/using-meta-draft7"
jsonpath "$.result.content[2].mimeType" == "application/schema+json"
jsonpath "$.result.structuredContent.results" count == 1
jsonpath "$.result.structuredContent.results[0].from" == "{{base}}/test/schemas/using-meta-draft7"
jsonpath "$.result.structuredContent.results[0].to" == "{{base}}/test/schemas/custom-meta-draft7"
jsonpath "$.result.structuredContent.results[0].at" == "/$schema"
variable "text" jsonpath "$.results" count == 1
variable "text" jsonpath "$.results[0].from" == "{{base}}/test/schemas/using-meta-draft7"
variable "text" jsonpath "$.results[0].to" == "{{base}}/test/schemas/custom-meta-draft7"
variable "text" jsonpath "$.results[0].at" == "/$schema"

POST {{base}}/self/v1/api/schemas/evaluate{{schema_path}}
```
{{last_response}}
```
HTTP 200
[Asserts]
header "Referrer-Policy" not exists
header "Date" matches /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), (0[1-9]|[12][0-9]|3[01]) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) [0-9]{4} ([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9] GMT$/
jsonpath "$.valid" == true

POST {{base}}/self/v1/api/schemas/evaluate{{output_schema_path}}
```
{{structured_content}}
```
HTTP 200
[Asserts]
header "Referrer-Policy" not exists
header "Date" matches /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), (0[1-9]|[12][0-9]|3[01]) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) [0-9]{4} ([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9] GMT$/
jsonpath "$.valid" == true

POST {{base}}/self/v1/mcp
MCP-Protocol-Version: 2025-11-25
Content-Type: application/json
```
{
"jsonrpc": "2.0",
"id": 361,
"method": "tools/call",
"params": {
"name": "get_schema_dependents",
"arguments": { "schema": "{{base}}/test/schemas/custom-meta-2020" }
}
}
```
HTTP 200
Content-Type: application/json
Access-Control-Allow-Origin: {{base}}
Link: </self/v1/schemas/mcp/response>; rel="describedby"
MCP-Protocol-Version: 2025-11-25
[Captures]
last_response: body
schema_path: header "Link" regex "<([^>]+)>"
text: jsonpath "$.result.content[0].text"
structured_content: body regex "(?s)\"structuredContent\": ((?:\\{.*?\n \\})|(?:\\[.*?\n \\]))"
[Asserts]
header "Referrer-Policy" not exists
header "Date" matches /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), (0[1-9]|[12][0-9]|3[01]) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) [0-9]{4} ([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9] GMT$/
jsonpath "$.jsonrpc" == "2.0"
jsonpath "$.id" == 361
jsonpath "$.result.isError" == false
jsonpath "$.result.content" count == 3
jsonpath "$.result.content[0].type" == "text"
jsonpath "$.result.content[1].type" == "resource_link"
jsonpath "$.result.content[1].uri" == "{{base}}/test/schemas/custom-meta-2020"
jsonpath "$.result.content[1].mimeType" == "application/schema+json"
jsonpath "$.result.content[2].type" == "resource_link"
jsonpath "$.result.content[2].uri" == "{{base}}/test/schemas/using-meta-2020"
jsonpath "$.result.content[2].mimeType" == "application/schema+json"
jsonpath "$.result.structuredContent.results" count == 1
jsonpath "$.result.structuredContent.results[0].from" == "{{base}}/test/schemas/using-meta-2020"
jsonpath "$.result.structuredContent.results[0].to" == "{{base}}/test/schemas/custom-meta-2020"
jsonpath "$.result.structuredContent.results[0].at" == "/$schema"
variable "text" jsonpath "$.results" count == 1
variable "text" jsonpath "$.results[0].from" == "{{base}}/test/schemas/using-meta-2020"
variable "text" jsonpath "$.results[0].to" == "{{base}}/test/schemas/custom-meta-2020"
variable "text" jsonpath "$.results[0].at" == "/$schema"

POST {{base}}/self/v1/api/schemas/evaluate{{schema_path}}
```
{{last_response}}
```
HTTP 200
[Asserts]
header "Referrer-Policy" not exists
header "Date" matches /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), (0[1-9]|[12][0-9]|3[01]) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) [0-9]{4} ([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9] GMT$/
jsonpath "$.valid" == true

POST {{base}}/self/v1/api/schemas/evaluate{{output_schema_path}}
```
{{structured_content}}
```
HTTP 200
[Asserts]
header "Referrer-Policy" not exists
header "Date" matches /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), (0[1-9]|[12][0-9]|3[01]) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) [0-9]{4} ([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9] GMT$/
jsonpath "$.valid" == true
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,11 @@ jsonpath "$.result.content[2].mimeType" == "application/schema+json"
jsonpath "$.result.structuredContent.results" count == 1
jsonpath "$.result.structuredContent.results[0].from" == "{{base}}/v1/catalog/self/v1/schemas/mcp/response"
jsonpath "$.result.structuredContent.results[0].to" == "{{base}}/v1/catalog/self/v1/schemas/mcp/error"
jsonpath "$.result.structuredContent.results[0].at" == "/$defs/single/anyOf/2/$ref"
variable "text" jsonpath "$.results" count == 1
variable "text" jsonpath "$.results[0].from" == "{{base}}/v1/catalog/self/v1/schemas/mcp/response"
variable "text" jsonpath "$.results[0].to" == "{{base}}/v1/catalog/self/v1/schemas/mcp/error"
variable "text" jsonpath "$.results[0].at" == "/$defs/single/anyOf/2/$ref"

POST {{base}}/v1/catalog/self/v1/api/schemas/evaluate{{schema_path}}
```
Expand Down Expand Up @@ -131,9 +133,11 @@ jsonpath "$.result.content[2].mimeType" == "application/schema+json"
jsonpath "$.result.structuredContent.results" count == 1
jsonpath "$.result.structuredContent.results[0].from" == "{{base}}/v1/catalog/self/v1/schemas/mcp/response"
jsonpath "$.result.structuredContent.results[0].to" == "{{base}}/v1/catalog/self/v1/schemas/mcp/error"
jsonpath "$.result.structuredContent.results[0].at" == "/$defs/single/anyOf/2/$ref"
variable "text" jsonpath "$.results" count == 1
variable "text" jsonpath "$.results[0].from" == "{{base}}/v1/catalog/self/v1/schemas/mcp/response"
variable "text" jsonpath "$.results[0].to" == "{{base}}/v1/catalog/self/v1/schemas/mcp/error"
variable "text" jsonpath "$.results[0].at" == "/$defs/single/anyOf/2/$ref"

POST {{base}}/v1/catalog/self/v1/api/schemas/evaluate{{schema_path}}
```
Expand Down
24 changes: 14 additions & 10 deletions src/index/generators.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include <queue> // std::queue
#include <set> // std::set
#include <sstream> // std::ostringstream
#include <tuple> // std::tuple
#include <unordered_map> // std::unordered_map
#include <utility> // std::move, std::pair

Expand Down Expand Up @@ -313,7 +314,8 @@ struct GENERATE_DEPENDENTS {

using DirectMap =
std::unordered_map<sourcemeta::core::JSON::String,
std::unordered_set<sourcemeta::core::JSON::String>>;
std::set<std::pair<sourcemeta::core::JSON::String,
sourcemeta::core::JSON::String>>>;
DirectMap direct;
for (const auto &dependency : action.dependencies) {
const auto contents_option{
Expand All @@ -322,15 +324,16 @@ struct GENERATE_DEPENDENTS {
const auto &contents{contents_option.value()};
assert(contents.is_array());
for (const auto &entry : contents.as_array()) {
direct[entry.at("to").to_string()].emplace(
entry.at("from").to_string());
direct[entry.at("to").to_string()].emplace(entry.at("from").to_string(),
entry.at("at").to_string());
}
}

using TransitiveMap =
std::unordered_map<sourcemeta::core::JSON::String,
std::set<std::pair<sourcemeta::core::JSON::String,
sourcemeta::core::JSON::String>>>;
using TransitiveMap = std::unordered_map<
sourcemeta::core::JSON::String,
std::set<std::tuple<sourcemeta::core::JSON::String,
sourcemeta::core::JSON::String,
sourcemeta::core::JSON::String>>>;
TransitiveMap transitive;
for (const auto &[target, _] : direct) {
auto &edges{transitive[target]};
Expand All @@ -346,8 +349,8 @@ struct GENERATE_DEPENDENTS {
continue;
}

for (const auto &dependent : match->second) {
edges.emplace(dependent, current);
for (const auto &[dependent, at] : match->second) {
edges.emplace(dependent, current, at);
if (visited.emplace(dependent).second) {
queue.emplace(dependent);
}
Expand All @@ -358,10 +361,11 @@ struct GENERATE_DEPENDENTS {
auto result{sourcemeta::core::JSON::make_array()};
const auto match{transitive.find(std::string{action.data})};
if (match != transitive.cend()) {
for (const auto &[from, to] : match->second) {
for (const auto &[from, to, at] : match->second) {
auto object{sourcemeta::core::JSON::make_object()};
object.assign("from", sourcemeta::core::JSON{from});
object.assign("to", sourcemeta::core::JSON{to});
object.assign("at", sourcemeta::core::JSON{at});
result.push_back(std::move(object));
}
}
Expand Down
10 changes: 8 additions & 2 deletions src/self/v1/schemas/api/schemas/dependents/response.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,21 @@
[
{
"from": "https://example.com/schemas/user.json",
"to": "https://example.com/schemas/address.json"
"to": "https://example.com/schemas/address.json",
"at": "/properties/address/$ref"
}
]
],
"type": "array",
"items": {
"type": "object",
"required": [ "from", "to" ],
"required": [ "from", "to", "at" ],
"properties": {
"at": {
"x-format-assertion": true,
"type": "string",
"format": "json-pointer"
},
"from": {
"x-format-assertion": true,
"type": "string",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"results": [
{
"from": "https://example.com/schemas/user.json",
"to": "https://example.com/schemas/address.json"
"to": "https://example.com/schemas/address.json",
"at": "/properties/address"
Comment thread
jviotti marked this conversation as resolved.
Outdated
}
]
}
Expand Down
7 changes: 7 additions & 0 deletions test/e2e/headless/hurl/schemas-dependents.all.hurl
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@ header "Last-Modified" exists
jsonpath "$" count == 3
jsonpath "$[0].from" == "{{base}}/test/schemas/bundling-double"
jsonpath "$[0].to" == "{{base}}/test/schemas/bundling-single"
jsonpath "$[0].at" == "/properties/foo/$ref"
jsonpath "$[1].from" == "{{base}}/test/schemas/with-rebase"
jsonpath "$[1].to" == "{{base}}/test/schemas/bundling-single"
jsonpath "$[1].at" == "/$ref"
jsonpath "$[2].from" == "{{base}}/test/schemas/with-rebase-same-host"
jsonpath "$[2].to" == "{{base}}/test/schemas/bundling-single"
jsonpath "$[2].at" == "/$ref"

POST {{base}}/self/v1/api/schemas/evaluate{{schema_path}}
```
Expand Down Expand Up @@ -46,12 +49,16 @@ header "Last-Modified" exists
jsonpath "$" count == 4
jsonpath "$[0].from" == "{{base}}/test/schemas/bundling-double"
jsonpath "$[0].to" == "{{base}}/test/schemas/bundling-single"
jsonpath "$[0].at" == "/properties/foo/$ref"
jsonpath "$[1].from" == "{{base}}/test/schemas/bundling-single"
jsonpath "$[1].to" == "{{base}}/test/schemas/no-id"
jsonpath "$[1].at" == "/properties/foo/$ref"
jsonpath "$[2].from" == "{{base}}/test/schemas/with-rebase"
jsonpath "$[2].to" == "{{base}}/test/schemas/bundling-single"
jsonpath "$[2].at" == "/$ref"
jsonpath "$[3].from" == "{{base}}/test/schemas/with-rebase-same-host"
jsonpath "$[3].to" == "{{base}}/test/schemas/bundling-single"
jsonpath "$[3].at" == "/$ref"

POST {{base}}/self/v1/api/schemas/evaluate{{schema_path}}
```
Expand Down
8 changes: 4 additions & 4 deletions test/e2e/html/hurl/list.all.hurl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ header "Last-Modified" exists
jsonpath "$.path" == "/"
jsonpath "$.url" == "{{base}}"
jsonpath "$.breadcrumb" count == 0
jsonpath "$.schemas" == 102
jsonpath "$.schemas" == 106
jsonpath "$.entries" count >= 2
jsonpath "$.entries[0].name" == "self"
jsonpath "$.entries[0].title" == "Self"
Expand All @@ -28,7 +28,7 @@ jsonpath "$.entries[1].title" == "Test"
jsonpath "$.entries[1].description" == "A directory full of testing schemas"
jsonpath "$.entries[1].type" == "directory"
jsonpath "$.entries[1].health" == 13
jsonpath "$.entries[1].schemas" == 46
jsonpath "$.entries[1].schemas" == 50
jsonpath "$.entries[1].path" == "/test/"

POST {{base}}/self/v1/api/schemas/evaluate{{schema_path}}
Expand Down Expand Up @@ -62,7 +62,7 @@ jsonpath "$.breadcrumb[0].name" == "test"
jsonpath "$.breadcrumb[0].path" == "/test/"
jsonpath "$.description" == "A directory full of testing schemas"
jsonpath "$.title" == "Test"
jsonpath "$.schemas" == 46
jsonpath "$.schemas" == 50
jsonpath "$.entries" count == 13
jsonpath "$.entries[0].name" == "v2.0"
jsonpath "$.entries[0].type" == "directory"
Expand Down Expand Up @@ -124,7 +124,7 @@ jsonpath "$.entries[10].path" == "/test/same/"
jsonpath "$.entries[11].name" == "schemas"
jsonpath "$.entries[11].type" == "directory"
jsonpath "$.entries[11].health" == 7
jsonpath "$.entries[11].schemas" == 25
jsonpath "$.entries[11].schemas" == 29
jsonpath "$.entries[11].path" == "/test/schemas/"
jsonpath "$.entries[12].name" == "unsafe-alert"
jsonpath "$.entries[12].type" == "directory"
Expand Down
Loading
Loading