In VS Code, how can I get JSON intellisense based on the files in a given directory? - intellisense

My application includes JSON Files.
One JSON property common to all JSON files in my app is "type".
The value of the type property must be the file name of any handlebars (.hbs) file in my /templates/ directory.
My goal is to get intellisense as I type the value for a given "type" property in a JSON file. The intellisense should include a list of all handlebars file names in the /templates/ directory. Either an automatic solution, or one where I provide a list of values would be great.
Is there a way in the VS Code config or with TypeScript to make that happen?

You can add a JSON schema to you workspace settings.json in .vscode directory.
This is an example that adds intellisense to package.json for ghooks settings:
"json.schemas": [
{
"fileMatch": [
"/package.json"
],
"schema": {
"type": "object",
"properties": {
"config": {
"properties": {
"ghooks": {
"type": "object",
"description": "Git hook configurations",
"properties": {
"applypatch-msg": {
"type": "string"
},
"pre-applypatch": {
"type": "string"
},
"post-applypatch": {
"type": "string"
},
"pre-commit": {
"type": "string"
},
"prepare-commit-msg": {
"type": "string"
},
"commit-msg": {
"type": "string"
},
"post-commit": {
"type": "string"
},
"pre-rebase": {
"type": "string"
},
"post-checkout": {
"type": "string"
},
"post-merge": {
"type": "string"
},
"pre-push": {
"type": "string"
},
"pre-receive": {
"type": "string"
},
"update": {
"type": "string"
},
"post-receive": {
"type": "string"
},
"post-update": {
"type": "string"
},
"pre-auto-gc": {
"type": "string"
},
"post-rewrite": {
"type": "string"
}
}
}
}
}
}
}
}
],
To get intellisense for specific property values you can check out this documentation: https://github.com/json-schema/json-schema/wiki/anyOf,-allOf,-oneOf,-not#oneof
For your usecase it could also be useful to dynamically generate the JSON schema that includes all possible template names and include the schema in your JSON file via $schema property or via configuration:
"json.schemas": [
{
"fileMatch": [
"/json-files/*.json"
],
"url": "./templates.schema.json"
}
],
I'm not aware of any vscode feature to dynamically generate such a schema. You might want to use an approach as I did in this extension: https://github.com/skolmer/vscode-i18n-tag-schema - an extension that uses a node module to dynamically generate a schema file.

Related

ajv-cli always says bad data is valid

Running ajv-cli as part of my automated testing scripts to make sure my mock data is up to date.
./node_modules/.bin/ajv -s ./test-data/manifest.schema.json -d ./test-data/fleet.manifest.json
./test-data/fleet.manifest.json valid
But the data isn't valid.
manifest.schema.json:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"ManifestHistoryItem": {
"properties": {
"id": {
"default": [
"assetCatalog",
"Roster"
],
"items": {
"type": "string"
},
"type": "array"
},
"name": {
"default": "",
"type": "string"
}
},
"required": [
"id",
"name"
],
"type": "object"
}
}
}
fleet.manifest.json:
{
"namee": "Epic Space Battles"
}
(it's missing the required "id" property, and "name" is misspelled)
Schema is generated from "typescript-json-schema": "^0.54.0" from a typescript model and evaluated via "ajv-cli": "^5.0.0".
Your schema declares definitions, but it doesn't reference them anywhere. You need to add a "$ref": "#/definitions/ManifestHistoryItem" at the root.
{
"definitions": {
"ManifestHistoryItem": { ... }
},
"$ref": "#/definitions/ManifestHistoryItem"
}
Either that or you can just get rid of the definitions wrapper altogether and just have the { ... } part from above.
Effectively what's happening is you've defined an empty schema, which applies no constraints, meaning all instances (data) pass.

Json schema conditional validation configuration - Unsupported keyword(s): ["const"]]

I want to set up the conditional validation in my schema. I saw an example here on SO.
I have a similar setup, where I would like to validate if the field public is set to string "public". If it is set to "public" then I want to make fields description, attachmentUrl and tags required. If the field is not set to "public" then this fields are not required.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Update todo",
"type": "object",
"properties": {
"public": {
"type": "string"
},
"description": {
"type": "string",
"minLength": 3
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"uniqueItems": true,
"minItems": 1
},
"attachmentUrl": {
"type": "string"
}
},
"anyOf": [
{
"not": {
"properties": {
"public": { "const": "public" }
},
"required": ["public"]
}
},
{ "required": ["description", "tags", "attachmentUrl"] }
],
"additionalProperties": false
}
But, when I try to deploy it like that, I get the following error:
Invalid model specified: Validation Result: warnings : [], errors :
[Invalid model schema specified. Unsupported keyword(s): ["const"]]
The "const" keyword wasn't added until draft 06. You should upgrade to an implementation that supports at least that version.
https://json-schema.org/draft-06/json-schema-release-notes.html#additions-and-backwards-compatible-changes
Otherwise, you can use "enum" with a single value: "enum": ["public"]

Allow additional properties in reference schemas, but none else

Suppose I have two schema being used to validate a json file.
testSchema.json
{
"$schema": "http://json-schema.org/draft-07/schema",
"type": "object",
"additionalProperties": false,
"properties": {
"$schema": { "type": "string" },
"sample": { "type": "number" }
},
"anyOf": [
{ "$ref": "./testSchema2.json" },
{}
]
}
testSchema2.json
{
"$schema": "http://json-schema.org/draft-04/schema",
"type": "object",
"properties": {
"test": { "type": "string" },
"test2": { "type": "number" }
}
}
test.json
{
"$schema": "../testSchema.json",
"sample": 0,
"test": "some text" //this line throws error "Property is not allowed"
}
I'd like for the file to be validated against the included schema's properties and any schema that is referenced's properties. Am I missing something?
Edit: I want to exclude any objects that are not explicitly defined in any of my included/referenced schema.
From JSON Schema draft 2019-09 (after draft-07), this is possible by using the unevaluatedProperties keyword.
additionalProperties cannot "see through" applicator keywords such as "anyOf" and "$ref", and only works based on the properties in the same schema object.
This is not possible with draft-07 or previous.

How to use definitions from external files in JSON Schema?

I'm trying to import the definitions from another json schema using $ref but getting the following error:
can't resolve reference ../base/definitions.schema.json#/definitions/datetime from id #
{
"$schema": "http://json-schema.org/draft-06/schema#",
"definitions": {
"datetime": {
"type": "string"
},
"name": {
"type": "string"
},
}
}
{
"$schema": "http://json-schema.org/draft-06/schema#",
"properties": {
"active": {"type": "boolean"},
"created_at": { "$ref": "../base/definitions.schema.json#/definitions/datetime" },
"name": { "$ref": "../base/base/definitions.schema.json#/definitions/name" },
"updated_at": { "$ref": "../base/definitions.schema.json#/definitions/datetime" }
},
"required": ["name"],
"type": "object"
}
Directory structure:
api
-- base
-- definitions.schema.json
-- country
-- country.schema.json
I have tried several combinations by using an absolute path, a file url and several other combinations of the path. Not sure what's going on.
Schema validator: ajv#5.1.1
You need to add schemas using "addSchema" method. $ref is resolved relative to "id" attribute ("$id" in draft-06), ajv doesn't (and can't) use file paths.
EDIT: added $ref section to docs.

Is it possible to inline JSON schemas into a JSON document? [duplicate]

For example a schema for a file system, directory contains a list of files. The schema consists of the specification of file, next a sub type "image" and another one "text".
At the bottom there is the main directory schema. Directory has a property content which is an array of items that should be sub types of file.
Basically what I am looking for is a way to tell the validator to look up the value of a "$ref" from a property in the json object being validated.
Example json:
{
"name":"A directory",
"content":[
{
"fileType":"http://x.y.z/fs-schema.json#definitions/image",
"name":"an-image.png",
"width":1024,
"height":800
}
{
"fileType":"http://x.y.z/fs-schema.json#definitions/text",
"name":"readme.txt",
"lineCount":101
}
{
"fileType":"http://x.y.z/extended-fs-schema-video.json",
"name":"demo.mp4",
"hd":true
}
]
}
The "pseudo" Schema note that "image" and "text" definitions are included in the same schema but they might be defined elsewhere
{
"id": "http://x.y.z/fs-schema.json",
"definitions": {
"file": {
"type": "object",
"properties": {
"name": { "type": "string" },
"fileType": {
"type": "string",
"format": "uri"
}
}
},
"image": {
"allOf": [
{ "$ref": "#definitions/file" },
{
"properties": {
"width": { "type": "integer" },
"height": { "type": "integer"}
}
}
]
},
"text": {
"allOf": [
{ "$ref": "#definitions/file" },
{ "properties": { "lineCount": { "type": "integer"}}}
]
}
},
"type": "object",
"properties": {
"name": { "type": "string"},
"content": {
"type": "array",
"items": {
"allOf": [
{ "$ref": "#definitions/file" },
{ *"$refFromProperty"*: "fileType" } // the magic thing
]
}
}
}
}
The validation parts of JSON Schema alone cannot do this - it represents a fixed structure. What you want requires resolving/referencing schemas at validation-time.
However, you can express this using JSON Hyper-Schema, and a rel="describedby" link:
{
"title": "Directory entry",
"type": "object",
"properties": {
"fileType": {"type": "string", "format": "uri"}
},
"links": [{
"rel": "describedby",
"href": "{+fileType}"
}]
}
So here, it takes the value from "fileType" and uses it to calculate a link with relation "describedby" - which means "the schema at this location also describes the current data".
The problem is that most validators do not take any notice of any links (including "describedby" ones). You need to find a "hyper-validator" that does.
UPDATE: the tv4 library has added this as a feature
I think cloudfeet answer is a valid solution. You could also use the same approach described here.
You would have a file object type which could be "anyOf" all the subtypes you want to define. You would use an enum in order to be able to reference and validate against each of the subtypes.
If the sub-types schemas are in the same Json-Schema file you don't need to reference the uri explicitly with the "$ref". A correct draft4 validator will find the enum value and will try to validate against that "subschema" in the Json-Schema tree.
In draft5 (in progress) a "switch" statement has been proposed, which will allow to express alternatives in a more explicit way.