Search code examples
vscode-extensions

Set programmatically jsonValidation for dynamic mapping


I am creating a new vscode extension, and I need to extend the standard usage of the jsonValidation system already present in vscode.

Note : I am talking about the system defined in package.json :

"contributes" : {
    "languages": [
        {
            "id" : "yml", 
            "filenamePatterns": ["module.service"]
        },
        {
            "id" : "json", 
            "filenamePatterns": ["module.*"]
        }
    ],
    "jsonValidation": [
        {
            "fileMatch": "module.test",
            "url": "./resources/test.schema"
        }
    ]
}

Now, I need to create a dynamic mapping, where the json fields filematch/url are defined from some internal rules (like version and other internal stuff). The standard usage is static : one fileMatch -> one schema.

I want for example to read the version from the json file to validate, and set the schema after that :

{
    "version" : "1.1"
}

validation schema must be test-schema.1.1 instead of test-schema.1.0

note : The question is only about the modification of the configuration provided by package.json from the extensions.ts

Thanks for the support


Solution

  • ** EDIT since the previous solution was not working in all cases

    There is one solution to modify the package.json at the activating of the function.

    export function activate(context: vscode.ExtensionContext) {
        const myPlugin = vscode.extensions.getExtension("your.plugin.id");
        if (!myPlugin)
        {
            throw new Error("Composer plugin is not found...")
        }
    
        // Get the current workspace path to found the schema later.
        const folderPath = vscode.workspace.workspaceFolders;
        if (!folderPath)
        {
            return;
        }
        const baseUri : vscode.Uri = folderPath[0].uri;
    
        let packageJSON = myPlugin.packageJSON;
        if (packageJSON && packageJSON.contributes && packageJSON.contributes.jsonValidation)
        {
            let jsonValidation = packageJSON.contributes.jsonValidation;
            const schemaUri : vscode.Uri =  vscode.Uri.joinPath(baseUri, "/schema/value-0.3.0.json-schema");            
            const schema = new JsonSchemaMatch("value.ospp", schemaUri)
            jsonValidation.push(schema);
        }
    }
    
    

    And the json schema class

    class JsonSchemaMatch 
    {
        fileMatch: string;
        url : string;
    
        constructor(fileMatch : string, url: vscode.Uri) 
        {
            this.fileMatch = fileMatch;
            this.url = url.path;
        }
    }
    

    Another important information is the loading of the element of contributes is not reread after modification, for example

    class Language 
    {
        id: string;
        filenamePatterns : string[];
    
        constructor(id : string, filenamePatterns: string[]) 
        {
            this.id = id;
            this.filenamePatterns = filenamePatterns;
        }
    }
    
    if (packageJSON && packageJSON.contributes && packageJSON.contributes.languages)
        {
            let languages : Language[] = packageJSON.contributes.languages;
            for (let language of languages) {
                if (language.id == "json") {
                    language.filenamePatterns.push("test.my-json-type")
                }
            }
        }
    

    This change has no effect, since the loading of file association is already done (I have not dig for the reason, but I think this is the case)

    In this case, creating a settings.json in the workspace directory can do the job:

    settings.json

    {
      "files.associations": {
        "target.snmp": "json",
        "stack.cfg": "json"
      }
    }
    

    Be aware that the settings.json can be created by the user with legitimate reason, so don't override it, just fill it.