%%%============================================================================= %% Copyright 2012- Klarna AB %% Copyright 2015- AUTHORS %% Copyright 2023- Shiguredo Inc. %% %% 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. %% %% @doc JESSE (JSon Schema Erlang) %% %% This is an interface module which provides an access to the main %% functionality of jesse, such as 1) updating of the schema definitions cache; %% 2) validation json data against a schema. %% @end %%%============================================================================= %%%_* Module declaration ======================================================= -module(jesse_cli). %%%_* Exports ================================================================== %% API -export([main/1]). %%%_* API ====================================================================== -include("jesse_schema_validator.hrl"). main([]) -> main(["--help"]); main(["-h"]) -> main(["--help"]); main(["--help"]) -> io:fwrite("Usage: ~s [--json] [path_to_json_schema] path_to_json_schema -- " "path_to_json_instance [path_to_json_instance] ~n", [escript:script_name()]); main(Options) -> main(Options, [], [], []). main(["--json" | Rest], Options, [], []) -> main(Rest, Options ++ [{json, true}], [], []); main(["--" | JsonInstances], Options, Schemata, []) -> run(Options, Schemata, JsonInstances); main([Schema | Rest], Options, Schemata, []) -> main(Rest, Options, [Schema | Schemata], []). %%%_* Internal ================================================================= run(_Options, _Schemata, []) -> ok; run(Options, [Schema | _] = Schemata, [JsonInstance | JsonInstances]) -> JesseResult = jesse_run(JsonInstance, Schema, Schemata), Result = case JesseResult of {ok, _} -> [{filename, list_to_binary(JsonInstance)}, {result, ok}]; {error, Reasons} -> JsxReasons = lists:map(fun jesse_error:reason_to_jsone/1, Reasons), [{filename, list_to_binary(JsonInstance)}, {result, error}, {errors, JsxReasons}] end, case proplists:get_value(json, Options) of undefined -> io:fwrite("~p\n\n", [Result]); true -> io:fwrite("~s\n\n", [jsone:encode(Result)]) end, case JesseResult of {ok, _} -> run(Options, Schemata, JsonInstances); _ -> %% init:stop not setting status code correctly %% init:stop(1) halt(1) end. jesse_run(JsonInstance, Schema, Schemata) -> {ok, _} = application:ensure_all_started(jesse), ok = add_schemata(Schemata), {ok, JsonInstanceBinary} = file:read_file(JsonInstance), JsonInstanceJsx = jsone:decode(JsonInstanceBinary, [{object_format, proplist}]), jesse:validate(Schema, JsonInstanceJsx). add_schemata([]) -> ok; add_schemata([SchemaFile | Rest]) -> {ok, SchemaBin} = file:read_file(SchemaFile), Schema0 = jsone:decode(SchemaBin, [{object_format, proplist}]), Schema = maybe_fill_schema_id(SchemaFile, Schema0), ok = jesse:add_schema(SchemaFile, Schema), add_schemata(Rest). maybe_fill_schema_id(SchemaFile, Schema) -> SchemaFqdn = "file://" ++ filename:absname(SchemaFile), Version = jesse_json_path:value(<<"$schema">>, Schema, undefined), Id = jesse_lib:get_schema_id(Schema), case {Version, Id} of {?JSON_SCHEMA_DRAFT6, undefined} -> [{?ID, unicode:characters_to_binary(SchemaFqdn)} | Schema]; {_, undefined} -> [{?ID_OLD, unicode:characters_to_binary(SchemaFqdn)} | Schema]; _ -> Schema end.