"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const testHelper_1 = require("./utils/testHelper");
const serviceSetup_1 = require("./utils/serviceSetup");
const chai_1 = require("chai");
const yamlSettings_1 = require("../src/yamlSettings");
const schemaUrls_1 = require("../src/languageservice/utils/schemaUrls");
describe('Validation Tests', () => {
    let languageSettingsSetup;
    let validationHandler;
    let yamlSettings;
    let schemaProvider;
    const KUBERNETES_SCHEMA_URL = `https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/${schemaUrls_1.DEFAULT_KUBERNETES_SCHEMA_VERSION}-standalone-strict/all.json`;
    const toContent = (data) => JSON.stringify(data, null, 2);
    before(() => {
        languageSettingsSetup = new serviceSetup_1.ServiceSetup()
            .withValidate()
            .withCompletion()
            .withCustomTags(['!Test', '!Ref sequence'])
            .withSchemaFileMatch({ uri: KUBERNETES_SCHEMA_URL, fileMatch: ['.drone.yml'] })
            .withSchemaFileMatch({ uri: 'https://json.schemastore.org/drone', fileMatch: ['.drone.yml'] })
            .withSchemaFileMatch({ uri: KUBERNETES_SCHEMA_URL, fileMatch: ['test.yml'] })
            .withSchemaFileMatch({
            uri: 'https://raw.githubusercontent.com/composer/composer/master/res/composer-schema.json',
            fileMatch: ['test.yml'],
        });
        const { validationHandler: valHandler, yamlSettings: settings, schemaProvider: testSchemaProvider, } = (0, testHelper_1.setupLanguageService)(languageSettingsSetup.languageSettings);
        validationHandler = valHandler;
        yamlSettings = settings;
        schemaProvider = testSchemaProvider;
    });
    function parseSetup(content, customSchemaID) {
        const testTextDocument = (0, testHelper_1.setupSchemaIDTextDocument)(content, customSchemaID);
        yamlSettings.documents = new yamlSettings_1.TextDocumentTestManager();
        yamlSettings.documents.set(testTextDocument);
        return validationHandler.validateTextDocument(testTextDocument);
    }
    afterEach(() => {
        schemaProvider.deleteSchema(testHelper_1.SCHEMA_ID);
    });
    describe('$ref resolution', () => {
        it('root pointer ref', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                properties: {
                    foo: { $ref: '#' },
                },
                additionalProperties: false,
            });
            // match
            let content = toContent({ foo: false });
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // recursive match
            content = toContent({ foo: { foo: false } });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // mismatch
            content = toContent({ bar: false });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('not allowed');
            // recursive mismatch
            content = toContent({ foo: { bar: false } });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('not allowed');
        });
        it('relative pointer ref to object', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                properties: {
                    foo: { type: 'integer' },
                    bar: { $ref: '#/properties/foo' },
                },
            });
            // match
            let content = toContent({ bar: 3 });
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // mismatch
            content = toContent({ bar: true });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Incorrect type');
        });
        it('relative pointer ref to array', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                items: [{ type: 'integer' }, { $ref: '#/items/0' }],
            });
            // match array
            let content = toContent([1, 2]);
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // mismatch array
            content = toContent([1, 'foo']);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Incorrect type');
        });
        it('escaped pointer ref', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $defs: {
                    'tilde~field': { type: 'integer' },
                    'slash/field': { type: 'integer' },
                    'percent%field': { type: 'integer' },
                },
                properties: {
                    tilde: { $ref: '#/$defs/tilde~0field' },
                    slash: { $ref: '#/$defs/slash~1field' },
                    percent: { $ref: '#/$defs/percent%25field' },
                },
            });
            // slash invalid
            let content = toContent({ slash: 'aoeu' });
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Incorrect type');
            // tilde invalid
            content = toContent({ tilde: 'aoeu' });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Incorrect type');
            // percent invalid
            content = toContent({ percent: 'aoeu' });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Incorrect type');
            // slash valid
            content = toContent({ slash: 123 });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // tilde valid
            content = toContent({ tilde: 123 });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // percent valid
            content = toContent({ percent: 123 });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
        });
        it('nested refs', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $defs: {
                    a: { type: 'integer' },
                    b: { $ref: '#/$defs/a' },
                    c: { $ref: '#/$defs/b' },
                },
                $ref: '#/$defs/c',
            });
            // nested ref valid
            let content = toContent(5);
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // nested ref invalid
            content = toContent('a');
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Incorrect type');
        });
        it('ref applies alongside sibling keywords', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $defs: {
                    reffed: {
                        type: 'array',
                    },
                },
                properties: {
                    foo: {
                        $ref: '#/$defs/reffed',
                        maxItems: 2,
                    },
                },
            });
            // ref valid, maxItems valid
            let content = toContent({ foo: [] });
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // ref valid, maxItems invalid
            content = toContent({ foo: [1, 2, 3] });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too many items');
            // ref invalid
            content = toContent({ foo: 'string' });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Incorrect type');
        });
        it('property named $ref that is not a reference', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                properties: {
                    $ref: { type: 'string' },
                },
            });
            // property named $ref valid
            let content = toContent({ $ref: 'a' });
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // property named $ref invalid
            content = toContent({ $ref: 2 });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Incorrect type');
        });
        it('property named $ref, containing an actual $ref', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                properties: {
                    $ref: { $ref: '#/$defs/is-string' },
                },
                $defs: {
                    'is-string': {
                        type: 'string',
                    },
                },
            });
            // property named $ref valid
            let content = toContent({ $ref: 'a' });
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // property named $ref invalid
            content = toContent({ $ref: 2 });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Incorrect type');
        });
        it('$ref to boolean schema true', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $ref: '#/$defs/bool',
                $defs: {
                    bool: true,
                },
            });
            // any value is valid
            const content = toContent('foo');
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
        });
        it('$ref to boolean schema false', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $ref: '#/$defs/bool',
                $defs: {
                    bool: false,
                },
            });
            // any value is invalid
            const content = toContent('foo');
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Matches a schema that is not allowed');
        });
    });
    describe('$anchor resolution', () => {
        it('Location-independent identifier', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $ref: '#foo',
                $defs: {
                    A: {
                        $anchor: 'foo',
                        type: 'integer',
                    },
                },
            });
            // match
            let content = toContent(1);
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // mismatch
            content = toContent('a');
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Incorrect type');
            (0, chai_1.expect)(result[0].message).to.include('integer');
        });
        it('Location-independent identifier with absolute URI', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $ref: 'http://localhost:1234/draft2019-09/bar#foo',
                $defs: {
                    A: {
                        $id: 'http://localhost:1234/draft2019-09/bar',
                        $anchor: 'foo',
                        type: 'integer',
                    },
                },
            });
            // match
            let content = toContent(1);
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // mismatch
            content = toContent('a');
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Incorrect type');
            (0, chai_1.expect)(result[0].message).to.include('integer');
        });
        it('Location-independent identifier with base URI change in subschema', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $id: 'http://localhost:1234/draft2019-09/root',
                $ref: 'http://localhost:1234/draft2019-09/nested.json#foo',
                $defs: {
                    A: {
                        $id: 'nested.json',
                        $defs: {
                            B: {
                                $anchor: 'foo',
                                type: 'integer',
                            },
                        },
                    },
                },
            });
            // match
            let content = toContent(1);
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // mismatch
            content = toContent('a');
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Incorrect type');
            (0, chai_1.expect)(result[0].message).to.include('integer');
        });
        it('same $anchor with different base uri', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $id: 'http://localhost:1234/draft2019-09/foobar',
                $defs: {
                    A: {
                        $id: 'child1',
                        allOf: [
                            {
                                $id: 'child2',
                                $anchor: 'my_anchor',
                                type: 'number',
                            },
                            {
                                $anchor: 'my_anchor',
                                type: 'string',
                            },
                        ],
                    },
                },
                $ref: 'child1#my_anchor',
            });
            // $ref resolves to /$defs/A/allOf/1
            let content = toContent('a');
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // $ref does not resolve to /$defs/A/allOf/0
            content = toContent(1);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Incorrect type');
            (0, chai_1.expect)(result[0].message).to.include('string');
        });
        it('resolves $ref "#name" via $anchor in same document', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $defs: {
                    Name: {
                        $anchor: 'name',
                        type: 'string',
                        minLength: 2,
                    },
                },
                $ref: '#name',
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = `A`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('String is shorter than the minimum length of 2.');
        });
        it('resolves external $ref to a root $anchor', async () => {
            const rootSchema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $anchor: 'rootThing',
                type: 'object',
                properties: {
                    x: {
                        type: 'number',
                    },
                },
                required: ['x'],
            };
            const useRootSchema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $ref: 'file:///root.schema.json#rootThing',
            };
            schemaProvider.addSchemaWithUri(testHelper_1.SCHEMA_ID, 'file:///root.schema.json', rootSchema);
            schemaProvider.addSchemaWithUri(testHelper_1.SCHEMA_ID, 'file:///use-root.schema.json', useRootSchema);
            const content = `# yaml-language-server: $schema=file:///use-root.schema.json\n{}`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Missing property');
        });
        it('resolves external $ref to $anchor in another schema', async () => {
            const typesSchema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $defs: {
                    Port: {
                        $anchor: 'port',
                        type: 'integer',
                        minimum: 1,
                        maximum: 65535,
                    },
                },
            };
            const serverSchema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                properties: {
                    port: { $ref: 'file:///types.schema.json#port' },
                },
            };
            schemaProvider.addSchemaWithUri(testHelper_1.SCHEMA_ID, 'file:///types.schema.json', typesSchema);
            schemaProvider.addSchemaWithUri(testHelper_1.SCHEMA_ID, 'file:///server.schema.json', serverSchema);
            const content = `# yaml-language-server: $schema=file:///server.schema.json\nport: 70000`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Value is above the maximum of 65535.');
        });
    });
    describe('keyword: unevaluatedProperties', () => {
        it('unevaluatedProperties as schema validates remaining property values', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                properties: {
                    known: { type: 'string' },
                },
                unevaluatedProperties: { type: 'number' },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = `known: ok\nextra: hi`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Incorrect type.');
            (0, chai_1.expect)(result[0].message).to.include('number');
        });
        it('unevaluatedProperties=false sees evaluated props across allOf', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                allOf: [
                    { type: 'object', properties: { a: { type: 'string' } } },
                    { type: 'object', properties: { b: { type: 'number' } } },
                ],
                unevaluatedProperties: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = `a: ok\nb: 1\nc: 2`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property c is not allowed');
        });
        it('unevaluatedProperties sees properties defined across $ref', async () => {
            const baseSchema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                properties: {
                    a: { type: 'string' },
                },
            };
            const strictSchema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                allOf: [{ $ref: 'file:///base-uneval.schema.json' }],
                unevaluatedProperties: false,
            };
            schemaProvider.addSchemaWithUri(testHelper_1.SCHEMA_ID, 'file:///base-uneval.schema.json', baseSchema);
            schemaProvider.addSchemaWithUri(testHelper_1.SCHEMA_ID, 'file:///strict-uneval.schema.json', strictSchema);
            const content = `# yaml-language-server: $schema=file:///strict-uneval.schema.json\na: ok\nc: nope`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property c is not allowed');
        });
        it('unevaluatedProperties true', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                unevaluatedProperties: true,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({}))).to.be.empty;
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'foo' }))).to.be.empty;
        });
        it('unevaluatedProperties schema', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                unevaluatedProperties: {
                    type: 'string',
                    minLength: 3,
                },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({}))).to.be.empty;
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'foo' }))).to.be.empty;
            const result = await parseSetup(toContent({ foo: 'fo' }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('String is shorter than the minimum length of 3.');
        });
        it('unevaluatedProperties false', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                unevaluatedProperties: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({}))).to.be.empty;
            const result = await parseSetup(toContent({ foo: 'foo' }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property foo is not allowed.');
        });
        it('unevaluatedProperties with adjacent properties', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                properties: {
                    foo: { type: 'string' },
                },
                unevaluatedProperties: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'foo' }))).to.be.empty;
            const result = await parseSetup(toContent({ foo: 'foo', bar: 'bar' }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property bar is not allowed.');
        });
        it('unevaluatedProperties with adjacent patternProperties', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                patternProperties: {
                    '^foo': { type: 'string' },
                },
                unevaluatedProperties: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'foo' }))).to.be.empty;
            const result = await parseSetup(toContent({ foo: 'foo', bar: 'bar' }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property bar is not allowed.');
        });
        it('unevaluatedProperties with adjacent additionalProperties', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                properties: {
                    foo: { type: 'string' },
                },
                additionalProperties: true,
                unevaluatedProperties: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'foo' }))).to.be.empty;
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'foo', bar: 'bar' }))).to.be.empty;
        });
        it('unevaluatedProperties with nested properties', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                properties: {
                    foo: { type: 'string' },
                },
                allOf: [
                    {
                        properties: {
                            bar: { type: 'string' },
                        },
                    },
                ],
                unevaluatedProperties: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'foo', bar: 'bar' }))).to.be.empty;
            const result = await parseSetup(toContent({ foo: 'foo', bar: 'bar', baz: 'baz' }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property baz is not allowed.');
        });
        it('unevaluatedProperties with nested patternProperties', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                properties: {
                    foo: { type: 'string' },
                },
                allOf: [
                    {
                        patternProperties: {
                            '^bar': { type: 'string' },
                        },
                    },
                ],
                unevaluatedProperties: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'foo', bar: 'bar' }))).to.be.empty;
            const result = await parseSetup(toContent({ foo: 'foo', bar: 'bar', baz: 'baz' }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property baz is not allowed.');
        });
        it('unevaluatedProperties with nested additionalProperties', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                properties: {
                    foo: { type: 'string' },
                },
                allOf: [
                    {
                        additionalProperties: true,
                    },
                ],
                unevaluatedProperties: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'foo' }))).to.be.empty;
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'foo', bar: 'bar' }))).to.be.empty;
        });
        it('unevaluatedProperties with nested unevaluatedProperties', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                properties: {
                    foo: { type: 'string' },
                },
                allOf: [
                    {
                        unevaluatedProperties: true,
                    },
                ],
                unevaluatedProperties: {
                    type: 'string',
                    maxLength: 2,
                },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'foo' }))).to.be.empty;
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'foo', bar: 'bar' }))).to.be.empty;
        });
        it('unevaluatedProperties with anyOf', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                properties: {
                    foo: { type: 'string' },
                },
                anyOf: [
                    {
                        properties: {
                            bar: { const: 'bar' },
                        },
                        required: ['bar'],
                    },
                    {
                        properties: {
                            baz: { const: 'baz' },
                        },
                        required: ['baz'],
                    },
                    {
                        properties: {
                            quux: { const: 'quux' },
                        },
                        required: ['quux'],
                    },
                ],
                unevaluatedProperties: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'foo', bar: 'bar' }))).to.be.empty;
            let result = await parseSetup(toContent({ foo: 'foo', bar: 'bar', baz: 'not-baz' }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property baz is not allowed.');
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'foo', bar: 'bar', baz: 'baz' }))).to.be.empty;
            result = await parseSetup(toContent({ foo: 'foo', bar: 'bar', baz: 'baz', quux: 'not-quux' }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property quux is not allowed.');
        });
        it('unevaluatedProperties with oneOf', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                properties: {
                    foo: { type: 'string' },
                },
                oneOf: [
                    {
                        properties: {
                            bar: { const: 'bar' },
                        },
                        required: ['bar'],
                    },
                    {
                        properties: {
                            baz: { const: 'baz' },
                        },
                        required: ['baz'],
                    },
                ],
                unevaluatedProperties: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'foo', bar: 'bar' }))).to.be.empty;
            const result = await parseSetup(toContent({ foo: 'foo', bar: 'bar', quux: 'quux' }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property quux is not allowed.');
        });
        it('unevaluatedProperties with not', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                properties: {
                    foo: { type: 'string' },
                },
                not: {
                    not: {
                        properties: {
                            bar: { const: 'bar' },
                        },
                        required: ['bar'],
                    },
                },
                unevaluatedProperties: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const result = await parseSetup(toContent({ foo: 'foo', bar: 'bar' }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property bar is not allowed.');
        });
        it('unevaluatedProperties with if/then/else', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                if: {
                    properties: {
                        foo: { const: 'then' },
                    },
                    required: ['foo'],
                },
                then: {
                    properties: {
                        bar: { type: 'string' },
                    },
                    required: ['bar'],
                },
                else: {
                    properties: {
                        baz: { type: 'string' },
                    },
                    required: ['baz'],
                },
                unevaluatedProperties: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'then', bar: 'bar' }))).to.be.empty;
            let result = await parseSetup(toContent({ foo: 'then', bar: 'bar', baz: 'baz' }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property baz is not allowed.');
            (0, chai_1.expect)(await parseSetup(toContent({ baz: 'baz' }))).to.be.empty;
            result = await parseSetup(toContent({ foo: 'else', baz: 'baz' }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property foo is not allowed.');
        });
        it('unevaluatedProperties with if/then/else, then not defined', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                if: {
                    properties: {
                        foo: { const: 'then' },
                    },
                    required: ['foo'],
                },
                else: {
                    properties: {
                        baz: { type: 'string' },
                    },
                    required: ['baz'],
                },
                unevaluatedProperties: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'then' }))).to.be.empty;
            let result = await parseSetup(toContent({ foo: 'then', bar: 'bar' }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property bar is not allowed.');
            (0, chai_1.expect)(await parseSetup(toContent({ baz: 'baz' }))).to.be.empty;
            result = await parseSetup(toContent({ foo: 'else', baz: 'baz' }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property foo is not allowed.');
        });
        it('unevaluatedProperties with if/then/else, else not defined', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                if: {
                    properties: {
                        foo: { const: 'then' },
                    },
                    required: ['foo'],
                },
                then: {
                    properties: {
                        bar: { type: 'string' },
                    },
                    required: ['bar'],
                },
                unevaluatedProperties: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'then', bar: 'bar' }))).to.be.empty;
            let result = await parseSetup(toContent({ foo: 'then', bar: 'bar', baz: 'baz' }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property baz is not allowed.');
            result = await parseSetup(toContent({ baz: 'baz' }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property baz is not allowed.');
            result = await parseSetup(toContent({ foo: 'else', baz: 'baz' }));
            (0, chai_1.expect)(result).to.have.length(2);
            const messages = result.map((entry) => entry.message).join(' | ');
            (0, chai_1.expect)(messages).to.include('Property foo is not allowed.');
            (0, chai_1.expect)(messages).to.include('Property baz is not allowed.');
        });
        it('unevaluatedProperties with dependentSchemas', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                properties: {
                    foo: { type: 'string' },
                },
                dependentSchemas: {
                    foo: {
                        properties: {
                            bar: { const: 'bar' },
                        },
                        required: ['bar'],
                    },
                },
                unevaluatedProperties: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'foo', bar: 'bar' }))).to.be.empty;
            const result = await parseSetup(toContent({ bar: 'bar' }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property bar is not allowed.');
        });
        it('unevaluatedProperties with boolean schemas', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                properties: {
                    foo: { type: 'string' },
                },
                allOf: [true],
                unevaluatedProperties: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'foo' }))).to.be.empty;
            const result = await parseSetup(toContent({ bar: 'bar' }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property bar is not allowed.');
        });
        it('unevaluatedProperties with $ref', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                $ref: '#/$defs/bar',
                properties: {
                    foo: { type: 'string' },
                },
                unevaluatedProperties: false,
                $defs: {
                    bar: {
                        properties: {
                            bar: { type: 'string' },
                        },
                    },
                },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'foo', bar: 'bar' }))).to.be.empty;
            const result = await parseSetup(toContent({ foo: 'foo', bar: 'bar', baz: 'baz' }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property baz is not allowed.');
        });
        it('unevaluatedProperties before $ref', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                unevaluatedProperties: false,
                properties: {
                    foo: { type: 'string' },
                },
                $ref: '#/$defs/bar',
                $defs: {
                    bar: {
                        properties: {
                            bar: { type: 'string' },
                        },
                    },
                },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'foo', bar: 'bar' }))).to.be.empty;
            const result = await parseSetup(toContent({ foo: 'foo', bar: 'bar', baz: 'baz' }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property baz is not allowed.');
        });
        it('unevaluatedProperties with $recursiveRef', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $id: 'https://example.com/unevaluated-properties-with-recursive-ref/extended-tree',
                $recursiveAnchor: true,
                $ref: './tree',
                properties: {
                    name: { type: 'string' },
                },
                $defs: {
                    tree: {
                        $id: './tree',
                        $recursiveAnchor: true,
                        type: 'object',
                        properties: {
                            node: true,
                            branches: {
                                $comment: "unevaluatedProperties comes first so it's more likely to bugs errors with implementations that are sensitive to keyword ordering",
                                unevaluatedProperties: false,
                                $recursiveRef: '#',
                            },
                        },
                        required: ['node'],
                    },
                },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({
                name: 'a',
                node: 1,
                branches: {
                    name: 'b',
                    node: 2,
                },
            }))).to.be.empty;
            const result = await parseSetup(toContent({
                name: 'a',
                node: 1,
                branches: {
                    foo: 'b',
                    node: 2,
                },
            }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property foo is not allowed.');
        });
        it("unevaluatedProperties can't see inside cousins", async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                allOf: [
                    {
                        properties: {
                            foo: true,
                        },
                    },
                    {
                        unevaluatedProperties: false,
                    },
                ],
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const result = await parseSetup(toContent({ foo: 1 }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property foo is not allowed.');
        });
        it("unevaluatedProperties can't see inside cousins (reverse order)", async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                allOf: [
                    {
                        unevaluatedProperties: false,
                    },
                    {
                        properties: {
                            foo: true,
                        },
                    },
                ],
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const result = await parseSetup(toContent({ foo: 1 }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property foo is not allowed.');
        });
        it('nested unevaluatedProperties, outer false, inner true, properties outside', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                properties: {
                    foo: { type: 'string' },
                },
                allOf: [
                    {
                        unevaluatedProperties: true,
                    },
                ],
                unevaluatedProperties: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'foo' }))).to.be.empty;
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'foo', bar: 'bar' }))).to.be.empty;
        });
        it('nested unevaluatedProperties, outer false, inner true, properties inside', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                allOf: [
                    {
                        properties: {
                            foo: { type: 'string' },
                        },
                        unevaluatedProperties: true,
                    },
                ],
                unevaluatedProperties: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'foo' }))).to.be.empty;
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'foo', bar: 'bar' }))).to.be.empty;
        });
        it('nested unevaluatedProperties, outer true, inner false, properties outside', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                properties: {
                    foo: { type: 'string' },
                },
                allOf: [
                    {
                        unevaluatedProperties: false,
                    },
                ],
                unevaluatedProperties: true,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const result1 = await parseSetup(toContent({ foo: 'foo' }));
            (0, chai_1.expect)(result1).to.have.length(1);
            (0, chai_1.expect)(result1[0].message).to.include('Property foo is not allowed.');
            const result2 = await parseSetup(toContent({ foo: 'foo', bar: 'bar' }));
            (0, chai_1.expect)(result2).to.have.length(2);
            const messages = result2.map((entry) => entry.message).join(' | ');
            (0, chai_1.expect)(messages).to.include('Property foo is not allowed.');
            (0, chai_1.expect)(messages).to.include('Property bar is not allowed.');
        });
        it('nested unevaluatedProperties, outer true, inner false, properties inside', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                allOf: [
                    {
                        properties: {
                            foo: { type: 'string' },
                        },
                        unevaluatedProperties: false,
                    },
                ],
                unevaluatedProperties: true,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'foo' }))).to.be.empty;
            const result = await parseSetup(toContent({ foo: 'foo', bar: 'bar' }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property bar is not allowed.');
        });
        it('cousin unevaluatedProperties, true and false, true with properties', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                allOf: [
                    {
                        properties: {
                            foo: { type: 'string' },
                        },
                        unevaluatedProperties: true,
                    },
                    {
                        unevaluatedProperties: false,
                    },
                ],
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const result1 = await parseSetup(toContent({ foo: 'foo' }));
            (0, chai_1.expect)(result1).to.have.length(1);
            (0, chai_1.expect)(result1[0].message).to.include('Property foo is not allowed.');
            const result2 = await parseSetup(toContent({ foo: 'foo', bar: 'bar' }));
            (0, chai_1.expect)(result2).to.have.length(2);
            const messages = result2.map((entry) => entry.message).join(' | ');
            (0, chai_1.expect)(messages).to.include('Property foo is not allowed.');
            (0, chai_1.expect)(messages).to.include('Property bar is not allowed.');
        });
        it('cousin unevaluatedProperties, true and false, false with properties', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                allOf: [
                    {
                        unevaluatedProperties: true,
                    },
                    {
                        properties: {
                            foo: { type: 'string' },
                        },
                        unevaluatedProperties: false,
                    },
                ],
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'foo' }))).to.be.empty;
            const result = await parseSetup(toContent({ foo: 'foo', bar: 'bar' }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property bar is not allowed.');
        });
        it('property is evaluated in an uncle schema to unevaluatedProperties', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                properties: {
                    foo: {
                        type: 'object',
                        properties: {
                            bar: {
                                type: 'string',
                            },
                        },
                        unevaluatedProperties: false,
                    },
                },
                anyOf: [
                    {
                        properties: {
                            foo: {
                                properties: {
                                    faz: {
                                        type: 'string',
                                    },
                                },
                            },
                        },
                    },
                ],
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({ foo: { bar: 'test' } }))).to.be.empty;
            const result = await parseSetup(toContent({ foo: { bar: 'test', faz: 'test' } }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property faz is not allowed.');
        });
        describe('in-place applicator siblings, allOf has unevaluated', () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                allOf: [
                    {
                        properties: {
                            foo: true,
                        },
                        unevaluatedProperties: false,
                    },
                ],
                anyOf: [
                    {
                        properties: {
                            bar: true,
                        },
                    },
                ],
            };
            beforeEach(() => {
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            });
            it('base case: both properties present', async () => {
                const result = await parseSetup(toContent({ foo: 1, bar: 1 }));
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Property bar is not allowed.');
            });
            it('in place applicator siblings, bar is missing', async () => {
                (0, chai_1.expect)(await parseSetup(toContent({ foo: 1 }))).to.be.empty;
            });
            it('in place applicator siblings, foo is missing', async () => {
                const result = await parseSetup(toContent({ bar: 1 }));
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Property bar is not allowed.');
            });
        });
        describe('in-place applicator siblings, anyOf has unevaluated', () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                allOf: [
                    {
                        properties: {
                            foo: true,
                        },
                    },
                ],
                anyOf: [
                    {
                        properties: {
                            bar: true,
                        },
                        unevaluatedProperties: false,
                    },
                ],
            };
            beforeEach(() => {
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            });
            it('base case: both properties present', async () => {
                const result = await parseSetup(toContent({ foo: 1, bar: 1 }));
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Property foo is not allowed.');
            });
            it('in place applicator siblings, bar is missing', async () => {
                const result = await parseSetup(toContent({ foo: 1 }));
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Property foo is not allowed.');
            });
            it('in place applicator siblings, foo is missing', async () => {
                (0, chai_1.expect)(await parseSetup(toContent({ bar: 1 }))).to.be.empty;
            });
        });
        describe('unevaluatedProperties + single cyclic ref', () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                properties: {
                    x: { $ref: '#' },
                },
                unevaluatedProperties: false,
            };
            beforeEach(() => {
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            });
            it('Empty is valid', async () => {
                (0, chai_1.expect)(await parseSetup(toContent({}))).to.be.empty;
            });
            it('Single is valid', async () => {
                (0, chai_1.expect)(await parseSetup(toContent({ x: {} }))).to.be.empty;
            });
            it('Unevaluated on 1st level is invalid', async () => {
                const result = await parseSetup(toContent({ x: {}, y: {} }));
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Property y is not allowed.');
            });
            it('Nested is valid', async () => {
                (0, chai_1.expect)(await parseSetup(toContent({ x: { x: {} } }))).to.be.empty;
            });
            it('Unevaluated on 2nd level is invalid', async () => {
                const result = await parseSetup(toContent({ x: { x: {}, y: {} } }));
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Property y is not allowed.');
            });
            it('Deep nested is valid', async () => {
                (0, chai_1.expect)(await parseSetup(toContent({ x: { x: { x: {} } } }))).to.be.empty;
            });
            it('Unevaluated on 3rd level is invalid', async () => {
                const result = await parseSetup(toContent({ x: { x: { x: {}, y: {} } } }));
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Property y is not allowed.');
            });
        });
        describe('unevaluatedProperties + ref inside allOf / oneOf', () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $defs: {
                    one: {
                        properties: { a: true },
                    },
                    two: {
                        required: ['x'],
                        properties: { x: true },
                    },
                },
                allOf: [
                    { $ref: '#/$defs/one' },
                    { properties: { b: true } },
                    {
                        oneOf: [
                            { $ref: '#/$defs/two' },
                            {
                                required: ['y'],
                                properties: { y: true },
                            },
                        ],
                    },
                ],
                unevaluatedProperties: false,
            };
            beforeEach(() => {
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            });
            it('Empty is invalid (no x or y)', async () => {
                const result = await parseSetup(toContent({}));
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Missing property');
                (0, chai_1.expect)(result[0].message).to.include('x');
            });
            it('a and b are invalid (no x or y)', async () => {
                const result = await parseSetup(toContent({ a: 1, b: 1 }));
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Missing property');
                (0, chai_1.expect)(result[0].message).to.include('x');
            });
            it('x and y are invalid', async () => {
                const result = await parseSetup(toContent({ x: 1, y: 1 }));
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Matches multiple schemas when only one must validate.');
            });
            it('a and x are valid', async () => {
                (0, chai_1.expect)(await parseSetup(toContent({ a: 1, x: 1 }))).to.be.empty;
            });
            it('a and y are valid', async () => {
                (0, chai_1.expect)(await parseSetup(toContent({ a: 1, y: 1 }))).to.be.empty;
            });
            it('a and b and x are valid', async () => {
                (0, chai_1.expect)(await parseSetup(toContent({ a: 1, b: 1, x: 1 }))).to.be.empty;
            });
            it('a and b and y are valid', async () => {
                (0, chai_1.expect)(await parseSetup(toContent({ a: 1, b: 1, y: 1 }))).to.be.empty;
            });
            it('a and b and x and y are invalid', async () => {
                const result = await parseSetup(toContent({ a: 1, b: 1, x: 1, y: 1 }));
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Matches multiple schemas when only one must validate.');
            });
        });
        describe('dynamic evalation inside nested refs', () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $defs: {
                    one: {
                        oneOf: [
                            { $ref: '#/$defs/two' },
                            { required: ['b'], properties: { b: true } },
                            { required: ['xx'], patternProperties: { x: true } },
                            { required: ['all'], unevaluatedProperties: true },
                        ],
                    },
                    two: {
                        oneOf: [
                            { required: ['c'], properties: { c: true } },
                            { required: ['d'], properties: { d: true } },
                        ],
                    },
                },
                oneOf: [{ $ref: '#/$defs/one' }, { required: ['a'], properties: { a: true } }],
                unevaluatedProperties: false,
            };
            beforeEach(() => {
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            });
            it('Empty is invalid', async () => {
                const result = await parseSetup(toContent({}));
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Missing property');
            });
            it('a is valid', async () => {
                (0, chai_1.expect)(await parseSetup(toContent({ a: 1 }))).to.be.empty;
            });
            it('b is valid', async () => {
                (0, chai_1.expect)(await parseSetup(toContent({ b: 1 }))).to.be.empty;
            });
            it('c is valid', async () => {
                (0, chai_1.expect)(await parseSetup(toContent({ c: 1 }))).to.be.empty;
            });
            it('d is valid', async () => {
                (0, chai_1.expect)(await parseSetup(toContent({ d: 1 }))).to.be.empty;
            });
            it('a + b is invalid', async () => {
                const result = await parseSetup(toContent({ a: 1, b: 1 }));
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Matches multiple schemas when only one must validate.');
            });
            it('a + c is invalid', async () => {
                const result = await parseSetup(toContent({ a: 1, c: 1 }));
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Matches multiple schemas when only one must validate.');
            });
            it('a + d is invalid', async () => {
                const result = await parseSetup(toContent({ a: 1, d: 1 }));
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Matches multiple schemas when only one must validate.');
            });
            it('b + c is invalid', async () => {
                const result = await parseSetup(toContent({ b: 1, c: 1 }));
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Matches multiple schemas when only one must validate.');
            });
            it('b + d is invalid', async () => {
                const result = await parseSetup(toContent({ b: 1, d: 1 }));
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Matches multiple schemas when only one must validate.');
            });
            it('c + d is invalid', async () => {
                const result = await parseSetup(toContent({ c: 1, d: 1 }));
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Matches multiple schemas when only one must validate.');
            });
            it('xx is valid', async () => {
                (0, chai_1.expect)(await parseSetup(toContent({ xx: 1 }))).to.be.empty;
            });
            it('xx + foox is valid', async () => {
                (0, chai_1.expect)(await parseSetup(toContent({ xx: 1, foox: 1 }))).to.be.empty;
            });
            it('xx + foo is invalid', async () => {
                const result = await parseSetup(toContent({ xx: 1, foo: 1 }));
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Property foo is not allowed.');
            });
            it('xx + a is invalid', async () => {
                const result = await parseSetup(toContent({ xx: 1, a: 1 }));
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Matches multiple schemas when only one must validate.');
            });
            it('xx + b is invalid', async () => {
                const result = await parseSetup(toContent({ xx: 1, b: 1 }));
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Matches multiple schemas when only one must validate.');
            });
            it('xx + c is invalid', async () => {
                const result = await parseSetup(toContent({ xx: 1, c: 1 }));
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Matches multiple schemas when only one must validate.');
            });
            it('xx + d is invalid', async () => {
                const result = await parseSetup(toContent({ xx: 1, d: 1 }));
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Matches multiple schemas when only one must validate.');
            });
            it('all is valid', async () => {
                (0, chai_1.expect)(await parseSetup(toContent({ all: 1 }))).to.be.empty;
            });
            it('all + foo is valid', async () => {
                (0, chai_1.expect)(await parseSetup(toContent({ all: 1, foo: 1 }))).to.be.empty;
            });
            it('all + a is invalid', async () => {
                const result = await parseSetup(toContent({ all: 1, a: 1 }));
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Matches multiple schemas when only one must validate.');
            });
        });
        it('non-object instances are valid', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                unevaluatedProperties: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent(true))).to.be.empty;
            (0, chai_1.expect)(await parseSetup(toContent(123))).to.be.empty;
            (0, chai_1.expect)(await parseSetup(toContent(1.0))).to.be.empty;
            (0, chai_1.expect)(await parseSetup(toContent([]))).to.be.empty;
            (0, chai_1.expect)(await parseSetup(toContent('foo'))).to.be.empty;
            (0, chai_1.expect)(await parseSetup(toContent(null))).to.be.empty;
        });
        it('unevaluatedProperties with null valued instance properties', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                unevaluatedProperties: {
                    type: 'null',
                },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({ foo: null }))).to.be.empty;
        });
        it('unevaluatedProperties not affected by propertyNames', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                propertyNames: { maxLength: 1 },
                unevaluatedProperties: {
                    type: 'number',
                },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({ a: 1 }))).to.be.empty;
            const result = await parseSetup(toContent({ a: 'b' }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Incorrect type');
            (0, chai_1.expect)(result[0].message).to.include('number');
        });
        it('unevaluatedProperties can see annotations from if without then and else', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                if: {
                    patternProperties: {
                        foo: {
                            type: 'string',
                        },
                    },
                },
                unevaluatedProperties: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(toContent({ foo: 'a' }))).to.be.empty;
            const result = await parseSetup(toContent({ bar: 'a' }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property bar is not allowed.');
        });
        it('dependentSchemas with unevaluatedProperties', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                properties: { foo2: {} },
                dependentSchemas: {
                    foo: {},
                    foo2: {
                        properties: {
                            bar: {},
                        },
                    },
                },
                unevaluatedProperties: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const result1 = await parseSetup(toContent({ foo: '' }));
            (0, chai_1.expect)(result1).to.have.length(1);
            (0, chai_1.expect)(result1[0].message).to.include('Property foo is not allowed.');
            const result2 = await parseSetup(toContent({ bar: '' }));
            (0, chai_1.expect)(result2).to.have.length(1);
            (0, chai_1.expect)(result2[0].message).to.include('Property bar is not allowed.');
            (0, chai_1.expect)(await parseSetup(toContent({ foo2: '', bar: '' }))).to.be.empty;
        });
        it('Evaluated properties collection needs to consider instance location', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                properties: {
                    foo: {
                        properties: {
                            bar: { type: 'string' },
                        },
                    },
                },
                unevaluatedProperties: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const result = await parseSetup(toContent({ foo: { bar: 'foo' }, bar: 'bar' }));
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Property bar is not allowed.');
        });
    });
    describe('keyword: unevaluatedItems', () => {
        it('unevaluatedItems true', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                unevaluatedItems: true,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(`[]`)).to.be.empty;
            (0, chai_1.expect)(await parseSetup(`- foo`)).to.be.empty;
        });
        it('unevaluatedItems false', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                unevaluatedItems: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(`[]`)).to.be.empty;
            const content = `- foo`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too many items according to schema. Expected 0 or fewer.');
        });
        it('unevaluatedItems as schema', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                unevaluatedItems: { type: 'string' },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(`[]`)).to.be.empty;
            (0, chai_1.expect)(await parseSetup(`- foo`)).to.be.empty;
            const result = await parseSetup(`- 42`);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Incorrect type. Expected');
            (0, chai_1.expect)(result[0].message).to.include('string');
        });
        it('unevaluatedItems with uniform items', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                items: { type: 'string' },
                unevaluatedItems: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = `- foo\n- bar`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
        });
        it('unevaluatedItems with tuple', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                items: [{ type: 'string' }],
                unevaluatedItems: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(`- foo`)).to.be.empty;
            const content = `- foo\n- bar`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too many items according to schema. Expected 1 or fewer.');
        });
        it('unevaluatedItems with items and additionalItems', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                items: [{ type: 'string' }],
                additionalItems: true,
                unevaluatedItems: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = `- foo\n- 42`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
        });
        it('unevaluatedItems with ignored additionalItems', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                additionalItems: { type: 'number' },
                unevaluatedItems: { type: 'string' },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = `- foo\n- 1`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Incorrect type. Expected');
            (0, chai_1.expect)(result[0].message).to.include('string');
            (0, chai_1.expect)(await parseSetup(`- foo\n- bar\n- baz`)).to.be.empty;
        });
        it('unevaluatedItems with ignored applicator additionalItems', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                allOf: [{ additionalItems: { type: 'number' } }],
                unevaluatedItems: { type: 'string' },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = `- foo\n- 1`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Incorrect type. Expected');
            (0, chai_1.expect)(result[0].message).to.include('string');
            (0, chai_1.expect)(await parseSetup(`- foo\n- bar\n- baz`)).to.be.empty;
        });
        it('unevaluatedItems with nested tuple', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                items: [{ type: 'string' }],
                allOf: [
                    {
                        items: [true, { type: 'number' }],
                    },
                ],
                unevaluatedItems: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(`- foo\n- 42`)).to.be.empty;
            const content = `- foo\n- 42\n- true`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too many items according to schema. Expected 2 or fewer.');
        });
        it('unevaluatedItems with nested items', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                unevaluatedItems: { type: 'boolean' },
                anyOf: [{ items: { type: 'string' } }, true],
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content1 = `- true\n- false`;
            const result1 = await parseSetup(content1);
            (0, chai_1.expect)(result1).to.be.empty;
            const content2 = `- "yes"\n- false`;
            const result2 = await parseSetup(content2);
            (0, chai_1.expect)(result2).to.have.length(1);
            (0, chai_1.expect)(result2[0].message).to.include('Incorrect type.');
            const content3 = `- "yes"\n- "no"`;
            const result3 = await parseSetup(content3);
            (0, chai_1.expect)(result3).to.be.empty;
        });
        it('unevaluatedItems with nested items and additionalItems', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                allOf: [
                    {
                        items: [{ type: 'string' }],
                        additionalItems: true,
                    },
                ],
                unevaluatedItems: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(`- foo`)).to.be.empty;
            (0, chai_1.expect)(await parseSetup(`- foo\n- 42\n- true`)).to.be.empty;
        });
        it('unevaluatedItems with nested unevaluatedItems', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                allOf: [
                    {
                        items: [{ type: 'string' }],
                    },
                    { unevaluatedItems: true },
                ],
                unevaluatedItems: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(`- foo`)).to.be.empty;
            const content = `- foo\n- 42\n- true`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
        });
        it('unevaluatedItems with anyOf', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                items: [{ const: 'foo' }],
                anyOf: [
                    {
                        items: [true, { const: 'bar' }],
                    },
                    {
                        items: [true, true, { const: 'baz' }],
                    },
                ],
                unevaluatedItems: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content1 = `- foo\n- bar`;
            const result1 = await parseSetup(content1);
            (0, chai_1.expect)(result1).to.be.empty;
            const content2 = `- foo\n- bar\n- 42`;
            const result2 = await parseSetup(content2);
            (0, chai_1.expect)(result2).to.have.length(1);
            (0, chai_1.expect)(result2[0].message).to.include('Array has too many items according to schema. Expected 2 or fewer.');
            const content3 = `- foo\n- bar\n- baz`;
            const result3 = await parseSetup(content3);
            (0, chai_1.expect)(result3).to.be.empty;
            const content4 = `- foo\n- bar\n- baz\n- 42`;
            const result4 = await parseSetup(content4);
            (0, chai_1.expect)(result4).to.have.length(1);
            (0, chai_1.expect)(result4[0].message).to.include('Array has too many items according to schema. Expected 3 or fewer.');
        });
        it('unevaluatedItems with oneOf', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                items: [{ const: 'foo' }],
                oneOf: [
                    {
                        items: [true, { const: 'bar' }],
                    },
                    {
                        items: [true, { const: 'baz' }],
                    },
                ],
                unevaluatedItems: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(`- foo\n- bar`)).to.be.empty;
            const content = `- foo\n- bar\n- 42`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too many items according to schema. Expected 2 or fewer.');
        });
        it('unevaluatedItems with not', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                items: [{ const: 'foo' }],
                not: {
                    not: {
                        items: [true, { const: 'bar' }],
                    },
                },
                unevaluatedItems: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = `- foo\n- bar`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too many items according to schema. Expected 1 or fewer.');
        });
        it('unevaluatedItems with if/then/else', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                items: [{ const: 'foo' }],
                if: {
                    items: [true, { const: 'bar' }],
                },
                then: {
                    items: [true, true, { const: 'then' }],
                },
                else: {
                    items: [true, true, true, { const: 'else' }],
                },
                unevaluatedItems: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const result1 = await parseSetup(`- foo\n- bar\n- then`);
            (0, chai_1.expect)(result1).to.be.empty;
            const result2 = await parseSetup(`- foo\n- bar\n- then\n- else`);
            (0, chai_1.expect)(result2).to.have.length(1);
            (0, chai_1.expect)(result2[0].message).to.include('Array has too many items according to schema. Expected 3 or fewer.');
            const result3 = await parseSetup(`- foo\n- 42\n- 42\n- else`);
            (0, chai_1.expect)(result3).to.be.empty;
            const result = await parseSetup(`- foo\n- 42\n- 42\n- else\n- 42`);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too many items according to schema. Expected 4 or fewer.');
        });
        it('unevaluatedItems with boolean schemas', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                allOf: [true],
                unevaluatedItems: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(`[]`)).to.be.empty;
            const content = `- foo`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too many items according to schema. Expected 0 or fewer.');
        });
        it('unevaluatedItems with $ref', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $ref: '#/$defs/bar',
                items: [{ type: 'string' }],
                unevaluatedItems: false,
                $defs: {
                    bar: {
                        items: [true, { type: 'string' }],
                    },
                },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(`- foo\n- bar`)).to.be.empty;
            const content = `- foo\n- bar\n- baz`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too many items according to schema. Expected 2 or fewer.');
        });
        it('unevaluatedItems before $ref', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                unevaluatedItems: false,
                items: [{ type: 'string' }],
                $ref: '#/$defs/bar',
                $defs: {
                    bar: {
                        items: [true, { type: 'string' }],
                    },
                },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(`- foo\n- bar`)).to.be.empty;
            const content = `- foo\n- bar\n- baz`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too many items according to schema. Expected 2 or fewer.');
        });
        it('unevaluatedItems with $recursiveRef', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $id: 'https://example.com/unevaluated-items-with-recursive-ref/extended-tree',
                $recursiveAnchor: true,
                $ref: './tree',
                items: [true, true, { type: 'string' }],
                $defs: {
                    tree: {
                        $id: './tree',
                        $recursiveAnchor: true,
                        type: 'array',
                        items: [
                            { type: 'number' },
                            {
                                unevaluatedItems: false,
                                $recursiveRef: '#',
                            },
                        ],
                    },
                },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(`- 1\n- - 2\n  - []\n  - b\n- a`)).to.be.empty;
            const content = `- 1\n- - 2\n  - []\n  - b\n  - too many\n- a`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too many items according to schema. Expected 3 or fewer.');
        });
        it("unevaluatedItems can't see inside cousins", async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                allOf: [{ items: [true] }, { unevaluatedItems: false }],
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = `- 1`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too many items according to schema. Expected 0 or fewer.');
        });
        it('item is evaluated in an uncle schema to unevaluatedItems', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                properties: {
                    foo: {
                        items: [{ type: 'string' }],
                        unevaluatedItems: false,
                    },
                },
                anyOf: [
                    {
                        properties: {
                            foo: {
                                items: [true, { type: 'string' }],
                            },
                        },
                    },
                ],
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(`foo:\n  - test`)).to.be.empty;
            const content = `foo:\n  - test\n  - test`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too many items according to schema. Expected 1 or fewer.');
        });
        describe('non-array instances are valid', () => {
            it('', async () => {
                const schema = {
                    $schema: 'https://json-schema.org/draft/2019-09/schema',
                    unevaluatedItems: false,
                };
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
                const content = `true`;
                const result = await parseSetup(content);
                (0, chai_1.expect)(result).to.be.empty;
            });
            it('ignores integers', async () => {
                const schema = {
                    $schema: 'https://json-schema.org/draft/2019-09/schema',
                    unevaluatedItems: false,
                };
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
                const content = `123`;
                const result = await parseSetup(content);
                (0, chai_1.expect)(result).to.be.empty;
            });
            it('ignores floats', async () => {
                const schema = {
                    $schema: 'https://json-schema.org/draft/2019-09/schema',
                    unevaluatedItems: false,
                };
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
                const content = `1.0`;
                const result = await parseSetup(content);
                (0, chai_1.expect)(result).to.be.empty;
            });
            it('ignores objects', async () => {
                const schema = {
                    $schema: 'https://json-schema.org/draft/2019-09/schema',
                    unevaluatedItems: false,
                };
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
                const content = `{}`;
                const result = await parseSetup(content);
                (0, chai_1.expect)(result).to.be.empty;
            });
            it('ignores strings', async () => {
                const schema = {
                    $schema: 'https://json-schema.org/draft/2019-09/schema',
                    unevaluatedItems: false,
                };
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
                const content = `foo`;
                const result = await parseSetup(content);
                (0, chai_1.expect)(result).to.be.empty;
            });
            it('ignores null', async () => {
                const schema = {
                    $schema: 'https://json-schema.org/draft/2019-09/schema',
                    unevaluatedItems: false,
                };
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
                const content = `null`;
                const result = await parseSetup(content);
                (0, chai_1.expect)(result).to.be.empty;
            });
        });
        it('unevaluatedItems with null instance elements', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                unevaluatedItems: {
                    type: 'null',
                },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = `- null`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
        });
        it('unevaluatedItems can see annotations from if without then and else', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                if: {
                    items: [{ const: 'a' }],
                },
                unevaluatedItems: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            (0, chai_1.expect)(await parseSetup(`- a`)).to.be.empty;
            const content = `- b`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too many items according to schema. Expected 0 or fewer.');
        });
        it('Evaluated items collection needs to consider instance location', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                items: [
                    {
                        items: [true, { type: 'string' }],
                    },
                ],
                unevaluatedItems: false,
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = `- - foo\n  - bar\n- bar`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too many items according to schema. Expected 1 or fewer.');
        });
    });
    describe('keyword: contains + minContains/maxContains', () => {
        it('minContains fails when too few items match contains subschema', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'array',
                contains: {
                    type: 'object',
                    properties: {
                        kind: { const: 'ok' },
                        id: { type: 'number' },
                    },
                    required: ['kind', 'id'],
                },
                minContains: 2,
            });
            const content = `- kind: ok\n  id: 1\n- kind: ok\n  id: "2"\n- kind: nope\n  id: 3`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too few items matching');
            (0, chai_1.expect)(result[0].message).to.include('contains');
            (0, chai_1.expect)(result[0].message).to.include('Expected 2 or more.');
        });
        it('maxContains fails when too many items match contains subschema', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'array',
                contains: {
                    type: 'object',
                    properties: {
                        kind: { const: 'ok' },
                        id: { type: 'number' },
                    },
                    required: ['kind', 'id'],
                },
                maxContains: 3,
            });
            const content = `- kind: ok\n  id: 1\n- kind: ok\n  id: 2\n- kind: ok\n  id: 3\n- kind: ok\n  id: 4`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too many items matching');
            (0, chai_1.expect)(result[0].message).to.include('contains');
            (0, chai_1.expect)(result[0].message).to.include('Expected 3 or fewer.');
        });
        it('minContains/maxContains passes when match count is within bounds', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'array',
                contains: {
                    type: 'object',
                    properties: {
                        kind: { const: 'ok' },
                        id: { type: 'number' },
                    },
                    required: ['kind', 'id'],
                },
                minContains: 2,
                maxContains: 3,
            });
            const content = `
- kind: ok
  id: 1
- kind: ok
  id: 2
- kind: nope
  id: 3
`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
        });
        it('contains matching is based on subschema, not just item type', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'array',
                contains: {
                    type: 'object',
                    required: ['tag'],
                    properties: {
                        tag: { const: 'match' },
                    },
                },
                minContains: 1,
            });
            const okYaml = `
- tag: other
- tag: match
- nope: 1
`;
            let result = await parseSetup(okYaml);
            (0, chai_1.expect)(result).to.be.empty;
            const badYaml = `
- tag: other
- tag: nope
- nope: 1`;
            result = await parseSetup(badYaml);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too few items matching');
            (0, chai_1.expect)(result[0].message).to.include('contains');
            (0, chai_1.expect)(result[0].message).to.include('Expected 1 or more.');
        });
    });
    describe('keyword: dependentRequired', () => {
        beforeEach(() => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                properties: {
                    billing_address: { type: 'string' },
                    credit_card: { type: 'string' },
                },
                dependentRequired: {
                    billing_address: ['credit_card'],
                },
            });
        });
        it('requires dependent properties when the trigger property is present', async () => {
            const content = `billing_address: "123 King St"`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Object is missing property credit_card required by property billing_address.');
        });
        it('passes when required dependent properties are present', async () => {
            const content = `billing_address: "123 King St"\ncredit_card: "4111-1111"`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
        });
    });
    describe('keyword: dependentSchemas', () => {
        it('does not apply when the trigger property is absent', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                properties: {
                    kind: { type: 'string' },
                    port: { type: 'number' },
                },
                dependentSchemas: {
                    kind: { required: ['port'] },
                },
            });
            const content = `port: 8080`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
        });
        it('applies dependent schema when the trigger property is present', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                properties: {
                    kind: { type: 'string' },
                    port: { type: 'number' },
                },
                dependentSchemas: {
                    kind: { required: ['port'] },
                },
            });
            const content = `kind: service`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Missing property');
            (0, chai_1.expect)(result[0].message).to.include('port');
        });
        it('can enforce additional constraints from the dependent schema', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                properties: {
                    tls: { type: 'boolean' },
                    port: { type: 'number' },
                },
                dependentSchemas: {
                    tls: {
                        required: ['port'],
                        properties: {
                            port: { minimum: 1024 },
                        },
                    },
                },
            });
            const content = `tls: true\nport: 80`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Value is below the minimum of 1024.');
        });
        it('applies multiple dependentSchemas when multiple triggers are present', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                properties: {
                    kind: { type: 'string' },
                    tls: { type: 'boolean' },
                    port: { type: 'number' },
                },
                dependentSchemas: {
                    kind: { required: ['port'] },
                    tls: {
                        required: ['port'],
                        properties: { port: { minimum: 1024 } },
                    },
                },
            });
            const content = `kind: service\ntls: true\nport: 80`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Value is below the minimum of 1024.');
        });
    });
    describe('keyword: dependencies (backward compatibility)', () => {
        describe('property dependencies tests', () => {
            beforeEach(() => {
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                    $schema: 'http://json-schema.org/draft-07/schema#',
                    type: 'object',
                    properties: {
                        credit_card: { type: 'string' },
                        billing_address: { type: 'string' },
                    },
                    dependencies: {
                        credit_card: ['billing_address'],
                    },
                });
            });
            it('requires dependent properties when the trigger property is present', async () => {
                const content = `credit_card: "4111-1111-1111-1111"`;
                const result = await parseSetup(content);
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Object is missing property billing_address required by property credit_card.');
            });
            it('does not apply when the trigger property is absent', async () => {
                const content = `billing_address: "123 Main St"`;
                const result = await parseSetup(content);
                (0, chai_1.expect)(result).to.be.empty;
            });
        });
        describe('schema dependencies tests', () => {
            beforeEach(() => {
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                    $schema: 'http://json-schema.org/draft-07/schema#',
                    type: 'object',
                    properties: {
                        mode: { type: 'string' },
                        port: { type: 'number' },
                    },
                    dependencies: {
                        mode: {
                            required: ['port'],
                            properties: {
                                port: { minimum: 1024 },
                            },
                        },
                    },
                });
            });
            it('enforces dependent schema constraints when trigger property is present', async () => {
                const content = `mode: "server"\nport: 80`;
                const result = await parseSetup(content);
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Value is below the minimum of 1024.');
            });
            it('enforces dependent schema required properties when trigger property is present', async () => {
                const content = `mode: "server"`;
                const result = await parseSetup(content);
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Missing property');
                (0, chai_1.expect)(result[0].message).to.include('port');
            });
            it('does not apply the dependent schema when trigger property is absent', async () => {
                const content = `port: 80`;
                const result = await parseSetup(content);
                (0, chai_1.expect)(result).to.be.empty;
            });
        });
    });
    describe('$ref resolution should support sibling keywords', () => {
        it('should apply sibling keywords next to $ref', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                properties: {
                    value: {
                        $ref: '#/$defs/A',
                        type: 'number',
                    },
                },
                $defs: {
                    A: { type: 'string' },
                },
            });
            // both should fail: must be both string and number
            (0, chai_1.expect)((await parseSetup(`value: hello`)).length).to.be.greaterThan(0);
            (0, chai_1.expect)((await parseSetup(`value: 1`)).length).to.be.greaterThan(0);
        });
        it('should apply sibling keywords next to $ref (top level)', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                definitions: {
                    obj1: {
                        type: 'object',
                        properties: {
                            value: { type: 'string' },
                        },
                        required: ['value'],
                    },
                },
                $ref: '#/definitions/obj1',
                additionalProperties: false,
                properties: {
                    value: {},
                    extra: { type: 'number' },
                },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = `value: hello
extra: notANumber
unknown: 1
`;
            const result = await parseSetup(content);
            (0, chai_1.expect)(result[0].message).to.include('Incorrect type. Expected');
            (0, chai_1.expect)(result[0].message).to.include('number');
            (0, chai_1.expect)(result[1].message).to.include('Property unknown is not allowed.');
        });
    });
    describe('$id resolution', () => {
        it('$id inside an enum is not a real identifier (the implementation must not be confused by an $id buried in the enum)', async () => {
            const root = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $defs: {
                    id_in_enum: {
                        enum: [
                            {
                                $id: 'https://localhost:1234/draft2019-09/id/my_identifier.json',
                                type: 'null',
                            },
                        ],
                    },
                    real_id_in_schema: {
                        $id: 'https://localhost:1234/draft2019-09/id/my_identifier.json',
                        type: 'string',
                    },
                    zzz_id_in_const: {
                        const: {
                            $id: 'https://localhost:1234/draft2019-09/id/my_identifier.json',
                            type: 'null',
                        },
                    },
                },
                anyOf: [{ $ref: '#/$defs/id_in_enum' }, { $ref: 'https://localhost:1234/draft2019-09/id/my_identifier.json' }],
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, root);
            // exact match to enum, and type matches
            (0, chai_1.expect)(await parseSetup(toContent({
                $id: 'https://localhost:1234/draft2019-09/id/my_identifier.json',
                type: 'null',
            }))).to.be.empty;
            // match $ref to $id
            (0, chai_1.expect)(await parseSetup('a string to match #/$defs/id_in_enum')).to.be.empty;
            // no match on enum or $ref to $id
            const result = await parseSetup(`1`);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Value is not accepted. Valid values:');
        });
        it('should resolve embedded resource $id for relative $ref without external load', async () => {
            const root = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                properties: {
                    x: { $ref: 'other.json#bar' },
                },
                required: ['x'],
                $defs: {
                    B: {
                        $id: 'other.json',
                        $defs: {
                            X: {
                                $anchor: 'bar',
                                type: 'string',
                                minLength: 2,
                            },
                        },
                    },
                },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, root);
            const yaml = `x: A`;
            const result = await parseSetup(yaml);
            (0, chai_1.expect)(result.some((d) => /Problems loading reference/i.test(d.message))).to.eq(false);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('String is shorter than the minimum length of 2.');
        });
        it('should handle $id changing base URI for nested $anchor resolution', async () => {
            const root = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                type: 'object',
                properties: {
                    address: { $ref: 'schemas/address.json#USAddress' },
                },
                $defs: {
                    addressSchema: {
                        $id: 'schemas/address.json',
                        $defs: {
                            us: {
                                $anchor: 'USAddress',
                                type: 'object',
                                properties: {
                                    zipCode: { type: 'string', minLength: 5 },
                                },
                                required: ['zipCode'],
                            },
                        },
                    },
                },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, root);
            const yaml = `address:\n  zipCode: "123"`;
            const result = await parseSetup(yaml);
            (0, chai_1.expect)(result.some((d) => /Problems loading reference/i.test(d.message))).to.eq(false);
            (0, chai_1.expect)(result[0].message).to.include('String is shorter than the minimum length of 5.');
        });
    });
    describe('$recursiveAnchor and $recursiveRef resolution', () => {
        describe('$recursiveRef without $recursiveAnchor works like $ref', () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                properties: {
                    foo: { $recursiveRef: '#' },
                },
                additionalProperties: false,
            };
            beforeEach(() => {
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            });
            it('match', async () => {
                (0, chai_1.expect)(await parseSetup('foo: false')).to.be.empty;
            });
            it('recursive match', async () => {
                (0, chai_1.expect)(await parseSetup(`foo:
  foo: false`)).to.be.empty;
            });
            it('mismatch', async () => {
                const result = await parseSetup('bar: false');
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Property bar is not allowed.');
            });
            it('recursive mismatch', async () => {
                const result = await parseSetup(`foo:
  bar: false`);
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Property bar is not allowed.');
            });
        });
        describe('$recursiveRef without using nesting', () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $id: 'http://localhost:4242/draft2019-09/recursiveRef2/schema.json',
                $defs: {
                    myobject: {
                        $id: 'myobject.json',
                        $recursiveAnchor: true,
                        anyOf: [
                            { type: 'string' },
                            {
                                type: 'object',
                                additionalProperties: { $recursiveRef: '#' },
                            },
                        ],
                    },
                },
                anyOf: [{ type: 'integer' }, { $ref: '#/$defs/myobject' }],
            };
            beforeEach(() => {
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            });
            it('integer matches at the outer level', async () => {
                (0, chai_1.expect)(await parseSetup(`1`)).to.be.empty;
            });
            it('single level match', async () => {
                (0, chai_1.expect)(await parseSetup(`foo: hi`)).to.be.empty;
            });
            it('integer does not match as a property value', async () => {
                const result = await parseSetup(`foo: 1`);
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Incorrect type.');
                (0, chai_1.expect)(result[0].message).to.include('string | object');
            });
            it('two levels, properties match with inner definition', async () => {
                (0, chai_1.expect)(await parseSetup(`foo:
  bar: hi`)).to.be.empty;
            });
            it('two levels, no match', async () => {
                const result = await parseSetup(`foo:
  bar: 1`);
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Incorrect type.');
                (0, chai_1.expect)(result[0].message).to.include('string | object');
            });
        });
        describe('$recursiveRef with nesting', () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $id: 'http://localhost:4242/draft2019-09/recursiveRef3/schema.json',
                $recursiveAnchor: true,
                $defs: {
                    myobject: {
                        $id: 'myobject.json',
                        $recursiveAnchor: true,
                        anyOf: [
                            { type: 'string' },
                            {
                                type: 'object',
                                additionalProperties: { $recursiveRef: '#' },
                            },
                        ],
                    },
                },
                anyOf: [{ type: 'integer' }, { $ref: '#/$defs/myobject' }],
            };
            beforeEach(() => {
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            });
            it('integer matches at the outer level', async () => {
                (0, chai_1.expect)(await parseSetup(`1`)).to.be.empty;
            });
            it('single level match', async () => {
                (0, chai_1.expect)(await parseSetup(`foo: hi`)).to.be.empty;
            });
            it('integer now matches as a property value', async () => {
                (0, chai_1.expect)(await parseSetup(`foo: 1`)).to.be.empty;
            });
            it('two levels, properties match with inner definition', async () => {
                (0, chai_1.expect)(await parseSetup(`foo:
  bar: hi`)).to.be.empty;
            });
            it('two levels, properties match with $recursiveRef', async () => {
                (0, chai_1.expect)(await parseSetup(`foo:
  bar: 1`)).to.be.empty;
            });
        });
        describe('$recursiveRef with $recursiveAnchor: false works like $ref', () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $id: 'http://localhost:4242/draft2019-09/recursiveRef4/schema.json',
                $recursiveAnchor: false,
                $defs: {
                    myobject: {
                        $id: 'myobject.json',
                        $recursiveAnchor: false,
                        anyOf: [
                            { type: 'string' },
                            {
                                type: 'object',
                                additionalProperties: { $recursiveRef: '#' },
                            },
                        ],
                    },
                },
                anyOf: [{ type: 'integer' }, { $ref: '#/$defs/myobject' }],
            };
            beforeEach(() => {
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            });
            it('integer matches at the outer level', async () => {
                (0, chai_1.expect)(await parseSetup(`1`)).to.be.empty;
            });
            it('single level match', async () => {
                (0, chai_1.expect)(await parseSetup(`foo: hi`)).to.be.empty;
            });
            it('integer does not match as a property value', async () => {
                const result = await parseSetup(`foo: 1`);
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Incorrect type.');
                (0, chai_1.expect)(result[0].message).to.include('string | object');
            });
            it('two levels, properties match with inner definition', async () => {
                (0, chai_1.expect)(await parseSetup(`foo:
  bar: hi`)).to.be.empty;
            });
            it('two levels, integer does not match as a property value', async () => {
                const result = await parseSetup(`foo:
  bar: 1`);
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Incorrect type.');
                (0, chai_1.expect)(result[0].message).to.include('string | object');
            });
        });
        describe('$recursiveRef with no $recursiveAnchor works like $ref', () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $id: 'http://localhost:4242/draft2019-09/recursiveRef5/schema.json',
                $defs: {
                    myobject: {
                        $id: 'myobject.json',
                        $recursiveAnchor: false,
                        anyOf: [
                            { type: 'string' },
                            {
                                type: 'object',
                                additionalProperties: { $recursiveRef: '#' },
                            },
                        ],
                    },
                },
                anyOf: [{ type: 'integer' }, { $ref: '#/$defs/myobject' }],
            };
            beforeEach(() => {
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            });
            it('integer matches at the outer level', async () => {
                (0, chai_1.expect)(await parseSetup(`1`)).to.be.empty;
            });
            it('single level match', async () => {
                (0, chai_1.expect)(await parseSetup(`foo: hi`)).to.be.empty;
            });
            it('integer does not match as a property value', async () => {
                const result = await parseSetup(`foo: 1`);
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Incorrect type.');
                (0, chai_1.expect)(result[0].message).to.include('string | object');
            });
            it('two levels, properties match with inner definition', async () => {
                (0, chai_1.expect)(await parseSetup(`foo:
  bar: hi`)).to.be.empty;
            });
            it('two levels, integer does not match as a property value', async () => {
                const result = await parseSetup(`foo:
  bar: 1`);
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Incorrect type.');
                (0, chai_1.expect)(result[0].message).to.include('string | object');
            });
        });
        describe('$recursiveRef with no $recursiveAnchor in the initial target schema resource', () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $id: 'http://localhost:4242/draft2019-09/recursiveRef6/base.json',
                $recursiveAnchor: true,
                anyOf: [
                    { type: 'boolean' },
                    {
                        type: 'object',
                        additionalProperties: {
                            $id: 'http://localhost:4242/draft2019-09/recursiveRef6/inner.json',
                            $comment: 'there is no $recursiveAnchor: true here, so we do NOT recurse to the base',
                            anyOf: [{ type: 'integer' }, { type: 'object', additionalProperties: { $recursiveRef: '#' } }],
                        },
                    },
                ],
            };
            beforeEach(() => {
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            });
            it('leaf node does not match; no recursion', async () => {
                const result = await parseSetup(`foo: true`);
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Incorrect type.');
                (0, chai_1.expect)(result[0].message).to.include('integer | object');
            });
            it('leaf node matches: recursion uses the inner schema', async () => {
                (0, chai_1.expect)(await parseSetup(`foo:
  bar: 1`)).to.be.empty;
            });
            it('leaf node does not match: recursion uses the inner schema', async () => {
                const result = await parseSetup(`foo:
  bar: true`);
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Incorrect type.');
                (0, chai_1.expect)(result[0].message).to.include('integer | object');
            });
        });
        describe('$recursiveRef with no $recursiveAnchor in the outer schema resource', () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $id: 'http://localhost:4242/draft2019-09/recursiveRef7/base.json',
                anyOf: [
                    { type: 'boolean' },
                    {
                        type: 'object',
                        additionalProperties: {
                            $id: 'http://localhost:4242/draft2019-09/recursiveRef7/inner.json',
                            $recursiveAnchor: true,
                            anyOf: [{ type: 'integer' }, { type: 'object', additionalProperties: { $recursiveRef: '#' } }],
                        },
                    },
                ],
            };
            beforeEach(() => {
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            });
            it('leaf node does not match; no recursion', async () => {
                const result = await parseSetup(`foo: true`);
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Incorrect type.');
                (0, chai_1.expect)(result[0].message).to.include('integer | object');
            });
            it('leaf node matches: recursion only uses inner schema', async () => {
                (0, chai_1.expect)(await parseSetup(`foo:
  bar: 1`)).to.be.empty;
            });
            it('leaf node does not match: recursion only uses inner schema', async () => {
                const result = await parseSetup(`foo:
  bar: true`);
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Incorrect type.');
                (0, chai_1.expect)(result[0].message).to.include('integer | object');
            });
        });
        describe('multiple dynamic paths to the $recursiveRef keyword', () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $id: 'https://example.com/recursiveRef8_main.json',
                $defs: {
                    inner: {
                        $id: 'recursiveRef8_inner.json',
                        $recursiveAnchor: true,
                        title: 'inner',
                        additionalProperties: {
                            $recursiveRef: '#',
                        },
                    },
                },
                if: {
                    propertyNames: {
                        pattern: '^[a-m]',
                    },
                },
                then: {
                    title: 'any type of node',
                    $id: 'recursiveRef8_anyLeafNode.json',
                    $recursiveAnchor: true,
                    $ref: 'recursiveRef8_inner.json',
                },
                else: {
                    title: 'integer node',
                    $id: 'recursiveRef8_integerNode.json',
                    $recursiveAnchor: true,
                    type: ['object', 'integer'],
                    $ref: 'recursiveRef8_inner.json',
                },
            };
            beforeEach(() => {
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            });
            it('recurse to anyLeafNode - floats are allowed', async () => {
                (0, chai_1.expect)(await parseSetup(`alpha: 1.1`)).to.be.empty;
            });
            it('recurse to integerNode - floats are not allowed', async () => {
                const result = await parseSetup(`november: 1.1`);
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Incorrect type. Expected one of object, integer.');
            });
        });
        describe('dynamic $recursiveRef destination (not predictable at schema compile time)', () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $id: 'https://example.com/main.json',
                $defs: {
                    inner: {
                        $id: 'inner.json',
                        $recursiveAnchor: true,
                        title: 'inner',
                        additionalProperties: {
                            $recursiveRef: '#',
                        },
                    },
                },
                if: { propertyNames: { pattern: '^[a-m]' } },
                then: {
                    title: 'any type of node',
                    $id: 'anyLeafNode.json',
                    $recursiveAnchor: true,
                    $ref: 'main.json#/$defs/inner',
                },
                else: {
                    title: 'integer node',
                    $id: 'integerNode.json',
                    $recursiveAnchor: true,
                    type: ['object', 'integer'],
                    $ref: 'main.json#/$defs/inner',
                },
            };
            beforeEach(() => {
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            });
            it('numeric node', async () => {
                (0, chai_1.expect)(await parseSetup(`alpha: 1.1`)).to.be.empty;
            });
            it('integer node', async () => {
                const result = await parseSetup(`november: 1.1`);
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Incorrect type. Expected one of object, integer.');
            });
        });
        it('does not infinite loop on self-recursive $recursiveRef', async () => {
            const schema = {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                $id: 'http://localhost:4242/recursive.json',
                $recursiveAnchor: true,
                anyOf: [
                    { type: 'string' },
                    {
                        type: 'object',
                        additionalProperties: { $recursiveRef: '#' },
                    },
                ],
            };
            schemaProvider.addSchemaWithUri(testHelper_1.SCHEMA_ID, 'http://localhost:4242/recursive.json', schema);
            const result = await parseSetup(`# yaml-language-server: $schema=http://localhost:4242/recursive.json
foo:
  bar:
    baz: 1`);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Incorrect type.');
            (0, chai_1.expect)(result[0].message).to.include('string | object');
        });
        describe('tree schema with unevaluatedProperties', () => {
            it('$recursiveRef resolves to outermost schema with $recursiveAnchor in dynamic scope', async () => {
                const treeSchema = {
                    $schema: 'https://json-schema.org/draft/2019-09/schema',
                    $id: 'http://example.com/tree.json',
                    $recursiveAnchor: true,
                    type: 'object',
                    properties: {
                        value: { type: 'integer' },
                        children: { type: 'array', items: { $recursiveRef: '#' } },
                    },
                    required: ['value'],
                };
                const treeWithMetaSchema = {
                    $schema: 'https://json-schema.org/draft/2019-09/schema',
                    $id: 'http://example.com/tree-with-meta.json',
                    $recursiveAnchor: true,
                    allOf: [{ $ref: 'http://example.com/tree.json' }],
                    properties: {
                        meta: { type: 'string' },
                    },
                    required: ['meta'],
                    unevaluatedProperties: false,
                };
                schemaProvider.addSchemaWithUri(testHelper_1.SCHEMA_ID, 'http://example.com/tree.json', treeSchema);
                schemaProvider.addSchemaWithUri(testHelper_1.SCHEMA_ID, 'http://example.com/tree-with-meta.json', treeWithMetaSchema);
                const content = `# yaml-language-server: $schema=http://example.com/tree-with-meta.json
value: 1
meta: root
children:
  - value: 2
`;
                const result = await parseSetup(content);
                (0, chai_1.expect)(result).to.have.length(1);
                (0, chai_1.expect)(result[0].message).to.include('Missing property');
                (0, chai_1.expect)(result[0].message).to.include('meta');
            });
            it('$recursiveRef with all required properties should pass', async () => {
                const treeSchema = {
                    $schema: 'https://json-schema.org/draft/2019-09/schema',
                    $id: 'http://example.com/tree2.json',
                    $recursiveAnchor: true,
                    type: 'object',
                    properties: {
                        value: { type: 'integer' },
                        children: { type: 'array', items: { $recursiveRef: '#' } },
                    },
                    required: ['value'],
                };
                const treeWithMetaSchema = {
                    $schema: 'https://json-schema.org/draft/2019-09/schema',
                    $id: 'http://example.com/tree-with-meta2.json',
                    $recursiveAnchor: true,
                    allOf: [{ $ref: 'http://example.com/tree2.json' }],
                    properties: {
                        meta: { type: 'string' },
                    },
                    required: ['meta'],
                    unevaluatedProperties: false,
                };
                schemaProvider.addSchemaWithUri(testHelper_1.SCHEMA_ID, 'http://example.com/tree2.json', treeSchema);
                schemaProvider.addSchemaWithUri(testHelper_1.SCHEMA_ID, 'http://example.com/tree-with-meta2.json', treeWithMetaSchema);
                const content = `# yaml-language-server: $schema=http://example.com/tree-with-meta2.json
value: 1
meta: root
children:
  - value: 2
    meta: child
`;
                (0, chai_1.expect)(await parseSetup(content)).to.be.empty;
            });
        });
    });
    describe('keyword: contains', () => {
        it('contains keyword validation', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                contains: { minimum: 5 },
            });
            // array with item matching schema (5) is valid
            let content = toContent([3, 4, 5]);
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // array with item matching schema (6) is valid
            content = toContent([3, 4, 6]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // array with two items matching schema (5, 6) is valid
            content = toContent([3, 4, 5, 6]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // array without items matching schema is invalid
            content = toContent([2, 3, 4]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too few items matching');
            // empty array is invalid
            content = toContent([]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too few items matching');
            // not array is valid
            content = toContent({});
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
        });
        it('contains keyword with const keyword', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                contains: { const: 5 },
            });
            // array with item 5 is valid
            let content = toContent([3, 4, 5]);
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // array with two items 5 is valid
            content = toContent([3, 4, 5, 5]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // array without item 5 is invalid
            content = toContent([1, 2, 3, 4]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too few items matching');
        });
        it('contains keyword with boolean schema true', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                contains: true,
            });
            // any non-empty array is valid
            let content = toContent(['foo']);
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // empty array is invalid
            content = toContent([]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too few items matching');
        });
        it('contains keyword with boolean schema false', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                contains: false,
            });
            // any non-empty array is invalid
            let content = toContent(['foo']);
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too few items matching');
            // empty array is invalid
            content = toContent([]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too few items matching');
            // non-arrays are valid
            content = toContent('contains does not apply to strings');
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
        });
        it('items + contains', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                items: { multipleOf: 2 },
                contains: { multipleOf: 3 },
            });
            // matches items, does not match contains
            let content = toContent([2, 4, 8]);
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too few items matching');
            // does not match items, matches contains
            content = toContent([3, 6, 9]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(2);
            (0, chai_1.expect)(result[0].message).to.include('Value is not divisible by 2.');
            (0, chai_1.expect)(result[1].message).to.include('Value is not divisible by 2.');
            // matches both items and contains
            content = toContent([6, 12]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // matches neither items nor contains
            content = toContent([1, 5]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(3);
            (0, chai_1.expect)(result[0].message).to.include('Value is not divisible by 2.');
            (0, chai_1.expect)(result[1].message).to.include('Value is not divisible by 2.');
            (0, chai_1.expect)(result[2].message).to.include('Array has too few items matching');
        });
        it('contains with false if subschema', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                contains: {
                    if: false,
                    else: true,
                },
            });
            // any non-empty array is valid
            let content = toContent(['foo']);
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // empty array is invalid
            content = toContent([]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too few items matching');
        });
        it('contains with null instance elements', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                contains: {
                    type: 'null',
                },
            });
            // allows null items
            const content = toContent([null]);
            const result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
        });
    });
    describe('keyword: maxContains', () => {
        it('maxContains without contains is ignored', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                maxContains: 1,
            });
            // one item valid against lone maxContains
            let content = toContent([1]);
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // two items still valid against lone maxContains
            content = toContent([1, 2]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
        });
        it('maxContains with contains', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                contains: { const: 1 },
                maxContains: 1,
            });
            // empty data
            let content = toContent([]);
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too few items matching');
            // all elements match, valid maxContains
            content = toContent([1]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // all elements match, invalid maxContains
            content = toContent([1, 1]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too many items matching');
            // some elements match, valid maxContains
            content = toContent([1, 2]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // some elements match, invalid maxContains
            content = toContent([1, 2, 1]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too many items matching');
        });
        it('maxContains with contains, value with a decimal', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                contains: { const: 1 },
                maxContains: 1.0,
            });
            // one element matches, valid maxContains
            let content = toContent([1]);
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // too many elements match, invalid maxContains
            content = toContent([1, 1]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too many items matching');
        });
        it('minContains < maxContains', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                contains: { const: 1 },
                minContains: 1,
                maxContains: 3,
            });
            // actual < minContains < maxContains
            let content = toContent([]);
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too few items matching');
            // minContains < actual < maxContains
            content = toContent([1, 1]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // minContains < maxContains < actual
            content = toContent([1, 1, 1, 1]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too many items matching');
        });
    });
    describe('keyword: minContains', () => {
        it('minContains without contains is ignored', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                minContains: 1,
            });
            // one item valid against lone minContains
            let content = toContent([1]);
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // zero items still valid against lone minContains
            content = toContent([]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
        });
        it('minContains=1 with contains', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                contains: { const: 1 },
                minContains: 1,
            });
            // empty data
            let content = toContent([]);
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too few items matching');
            // no elements match
            content = toContent([2]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too few items matching');
            // single element matches, valid minContains
            content = toContent([1]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // some elements match, valid minContains
            content = toContent([1, 2]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // all elements match, valid minContains
            content = toContent([1, 1]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
        });
        it('minContains=2 with contains', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                contains: { const: 1 },
                minContains: 2,
            });
            // empty data
            let content = toContent([]);
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too few items matching');
            // all elements match, invalid minContains
            content = toContent([1]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too few items matching');
            // some elements match, invalid minContains
            content = toContent([1, 2]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too few items matching');
            // all elements match, valid minContains (exactly as needed)
            content = toContent([1, 1]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // all elements match, valid minContains (more than needed)
            content = toContent([1, 1, 1]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // some elements match, valid minContains
            content = toContent([1, 2, 1]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
        });
        it('minContains=2 with contains with a decimal value', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                contains: { const: 1 },
                minContains: 2.0,
            });
            // one element matches, invalid minContains
            let content = toContent([1]);
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too few items matching');
            // both elements match, valid minContains
            content = toContent([1, 1]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
        });
        it('maxContains = minContains', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                contains: { const: 1 },
                maxContains: 2,
                minContains: 2,
            });
            // empty data
            let content = toContent([]);
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too few items matching');
            // all elements match, invalid minContains
            content = toContent([1]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too few items matching');
            // all elements match, invalid maxContains
            content = toContent([1, 1, 1]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too many items matching');
            // all elements match, valid maxContains and minContains
            content = toContent([1, 1]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
        });
        it('maxContains < minContains', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                contains: { const: 1 },
                maxContains: 1,
                minContains: 3,
            });
            // empty data
            let content = toContent([]);
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too few items matching');
            // invalid minContains
            content = toContent([1]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too few items matching');
            // invalid maxContains
            content = toContent([1, 1, 1]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(2);
            (0, chai_1.expect)(result[0].message).to.include('Array has too few items matching');
            (0, chai_1.expect)(result[1].message).to.include('Array has too many items matching');
            // invalid maxContains and minContains
            content = toContent([1, 1]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(2);
            (0, chai_1.expect)(result[0].message).to.include('Array has too few items matching');
            (0, chai_1.expect)(result[1].message).to.include('Array has too many items matching');
        });
        it('minContains = 0 with no maxContains', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                contains: { const: 1 },
                minContains: 0,
            });
            // empty data
            let content = toContent([]);
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // minContains = 0 makes contains always pass
            content = toContent([2]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
        });
        it('minContains = 0 with maxContains', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                contains: { const: 1 },
                minContains: 0,
                maxContains: 1,
            });
            // empty data
            let content = toContent([]);
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // not more than maxContains
            content = toContent([1]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // too many
            content = toContent([1, 1]);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Array has too many items matching');
        });
    });
    describe('keyword: dependentSchemas', () => {
        it('single dependency', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                dependentSchemas: {
                    bar: {
                        properties: {
                            foo: { type: 'integer' },
                            bar: { type: 'integer' },
                        },
                    },
                },
            });
            // valid
            let content = toContent({ foo: 1, bar: 2 });
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // no dependency
            content = toContent({ foo: 'quux' });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // wrong type
            content = toContent({ foo: 'quux', bar: 2 });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Incorrect type');
            // wrong type other
            content = toContent({ foo: 2, bar: 'quux' });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Incorrect type');
            // wrong type both
            content = toContent({ foo: 'quux', bar: 'quux' });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(2);
            (0, chai_1.expect)(result[0].message).to.include('Incorrect type');
            (0, chai_1.expect)(result[1].message).to.include('Incorrect type');
            // ignores arrays
            content = toContent(['bar']);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // ignores strings
            content = toContent('foobar');
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // ignores other non-objects
            content = toContent(12);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
        });
        it('boolean subschemas', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                dependentSchemas: {
                    foo: true,
                    bar: false,
                },
            });
            // object with property having schema true is valid
            let content = toContent({ foo: 1 });
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // object with property having schema false is invalid
            content = toContent({ bar: 2 });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Matches a schema that is not allowed');
            // object with both properties is invalid
            content = toContent({ foo: 1, bar: 2 });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Matches a schema that is not allowed');
            // empty object is valid
            content = toContent({});
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
        });
        it('dependencies with escaped characters', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                dependentSchemas: {
                    'foo\tbar': { minProperties: 4 },
                    "foo'bar": { required: ['foo"bar'] },
                },
            });
            // quoted tab
            let content = toContent({
                'foo\tbar': 1,
                a: 2,
                b: 3,
                c: 4,
            });
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // quoted quote
            content = toContent({
                "foo'bar": { 'foo"bar': 1 },
            });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Missing property');
            // quoted tab invalid under dependent schema
            content = toContent({
                'foo\tbar': 1,
                a: 2,
            });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Object has fewer properties than the required number of 4');
            // quoted quote invalid under dependent schema
            content = toContent({ "foo'bar": 1 });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Missing property');
        });
        it('dependent subschema incompatible with root', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                properties: {
                    foo: {},
                },
                dependentSchemas: {
                    foo: {
                        properties: {
                            bar: {},
                        },
                        additionalProperties: false,
                    },
                },
            });
            // matches root
            let content = toContent({ foo: 1 });
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('not allowed');
            // matches dependency
            content = toContent({ bar: 1 });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // matches both
            content = toContent({ foo: 1, bar: 2 });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('not allowed');
            // no dependency
            content = toContent({ baz: 1 });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
        });
    });
    describe('keyword: dependentRequired', () => {
        it('single dependency', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                dependentRequired: { bar: ['foo'] },
            });
            // neither
            let content = toContent({});
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // nondependant
            content = toContent({ foo: 1 });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // with dependency
            content = toContent({ foo: 1, bar: 2 });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // missing dependency
            content = toContent({ bar: 2 });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Object is missing property foo required by property bar.');
            // ignores arrays
            content = toContent(['bar']);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // ignores strings
            content = toContent('foobar');
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // ignores other non-objects
            content = toContent(12);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
        });
        it('empty dependents', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                dependentRequired: { bar: [] },
            });
            // empty object
            let content = toContent({});
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // object with one property
            content = toContent({ bar: 2 });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // non-object is valid
            content = toContent(1);
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
        });
        it('multiple dependents required', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                dependentRequired: { quux: ['foo', 'bar'] },
            });
            // neither
            let content = toContent({});
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // nondependants
            content = toContent({ foo: 1, bar: 2 });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // with dependencies
            content = toContent({ foo: 1, bar: 2, quux: 3 });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // missing dependency
            content = toContent({ foo: 1, quux: 2 });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Object is missing property bar required by property quux.');
            // missing other dependency
            content = toContent({ bar: 1, quux: 2 });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Object is missing property foo required by property quux.');
            // missing both dependencies
            content = toContent({ quux: 1 });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(2);
            (0, chai_1.expect)(result[0].message).to.include('Object is missing property foo required by property quux.');
            (0, chai_1.expect)(result[1].message).to.include('Object is missing property bar required by property quux.');
        });
        it('dependencies with escaped characters', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                $schema: 'https://json-schema.org/draft/2019-09/schema',
                dependentRequired: {
                    'foo\nbar': ['foo\rbar'],
                    'foo"bar': ["foo'bar"],
                },
            });
            // CRLF
            let content = toContent({
                'foo\nbar': 1,
                'foo\rbar': 2,
            });
            let result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // quoted quotes
            content = toContent({
                "foo'bar": 1,
                'foo"bar': 2,
            });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.be.empty;
            // CRLF missing dependent
            content = toContent({
                'foo\nbar': 1,
                foo: 2,
            });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Object is missing property foo\rbar required by property foo\nbar.');
            // quoted quotes missing dependent
            content = toContent({
                'foo"bar': 2,
            });
            result = await parseSetup(content);
            (0, chai_1.expect)(result).to.have.length(1);
            (0, chai_1.expect)(result[0].message).to.include('Object is missing property foo\'bar required by property foo"bar.');
        });
    });
});
//# sourceMappingURL=schema2019Validation.test.js.map