"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 (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getVirtualLS = exports.isKitRouteExportAllowedIn = exports.kitExports = void 0;
const utils_1 = require("../utils");
const svelte2tsx_1 = require("svelte2tsx");
const cache = new WeakMap();
function createApiExport(name) {
    return {
        allowedIn: ['api', 'server'],
        displayParts: [
            {
                text: 'export',
                kind: 'keyword'
            },
            {
                text: ' ',
                kind: 'space'
            },
            {
                text: 'async',
                kind: 'keyword'
            },
            {
                text: ' ',
                kind: 'space'
            },
            {
                text: 'function',
                kind: 'keyword'
            },
            {
                text: ' ',
                kind: 'space'
            },
            {
                text: name,
                kind: 'localName'
            },
            {
                text: '(',
                kind: 'punctuation'
            },
            {
                text: 'event',
                kind: 'parameterName'
            },
            {
                text: ': ',
                kind: 'punctuation'
            },
            {
                text: 'RequestEvent',
                kind: 'interfaceName'
            },
            {
                text: ')',
                kind: 'punctuation'
            },
            {
                text: ': ',
                kind: 'punctuation'
            },
            {
                text: 'Promise',
                kind: 'keyword'
            },
            {
                text: '<',
                kind: 'punctuation'
            },
            {
                text: 'Response',
                kind: 'interfaceName'
            },
            {
                text: '>',
                kind: 'punctuation'
            }
        ],
        documentation: [
            {
                text: `Handles ${name} requests. More info: https://kit.svelte.dev/docs/routing#server`,
                kind: 'text'
            }
        ]
    };
}
exports.kitExports = {
    prerender: {
        allowedIn: ['layout', 'page', 'api', 'server', 'universal'],
        displayParts: [
            {
                text: 'const',
                kind: 'keyword'
            },
            {
                text: ' ',
                kind: 'space'
            },
            {
                text: 'prerender',
                kind: 'localName'
            },
            {
                text: ': ',
                kind: 'punctuation'
            },
            {
                text: 'boolean',
                kind: 'keyword'
            },
            {
                text: ' | ',
                kind: 'punctuation'
            },
            {
                text: "'auto'",
                kind: 'stringLiteral'
            }
        ],
        documentation: [
            {
                text: 'Control whether or not this page is prerendered. More info: https://kit.svelte.dev/docs/page-options#prerender',
                kind: 'text'
            }
        ]
    },
    ssr: {
        allowedIn: ['layout', 'page', 'server', 'universal'],
        displayParts: [
            {
                text: 'const',
                kind: 'keyword'
            },
            {
                text: ' ',
                kind: 'space'
            },
            {
                text: 'ssr',
                kind: 'localName'
            },
            {
                text: ': ',
                kind: 'punctuation'
            },
            {
                text: 'boolean',
                kind: 'keyword'
            }
        ],
        documentation: [
            {
                text: 'Control whether or not this page is server-side rendered. More info: https://kit.svelte.dev/docs/page-options#ssr',
                kind: 'text'
            }
        ]
    },
    csr: {
        allowedIn: ['layout', 'page', 'server', 'universal'],
        displayParts: [
            {
                text: 'const',
                kind: 'keyword'
            },
            {
                text: ' ',
                kind: 'space'
            },
            {
                text: 'csr',
                kind: 'localName'
            },
            {
                text: ': ',
                kind: 'punctuation'
            },
            {
                text: 'boolean',
                kind: 'keyword'
            }
        ],
        documentation: [
            {
                text: 'Control whether or not this page is hydrated (i.e. if JS is delivered to the client). More info: https://kit.svelte.dev/docs/page-options#csr',
                kind: 'text'
            }
        ]
    },
    trailingSlash: {
        allowedIn: ['layout', 'page', 'api', 'server', 'universal'],
        displayParts: [
            {
                text: 'const',
                kind: 'keyword'
            },
            {
                text: ' ',
                kind: 'space'
            },
            {
                text: 'trailingSlash',
                kind: 'localName'
            },
            {
                text: ': ',
                kind: 'punctuation'
            },
            {
                text: "'auto' | 'always' | 'never'",
                kind: 'stringLiteral'
            }
        ],
        documentation: [
            {
                text: 'Control how SvelteKit should handle (missing) trailing slashes in the URL. More info: https://kit.svelte.dev/docs/page-options#trailingslash',
                kind: 'text'
            }
        ]
    },
    config: {
        allowedIn: ['layout', 'page', 'api', 'server', 'universal'],
        displayParts: [
            {
                text: 'const',
                kind: 'keyword'
            },
            {
                text: ' ',
                kind: 'space'
            },
            {
                text: 'config',
                kind: 'localName'
            },
            {
                text: ': ',
                kind: 'punctuation'
            },
            {
                text: 'Config',
                kind: 'interfaceName'
            }
        ],
        documentation: [
            {
                text: `With the concept of adapters, SvelteKit is able to run on a variety of platforms. ` +
                    `Each of these might have specific configuration to further tweak the deployment, which you can configure here. ` +
                    `More info: https://kit.svelte.dev/docs/page-options#config`,
                kind: 'text'
            }
        ]
    },
    actions: {
        allowedIn: ['page', 'server'],
        displayParts: [
            {
                text: 'const',
                kind: 'keyword'
            },
            {
                text: ' ',
                kind: 'space'
            },
            {
                text: 'actions',
                kind: 'localName'
            },
            {
                text: ': ',
                kind: 'punctuation'
            },
            {
                text: 'Actions',
                kind: 'interfaceName'
            }
        ],
        documentation: [
            {
                text: `An object of methods which handle form POST requests. ` +
                    `More info: https://kit.svelte.dev/docs/form-actions`,
                kind: 'text'
            }
        ]
    },
    load: {
        allowedIn: ['layout', 'page', 'server', 'universal'],
        displayParts: [
            {
                text: 'export',
                kind: 'keyword'
            },
            {
                text: ' ',
                kind: 'space'
            },
            {
                text: 'function',
                kind: 'keyword'
            },
            {
                text: ' ',
                kind: 'space'
            },
            {
                text: 'load',
                kind: 'localName'
            },
            {
                text: '(',
                kind: 'punctuation'
            },
            {
                text: 'event',
                kind: 'parameterName'
            },
            {
                text: ': ',
                kind: 'punctuation'
            },
            {
                text: 'LoadEvent',
                kind: 'interfaceName'
            },
            {
                text: ')',
                kind: 'punctuation'
            },
            {
                text: ': ',
                kind: 'punctuation'
            },
            {
                text: 'Promise',
                kind: 'keyword'
            },
            {
                text: '<',
                kind: 'punctuation'
            },
            {
                text: 'LoadOutput',
                kind: 'interfaceName'
            },
            {
                text: '>',
                kind: 'punctuation'
            }
        ],
        documentation: [
            {
                text: 'Loads data for the given page or layout. More info: https://kit.svelte.dev/docs/load',
                kind: 'text'
            }
        ]
    },
    entries: {
        allowedIn: ['api', 'page', 'server', 'universal'],
        displayParts: [
            {
                text: 'export',
                kind: 'keyword'
            },
            {
                text: ' ',
                kind: 'space'
            },
            {
                text: 'function',
                kind: 'keyword'
            },
            {
                text: ' ',
                kind: 'space'
            },
            {
                text: 'entries',
                kind: 'functionName'
            },
            {
                text: '() {}',
                kind: 'punctuation'
            }
        ],
        documentation: [
            {
                text: 'Generate values for dynamic parameters in prerendered pages.\n' +
                    'More info: https://kit.svelte.dev/docs/page-options#entries',
                kind: 'text'
            }
        ]
    },
    GET: createApiExport('GET'),
    POST: createApiExport('POST'),
    PUT: createApiExport('PUT'),
    PATCH: createApiExport('PATCH'),
    DELETE: createApiExport('DELETE'),
    OPTIONS: createApiExport('OPTIONS'),
    // param matching
    match: {
        allowedIn: [],
        displayParts: [],
        documentation: [
            {
                text: `A parameter matcher. ` +
                    `More info: https://kit.svelte.dev/docs/advanced-routing#matching`,
                kind: 'text'
            }
        ]
    },
    // hooks
    handle: {
        allowedIn: [],
        displayParts: [],
        documentation: [
            {
                text: `The  handle hook runs every time the SvelteKit server receives a request and determines the response. ` +
                    `It receives an 'event' object representing the request and a function called 'resolve', which renders the route and generates a Response. ` +
                    `This allows you to modify response headers or bodies, or bypass SvelteKit entirely (for implementing routes programmatically, for example). ` +
                    `More info: https://kit.svelte.dev/docs/hooks#server-hooks-handle`,
                kind: 'text'
            }
        ]
    },
    handleFetch: {
        allowedIn: [],
        displayParts: [],
        documentation: [
            {
                text: `The handleFetch hook allows you to modify (or replace) a 'fetch' request that happens inside a 'load' function that runs on the server (or during pre-rendering). ` +
                    `More info: https://kit.svelte.dev/docs/hooks#server-hooks-handlefetch`,
                kind: 'text'
            }
        ]
    },
    handleError: {
        allowedIn: [],
        displayParts: [],
        documentation: [
            {
                text: `The handleError hook runs when an unexpected error is thrown while responding to a request. ` +
                    `If an unexpected error is thrown during loading or rendering, this function will be called with the error and the event. ` +
                    `Make sure that this function _never_ throws an error. ` +
                    `More info: https://kit.svelte.dev/docs/hooks#shared-hooks-handleerror`,
                kind: 'text'
            }
        ]
    }
};
function isKitRouteExportAllowedIn(basename, kitExport) {
    if (!basename.startsWith('+')) {
        return false;
    }
    const allowedIn = kitExport.allowedIn;
    return ((basename.includes('layout')
        ? allowedIn.includes('layout')
        : basename.includes('+server')
            ? allowedIn.includes('api')
            : allowedIn.includes('page')) &&
        (basename.includes('server')
            ? allowedIn.includes('server')
            : allowedIn.includes('universal')));
}
exports.isKitRouteExportAllowedIn = isKitRouteExportAllowedIn;
function getProxiedLanguageService(info, ts, logger) {
    const cachedProxiedLanguageService = cache.get(info);
    if (cachedProxiedLanguageService !== undefined) {
        return cachedProxiedLanguageService ?? undefined;
    }
    if (!(0, utils_1.hasNodeModule)(info.project.getCompilerOptions(), '@sveltejs/kit')) {
        // Not a SvelteKit project, do nothing
        cache.set(info, null);
        return;
    }
    const originalLanguageServiceHost = info.languageServiceHost;
    class ProxiedLanguageServiceHost {
        constructor() {
            this.files = {};
            this.paramsPath = 'src/params';
            this.serverHooksPath = 'src/hooks.server';
            this.clientHooksPath = 'src/hooks.client';
            this.resolveModuleNames = originalLanguageServiceHost.resolveModuleNames
                ? (...args) => {
                    return originalLanguageServiceHost.resolveModuleNames(
                    // @ts-ignore
                    ...args);
                }
                : undefined;
            this.resolveModuleNameLiterals = originalLanguageServiceHost.resolveModuleNameLiterals
                ? (...args) => {
                    return originalLanguageServiceHost.resolveModuleNameLiterals(
                    // @ts-ignore
                    ...args);
                }
                : undefined;
            // needed for path auto completions
            this.readDirectory = originalLanguageServiceHost.readDirectory
                ? (...args) => {
                    return originalLanguageServiceHost.readDirectory(...args);
                }
                : undefined;
            this.getDirectories = originalLanguageServiceHost.getDirectories
                ? (...args) => {
                    return originalLanguageServiceHost.getDirectories(...args);
                }
                : undefined;
            this.getCancellationToken = originalLanguageServiceHost.getCancellationToken
                ? () => originalLanguageServiceHost.getCancellationToken()
                : undefined;
            this.getNewLine = originalLanguageServiceHost.getNewLine
                ? () => originalLanguageServiceHost.getNewLine()
                : undefined;
            this.useCaseSensitiveFileNames = originalLanguageServiceHost.useCaseSensitiveFileNames
                ? () => originalLanguageServiceHost.useCaseSensitiveFileNames()
                : undefined;
            this.realpath = originalLanguageServiceHost.realpath
                ? (...args) => originalLanguageServiceHost.realpath(...args)
                : undefined;
            const configPath = info.project.getCurrentDirectory() + '/svelte.config.js';
            Promise.resolve(`${configPath}`).then(s => __importStar(require(s))).then((module) => {
                const config = module.default;
                if (config.kit && config.kit.files) {
                    if (config.kit.files.params) {
                        this.paramsPath = config.kit.files.params;
                    }
                    if (config.kit.files.hooks) {
                        this.serverHooksPath ||= config.kit.files.hooks.server;
                        this.clientHooksPath ||= config.kit.files.hooks.client;
                    }
                    // We could be more sophisticated with only removing the files that are actually
                    // wrong but this is good enough given how rare it is that this setting is used
                    Object.keys(this.files)
                        .filter((name) => {
                        return !name.includes('src/hooks') && !name.includes('src/params');
                    })
                        .forEach((name) => {
                        delete this.files[name];
                    });
                }
            })
                .catch(() => { });
        }
        log() { }
        trace() { }
        error() { }
        getCompilationSettings() {
            return originalLanguageServiceHost.getCompilationSettings();
        }
        getCurrentDirectory() {
            return originalLanguageServiceHost.getCurrentDirectory();
        }
        getDefaultLibFileName(o) {
            return originalLanguageServiceHost.getDefaultLibFileName(o);
        }
        getScriptVersion(fileName) {
            const file = this.files[fileName];
            if (!file)
                return originalLanguageServiceHost.getScriptVersion(fileName);
            return file.version.toString();
        }
        getScriptSnapshot(fileName) {
            const file = this.files[fileName];
            if (!file)
                return originalLanguageServiceHost.getScriptSnapshot(fileName);
            return file.file;
        }
        getScriptFileNames() {
            const names = new Set(Object.keys(this.files));
            const files = originalLanguageServiceHost.getScriptFileNames();
            for (const file of files) {
                names.add(file);
            }
            return [...names];
        }
        getKitScriptSnapshotIfUpToDate(fileName) {
            if (!this.files[fileName] ||
                this.getScriptVersion(fileName) !==
                    originalLanguageServiceHost.getScriptVersion(fileName)) {
                return undefined;
            }
            return this.files[fileName];
        }
        upsertKitFile(fileName) {
            const result = svelte2tsx_1.internalHelpers.upsertKitFile(ts, fileName, {
                clientHooksPath: this.clientHooksPath,
                paramsPath: this.paramsPath,
                serverHooksPath: this.serverHooksPath
            }, () => info.languageService.getProgram()?.getSourceFile(fileName));
            if (!result) {
                return;
            }
            const { text, addedCode } = result;
            const snap = ts.ScriptSnapshot.fromString(text);
            snap.getChangeRange = (_) => undefined;
            this.files[fileName] = {
                version: originalLanguageServiceHost.getScriptVersion(fileName),
                file: snap,
                addedCode
            };
            return this.files[fileName];
        }
        readFile(fileName) {
            const file = this.files[fileName];
            return file
                ? file.file.getText(0, file.file.getLength())
                : originalLanguageServiceHost.readFile(fileName);
        }
        fileExists(fileName) {
            return (this.files[fileName] !== undefined ||
                originalLanguageServiceHost.fileExists(fileName));
        }
    }
    // Ideally we'd create a full Proxy of the language service, but that seems to have cache issues
    // with diagnostics, which makes positions go out of sync.
    const languageServiceHost = new ProxiedLanguageServiceHost();
    const languageService = ts.createLanguageService(languageServiceHost, createProxyRegistry(ts, originalLanguageServiceHost, languageServiceHost));
    cache.set(info, { languageService, languageServiceHost });
    return {
        languageService,
        languageServiceHost
    };
}
function createProxyRegistry(ts, originalLanguageServiceHost, options) {
    // Don't destructure options param, as the value may be mutated through a svelte.config.js later
    const registry = ts.createDocumentRegistry();
    return registry;
    // TODO check why this fails on linux and reenable later
    // const originalRegistry = (originalLanguageServiceHost as any).documentRegistry;
    // const proxyRegistry: ts.DocumentRegistry = {
    //     ...originalRegistry,
    //     acquireDocumentWithKey(
    //         fileName,
    //         tsPath,
    //         compilationSettingsOrHost,
    //         key,
    //         scriptSnapshot,
    //         version,
    //         scriptKind,
    //         sourceFileOptions
    //     ) {
    //         if (internalHelpers.isKitFile(fileName, options)) {
    //             return registry.acquireDocumentWithKey(
    //                 fileName,
    //                 tsPath,
    //                 compilationSettingsOrHost,
    //                 key,
    //                 scriptSnapshot,
    //                 version,
    //                 scriptKind,
    //                 sourceFileOptions
    //             );
    //         }
    //         return originalRegistry.acquireDocumentWithKey(
    //             fileName,
    //             tsPath,
    //             compilationSettingsOrHost,
    //             key,
    //             scriptSnapshot,
    //             version,
    //             scriptKind,
    //             sourceFileOptions
    //         );
    //     },
    //     updateDocumentWithKey(
    //         fileName,
    //         tsPath,
    //         compilationSettingsOrHost,
    //         key,
    //         scriptSnapshot,
    //         version,
    //         scriptKind,
    //         sourceFileOptions
    //     ) {
    //         if (internalHelpers.isKitFile(fileName, options)) {
    //             return registry.updateDocumentWithKey(
    //                 fileName,
    //                 tsPath,
    //                 compilationSettingsOrHost,
    //                 key,
    //                 scriptSnapshot,
    //                 version,
    //                 scriptKind,
    //                 sourceFileOptions
    //             );
    //         }
    //         return originalRegistry.updateDocumentWithKey(
    //             fileName,
    //             tsPath,
    //             compilationSettingsOrHost,
    //             key,
    //             scriptSnapshot,
    //             version,
    //             scriptKind,
    //             sourceFileOptions
    //         );
    //     }
    // };
    // return proxyRegistry;
}
function getVirtualLS(fileName, info, ts, logger) {
    const proxy = getProxiedLanguageService(info, ts, logger);
    if (!proxy) {
        return;
    }
    const result = proxy.languageServiceHost.getKitScriptSnapshotIfUpToDate(fileName) ??
        proxy.languageServiceHost.upsertKitFile(fileName);
    if (result) {
        return {
            languageService: proxy.languageService,
            addedCode: result.addedCode,
            toVirtualPos: (pos) => svelte2tsx_1.internalHelpers.toVirtualPos(pos, result.addedCode),
            toOriginalPos: (pos) => svelte2tsx_1.internalHelpers.toOriginalPos(pos, result.addedCode)
        };
    }
}
exports.getVirtualLS = getVirtualLS;
//# sourceMappingURL=sveltekit.js.map