Skip to content

File simpleModuleLoaderFeature.h

File List > features > simpleModuleLoaderFeature.h

Go to the documentation of this file

#pragma once

#include <jac/machine/machine.h>

#include <jac/features/util/moduleLoader.h>


namespace jac {


template<class Next>
class SimpleModuleLoaderFeature : public Next {
private:
    static JSModuleDef *moduleLoaderCbk(JSContext* ctx, const char *module_name, void *_self, JSValueConst attributes) {
        auto &self = *static_cast<SimpleModuleLoaderFeature<Next>*>(_self);

        std::string filename = module_name;

        std::string buffer;
        try {
            buffer = self.fs.loadCode(filename);
        } catch (jac::Exception &e) {
            e.throwJS(ctx);
            return nullptr;
        }

        self.resetWatchdog();

        int jsonType = moduleAttributesJsonType(ctx, attributes);
        if (jsonType > 0 || filename.ends_with(".json")) {
            JSValue val = JS_ParseJSON2(ctx, buffer.c_str(), buffer.size(), module_name,
                                        jsonType == 2 ? JS_PARSE_JSON_EXT : 0);
            if (JS_IsException(val)) {
                return nullptr;
            }
            return createJsonModule(ctx, module_name, val);
        }

        // compile and return module
        JSValue val = JS_Eval(ctx, buffer.c_str(), buffer.size(), module_name,
                              JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
        if (JS_IsException(val)) {
            return nullptr;
        }

        auto mdl = static_cast<JSModuleDef*>(JS_VALUE_GET_PTR(val));

        Object meta(ctx, JS_GetImportMeta(ctx, mdl));
        meta.set("url", filename);
        meta.set("main", false);

        JS_FreeValue(ctx, val);
        return mdl;
    }

public:
    Value evalFile(std::string path_) {
        auto buffer = this->fs.loadCode(path_);

        Value val = this->eval(std::move(buffer), path_, EvalFlags::Module);
        return val;
    }

    void evalFileWithEventLoop(std::string path_) {
        Value promise = this->evalFile(path_);
        this->evalWithEventLoopCommon(promise);
    }

    void initialize() {
        Next::initialize();

        this->setFileModuleLoader([this](JSContext* ctx, const char* name, JSValueConst attributes) {
            return moduleLoaderCbk(ctx, name, this, attributes);
        });
    }
};


} // namespace jac