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