1/*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "ecmascript/module/napi_module_loader.h"
17#include "ecmascript/module/module_path_helper.h"
18#include "ecmascript/module/js_module_manager.h"
19#include "ecmascript/jspandafile/js_pandafile_manager.h"
20#include "ecmascript/jspandafile/js_pandafile_executor.h"
21
22namespace panda::ecmascript {
23JSHandle<JSTaggedValue> NapiModuleLoader::LoadModuleNameSpaceWithModuleInfo(EcmaVM *vm, CString &requestPath,
24    CString &modulePath)
25{
26    CString moduleStr = ModulePathHelper::GetModuleNameWithPath(modulePath);
27    CString abcFilePath = ModulePathHelper::ConcatPandaFilePath(moduleStr);
28    JSThread *thread = vm->GetJSThread();
29    std::shared_ptr<JSPandaFile> curJsPandaFile;
30    if (modulePath.size() != 0) {
31        curJsPandaFile = JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, abcFilePath, requestPath);
32        if (curJsPandaFile == nullptr) {
33            CString msg = "Load file with filename '" + abcFilePath +
34                "' failed, module name '" + requestPath + "'" + ", from napi load module";
35            THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, ErrorType::REFERENCE_ERROR, JSTaggedValue, msg.c_str());
36        }
37        if (vm->IsNormalizedOhmUrlPack()) {
38            ModulePathHelper::TranslateExpressionToNormalized(thread, curJsPandaFile.get(), abcFilePath, "",
39                requestPath);
40        } else if (ModulePathHelper::NeedTranstale(requestPath)) {
41            ModulePathHelper::TranstaleExpressionInput(curJsPandaFile.get(), requestPath);
42        }
43    }
44    JSHandle<JSTaggedValue> nameSp = LoadModuleNameSpaceWithPath(thread, abcFilePath, requestPath, modulePath,
45        curJsPandaFile.get());
46    return nameSp;
47}
48
49JSHandle<JSTaggedValue> NapiModuleLoader::LoadModuleNameSpaceWithPath(JSThread *thread, CString &abcFilePath,
50    CString &requestPath, CString &modulePath, const JSPandaFile *pandaFile)
51{
52    auto [isNative, moduleType] = SourceTextModule::CheckNativeModule(requestPath);
53    ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
54    if (isNative) {
55        JSHandle<JSTaggedValue> moduleHandle = moduleManager->LoadNativeModule(thread, requestPath);
56        return moduleHandle;
57    }
58    CString entryPoint = ModulePathHelper::ConcatFileNameWithMerge(thread, pandaFile,
59        abcFilePath, modulePath, requestPath);
60    RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
61
62    std::shared_ptr<JSPandaFile> jsPandaFile =
63        JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, abcFilePath, entryPoint);
64    if (jsPandaFile == nullptr) {
65        CString msg = "Load file with filename '" + abcFilePath +
66            "' failed, module name '" + requestPath + "'" + ", from napi load module";
67        THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, ErrorType::REFERENCE_ERROR, JSTaggedValue, msg.c_str());
68    }
69
70    JSRecordInfo *recordInfo = nullptr;
71    bool hasRecord = jsPandaFile->CheckAndGetRecordInfo(entryPoint, &recordInfo);
72    if (!hasRecord) {
73        LOG_FULL(ERROR) << "cannot find record '" << entryPoint <<"' in basefileName " << abcFilePath << ","
74            << "from napi load module";
75        CString msg = "cannot find record '" + entryPoint + "' in basefileName " + abcFilePath + "," +
76            "from napi load module";
77        THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, ErrorType::REFERENCE_ERROR, JSTaggedValue, msg.c_str());
78    }
79    // IsInstantiatedModule is for lazy module to execute
80    if (!moduleManager->IsLocalModuleLoaded(entryPoint) || moduleManager->IsLocalModuleInstantiated(entryPoint)) {
81        if (!JSPandaFileExecutor::ExecuteFromAbcFile(thread, abcFilePath, entryPoint.c_str(), false, true)) {
82            CString msg = "Cannot execute request from napi load module : " + entryPoint +
83                ", from napi load module";
84            THROW_NEW_ERROR_AND_RETURN_HANDLE(thread, ErrorType::REFERENCE_ERROR, JSTaggedValue, msg.c_str());
85        }
86    }
87    JSHandle<SourceTextModule> moduleRecord = moduleManager->HostGetImportedModule(entryPoint);
88    JSHandle<JSTaggedValue> nameSp = SourceTextModule::GetModuleNamespace(thread, moduleRecord);
89    RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
90    return nameSp;
91}
92}