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 if (pos == CString::npos) { 143 LOG_FULL(FATAL) << "Invalid Ohm url, please check."; 144 } 145 CString moduleName = inputFileName.substr(startStrLen, pos - startStrLen); 146 outFileName = BUNDLE_INSTALL_PATH + moduleName + MERGE_ABC_ETS_MODULES; 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 #if !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS) 155 entryPoint = vm->GetBundleName() + "/" + inputFileName; 156 #else 157 entryPoint = vm->GetBundleName() + "/" + vm->GetModuleName() + MODULE_DEFAULE_ETS + inputFileName; 158 #endif 159 } 160 } 161 if (StringHelper::StringEndWith(entryPoint, EXT_NAME_ABC)) { 162 entryPoint.erase(entryPoint.length() - EXT_NAME_ABC_LEN, EXT_NAME_ABC_LEN); 163 } 164 return entryPoint; 165 } 166 CropNamespaceIfAbsent(CString & moduleName)167 static void CropNamespaceIfAbsent(CString &moduleName) 168 { 169 size_t pos = moduleName.find(NAME_SPACE_TAG); 170 if (pos == CString::npos) { 171 return; 172 } 173 moduleName.erase(pos, moduleName.size() - pos); 174 } 175 176 // current ohmUrl format : @bundle:bundlename/modulename@namespace/entry/src/index ParseUrl(EcmaVM * vm,const CString & entryPoint)177 static CString ParseUrl(EcmaVM *vm, const CString &entryPoint) 178 { 179 CVector<CString> vec; 180 StringHelper::SplitString(entryPoint, vec, 0, SEGMENTS_LIMIT_TWO); 181 if (vec.size() < SEGMENTS_LIMIT_TWO) { 182 LOG_ECMA(DEBUG) << "ParseUrl SplitString filed, please check Url" << entryPoint; 183 return CString(); 184 } 185 CString bundleName = vec[0]; 186 CString moduleName = vec[1]; 187 CropNamespaceIfAbsent(moduleName); 188 189 CString baseFileName; 190 if (bundleName != vm->GetBundleName()) { 191 // Cross-application 192 baseFileName = 193 BUNDLE_INSTALL_PATH + bundleName + "/" + moduleName + "/" + moduleName + MERGE_ABC_ETS_MODULES; 194 } else { 195 // Intra-application cross hap 196 baseFileName = BUNDLE_INSTALL_PATH + moduleName + MERGE_ABC_ETS_MODULES; 197 } 198 return baseFileName; 199 } 200 ParseHapPath(const CString & fileName)201 static std::string ParseHapPath(const CString &fileName) 202 { 203 CString bundleSubInstallName(BUNDLE_SUB_INSTALL_PATH); 204 size_t startStrLen = bundleSubInstallName.length(); 205 if (fileName.length() > startStrLen && fileName.compare(0, startStrLen, bundleSubInstallName) == 0) { 206 CString hapPath = fileName.substr(startStrLen); 207 size_t pos = hapPath.find(MERGE_ABC_ETS_MODULES); 208 if (pos != CString::npos) { 209 return hapPath.substr(0, pos).c_str(); 210 } 211 } 212 return std::string(); 213 } 214 CroppingRecord(CString & recordName)215 static void CroppingRecord(CString &recordName) 216 { 217 size_t pos = recordName.find('/'); 218 if (pos != CString::npos) { 219 pos = recordName.find('/', pos + 1); 220 if (pos != CString::npos) { 221 recordName = recordName.substr(pos + 1); 222 } 223 } 224 } 225 ParsePrefixBundle(JSThread * thread,const JSPandaFile * jsPandaFile,CString & baseFileName,CString moduleRequestName,CString recordName)226 static CString ParsePrefixBundle(JSThread *thread, const JSPandaFile *jsPandaFile, 227 [[maybe_unused]] CString &baseFileName, CString moduleRequestName, [[maybe_unused]] CString recordName) 228 { 229 EcmaVM *vm = thread->GetEcmaVM(); 230 moduleRequestName = moduleRequestName.substr(PREFIX_BUNDLE_LEN); 231 CString entryPoint = moduleRequestName; 232 if (jsPandaFile->IsRecordWithBundleName()) { 233 CVector<CString> vec; 234 StringHelper::SplitString(moduleRequestName, vec, 0, SEGMENTS_LIMIT_TWO); 235 if (vec.size() < SEGMENTS_LIMIT_TWO) { 236 LOG_ECMA(INFO) << "SplitString filed, please check moduleRequestName"; 237 return CString(); 238 } 239 CString bundleName = vec[0]; 240 CString moduleName = vec[1]; 241 CropNamespaceIfAbsent(moduleName); 242 243 #if !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS) 244 if (bundleName != vm->GetBundleName()) { 245 baseFileName = 246 BUNDLE_INSTALL_PATH + bundleName + '/' + moduleName + '/' + moduleName + MERGE_ABC_ETS_MODULES; 247 } else { 248 baseFileName = BUNDLE_INSTALL_PATH + moduleName + MERGE_ABC_ETS_MODULES; 249 } 250 #else 251 CVector<CString> currentVec; 252 StringHelper::SplitString(recordName, currentVec, 0, SEGMENTS_LIMIT_TWO); 253 if (vec.size() < SEGMENTS_LIMIT_TWO) { 254 LOG_ECMA(INFO) << "SplitString filed, please check moduleRequestName"; 255 return CString(); 256 } 257 CString currentModuleName = currentVec[1]; 258 CropNamespaceIfAbsent(currentModuleName); 259 if (bundleName != vm->GetBundleName() || moduleName != currentModuleName) { 260 entryPoint = PREVIEW_OF_ACROSS_HAP_FLAG; 261 LOG_NO_TAG(ERROR) << "[ArkRuntime Log] Importing shared package is not supported in the Previewer."; 262 } 263 #endif 264 } else { 265 CroppingRecord(entryPoint); 266 } 267 return entryPoint; 268 } 269 MakeNewRecord(const JSPandaFile * jsPandaFile,CString & baseFileName,const CString & recordName,const CString & requestName)270 static CString MakeNewRecord(const JSPandaFile *jsPandaFile, CString &baseFileName, const CString &recordName, 271 const CString &requestName) 272 { 273 CString entryPoint; 274 CString moduleRequestName = RemoveSuffix(requestName); 275 size_t pos = moduleRequestName.find("./"); 276 if (pos == 0) { 277 moduleRequestName = moduleRequestName.substr(2); // 2 means jump "./" 278 } 279 pos = recordName.rfind('/'); 280 if (pos != CString::npos) { 281 entryPoint = recordName.substr(0, pos + 1) + moduleRequestName; 282 } else { 283 entryPoint = moduleRequestName; 284 } 285 entryPoint = NormalizePath(entryPoint); 286 entryPoint = ConfirmLoadingIndexOrNot(jsPandaFile, entryPoint); 287 if (!entryPoint.empty()) { 288 return entryPoint; 289 } 290 // the package name may have a '.js' suffix, try to parseThirdPartyPackage 291 entryPoint = ParseThirdPartyPackage(jsPandaFile, recordName, requestName, NPM_PATH_SEGMENT); 292 if (!entryPoint.empty()) { 293 return entryPoint; 294 } 295 // Execute abc locally 296 pos = baseFileName.rfind('/'); 297 if (pos != CString::npos) { 298 baseFileName = baseFileName.substr(0, pos + 1) + moduleRequestName + EXT_NAME_ABC; 299 } else { 300 baseFileName = moduleRequestName + EXT_NAME_ABC; 301 } 302 pos = moduleRequestName.rfind('/'); 303 if (pos != CString::npos) { 304 entryPoint = moduleRequestName.substr(pos + 1); 305 } else { 306 entryPoint = moduleRequestName; 307 } 308 return entryPoint; 309 } 310 ConfirmLoadingIndexOrNot(const JSPandaFile * jsPandaFile,const CString & packageEntryPoint)311 static CString ConfirmLoadingIndexOrNot(const JSPandaFile *jsPandaFile, const CString &packageEntryPoint) 312 { 313 CString entryPoint = packageEntryPoint; 314 if (jsPandaFile->HasRecord(entryPoint)) { 315 return entryPoint; 316 } 317 // Possible import directory 318 entryPoint += PACKAGE_ENTRY_FILE; 319 if (jsPandaFile->HasRecord(entryPoint)) { 320 return entryPoint; 321 } 322 return CString(); 323 } 324 FindNpmEntryPoint(const JSPandaFile * jsPandaFile,const CString & packageEntryPoint)325 static CString FindNpmEntryPoint(const JSPandaFile *jsPandaFile, const CString &packageEntryPoint) 326 { 327 // if we are currently importing a specific file or directory, we will get the entryPoint here 328 CString entryPoint = ConfirmLoadingIndexOrNot(jsPandaFile, packageEntryPoint); 329 if (!entryPoint.empty()) { 330 return entryPoint; 331 } 332 // When you come here, must import a packageName 333 return jsPandaFile->GetEntryPoint(packageEntryPoint); 334 } 335 FindPackageInTopLevel(const JSPandaFile * jsPandaFile,const CString & requestName,const CString & packagePath)336 static CString FindPackageInTopLevel(const JSPandaFile *jsPandaFile, const CString& requestName, 337 const CString &packagePath) 338 { 339 // we find node_modules/0/xxx or node_modules/1/xxx 340 CString entryPoint; 341 for (size_t level = 0; level <= MAX_PACKAGE_LEVEL; ++level) { 342 CString levelStr = std::to_string(level).c_str(); 343 CString key = packagePath + "/" + levelStr + '/' + requestName; 344 entryPoint = FindNpmEntryPoint(jsPandaFile, key); 345 if (!entryPoint.empty()) { 346 return entryPoint; 347 } 348 } 349 return CString(); 350 } 351 FindOhpmEntryPoint(const JSPandaFile * jsPandaFile,const CString & ohpmPath,const CString & requestName)352 static CString FindOhpmEntryPoint(const JSPandaFile *jsPandaFile, const CString& ohpmPath, 353 const CString& requestName) 354 { 355 CVector<CString> vec; 356 StringHelper::SplitString(requestName, vec, 0); 357 size_t maxIndex = vec.size() - 1; 358 CString ohpmKey; 359 size_t index = 0; 360 // first we find the ohpmKey by splicing the requestName 361 while (index <= maxIndex) { 362 CString maybeKey = ohpmPath + "/" + StringHelper::JoinString(vec, 0, index); 363 ohpmKey = jsPandaFile->GetNpmEntries(maybeKey); 364 if (!ohpmKey.empty()) { 365 break; 366 } 367 ++index; 368 } 369 if (ohpmKey.empty()) { 370 return CString(); 371 } 372 // second If the ohpmKey is not empty, we will use it to obtain the real entrypoint 373 CString entryPoint; 374 if (index == maxIndex) { 375 // requestName is a packageName 376 entryPoint = jsPandaFile->GetEntryPoint(ohpmKey); 377 } else { 378 // import a specific file or directory 379 ohpmKey = ohpmKey + "/" + StringHelper::JoinString(vec, index + 1, maxIndex); 380 entryPoint = ConfirmLoadingIndexOrNot(jsPandaFile, ohpmKey); 381 } 382 return entryPoint; 383 } 384 FindPackageInTopLevelWithNamespace(const JSPandaFile * jsPandaFile,const CString & requestName,const CString & recordName)385 static CString FindPackageInTopLevelWithNamespace(const JSPandaFile *jsPandaFile, const CString& requestName, 386 const CString &recordName) 387 { 388 // find in current module <PACKAGE_PATH_SEGMENT>@[moduleName|namespace]/<requestName> 389 CString entryPoint; 390 CString ohpmPath; 391 if (StringHelper::StringStartWith(recordName, PACKAGE_PATH_SEGMENT)) { 392 size_t pos = recordName.find('/'); 393 if (pos == CString::npos) { 394 LOG_ECMA(DEBUG) << "wrong recordname : " << recordName; 395 return CString(); 396 } 397 ohpmPath = recordName.substr(0, pos); 398 entryPoint = FindOhpmEntryPoint(jsPandaFile, recordName.substr(0, pos), requestName); 399 } else { 400 CVector<CString> vec; 401 StringHelper::SplitString(recordName, vec, 0, SEGMENTS_LIMIT_TWO); 402 if (vec.size() < SEGMENTS_LIMIT_TWO) { 403 LOG_ECMA(DEBUG) << "SplitString filed, please check moduleRequestName"; 404 return CString(); 405 } 406 CString moduleName = vec[1]; 407 // If namespace exists, use namespace as moduleName 408 size_t pos = moduleName.find(NAME_SPACE_TAG); 409 if (pos != CString::npos) { 410 moduleName = moduleName.substr(pos + 1); 411 } 412 ohpmPath = CString(PACKAGE_PATH_SEGMENT) + NAME_SPACE_TAG + moduleName; 413 entryPoint = FindOhpmEntryPoint(jsPandaFile, ohpmPath, requestName); 414 } 415 if (!entryPoint.empty()) { 416 return entryPoint; 417 } 418 // find in project directory <packagePath>/<requestName> 419 return FindOhpmEntryPoint(jsPandaFile, PACKAGE_PATH_SEGMENT, requestName); 420 } 421 ParseOhpmPackage(const JSPandaFile * jsPandaFile,const CString & recordName,const CString & requestName)422 static CString ParseOhpmPackage(const JSPandaFile *jsPandaFile, const CString &recordName, 423 const CString &requestName) 424 { 425 CString entryPoint; 426 if (StringHelper::StringStartWith(recordName, PACKAGE_PATH_SEGMENT)) { 427 //this way is thirdPartyPackage import ThirdPartyPackage 428 auto info = const_cast<JSPandaFile *>(jsPandaFile)->FindRecordInfo(recordName); 429 CString packageName = info.npmPackageName; 430 size_t pos = packageName.rfind(PACKAGE_PATH_SEGMENT); 431 if (pos != CString::npos) { 432 packageName.erase(pos, packageName.size() - pos); 433 CString ohpmPath = packageName + PACKAGE_PATH_SEGMENT; 434 entryPoint = FindOhpmEntryPoint(jsPandaFile, ohpmPath, requestName); 435 if (!entryPoint.empty()) { 436 return entryPoint; 437 } 438 } 439 } 440 // Import packages under the current module or project directory 441 return FindPackageInTopLevelWithNamespace(jsPandaFile, requestName, recordName); 442 } 443 ParseThirdPartyPackage(const JSPandaFile * jsPandaFile,const CString & recordName,const CString & requestName,const CString & packagePath)444 static CString ParseThirdPartyPackage(const JSPandaFile *jsPandaFile, const CString &recordName, 445 const CString &requestName, const CString &packagePath) 446 { 447 CString entryPoint; 448 if (StringHelper::StringStartWith(recordName, packagePath)) { 449 auto info = const_cast<JSPandaFile *>(jsPandaFile)->FindRecordInfo(recordName); 450 CString packageName = info.npmPackageName; 451 size_t pos = 0; 452 while (true) { 453 CString key = packageName + '/' + packagePath + "/" + requestName; 454 entryPoint = FindNpmEntryPoint(jsPandaFile, key); 455 if (!entryPoint.empty()) { 456 return entryPoint; 457 } 458 pos = packageName.rfind(packagePath) - 1; 459 if (pos == CString::npos || pos < 0) { 460 break; 461 } 462 packageName.erase(pos, packageName.size() - pos); 463 } 464 } 465 return FindPackageInTopLevel(jsPandaFile, requestName, packagePath); 466 } 467 ParseThirdPartyPackage(const JSPandaFile * jsPandaFile,const CString & recordName,const CString & requestName)468 static CString ParseThirdPartyPackage(const JSPandaFile *jsPandaFile, const CString &recordName, 469 const CString &requestName) 470 { 471 static CVector<CString> packagePaths = {CString(PACKAGE_PATH_SEGMENT), CString(NPM_PATH_SEGMENT)}; 472 // We need to deal with scenarios like this 'json5/' -> 'json5' 473 CString normalizeRequestName = NormalizePath(requestName); 474 CString entryPoint = ParseOhpmPackage(jsPandaFile, recordName, normalizeRequestName); 475 if (!entryPoint.empty()) { 476 return entryPoint; 477 } 478 // Package compatible with old soft link format 479 for (size_t i = 0; i < packagePaths.size(); ++i) { 480 entryPoint = ParseThirdPartyPackage(jsPandaFile, recordName, normalizeRequestName, packagePaths[i]); 481 if (!entryPoint.empty()) { 482 return entryPoint; 483 } 484 } 485 return CString(); 486 } 487 IsImportFile(CString & moduleRequestName)488 static bool IsImportFile(CString &moduleRequestName) 489 { 490 if (moduleRequestName[0] == '.') { 491 return true; 492 } 493 size_t pos = moduleRequestName.rfind('.'); 494 if (pos != CString::npos) { 495 CString suffix = moduleRequestName.substr(pos); 496 if (suffix == EXT_NAME_JS || suffix == EXT_NAME_TS || suffix == EXT_NAME_ETS || suffix == EXT_NAME_JSON) { 497 return true; 498 } 499 } 500 return false; 501 } 502 RemoveSuffix(const CString & requestName)503 static CString RemoveSuffix(const CString &requestName) 504 { 505 CString res = requestName; 506 size_t pos = res.rfind('.'); 507 if (pos != CString::npos) { 508 CString suffix = res.substr(pos); 509 if (suffix == EXT_NAME_JS || suffix == EXT_NAME_TS || suffix == EXT_NAME_ETS || suffix == EXT_NAME_JSON) { 510 res.erase(pos, suffix.length()); 511 } 512 } 513 return res; 514 } 515 ConcatFileNameWithMerge(JSThread * thread,const JSPandaFile * jsPandaFile,CString & baseFileName,CString recordName,CString requestName)516 static CString ConcatFileNameWithMerge(JSThread *thread, const JSPandaFile *jsPandaFile, CString &baseFileName, 517 CString recordName, CString requestName) 518 { 519 CString entryPoint; 520 if (StringHelper::StringStartWith(requestName, PREFIX_BUNDLE)) { 521 entryPoint = ParsePrefixBundle(thread, jsPandaFile, baseFileName, requestName, recordName); 522 } else if (StringHelper::StringStartWith(requestName, PREFIX_PACKAGE)) { 523 entryPoint = requestName.substr(PREFIX_PACKAGE_LEN); 524 } else if (IsImportFile(requestName)) { // load a relative pathName. 525 entryPoint = MakeNewRecord(jsPandaFile, baseFileName, recordName, requestName); 526 } else { 527 entryPoint = ParseThirdPartyPackage(jsPandaFile, recordName, requestName); 528 } 529 if (entryPoint.empty()) { 530 LOG_ECMA(ERROR) << "Failed to resolve the requested entryPoint. baseFileName : '" << baseFileName << 531 "'. RecordName : '" << recordName << "'. RequestName : '" << requestName << "'."; 532 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 533 CString msg = "failed to load module'" + requestName + "' which imported by '" + 534 recordName + "'. Please check the target path."; 535 JSTaggedValue error = factory->GetJSError(ErrorType::REFERENCE_ERROR, msg.c_str()).GetTaggedValue(); 536 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, entryPoint); 537 } 538 return entryPoint; 539 } 540 }; 541 } // namespace panda::ecmascript::base 542 #endif // ECMASCRIPT_BASE_PATH_HELPER_H