Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
6 changes: 4 additions & 2 deletions docs/bundle.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ to resolve remote references in advance and inline them into the given schema
for local consumption or further distribution. The JSON Schema CLI supports
this functionality through the `bundle` command.

Use `--indentation/-n` to set how many spaces each level of nesting of the
result is laid out with, which defaults to two.
The result is printed in the format the input was written in: a YAML schema
bundles into YAML and a JSON schema into JSON. A YAML result keeps the width
each level of nesting was written with, while a JSON result is laid out with
two spaces. Use `--indentation/-n` to set the width in either case.

> [!WARNING]
> A popular use case for JSON Schema is providing auto-completion for code
Expand Down
8 changes: 5 additions & 3 deletions docs/upgrade.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ specifications into account, including re-writing references that point at
locations whose path has changed. By default, schemas are upgraded to the
latest supported dialect, and the result is printed to standard output.

Use `--indentation/-n` to set how many spaces each level of nesting of the
result is laid out with, which defaults to two.
The result is printed in the format the input was written in: a YAML schema
upgrades into YAML and a JSON schema into JSON. A YAML result keeps the width
each level of nesting was written with, while a JSON result is laid out with
two spaces. Use `--indentation/-n` to set the width in either case.

For example, consider the following Draft 3 schema:

Expand Down Expand Up @@ -132,7 +134,7 @@ jsonschema upgrade path/to/schema.json \
--resolve path/to/imported.json
```

### Upgrade a YAML JSON Schema (output is JSON)
### Upgrade a YAML JSON Schema

```sh
jsonschema upgrade path/to/schema.yaml
Expand Down
17 changes: 12 additions & 5 deletions src/command_bundle.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ auto sourcemeta::jsonschema::bundle(const sourcemeta::core::Options &options)
}

validate_http_headers(options);
const auto indentation{parse_indentation(options)};
const auto indentation{parse_optional_indentation(options)};

const std::filesystem::path schema_path{options.positional().front()};
const bool schema_from_stdin = (schema_path == "-");
Expand All @@ -41,8 +41,15 @@ auto sourcemeta::jsonschema::bundle(const sourcemeta::core::Options &options)
const auto &configuration{
read_configuration(options, configuration_path, schema_config_base)};
const auto dialect{default_dialect(options, configuration)};
auto parsed_schema{schema_from_stdin ? read_from_stdin()
: read_file(schema_path)};
auto parsed_schema{schema_from_stdin
? read_from_stdin(nullptr, InputFormatting::Preserve)
: read_file(schema_path, InputFormatting::Preserve)};

@augmentcode augmentcode Bot Sep 24, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/command_bundle.cc:45: In preserve mode, read_yaml_file flags subsequent YAML documents in parsed_schema.multidocument, but this command never inspects it; a multi-document YAML file therefore bundles only the first document and silently drops the rest from stdout. read_from_stdin rejects this case, so file and stdin inputs now behave inconsistently. Other locations where this applies: src/command_upgrade.cc:182.

Severity: medium

Other Locations
  • src/command_upgrade.cc:182

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.

if (parsed_schema.multidocument) {
throw MultiDocumentInputError{
"This command does not support input with multiple documents",
schema_display_path};
}

if (!parsed_schema.document.is_object() &&
!parsed_schema.document.is_boolean()) {
Expand Down Expand Up @@ -119,6 +126,6 @@ auto sourcemeta::jsonschema::bundle(const sourcemeta::core::Options &options)
schema_display_path, error.what());
}

sourcemeta::core::prettify(schema, std::cout, indentation);
std::cout << "\n";
sourcemeta::jsonschema::write_schema(schema, std::cout, indentation,
parsed_schema.roundtrip);
}
17 changes: 12 additions & 5 deletions src/command_upgrade.cc
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ auto sourcemeta::jsonschema::upgrade(const sourcemeta::core::Options &options)
const auto target_value{options.contains("to") ? options.at("to").front()
: std::string_view{"2020-12"}};
const auto target_dialect{parse_target_dialect(target_value)};
const auto indentation{parse_indentation(options)};
const auto indentation{parse_optional_indentation(options)};

const std::filesystem::path schema_path{options.positional().front()};
const bool schema_from_stdin = (schema_path == "-");
Expand All @@ -178,8 +178,15 @@ auto sourcemeta::jsonschema::upgrade(const sourcemeta::core::Options &options)
const auto &configuration{
read_configuration(options, configuration_path, schema_config_base)};
const auto dialect{default_dialect(options, configuration)};
auto parsed_schema{schema_from_stdin ? read_from_stdin()
: read_file(schema_path)};
auto parsed_schema{schema_from_stdin
? read_from_stdin(nullptr, InputFormatting::Preserve)
: read_file(schema_path, InputFormatting::Preserve)};

if (parsed_schema.multidocument) {
throw MultiDocumentInputError{
"This command does not support input with multiple documents",
schema_display_path};
}

if (!parsed_schema.document.is_object() &&
!parsed_schema.document.is_boolean()) {
Expand All @@ -198,6 +205,6 @@ auto sourcemeta::jsonschema::upgrade(const sourcemeta::core::Options &options)

sourcemeta::jsonschema::format_schema(schema, custom_resolver, dialect);

sourcemeta::core::prettify(schema, std::cout, indentation);
std::cout << "\n";
sourcemeta::jsonschema::write_schema(schema, std::cout, indentation,
parsed_schema.roundtrip);
}
17 changes: 12 additions & 5 deletions src/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ inline auto format_schema(sourcemeta::core::JSON &schema,

inline auto
write_schema(const sourcemeta::core::JSON &schema, std::ostream &stream,
const std::size_t indentation,
const std::optional<std::size_t> indentation,
const std::optional<sourcemeta::core::YAMLRoundTrip> &roundtrip)
-> void {
if (roundtrip.has_value()) {
Expand All @@ -192,7 +192,7 @@ write_schema(const sourcemeta::core::JSON &schema, std::ostream &stream,
return;
}

sourcemeta::core::prettify(schema, stream, indentation);
sourcemeta::core::prettify(schema, stream, indentation.value_or(2));
stream << "\n";
}

Expand Down Expand Up @@ -226,10 +226,12 @@ inline auto parse_jobs(const sourcemeta::core::Options &options)
static_cast<std::size_t>(1));
}

inline auto parse_indentation(const sourcemeta::core::Options &options)
-> std::size_t {
// The width the user asked for, or nothing when they asked for none, which
// leaves a document that carries a width of its own keeping it
inline auto parse_optional_indentation(const sourcemeta::core::Options &options)
-> std::optional<std::size_t> {
if (!options.contains("indentation")) {
return 2;
return std::nullopt;
}

const std::string value{options.at("indentation").front()};
Expand All @@ -246,6 +248,11 @@ inline auto parse_indentation(const sourcemeta::core::Options &options)
}
}

inline auto parse_indentation(const sourcemeta::core::Options &options)
-> std::size_t {
return parse_optional_indentation(options).value_or(2);
}

inline auto format_assertion_tweaks(const sourcemeta::core::Options &options)
-> std::optional<sourcemeta::blaze::Tweaks> {
if (options.contains("format-assertion")) {
Expand Down
5 changes: 5 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,7 @@ add_jsonschema_test(bundle/pass_resolve_single_default_dialect)
add_jsonschema_test(bundle/pass_boolean_schema_default_dialect)
add_jsonschema_test(bundle/pass_resolve_yaml)
add_jsonschema_test(bundle/pass_indentation)
add_jsonschema_test(bundle/pass_yaml_indentation)
add_jsonschema_test(bundle/fail_invalid_indentation)
add_jsonschema_test(bundle/pass_resolve_with_ignore)
add_jsonschema_test(bundle/pass_resolve_no_identifier)
Expand Down Expand Up @@ -720,7 +721,9 @@ add_jsonschema_test(bundle/pass_config_ignore)
add_jsonschema_test(bundle/pass_ref_in_bundled_resolves_against_id)
add_jsonschema_test(bundle/pass_resolve_deduplicate_embedded)
add_jsonschema_test(bundle/pass_stdin)
add_jsonschema_test(bundle/pass_stdin_yaml)
add_jsonschema_test(bundle/fail_stdin_multidocument)
add_jsonschema_test(bundle/fail_multidocument)
add_jsonschema_test(bundle/fail_stdin_not_schema)
add_jsonschema_test(bundle/fail_stdin_invalid_json)
add_jsonschema_test(bundle/fail_invalid_header)
Expand Down Expand Up @@ -1214,6 +1217,8 @@ add_jsonschema_test(upgrade/pass_configuration_option)
add_jsonschema_test(upgrade/pass_resolve)
add_jsonschema_test(upgrade/pass_yaml_input)
add_jsonschema_test(upgrade/pass_indentation)
add_jsonschema_test(upgrade/pass_yaml_indentation)
add_jsonschema_test(upgrade/fail_multidocument)
add_jsonschema_test(upgrade/fail_invalid_indentation)
add_jsonschema_test(upgrade/pass_embedded_resources)
add_jsonschema_test(upgrade/fail_custom_metaschema_root)
Expand Down
35 changes: 35 additions & 0 deletions test/bundle/fail_multidocument.clitest
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
WRITE schema.yaml UNTIL EOF
$schema: https://json-schema.org/draft/2020-12/schema
$id: https://example.com/first
type: string
---
$schema: https://json-schema.org/draft/2020-12/schema
$id: https://example.com/second
type: integer
EOF

// Not supported
RUN bundle schema.yaml STDIN /dev/null IN . INTO result_0.txt EXPECTING 3

REPLACE $CWD WITH '[CWD]' IN result_0.txt

WRITE expected_0.txt UNTIL EOF
2> error: This command does not support input with multiple documents
2> at file path [CWD]/schema.yaml
EOF

COMPARE result_0.txt AGAINST expected_0.txt

// Not supported
RUN bundle schema.yaml --json STDIN /dev/null IN . INTO result_1.txt EXPECTING 3

REPLACE $CWD WITH '[CWD]' IN result_1.txt

WRITE expected_1.txt UNTIL EOF
1> {
1> "error": "This command does not support input with multiple documents",
1> "filePath": "[CWD]/schema.yaml"
1> }
EOF

COMPARE result_1.txt AGAINST expected_1.txt
20 changes: 8 additions & 12 deletions test/bundle/pass_custom_extension_yaml.clitest
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,14 @@ EOF
RUN bundle schema.custom --resolve nested.custom STDIN /dev/null IN . INTO result.txt EXPECTING 0

WRITE expected.txt UNTIL EOF
1> {
1> "$schema": "https://json-schema.org/draft/2020-12/schema",
1> "$id": "https://example.com",
1> "$ref": "nested",
1> "$defs": {
1> "https://example.com/nested": {
1> "$schema": "https://json-schema.org/draft/2020-12/schema",
1> "$id": "https://example.com/nested",
1> "type": "string"
1> }
1> }
1> }
1> $schema: https://json-schema.org/draft/2020-12/schema
1> $id: https://example.com
1> $ref: nested
1> $defs:
1> https://example.com/nested:
1> $schema: https://json-schema.org/draft/2020-12/schema
1> $id: https://example.com/nested
1> type: string
EOF

COMPARE result.txt AGAINST expected.txt
32 changes: 14 additions & 18 deletions test/bundle/pass_resolve_yaml.clitest
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,25 @@ EOF

RUN bundle schema.yaml --resolve remote.yaml STDIN /dev/null IN . INTO result.txt EXPECTING 0

EXTRACT STDOUT FROM result.txt INTO bundled.json
EXTRACT STDOUT FROM result.txt INTO bundled.yaml

WRITE expected_0.txt UNTIL EOF
1> {
1> "$schema": "https://json-schema.org/draft/2020-12/schema",
1> "$id": "https://example.com",
1> "title": "Test",
1> "description": "Test schema",
1> "$ref": "nested",
1> "$defs": {
1> "https://example.com/nested": {
1> "$schema": "https://json-schema.org/draft/2020-12/schema",
1> "$id": "https://example.com/nested",
1> "title": "Test",
1> "description": "Test schema",
1> "type": "string"
1> }
1> }
1> }
1> $schema: https://json-schema.org/draft/2020-12/schema
1> $id: https://example.com
1> title: Test
1> description: Test schema
1> $ref: nested
1> $defs:
1> https://example.com/nested:
1> $schema: https://json-schema.org/draft/2020-12/schema
1> $id: https://example.com/nested
1> title: Test
1> description: Test schema
1> type: string
EOF

COMPARE result.txt AGAINST expected_0.txt

RUN fmt bundled.json --check STDIN /dev/null IN . INTO checked.txt EXPECTING 0
RUN fmt bundled.yaml --check STDIN /dev/null IN . INTO checked.txt EXPECTING 0

COMPARE checked.txt AGAINST silent.txt
26 changes: 26 additions & 0 deletions test/bundle/pass_stdin_yaml.clitest
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
WRITE input.yaml UNTIL EOF
$schema: https://json-schema.org/draft/2020-12/schema
$id: https://example.com
$ref: nested
EOF

WRITE remote.yaml UNTIL EOF
$schema: https://json-schema.org/draft/2020-12/schema
$id: https://example.com/nested
type: string
EOF

RUN bundle - --resolve remote.yaml STDIN input.yaml IN . INTO result.txt EXPECTING 0

WRITE expected.txt UNTIL EOF
1> $schema: https://json-schema.org/draft/2020-12/schema
1> $id: https://example.com
1> $ref: nested
1> $defs:
1> https://example.com/nested:
1> $schema: https://json-schema.org/draft/2020-12/schema
1> $id: https://example.com/nested
1> type: string
EOF

COMPARE result.txt AGAINST expected.txt
28 changes: 12 additions & 16 deletions test/bundle/pass_without_extension_yaml.clitest
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,23 @@ EOF

RUN bundle schema --resolve remote STDIN /dev/null IN . INTO result.txt EXPECTING 0

EXTRACT STDOUT FROM result.txt INTO bundled.json
EXTRACT STDOUT FROM result.txt INTO bundled.yaml

WRITE expected_0.txt UNTIL EOF
1> {
1> "$schema": "https://json-schema.org/draft/2020-12/schema",
1> "$id": "https://example.com",
1> "title": "Test",
1> "description": "Test schema",
1> "$ref": "nested",
1> "$defs": {
1> "https://example.com/nested": {
1> "$schema": "https://json-schema.org/draft/2020-12/schema",
1> "$id": "https://example.com/nested",
1> "type": "string"
1> }
1> }
1> }
1> $schema: https://json-schema.org/draft/2020-12/schema
1> $id: https://example.com
1> title: Test
1> description: Test schema
1> $ref: nested
1> $defs:
1> https://example.com/nested:
1> $schema: https://json-schema.org/draft/2020-12/schema
1> $id: https://example.com/nested
1> type: string
EOF

COMPARE result.txt AGAINST expected_0.txt

RUN fmt bundled.json --check STDIN /dev/null IN . INTO checked.txt EXPECTING 0
RUN fmt bundled.yaml --check STDIN /dev/null IN . INTO checked.txt EXPECTING 0

COMPARE checked.txt AGAINST silent.txt
Loading
Loading