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