v8r icon indicating copy to clipboard operation
v8r copied to clipboard

Check `$schema` key inside the document to know what schema to validate against

Open Zegnat opened this issue 9 months ago • 9 comments

Sometimes there are files where multiple schemas from the catalogue might match, e.g. a manifest.json file:

ℹ Processing ./src/manifest.json
ℹ Cache hit: using cached response from https://www.schemastore.org/api/json/catalog.json
ℹ Cache hit: using cached response from https://json.schemastore.org/schema-catalog.json
ℹ Searching for schema in https://www.schemastore.org/api/json/catalog.json ...
ℹ Found multiple possible matches for ./src/manifest.json. Possible matches:

  Foxx Manifest
  ArangoDB Foxx service manifest file
  https://json.schemastore.org/foxx-manifest.json

  UI5 Manifest
  UI5 Manifest (manifest.json)
  https://raw.githubusercontent.com/SAP/ui5-manifest/master/schema.json

  WebExtensions
  WebExtension manifest files
  https://json.schemastore.org/webextension.json

  Web App Manifest
  Web Application manifest file
  https://json.schemastore.org/web-manifest-combined.json

✖ Found multiple possible schemas to validate ./src/manifest.json

As I also depend on JSON schemas when editing these type of files, I often supply a specific $schema within the file so VSCode can manage. See the following screenshots showing how VSCode is warning me about all the keys before I add $schema:

Screenshot of VSCode showing the first three lines of a web extension manifest JSON file, all JSON members have yellow squigly lines because of warnings.

Screenshot of VSCode showing the same three lines of a web extension manifest JSON file with an explicit schema link prepended., all JSON members have yellow squigly lines because of warnings.

  1. Can v8r break ties based on the $schema member?
  2. Should v8r go as far as to prefer the explicit $schema member over the catalogue?

In case of 2, it could save the entire round trip to schemastore.org. If all files in a repository include $schema it will not need to check a catalogue at all.

Zegnat avatar Mar 02 '25 16:03 Zegnat

As an aside to this, it would be really nice if $schema was allowed by the v8r config schema. This would then allow the schema to be used by the code editor by doing something like the following:

{
    "$schema": "./node_modules/v8r/config-schema.json",
    "customCatalog": {
        "schemas": [
            {
                "name": "JSON schema for WebExtensions manifest files",
                "fileMatch": [
                    "manifest.json"
                ],
                "location": "https://json.schemastore.org/webextension.json"
            }
        ]
    }
}

Currently this cannot be done as v8r (correctly) validates its config file before using it, leading to an additional properties error because of $schema:

/Users/Zegnat/path/.v8rrc.json# must NOT have additional properties

Zegnat avatar Mar 02 '25 17:03 Zegnat

If you've got files where SchemaStore doesn't know how to validate them, you can use a custom catalog to tell v8r which schemas to use for which files. This can either be a standalone catalog https://chris48s.github.io/v8r/usage-examples/#using-a-custom-catlog or you can do it in the config file https://chris48s.github.io/v8r/configuration/ So there is a way to solve the case where there are multiple possible matches in schemastore.

This idea of files that contain a $schema key has come up once before a few years ago in https://github.com/chris48s/v8r/pull/129 I asked some follow up questions but the original poster never responded so it never went anywhere. Maybe you have some info on how widespread this is or resources I could look at.

chris48s avatar Mar 03 '25 17:03 chris48s

Thanks for linking the closed PR. I had looked through the repo before, but clearly still managed to somehow miss that one.

I am not sure how wide-spread the usage is. Like I described above, I mostly do it because it makes VSCode’s linting work and delivers auto-complete. It would not surprise me if this is how most people use it, which might be hard to track.

I will do some discovery work this weekend and see if I can find any projects that explicitly use or call out the use of $schema and then report back. Probably better to have this as an issue for discussing than immediately jump to a PR.

Zegnat avatar Mar 05 '25 18:03 Zegnat

After reading into this more, I think the use of $schema as a property on non-schema documents does not have a very clear origin. Or at least I have not been able to find one. It is definitely not something that came from the JSON Schema specifications. As such, I am now less inclined to push for v8r to make special concessions for it.

Mostly people discuss it in combination with talk of their IDEs helping through auto-complete / intellisense. And here it might have been Microsoft that has been pushing this convention the most. Back in 2014 they already added $schema for Visual Studio 2013, before Visual Studio Code (VSCode) had even launched. So it is not surprising that Microsoft also maintains the JSON language server within VSCode and the “smarts behind” it to follow the convention that they have set.

The VSCode documentation for JSON schemas and settings still recommends mapping a schema with a $schema key in the JSON. But it also offers a few other ways to configure the IDE through settings files.

As these settings files allow for schemas to be defined with a fileMatch array of globs as well as a url property, it might actually be possible to use the VSCode settings as custom catalogues after a little pre-processing. That will be my next focus. I would prefer not to have to create both a custom Schema Catalog and duplicate that data within my VSCode settings file.

Although I would personally still like to see config-schema.json expanded to explicitly allow a $schema property in the same way the schema for JSON Catalogs does. Just so it allows people who like the convention to use it.

Zegnat avatar Mar 09 '25 17:03 Zegnat

Sharing my current solution here, to see if people have other ideas.

I have a .vscode/settings.json file that defines the schema for my WebExtensions manifest (an example JSON file where multiple schemas would otherwise match):

{
	"json.schemas": [
		{
			"fileMatch": ["src/manifest.json"],
			"url": "https://json.schemastore.org/webextension.json"
		}
	]
}

I also have a .v8rrc.json file that makes sure I validate all JSON files in my project that are not something I do not control:

{
	"patterns": ["./!(package-lock)*.json", "./!(node_modules|.vscode)/**/*.json"]
}

My package.json includes a script to lint (validate) all my JSON files with v8r:

{
	"scripts": {
		"lint": "run-p --print-label --continue-on-error lint:**",
		"lint:json": "bash v8r.sh"
	}
}

Previously this script would just run v8r, but now I am using a bash script to make sure the schemas I define within .vscode/settings.json are picked up as an alternative catalogue:

#!/usr/bin/env bash

tempfile=$(mktemp)
jq '{
	"$schema": "https://json.schemastore.org/schema-catalog.json",
	"version": 1,
	"schemas": [."json.schemas"[] | . + { "name": .url, "description": .url }]
}' ./.vscode/settings.json >"$tempfile"

if [ -f "$tempfile" ]; then
	npm exec -- v8r -c "$tempfile"
	rm "$tempfile"
else
	echo "Error: Failed to create temporary file."
	exit 1
fi

I am not sure if I really like going via Bash and jq. It is a very light shell script, but it does introduce some dependencies outside of the npm ecosystem and put some minor portability constraints on the repository. For now I will be using this to see how I like it, as it ticks all the boxes:

  1. No need for $schema in documents that do not support it, depend on VSCode’s own settings.
  2. Able to validate all JSON documents in the repository, based on schemas VSCode know about.
  3. No repitition of settings.

Zegnat avatar Mar 10 '25 17:03 Zegnat

I was looking for this exact question myself, @Zegnat . Thank you for mentioning the custom catalog approach -- I wouldn't have thought about that.

My use-case is that I'm writing a plugin for MegaLinter and I would like to be able to validate the YAML plugin configuration file. I, too, was thinking about a $schema approach in the plugin file; as it is, I'm currently using v8r -s "https://url/to.the/JSON.schema" "./file-to-validate.yml" approach and that's working just fine.

As an alternative to the configuration / catalog approach, my other thought was to include a test file that would run the above command.

Thank you for your feedback, @chris48s . It's very helpful!

wesley-dean avatar Mar 13 '25 14:03 wesley-dean

Minor update on this, which is v8r 4.3.0 no longer rejects config files containing a $schema property

chris48s avatar Apr 21 '25 11:04 chris48s

Nice update, this means I can make use of the language server features of VSCode for the v8r config file! Thank you for considering this.

Screenshot: code completion pop-up within a .v8rrc.json file.

Zegnat avatar May 08 '25 15:05 Zegnat

I am also interested using this. I have been decorating all of my yaml files for my k8s repo with the schema that I want to validate the files against.

putz612 avatar Oct 02 '25 14:10 putz612