UNPKG

yaml-language-server

Version:
1,175 lines 52.4 kB
"use strict";
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Red Hat. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
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 = 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.22.4-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-var-requires
        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-var-requires
        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|}');
        });
    });
    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');
    });
    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.equal('Property Description');
    });
});
//# sourceMappingURL=autoCompletionFix.test.js.map