• 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 if (StringHelper::StringStartWith(requestName, PREFIX_ETS)) {
37         // requestName: ets/xxx/xxx
38         entryPoint = TranslateExpressionInputWithEts(thread, jsPandaFile, baseFileName, requestName);
39     } else {
40         // this branch save for require/dynamic import/old version sdk
41         // requestName: requestPkgName
42         entryPoint = ParseThirdPartyPackage(jsPandaFile, recordName, requestName);
43     }
44     if (entryPoint.empty() && thread->GetEcmaVM()->EnableReportModuleResolvingFailure()) {
45         LOG_ECMA(ERROR) << "Failed to resolve the requested entryPoint. baseFileName : '" << baseFileName <<
46             "'. RecordName : '" <<  recordName << "'. RequestName : '" <<  requestName << "'.";
47         ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
48         CString msg = "failed to load module'" + requestName + "' which imported by '" +
49             recordName + "'. Please check the target path.";
50         JSTaggedValue error = factory->GetJSError(ErrorType::REFERENCE_ERROR, msg.c_str()).GetTaggedValue();
51         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, entryPoint);
52     }
53     return entryPoint;
54 }
55 
56 /*
57  * Before: inputFileName: 1. /data/storage/el1/bundle/moduleName@namespace/ets/xxx/xxx.abc
58                           2. @bundle:bundleName/moduleName/ets/xxx/xxx.abc
59                           3. moduleName/ets/xxx/xxx.abc
60                           4. .test/xxx/xxx.abc
61                           5. xxx/xxx.abc
62  * After:  outBaseFileName: /data/storage/el1/bundle/moduleName/ets/modules.abc
63  *         outEntryPoint: bundleName/moduleName/ets/xxx/xxx
64  */
ParseOhmUrl(EcmaVM * vm,const CString & inputFileName,CString & outBaseFileName,CString & outEntryPoint)65 void ModulePathHelper::ParseOhmUrl(EcmaVM *vm, const CString &inputFileName,
66     CString &outBaseFileName, CString &outEntryPoint)
67 {
68     size_t pos = CString::npos;
69     if (inputFileName.length() > BUNDLE_INSTALL_PATH_LEN &&
70         inputFileName.compare(0, BUNDLE_INSTALL_PATH_LEN, BUNDLE_INSTALL_PATH) == 0) {
71         pos = BUNDLE_INSTALL_PATH_LEN;
72     }
73     if (pos != CString::npos) {
74         // inputFileName: /data/storage/el1/bundle/moduleName@namespace/ets/xxx/xxx.abc
75         pos = inputFileName.find(PathHelper::SLASH_TAG, BUNDLE_INSTALL_PATH_LEN);
76         if (pos == CString::npos) {
77             LOG_FULL(FATAL) << "Invalid Ohm url, please check.";
78         }
79         CString moduleName = inputFileName.substr(BUNDLE_INSTALL_PATH_LEN, pos - BUNDLE_INSTALL_PATH_LEN);
80         PathHelper::DeleteNamespace(moduleName);
81         outBaseFileName = BUNDLE_INSTALL_PATH + moduleName + MERGE_ABC_ETS_MODULES;
82         outEntryPoint = vm->GetBundleName() + PathHelper::SLASH_TAG + inputFileName.substr(BUNDLE_INSTALL_PATH_LEN);
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             baseFileName = BUNDLE_INSTALL_PATH + bundleName + PathHelper::SLASH_TAG + moduleName +
186                            PathHelper::SLASH_TAG + moduleName + MERGE_ABC_ETS_MODULES;
187         } else if (currentModuleName != vm->GetModuleName()) {
188             baseFileName = BUNDLE_INSTALL_PATH + moduleName + MERGE_ABC_ETS_MODULES;
189         }
190 #endif
191     } else {
192         PathHelper::AdaptOldIsaRecord(entryPoint);
193     }
194     return entryPoint;
195 }
196 
197 /*
198  * Before: requestName: ../xxx1/xxx2 || ./b
199  *         recordName: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx1/xxx3 || a
200  * After:  entryPoint: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx1/xxx2 || b
201  *         baseFileName: /data/storage/el1/bundle/moduleName/ets/modules.abc || /home/user/src/a
202  */
MakeNewRecord(const JSPandaFile * jsPandaFile,CString & baseFileName,const CString & recordName,const CString & requestName)203 CString ModulePathHelper::MakeNewRecord(const JSPandaFile *jsPandaFile, CString &baseFileName,
204     const CString &recordName, const CString &requestName)
205 {
206     CString entryPoint;
207     CString moduleRequestName = RemoveSuffix(requestName);
208     size_t pos = moduleRequestName.find(PathHelper::CURRENT_DIREATORY_TAG);
209     if (pos == 0) {
210         moduleRequestName = moduleRequestName.substr(2); // 2 means jump "./"
211     }
212     pos = recordName.rfind(PathHelper::SLASH_TAG);
213     if (pos != CString::npos) {
214         // entryPoint: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx1/../xxx1/xxx2
215         entryPoint = recordName.substr(0, pos + 1) + moduleRequestName;
216     } else {
217         entryPoint = moduleRequestName;
218     }
219     // entryPoint: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx1/xxx2
220     entryPoint = PathHelper::NormalizePath(entryPoint);
221     entryPoint = ConfirmLoadingIndexOrNot(jsPandaFile, entryPoint);
222     if (!entryPoint.empty()) {
223         return entryPoint;
224     }
225     // the package name may have a '.js' suffix, try to parseThirdPartyPackage
226     entryPoint = ParseThirdPartyPackage(jsPandaFile, recordName, requestName);
227     if (!entryPoint.empty()) {
228         return entryPoint;
229     }
230     // Execute abc locally
231     pos = baseFileName.rfind(PathHelper::SLASH_TAG);
232     if (pos != CString::npos) {
233         baseFileName = baseFileName.substr(0, pos + 1) + moduleRequestName + EXT_NAME_ABC;
234     } else {
235         baseFileName = moduleRequestName + EXT_NAME_ABC;
236     }
237     pos = moduleRequestName.rfind(PathHelper::SLASH_TAG);
238     if (pos != CString::npos) {
239         entryPoint = moduleRequestName.substr(pos + 1);
240     } else {
241         entryPoint = moduleRequestName;
242     }
243     return entryPoint;
244 }
245 
246 /*
247  * Before: ohpmPath:      pkg_modules/.ohpm/pkgName/pkg_modules
248  *         requestName:   requestPkgName
249  * After:  entryPoint:   pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
250  */
FindOhpmEntryPoint(const JSPandaFile * jsPandaFile,const CString & ohpmPath,const CString & requestName)251 CString ModulePathHelper::FindOhpmEntryPoint(const JSPandaFile *jsPandaFile,
252     const CString& ohpmPath, const CString& requestName)
253 {
254     CVector<CString> vec;
255     StringHelper::SplitString(requestName, vec, 0);
256     size_t maxIndex = vec.size() - 1;
257     CString ohpmKey;
258     size_t index = 0;
259     // first we find the ohpmKey by splicing the requestName
260     while (index <= maxIndex) {
261         // maybeKey: pkg_modules/.ohpm/pkgName/pkg_modules/requestPkgName
262         CString maybeKey = ohpmPath + PathHelper::SLASH_TAG + StringHelper::JoinString(vec, 0, index);
263         // ohpmKey: pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName
264         if (jsPandaFile->FindOhmUrlInPF(maybeKey, ohpmKey)) {
265             break;
266         }
267         ++index;
268     }
269     if (ohpmKey.empty()) {
270         return CString();
271     }
272     // second If the ohpmKey is not empty, we will use it to obtain the real entrypoint
273     CString entryPoint;
274     if (index == maxIndex) {
275         // requestName is a packageName
276         // entryPoint: pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
277         entryPoint = jsPandaFile->GetEntryPoint(ohpmKey);
278     } else {
279         // import a specific file or directory
280         ohpmKey = ohpmKey + PathHelper::SLASH_TAG + StringHelper::JoinString(vec, index + 1, maxIndex);
281         entryPoint = ConfirmLoadingIndexOrNot(jsPandaFile, ohpmKey);
282     }
283     return entryPoint;
284 }
285 
FindPackageInTopLevelWithNamespace(const JSPandaFile * jsPandaFile,const CString & requestName,const CString & recordName)286 CString ModulePathHelper::FindPackageInTopLevelWithNamespace(const JSPandaFile *jsPandaFile,
287     const CString& requestName, const CString &recordName)
288 {
289     // find in current module <PACKAGE_PATH_SEGMENT>@[moduleName|namespace]/<requestName>
290     CString entryPoint;
291     CString ohpmPath;
292     if (StringHelper::StringStartWith(recordName, PACKAGE_PATH_SEGMENT)) {
293         size_t pos = recordName.find(PathHelper::SLASH_TAG);
294         if (pos == CString::npos) {
295             LOG_ECMA(DEBUG) << "wrong recordname : " << recordName;
296             return CString();
297         }
298         ohpmPath = recordName.substr(0, pos);
299         entryPoint = FindOhpmEntryPoint(jsPandaFile, recordName.substr(0, pos), requestName);
300     } else {
301         CVector<CString> vec;
302         StringHelper::SplitString(recordName, vec, 0, SEGMENTS_LIMIT_TWO);
303         if (vec.size() < SEGMENTS_LIMIT_TWO) {
304             LOG_ECMA(DEBUG) << "SplitString filed, please check moduleRequestName";
305             return CString();
306         }
307         CString moduleName = vec[1];
308         // If namespace exists, use namespace as moduleName
309         size_t pos = moduleName.find(PathHelper::NAME_SPACE_TAG);
310         if (pos != CString::npos) {
311             moduleName = moduleName.substr(pos + 1);
312         }
313         ohpmPath = CString(PACKAGE_PATH_SEGMENT) + PathHelper::NAME_SPACE_TAG + moduleName;
314         entryPoint = FindOhpmEntryPoint(jsPandaFile, ohpmPath, requestName);
315     }
316     if (!entryPoint.empty()) {
317         return entryPoint;
318     }
319     // find in project directory <packagePath>/<requestName>
320     return FindOhpmEntryPoint(jsPandaFile, PACKAGE_PATH_SEGMENT, requestName);
321 }
322 
323 /*
324  * Before: requestName:  requestPkgName
325  *         recordName:   pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx
326  * After:  entryPoint:   pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
327  */
ParseOhpmPackage(const JSPandaFile * jsPandaFile,const CString & recordName,const CString & requestName)328 CString ModulePathHelper::ParseOhpmPackage(const JSPandaFile *jsPandaFile,
329     const CString &recordName, const CString &requestName)
330 {
331     CString entryPoint;
332     if (StringHelper::StringStartWith(recordName, PACKAGE_PATH_SEGMENT)) {
333         // this way is thirdPartyPackage import ThirdPartyPackage
334         auto info = const_cast<JSPandaFile *>(jsPandaFile)->FindRecordInfo(recordName);
335         // packageName: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName
336         CString packageName = info.npmPackageName;
337         size_t pos = packageName.rfind(PACKAGE_PATH_SEGMENT);
338         if (pos != CString::npos) {
339             packageName.erase(pos, packageName.size() - pos);
340             // ohpmPath: pkg_modules/.ohpm/pkgName/pkg_modules
341             CString ohpmPath = packageName + PACKAGE_PATH_SEGMENT;
342             // entryPoint: pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
343             entryPoint = FindOhpmEntryPoint(jsPandaFile, ohpmPath, requestName);
344             if (!entryPoint.empty()) {
345                 return entryPoint;
346             }
347         }
348     }
349     // Import packages under the current module or project directory
350     return FindPackageInTopLevelWithNamespace(jsPandaFile, requestName, recordName);
351 }
352 
353 /*
354  * Before: requestName:  requestPkgName
355  *         recordName:   pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx
356  *         packagePath:  pkg_modules || node_modules
357  * After:  entryPoint:   pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
358  */
ParseThirdPartyPackage(const JSPandaFile * jsPandaFile,const CString & recordName,const CString & requestName,const CString & packagePath)359 CString ModulePathHelper::ParseThirdPartyPackage(const JSPandaFile *jsPandaFile,
360     const CString &recordName, const CString &requestName, const CString &packagePath)
361 {
362     CString entryPoint;
363     if (StringHelper::StringStartWith(recordName, packagePath)) {
364         auto info = const_cast<JSPandaFile *>(jsPandaFile)->FindRecordInfo(recordName);
365         CString packageName = info.npmPackageName; // pkg_modules/.ohpm/pkgName/pkg_modules/pkgName
366         size_t pos = 0;
367         while (true) {
368             CString key = packageName + PathHelper::SLASH_TAG + packagePath + PathHelper::SLASH_TAG + requestName;
369             entryPoint = FindNpmEntryPoint(jsPandaFile, key);
370             if (!entryPoint.empty()) {
371                 return entryPoint;
372             }
373             pos = packageName.rfind(packagePath) - 1;
374             if (pos == CString::npos || pos < 0) {
375                 break;
376             }
377             packageName.erase(pos, packageName.size() - pos);
378         }
379     }
380     return FindPackageInTopLevel(jsPandaFile, requestName, packagePath);
381 }
382 
383 /*
384  * Before: requestName:  requestPkgName
385  *         recordName:   pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx
386  * After:  entryPoint:   pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
387  */
ParseThirdPartyPackage(const JSPandaFile * jsPandaFile,const CString & recordName,const CString & requestName)388 CString ModulePathHelper::ParseThirdPartyPackage(const JSPandaFile *jsPandaFile,
389     const CString &recordName, const CString &requestName)
390 {
391     // We need to deal with scenarios like this 'json5/' -> 'json5'
392     CString normalizeRequestName = PathHelper::NormalizePath(requestName);
393     CString entryPoint = ParseOhpmPackage(jsPandaFile, recordName, normalizeRequestName);
394     if (!entryPoint.empty()) {
395         return entryPoint;
396     }
397 
398     static CVector<CString> packagePaths = {CString(PACKAGE_PATH_SEGMENT), CString(NPM_PATH_SEGMENT)};
399     // Package compatible with old soft link format
400     for (size_t i = 0; i < packagePaths.size(); ++i) {
401         entryPoint = ParseThirdPartyPackage(jsPandaFile, recordName, normalizeRequestName, packagePaths[i]);
402         if (!entryPoint.empty()) {
403             return entryPoint;
404         }
405     }
406     return CString();
407 }
408 
409 /*
410  * Before: dirPath: Undefined
411  *         fileName: Undefined
412  * After:  dirPath: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx/
413  *         fileName: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx/xxx.abc
414  */
ResolveCurrentPath(JSThread * thread,JSMutableHandle<JSTaggedValue> & dirPath,JSMutableHandle<JSTaggedValue> & fileName,const JSPandaFile * jsPandaFile)415 void ModulePathHelper::ResolveCurrentPath(JSThread *thread, JSMutableHandle<JSTaggedValue> &dirPath,
416     JSMutableHandle<JSTaggedValue> &fileName, const JSPandaFile *jsPandaFile)
417 {
418     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
419     CString fullName = jsPandaFile->GetJSPandaFileDesc();
420     JSHandle<EcmaString> dirPathName = PathHelper::ResolveDirPath(thread, fullName);
421     dirPath.Update(dirPathName.GetTaggedValue());
422 
423     // Get filename from JSPandaFile
424     JSHandle<EcmaString> cbFileName = factory->NewFromUtf8(fullName);
425     fileName.Update(cbFileName.GetTaggedValue());
426 }
427 
FindNpmEntryPoint(const JSPandaFile * jsPandaFile,const CString & packageEntryPoint)428 CString ModulePathHelper::FindNpmEntryPoint(const JSPandaFile *jsPandaFile, const CString &packageEntryPoint)
429 {
430     // if we are currently importing a specific file or directory, we will get the entryPoint here
431     CString entryPoint = ConfirmLoadingIndexOrNot(jsPandaFile, packageEntryPoint);
432     if (!entryPoint.empty()) {
433         return entryPoint;
434     }
435     // When you come here, must import a packageName
436     return jsPandaFile->GetEntryPoint(packageEntryPoint);
437 }
438 
439 /*
440  * Before: requestName:  requestPkgName
441  *         packagePath:  pkg_modules || node_modules
442  * After:  entryPoint:   pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
443  */
FindPackageInTopLevel(const JSPandaFile * jsPandaFile,const CString & requestName,const CString & packagePath)444 CString ModulePathHelper::FindPackageInTopLevel(const JSPandaFile *jsPandaFile,
445     const CString& requestName, const CString &packagePath)
446 {
447     // we find packagePath/0/xxx or packagePath/1/xxx
448     CString entryPoint;
449     for (size_t level = 0; level <= MAX_PACKAGE_LEVEL; ++level) {
450         CString levelStr = std::to_string(level).c_str();
451         CString key = packagePath + PathHelper::SLASH_TAG + levelStr + PathHelper::SLASH_TAG + requestName;
452         entryPoint = FindNpmEntryPoint(jsPandaFile, key);
453         if (!entryPoint.empty()) {
454             return entryPoint;
455         }
456     }
457     return CString();
458 }
459 
IsImportFile(const CString & moduleRequestName)460 bool ModulePathHelper::IsImportFile(const CString &moduleRequestName)
461 {
462     if (moduleRequestName[0] == PathHelper::POINT_TAG) {
463         return true;
464     }
465     size_t pos = moduleRequestName.rfind(PathHelper::POINT_TAG);
466     if (pos != CString::npos) {
467         CString suffix = moduleRequestName.substr(pos);
468         if (suffix == EXT_NAME_JS || suffix == EXT_NAME_TS || suffix == EXT_NAME_ETS || suffix == EXT_NAME_JSON) {
469             return true;
470         }
471     }
472     return false;
473 }
474 
475 /*
476  * Before: xxx/xxx.js || xxx/xxx.ts || xxx/xxx.ets ||xxx/xxx.json
477  * After:  xxx/xxx
478  */
RemoveSuffix(const CString & requestName)479 CString ModulePathHelper::RemoveSuffix(const CString &requestName)
480 {
481     CString res = requestName;
482     size_t pos = res.rfind(PathHelper::POINT_TAG);
483     if (pos != CString::npos) {
484         CString suffix = res.substr(pos);
485         if (suffix == EXT_NAME_JS || suffix == EXT_NAME_TS || suffix == EXT_NAME_ETS || suffix == EXT_NAME_JSON) {
486             res.erase(pos, suffix.length());
487         }
488     }
489     return res;
490 }
491 
NeedTranstale(const CString & requestName)492 bool ModulePathHelper::NeedTranstale(const CString &requestName)
493 {
494     if (StringHelper::StringStartWith(requestName, PREFIX_BUNDLE) ||
495         StringHelper::StringStartWith(requestName, PREFIX_PACKAGE) ||
496         requestName[0] == PathHelper::POINT_TAG ||  // ./
497         (requestName[0] == PathHelper::NAME_SPACE_TAG && // @***:
498          requestName.find(PathHelper::COLON_TAG) != CString::npos)) {
499         return false;
500     }
501     return true;
502 }
503 
504 // Adapt dynamic import using expression input, translate include NativeModule/ohpm/hsp/har.
TranstaleExpressionInput(JSThread * thread,CString & requestPath,const JSPandaFile * jsPandaFile,JSHandle<EcmaString> & specifierString)505 void ModulePathHelper::TranstaleExpressionInput(JSThread *thread, CString &requestPath,
506                                                 const JSPandaFile *jsPandaFile, JSHandle<EcmaString> &specifierString)
507 {
508     LOG_ECMA(DEBUG) << "Enter Translate OhmUrl for DynamicImport, requestPath: " << requestPath;
509     if (StringHelper::StringStartWith(requestPath, RAW_ARKUIX_PREFIX)) {
510         requestPath = StringHelper::Replace(requestPath, RAW_ARKUIX_PREFIX, REQUIRE_NAPI_OHOS_PREFIX);
511     } else {
512         CString outEntryPoint;
513         // FindOhmUrlInPF: frontend generate mapping in abc,
514         // all we need to do is to find the corresponding mapping result.
515         // EXCEPTION: @ohos. @hms. is translated all by runtime.
516         if (jsPandaFile->FindOhmUrlInPF(requestPath, outEntryPoint)) {
517             requestPath = outEntryPoint;
518         }
519         // change origin: @ohos. @hms. -> @ohos: @hms:
520         // change mapping result: @package. @bundle. @xxx. -> @package: @bundle: @xxx:
521         ChangeTag(requestPath);
522     }
523     specifierString = thread->GetEcmaVM()->GetFactory()->NewFromUtf8(requestPath);
524     LOG_ECMA(DEBUG) << "Exit Translate OhmUrl for DynamicImport, resultPath: " << requestPath;
525 }
526 
GetModuleNameWithBaseFile(const CString & baseFileName)527 CString ModulePathHelper::GetModuleNameWithBaseFile(const CString &baseFileName)
528 {
529     size_t pos = CString::npos;
530     if (baseFileName.length() > BUNDLE_INSTALL_PATH_LEN &&
531         baseFileName.compare(0, BUNDLE_INSTALL_PATH_LEN, BUNDLE_INSTALL_PATH) == 0) {
532         pos = BUNDLE_INSTALL_PATH_LEN;
533     }
534     CString moduleName;
535     if (pos != CString::npos) {
536         // baseFileName: /data/storage/el1/bundle/moduleName/ets/xxx/xxx.abc
537         pos = baseFileName.find(PathHelper::SLASH_TAG, BUNDLE_INSTALL_PATH_LEN);
538         if (pos == CString::npos) {
539             LOG_FULL(FATAL) << "Invalid Ohm url, please check.";
540         }
541         moduleName = baseFileName.substr(BUNDLE_INSTALL_PATH_LEN, pos - BUNDLE_INSTALL_PATH_LEN);
542     }
543     return moduleName;
544 }
545 
546 /*
547  * Before: ets/xxx/xxx
548  * After:  bundleName/moduleName/ets/xxx/xxx
549  */
TranslateExpressionInputWithEts(JSThread * thread,const JSPandaFile * jsPandaFile,CString & baseFileName,const CString & requestName)550 CString ModulePathHelper::TranslateExpressionInputWithEts(JSThread *thread, const JSPandaFile *jsPandaFile,
551                                                           CString &baseFileName, const CString &requestName)
552 {
553     CString entryPoint;
554     EcmaVM *vm = thread->GetEcmaVM();
555     CString moduleName = GetModuleNameWithBaseFile(baseFileName);
556     entryPoint = vm->GetBundleName() + PathHelper::SLASH_TAG + moduleName + PathHelper::SLASH_TAG + requestName;
557     if (!jsPandaFile->HasRecord(entryPoint)) {
558         LOG_FULL(ERROR) << "cannot find record '" << entryPoint <<"' from request path '" << requestName << "'.";
559         CString msg = "cannot find record '" + entryPoint + "' from request path'" + requestName +
560             "', please check the request path";
561         ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
562         JSTaggedValue error = factory->GetJSError(ErrorType::REFERENCE_ERROR, msg.c_str()).GetTaggedValue();
563         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, entryPoint);
564     }
565     return entryPoint;
566 }
567 }  // namespace panda::ecmascript