• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 #ifndef ECMASCRIPT_BASE_PATH_HELPER_H
16 #define ECMASCRIPT_BASE_PATH_HELPER_H
17 
18 #include "ecmascript/aot_file_manager.h"
19 #include "ecmascript/base/string_helper.h"
20 #include "ecmascript/ecma_macros.h"
21 #include "ecmascript/ecma_string.h"
22 #include "ecmascript/ecma_vm.h"
23 #include "ecmascript/global_env.h"
24 #include "ecmascript/js_tagged_value-inl.h"
25 #include "ecmascript/jspandafile/js_pandafile.h"
26 
27 namespace panda::ecmascript::base {
28 class PathHelper {
29 public:
30     static constexpr char EXT_NAME_ABC[] = ".abc";
31     static constexpr char EXT_NAME_ETS[] = ".ets";
32     static constexpr char EXT_NAME_TS[] = ".ts";
33     static constexpr char EXT_NAME_JS[] = ".js";
34     static constexpr char EXT_NAME_JSON[] = ".json";
35     static constexpr char PREFIX_BUNDLE[] = "@bundle:";
36     static constexpr char PREFIX_MODULE[] = "@module:";
37     static constexpr char PREFIX_PACKAGE[] = "@package:";
38     static constexpr char NPM_PATH_SEGMENT[] = "node_modules";
39     static constexpr char PACKAGE_PATH_SEGMENT[] = "pkg_modules";
40     static constexpr char PACKAGE_ENTRY_FILE[] = "/index";
41     static constexpr char BUNDLE_INSTALL_PATH[] = "/data/storage/el1/bundle/";
42     static constexpr char MERGE_ABC_ETS_MODULES[] = "/ets/modules.abc";
43     static constexpr char MODULE_DEFAULE_ETS[] = "/ets/";
44     static constexpr char BUNDLE_SUB_INSTALL_PATH[] = "/data/storage/el1/";
45     static constexpr char PREVIEW_OF_ACROSS_HAP_FLAG[] = "[preview]";
46     static constexpr char NAME_SPACE_TAG[] = "@";
47 
48     static constexpr size_t MAX_PACKAGE_LEVEL = 1;
49     static constexpr size_t SEGMENTS_LIMIT_TWO = 2;
50     static constexpr size_t EXT_NAME_ABC_LEN = 4;
51     static constexpr size_t EXT_NAME_ETS_LEN = 4;
52     static constexpr size_t EXT_NAME_TS_LEN = 3;
53     static constexpr size_t EXT_NAME_JS_LEN = 3;
54     static constexpr size_t EXT_NAME_JSON_LEN = 5;
55     static constexpr size_t PREFIX_BUNDLE_LEN = 8;
56     static constexpr size_t PREFIX_MODULE_LEN = 8;
57     static constexpr size_t PREFIX_PACKAGE_LEN = 9;
58 
ResolveCurrentPath(JSThread * thread,JSMutableHandle<JSTaggedValue> & dirPath,JSMutableHandle<JSTaggedValue> & fileName,const JSPandaFile * jsPandaFile)59     static void ResolveCurrentPath(JSThread *thread,
60                                    JSMutableHandle<JSTaggedValue> &dirPath,
61                                    JSMutableHandle<JSTaggedValue> &fileName,
62                                    const JSPandaFile *jsPandaFile)
63     {
64         ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
65         CString fullName = jsPandaFile->GetJSPandaFileDesc();
66         // find last '/'
67         int foundPos = static_cast<int>(fullName.find_last_of("/\\"));
68         if (foundPos == -1) {
69             RETURN_IF_ABRUPT_COMPLETION(thread);
70         }
71         CString dirPathStr = fullName.substr(0, foundPos + 1);
72         JSHandle<EcmaString> dirPathName = factory->NewFromUtf8(dirPathStr);
73         dirPath.Update(dirPathName.GetTaggedValue());
74 
75         // Get filename from JSPandaFile
76         JSHandle<EcmaString> cbFileName = factory->NewFromUtf8(fullName);
77         fileName.Update(cbFileName.GetTaggedValue());
78     }
79 
ResolveDirPath(JSThread * thread,JSHandle<JSTaggedValue> fileName)80     static JSHandle<EcmaString> ResolveDirPath(JSThread *thread,
81                                                JSHandle<JSTaggedValue> fileName)
82     {
83         ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
84         CString fullName = ConvertToString(fileName.GetTaggedValue());
85         // find last '/'
86         int foundPos = static_cast<int>(fullName.find_last_of("/\\"));
87         if (foundPos == -1) {
88             RETURN_HANDLE_IF_ABRUPT_COMPLETION(EcmaString, thread);
89         }
90         CString dirPathStr = fullName.substr(0, foundPos + 1);
91         return factory->NewFromUtf8(dirPathStr);
92     }
93 
NormalizePath(const CString & fileName)94     static CString NormalizePath(const CString &fileName)
95     {
96         if (fileName.find("//") == CString::npos && fileName.find("./") == CString::npos &&
97             fileName[fileName.size() - 1] != '/') {
98             return fileName;
99         }
100         const char delim = '/';
101         CString res = "";
102         size_t prev = 0;
103         size_t curr = fileName.find(delim);
104         CVector<CString> elems;
105         while (curr != CString::npos) {
106             if (curr > prev) {
107                 CString elem = fileName.substr(prev, curr - prev);
108                 if (elem == ".." && !elems.empty()) {
109                     elems.pop_back();
110                 } else if (elem != ".") {
111                     elems.push_back(elem);
112                 }
113             }
114             prev = curr + 1;
115             curr = fileName.find(delim, prev);
116         }
117         if (prev != fileName.size()) {
118             elems.push_back(fileName.substr(prev));
119         }
120         for (auto e : elems) {
121             if (res.size() == 0 && fileName.at(0) != delim) {
122                 res.append(e);
123                 continue;
124             }
125             res.append(1, delim).append(e);
126         }
127         return res;
128     }
129 
ParseOhmUrl(EcmaVM * vm,const CString & inputFileName,CString & outFileName)130     static CString ParseOhmUrl(EcmaVM *vm, const CString &inputFileName, CString &outFileName)
131     {
132         CString bundleInstallName(BUNDLE_INSTALL_PATH);
133         size_t startStrLen = bundleInstallName.length();
134         size_t pos = CString::npos;
135 
136         if (inputFileName.length() > startStrLen && inputFileName.compare(0, startStrLen, bundleInstallName) == 0) {
137             pos = startStrLen;
138         }
139         CString entryPoint;
140         if (pos != CString::npos) {
141             pos = inputFileName.find('/', startStrLen);
142             ASSERT(pos != CString::npos);
143             CString moduleName = inputFileName.substr(startStrLen, pos - startStrLen);
144             if (moduleName != vm->GetModuleName()) {
145                 outFileName = BUNDLE_INSTALL_PATH + moduleName + MERGE_ABC_ETS_MODULES;
146             }
147             entryPoint = vm->GetBundleName() + "/" + inputFileName.substr(startStrLen);
148         } else {
149             // Temporarily handle the relative path sent by arkui
150             if (StringHelper::StringStartWith(inputFileName, PREFIX_BUNDLE)) {
151                 entryPoint = inputFileName.substr(PREFIX_BUNDLE_LEN);
152                 outFileName = ParseUrl(vm, entryPoint);
153             } else {
154                 entryPoint = vm->GetBundleName() + "/" + vm->GetModuleName() + MODULE_DEFAULE_ETS + inputFileName;
155             }
156         }
157         if (StringHelper::StringEndWith(entryPoint, EXT_NAME_ABC)) {
158             entryPoint.erase(entryPoint.length() - EXT_NAME_ABC_LEN, EXT_NAME_ABC_LEN);
159         }
160         return entryPoint;
161     }
162 
CropNamespaceIfAbsent(CString & moduleName)163     static void CropNamespaceIfAbsent(CString &moduleName)
164     {
165         size_t pos = moduleName.find(NAME_SPACE_TAG);
166         if (pos == CString::npos) {
167             return;
168         }
169         moduleName.erase(pos, moduleName.size() - pos);
170     }
171 
172     // current ohmUrl format : @bundle:bundlename/modulename@namespace/entry/src/index
ParseUrl(EcmaVM * vm,const CString & entryPoint)173     static CString ParseUrl(EcmaVM *vm, const CString &entryPoint)
174     {
175         CVector<CString> vec;
176         StringHelper::SplitString(entryPoint, vec, 0, SEGMENTS_LIMIT_TWO);
177         if (vec.size() < SEGMENTS_LIMIT_TWO) {
178             LOG_ECMA(DEBUG) << "ParseUrl SplitString filed, please check Url" << entryPoint;
179             return CString();
180         }
181         CString bundleName = vec[0];
182         CString moduleName = vec[1];
183         CropNamespaceIfAbsent(moduleName);
184 
185         CString baseFileName;
186         if (bundleName != vm->GetBundleName()) {
187             // Cross-application
188             baseFileName =
189                 BUNDLE_INSTALL_PATH + bundleName + "/" + moduleName + "/" + moduleName + MERGE_ABC_ETS_MODULES;
190         } else if (moduleName != vm->GetModuleName()) {
191             // Intra-application cross hap
192             baseFileName = BUNDLE_INSTALL_PATH + moduleName + MERGE_ABC_ETS_MODULES;
193         } else {
194             baseFileName = CString();
195         }
196         return baseFileName;
197     }
198 
ParseHapPath(const CString & fileName)199     static std::string ParseHapPath(const CString &fileName)
200     {
201         CString bundleSubInstallName(BUNDLE_SUB_INSTALL_PATH);
202         size_t startStrLen = bundleSubInstallName.length();
203         if (fileName.length() > startStrLen && fileName.compare(0, startStrLen, bundleSubInstallName) == 0) {
204             CString hapPath = fileName.substr(startStrLen);
205             size_t pos = hapPath.find(MERGE_ABC_ETS_MODULES);
206             if (pos != CString::npos) {
207                 return hapPath.substr(0, pos).c_str();
208             }
209         }
210         return std::string();
211     }
212 
CroppingRecord(CString & recordName)213     static void CroppingRecord(CString &recordName)
214     {
215         size_t pos = recordName.find('/');
216         if (pos != CString::npos) {
217             pos = recordName.find('/', pos + 1);
218             if (pos != CString::npos) {
219                 recordName = recordName.substr(pos + 1);
220             }
221         }
222     }
223 
ParsePrefixBundle(JSThread * thread,const JSPandaFile * jsPandaFile,CString & baseFileName,CString moduleRequestName)224     static CString ParsePrefixBundle(JSThread *thread, const JSPandaFile *jsPandaFile,
225                                      [[maybe_unused]] CString &baseFileName, CString moduleRequestName)
226     {
227         EcmaVM *vm = thread->GetEcmaVM();
228         moduleRequestName = moduleRequestName.substr(PREFIX_BUNDLE_LEN);
229         CString entryPoint = moduleRequestName;
230         if (jsPandaFile->IsRecordWithBundleName()) {
231             CVector<CString> vec;
232             StringHelper::SplitString(moduleRequestName, vec, 0, SEGMENTS_LIMIT_TWO);
233             if (vec.size() < SEGMENTS_LIMIT_TWO) {
234                 LOG_ECMA(DEBUG) << "SplitString filed, please check moduleRequestName";
235                 return CString();
236             }
237             CString bundleName = vec[0];
238             CString moduleName = vec[1];
239             CropNamespaceIfAbsent(moduleName);
240 
241 #if !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS)
242             if (bundleName != vm->GetBundleName()) {
243                 baseFileName =
244                     BUNDLE_INSTALL_PATH + bundleName + '/' + moduleName + '/' + moduleName + MERGE_ABC_ETS_MODULES;
245             } else if (moduleName != vm->GetModuleName()) {
246                 baseFileName = BUNDLE_INSTALL_PATH + moduleName + MERGE_ABC_ETS_MODULES;
247             } else {
248                 baseFileName = vm->GetAssetPath();
249             }
250 #else
251             if (bundleName != vm->GetBundleName() || moduleName != vm->GetModuleName()) {
252                 entryPoint = PREVIEW_OF_ACROSS_HAP_FLAG;
253                 LOG_NO_TAG(ERROR) << "[ArkRuntime Log] Importing shared package is not supported in the Previewer.";
254             }
255 #endif
256         } else {
257             CroppingRecord(entryPoint);
258         }
259         return entryPoint;
260     }
261 
MakeNewRecord(const JSPandaFile * jsPandaFile,CString & baseFileName,const CString & recordName,const CString & requestName)262     static CString MakeNewRecord(const JSPandaFile *jsPandaFile, CString &baseFileName, const CString &recordName,
263                                  const CString &requestName)
264     {
265         CString entryPoint;
266         CString moduleRequestName = RemoveSuffix(requestName);
267         size_t pos = moduleRequestName.find("./");
268         if (pos == 0) {
269             moduleRequestName = moduleRequestName.substr(2); // 2 means jump "./"
270         }
271         pos = recordName.rfind('/');
272         if (pos != CString::npos) {
273             entryPoint = recordName.substr(0, pos + 1) + moduleRequestName;
274         } else {
275             entryPoint = moduleRequestName;
276         }
277         entryPoint = NormalizePath(entryPoint);
278         entryPoint = ConfirmLoadingIndexOrNot(jsPandaFile, entryPoint);
279         if (!entryPoint.empty()) {
280             return entryPoint;
281         }
282         // the package name may have a '.js' suffix, try to parseThirdPartyPackage
283         entryPoint = ParseThirdPartyPackage(jsPandaFile, recordName, requestName, NPM_PATH_SEGMENT);
284         if (!entryPoint.empty()) {
285             return entryPoint;
286         }
287         // Execute abc locally
288         pos = baseFileName.rfind('/');
289         if (pos != CString::npos) {
290             baseFileName = baseFileName.substr(0, pos + 1) + moduleRequestName + EXT_NAME_ABC;
291         } else {
292             baseFileName = moduleRequestName + EXT_NAME_ABC;
293         }
294         pos = moduleRequestName.rfind('/');
295         if (pos != CString::npos) {
296             entryPoint = moduleRequestName.substr(pos + 1);
297         } else {
298             entryPoint = moduleRequestName;
299         }
300         return entryPoint;
301     }
302 
ConfirmLoadingIndexOrNot(const JSPandaFile * jsPandaFile,const CString & packageEntryPoint)303     static CString ConfirmLoadingIndexOrNot(const JSPandaFile *jsPandaFile, const CString &packageEntryPoint)
304     {
305         CString entryPoint = packageEntryPoint;
306         if (jsPandaFile->HasRecord(entryPoint)) {
307             return entryPoint;
308         }
309         // Possible import directory
310         entryPoint += PACKAGE_ENTRY_FILE;
311         if (jsPandaFile->HasRecord(entryPoint)) {
312             return entryPoint;
313         }
314         return CString();
315     }
316 
FindNpmEntryPoint(const JSPandaFile * jsPandaFile,const CString & packageEntryPoint)317     static CString FindNpmEntryPoint(const JSPandaFile *jsPandaFile, const CString &packageEntryPoint)
318     {
319         // if we are currently importing a specific file or directory, we will get the entryPoint here
320         CString entryPoint = ConfirmLoadingIndexOrNot(jsPandaFile, packageEntryPoint);
321         if (!entryPoint.empty()) {
322             return entryPoint;
323         }
324         // When you come here, must import a packageName
325         return jsPandaFile->GetEntryPoint(packageEntryPoint);
326     }
327 
FindPackageInTopLevel(const JSPandaFile * jsPandaFile,const CString & requestName,const CString & packagePath)328     static CString FindPackageInTopLevel(const JSPandaFile *jsPandaFile, const CString& requestName,
329                                          const CString &packagePath)
330     {
331         // we find node_modules/0/xxx or node_modules/1/xxx
332         CString entryPoint;
333         for (size_t level = 0; level <= MAX_PACKAGE_LEVEL; ++level) {
334             CString levelStr = std::to_string(level).c_str();
335             CString key = packagePath + "/" + levelStr + '/' + requestName;
336             entryPoint = FindNpmEntryPoint(jsPandaFile, key);
337             if (!entryPoint.empty()) {
338                 return entryPoint;
339             }
340         }
341         return CString();
342     }
343 
FindOhpmEntryPoint(const JSPandaFile * jsPandaFile,const CString & ohpmPath,const CString & requestName)344     static CString FindOhpmEntryPoint(const JSPandaFile *jsPandaFile, const CString& ohpmPath,
345                                       const CString& requestName)
346     {
347         CVector<CString> vec;
348         StringHelper::SplitString(requestName, vec, 0);
349         size_t maxIndex = vec.size() - 1;
350         CString ohpmKey;
351         size_t index = 0;
352         // first we find the ohpmKey by splicing the requestName
353         while (index <= maxIndex) {
354             CString maybeKey = ohpmPath + "/" + StringHelper::JoinString(vec, 0, index);
355             ohpmKey = jsPandaFile->GetNpmEntries(maybeKey);
356             if (!ohpmKey.empty()) {
357                 break;
358             }
359             ++index;
360         }
361         if (ohpmKey.empty()) {
362             return CString();
363         }
364         // second If the ohpmKey is not empty, we will use it to obtain the real entrypoint
365         CString entryPoint;
366         if (index == maxIndex) {
367             // requestName is a packageName
368             entryPoint = jsPandaFile->GetEntryPoint(ohpmKey);
369         } else {
370             // import a specific file or directory
371             ohpmKey = ohpmKey + "/" + StringHelper::JoinString(vec, index + 1, maxIndex);
372             entryPoint = ConfirmLoadingIndexOrNot(jsPandaFile, ohpmKey);
373         }
374         return entryPoint;
375     }
376 
FindPackageInTopLevelWithNamespace(const JSPandaFile * jsPandaFile,const CString & requestName,const CString & recordName)377     static CString FindPackageInTopLevelWithNamespace(const JSPandaFile *jsPandaFile, const CString& requestName,
378                                                       const CString &recordName)
379     {
380         // find in current module <PACKAGE_PATH_SEGMENT>@[moduleName|namespace]/<requestName>
381         CString entryPoint;
382         CString ohpmPath;
383         if (StringHelper::StringStartWith(recordName, PACKAGE_PATH_SEGMENT)) {
384             size_t pos = recordName.find('/');
385             if (pos == CString::npos) {
386                 LOG_ECMA(DEBUG) << "wrong recordname : " << recordName;
387                 return CString();
388             }
389             ohpmPath = recordName.substr(0, pos);
390             entryPoint = FindOhpmEntryPoint(jsPandaFile, recordName.substr(0, pos), requestName);
391         } else {
392             CVector<CString> vec;
393             StringHelper::SplitString(recordName, vec, 0, SEGMENTS_LIMIT_TWO);
394             if (vec.size() < SEGMENTS_LIMIT_TWO) {
395                 LOG_ECMA(DEBUG) << "SplitString filed, please check moduleRequestName";
396                 return CString();
397             }
398             CString moduleName = vec[1];
399             // If namespace exists, use namespace as moduleName
400             size_t pos = moduleName.find(NAME_SPACE_TAG);
401             if (pos != CString::npos) {
402                 moduleName = moduleName.substr(pos + 1);
403             }
404             ohpmPath = CString(PACKAGE_PATH_SEGMENT) + NAME_SPACE_TAG + moduleName;
405             entryPoint = FindOhpmEntryPoint(jsPandaFile, ohpmPath, requestName);
406         }
407         if (!entryPoint.empty()) {
408             return entryPoint;
409         }
410         // find in project directory <packagePath>/<requestName>
411         return FindOhpmEntryPoint(jsPandaFile, PACKAGE_PATH_SEGMENT, requestName);
412     }
413 
ParseOhpmPackage(const JSPandaFile * jsPandaFile,const CString & recordName,const CString & requestName)414     static CString ParseOhpmPackage(const JSPandaFile *jsPandaFile, const CString &recordName,
415                                     const CString &requestName)
416     {
417         CString entryPoint;
418         if (StringHelper::StringStartWith(recordName, PACKAGE_PATH_SEGMENT)) {
419             //this way is thirdPartyPackage import ThirdPartyPackage
420             auto info = const_cast<JSPandaFile *>(jsPandaFile)->FindRecordInfo(recordName);
421             CString packageName = info.npmPackageName;
422             size_t pos = packageName.rfind(PACKAGE_PATH_SEGMENT);
423             if (pos != CString::npos) {
424                 packageName.erase(pos, packageName.size() - pos);
425                 CString ohpmPath = packageName + PACKAGE_PATH_SEGMENT;
426                 entryPoint = FindOhpmEntryPoint(jsPandaFile, ohpmPath, requestName);
427                 if (!entryPoint.empty()) {
428                     return entryPoint;
429                 }
430             }
431         }
432         // Import packages under the current module or project directory
433         return FindPackageInTopLevelWithNamespace(jsPandaFile, requestName, recordName);
434     }
435 
ParseThirdPartyPackage(const JSPandaFile * jsPandaFile,const CString & recordName,const CString & requestName,const CString & packagePath)436     static CString ParseThirdPartyPackage(const JSPandaFile *jsPandaFile, const CString &recordName,
437                                           const CString &requestName, const CString &packagePath)
438     {
439         CString entryPoint;
440         if (StringHelper::StringStartWith(recordName, packagePath)) {
441             auto info = const_cast<JSPandaFile *>(jsPandaFile)->FindRecordInfo(recordName);
442             CString packageName = info.npmPackageName;
443             size_t pos = 0;
444             while (true) {
445                 CString key = packageName + '/' + packagePath + "/" + requestName;
446                 entryPoint = FindNpmEntryPoint(jsPandaFile, key);
447                 if (!entryPoint.empty()) {
448                     return entryPoint;
449                 }
450                 pos = packageName.rfind(packagePath) - 1;
451                 if (pos == CString::npos || pos < 0) {
452                     break;
453                 }
454                 packageName.erase(pos, packageName.size() - pos);
455             }
456         }
457         return FindPackageInTopLevel(jsPandaFile, requestName, packagePath);
458     }
459 
ParseThirdPartyPackage(const JSPandaFile * jsPandaFile,const CString & recordName,const CString & requestName)460     static CString ParseThirdPartyPackage(const JSPandaFile *jsPandaFile, const CString &recordName,
461                                           const CString &requestName)
462     {
463         static CVector<CString> packagePaths = {CString(PACKAGE_PATH_SEGMENT), CString(NPM_PATH_SEGMENT)};
464         // We need to deal with scenarios like this 'json5/' -> 'json5'
465         CString normalizeRequestName = NormalizePath(requestName);
466         CString entryPoint = ParseOhpmPackage(jsPandaFile, recordName, normalizeRequestName);
467         if (!entryPoint.empty()) {
468             return entryPoint;
469         }
470         // Package compatible with old soft link format
471         for (size_t i = 0; i < packagePaths.size(); ++i) {
472             entryPoint = ParseThirdPartyPackage(jsPandaFile, recordName, normalizeRequestName, packagePaths[i]);
473             if (!entryPoint.empty()) {
474                 return entryPoint;
475             }
476         }
477         return CString();
478     }
479 
IsImportFile(CString & moduleRequestName)480     static bool IsImportFile(CString &moduleRequestName)
481     {
482         if (moduleRequestName[0] == '.') {
483             return true;
484         }
485         size_t pos = moduleRequestName.rfind('.');
486         if (pos != CString::npos) {
487             CString suffix = moduleRequestName.substr(pos);
488             if (suffix == EXT_NAME_JS || suffix == EXT_NAME_TS || suffix == EXT_NAME_ETS || suffix == EXT_NAME_JSON) {
489                 return true;
490             }
491         }
492         return false;
493     }
494 
RemoveSuffix(const CString & requestName)495     static CString RemoveSuffix(const CString &requestName)
496     {
497         CString res = requestName;
498         size_t pos = res.rfind('.');
499         if (pos != CString::npos) {
500             CString suffix = res.substr(pos);
501             if (suffix == EXT_NAME_JS || suffix == EXT_NAME_TS || suffix == EXT_NAME_ETS || suffix == EXT_NAME_JSON) {
502                 res.erase(pos, suffix.length());
503             }
504         }
505         return res;
506     }
507 
ConcatFileNameWithMerge(JSThread * thread,const JSPandaFile * jsPandaFile,CString & baseFileName,CString recordName,CString requestName)508     static CString ConcatFileNameWithMerge(JSThread *thread, const JSPandaFile *jsPandaFile, CString &baseFileName,
509                                            CString recordName, CString requestName)
510     {
511         CString entryPoint;
512         if (StringHelper::StringStartWith(requestName, PREFIX_BUNDLE)) {
513             entryPoint = ParsePrefixBundle(thread, jsPandaFile, baseFileName, requestName);
514         } else if (StringHelper::StringStartWith(requestName, PREFIX_PACKAGE)) {
515             entryPoint = requestName.substr(PREFIX_PACKAGE_LEN);
516         } else if (IsImportFile(requestName)) { // load a relative pathName.
517             entryPoint = MakeNewRecord(jsPandaFile, baseFileName, recordName, requestName);
518         } else {
519             entryPoint = ParseThirdPartyPackage(jsPandaFile, recordName, requestName);
520         }
521         if (entryPoint.empty()) {
522             LOG_ECMA(ERROR) << "Failed to resolve the requested entryPoint. baseFileName : '" << baseFileName <<
523                 "'. RecordName : '" <<  recordName << "'. RequestName : '" <<  requestName << "'.";
524             ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
525             CString msg = "failed to load module'" + requestName + "' which imported by '" +
526                           recordName + "'. Please check the target path.";
527             JSTaggedValue error = factory->GetJSError(ErrorType::REFERENCE_ERROR, msg.c_str()).GetTaggedValue();
528             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, entryPoint);
529         }
530         return entryPoint;
531     }
532 };
533 }  // namespace panda::ecmascript::base
534 #endif  // ECMASCRIPT_BASE_PATH_HELPER_H