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