"use strict";
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;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const assert = __importStar(require("assert"));
const typescript_1 = __importDefault(require("typescript"));
const DocumentSnapshot_1 = require("../../../src/plugins/typescript/DocumentSnapshot");
const documents_1 = require("../../../src/lib/documents");
const utils_1 = require("../../../src/utils");
/**
 * Helper: verifies the reconstruction invariant for computeChangeRange.
 * Given old and new text, the change range should allow reconstructing
 * the new text by splicing the changed portion into the old text.
 */
function assertValidChangeRange(oldText, newText, label) {
    const range = (0, DocumentSnapshot_1.computeChangeRange)(oldText, newText);
    const before = oldText.substring(0, range.span.start);
    const after = oldText.substring(range.span.start + range.span.length);
    const inserted = newText.substring(range.span.start, range.span.start + range.newLength);
    const reconstructed = before + inserted + after;
    assert.strictEqual(reconstructed, newText, `${label ? label + ': ' : ''}Reconstruction failed for change ` +
        `span(${range.span.start}, ${range.span.length}), newLength=${range.newLength}`);
    return range;
}
describe('computeChangeRange', () => {
    it('returns empty change range for identical texts', () => {
        const result = (0, DocumentSnapshot_1.computeChangeRange)('hello world', 'hello world');
        assert.deepStrictEqual(result, {
            span: { start: 11, length: 0 },
            newLength: 0
        });
    });
    it('detects insertion in the middle', () => {
        const range = assertValidChangeRange('hello world', 'hello beautiful world');
        assert.deepStrictEqual(range, {
            span: { start: 6, length: 0 },
            newLength: 10
        });
    });
    it('detects deletion in the middle', () => {
        const range = assertValidChangeRange('hello beautiful world', 'hello world');
        assert.deepStrictEqual(range, {
            span: { start: 6, length: 10 },
            newLength: 0
        });
    });
    it('detects replacement', () => {
        const range = assertValidChangeRange('hello world', 'hello earth');
        assert.deepStrictEqual(range, {
            span: { start: 6, length: 5 },
            newLength: 5
        });
    });
    it('handles multiline text with change on one line', () => {
        assertValidChangeRange('line1\nline2\nline3\nline4', 'line1\nmodified\nline3\nline4');
    });
    it('holds reconstruction invariant for diverse edit patterns', () => {
        const cases = [
            ['', 'x'],
            ['x', ''],
            ['abcdef', 'abcxyzdef'],
            ['abcxyzdef', 'abcdef'],
            ['prefix_middle_suffix', 'prefix_changed_suffix'],
            ['aaa', 'aaaa']
        ];
        for (const [oldText, newText] of cases) {
            assertValidChangeRange(oldText, newText, `'${oldText}' -> '${newText}'`);
        }
    });
});
describe('JSOrTSDocumentSnapshot.getChangeRange', () => {
    function createSnapshot(text, version = 0, filePath = '/test/file.ts') {
        return new DocumentSnapshot_1.JSOrTSDocumentSnapshot(version, filePath, text);
    }
    it('computes change range between two different snapshots', () => {
        const old = createSnapshot('const x = 1;');
        const current = createSnapshot('const x = 42;');
        const range = current.getChangeRange(old);
        assert.ok(range);
        assert.deepStrictEqual(range.span.start, 10);
        assert.deepStrictEqual(range.span.length, 1);
        assert.deepStrictEqual(range.newLength, 2);
    });
    it('returns empty change for identical snapshots', () => {
        const old = createSnapshot('const x = 1;');
        const current = createSnapshot('const x = 1;');
        const range = current.getChangeRange(old);
        assert.ok(range);
        assert.strictEqual(range.span.length, 0);
        assert.strictEqual(range.newLength, 0);
    });
    it('update returns a new snapshot with correct change range', () => {
        const original = createSnapshot('const x = 1;');
        const updated = original.update([
            {
                range: {
                    start: { line: 0, character: 10 },
                    end: { line: 0, character: 11 }
                },
                text: '42'
            }
        ]);
        assert.notStrictEqual(original, updated, 'update should return a new snapshot');
        assert.strictEqual(updated.getFullText(), 'const x = 42;');
        assert.strictEqual(updated.version, original.version + 1);
        const range = updated.getChangeRange(original);
        assert.ok(range);
        const oldText = original.getFullText();
        const newText = updated.getFullText();
        const before = oldText.substring(0, range.span.start);
        const after = oldText.substring(range.span.start + range.span.length);
        const inserted = newText.substring(range.span.start, range.span.start + range.newLength);
        assert.strictEqual(before + inserted + after, newText);
    });
});
describe('SvelteDocumentSnapshot.getChangeRange', () => {
    function createSvelteSnapshot(generatedText, options) {
        const uri = (0, utils_1.pathToUrl)('/test/Component.svelte');
        const doc = documents_1.Document.createForTest(uri, generatedText);
        return new DocumentSnapshot_1.SvelteDocumentSnapshot(doc, options?.parserError
            ? {
                message: 'error',
                range: { start: { line: 0, character: 0 }, end: { line: 0, character: 0 } },
                code: -1
            }
            : null, options?.scriptKind ?? typescript_1.default.ScriptKind.TS, '4.0.0', generatedText, 0, { has: () => false });
    }
    it('computes change range between two svelte snapshots', () => {
        const old = createSvelteSnapshot('let x = 1;');
        const current = createSvelteSnapshot('let x = 42;');
        const range = current.getChangeRange(old);
        assert.ok(range);
        const oldText = old.getFullText();
        const newText = current.getFullText();
        const before = oldText.substring(0, range.span.start);
        const after = oldText.substring(range.span.start + range.span.length);
        const inserted = newText.substring(range.span.start, range.span.start + range.newLength);
        assert.strictEqual(before + inserted + after, newText);
    });
    it('returns undefined when scriptKind changes', () => {
        const old = createSvelteSnapshot('let x = 1;', { scriptKind: typescript_1.default.ScriptKind.JS });
        const current = createSvelteSnapshot('let x = 1;', { scriptKind: typescript_1.default.ScriptKind.TS });
        const range = current.getChangeRange(old);
        assert.strictEqual(range, undefined);
    });
    it('returns undefined when parserError state changes', () => {
        const old = createSvelteSnapshot('let x = 1;', { parserError: false });
        const current = createSvelteSnapshot('let x = 1;', { parserError: true });
        const range = current.getChangeRange(old);
        assert.strictEqual(range, undefined);
    });
});
//# sourceMappingURL=DocumentSnapshot.test.js.map