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