"use strict";
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Red Hat. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
const vscode_languageserver_types_1 = require("vscode-languageserver-types");
const yamlSettings_1 = require("../src/yamlSettings");
const serviceSetup_1 = require("./utils/serviceSetup");
const testHelper_1 = require("./utils/testHelper");
const chai_1 = require("chai");
const verifyError_1 = require("./utils/verifyError");
const path = __importStar(require("path"));
describe('Auto Completion Fix Tests', () => {
    let languageSettingsSetup;
    let languageService;
    let languageHandler;
    let yamlSettings;
    let schemaProvider;
    before(() => {
        languageSettingsSetup = new serviceSetup_1.ServiceSetup().withCompletion().withSchemaFileMatch({
            uri: 'https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.32.1-standalone-strict/all.json',
            fileMatch: [testHelper_1.SCHEMA_ID],
        });
        const { languageService: langService, languageHandler: langHandler, yamlSettings: settings, schemaProvider: testSchemaProvider, } = (0, testHelper_1.setupLanguageService)(languageSettingsSetup.languageSettings);
        languageService = langService;
        languageHandler = langHandler;
        yamlSettings = settings;
        schemaProvider = testSchemaProvider;
    });
    /**
     * Generates a completion list for the given document and caret (cursor) position.
     * @param content The content of the document.
     * @param line starts with 0 index
     * @param character starts with 1 index
     * @returns A list of valid completions.
     */
    function parseSetup(content, line, character) {
        const testTextDocument = (0, testHelper_1.setupSchemaIDTextDocument)(content);
        yamlSettings.documents = new yamlSettings_1.TextDocumentTestManager();
        yamlSettings.documents.set(testTextDocument);
        return languageHandler.completionHandler({
            position: vscode_languageserver_types_1.Position.create(line, character),
            textDocument: testTextDocument,
        });
    }
    /**
     * Generates a completion list for the given document and caret (cursor) position.
     * @param content The content of the document.
     * The caret is located in the content using `|` bookends.
     * For example, `content = 'ab|c|d'` places the caret over the `'c'`, at `position = 2`
     * @returns A list of valid completions.
     */
    function parseCaret(content) {
        const { position, content: content2 } = (0, testHelper_1.caretPosition)(content);
        const testTextDocument = (0, testHelper_1.setupSchemaIDTextDocument)(content2);
        yamlSettings.documents = new yamlSettings_1.TextDocumentTestManager();
        yamlSettings.documents.set(testTextDocument);
        return languageHandler.completionHandler({
            position: testTextDocument.positionAt(position),
            textDocument: testTextDocument,
        });
    }
    afterEach(() => {
        schemaProvider.deleteSchema(testHelper_1.SCHEMA_ID);
        languageService.configure(languageSettingsSetup.languageSettings);
    });
    it('should show completion on map under array', async () => {
        schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
            type: 'array',
            items: {
                type: 'object',
                properties: {
                    from: {
                        type: 'object',
                        properties: {
                            foo: {
                                type: 'boolean',
                            },
                        },
                    },
                },
            },
        });
        const content = '- from:\n   | |'; // len: 12, pos: 11
        const completion = await parseCaret(content);
        (0, chai_1.expect)(completion.items).lengthOf(1);
        (0, chai_1.expect)(completion.items[0]).eql((0, verifyError_1.createExpectedCompletion)('foo', 'foo: ', 1, 3, 1, 4, 10, 2, {
            documentation: '',
        }));
    });
    it('completion with array objects', async () => {
        schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
            type: 'array',
            items: {
                type: 'object',
                properties: {
                    prop1: {
                        type: 'string',
                    },
                    prop2: {
                        type: 'string',
                    },
                    prop3: {
                        type: 'string',
                    },
                },
            },
        });
        const content = '- prop1: a\n   | |'; // len: 12, pos: 11
        const completion = await parseCaret(content);
        (0, chai_1.expect)(completion.items).lengthOf(2);
        (0, chai_1.expect)(completion.items[0]).eql((0, verifyError_1.createExpectedCompletion)('prop2', 'prop2: ', 1, 3, 1, 4, 10, 2, {
            documentation: '',
        }));
        (0, chai_1.expect)(completion.items[1]).eql((0, verifyError_1.createExpectedCompletion)('prop3', 'prop3: ', 1, 3, 1, 4, 10, 2, {
            documentation: '',
        }));
    });
    it('should show completion on array empty array item', async () => {
        schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
            type: 'array',
            items: {
                type: 'object',
                properties: {
                    from: {
                        type: 'object',
                        properties: {
                            foo: {
                                type: 'boolean',
                            },
                        },
                    },
                },
            },
        });
        const content = '- '; // len: 2
        const completion = await parseSetup(content, 0, 2);
        (0, chai_1.expect)(completion.items).lengthOf(1);
        (0, chai_1.expect)(completion.items[0]).eql((0, verifyError_1.createExpectedCompletion)('from', 'from:\n    ', 0, 2, 0, 2, 10, 2, {
            documentation: '',
        }));
    });
    it('should show completion items in the middle of map in array', async () => {
        const content = `apiVersion: v1
kind: Pod
metadata:
  name: foo
spec:
  containers:
    - name: test
      
      image: alpine
    `; // len: 90
        const completion = await parseSetup(content, 7, 6);
        (0, chai_1.expect)(completion.items).length.greaterThan(1);
    });
    it('should show completion on array item on first line', async () => {
        const content = '-d'; // len: 2
        const completion = await parseSetup(content, 0, 1);
        (0, chai_1.expect)(completion.items).is.empty;
    });
    it('should complete without error on map inside array', async () => {
        const content = '- foo\n- bar:\n    so'; // len: 19
        const completion = await parseSetup(content, 2, 6);
        (0, chai_1.expect)(completion.items).is.empty;
    });
    it('should complete  array', async () => {
        // eslint-disable-next-line @typescript-eslint/no-require-imports
        const schema = require(path.join(__dirname, './fixtures/test-nested-object-array.json'));
        schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
        const content = `objA:
  - name: nameA1
      
objB:
  size: midle
  name: nameB2  
`; // len: 67
        const completion = await parseSetup(content, 2, 4);
        (0, chai_1.expect)(completion.items).is.not.empty;
    });
    it('should complete array item for "oneOf" schema', async () => {
        // eslint-disable-next-line @typescript-eslint/no-require-imports
        const schema = require(path.join(__dirname, './fixtures/test-completion-oneOf.json'));
        schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
        const content = `metadata:
  Selector:
    query:
      - 
`; // len: 42
        const completion = await parseSetup(content, 3, 8);
        (0, chai_1.expect)(completion.items).length(5);
        (0, chai_1.expect)(completion.items.map((it) => it.label)).to.have.members(['NOT', 'attribute', 'operation', 'value', 'FUNC_item']);
    });
    it('Autocomplete with short nextLine - nested object', async () => {
        schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
            type: 'object',
            properties: {
                example: {
                    type: 'object',
                    properties: {
                        sample: {
                            type: 'object',
                            properties: {
                                detail: {
                                    type: 'object',
                                },
                            },
                        },
                    },
                },
                a: {
                    type: 'string',
                    description: 'short prop name because of distance to the cursor',
                },
            },
        });
        const content = 'example:\n  sample:\n    '; // len: 23
        const completion = await parseSetup(content + '\na: test', 2, 4);
        (0, chai_1.expect)(completion.items.length).equal(1);
        (0, chai_1.expect)(completion.items[0]).to.be.deep.equal((0, verifyError_1.createExpectedCompletion)('detail', 'detail:\n  ', 2, 4, 2, 4, 10, 2, {
            documentation: '',
        }));
    });
    it('Should suggest valid matches from oneOf', async () => {
        schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
            oneOf: [
                {
                    type: 'object',
                    properties: {
                        spec: {
                            type: 'object',
                        },
                    },
                },
                {
                    properties: {
                        spec: {
                            type: 'object',
                            required: ['bar'],
                            properties: {
                                bar: {
                                    type: 'string',
                                },
                            },
                        },
                    },
                },
            ],
        });
        const content = '|s|'; // len: 1, pos: 1
        const completion = await parseCaret(content);
        (0, chai_1.expect)(completion.items.length).equal(1);
        (0, chai_1.expect)(completion.items[0]).to.be.deep.equal((0, verifyError_1.createExpectedCompletion)('spec', 'spec:\n  bar: ', 0, 0, 0, 1, 10, 2, {
            documentation: '',
        }));
    });
    it('Should suggest all the matches from allOf', async () => {
        schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
            allOf: [
                {
                    type: 'object',
                    properties: {
                        spec: {
                            type: 'object',
                        },
                    },
                },
                {
                    properties: {
                        spec: {
                            type: 'object',
                            required: ['bar'],
                            properties: {
                                bar: {
                                    type: 'string',
                                },
                            },
                        },
                    },
                },
            ],
        });
        const content = '|s|'; // len: 1, pos: 1
        const completion = await parseCaret(content);
        (0, chai_1.expect)(completion.items.length).equal(2);
        (0, chai_1.expect)(completion.items[0]).to.be.deep.equal((0, verifyError_1.createExpectedCompletion)('spec', 'spec:\n  ', 0, 0, 0, 1, 10, 2, {
            documentation: '',
        }));
        (0, chai_1.expect)(completion.items[1]).to.be.deep.equal((0, verifyError_1.createExpectedCompletion)('spec', 'spec:\n  bar: ', 0, 0, 0, 1, 10, 2, {
            documentation: '',
        }));
    });
    it('Autocomplete with a new line inside the object', async () => {
        schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
            type: 'object',
            properties: {
                example: {
                    type: 'object',
                    properties: {
                        sample: {
                            type: 'object',
                            properties: {
                                prop1: {
                                    type: 'string',
                                },
                                prop2: {
                                    type: 'string',
                                },
                            },
                        },
                    },
                },
            },
        });
        const content = 'example:\n  sample:\n    |\n|    prop2: value2'; // len: 41, pos: 23
        const completion = await parseCaret(content);
        (0, chai_1.expect)(completion.items.length).equal(1);
        (0, chai_1.expect)(completion.items[0]).to.be.deep.equal((0, verifyError_1.createExpectedCompletion)('prop1', 'prop1: ', 2, 4, 2, 4, 10, 2, {
            documentation: '',
        }));
    });
    it('Autocomplete on the first array item', async () => {
        schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
            type: 'object',
            properties: {
                examples: {
                    type: 'array',
                    items: {
                        type: 'object',
                        properties: {
                            sample: {
                                type: 'object',
                                properties: {
                                    prop1: {
                                        type: 'string',
                                    },
                                },
                            },
                        },
                    },
                },
            },
        });
        const content = 'examples:\n  |\n|  - sample:\n      prop1: value1'; // len: 44, pos: 12
        const completion = await parseCaret(content);
        (0, chai_1.expect)(completion.items.length).equal(1);
        (0, chai_1.expect)(completion.items[0]).to.be.deep.equal((0, verifyError_1.createExpectedCompletion)('- (array item) object', '- ', 1, 2, 1, 2, 9, 2, {
            documentation: {
                kind: 'markdown',
                value: 'Create an item of an array type `object`\n ```\n- \n```',
            },
        }));
    });
    it('Array of enum autocomplete of irregular order', async () => {
        schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
            type: 'object',
            properties: {
                apiVersion: {
                    type: 'string',
                },
                metadata: {
                    type: 'object',
                    properties: {
                        name: {
                            type: 'string',
                        },
                    },
                },
                kind: {
                    type: 'string',
                    enum: ['Pod', 'PodTemplate'],
                },
            },
        });
        const content = 'kind: Po'; // len: 8
        const completion = await parseSetup(content, 1, 9);
        (0, chai_1.expect)(completion.items.length).equal(2);
        (0, chai_1.expect)(completion.items[0].insertText).equal('Pod');
        (0, chai_1.expect)(completion.items[1].insertText).equal('PodTemplate');
    });
    it('Test that properties have enum of string type with number', async () => {
        schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
            type: 'object',
            properties: {
                version: {
                    type: 'array',
                    items: {
                        enum: ['12.1', 13, '13.1', '14.0', 'all', 14.4, false, null, ['test']],
                        type: ['string', 'integer', 'number', 'boolean', 'object', 'array'],
                    },
                },
            },
        });
        const content = 'version:\n  - ';
        const completion = await parseSetup(content, 2, 0);
        (0, chai_1.expect)(completion.items).lengthOf(9);
        (0, chai_1.expect)(completion.items[0].insertText).equal('"12.1"');
        (0, chai_1.expect)(completion.items[1].insertText).equal('13');
        (0, chai_1.expect)(completion.items[4].insertText).equal('all');
        (0, chai_1.expect)(completion.items[5].insertText).equal('14.4');
        (0, chai_1.expect)(completion.items[6].insertText).equal('false');
        (0, chai_1.expect)(completion.items[7].insertText).equal('null');
        (0, chai_1.expect)(completion.items[8].insertText).equal('\n  - ${1:test}\n');
    });
    it('Autocomplete indent on array when parent is array', async () => {
        schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
            type: 'object',
            properties: {
                examples: {
                    type: 'array',
                    items: {
                        type: 'object',
                        properties: {
                            objectWithArray: {
                                type: 'array',
                                items: {
                                    type: 'string',
                                },
                            },
                        },
                    },
                },
            },
        });
        const content = 'examples:\n  - '; // len: 14
        const completion = await parseSetup(content, 1, 4);
        (0, chai_1.expect)(completion.items.length).equal(1);
        (0, chai_1.expect)(completion.items[0]).to.be.deep.equal((0, verifyError_1.createExpectedCompletion)('objectWithArray', 'objectWithArray:\n    - ${1}', 1, 4, 1, 4, 10, 2, {
            documentation: '',
        }));
    });
    it('Autocomplete indent on array object when parent is array', async () => {
        schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
            type: 'object',
            properties: {
                examples: {
                    type: 'array',
                    items: {
                        type: 'object',
                        properties: {
                            objectWithArray: {
                                type: 'array',
                                items: {
                                    type: 'object',
                                    required: ['item', 'item2'],
                                    properties: {
                                        item: { type: 'string' },
                                        item2: { type: 'string' },
                                    },
                                },
                            },
                        },
                    },
                },
            },
        });
        const content = 'examples:\n  - '; // len: 14
        const completion = await parseSetup(content, 1, 4);
        (0, chai_1.expect)(completion.items.length).equal(1);
        (0, chai_1.expect)(completion.items[0]).to.be.deep.equal((0, verifyError_1.createExpectedCompletion)('objectWithArray', 'objectWithArray:\n    - item: $1\n      item2: $2', 1, 4, 1, 4, 10, 2, {
            documentation: '',
        }));
    });
    it('Autocomplete indent on array object when parent is array of an array', async () => {
        schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
            type: 'object',
            properties: {
                array1: {
                    type: 'array',
                    items: {
                        type: 'object',
                        required: ['thing1'],
                        properties: {
                            thing1: {
                                type: 'object',
                                required: ['array2'],
                                properties: {
                                    array2: {
                                        type: 'array',
                                        items: {
                                            type: 'object',
                                            required: ['thing2', 'type'],
                                            properties: {
                                                type: {
                                                    type: 'string',
                                                },
                                                thing2: {
                                                    type: 'object',
                                                    required: ['item1', 'item2'],
                                                    properties: {
                                                        item1: { type: 'string' },
                                                        item2: { type: 'string' },
                                                    },
                                                },
                                            },
                                        },
                                    },
                                },
                            },
                        },
                    },
                },
            },
        });
        const content = 'array1:\n  - ';
        const completion = await parseSetup(content, 1, 4);
        (0, chai_1.expect)(completion.items[0].insertText).to.be.equal('thing1:\n    array2:\n      - type: $1\n        thing2:\n          item1: $2\n          item2: $3');
    });
    describe('array indent on different index position', () => {
        const schema = {
            type: 'object',
            properties: {
                objectWithArray: {
                    type: 'array',
                    items: {
                        type: 'object',
                        required: ['item', 'item2'],
                        properties: {
                            item: { type: 'string' },
                            item2: {
                                type: 'object',
                                required: ['prop1', 'prop2'],
                                properties: {
                                    prop1: { type: 'string' },
                                    prop2: { type: 'string' },
                                },
                            },
                        },
                    },
                },
            },
        };
        it('array indent on the first item', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = 'objectWithArray:\n  - '; // len: 21
            const completion = await parseSetup(content, 1, 4);
            (0, chai_1.expect)(completion.items.length).equal(3);
            (0, chai_1.expect)(completion.items[0]).to.be.deep.equal((0, verifyError_1.createExpectedCompletion)('item', 'item: ', 1, 4, 1, 4, 10, 2, {
                documentation: '',
            }));
            (0, chai_1.expect)(completion.items[2]).to.be.deep.equal((0, verifyError_1.createExpectedCompletion)('item2', 'item2:\n    prop1: $1\n    prop2: $2', 1, 4, 1, 4, 10, 2, {
                documentation: '',
            }));
        });
        it('array indent on the second item', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = 'objectWithArray:\n  - item: first line\n    '; // len: 42
            const completion = await parseSetup(content, 2, 4);
            (0, chai_1.expect)(completion.items.length).equal(2);
            (0, chai_1.expect)(completion.items[0]).to.be.deep.equal((0, verifyError_1.createExpectedCompletion)('item2', 'item2:\n  prop1: $1\n  prop2: $2', 2, 4, 2, 4, 10, 2, {
                documentation: '',
            }));
        });
    });
    describe('merge properties from anyOf objects', () => {
        it('should merge different simple values', async () => {
            const schema = {
                anyOf: [
                    {
                        properties: {
                            simplePropWithSimpleValue: { type: 'string', const: 'const value' },
                        },
                    },
                    {
                        properties: {
                            simplePropWithSimpleValue: { type: 'boolean', default: false },
                        },
                    },
                    {
                        properties: {
                            simplePropWithSimpleValue: { type: 'null', default: null },
                        },
                    },
                    {
                        properties: {
                            simplePropWithSimpleValue: { type: 'string' },
                        },
                    },
                ],
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = '';
            const completion = await parseSetup(content, 0, 1);
            (0, chai_1.expect)(completion.items.length).equal(1);
            (0, chai_1.expect)(completion.items[0].insertText).to.be.equal('simplePropWithSimpleValue: ${1|const value,false,null|}');
        });
        it('should autocomplete as single item with same value', async () => {
            const schema = {
                anyOf: [
                    {
                        properties: {
                            simplePropWithSameValue: { type: 'string', const: 'const value 1' },
                            obj1: { properties: { prop1: { type: 'string' } } },
                        },
                    },
                    {
                        properties: {
                            simplePropWithSameValue: { type: 'string', const: 'const value 1' },
                            obj1: { properties: { prop1: { type: 'string' } } },
                        },
                    },
                ],
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = '';
            const completion = await parseSetup(content, 0, 1);
            (0, chai_1.expect)(completion.items.length).equal(2);
            (0, chai_1.expect)(completion.items[0].insertText).to.be.equal('simplePropWithSameValue: const value 1');
            (0, chai_1.expect)(completion.items[1].insertText).to.be.equal('obj1:\n  ');
        });
        it('should not merge objects', async () => {
            const schema = {
                anyOf: [
                    {
                        properties: {
                            obj1: { properties: { prop1: { type: 'string' } }, required: ['prop1'] },
                        },
                    },
                    {
                        properties: {
                            obj1: { properties: { prop2: { type: 'string', const: 'value' } }, required: ['prop2'] },
                        },
                    },
                ],
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = '';
            const completion = await parseSetup(content, 0, 1);
            (0, chai_1.expect)(completion.items.length).equal(2);
            (0, chai_1.expect)(completion.items[0].label).to.be.equal('obj1');
            (0, chai_1.expect)(completion.items[0].insertText).to.be.equal('obj1:\n  prop1: ');
            (0, chai_1.expect)(completion.items[1].label).to.be.equal('obj1');
            (0, chai_1.expect)(completion.items[1].insertText).to.be.equal('obj1:\n  prop2: ${1:value}');
        });
        it('Autocomplete should not suggest items for parent object', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    scripts: {
                        type: 'object',
                        properties: {
                            sample: {
                                type: 'string',
                            },
                        },
                    },
                    scripts2: {
                        type: 'string',
                    },
                },
            });
            const content = 'scripts:   \n  sample: | |';
            const completion = await parseSetup(content, 0, 9); // before line brake
            (0, chai_1.expect)(completion.items.length).equal(0);
        });
        it('autoCompletion when value is null inside anyOf object', async () => {
            const schema = {
                anyOf: [
                    {
                        properties: {
                            prop: {
                                const: 'const value',
                            },
                        },
                    },
                    {
                        properties: {
                            prop: {
                                type: 'null',
                            },
                        },
                    },
                ],
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = '';
            const completion = await parseSetup(content, 0, 6);
            (0, chai_1.expect)(completion.items.length).equal(1);
            (0, chai_1.expect)(completion.items[0].label).to.be.equal('prop');
            (0, chai_1.expect)(completion.items[0].insertText).to.be.equal('prop: ${1|const value,null|}');
        });
        it('should take all sub-schemas when value has not been set (cursor in the middle of the empty space)', async () => {
            const schema = {
                anyOf: [
                    {
                        properties: {
                            prop: { type: 'null' },
                        },
                    },
                    {
                        properties: {
                            prop: { const: 'const value' },
                        },
                    },
                    {
                        properties: {
                            prop: { const: 5 },
                        },
                    },
                ],
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = 'prop: | | ';
            const completion = await parseCaret(content);
            (0, chai_1.expect)(completion.items.map((i) => i.label)).to.be.deep.eq(['const value', '5', 'null']);
        });
        it('should take only null sub-schema when value is "null"', async () => {
            const schema = {
                anyOf: [
                    {
                        properties: {
                            prop: { type: 'null' },
                        },
                    },
                    {
                        properties: {
                            prop: { const: 'const value' },
                        },
                    },
                ],
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = 'prop: null';
            const completion = await parseSetup(content, 0, content.length);
            (0, chai_1.expect)(completion.items.map((i) => i.label)).to.be.deep.eq(['null']);
        });
        it('should take only one sub-schema because first sub-schema does not match', async () => {
            const schema = {
                anyOf: [
                    {
                        properties: {
                            prop: { const: 'const value' },
                        },
                    },
                    {
                        properties: {
                            prop: { const: 'const value2' },
                        },
                    },
                ],
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = 'prop: const value2';
            const completion = await parseSetup(content, 0, content.length);
            (0, chai_1.expect)(completion.items.map((i) => i.label)).to.be.deep.eq(['const value2']);
        });
        it('should match only second sub-schema because the first one does not match', async () => {
            const schema = {
                anyOf: [
                    {
                        properties: {
                            prop: {
                                const: 'typeA',
                            },
                            propA: {},
                        },
                    },
                    {
                        properties: {
                            prop: {
                                const: 'typeB',
                            },
                            propB: {},
                        },
                    },
                ],
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = 'prop: typeB\n|\n|';
            const completion = await parseCaret(content);
            (0, chai_1.expect)(completion.items.map((i) => i.label)).to.be.deep.eq(['propB']);
        });
        it('should suggest from all sub-schemas even if nodes properties match better other schema', async () => {
            // this is a case when we have a better match in the second schema but we should still suggest from the first one
            // it works because `prop: ` will evaluate to `enumValueMatch = true` for both schemas
            const schema = {
                anyOf: [
                    {
                        properties: {
                            prop: {
                                const: 'typeA',
                            },
                        },
                    },
                    {
                        properties: {
                            prop: {
                                const: 'typeB',
                            },
                            propB: {},
                        },
                    },
                ],
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = 'prop: |\n|\npropB: B';
            const completion = await parseCaret(content);
            (0, chai_1.expect)(completion.items.map((i) => i.label)).to.be.deep.eq(['typeA', 'typeB'], 'with null value');
            const content2 = 'prop: typ|\n|\npropB: B';
            const completion2 = await parseCaret(content2);
            (0, chai_1.expect)(completion2.items.map((i) => i.label)).to.be.deep.eq(['typeA', 'typeB'], 'with prefix value');
        });
        it('should suggest both sub-schemas for anyof array', async () => {
            const schema = {
                properties: {
                    entities: {
                        type: 'array',
                        items: {
                            anyOf: [
                                {
                                    enum: ['enum1'],
                                },
                                {
                                    type: 'object',
                                    title: 'entity object',
                                    properties: {
                                        entityProp: { type: 'string' },
                                    },
                                    required: ['entityProp'],
                                },
                            ],
                        },
                    },
                },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = 'entities:\n  - |\n|';
            const completion = await parseCaret(content);
            (0, chai_1.expect)(completion.items.map((i) => i.label)).to.be.deep.eq(['enum1', 'entityProp', 'entity object']);
        });
    });
    describe('conditional schemas', () => {
        it('should not suggest value from conditional if branch', async () => {
            const schema = {
                required: ['on'],
                type: 'object',
                properties: {
                    on: {
                        type: 'object',
                        properties: {
                            workflow_dispatch: {
                                $comment: 'https://github.blog/changelog/2020-07-06-github-actions-manual-triggers-with-workflow_dispatch/',
                                description: "You can now create workflows that are manually triggered with the new workflow_dispatch event. You will then see a 'Run workflow' button on the Actions tab, enabling you to easily trigger a run.",
                                properties: {
                                    inputs: {
                                        $comment: 'https://help.github.com/en/github/automating-your-workflow-with-github-actions/metadata-syntax-for-github-actions#inputs',
                                        description: 'Input parameters allow you to specify data that the action expects to use during runtime. GitHub stores input parameters as environment variables. Input ids with uppercase letters are converted to lowercase during runtime. We recommended using lowercase input ids.',
                                        type: 'object',
                                        patternProperties: {
                                            '^[_a-zA-Z][a-zA-Z0-9_-]*$': {
                                                $ref: '#/definitions/workflowDispatchInput',
                                            },
                                        },
                                        additionalProperties: false,
                                    },
                                },
                                additionalProperties: false,
                            },
                        },
                    },
                    jobs: {
                        type: 'object',
                    },
                },
                definitions: {
                    workflowDispatchInput: {
                        $comment: 'https://help.github.com/en/github/automating-your-workflow-with-github-actions/metadata-syntax-for-github-actions#inputsinput_id',
                        description: "A string identifier to associate with the input. The value of <input_id> is a map of the input's metadata. The <input_id> must be a unique identifier within the inputs object. The <input_id> must start with a letter or _ and contain only alphanumeric characters, -, or _.",
                        type: 'object',
                        properties: {
                            description: {
                                $comment: 'https://help.github.com/en/github/automating-your-workflow-with-github-actions/metadata-syntax-for-github-actions#inputsinput_iddescription',
                                description: 'A string description of the input parameter.',
                                type: 'string',
                            },
                            deprecationMessage: {
                                description: 'A string shown to users using the deprecated input.',
                                type: 'string',
                            },
                            required: {
                                $comment: 'https://help.github.com/en/github/automating-your-workflow-with-github-actions/metadata-syntax-for-github-actions#inputsinput_idrequired',
                                description: 'A boolean to indicate whether the action requires the input parameter. Set to true when the parameter is required.',
                                type: 'boolean',
                            },
                            default: {
                                $comment: 'https://help.github.com/en/github/automating-your-workflow-with-github-actions/metadata-syntax-for-github-actions#inputsinput_iddefault',
                                description: "A string representing the default value. The default value is used when an input parameter isn't specified in a workflow file.",
                            },
                            type: {
                                $comment: 'https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#onworkflow_dispatchinputsinput_idtype',
                                description: 'A string representing the type of the input.',
                                type: 'string',
                                enum: ['string', 'choice', 'boolean', 'number', 'environment'],
                            },
                            options: {
                                $comment: 'https://github.blog/changelog/2021-11-10-github-actions-input-types-for-manual-workflows',
                                description: 'The options of the dropdown list, if the type is a choice.',
                                type: 'array',
                                items: {
                                    type: 'string',
                                },
                                minItems: 1,
                            },
                        },
                        allOf: [
                            {
                                if: {
                                    properties: {
                                        type: {
                                            const: 'string',
                                        },
                                    },
                                    required: ['type'],
                                },
                                then: {
                                    properties: {
                                        default: {
                                            type: 'string',
                                        },
                                    },
                                },
                            },
                            {
                                if: {
                                    properties: {
                                        type: {
                                            const: 'boolean',
                                        },
                                    },
                                    required: ['type'],
                                },
                                then: {
                                    properties: {
                                        default: {
                                            type: 'boolean',
                                        },
                                    },
                                },
                            },
                            {
                                if: {
                                    properties: {
                                        type: {
                                            const: 'number',
                                        },
                                    },
                                    required: ['type'],
                                },
                                then: {
                                    properties: {
                                        default: {
                                            type: 'number',
                                        },
                                    },
                                },
                            },
                            {
                                if: {
                                    properties: {
                                        type: {
                                            const: 'environment',
                                        },
                                    },
                                    required: ['type'],
                                },
                                then: {
                                    properties: {
                                        default: {
                                            type: 'string',
                                        },
                                    },
                                },
                            },
                            {
                                if: {
                                    properties: {
                                        type: {
                                            const: 'choice',
                                        },
                                    },
                                    required: ['type'],
                                },
                                then: {
                                    required: ['options'],
                                },
                            },
                        ],
                        additionalProperties: false,
                    },
                },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = `name: Check configuration schema changes

on:
  workflow_dispatch:
    inputs:
      sdaf:
        

jobs:
  foo:
    uses: repo/test.yml@main`;
            const completion = await parseSetup(content, 7, 8);
            const labels = completion.items.map((i) => i.label);
            (0, chai_1.expect)(labels).to.include.members(['description', 'required', 'default', 'type', 'options']);
            (0, chai_1.expect)(labels.filter((label) => label === 'GitHub Workflow')).to.be.empty;
        });
    });
    describe('extra space after cursor', () => {
        it('simple const', async () => {
            const schema = {
                properties: {
                    prop: {
                        const: 'const',
                    },
                },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = 'prop: | | '; // len: 8, pos: 6
            const completion = await parseCaret(content);
            (0, chai_1.expect)(completion.items.length).equal(1);
            (0, chai_1.expect)(completion.items[0].label).to.be.equal('const');
            (0, chai_1.expect)(completion.items[0].textEdit).to.be.deep.equal({ newText: 'const', range: vscode_languageserver_types_1.Range.create(0, 6, 0, 8) });
        });
        it('partial key with trailing spaces', async () => {
            const schema = {
                properties: {
                    name: {
                        const: 'my name',
                    },
                },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = 'na  ';
            const completion = await parseSetup(content, 0, 2);
            (0, chai_1.expect)(completion.items.length).equal(1);
            (0, chai_1.expect)(completion.items[0]).eql((0, verifyError_1.createExpectedCompletion)('name', 'name: my name', 0, 0, 0, 4, 10, 2, {
                documentation: '',
            }));
        });
        it('partial key with trailing spaces with new line', async () => {
            const schema = {
                properties: {
                    name: {
                        const: 'my name',
                    },
                },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = 'na  \n';
            const completion = await parseSetup(content, 0, 2);
            (0, chai_1.expect)(completion.items.length).equal(1);
            (0, chai_1.expect)(completion.items[0]).eql((0, verifyError_1.createExpectedCompletion)('name', 'name: my name', 0, 0, 0, 5, 10, 2, {
                documentation: '',
            }));
        });
        it('partial key with leading and trailing spaces', async () => {
            const schema = {
                properties: {
                    name: {
                        const: 'my name',
                    },
                },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = '  na  ';
            const completion = await parseSetup(content, 0, 2);
            (0, chai_1.expect)(completion.items.length).equal(1);
            (0, chai_1.expect)(completion.items[0]).eql((0, verifyError_1.createExpectedCompletion)('name', 'name: my name', 0, 2, 0, 4, 10, 2, {
                documentation: '',
            }));
        });
        it('partial key with trailing spaces with special chars inside the array', async () => {
            const schema = {
                type: 'object',
                properties: {
                    array: {
                        type: 'array',
                        items: {
                            type: 'object',
                            properties: {
                                'name / 123': {
                                    const: 'my name',
                                },
                            },
                        },
                    },
                },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = 'array:\n - name /   ';
            const completion = await parseSetup(content, 1, 9);
            (0, chai_1.expect)(completion.items.length).equal(1);
            (0, chai_1.expect)(completion.items[0]).eql((0, verifyError_1.createExpectedCompletion)('name / 123', 'name / 123: my name', 1, 3, 1, 12, 10, 2, {
                documentation: '',
            }));
        });
        describe('partial value with trailing spaces', () => {
            it('partial value with trailing spaces', async () => {
                const schema = {
                    properties: {
                        name: {
                            const: 'my name',
                        },
                    },
                };
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
                const content = 'name: my| |   ';
                const completion = await parseCaret(content);
                (0, chai_1.expect)(completion.items.length).equal(1);
                (0, chai_1.expect)(completion.items[0]).eql((0, verifyError_1.createExpectedCompletion)('my name', 'my name', 0, 6, 0, 12, 12, 2, {
                    documentation: undefined,
                }));
            });
            it('partial value with trailing spaces with new line', async () => {
                const schema = {
                    properties: {
                        name: {
                            const: 'my name',
                        },
                    },
                };
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
                const content = 'name: my| |   \n';
                const completion = await parseCaret(content);
                (0, chai_1.expect)(completion.items.length).equal(1);
                (0, chai_1.expect)(completion.items[0]).eql((0, verifyError_1.createExpectedCompletion)('my name', 'my name', 0, 6, 0, 13, 12, 2, {
                    documentation: undefined,
                }));
            });
            it('partial value with leading and trailing spaces', async () => {
                const schema = {
                    properties: {
                        name: {
                            const: 'my name',
                        },
                    },
                };
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
                const content = 'name:   my na| |   ';
                const completion = await parseCaret(content);
                (0, chai_1.expect)(completion.items.length).equal(1);
                (0, chai_1.expect)(completion.items[0]).eql((0, verifyError_1.createExpectedCompletion)('my name', 'my name', 0, 6, 0, 17, 12, 2, {
                    documentation: undefined,
                }));
            });
            it('partial value with trailing spaces with special chars inside the array', async () => {
                const schema = {
                    type: 'object',
                    properties: {
                        array: {
                            type: 'array',
                            items: {
                                type: 'object',
                                properties: {
                                    name: {
                                        const: 'my name / 123',
                                    },
                                },
                            },
                        },
                    },
                };
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
                const content = 'array:\n - name: my name /| |  ';
                const completion = await parseCaret(content);
                (0, chai_1.expect)(completion.items.length).equal(1);
                (0, chai_1.expect)(completion.items[0]).eql((0, verifyError_1.createExpectedCompletion)('my name / 123', 'my name / 123', 1, 9, 1, 21, 12, 2, {
                    documentation: undefined,
                }));
            });
        });
        it('object - 2nd nested property', async () => {
            const schema = {
                properties: {
                    parent: {
                        properties: {
                            prop1: {
                                const: 'const1',
                            },
                            prop2: {
                                const: 'const2',
                            },
                        },
                    },
                },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = 'parent:\n  prop1: const1\n  prop2:   ';
            const completion = await parseSetup(content, 2, 9);
            (0, chai_1.expect)(completion.items.length).equal(1);
            (0, chai_1.expect)(completion.items[0].label).to.be.equal('const2');
            (0, chai_1.expect)(completion.items[0].textEdit).to.be.deep.equal({
                newText: 'const2',
                range: vscode_languageserver_types_1.Range.create(2, 9, 2, 11),
            });
        });
        it('array - 2nd nested property', async () => {
            const schema = {
                properties: {
                    arrayObj: {
                        type: 'array',
                        items: {
                            type: 'object',
                            properties: {
                                item1: {
                                    type: 'string',
                                },
                                item2: {
                                    const: 'const2',
                                },
                            },
                            required: ['item1', 'item2'],
                        },
                    },
                },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = 'arrayObj:\n  - item1: test\n  - item2:   ';
            const completion = await parseSetup(content, 2, 11);
            (0, chai_1.expect)(completion.items.length).equal(1);
            (0, chai_1.expect)(completion.items[0].label).to.be.equal('const2');
            (0, chai_1.expect)(completion.items[0].textEdit).to.be.deep.equal({
                newText: 'const2',
                range: vscode_languageserver_types_1.Range.create(2, 11, 2, 13),
            });
        });
        describe('array object item', () => {
            const schema = {
                properties: {
                    arrayObj: {
                        type: 'array',
                        items: {
                            type: 'object',
                            properties: {
                                item1: {
                                    type: 'string',
                                },
                                item2: {
                                    type: 'string',
                                },
                            },
                            required: ['item1', 'item2'],
                        },
                    },
                },
            };
            it('1st item', async () => {
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
                const content = 'arrayObj:\n  -   ';
                const completion = await parseSetup(content, 1, 4);
                (0, chai_1.expect)(completion.items.length).equal(3);
                (0, chai_1.expect)(completion.items[1].textEdit).to.be.deep.equal({
                    newText: 'item1: $1\n  item2: $2',
                    range: vscode_languageserver_types_1.Range.create(1, 4, 1, 6), // removes extra spaces after cursor
                });
            });
            it('next item', async () => {
                schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
                const content = 'arrayObj:\n  - item1: a\n  - item2: b\n  -   ';
                const completion = await parseSetup(content, 3, 4);
                (0, chai_1.expect)(completion.items.length).equal(3);
                (0, chai_1.expect)(completion.items[1].textEdit).to.be.deep.equal({
                    newText: 'item1: $1\n  item2: $2',
                    range: vscode_languageserver_types_1.Range.create(3, 4, 3, 6), // removes extra spaces after cursor
                });
            });
        });
        it('array completion - should suggest correct indent when extra spaces after cursor', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    test: {
                        type: 'array',
                        items: {
                            type: 'object',
                            properties: {
                                objA: {
                                    type: 'object',
                                    required: ['itemA'],
                                    properties: {
                                        itemA: {
                                            type: 'string',
                                        },
                                    },
                                },
                            },
                        },
                    },
                },
            });
            const content = 'test:\n  -               ';
            const result = await parseSetup(content, 1, 4);
            (0, chai_1.expect)(result.items.length).to.be.equal(1);
            (0, chai_1.expect)(result.items[0].insertText).to.be.equal('objA:\n    itemA: ');
        });
        it('array of arrays completion - should suggest correct indent when extra spaces after cursor', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    array1: {
                        type: 'array',
                        items: {
                            type: 'object',
                            required: ['array2'],
                            properties: {
                                array2: {
                                    type: 'array',
                                    items: {
                                        type: 'object',
                                        required: ['objA'],
                                        properties: {
                                            objA: {
                                                type: 'object',
                                                required: ['itemA'],
                                                properties: {
                                                    itemA: {
                                                        type: 'string',
                                                    },
                                                },
                                            },
                                        },
                                    },
                                },
                            },
                        },
                    },
                },
            });
            const content = 'array1:\n  -               ';
            const result = await parseSetup(content, 1, 4);
            (0, chai_1.expect)(result.items.length).to.be.equal(2);
            (0, chai_1.expect)(result.items[0].insertText).to.be.equal('array2:\n    - objA:\n        itemA: ');
        });
        it('object of array of arrays completion - should suggest correct indent when extra spaces after cursor', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, {
                type: 'object',
                properties: {
                    array1: {
                        type: 'array',
                        items: {
                            type: 'object',
                            properties: {
                                array2: {
                                    type: 'array',
                                    items: {
                                        type: 'object',
                                        properties: {
                                            objA: {
                                                type: 'object',
                                                required: ['itemA'],
                                                properties: {
                                                    itemA: {
                                                        type: 'string',
                                                    },
                                                },
                                            },
                                        },
                                    },
                                },
                            },
                        },
                    },
                },
            });
            const content = 'array1:\n  - array2:\n      -               ';
            const result = await parseSetup(content, 2, 8);
            (0, chai_1.expect)(result.items.length).to.be.equal(1);
            (0, chai_1.expect)(result.items[0].insertText).to.be.equal('objA:\n    itemA: ');
        });
    }); //'extra space after cursor'
    it('should suggest from additionalProperties', async () => {
        const schema = {
            type: 'object',
            additionalProperties: {
                anyOf: [
                    {
                        type: 'string',
                        const: 'test1',
                    },
                ],
            },
        };
        schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
        const content = 'value: ';
        const completion = await parseSetup(content, 0, content.length);
        (0, chai_1.expect)(completion.items.length).equal(1);
        (0, chai_1.expect)(completion.items[0].insertText).to.be.equal('test1');
    });
    it('should suggest defaultSnippets from additionalProperties', async () => {
        const schema = {
            type: 'object',
            properties: {
                id: {
                    type: 'string',
                },
            },
            additionalProperties: {
                anyOf: [
                    {
                        type: 'string',
                        defaultSnippets: [{ label: 'snippet', body: 'snippetBody' }],
                    },
                ],
            },
        };
        schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
        const content = 'value: |\n|';
        const completion = await parseCaret(content);
        (0, chai_1.expect)(completion.items.map((i) => i.insertText)).to.be.deep.equal(['snippetBody']);
    });
    describe('should suggest prop of the object (based on not completed prop name)', () => {
        const schema = {
            definitions: {
                Obj: {
                    anyOf: [
                        { type: 'string' },
                        {
                            type: 'object',
                            properties: {
                                prop1: { type: 'string' },
                            },
                            required: ['prop1'],
                        },
                    ],
                },
            },
            properties: {
                test1: {
                    properties: {
                        nested: { $ref: '#/definitions/Obj' },
                    },
                },
                test2: { $ref: '#/definitions/Obj' },
            },
        };
        const content = `
test2: 
  pr
test1:
  nested: 
    pr
`;
        it('nested object', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const completion = await parseSetup(content, 5, 6);
            (0, chai_1.expect)(completion.items.length).equal(2);
            (0, chai_1.expect)(completion.items[0].label).to.be.equal('prop1');
        });
        it('root object', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const completion = await parseSetup(content, 2, 4);
            (0, chai_1.expect)(completion.items.length).equal(2);
            (0, chai_1.expect)(completion.items[0].label).to.be.equal('prop1');
        });
    });
    describe('should suggest property before indented comment', () => {
        const schema = {
            type: 'object',
            properties: {
                example: {
                    type: 'object',
                    properties: {
                        prop1: {
                            type: 'string',
                        },
                        prop2: {
                            type: 'string',
                        },
                        prop3: {
                            type: 'string',
                        },
                    },
                },
            },
        };
        it('completion should handle indented comment on new line', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = 'example:\n  prop1: "test"\n  \n    #comment';
            const completion = await parseSetup(content, 2, 2);
            (0, chai_1.expect)(completion.items.length).equal(2);
            (0, chai_1.expect)(completion.items[0]).to.be.deep.equal((0, verifyError_1.createExpectedCompletion)('prop2', 'prop2: ', 2, 2, 2, 2, vscode_languageserver_types_1.CompletionItemKind.Property, vscode_languageserver_types_1.InsertTextFormat.Snippet, {
                documentation: '',
            }));
        });
        it('completion should handle comment at same indent level on new line', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = 'example:\n  prop1: "test"\n  \n  #comment';
            const completion = await parseSetup(content, 2, 2);
            (0, chai_1.expect)(completion.items.length).equal(2);
            (0, chai_1.expect)(completion.items[0]).to.be.deep.equal((0, verifyError_1.createExpectedCompletion)('prop2', 'prop2: ', 2, 2, 2, 2, vscode_languageserver_types_1.CompletionItemKind.Property, vscode_languageserver_types_1.InsertTextFormat.Snippet, {
                documentation: '',
            }));
        });
        it('completion should handle suggestion without comment on next line', async () => {
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
            const content = 'example:\n  prop1: "test"\n  \n  prop3: "test"';
            const completion = await parseSetup(content, 2, 2);
            (0, chai_1.expect)(completion.items.length).equal(1);
            (0, chai_1.expect)(completion.items[0]).to.be.deep.equal((0, verifyError_1.createExpectedCompletion)('prop2', 'prop2: ', 2, 2, 2, 2, vscode_languageserver_types_1.CompletionItemKind.Property, vscode_languageserver_types_1.InsertTextFormat.Snippet, {
                documentation: '',
            }));
        });
    });
    it('should suggest property of unknown object', async () => {
        const schema = {
            type: 'object',
            additionalProperties: true,
            propertyNames: {
                title: 'property',
                description: 'Property Description',
            },
        };
        schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
        const content = '';
        const completion = await parseSetup(content, 0, content.length);
        (0, chai_1.expect)(completion.items.length).equal(1);
        (0, chai_1.expect)(completion.items[0].insertText).to.be.equal('${1:property}: ');
        (0, chai_1.expect)(completion.items[0].documentation).to.be.deep.equal({ kind: 'markdown', value: 'Property Description' });
    });
    it('should not suggest propertyNames with doNotSuggest', async () => {
        const schema = {
            type: 'object',
            additionalProperties: true,
            propertyNames: {
                title: 'property',
                doNotSuggest: true,
            },
        };
        schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
        const content = '';
        const completion = await parseSetup(content, 0, content.length);
        (0, chai_1.expect)(completion.items.length).equal(0);
    });
    it('should suggest enum based on type', async () => {
        const schema = {
            type: 'object',
            additionalProperties: false,
            properties: {
                test: {
                    type: 'string',
                    enum: ['YES', 'NO'],
                },
            },
        };
        schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
        const content = 'test: ';
        const completion = await parseSetup(content, 0, content.length);
        (0, chai_1.expect)(completion.items.length).equal(2);
        (0, chai_1.expect)(completion.items[0].insertText).to.be.equal('"YES"');
        (0, chai_1.expect)(completion.items[1].insertText).to.be.equal('"NO"');
    });
    it('should suggest propertyNames keys from definitions $ref', async () => {
        const schema = {
            definitions: {
                EventName: {
                    type: 'string',
                    title: 'EventName',
                    enum: ['None', 'Event1', 'Event2'],
                },
            },
            type: 'object',
            properties: {
                events: {
                    type: 'object',
                    propertyNames: { $ref: '#/definitions/EventName' },
                },
            },
            required: ['events'],
        };
        schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
        const completion = await parseSetup('events:\n  ', 1, 2);
        (0, chai_1.expect)(completion.items.map((i) => i.label)).to.have.members(['None', 'Event1', 'Event2']);
    });
    it('should suggest propertyNames candidates from const', async () => {
        const schema = {
            type: 'object',
            propertyNames: {
                const: 'Event0',
            },
        };
        schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
        const completion = await parseSetup('', 0, 0);
        (0, chai_1.expect)(completion.items.map((i) => i.label)).to.have.members(['Event0']);
    });
    it('should suggest propertyNames candidates from enum', async () => {
        const schema = {
            type: 'object',
            additionalProperties: true,
            propertyNames: {
                enum: ['Event1', 'Event2', 'Event3'],
            },
        };
        schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
        const completion = await parseSetup('', 0, 0);
        (0, chai_1.expect)(completion.items.map((i) => i.label)).to.have.members(['Event1', 'Event2', 'Event3']);
    });
    it('should suggest propertyNames candidates from oneOf', async () => {
        const schema = {
            type: 'object',
            propertyNames: {
                oneOf: [{ const: 'Event1' }, { const: 'Event2' }],
            },
        };
        schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
        const completion = await parseSetup('', 0, 0);
        (0, chai_1.expect)(completion.items.map((i) => i.label)).to.have.members(['Event1', 'Event2']);
    });
    it('should suggest propertyNames candidates from anyOf', async () => {
        const schema = {
            type: 'object',
            propertyNames: {
                anyOf: [{ const: 'Event1' }, { enum: ['Event2', 'Event3'] }],
            },
        };
        schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
        const completion = await parseSetup('', 0, 0);
        (0, chai_1.expect)(completion.items.map((i) => i.label)).to.have.members(['Event1', 'Event2', 'Event3']);
    });
    it('should suggest only the intersected propertyNames candidate from allOf (const + enum)', async () => {
        const schema = {
            type: 'object',
            propertyNames: {
                allOf: [{ const: 'One' }, { enum: ['One', 'Two'] }],
            },
        };
        schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
        const completion = await parseSetup('', 0, 0);
        (0, chai_1.expect)(completion.items.map((i) => i.label)).to.have.members(['One']);
        (0, chai_1.expect)(completion.items.map((i) => i.label)).to.not.include('Two');
    });
    it('should not suggest any propertyNames when allOf makes keys impossible (const + const)', async () => {
        const schema = {
            type: 'object',
            propertyNames: {
                allOf: [{ const: 'One' }, { const: 'Two' }],
            },
        };
        schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
        const completion = await parseSetup('', 0, 0);
        (0, chai_1.expect)(completion.items).to.be.empty;
    });
    describe('String scalar completion comprehensive tests', () => {
        const STRING_CASES = [
            { value: '', expected: '""', description: 'empty string' },
            { value: '""', expected: '"\\"\\""', description: 'literal double quotes' },
            { value: "''", expected: `"''"`, description: 'literal single quotes' },
            { value: '"', expected: '"\\""', description: 'single quote character' },
            { value: "'", expected: '"\'"', description: 'single apostrophe' },
            { value: 'a: b', expected: '"a: b"', description: 'string with colon and space' },
            { value: '# not a comment', expected: '"# not a comment"', description: 'string starting with hash' },
            { value: '- starts with dash', expected: '"- starts with dash"', description: 'string starting with dash' },
            {
                value: '? starts with question',
                expected: '"? starts with question"',
                description: 'string starting with question mark',
            },
            { value: 'null', expected: '"null"', description: 'string "null"' },
            { value: '123', expected: '"123"', description: 'numeric string' },
            { value: '  leading space', expected: '"  leading space"', description: 'string with leading spaces' },
            { value: 'trailing space ', expected: '"trailing space "', description: 'string with trailing space' },
            {
                value: 'line1\n\tline2',
                expected: '"line1\\n\\tline2"',
                expectedLabel: '"line1↵\\tline2"',
                description: 'string with newline and tab',
            },
            { value: 'endsWithColon:', expected: '"endsWithColon:"', description: 'string ending with colon' },
            { value: '0xdeadbeef', expected: '"0xdeadbeef"', description: 'hex-like string' },
            { value: '01', expected: '"01"', description: 'octal-like string' },
            { value: '0o12', expected: '"0o12"', description: 'octal-like string with prefix' },
            { value: '\\"', expected: '"\\\\\\\\\\""', description: 'backslash-quote' },
        ];
        const addEnumSchema = (value) => {
            const schema = {
                type: 'object',
                additionalProperties: false,
                properties: {
                    testProp: {
                        type: 'string',
                        enum: [value],
                    },
                },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
        };
        describe('Enum', () => {
            STRING_CASES.forEach(({ value, expected, description }) => {
                describe(description, () => {
                    beforeEach(() => addEnumSchema(value));
                    it('should handle enum key value', async () => {
                        const content = '';
                        const completion = await parseSetup(content, 0, content.length);
                        (0, chai_1.expect)(completion.items.length).to.equal(1);
                        (0, chai_1.expect)(completion.items[0].insertText).to.equal(`testProp: \${1:${expected}}`);
                    });
                    it('should handle enum value after property name', async () => {
                        const content = 'testProp: ';
                        const completion = await parseSetup(content, 0, content.length);
                        (0, chai_1.expect)(completion.items.length).to.equal(1);
                        (0, chai_1.expect)(completion.items[0].insertText).to.equal(expected);
                    });
                });
            });
        });
        const addConstSchema = (value) => {
            const schema = {
                type: 'object',
                additionalProperties: false,
                properties: {
                    testProp: {
                        type: 'string',
                        const: value,
                    },
                },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
        };
        describe('Const', () => {
            STRING_CASES.forEach(({ value, expected, expectedLabel, description }) => {
                describe(description, () => {
                    beforeEach(() => addConstSchema(value));
                    it('should handle const key value', async () => {
                        const content = 'test';
                        const completion = await parseSetup(content, 0, content.length);
                        (0, chai_1.expect)(completion.items.length).to.equal(1);
                        (0, chai_1.expect)(completion.items[0].insertText).to.equal(`testProp: ${expected}`);
                    });
                    it('should handle const value after property name', async () => {
                        const content = 'testProp: ';
                        const completion = await parseSetup(content, 0, content.length);
                        (0, chai_1.expect)(completion.items.length).to.be.greaterThan(0);
                        (0, chai_1.expect)(completion.items[0].insertText).to.equal(expected);
                        // Only assert label when we expect it to differ (e.g., newline rendering)
                        if (expectedLabel !== undefined) {
                            (0, chai_1.expect)(completion.items[0].label).to.equal(expectedLabel);
                        }
                    });
                });
            });
        });
        const addPropertyNameSchema = (propName) => {
            const schema = {
                type: 'object',
                additionalProperties: false,
                properties: {
                    [propName]: { type: 'string' },
                },
            };
            schemaProvider.addSchema(testHelper_1.SCHEMA_ID, schema);
        };
        describe('Property name (key)', () => {
            STRING_CASES.filter(({ value }) => value !== '').forEach(({ value, expected, description }) => {
                describe(description, () => {
                    beforeEach(() => addPropertyNameSchema(value));
                    it('should handle property name completion', async () => {
                        const content = '';
                        const completion = await parseSetup(content, 0, content.length);
                        (0, chai_1.expect)(completion.items.length).to.equal(1);
                        (0, chai_1.expect)(completion.items[0].insertText).to.equal(`${expected}: `);
                    });
                });
            });
        });
    });
});
//# sourceMappingURL=autoCompletionFix.test.js.map