"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ResourceLoadError = void 0;
exports.handleApplication = handleApplication;
const path_1 = require("path");
function isResource(value) {
    return (value &&
        (typeof value.get === 'function' ||
            typeof value.put === 'function' ||
            typeof value.post === 'function' ||
            typeof value.delete === 'function'));
}
/**
 * Error thrown when a JavaScript resource module fails to load
 */
class ResourceLoadError extends Error {
    filePath;
    cause;
    constructor(filePath, cause) {
        super(`Failed to load resource module ${filePath}${cause ? `: ${cause.message}` : ''}`);
        this.name = 'ResourceLoadError';
        this.filePath = filePath;
        this.cause = cause;
    }
}
exports.ResourceLoadError = ResourceLoadError;
/**
 * This plugin loads JavaScript files and registers their exports as resources.
 *
 * The export can be the default export and will be assigned to the root URL path.
 *
 * Otherwise, the name of the export will be used.
 *
 * After loading the JavaScript code using the secure import, it adds it to the global `resources` map.
 *
 * Once a file has been loaded it cannot be unloaded without a restart.
 *
 * Thus, this plugin only handle files as they are added (`add` event). All other events result in a restart request.
 *
 */
async function handleApplication(scope) {
    scope.handleEntry(async function handleResourceEntry(entryEvent) {
        if (entryEvent.entryType !== 'file') {
            scope.logger.warn(`jsResource plugin cannot handle entry type ${entryEvent.entryType}. Modify the 'files' option in ${scope.configFilePath} to only include files.`);
            return;
        }
        if (entryEvent.eventType !== 'add') {
            scope.requestRestart();
            return;
        }
        try {
            const resourceModule = await scope.import(entryEvent.absolutePath);
            const root = (0, path_1.dirname)(entryEvent.urlPath).replace(/\\/g, '/').replace(/^\/$/, '');
            if (isResource(resourceModule.default)) {
                // register the resource
                scope.resources.set(root, resourceModule.default);
                scope.logger.debug?.(`Registered root resource: ${root}`);
            }
            recurseForResources(scope, resourceModule, root);
        }
        catch (error) {
            // Rethrow with more context
            throw new ResourceLoadError(entryEvent.absolutePath, error);
        }
    });
}
function recurseForResources(scope, resourceModule, prefix) {
    for (const name in resourceModule) {
        // check each of the module exports to see if it implements a Resource handler
        const exported = resourceModule[name];
        const resourcePath = `${prefix}/${name}`;
        if (isResource(exported)) {
            // expose as an endpoint
            scope.resources.set(resourcePath, exported);
            scope.logger.debug?.(`Registered resource: ${resourcePath}`);
        }
        else if (typeof exported === 'object') {
            recurseForResources(scope, exported, resourcePath);
        }
    }
}
//# sourceMappingURL=jsResource.js.map