{"id":13783860,"url":"https://github.com/ssilverman/snowy-json","last_synced_at":"2026-04-07T19:31:11.811Z","repository":{"id":39936345,"uuid":"266730412","full_name":"ssilverman/snowy-json","owner":"ssilverman","description":"Snow, a full-featured JSON Schema validator","archived":false,"fork":false,"pushed_at":"2024-06-21T15:07:36.000Z","size":768,"stargazers_count":55,"open_issues_count":6,"forks_count":4,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-09-14T13:32:15.311Z","etag":null,"topics":["json-schema","json-schema-validator","json-validator","linter","validator"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ssilverman.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-05-25T08:52:29.000Z","updated_at":"2025-06-01T11:03:01.000Z","dependencies_parsed_at":"2024-08-03T19:02:13.474Z","dependency_job_id":null,"html_url":"https://github.com/ssilverman/snowy-json","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/ssilverman/snowy-json","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssilverman%2Fsnowy-json","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssilverman%2Fsnowy-json/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssilverman%2Fsnowy-json/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssilverman%2Fsnowy-json/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ssilverman","download_url":"https://codeload.github.com/ssilverman/snowy-json/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssilverman%2Fsnowy-json/sbom","scorecard":{"id":844754,"data":{"date":"2025-08-11","repo":{"name":"github.com/ssilverman/snowy-json","commit":"b4a2dcc4274322a09f8409176d675918b4e9321a"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.2,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: GNU Affero General Public License v3.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":8,"reason":"2 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-4jrv-ppp4-jm57","Warn: Project is vulnerable to: GHSA-v2xm-76pq-phcf"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-23T21:10:52.808Z","repository_id":39936345,"created_at":"2025-08-23T21:10:52.809Z","updated_at":"2025-08-23T21:10:52.809Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31526665,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-07T16:28:08.000Z","status":"ssl_error","status_checked_at":"2026-04-07T16:28:06.951Z","response_time":105,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["json-schema","json-schema-validator","json-validator","linter","validator"],"created_at":"2024-08-03T19:00:31.989Z","updated_at":"2026-04-07T19:31:11.793Z","avatar_url":"https://github.com/ssilverman.png","language":"Java","readme":"\u003ca href=\"https://www.buymeacoffee.com/ssilverman\" title=\"Donate to this project using Buy Me A Coffee\"\u003e\u003cimg src=\"https://img.shields.io/badge/buy%20me%20a%20coffee-donate-orange.svg\" alt=\"Buy Me A Coffee donate button\"\u003e\u003c/a\u003e\n\n# Snow, a JSON Schema Validator\n\nVersion: 0.16.0\n\nThe main goal of this project is to be a reference JSON Schema validator. While\nit provides a few working applications, it's meant primarily as an API for\nbuilding your own toolset.\n\nSee: [JSON Schema](https://json-schema.org)\n\n## Table of contents\n\n1. [Features](#features)\n   1. [Additional features](#additional-features)\n2. [Quick start](#quick-start)\n3. [Under the covers](#under-the-covers)\n4. [Limitations](#limitations)\n5. [Which specification is used for processing?](#which-specification-is-used-for-processing)\n6. [Options for controlling behaviour](#options-for-controlling-behaviour)\n   1. [AUTO_RESOLVE](#option-auto_resolve)\n   2. [COLLECT_ANNOTATIONS_FOR_FAILED](#option-collect_annotations_for_failed)\n   3. [CONTENT](#option-content)\n   4. [DEFAULT_SPECIFICATION](#option-default_specification)\n   5. [FORMAT](#option-format)\n   6. [SPECIFICATION](#option-specification)\n7. [Project structure](#project-structure)\n   1. [Module information](#module-information)\n   2. [Complete programs](#complete-programs)\n   3. [API](#api)\n      1. [Annotations and errors](#annotations-and-errors)\n      2. [Internal APIs](#internal-apis)\n8. [Building and running](#building-and-running)\n   1. [Program execution with Maven](#program-execution-with-maven)\n   2. [Using Snow in your own projects](#using-snow-in-your-own-projects)\n9. [The linter](#the-linter)\n   1. [Doing your own linting](#doing-your-own-linting)\n      1. [Linting by traversing the tree](#linting-by-traversing-the-tree)\n10. [The coverage checker](#the-coverage-checker)\n11. [Future plans](#future-plans)\n    1. [Possible future plans](#possible-future-plans)\n12. [References](#references)\n13. [An ending thought](#an-ending-thought)\n14. [Acknowledgements](#acknowledgements)\n15. [License](#license)\n\n## Features\n\nThis project has the following features:\n\n1. Full support for all drafts since Draft-06.\n2. Full \"format\" validation support, with a few platform-specific exceptions.\n3. Full annotation and error support.\n   1. There is enough information to provide full output support. The calling\n      app has to sort through and format what it wants, however.\n4. Written for correctness. This aims to be a reference implementation.\n5. Can initialize with known URIs. These can be any of:\n   1. Parsed JSON objects.\n   2. URLs. The URLs can be anything, including filesystem locations, web\n      resources, and other objects. \"URL\" here means that the system knows how\n      to retrieve something vs. \"URI\", which is just an ID.\n6. Options for controlling \"format\" validation, annotation collection, error\n   collection, and default and non-default specification choice.\n7. There's rudimentary infinite loop detection, but only if error or annotation\n   collection is enabled. It works by detecting that a previous keyword has been\n   applied to the same instance location.\n8. Specification detection heuristics for when there's no $schema declared.\n9. Content validation support for the \"base64\" encoding and \"application/json\"\n   media type.\n\n### Additional features\n\nThese additional features exist:\n\n1. A rudimentary linter that catches simple but common errors.\n2. A coverage tool.\n\n## Quick start\n\nThere are more details below, but here are four commands that will get you\nstarted right away:\n\n1. Run the validator on an instance against a schema:\n   ```bash\n   mvn compile exec:java@main -Dexec.args=\"schema.json instance.json\"\n   ```\n   The two files in this example are named `schema.json` for the schema and\n   `instance.json` for the instance. The example assumes the files are in the\n   current working directory.\n2. Clone and then run the test suite:\n   ```bash\n   mvn compile exec:java@test -Dexec.args=\"/suites/json-schema-test-suite\"\n   ```\n   This assumes that the test suite is in `/suites/json-schema-test-suite`.\n   Yours may be in a different location. The test suite can be cloned from\n   [JSON Schema Test Suite](https://github.com/json-schema-org/JSON-Schema-Test-Suite).\n3. Run the linter on a schema:\n   ```bash\n   mvn compile exec:java@linter -Dexec.args=\"schema.json\"\n   ```\n   The schema file in this example is named `schema.json`. The example assumes\n   the file is in the current working directory.\n4. Run the schema coverage checker after a validation:\n   ```bash\n   mvn compile exec:java@coverage -Dexec.args=\"schema.json instance.json\"\n   ```\n   The two files in this example are named `schema.json` for the schema and\n   `instance.json` for the instance. The example assumes the files are in the\n   current working directory.\n\n## Under the covers\n\nThis project uses Google's [Gson](https://github.com/google/gson) library under\nthe hood for JSON parsing.\n[ClassGraph](https://github.com/classgraph/classgraph) is used to support\nclass finding.\n\nThis means these things:\n1. The external API for this project uses Gson's JSON object model.\n\n## Limitations\n\nThis project follows just about everything it can from the latest JSON Schema\nspecification draft. There are a few things it does slightly differently due to\nsome implementation details.\n\n1. Regular expressions allow or disallow some things that\n   [ECMA 262](https://www.ecma-international.org/publications/standards/Ecma-262.htm)\n   regular expressions do not. For example, Java allows the `\\Z` boundary\n   matcher but ECMA 262 does not.\n\n## Which specification is used for processing?\n\nThere are a few ways the validator determines which specification to use when\nprocessing and validating a schema. The steps are as follows:\n\n1. $schema value. If the schema explicitly specifies this value, and if it is\n   known by the validator, then this is the specification that the validator\n   will use.\n2. The `SPECIFICATION` option or any default.\n3. Guessed by heuristics.\n4. The `DEFAULT_SPECIFICATION` option or any default.\n5. Not known.\n\n## Options for controlling behaviour\n\nThis section describes options that control the validator behaviour.\n\nAll options are defined in the `com.qindesign.json.schema.Option` class, and\ntheir use is in `com.qindesign.json.schema.Options`.\n\nSome options are specification-specific, meaning they have different defaults\ndepending on which specification is applied. Everything else works as expected:\nusers set or remove options. It is only the internal defaults that have any\nspecification-specific meanings.\n\nThere are two ways to retrieve an option. Both are similar, except one of the\nways checks the specification-specific defaults before the\nnon-specification-specific defaults. The steps are as follows, where subsequent\nsteps are followed only if the current step is not successful.\n\nSpecification-specific consultation steps, using a specific specification:\n\n1. Options set by the user.\n2. Specification-specific defaults.\n3. Non-specification-specific defaults.\n4. Not found.\n\nNon-specification-specific consultation steps:\n\n1. Options set by the user.\n2. Non-specification-specific defaults.\n3. Not found.\n\n### Option: AUTO_RESOLVE\n\nType: `java.lang.Boolean`\n\nThis controls whether the validator should attempt auto-resolution when\nsearching for schemas or when otherwise resolving IDs. This entails adding the\noriginal base URI and any root $id as known URLs during validation.\n\n### Option: COLLECT_ANNOTATIONS_FOR_FAILED\n\nType: `java.lang.Boolean`\n\nThis controls, if annotations are collected, whether they should also be\nretained for failed schemas. This option only has an effect when annotations are\nbeing collected.\n\n### Option: CONTENT\n\nType: `java.lang.Boolean`\n\nThis controls whether to treat the \"content\" values as assertions in Draft-07.\nThis only includes \"contentEncoding\" and \"contentMediaType\".\n\n### Option: DEFAULT_SPECIFICATION\n\nType: `com.qindesign.json.schema.Specification`\n\nThis option specifies the default specification to follow if one cannot be\ndetermined from a schema, either by an explicit indication, or by heuristics.\nThis is the final fallback specification.\n\n### Option: FORMAT\n\nType: `java.lang.Boolean`\n\nThis is a specification-specific option meaning its default is different\ndepending on which specification is being used. It controls whether to treat\n\"format\" values as assertions.\n\n### Option: SPECIFICATION\n\nType: `com.qindesign.json.schema.Specification`\n\nThis indicates which specification to use if one is not explicitly stated in\na schema.\n\n## Project structure\n\nThis project is designed to provide APIs and tools for performing JSON Schema\nvalidation. Its main purpose is to do most of the work, but have the user wire\nin everything themselves. A few rudimentary and runnable test programs are\nprovided, however.\n\nThe main package is `com.qindesign.json.schema`.\n\n### Module information\n\nThis project defines a module and exports these packages:\n1. `com.qindesign.json.schema`: This is the main validation package.\n2. `com.qindesign.json.schema.net`: Provides some URI and hostname\n   processing tools.\n\nIt also transitively requires this package:\n1. `com.google.gson`\n\n### Complete programs\n\nThe first program is `Main`. This takes two arguments, a schema file and an\ninstance file, and then performs validation of the instance against the schema.\n\nThe second program is `Test`. This takes one argument, a directory containing\nthe JSON Schema test suite, and then runs all the tests in the suite. You can\nobtain a copy of the test suite by cloning the\n[test suite repository](https://github.com/json-schema-org/JSON-Schema-Test-Suite).\n\nThe third program is `Linter`, a rudimentary linter for JSON Schema files. It\ntakes one argument, the schema file to check.\n\nThe fouth program is `Coverage`, a simple coverage tool for JSON Schemas and\ninstances. It's similar to `Main`, but prints different output.\n\n### API\n\nThe main entry point to the API is the `Validator` constructor and `validate`\nmethod. In addition to the non-optional schema, instance, and base URI, you can\npass options, known IDs and URLs, and a place to put collected annotations and\nerrors.\n\nIn this version, the caller must organize the errors into the desired output\nformat. An example of how to convert them into the Basic output format is in\nthe `Main.basicOutput` method.\n\nProviding tools to format the errors into more output formats may happen in\nthe future.\n\n#### Annotations and errors\n\nAnnotations and errors are collected by optionally providing maps to\n`Validator.validate`. They're maps from instance locations to an associated\n`Annotation` object, with some intervening values.\n\n* The annotations map follows this structure: instance location \u0026rarr; name\n  \u0026rarr; schema location \u0026rarr; `Annotation`. The `Annotation` value is\n  dependent on the source of the annotation.\n* The errors map has this structure: instance location \u0026rarr; schema location\n  \u0026rarr; `Annotation`. The `Annotation` value is a `ValidationResult` object,\n  and its name will be \"error\" when the result is `false` and \"annotation\" when\n  the result is `true`.\n\nFor annotations, `Annotation.isValid()` indicates whether the annotation is\nconsidered valid or auxiliary. When\n[failed annotations](#option-collect_annotations_for_failed) are collected,\ninvalid annotations indicate an annotation that would otherwise exist if the\nassociated schema had not failed.\n\nFor errors, `Error.isPruned()` means that the result is not relevant to the\nschema result. For example, \"oneOf\" will pass validation if one subschema passes\nand all the other subschemas fail. All failing subschemas will indicate an\nerror, but it will be marked as _pruned_.\n\nThis is useful to track coverage vs. a minimal set of useful errors.\n\nThe `Results` class provides some tools for sorting and collecting annotations\nand errors. It does the work of extracting a list of useful results.\n\nThe locations are given as\n[JSON Pointers](https://www.rfc-editor.org/rfc/rfc6901.html).\n\nThe annotation types for specific keywords are as follows:\n* \"additionalItems\": `java.lang.Boolean`, always `true` if present, indicating\n  that the subschema was applied to all remaining items in the instance array.\n* \"additionalProperties\": `java.util.Set\u003cString\u003e`, the set of property names\n  whose contents were validated by this subschema.\n* \"contentEncoding\": `java.lang.String`\n* \"contentMediaType\": `java.lang.String`\n* \"contentSchema\": `com.google.gson.JsonElement`\n* \"default\": `com.google.gson.JsonElement`\n* \"deprecated\": `java.lang.Boolean`\n* \"description\": `java.lang.String`\n* \"examples\": `com.google.gson.JsonArray`\n* \"format\": `java.lang.String`\n* \"items\": `java.lang.Integer`, the largest index in the instance to which a\n  subschema was applied, or `java.lang.Boolean` (always `true`) if a subschema\n  was applied to every index.\n* \"patternProperties\": `java.util.Set\u003cString\u003e`, the set of property names\n  matched by this keyword.\n* \"properties\": `java.util.Set\u003cString\u003e`, the set of property names matched by\n  this keyword.\n* \"readOnly\": `java.lang.Boolean`\n* \"title\": `java.lang.String`\n* \"unevaluatedItems\": `java.lang.Boolean`, always `true` if present, indicating\n  that the subschema was applied to all remaining items in the instance array.\n* \"unevaluatedProperties\": `java.util.Set\u003cString\u003e`, the set of property names\n  whose contents were validated by this subschema.\n* \"writeOnly\": `java.lang.Boolean`\n\n#### Internal APIs\n\nThere are a few internal APIs that may be useful for your own projects, outside\nof schema validation. Note that these are subject to change.\n\n1. `com.qindesign.json.schema.util.Base64InputStream`: Converts a Base64-encoded\n   string into a byte stream.\n2. `com.qindesign.json.schema.util.LRUCache`: An\n   [LRU cache](https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU))\n   implementation.\n3. `com.qindesign.json.schema.net.Hostname`: Parses regular and IDN hostnames.\n4. `com.qindesign.json.schema.net.URI`: An\n   [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986.html)-compliant URI parser.\n   As of this writing, Java's URI API is only RFC 2396-compliant and is not\n   sufficient for processing JSON Schemas.\n5. `com.qindesign.json.schema.net.URIParser.parseIPv6`: Parses IPv6 addresses,\n   per RFC 3986.\n6. `com.qindesign.json.schema.net.URIParser.parseIPv4`: Parses IPv4 addresses,\n   per RFC 3986.\n\nPlease consult the Javadocs for those classes and methods for more information.\n\n## Building and running\n\nThis project uses Maven as its build tool because it makes managing the\ndependencies easy. It uses standard Maven commands and phases. For example, to\ncompile the project, use:\n\n```bash\nmvn compile\n```\n\nTo clean and then re-compile:\n\n```bash\nmvn clean compile\n```\n\nMaven makes it easy to build, execute, and package everything with the right\ndependencies, however it's also possible to use your IDE or different tools\nto manage the project.  This section only discusses Maven usage.\n\n### Program execution with Maven\n\nMaven takes care of project dependencies for you so you don't have to manage the\nclasspath or downloads.\n\nCurrently, there are four predefined execution targets:\n1. `main`: Executes `Main`. Validates an instance against a schema.\n2. `test`: Executes `Test`. Runs the test suite.\n3. `linter`: Executes `Linter`. Checks a schema.\n4. `coverage`: Executes `Coverage`. Does a schema coverage check\n   after validation.\n\nThis section shows some simple execution examples. There's more information\nabout the included programs below.\n\nNote that Maven doesn't automatically build the project when running an\nexecution target. It either has to be pre-built using `compile` or added to the\ncommand line. For example, to compile and then run the linter:\n\n```bash\nmvn compile exec:java@linter -Dexec.args=\"schema.json\"\n```\n\nTo run the main validator without attempting a compile first, say because it's\nalready built:\n\n```bash\nmvn exec:java@main -Dexec.args=\"schema.json instance.json\"\n```\n\nTo compile and run the test suite and tell the test runner that the suite is\nin `/suites/json-schema-test-suite`:\n\n```bash\nmvn compile exec:java@test -Dexec.args=\"/suites/json-schema-test-suite\"\n```\n\nTo execute a specific main class, say one that isn't defined as a specific\nexecution, add an `exec.mainClass` property. For example, if the fully-qualified\nmain class is `my.Main` and it takes some \"program arguments\":\n\n```bash\nmvn exec:java -Dexec.mainClass=\"my.Main\" -Dexec.args=\"program arguments\"\n```\n\n### Using Snow in your own projects\n\nSnow is available from the Maven Central Repository. To include it in your own\nprograms, add the following dependency:\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.qindesign\u003c/groupId\u003e\n  \u003cartifactId\u003esnowy-json\u003c/artifactId\u003e\n  \u003cversion\u003e0.15.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## The linter\n\nThe linter's job is to provide suggestions about potential errors in a schema.\nIt shows only potential problems whose presence does not necessarily mean the\nschema won't work.\n\nThe linter is rudimentary and does not check or validate everything about the\nschema. It does currently check for the following things:\n\n1. Unknown `format` values.\n2. Empty `items` arrays.\n3. `additionalItems` without a sibling array-form `items`.\n4. `$schema` elements inside a subschema that do not have a sibling `$id`.\n5. Unknown keywords. Similar keywords are noted by doing case-insensitive\n   matching to known keywords.\n6. Property names that start with \"$\".\n7. Unnormalized `$id` values.\n8. Locally-pointing `$ref` values that don't exist.\n9. Any \"minimum\" keyword that is greater than its corresponding \"maximum\"\n   keyword. For example, `minLength` and `maxLength`.\n10. `exclusiveMinimum` is not strictly less than `exclusiveMaximum`.\n11. Expected type checking for appropriate keywords. For example, `minimum`\n    expects that the type is \"number\" or \"integer\" and `format` expects a\n    \"string\" type.\n12. Implied type checking for `default` and `const`; a type is expected to\n    exist and to match the implied type for these values.\n13. Non-unique `enum`s.\n14. Empty `enum`, `allOf`, `anyOf`, or `oneOf`.\n15. Draft 2019-09 or later schemas having keywords that were removed in\n    Draft 2019-09.\n16. Pre-Draft 2019-09 schemas having keywords that were added in Draft 2019-09.\n17. Pre-Draft-07 schemas having keywords that were added in Draft-07.\n18. Draft 2019-09 or later, or unspecified, schemas:\n    1. `minContains` without a sibling `contains`.\n    2. `maxContains` without a sibling `contains`.\n    3. `unevaluatedItems` without a sibling array-form `items`.\n    4. `$id` values that have an empty fragment.\n19. Draft-07 or later, or unspecified, schemas:\n    1. `then` without `if`.\n    2. `else` without `if`.\n20. Draft-07 or earlier schemas:\n    1. `$ref` members with siblings.\n\n### Doing your own linting\n\nIt's possible to add your own rules to the linter. There are four important\nconcepts to know about when adding rules:\n1. A rule may optionally be assigned to execute for a specific element type. For\n   example, a rule added via `Linter.addStringRule` will execute if the current\n   element is a primitive string.\n2. A rule learns about the current state of the JSON tree from a context object\n   parameter, an instance of `Linter.Context`.\n3. Any detected issues are sent to the context.\n4. The rules operate in addition to the existing linter rules.\n\nThe following example snippet tests for the existence of any \"anyOf\"\nschema keywords:\n\n```java\nJsonElement schema;\n// ...load the schema...\nLinter linter = new Linter();\nlinter.addRule(context -\u003e {\n  if (context.isKeyword() \u0026\u0026 context.is(\"anyOf\")) {\n    context.addIssue(\"anyOf detected\");\n  }\n});\nMap\u003cJSONPath, List\u003cString\u003e\u003e issues = linter.check();\n// ...print the issues...\n```\n\n#### Linting by traversing the tree\n\nThe `JSON` class has a `traverseSchema` method that does a preorder tree\ntraversal for JSON schemas. It's what the linter uses internally. It's also\npossible to use this to write your own linting rules.\n\nThe following example snippet also tests for the existence of any \"anyOf\"\nschema keywords:\n\n```java\nJsonElement schema;\n// ...load the schema...\nJSON.traverseSchema(schema, (e, parent, path, state) -\u003e {\n  if (!state.isNotKeyword() \u0026\u0026 path.endsWith(\"anyOf\")) {\n    System.out.println(path + \": anyOf keyword present\");\n  }\n});\n```\n\n## The coverage checker\n\nThe coverage checker works similarly to the main validator, except that after\nvalidation, it prints out some coverage results.\n\nIt outputs two JSON objects:\n1. Seen and unseen schema locations organized by instance location.\n2. Seen schema locations only.\n\n## Future plans\n\nThere are plans to explore supporting more features, including:\n\n1. Custom vocabulary support.\n2. More output formatting. All the information is currently there, but the\n   caller must process and organize it.\n3. Better caching. The current implementation doesn't cache things such as URLs\n   and regex Patterns across different instances of `ValidatorContext`, i.e.\n   across calls to `Validator.validate`.\n4. Compilation into an internal representation that provides both speed and\n   optimizations for non-dynamic validation paths.\n5. A better representation than maps for annotations and errors.\n6. A better way of filtering (i.e. organizing) errors and annotations for human\n   consumption. For example, not needing to manually prune parent errors. A more\n   fleshed-out way to identify terminal and non-terminal errors, and also which\n   are important.\n\n### Possible future plans\n\nThese are plans that may or may not be explored:\n\n1. Linter rule IDs for selective linting.\n\n## References\n\n1. [JSON Schema Specification](https://json-schema.org/specification.html)\n2. [Gson](https://github.com/google/gson)\n3. [ClassGraph](https://github.com/classgraph/classgraph)\n4. [ECMA 262](https://www.ecma-international.org/publications/standards/Ecma-262.htm)\n5. [JSON Schema Test Suite](https://github.com/json-schema-org/JSON-Schema-Test-Suite)\n6. [JSON Schema Draft Sources](https://github.com/json-schema-org/json-schema-spec)\n7. [JSON Pointer](https://www.rfc-editor.org/rfc/rfc6901.html)\n8. [URI Syntax](https://www.rfc-editor.org/rfc/rfc3986.html)\n9. [IDN Hostnames](https://www.rfc-editor.org/rfc/rfc5890.html)\n\n## An ending thought\n\nI'd love to say this: \"The validator isn't wrong, the spec is ambiguous.\"™ \\\nRealistic? No, but fun to say anyway.\n\n## Acknowledgements\n\nThanks to\n\u003ca href=\"https://www.jetbrains.com/?from=Snow\"\u003eJetBrains\u003c/a\u003e for providing an\nOpen Source licence for IntelliJ, my favourite IDE since forever.\n\n## License\n\n```\nSnow, a JSON Schema validator\nCopyright (c) 2020-2021  Shawn Silverman\n\nThis program is free software: you can redistribute it and/or modify\nit under the terms of the GNU Affero General Public License as published\nby the Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU Affero General Public License for more details.\n\nYou should have received a copy of the GNU Affero General Public License\nalong with this program.  If not, see \u003chttps://www.gnu.org/licenses/\u003e.\n```\n\n---\nCopyright (c) 2020-2021 Shawn Silverman\n","funding_links":["https://www.buymeacoffee.com/ssilverman"],"categories":["Who Uses the Test Suite","\u003ca name=\"Java\"\u003e\u003c/a\u003eJava"],"sub_categories":["Java"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fssilverman%2Fsnowy-json","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fssilverman%2Fsnowy-json","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fssilverman%2Fsnowy-json/lists"}