@@ -140,14 +140,14 @@ auto sourcemeta::jsonschema::validate(const sourcemeta::core::Options &options)
140140 " jsonschema validate path/to/schema.json path/to/instance.json" };
141141 }
142142
143- if (options.positional ().size () < 2 ) {
144- throw PositionalArgumentError{
145- " In addition to the schema, you must also pass an argument\n "
146- " that represents the instance to validate against" ,
147- " jsonschema validate path/to/schema.json path/to/instance.json" };
143+ const auto &schema_path{options.positional ().at (0 )};
144+
145+ if (std::filesystem::is_directory (schema_path)) {
146+ throw std::filesystem::filesystem_error{
147+ " The input was supposed to be a file but it is a directory" ,
148+ schema_path, std::make_error_code (std::errc::is_a_directory)};
148149 }
149150
150- const auto &schema_path{options.positional ().at (0 )};
151151 const auto configuration_path{find_configuration (schema_path)};
152152 const auto &configuration{read_configuration (options, configuration_path)};
153153 const auto dialect{default_dialect (options, configuration)};
@@ -188,10 +188,40 @@ auto sourcemeta::jsonschema::validate(const sourcemeta::core::Options &options)
188188
189189 bool result{true };
190190
191- auto iterator{options.positional ().cbegin ()};
192- std::advance (iterator, 1 );
193- for (; iterator != options.positional ().cend (); ++iterator) {
194- const std::filesystem::path instance_path{*iterator};
191+ std::vector<std::string_view> instance_arguments;
192+ if (options.positional ().size () > 1 ) {
193+ instance_arguments.assign (options.positional ().cbegin () + 1 ,
194+ options.positional ().cend ());
195+ } else {
196+ instance_arguments.push_back (" ." );
197+ }
198+
199+ if (trace && instance_arguments.size () > 1 ) {
200+ throw std::runtime_error{
201+ " The `--trace/-t` option is only allowed given a single instance" };
202+ }
203+
204+ if (benchmark && instance_arguments.size () > 1 ) {
205+ throw std::runtime_error{
206+ " The `--benchmark/-b` option is only allowed given a single instance" };
207+ }
208+
209+ for (const auto &instance_path_view : instance_arguments) {
210+ const std::filesystem::path instance_path{instance_path_view};
211+ if (trace && instance_path.extension () == " .jsonl" ) {
212+ throw std::runtime_error{
213+ " The `--trace/-t` option is only allowed given a single instance" };
214+ }
215+
216+ if (trace && std::filesystem::is_directory (instance_path)) {
217+ throw std::runtime_error{
218+ " The `--trace/-t` option is only allowed given a single instance" };
219+ }
220+
221+ if (benchmark && std::filesystem::is_directory (instance_path)) {
222+ throw std::runtime_error{" The `--benchmark/-b` option is only allowed "
223+ " given a single instance" };
224+ }
195225 if (instance_path.extension () == " .jsonl" ) {
196226 LOG_VERBOSE (options)
197227 << " Interpreting input as JSONL: "
@@ -288,6 +318,51 @@ auto sourcemeta::jsonschema::validate(const sourcemeta::core::Options &options)
288318 if (index == 0 ) {
289319 sourcemeta::jsonschema::LOG_WARNING () << " The JSONL file is empty\n " ;
290320 }
321+ } else if (std::filesystem::is_directory (instance_path)) {
322+ for (const auto &entry : for_each_json ({instance_path_view}, options)) {
323+ std::ostringstream error;
324+ sourcemeta::blaze::SimpleOutput output{entry.second };
325+ bool subresult{true };
326+ if (fast_mode) {
327+ subresult = evaluator.validate (schema_template, entry.second );
328+ } else if (!json_output) {
329+ subresult = evaluator.validate (schema_template, entry.second ,
330+ std::ref (output));
331+ }
332+
333+ if (json_output) {
334+ std::cerr << entry.first .string () << " \n " ;
335+ const auto suboutput{sourcemeta::blaze::standard (
336+ evaluator, schema_template, entry.second ,
337+ fast_mode ? sourcemeta::blaze::StandardOutput::Flag
338+ : sourcemeta::blaze::StandardOutput::Basic,
339+ entry.positions )};
340+ assert (suboutput.is_object ());
341+ assert (suboutput.defines (" valid" ));
342+ assert (suboutput.at (" valid" ).is_boolean ());
343+ if (!suboutput.at (" valid" ).to_boolean ()) {
344+ result = false ;
345+ }
346+
347+ sourcemeta::core::prettify (suboutput, std::cout);
348+ std::cout << " \n " ;
349+ } else if (subresult) {
350+ LOG_VERBOSE (options)
351+ << " ok: "
352+ << sourcemeta::core::weakly_canonical (entry.first ).string ()
353+ << " \n matches "
354+ << sourcemeta::core::weakly_canonical (schema_path).string ()
355+ << " \n " ;
356+ print_annotations (output, options, entry.positions , std::cerr);
357+ } else {
358+ std::cerr << " fail: "
359+ << sourcemeta::core::weakly_canonical (entry.first ).string ()
360+ << " \n " ;
361+ std::cerr << error.str ();
362+ print (output, entry.positions , std::cerr);
363+ result = false ;
364+ }
365+ }
291366 } else {
292367 sourcemeta::core::PointerPositionTracker tracker;
293368 const auto instance{sourcemeta::core::read_yaml_or_json (
0 commit comments