"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.registerExtension = exports.Module = exports.defineModules = void 0;
const tslib_1 = require("tslib");
/* eslint-disable no-use-before-define */
/* eslint-disable @typescript-eslint/no-use-before-define */
const path = tslib_1.__importStar(require("path"));
const util_1 = require("./util");
const core_module_1 = require("./core_module");
function defineModules(allModules, opts) {
    (0, core_module_1.init)(opts.runtime);
    const definedModules = {};
    opts.runtime[opts.defineFuncName] = function (id, factory) {
        definedModules[id].factory = factory;
    };
    Object.entries(allModules).map(([id, modData]) => {
        const mod = new Module(id, modData.url);
        definedModules[id] = mod;
        try {
            mod.defineModule(modData.code, opts.defineFuncName, opts.runtime);
        }
        catch (e) {
            opts.onError(e);
        }
    });
    Object.entries(definedModules).map(([id, mod]) => {
        Object.entries(allModules[id].requires).map(([requirePath, resolvedPath]) => {
            mod.dependencies[requirePath] = definedModules[resolvedPath];
        });
    });
    return definedModules;
}
exports.defineModules = defineModules;
// https://nodejs.org/api/modules.html#modules_the_module_object
class Module {
    constructor(id, url) {
        this.dependencies = {};
        this.require = (path) => {
            const dep = this.dependencies[path];
            if (dep) {
                return dep.execute();
            }
            console.warn(`Dependeny ${path} not loaded properly for ${this.id}`);
        };
        this.id = id;
        this.url = url;
    }
    execute() {
        if (this.exports) {
            // console.warn('Using cached exports for ' + self.id)
            return this.exports;
        }
        this.exports = {};
        this.factory.call(this.exports, this.require, this.exports, this);
        return this.exports;
    }
    /**
     * Register the module
     */
    defineModule(srcCode, defineFuncName, runtime) {
        const { id } = this;
        const ext = path.extname(id).substr(1);
        let source = srcCode;
        if (loaders[ext]) {
            source = loaders[ext](source);
        }
        const code = `${defineFuncName}("${id}", function(require, exports, module) {
${source}
})//# sourceURL=${id}`;
        if (runtime.document) {
            (0, util_1.evalCode)(code, runtime.document);
        }
        else {
            console.warn('script runtime error, runtime do not has document.');
        }
        if (typeof this.factory !== 'function') {
            throw new Error(`Lowcode syntax error of module ${this.url}`);
        }
    }
}
exports.Module = Module;
const loaders = {
    json(src) {
        return `module.exports=${src}`;
    },
    css: textLoader,
    txt: textLoader,
};
function registerExtension(ext, transform) {
    if (loaders[ext]) {
        console.error(`Duplicate transform for ${ext}`);
        return;
    }
    loaders[ext] = transform;
}
exports.registerExtension = registerExtension;
function textLoader(src) {
    return `module.exports=${JSON.stringify(src)}`;
}
//# sourceMappingURL=module.js.map