1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #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 if (thread->GetEcmaVM()->IsNormalizedOhmUrlPack() && !StringHelper::StringStartWith(requestName, PREFIX_BUNDLE) &&
25 !StringHelper::StringStartWith(requestName, PREFIX_PACKAGE)) {
26 return ConcatMergeFileNameToNormalized(thread, jsPandaFile, baseFileName, recordName, requestName);
27 }
28
29 if (StringHelper::StringStartWith(requestName, PREFIX_BUNDLE)) {
30 return ParsePrefixBundle(thread, jsPandaFile, baseFileName, requestName, recordName);
31 } else if (StringHelper::StringStartWith(requestName, PREFIX_PACKAGE)) {
32 return requestName.substr(PREFIX_PACKAGE_LEN);
33 } else if (IsImportFile(requestName)) {
34 // this branch save for require/dynamic import/old version sdk
35 // load a relative pathName.
36 // requestName: ./ || ./xxx/xxx.js || ../xxx/xxx.js || ./xxx/xxx
37 return MakeNewRecord(thread, jsPandaFile, baseFileName, recordName, requestName);
38 } else if (StringHelper::StringStartWith(requestName, PREFIX_ETS)) {
39 CString entryPoint = TranslateExpressionInputWithEts(thread, jsPandaFile, baseFileName, requestName);
40 if (entryPoint.empty()) {
41 THROW_MODULE_NOT_FOUND_ERROR_WITH_RETURN_VALUE(thread, requestName, recordName, entryPoint);
42 }
43 return entryPoint;
44 } else {
45 // this branch save for require/dynamic import/old version sdk
46 // requestName: requestPkgName
47 CString entryPoint = ParseThirdPartyPackage(jsPandaFile, recordName, requestName);
48 if (entryPoint.empty()) {
49 THROW_MODULE_NOT_FOUND_ERROR_WITH_RETURN_VALUE(thread, requestName, recordName, entryPoint);
50 }
51 return entryPoint;
52 }
53 LOG_FULL(FATAL) << "this branch is unreachable";
54 UNREACHABLE();
55 }
56
ConcatMergeFileNameToNormalized(JSThread * thread,const JSPandaFile * jsPandaFile,CString & baseFileName,const CString & recordName,CString requestName)57 CString ModulePathHelper::ConcatMergeFileNameToNormalized(JSThread *thread, const JSPandaFile *jsPandaFile,
58 CString &baseFileName, const CString &recordName, CString requestName)
59 {
60 CString prefix(1, PathHelper::NORMALIZED_OHMURL_TAG);
61 if (StringHelper::StringStartWith(requestName, prefix)) {
62 return requestName;
63 } else if (IsImportFile(requestName)) {
64 // this branch save for import "xxx.js" in npm
65 CString inputPath = requestName;
66 CString entryPoint = ConcatImportFileNormalizedOhmurlWithRecordName(thread, jsPandaFile, baseFileName,
67 recordName, requestName);
68 if (entryPoint.empty()) {
69 THROW_MODULE_NOT_FOUND_ERROR_WITH_RETURN_VALUE(thread, inputPath, recordName, requestName);
70 }
71 return entryPoint;
72 } else {
73 // this branch save for require npm
74 TranslateExpressionToNormalized(thread, jsPandaFile, baseFileName, recordName, requestName);
75 }
76 return ParseNormalizedOhmUrl(thread, baseFileName, recordName, requestName);
77 }
78
79 /*
80 * Before: requestName: ../xxx1/xxx2 || ./xxx1
81 * After: &entryPath&version
82 */
ConcatImportFileNormalizedOhmurlWithRecordName(JSThread * thread,const JSPandaFile * jsPandaFile,CString & baseFileName,const CString & recordName,const CString & requestName)83 CString ModulePathHelper::ConcatImportFileNormalizedOhmurlWithRecordName(JSThread *thread,
84 const JSPandaFile *jsPandaFile, CString &baseFileName, const CString &recordName, const CString &requestName)
85 {
86 CString entryPoint;
87 CVector<CString> res = SplitNormalizedRecordName(recordName);
88 CString path = PathHelper::NORMALIZED_OHMURL_TAG + res[NORMALIZED_IMPORT_PATH_INDEX];
89 CString version = res[NORMALIZED_VERSION_INDEX];
90 CString moduleRequestName = requestName;
91 moduleRequestName = RemoveSuffix(moduleRequestName);
92 size_t pos = moduleRequestName.find(PathHelper::CURRENT_DIREATORY_TAG);
93 if (pos == 0) {
94 moduleRequestName = moduleRequestName.substr(CURRENT_DIREATORY_TAG_LEN);
95 }
96 pos = path.rfind(PathHelper::SLASH_TAG);
97 if (pos != CString::npos) {
98 entryPoint = path.substr(0, pos + 1) + moduleRequestName;
99 } else {
100 entryPoint = moduleRequestName;
101 }
102 entryPoint = PathHelper::NormalizePath(entryPoint);
103 moduleRequestName = ConcatImportFileNormalizedOhmurl(entryPoint, "", version);
104 if (jsPandaFile->HasRecord(moduleRequestName)) {
105 return moduleRequestName;
106 }
107 // requestName may be a folder
108 entryPoint += PACKAGE_ENTRY_FILE;
109 entryPoint = PathHelper::NormalizePath(entryPoint);
110 moduleRequestName = ConcatImportFileNormalizedOhmurl(entryPoint, "", version);
111 if (jsPandaFile->HasRecord(moduleRequestName)) {
112 return moduleRequestName;
113 }
114
115 // requestName may be a packageName
116 moduleRequestName = requestName;
117 ConcatOtherNormalizedOhmurl(thread->GetEcmaVM(), jsPandaFile, baseFileName, moduleRequestName);
118 moduleRequestName = ParseNormalizedOhmUrl(thread, baseFileName, recordName, moduleRequestName);
119 if (jsPandaFile->HasRecord(moduleRequestName)) {
120 return moduleRequestName;
121 }
122 return CString();
123 }
124
ReformatPath(CString requestName)125 CString ModulePathHelper::ReformatPath(CString requestName)
126 {
127 CString normalizeStr;
128 if (StringHelper::StringStartWith(requestName, PACKAGE_PATH_SEGMENT) ||
129 StringHelper::StringStartWith(requestName, PREFIX_PACKAGE)) {
130 auto pos = requestName.rfind(PACKAGE_PATH_SEGMENT);
131 ASSERT(pos != CString::npos);
132 normalizeStr = requestName.substr(pos + 1);
133 } else if (StringHelper::StringStartWith(requestName, REQUIRE_NAPI_APP_PREFIX)) {
134 auto pos = requestName.find(PathHelper::SLASH_TAG);
135 pos = requestName.find(PathHelper::SLASH_TAG, pos + 1);
136 ASSERT(pos != CString::npos);
137 normalizeStr = requestName.substr(pos + 1);
138 } else {
139 normalizeStr = requestName;
140 }
141 return normalizeStr;
142 }
143
144 /*
145 * Before: inputFileName: 1. /data/storage/el1/bundle/moduleName@namespace/ets/xxx/xxx.abc
146 2. @bundle:bundleName/moduleName/ets/xxx/xxx.abc
147 3. moduleName/ets/xxx/xxx.abc
148 4. .test/xxx/xxx.abc
149 5. xxx/xxx.abc
150 * After: outBaseFileName: /data/storage/el1/bundle/moduleName/ets/modules.abc
151 * outEntryPoint: bundleName/moduleName/ets/xxx/xxx
152 */
ParseAbcPathAndOhmUrl(EcmaVM * vm,const CString & inputFileName,CString & outBaseFileName,CString & outEntryPoint)153 void ModulePathHelper::ParseAbcPathAndOhmUrl(EcmaVM *vm, const CString &inputFileName,
154 CString &outBaseFileName, CString &outEntryPoint)
155 {
156 size_t pos = CString::npos;
157 if (inputFileName.length() > BUNDLE_INSTALL_PATH_LEN &&
158 inputFileName.compare(0, BUNDLE_INSTALL_PATH_LEN, BUNDLE_INSTALL_PATH) == 0) {
159 pos = BUNDLE_INSTALL_PATH_LEN;
160 }
161 if (pos != CString::npos) {
162 // inputFileName: /data/storage/el1/bundle/moduleName@namespace/ets/xxx/xxx.abc
163 pos = inputFileName.find(PathHelper::SLASH_TAG, BUNDLE_INSTALL_PATH_LEN);
164 if (pos == CString::npos) { // LCOV_EXCL_BR_LINE
165 LOG_FULL(FATAL) << "Invalid Ohm url, please check.";
166 }
167 CString moduleName = inputFileName.substr(BUNDLE_INSTALL_PATH_LEN, pos - BUNDLE_INSTALL_PATH_LEN);
168 PathHelper::DeleteNamespace(moduleName);
169 outBaseFileName = BUNDLE_INSTALL_PATH + moduleName + MERGE_ABC_ETS_MODULES;
170 outEntryPoint = vm->GetBundleName() + PathHelper::SLASH_TAG + inputFileName.substr(BUNDLE_INSTALL_PATH_LEN);
171 } else {
172 // Temporarily handle the relative path sent by arkui
173 // inputFileName: @bundle:bundleName/moduleName/ets/xxx/xxx.abc
174 if (StringHelper::StringStartWith(inputFileName, PREFIX_BUNDLE)) {
175 outEntryPoint = inputFileName.substr(PREFIX_BUNDLE_LEN);
176 outBaseFileName = ParseUrl(vm, outEntryPoint);
177 } else {
178 #if !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS)
179 // inputFileName: moduleName/ets/xxx/xxx.abc
180 outEntryPoint = vm->GetBundleName() + PathHelper::SLASH_TAG + inputFileName;
181 #else
182 // if the inputFileName starts with '.test', the preview test page is started.
183 // in this case, the path ets does not need to be combined.
184 // inputFileName: .test/xxx/xxx.abc
185 if (StringHelper::StringStartWith(inputFileName, PREVIER_TEST_DIR)) {
186 outEntryPoint = vm->GetBundleName() + PathHelper::SLASH_TAG + vm->GetModuleName() +
187 PathHelper::SLASH_TAG + inputFileName;
188 } else {
189 // inputFileName: xxx/xxx.abc
190 outEntryPoint = vm->GetBundleName() + PathHelper::SLASH_TAG + vm->GetModuleName() +
191 MODULE_DEFAULE_ETS + inputFileName;
192 }
193 #endif
194 }
195 }
196 if (StringHelper::StringEndWith(outEntryPoint, EXT_NAME_ABC)) {
197 outEntryPoint.erase(outEntryPoint.length() - EXT_NAME_ABC_LEN, EXT_NAME_ABC_LEN);
198 }
199 if (vm->IsNormalizedOhmUrlPack()) {
200 outEntryPoint = TransformToNormalizedOhmUrl(vm, inputFileName, outBaseFileName, outEntryPoint);
201 }
202 }
203
204 // Unified ohmUrl used be cached: [<bundle name>?]&<pkg name + /src/main + path>&[<version>?]
ConcatUnifiedOhmUrl(const CString & bundleName,const CString & pkgname,const CString & entryPath,const CString & path,const CString & version)205 CString ModulePathHelper::ConcatUnifiedOhmUrl(const CString &bundleName, const CString &pkgname,
206 const CString &entryPath, const CString &path, const CString &version)
207 {
208 if (entryPath.size() != 0) {
209 // entryPath is src/xxx/
210 return bundleName + PathHelper::NORMALIZED_OHMURL_TAG + pkgname + PathHelper::SLASH_TAG + entryPath + path +
211 PathHelper::NORMALIZED_OHMURL_TAG + version;
212 }
213 return bundleName + PathHelper::NORMALIZED_OHMURL_TAG + pkgname + PHYCICAL_FILE_PATH + path +
214 PathHelper::NORMALIZED_OHMURL_TAG + version;
215 }
216
ConcatUnifiedOhmUrl(const CString & bundleName,const CString & normalizedpath,const CString & version)217 CString ModulePathHelper::ConcatUnifiedOhmUrl(const CString &bundleName, const CString &normalizedpath,
218 const CString &version)
219 {
220 return bundleName + PathHelper::NORMALIZED_OHMURL_TAG + normalizedpath + PathHelper::NORMALIZED_OHMURL_TAG +
221 version;
222 }
223
ConcatPreviewTestUnifiedOhmUrl(const CString & bundleName,const CString & pkgname,const CString & path,const CString & version)224 CString ModulePathHelper::ConcatPreviewTestUnifiedOhmUrl(const CString &bundleName, const CString &pkgname,
225 const CString &path, const CString &version)
226 {
227 return bundleName + PathHelper::NORMALIZED_OHMURL_TAG + pkgname + path + PathHelper::NORMALIZED_OHMURL_TAG +
228 version;
229 }
230
ConcatHspFileNameCrossBundle(const CString & bundleName,const CString & moduleName)231 CString ModulePathHelper::ConcatHspFileNameCrossBundle(const CString &bundleName, const CString &moduleName)
232 {
233 CString bundlePath = BUNDLE_INSTALL_PATH;
234 return bundlePath + bundleName + PathHelper::SLASH_TAG + moduleName + PathHelper::SLASH_TAG + moduleName +
235 MERGE_ABC_ETS_MODULES;
236 }
237
ConcatHspFileName(const CString & moduleName)238 CString ModulePathHelper::ConcatHspFileName(const CString &moduleName)
239 {
240 CString bundlePath = BUNDLE_INSTALL_PATH;
241 return bundlePath + moduleName + MERGE_ABC_ETS_MODULES;
242 }
243
TransformToNormalizedOhmUrl(EcmaVM * vm,const CString & inputFileName,const CString & baseFileName,const CString & oldEntryPoint)244 CString ModulePathHelper::TransformToNormalizedOhmUrl(EcmaVM *vm, const CString &inputFileName,
245 const CString &baseFileName, const CString &oldEntryPoint)
246 {
247 CString prefix(1, PathHelper::NORMALIZED_OHMURL_TAG);
248 if (oldEntryPoint == ENTRY_MAIN_FUNCTION || StringHelper::StringStartWith(oldEntryPoint, prefix)) {
249 return oldEntryPoint;
250 }
251 size_t pos = oldEntryPoint.find(PathHelper::SLASH_TAG);
252 size_t pathPos = oldEntryPoint.find(PathHelper::SLASH_TAG, pos + 1);
253 LOG_ECMA(DEBUG) << "TransformToNormalizedOhmUrl inputFileName: " << inputFileName << " oldEntryPoint: " <<
254 oldEntryPoint;
255 if (pos == CString::npos || pathPos == CString::npos) {
256 CString errorMsg = "TransformToNormalizedOhmUrl Invalid Ohmurl: " + oldEntryPoint + ", please check.";
257 THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(vm->GetJSThread(), ErrorType::SYNTAX_ERROR, errorMsg.c_str(),
258 oldEntryPoint);
259 }
260 CString path = oldEntryPoint.substr(pathPos);
261 CString moduleName = oldEntryPoint.substr(pos + 1, pathPos - pos - 1);
262 if (moduleName.find(PathHelper::NAME_SPACE_TAG) != CString::npos) {
263 moduleName = PathHelper::GetHarName(moduleName);
264 }
265 CString pkgname = vm->GetPkgName(moduleName);
266 CString currentModuleName = GetModuleNameWithBaseFile(baseFileName);
267 if (currentModuleName.size() == 0) {
268 currentModuleName = moduleName;
269 }
270 CVector<CString> data = GetPkgContextInfoListElements(vm, currentModuleName, pkgname);
271 CString version;
272 CString entryPath;
273 if (data.size() > 0) {
274 version = data[PKGINFO_VERSION_INDEX];
275 entryPath = data[PKGINFO_ENTRY_PATH_INDEX];
276 } else {
277 return oldEntryPoint;
278 }
279 // If the subPath starts with '.test', it is a preview test, no need to splice the entry path.
280 CString subPath = oldEntryPoint.substr(pathPos + 1);
281 if (StringHelper::StringStartWith(subPath, PREVIER_TEST_DIR)) {
282 return ConcatPreviewTestUnifiedOhmUrl("", pkgname, path, version);
283 }
284 // When the entry path ends with a slash (/), use the entry path to concatenate ohmurl.
285 CString endStr(1, PathHelper::SLASH_TAG);
286 if (entryPath.size() != 0 && StringHelper::StringEndWith(entryPath, endStr)) {
287 size_t endPos = entryPath.rfind(PathHelper::SLASH_TAG);
288 entryPath = entryPath.substr(0, endPos);
289 return ConcatUnifiedOhmUrl("", pkgname, entryPath, path, version);
290 }
291 // bundleName and entryPath is empty.
292 return ConcatUnifiedOhmUrl("", pkgname, "", path, version);
293 }
294
295 /*
296 * Before: recordName: bundleName/moduleName@namespace/xxx/xxx.abc
297 * After: Intra-application cross hap: /data/storage/el1/bundle/bundleName/ets/modules.abc
298 * Cross-application: /data/storage/el1/bundle/bundleName/moduleName/moduleName/ets/modules.abc
299 */
ParseUrl(EcmaVM * vm,const CString & recordName)300 CString ModulePathHelper::ParseUrl(EcmaVM *vm, const CString &recordName)
301 {
302 CVector<CString> vec;
303 StringHelper::SplitString(recordName, vec, 0, SEGMENTS_LIMIT_TWO);
304 if (vec.size() < SEGMENTS_LIMIT_TWO) {
305 LOG_ECMA(DEBUG) << "ParseUrl SplitString filed, please check Url" << recordName;
306 return CString();
307 }
308 CString bundleName = vec[0];
309 CString moduleName = vec[1];
310 PathHelper::DeleteNamespace(moduleName);
311
312 CString baseFileName;
313 if (bundleName != vm->GetBundleName()) {
314 // Cross-application
315 baseFileName = BUNDLE_INSTALL_PATH + bundleName + PathHelper::SLASH_TAG + moduleName +
316 PathHelper::SLASH_TAG + moduleName + MERGE_ABC_ETS_MODULES;
317 } else {
318 // Intra-application cross hap
319 baseFileName = BUNDLE_INSTALL_PATH + moduleName + MERGE_ABC_ETS_MODULES;
320 }
321 return baseFileName;
322 }
323
324 /*
325 * Before: moduleRequestName: @bundle:bundleName/moduleName@namespace/ets/xxx
326 * After: baseFileName: 1./data/storage/el1/bundle/moduleName/ets/modules.abc
327 * 2./data/storage/el1/bundle/bundleName/moduleName/moduleName/ets/modules.abc
328 * entryPoint: bundleName/moduleName@namespace/ets/xxx
329 */
ParsePrefixBundle(JSThread * thread,const JSPandaFile * jsPandaFile,CString & baseFileName,CString moduleRequestName,CString recordName)330 CString ModulePathHelper::ParsePrefixBundle(JSThread *thread, const JSPandaFile *jsPandaFile,
331 [[maybe_unused]] CString &baseFileName, CString moduleRequestName, [[maybe_unused]] CString recordName)
332 {
333 EcmaVM *vm = thread->GetEcmaVM();
334 moduleRequestName = moduleRequestName.substr(PREFIX_BUNDLE_LEN);
335 CString entryPoint = moduleRequestName;
336 if (jsPandaFile->IsRecordWithBundleName()) {
337 CVector<CString> vec;
338 StringHelper::SplitString(moduleRequestName, vec, 0, SEGMENTS_LIMIT_TWO);
339 if (vec.size() < SEGMENTS_LIMIT_TWO) { // LCOV_EXCL_BR_LINE
340 LOG_ECMA(FATAL) << " Exceptional module path : " << moduleRequestName << ", abc path: " <<
341 baseFileName << ", current file name: " << recordName;
342 }
343 CString bundleName = vec[0];
344 CString moduleName = vec[1];
345 PathHelper::DeleteNamespace(moduleName);
346
347 #if !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS)
348 if (bundleName != vm->GetBundleName()) {
349 baseFileName = BUNDLE_INSTALL_PATH + bundleName + PathHelper::SLASH_TAG + moduleName +
350 PathHelper::SLASH_TAG + moduleName + MERGE_ABC_ETS_MODULES;
351 } else if (moduleName != vm->GetModuleName()) {
352 baseFileName = BUNDLE_INSTALL_PATH + moduleName + MERGE_ABC_ETS_MODULES;
353 } else {
354 // Support multi-module card service
355 baseFileName = vm->GetAssetPath();
356 }
357 #else
358 CVector<CString> currentVec;
359 StringHelper::SplitString(moduleRequestName, currentVec, 0, SEGMENTS_LIMIT_TWO);
360 if (currentVec.size() < SEGMENTS_LIMIT_TWO) { // LCOV_EXCL_BR_LINE
361 LOG_ECMA(FATAL) << " Exceptional module path : " << moduleRequestName << ", abc path: " <<
362 baseFileName << ", current file name: " << recordName;
363 }
364 CString currentModuleName = currentVec[1];
365 PathHelper::DeleteNamespace(currentModuleName);
366 if (bundleName != vm->GetBundleName()) {
367 baseFileName = BUNDLE_INSTALL_PATH + bundleName + PathHelper::SLASH_TAG + moduleName +
368 PathHelper::SLASH_TAG + moduleName + MERGE_ABC_ETS_MODULES;
369 } else if (currentModuleName != vm->GetModuleName()) {
370 baseFileName = BUNDLE_INSTALL_PATH + moduleName + MERGE_ABC_ETS_MODULES;
371 }
372 #endif
373 } else {
374 PathHelper::AdaptOldIsaRecord(entryPoint);
375 }
376 return entryPoint;
377 }
378
379
ParseNormalizedOhmUrl(JSThread * thread,CString & baseFileName,const CString & recordName,CString requestName)380 CString ModulePathHelper::ParseNormalizedOhmUrl(JSThread *thread, CString &baseFileName, const CString &recordName,
381 CString requestName)
382 {
383 ASSERT(StringHelper::StringStartWith(requestName, PREFIX_NORMALIZED_NOT_SO));
384 CVector<CString> res = SplitNormalizedOhmurl(requestName);
385 if (res.size() != NORMALIZED_OHMURL_ARGS_NUM) {
386 THROW_MODULE_NOT_FOUND_ERROR_WITH_RETURN_VALUE(thread, requestName, recordName, requestName);
387 }
388 CString moduleName = res[NORMALIZED_MODULE_NAME_INDEX];
389 CString bundleName = res[NORMALIZED_BUNDLE_NAME_INDEX];
390 if (!bundleName.empty() && !moduleName.empty()) {
391 baseFileName = ConcatHspFileNameCrossBundle(bundleName, moduleName);
392 } else if (!moduleName.empty()) {
393 baseFileName = ConcatHspFileName(moduleName);
394 } else if (baseFileName.empty()) {
395 // Support multi-module card service
396 baseFileName = thread->GetEcmaVM()->GetAssetPath();
397 // test card service
398 }
399 CString importPath = res[NORMALIZED_IMPORT_PATH_INDEX];
400 CString version = res[NORMALIZED_VERSION_INDEX];
401 return ConcatUnifiedOhmUrl(bundleName, importPath, version);
402 }
403
404 /*
405 * Before: requestName: ../xxx1/xxx2 || ./b
406 * recordName: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx1/xxx3 || a
407 * After: entryPoint: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx1/xxx2 || b
408 * baseFileName: /data/storage/el1/bundle/moduleName/ets/modules.abc || /home/user/src/a
409 */
MakeNewRecord(JSThread * thread,const JSPandaFile * jsPandaFile,CString & baseFileName,const CString & recordName,const CString & requestName)410 CString ModulePathHelper::MakeNewRecord(JSThread *thread, const JSPandaFile *jsPandaFile, CString &baseFileName,
411 const CString &recordName, const CString &requestName)
412 {
413 CString entryPoint;
414 CString moduleRequestName = RemoveSuffix(requestName);
415 size_t pos = moduleRequestName.find(PathHelper::CURRENT_DIREATORY_TAG);
416 if (pos == 0) {
417 moduleRequestName = moduleRequestName.substr(2); // 2 means jump "./"
418 }
419 pos = recordName.rfind(PathHelper::SLASH_TAG);
420 if (pos != CString::npos) {
421 // entryPoint: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx1/../xxx1/xxx2
422 entryPoint = recordName.substr(0, pos + 1) + moduleRequestName;
423 } else {
424 entryPoint = moduleRequestName;
425 }
426 // entryPoint: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx1/xxx2
427 entryPoint = PathHelper::NormalizePath(entryPoint);
428 entryPoint = ConfirmLoadingIndexOrNot(jsPandaFile, entryPoint);
429 if (!entryPoint.empty()) {
430 return entryPoint;
431 }
432 // the package name may have a '.js' suffix, try to parseThirdPartyPackage
433 entryPoint = ParseThirdPartyPackage(jsPandaFile, recordName, requestName);
434 if (!entryPoint.empty()) {
435 return entryPoint;
436 }
437 // An exception is thrown when the module cannot be found in bundlePack mode.
438 if (StringHelper::StringStartWith(baseFileName, BUNDLE_INSTALL_PATH) && !jsPandaFile->IsBundlePack() &&
439 !jsPandaFile->HasRecord(entryPoint)) {
440 THROW_MODULE_NOT_FOUND_ERROR_WITH_RETURN_VALUE(thread, requestName, recordName, entryPoint);
441 }
442 // Execute abc locally
443 pos = baseFileName.rfind(PathHelper::SLASH_TAG);
444 if (pos != CString::npos) {
445 baseFileName = baseFileName.substr(0, pos + 1) + moduleRequestName + EXT_NAME_ABC;
446 } else {
447 baseFileName = moduleRequestName + EXT_NAME_ABC;
448 }
449 pos = moduleRequestName.rfind(PathHelper::SLASH_TAG);
450 if (pos != CString::npos) {
451 entryPoint = moduleRequestName.substr(pos + 1);
452 } else {
453 entryPoint = moduleRequestName;
454 }
455 return entryPoint;
456 }
457
FindOhpmEntryPoint(const JSPandaFile * jsPandaFile,const CString & ohpmPath,const CString & requestName)458 CString ModulePathHelper::FindOhpmEntryPoint(const JSPandaFile *jsPandaFile,
459 const CString& ohpmPath, const CString& requestName)
460 {
461 CVector<CString> vec;
462 StringHelper::SplitString(requestName, vec, 0);
463 ASSERT(vec.size() > 0);
464 size_t maxIndex = vec.size() - 1;
465 CString ohpmKey;
466 size_t index = 0;
467 // first we find the ohpmKey by splicing the requestName
468 while (index <= maxIndex) {
469 CString maybeKey = ohpmPath + PathHelper::SLASH_TAG + StringHelper::JoinString(vec, 0, index);
470 if (jsPandaFile->FindOhmUrlInPF(maybeKey, ohpmKey)) {
471 break;
472 }
473 ++index;
474 }
475 if (ohpmKey.empty()) {
476 return CString();
477 }
478 // second If the ohpmKey is not empty, we will use it to obtain the real entrypoint
479 CString entryPoint;
480 if (index == maxIndex) {
481 // requestName is a packageName
482 entryPoint = jsPandaFile->GetEntryPoint(ohpmKey);
483 } else {
484 // import a specific file or directory
485 ohpmKey = ohpmKey + PathHelper::SLASH_TAG + StringHelper::JoinString(vec, index + 1, maxIndex);
486 entryPoint = ConfirmLoadingIndexOrNot(jsPandaFile, ohpmKey);
487 }
488 return entryPoint;
489 }
490
FindPackageInTopLevelWithNamespace(const JSPandaFile * jsPandaFile,const CString & requestName,const CString & recordName)491 CString ModulePathHelper::FindPackageInTopLevelWithNamespace(const JSPandaFile *jsPandaFile,
492 const CString& requestName, const CString &recordName)
493 {
494 // find in current module <PACKAGE_PATH_SEGMENT>@[moduleName|namespace]/<requestName>
495 CString entryPoint;
496 CString ohpmPath;
497 if (StringHelper::StringStartWith(recordName, PACKAGE_PATH_SEGMENT)) {
498 size_t pos = recordName.find(PathHelper::SLASH_TAG);
499 if (pos == CString::npos) {
500 LOG_ECMA(DEBUG) << "wrong recordname : " << recordName;
501 return CString();
502 }
503 ohpmPath = recordName.substr(0, pos);
504 entryPoint = FindOhpmEntryPoint(jsPandaFile, recordName.substr(0, pos), requestName);
505 } else {
506 // recordName: moduleName/xxx/xxx
507 CVector<CString> vec;
508 StringHelper::SplitString(recordName, vec, 0, SEGMENTS_LIMIT_TWO);
509 if (vec.size() < SEGMENTS_LIMIT_TWO) {
510 LOG_ECMA(DEBUG) << "SplitString filed, please check moduleRequestName";
511 return CString();
512 }
513 CString moduleName = vec[1];
514 // If namespace exists, use namespace as moduleName
515 size_t pos = moduleName.find(PathHelper::NAME_SPACE_TAG);
516 if (pos != CString::npos) {
517 moduleName = moduleName.substr(pos + 1);
518 }
519 ohpmPath = CString(PACKAGE_PATH_SEGMENT) + PathHelper::NAME_SPACE_TAG + moduleName;
520 entryPoint = FindOhpmEntryPoint(jsPandaFile, ohpmPath, requestName);
521 // If haven't find with namespace, then use moduleName
522 if ((pos != CString::npos) && entryPoint.empty()) {
523 moduleName = vec[1].substr(0, pos);
524 ohpmPath = CString(PACKAGE_PATH_SEGMENT) + PathHelper::NAME_SPACE_TAG + moduleName;
525 entryPoint = FindOhpmEntryPoint(jsPandaFile, ohpmPath, requestName);
526 }
527 }
528 if (!entryPoint.empty()) {
529 return entryPoint;
530 }
531 // find in project directory <packagePath>/<requestName>
532 return FindOhpmEntryPoint(jsPandaFile, PACKAGE_PATH_SEGMENT, requestName);
533 }
534
535 /*
536 * Before: requestName: requestPkgName
537 * recordName: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx
538 * After: entryPoint: pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
539 */
ParseOhpmPackage(const JSPandaFile * jsPandaFile,const CString & recordName,const CString & requestName)540 CString ModulePathHelper::ParseOhpmPackage(const JSPandaFile *jsPandaFile,
541 const CString &recordName, const CString &requestName)
542 {
543 CString entryPoint;
544 if (StringHelper::StringStartWith(recordName, PACKAGE_PATH_SEGMENT)) {
545 // this way is thirdPartyPackage import ThirdPartyPackage
546 auto info = const_cast<JSPandaFile *>(jsPandaFile)->FindRecordInfo(recordName);
547 // packageName: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName
548 CString packageName = info.npmPackageName;
549 size_t pos = packageName.rfind(PACKAGE_PATH_SEGMENT);
550 if (pos != CString::npos) {
551 packageName.erase(pos, packageName.size() - pos);
552 // ohpmPath: pkg_modules/.ohpm/pkgName/pkg_modules
553 CString ohpmPath = packageName + PACKAGE_PATH_SEGMENT;
554 // entryPoint: pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
555 entryPoint = FindOhpmEntryPoint(jsPandaFile, ohpmPath, requestName);
556 if (!entryPoint.empty()) {
557 return entryPoint;
558 }
559 }
560 }
561 // Import packages under the current module or project directory
562 return FindPackageInTopLevelWithNamespace(jsPandaFile, requestName, recordName);
563 }
564
565 /*
566 * Before: requestName: requestPkgName
567 * recordName: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx
568 * packagePath: pkg_modules || node_modules
569 * After: entryPoint: pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
570 */
ParseThirdPartyPackage(const JSPandaFile * jsPandaFile,const CString & recordName,const CString & requestName,const CString & packagePath)571 CString ModulePathHelper::ParseThirdPartyPackage(const JSPandaFile *jsPandaFile,
572 const CString &recordName, const CString &requestName, const CString &packagePath)
573 {
574 CString entryPoint;
575 if (StringHelper::StringStartWith(recordName, packagePath)) {
576 auto info = const_cast<JSPandaFile *>(jsPandaFile)->FindRecordInfo(recordName);
577 CString packageName = info.npmPackageName; // pkg_modules/.ohpm/pkgName/pkg_modules/pkgName
578 size_t pos = 0;
579 while (true) {
580 CString key = packageName + PathHelper::SLASH_TAG + packagePath + PathHelper::SLASH_TAG + requestName;
581 entryPoint = FindNpmEntryPoint(jsPandaFile, key);
582 if (!entryPoint.empty()) {
583 return entryPoint;
584 }
585 size_t index = packageName.rfind(packagePath);
586 ASSERT(index > 0);
587 pos = index - 1;
588 if (pos == CString::npos || pos < 0) {
589 break;
590 }
591 packageName.erase(pos, packageName.size() - pos);
592 }
593 }
594 return FindPackageInTopLevel(jsPandaFile, requestName, packagePath);
595 }
596
597 /*
598 * Before: requestName: requestPkgName
599 * recordName: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx
600 * After: entryPoint: pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
601 */
ParseThirdPartyPackage(const JSPandaFile * jsPandaFile,const CString & recordName,const CString & requestName)602 CString ModulePathHelper::ParseThirdPartyPackage(const JSPandaFile *jsPandaFile,
603 const CString &recordName, const CString &requestName)
604 {
605 // We need to deal with scenarios like this 'json5/' -> 'json5'
606 CString normalizeRequestName = PathHelper::NormalizePath(requestName);
607 CString entryPoint = ParseOhpmPackage(jsPandaFile, recordName, normalizeRequestName);
608 if (!entryPoint.empty()) {
609 return entryPoint;
610 }
611
612 static CVector<CString> packagePaths = {CString(PACKAGE_PATH_SEGMENT), CString(NPM_PATH_SEGMENT)};
613 // Package compatible with old soft link format
614 for (size_t i = 0; i < packagePaths.size(); ++i) {
615 entryPoint = ParseThirdPartyPackage(jsPandaFile, recordName, normalizeRequestName, packagePaths[i]);
616 if (!entryPoint.empty()) {
617 return entryPoint;
618 }
619 }
620 return CString();
621 }
622
623 /*
624 * Before: dirPath: Undefined
625 * fileName: Undefined
626 * After: dirPath: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx/
627 * fileName: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx/xxx.abc
628 */
ResolveCurrentPath(CString & dirPath,CString & fileName,const JSPandaFile * jsPandaFile)629 void ModulePathHelper::ResolveCurrentPath(CString &dirPath, CString &fileName, const JSPandaFile *jsPandaFile)
630 {
631 ASSERT(jsPandaFile != nullptr);
632 fileName = jsPandaFile->GetJSPandaFileDesc();
633 dirPath = PathHelper::ResolveDirPath(fileName);
634 }
635
FindNpmEntryPoint(const JSPandaFile * jsPandaFile,const CString & packageEntryPoint)636 CString ModulePathHelper::FindNpmEntryPoint(const JSPandaFile *jsPandaFile, const CString &packageEntryPoint)
637 {
638 // if we are currently importing a specific file or directory, we will get the entryPoint here
639 CString entryPoint = ConfirmLoadingIndexOrNot(jsPandaFile, packageEntryPoint);
640 if (!entryPoint.empty()) {
641 return entryPoint;
642 }
643 // When you come here, must import a packageName
644 return jsPandaFile->GetEntryPoint(packageEntryPoint);
645 }
646
647 /*
648 * Before: requestName: requestPkgName
649 * packagePath: pkg_modules || node_modules
650 * After: entryPoint: pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
651 */
FindPackageInTopLevel(const JSPandaFile * jsPandaFile,const CString & requestName,const CString & packagePath)652 CString ModulePathHelper::FindPackageInTopLevel(const JSPandaFile *jsPandaFile,
653 const CString& requestName, const CString &packagePath)
654 {
655 // we find packagePath/0/xxx or packagePath/1/xxx
656 CString entryPoint;
657 for (size_t level = 0; level <= MAX_PACKAGE_LEVEL; ++level) {
658 CString levelStr = std::to_string(level).c_str();
659 CString key = packagePath + PathHelper::SLASH_TAG + levelStr + PathHelper::SLASH_TAG + requestName;
660 entryPoint = FindNpmEntryPoint(jsPandaFile, key);
661 if (!entryPoint.empty()) {
662 return entryPoint;
663 }
664 }
665 return CString();
666 }
667
IsImportFile(const CString & moduleRequestName)668 bool ModulePathHelper::IsImportFile(const CString &moduleRequestName)
669 {
670 if (moduleRequestName[0] == PathHelper::POINT_TAG) {
671 return true;
672 }
673 size_t pos = moduleRequestName.rfind(PathHelper::POINT_TAG);
674 if (pos != CString::npos) {
675 CString suffix = moduleRequestName.substr(pos);
676 if (suffix == EXT_NAME_JS || suffix == EXT_NAME_TS || suffix == EXT_NAME_ETS || suffix == EXT_NAME_JSON) {
677 return true;
678 }
679 }
680 return false;
681 }
682
683 /*
684 * Before: xxx/xxx.js || xxx/xxx.ts || xxx/xxx.ets ||xxx/xxx.json
685 * After: xxx/xxx
686 */
RemoveSuffix(const CString & requestName)687 CString ModulePathHelper::RemoveSuffix(const CString &requestName)
688 {
689 CString res = requestName;
690 size_t pos = res.rfind(PathHelper::POINT_TAG);
691 if (pos != CString::npos) {
692 CString suffix = res.substr(pos);
693 if (suffix == EXT_NAME_JS || suffix == EXT_NAME_TS || suffix == EXT_NAME_ETS ||
694 suffix == EXT_NAME_JSON || suffix == EXT_NAME_MJS) {
695 res.erase(pos, suffix.length());
696 }
697 }
698 return res;
699 }
700
NeedTranstale(const CString & requestName)701 bool ModulePathHelper::NeedTranstale(const CString &requestName)
702 {
703 if (StringHelper::StringStartWith(requestName, PREFIX_BUNDLE) ||
704 StringHelper::StringStartWith(requestName, PREFIX_PACKAGE) ||
705 requestName[0] == PathHelper::POINT_TAG || // ./
706 (requestName[0] == PathHelper::NAME_SPACE_TAG && // @***:
707 requestName.find(PathHelper::COLON_TAG) != CString::npos)) {
708 return false;
709 }
710 return true;
711 }
712
713 // Adapt dynamic import using expression input, translate include NativeModule/ohpm/hsp/har.
TranstaleExpressionInput(const JSPandaFile * jsPandaFile,CString & requestPath)714 void ModulePathHelper::TranstaleExpressionInput(const JSPandaFile *jsPandaFile, CString &requestPath)
715 {
716 LOG_ECMA(DEBUG) << "Enter Translate OhmUrl for DynamicImport, requestPath: " << requestPath;
717 if (StringHelper::StringStartWith(requestPath, RAW_ARKUIX_PREFIX)) {
718 requestPath = StringHelper::Replace(requestPath, RAW_ARKUIX_PREFIX, REQUIRE_NAPI_OHOS_PREFIX);
719 return;
720 }
721 CString outEntryPoint;
722 // FindOhmUrlInPF: frontend generate mapping in abc,
723 // all we need to do is to find the corresponding mapping result.
724 // EXCEPTION: @ohos. @hms. is translated all by runtime.
725 if (jsPandaFile->FindOhmUrlInPF(requestPath, outEntryPoint)) {
726 // this path for moduleName(xxx or xxx/xxx) -> moduleName/Index;
727 requestPath = outEntryPoint;
728 } else {
729 ParseCrossModuleFile(jsPandaFile, requestPath);
730 }
731 // change origin: @ohos. @hms. -> @ohos: @hms:
732 // change mapping result: @package. @bundle. @xxx. -> @package: @bundle: @xxx:
733 ChangeTag(requestPath);
734 }
735
736 /*
737 * Before: 1. /data/storage/el1/bundle/moduleName/ets/xxx/xxx.abc
738 * 2. /data/storage/el1/bundle/bundleName/moduleName/moduleName/ets/modules.abc
739 * After: moduleName
740 */
GetModuleNameWithBaseFile(const CString & baseFileName)741 CString ModulePathHelper::GetModuleNameWithBaseFile(const CString &baseFileName)
742 {
743 size_t pos = CString::npos;
744 if (baseFileName.length() > BUNDLE_INSTALL_PATH_LEN &&
745 baseFileName.compare(0, BUNDLE_INSTALL_PATH_LEN, BUNDLE_INSTALL_PATH) == 0) {
746 pos = BUNDLE_INSTALL_PATH_LEN;
747 }
748 CString moduleName;
749 if (pos != CString::npos) {
750 // baseFileName: /data/storage/el1/bundle/moduleName/ets/xxx/xxx.abc
751 pos = baseFileName.find(PathHelper::SLASH_TAG, BUNDLE_INSTALL_PATH_LEN);
752 if (pos == CString::npos) { // LCOV_EXCL_BR_LINE
753 LOG_FULL(FATAL) << "Invalid Ohm url, please check.";
754 }
755 moduleName = baseFileName.substr(BUNDLE_INSTALL_PATH_LEN, pos - BUNDLE_INSTALL_PATH_LEN);
756 // baseFileName /data/storage/el1/bundle/bundleName/moduleName/moduleName/ets/modules.abc
757 if (moduleName.find(PathHelper::POINT_STRING_TAG) != CString::npos) {
758 // length of /data/storage/el1/bundle/bundleName/
759 size_t pathLength = BUNDLE_INSTALL_PATH_LEN + moduleName.size() + 1;
760 pos = baseFileName.find(PathHelper::SLASH_TAG, pathLength);
761 moduleName = baseFileName.substr(pathLength, pos - pathLength);
762 }
763 }
764 return moduleName;
765 }
766
767 /*
768 * Before: ets/xxx/xxx
769 * After: bundleName/moduleName/ets/xxx/xxx
770 */
TranslateExpressionInputWithEts(JSThread * thread,const JSPandaFile * jsPandaFile,CString & baseFileName,const CString & requestName)771 CString ModulePathHelper::TranslateExpressionInputWithEts(JSThread *thread, const JSPandaFile *jsPandaFile,
772 CString &baseFileName, const CString &requestName)
773 {
774 CString entryPoint;
775 EcmaVM *vm = thread->GetEcmaVM();
776 CString moduleName = GetModuleNameWithBaseFile(baseFileName);
777 entryPoint = vm->GetBundleName() + PathHelper::SLASH_TAG + moduleName + PathHelper::SLASH_TAG + requestName;
778 if (!jsPandaFile->HasRecord(entryPoint)) {
779 return CString();
780 }
781 return entryPoint;
782 }
783
784 /*
785 * input requestPath: moduleName/src/main/xxx/xxx/xxx
786 * moduleName/xxx/xxx
787 * moduleName : singleLevelName or twoLevelName
788 * output requestPath: @bundle.bundleName/moduleName/xxx/xxx/xxx
789 * @bundle.bundleName/moduleName/xxx/xxx
790 */
ParseCrossModuleFile(const JSPandaFile * jsPandaFile,CString & requestPath)791 void ModulePathHelper::ParseCrossModuleFile(const JSPandaFile *jsPandaFile, CString &requestPath)
792 {
793 size_t pos = requestPath.find(PathHelper::SLASH_TAG);
794 if (pos == CString::npos) {
795 return;
796 }
797 CString moduleName = requestPath.substr(0, pos);
798 CString outEntryPoint;
799 // try get mapped module path by single level moduleName.
800 bool isModuleName = jsPandaFile->FindOhmUrlInPF(moduleName, outEntryPoint);
801 if (!isModuleName) {
802 // retry get mapped module path by two level moduleName
803 pos = requestPath.find(PathHelper::SLASH_TAG, pos + 1);
804 if (pos == CString::npos) {
805 return;
806 }
807 moduleName = requestPath.substr(0, pos);
808 isModuleName = jsPandaFile->FindOhmUrlInPF(moduleName, outEntryPoint);
809 }
810 if (isModuleName) {
811 // outEntryPoint: @bundle.bundleName/moduleName/Index
812 CString relativePath = requestPath.substr(pos);
813 // get rid of Index, get pure perfix(@bundle.bundleName/moduleName).
814 size_t index = outEntryPoint.rfind(PathHelper::SLASH_TAG);
815 // get rid of src/main. Concat perfix and input relative path.
816 if (relativePath.find(PHYCICAL_FILE_PATH, 0) == 0) {
817 requestPath = outEntryPoint.substr(0, index) + PathHelper::SLASH_TAG +
818 requestPath.substr(pos + PHYCICAL_FILE_PATH_LEN);
819 return;
820 }
821 requestPath = outEntryPoint.substr(0, index) + requestPath.substr(pos);
822 }
823 }
824
ParseFileNameToVMAName(const CString & filename)825 CString ModulePathHelper::ParseFileNameToVMAName(const CString &filename)
826 {
827 CString tag = VMA_NAME_ARKTS_CODE;
828 size_t pos = CString::npos;
829 if (filename.empty()) {
830 return tag;
831 }
832
833 if (filename.find(EXT_NAME_JS) != CString::npos) {
834 pos = filename.find(EXT_NAME_Z_SO);
835 if (pos == CString::npos) {
836 return tag;
837 }
838 CString moduleName = filename.substr(0, pos);
839 pos = moduleName.rfind(PathHelper::POINT_TAG);
840 if (pos == CString::npos) {
841 return tag + PathHelper::COLON_TAG + filename;
842 }
843 CString realModuleName = moduleName.substr(pos + 1);
844 CString realFileName = realModuleName;
845 std::transform(realFileName.begin(), realFileName.end(), realFileName.begin(), ::tolower);
846 CString file = PREFIX_LIB + realFileName + EXT_NAME_Z_SO + PathHelper::SLASH_TAG + realModuleName + EXT_NAME_JS;
847 return tag + PathHelper::COLON_TAG + file;
848 }
849
850 if (filename.find(EXT_NAME_ABC) != CString::npos) {
851 pos = filename.find(BUNDLE_INSTALL_PATH);
852 if (pos == CString::npos) {
853 return tag + PathHelper::COLON_TAG + filename;
854 }
855 CString file = filename.substr(BUNDLE_INSTALL_PATH_LEN);
856 return tag + PathHelper::COLON_TAG + file;
857 }
858
859 return tag;
860 }
861
GetPkgContextInfoListElements(EcmaVM * vm,CString & moduleName,CString & packageName)862 CVector<CString> ModulePathHelper::GetPkgContextInfoListElements(EcmaVM *vm, CString &moduleName,
863 CString &packageName)
864 {
865 CVector<CString> resultList;
866 if (packageName.size() == 0) {
867 return resultList;
868 }
869 CMap<CString, CMap<CString, CVector<CString>>> pkgContextList = vm->GetPkgContextInfoLit();
870 if (pkgContextList.find(moduleName) == pkgContextList.end()) {
871 return resultList;
872 }
873 CMap<CString, CVector<CString>> pkgList = pkgContextList[moduleName];
874 if (pkgList.find(packageName) == pkgList.end()) {
875 return resultList;
876 }
877 resultList = pkgList[packageName];
878 return resultList;
879 }
880
ConcatImportFileNormalizedOhmurl(const CString & recordPath,const CString & requestName,const CString & version)881 CString ModulePathHelper::ConcatImportFileNormalizedOhmurl(const CString &recordPath, const CString &requestName,
882 const CString &version)
883 {
884 return recordPath + requestName + PathHelper::NORMALIZED_OHMURL_TAG + version;
885 }
886
ConcatNativeSoNormalizedOhmurl(const CString & moduleName,const CString & bundleName,const CString & pkgName,const CString & version)887 CString ModulePathHelper::ConcatNativeSoNormalizedOhmurl(const CString &moduleName, const CString &bundleName,
888 const CString &pkgName, const CString &version)
889 {
890 CString prefix = PREFIX_NORMALIZED_SO;
891 return prefix + PathHelper::NORMALIZED_OHMURL_TAG + moduleName + PathHelper::NORMALIZED_OHMURL_TAG +
892 bundleName + PathHelper::NORMALIZED_OHMURL_TAG + pkgName + PathHelper::NORMALIZED_OHMURL_TAG + version;
893 }
894
ConcatNotSoNormalizedOhmurl(const CString & moduleName,const CString & bundleName,const CString & pkgName,const CString & entryPath,const CString & version)895 CString ModulePathHelper::ConcatNotSoNormalizedOhmurl(const CString &moduleName, const CString &bundleName,
896 const CString &pkgName, const CString &entryPath, const CString &version)
897 {
898 CString prefix = PREFIX_NORMALIZED_NOT_SO;
899 return prefix + PathHelper::NORMALIZED_OHMURL_TAG + moduleName + PathHelper::NORMALIZED_OHMURL_TAG +
900 bundleName + PathHelper::NORMALIZED_OHMURL_TAG + pkgName + PathHelper::SLASH_TAG + entryPath +
901 PathHelper::NORMALIZED_OHMURL_TAG + version;
902 }
903
NeedTranslateToNormalized(const CString & requestName)904 bool ModulePathHelper::NeedTranslateToNormalized(const CString &requestName)
905 {
906 // if start with @normalized:xxx @native:xxx.xxx @ohos:xxx
907 // no translation is required
908 if (StringHelper::StringStartWith(requestName, PREFIX_NORMALIZED) ||
909 (requestName[0] == PathHelper::NAME_SPACE_TAG &&
910 requestName.find(PathHelper::COLON_TAG) != CString::npos)) {
911 return false;
912 }
913 return true;
914 }
915
TranslateExpressionToNormalized(JSThread * thread,const JSPandaFile * jsPandaFile,CString & baseFileName,const CString & recordName,CString & requestPath)916 CString ModulePathHelper::TranslateExpressionToNormalized(JSThread *thread, const JSPandaFile *jsPandaFile,
917 [[maybe_unused]] CString &baseFileName, const CString &recordName, CString &requestPath)
918 {
919 if (!NeedTranslateToNormalized(requestPath)) {
920 return requestPath;
921 }
922 if (StringHelper::StringStartWith(requestPath, RAW_ARKUIX_PREFIX)) {
923 return StringHelper::Replace(requestPath, RAW_ARKUIX_PREFIX, REQUIRE_NAPI_OHOS_PREFIX);
924 }
925 EcmaVM *vm = thread->GetEcmaVM();
926 CString inputPath = requestPath;
927 if (IsImportFile(requestPath)) {
928 CString entryPoint = ConcatImportFileNormalizedOhmurlWithRecordName(thread, jsPandaFile, baseFileName,
929 recordName, requestPath);
930 if (entryPoint.empty()) {
931 THROW_MODULE_NOT_FOUND_ERROR_WITH_RETURN_VALUE(thread, inputPath, recordName, requestPath);
932 }
933 } else if (StringHelper::StringStartWith(requestPath, PREFIX_ETS)) {
934 size_t pos = recordName.find(PREFIX_ETS);
935 if (pos != CString::npos) {
936 requestPath = ConcatImportFileNormalizedOhmurl(recordName.substr(0, pos), requestPath);
937 }
938 if (!jsPandaFile->HasRecord(requestPath)) {
939 THROW_MODULE_NOT_FOUND_ERROR_WITH_RETURN_VALUE(thread, inputPath, recordName, requestPath);
940 }
941 } else {
942 ConcatOtherNormalizedOhmurl(vm, jsPandaFile, baseFileName, requestPath);
943 }
944 return requestPath;
945 }
946
947 /*
948 * Before: requestPath: 1. @ohos.xxx
949 * 2. har or har/xxx/xxx
950 * 3. hsp or hsp/xxx/xxx
951 * 4. libentry.so
952 * After: requestPath: 1. @ohos:xxx or @native:xxx.xxx
953 * 2. @normalized:N&moduleName&bundleName&entryPath&version
954 * 3. @normalized:N&moduleName&bundleName&entryPath&
955 * 4. @normalized:Y&&bundleName&entryPath&version
956 */
ConcatOtherNormalizedOhmurl(EcmaVM * vm,const JSPandaFile * jsPandaFile,CString & baseFileName,CString & requestPath)957 void ModulePathHelper::ConcatOtherNormalizedOhmurl(EcmaVM *vm, const JSPandaFile *jsPandaFile,
958 [[maybe_unused]] CString &baseFileName, CString &requestPath)
959 {
960 CString entryPath;
961 CString currentModuleName = GetModuleNameWithBaseFile(baseFileName);
962 CString pkgName = vm->GetPkgNameWithAlias(requestPath);
963 CVector<CString> data = GetPkgContextInfoListElements(vm, currentModuleName, pkgName);
964 if (data.size() != 0) {
965 requestPath = ConcatNormalizedOhmurlWithData(data, pkgName, entryPath);
966 return;
967 }
968 // When requestName contains '/', it is considered to be a file path.
969 CString result;
970 size_t filePathPos = requestPath.find(PathHelper::SLASH_TAG);
971 if (filePathPos != CString::npos) {
972 result = ConcatOtherNormalizedOhmurlWithFilePath(vm, filePathPos, currentModuleName, requestPath);
973 // Try to get the PkgContextInfo by two levels alias
974 if (result.size() == 0) {
975 filePathPos = requestPath.find(PathHelper::SLASH_TAG, filePathPos + 1);
976 if (filePathPos != CString::npos) {
977 result = ConcatOtherNormalizedOhmurlWithFilePath(vm, filePathPos, currentModuleName, requestPath);
978 }
979 }
980 }
981 if (result.size() == 0) {
982 CString outEntryPoint;
983 if (jsPandaFile->FindOhmUrlInPF(requestPath, outEntryPoint)) {
984 requestPath = outEntryPoint;
985 }
986 ChangeTag(requestPath);
987 return;
988 }
989 requestPath = result;
990 }
991
ConcatOtherNormalizedOhmurlWithFilePath(EcmaVM * vm,size_t filePathPos,CString & moduleName,const CString & requestPath)992 CString ModulePathHelper::ConcatOtherNormalizedOhmurlWithFilePath(EcmaVM *vm, size_t filePathPos,
993 CString &moduleName, const CString &requestPath)
994 {
995 CString result;
996 CString alias = requestPath.substr(0, filePathPos);
997 CString entryPath = requestPath.substr(filePathPos + 1);
998 CString pkgName = vm->GetPkgNameWithAlias(alias);
999 CVector<CString> data = GetPkgContextInfoListElements(vm, moduleName, pkgName);
1000 if (data.size() != 0) {
1001 result = ConcatNormalizedOhmurlWithData(data, pkgName, entryPath);
1002 }
1003 return result;
1004 }
1005
ConcatNormalizedOhmurlWithData(CVector<CString> & data,CString & pkgName,CString & entryPath)1006 CString ModulePathHelper::ConcatNormalizedOhmurlWithData(CVector<CString> &data, CString &pkgName, CString &entryPath)
1007 {
1008 CString bundleName = data[PKGINFO_BUDNLE_NAME_INDEX];
1009 CString moduleName = data[PKGINFO_MODULE_NAME_INDEX];
1010 CString version = data[PKGINFO_VERSION_INDEX];
1011 if (entryPath.size() == 0) {
1012 entryPath = data[PKGINFO_ENTRY_PATH_INDEX];
1013 }
1014 CString isSO = data[PKGINFO_IS_SO_INDEX];
1015 size_t pos = entryPath.find(PathHelper::CURRENT_DIREATORY_TAG);
1016 if (pos == 0) {
1017 entryPath = entryPath.substr(CURRENT_DIREATORY_TAG_LEN);
1018 }
1019 if (isSO == TRUE_FLAG) {
1020 return ConcatNativeSoNormalizedOhmurl(moduleName, bundleName, pkgName, version);
1021 } else {
1022 entryPath = RemoveSuffix(entryPath);
1023 return ConcatNotSoNormalizedOhmurl(moduleName, bundleName, pkgName, entryPath, version);
1024 }
1025 }
1026
TranslateNapiFileRequestPath(JSThread * thread,const CString & modulePath,const CString & requestName)1027 CString ModulePathHelper::TranslateNapiFileRequestPath(JSThread *thread, const CString &modulePath,
1028 const CString &requestName)
1029 {
1030 if (thread->GetEcmaVM()->IsNormalizedOhmUrlPack()) {
1031 CString moduleName = GetModuleNameWithPath(modulePath);
1032 return PathHelper::NORMALIZED_OHMURL_TAG + moduleName + PHYCICAL_FILE_PATH + PathHelper::SLASH_TAG +
1033 requestName + PathHelper::NORMALIZED_OHMURL_TAG;
1034 } else {
1035 return modulePath + PathHelper::SLASH_TAG + requestName;
1036 }
1037 }
1038
SplitNormalizedOhmurl(const CString & ohmurl)1039 CVector<CString> ModulePathHelper::SplitNormalizedOhmurl(const CString &ohmurl)
1040 {
1041 CVector<CString> res;
1042 size_t start = 0;
1043 size_t pos = ohmurl.find(PathHelper::NORMALIZED_OHMURL_TAG);
1044 while (pos != CString::npos) {
1045 CString element = ohmurl.substr(start, pos - start);
1046 res.emplace_back(element);
1047 start = pos + 1;
1048 pos = ohmurl.find(PathHelper::NORMALIZED_OHMURL_TAG, start);
1049 }
1050 CString tail = ohmurl.substr(start);
1051 res.emplace_back(tail);
1052 return res;
1053 }
1054
SplitNormalizedRecordName(const CString & recordName)1055 CVector<CString> ModulePathHelper::SplitNormalizedRecordName(const CString &recordName)
1056 {
1057 CVector<CString> res(NORMALIZED_OHMURL_ARGS_NUM);
1058 int index = NORMALIZED_OHMURL_ARGS_NUM - 1;
1059 CString temp;
1060 int endIndex = static_cast<int>(recordName.size()) - 1;
1061 for (int i = endIndex; i >= 0; i--) {
1062 char element = recordName[i];
1063 if (element == PathHelper::NORMALIZED_OHMURL_TAG) {
1064 res[index] = temp;
1065 index--;
1066 temp = "";
1067 continue;
1068 }
1069 temp = element + temp;
1070 }
1071 if (temp.size()) {
1072 res[index] = temp;
1073 }
1074 return res;
1075 }
1076
1077 /*
1078 * Before: 1. bundleName/moduleName/xxx/xxx
1079 2. bunldeName&moduleName/xxx/xxx&
1080 * After: bundleName
1081 */
GetBundleNameWithRecordName(EcmaVM * vm,const CString & recordName)1082 CString ModulePathHelper::GetBundleNameWithRecordName(EcmaVM *vm, const CString &recordName)
1083 {
1084 CString bundleName;
1085 if (vm->IsNormalizedOhmUrlPack()) {
1086 CVector<CString> res = ModulePathHelper::SplitNormalizedRecordName(recordName);
1087 bundleName = res[ModulePathHelper::NORMALIZED_BUNDLE_NAME_INDEX];
1088 if (bundleName.size() == 0) {
1089 bundleName = vm->GetBundleName();
1090 }
1091 } else {
1092 size_t pos = recordName.find(PathHelper::SLASH_TAG);
1093 bundleName = recordName.substr(0, pos);
1094 }
1095 return bundleName;
1096 }
1097
1098 // this function convert for ESModule name string(Utf8)
Utf8ConvertToString(JSTaggedValue str)1099 CString ModulePathHelper::Utf8ConvertToString(JSTaggedValue str)
1100 {
1101 return EcmaStringAccessor(str).Utf8ConvertToString();
1102 }
1103 } // namespace panda::ecmascript