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(recordName, 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() || moduleName != currentModuleName) {
185 entryPoint = PREVIEW_OF_ACROSS_HAP_FLAG;
186 if (vm->EnableReportModuleResolvingFailure()) {
187 LOG_NO_TAG(ERROR) << "[ArkRuntime Log] Importing shared package is not supported in the Previewer.";
188 }
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 ohpmKey = jsPandaFile->GetNpmEntries(maybeKey);
265 if (!ohpmKey.empty()) {
266 break;
267 }
268 ++index;
269 }
270 if (ohpmKey.empty()) {
271 return CString();
272 }
273 // second If the ohpmKey is not empty, we will use it to obtain the real entrypoint
274 CString entryPoint;
275 if (index == maxIndex) {
276 // requestName is a packageName
277 // entryPoint: pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
278 entryPoint = jsPandaFile->GetEntryPoint(ohpmKey);
279 } else {
280 // import a specific file or directory
281 ohpmKey = ohpmKey + PathHelper::SLASH_TAG + StringHelper::JoinString(vec, index + 1, maxIndex);
282 entryPoint = ConfirmLoadingIndexOrNot(jsPandaFile, ohpmKey);
283 }
284 return entryPoint;
285 }
286
FindPackageInTopLevelWithNamespace(const JSPandaFile * jsPandaFile,const CString & requestName,const CString & recordName)287 CString ModulePathHelper::FindPackageInTopLevelWithNamespace(const JSPandaFile *jsPandaFile,
288 const CString& requestName, const CString &recordName)
289 {
290 // find in current module <PACKAGE_PATH_SEGMENT>@[moduleName|namespace]/<requestName>
291 CString entryPoint;
292 CString ohpmPath;
293 if (StringHelper::StringStartWith(recordName, PACKAGE_PATH_SEGMENT)) {
294 size_t pos = recordName.find(PathHelper::SLASH_TAG);
295 if (pos == CString::npos) {
296 LOG_ECMA(DEBUG) << "wrong recordname : " << recordName;
297 return CString();
298 }
299 ohpmPath = recordName.substr(0, pos);
300 entryPoint = FindOhpmEntryPoint(jsPandaFile, recordName.substr(0, pos), requestName);
301 } else {
302 CVector<CString> vec;
303 StringHelper::SplitString(recordName, vec, 0, SEGMENTS_LIMIT_TWO);
304 if (vec.size() < SEGMENTS_LIMIT_TWO) {
305 LOG_ECMA(DEBUG) << "SplitString filed, please check moduleRequestName";
306 return CString();
307 }
308 CString moduleName = vec[1];
309 // If namespace exists, use namespace as moduleName
310 size_t pos = moduleName.find(PathHelper::NAME_SPACE_TAG);
311 if (pos != CString::npos) {
312 moduleName = moduleName.substr(pos + 1);
313 }
314 ohpmPath = CString(PACKAGE_PATH_SEGMENT) + PathHelper::NAME_SPACE_TAG + moduleName;
315 entryPoint = FindOhpmEntryPoint(jsPandaFile, ohpmPath, requestName);
316 }
317 if (!entryPoint.empty()) {
318 return entryPoint;
319 }
320 // find in project directory <packagePath>/<requestName>
321 return FindOhpmEntryPoint(jsPandaFile, PACKAGE_PATH_SEGMENT, requestName);
322 }
323
324 /*
325 * Before: requestName: requestPkgName
326 * recordName: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx
327 * After: entryPoint: pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
328 */
ParseOhpmPackage(const JSPandaFile * jsPandaFile,const CString & recordName,const CString & requestName)329 CString ModulePathHelper::ParseOhpmPackage(const JSPandaFile *jsPandaFile,
330 const CString &recordName, const CString &requestName)
331 {
332 CString entryPoint;
333 if (StringHelper::StringStartWith(recordName, PACKAGE_PATH_SEGMENT)) {
334 // this way is thirdPartyPackage import ThirdPartyPackage
335 auto info = const_cast<JSPandaFile *>(jsPandaFile)->FindRecordInfo(recordName);
336 // packageName: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName
337 CString packageName = info.npmPackageName;
338 size_t pos = packageName.rfind(PACKAGE_PATH_SEGMENT);
339 if (pos != CString::npos) {
340 packageName.erase(pos, packageName.size() - pos);
341 // ohpmPath: pkg_modules/.ohpm/pkgName/pkg_modules
342 CString ohpmPath = packageName + PACKAGE_PATH_SEGMENT;
343 // entryPoint: pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
344 entryPoint = FindOhpmEntryPoint(jsPandaFile, ohpmPath, requestName);
345 if (!entryPoint.empty()) {
346 return entryPoint;
347 }
348 }
349 }
350 // Import packages under the current module or project directory
351 return FindPackageInTopLevelWithNamespace(jsPandaFile, requestName, recordName);
352 }
353
354 /*
355 * Before: requestName: requestPkgName
356 * recordName: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx
357 * packagePath: pkg_modules || node_modules
358 * After: entryPoint: pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
359 */
ParseThirdPartyPackage(const JSPandaFile * jsPandaFile,const CString & recordName,const CString & requestName,const CString & packagePath)360 CString ModulePathHelper::ParseThirdPartyPackage(const JSPandaFile *jsPandaFile,
361 const CString &recordName, const CString &requestName, const CString &packagePath)
362 {
363 CString entryPoint;
364 if (StringHelper::StringStartWith(recordName, packagePath)) {
365 auto info = const_cast<JSPandaFile *>(jsPandaFile)->FindRecordInfo(recordName);
366 CString packageName = info.npmPackageName; // pkg_modules/.ohpm/pkgName/pkg_modules/pkgName
367 size_t pos = 0;
368 while (true) {
369 CString key = packageName + PathHelper::SLASH_TAG + packagePath + PathHelper::SLASH_TAG + requestName;
370 entryPoint = FindNpmEntryPoint(jsPandaFile, key);
371 if (!entryPoint.empty()) {
372 return entryPoint;
373 }
374 pos = packageName.rfind(packagePath) - 1;
375 if (pos == CString::npos || pos < 0) {
376 break;
377 }
378 packageName.erase(pos, packageName.size() - pos);
379 }
380 }
381 return FindPackageInTopLevel(jsPandaFile, requestName, packagePath);
382 }
383
384 /*
385 * Before: requestName: requestPkgName
386 * recordName: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx
387 * After: entryPoint: pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
388 */
ParseThirdPartyPackage(const JSPandaFile * jsPandaFile,const CString & recordName,const CString & requestName)389 CString ModulePathHelper::ParseThirdPartyPackage(const JSPandaFile *jsPandaFile,
390 const CString &recordName, const CString &requestName)
391 {
392 // We need to deal with scenarios like this 'json5/' -> 'json5'
393 CString normalizeRequestName = PathHelper::NormalizePath(requestName);
394 CString entryPoint = ParseOhpmPackage(jsPandaFile, recordName, normalizeRequestName);
395 if (!entryPoint.empty()) {
396 return entryPoint;
397 }
398
399 static CVector<CString> packagePaths = {CString(PACKAGE_PATH_SEGMENT), CString(NPM_PATH_SEGMENT)};
400 // Package compatible with old soft link format
401 for (size_t i = 0; i < packagePaths.size(); ++i) {
402 entryPoint = ParseThirdPartyPackage(jsPandaFile, recordName, normalizeRequestName, packagePaths[i]);
403 if (!entryPoint.empty()) {
404 return entryPoint;
405 }
406 }
407 return CString();
408 }
409
410 /*
411 * Before: dirPath: Undefined
412 * fileName: Undefined
413 * After: dirPath: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx/
414 * fileName: pkg_modules/.ohpm/pkgName/pkg_modules/pkgName/xxx/xxx.abc
415 */
ResolveCurrentPath(JSThread * thread,JSMutableHandle<JSTaggedValue> & dirPath,JSMutableHandle<JSTaggedValue> & fileName,const JSPandaFile * jsPandaFile)416 void ModulePathHelper::ResolveCurrentPath(JSThread *thread, JSMutableHandle<JSTaggedValue> &dirPath,
417 JSMutableHandle<JSTaggedValue> &fileName, const JSPandaFile *jsPandaFile)
418 {
419 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
420 CString fullName = jsPandaFile->GetJSPandaFileDesc();
421 JSHandle<EcmaString> dirPathName = PathHelper::ResolveDirPath(thread, fullName);
422 dirPath.Update(dirPathName.GetTaggedValue());
423
424 // Get filename from JSPandaFile
425 JSHandle<EcmaString> cbFileName = factory->NewFromUtf8(fullName);
426 fileName.Update(cbFileName.GetTaggedValue());
427 }
428
FindNpmEntryPoint(const JSPandaFile * jsPandaFile,const CString & packageEntryPoint)429 CString ModulePathHelper::FindNpmEntryPoint(const JSPandaFile *jsPandaFile, const CString &packageEntryPoint)
430 {
431 // if we are currently importing a specific file or directory, we will get the entryPoint here
432 CString entryPoint = ConfirmLoadingIndexOrNot(jsPandaFile, packageEntryPoint);
433 if (!entryPoint.empty()) {
434 return entryPoint;
435 }
436 // When you come here, must import a packageName
437 return jsPandaFile->GetEntryPoint(packageEntryPoint);
438 }
439
440 /*
441 * Before: requestName: requestPkgName
442 * packagePath: pkg_modules || node_modules
443 * After: entryPoint: pkg_modules/.ohpm/requestPkgName/pkg_modules/requestPkgName/xxx
444 */
FindPackageInTopLevel(const JSPandaFile * jsPandaFile,const CString & requestName,const CString & packagePath)445 CString ModulePathHelper::FindPackageInTopLevel(const JSPandaFile *jsPandaFile,
446 const CString& requestName, const CString &packagePath)
447 {
448 // we find packagePath/0/xxx or packagePath/1/xxx
449 CString entryPoint;
450 for (size_t level = 0; level <= MAX_PACKAGE_LEVEL; ++level) {
451 CString levelStr = std::to_string(level).c_str();
452 CString key = packagePath + PathHelper::SLASH_TAG + levelStr + PathHelper::SLASH_TAG + requestName;
453 entryPoint = FindNpmEntryPoint(jsPandaFile, key);
454 if (!entryPoint.empty()) {
455 return entryPoint;
456 }
457 }
458 return CString();
459 }
460
IsImportFile(const CString & moduleRequestName)461 bool ModulePathHelper::IsImportFile(const CString &moduleRequestName)
462 {
463 if (moduleRequestName[0] == PathHelper::POINT_TAG) {
464 return true;
465 }
466 size_t pos = moduleRequestName.rfind(PathHelper::POINT_TAG);
467 if (pos != CString::npos) {
468 CString suffix = moduleRequestName.substr(pos);
469 if (suffix == EXT_NAME_JS || suffix == EXT_NAME_TS || suffix == EXT_NAME_ETS || suffix == EXT_NAME_JSON) {
470 return true;
471 }
472 }
473 return false;
474 }
475
476 /*
477 * Before: xxx/xxx.js || xxx/xxx.ts || xxx/xxx.ets ||xxx/xxx.json
478 * After: xxx/xxx
479 */
RemoveSuffix(const CString & requestName)480 CString ModulePathHelper::RemoveSuffix(const CString &requestName)
481 {
482 CString res = requestName;
483 size_t pos = res.rfind(PathHelper::POINT_TAG);
484 if (pos != CString::npos) {
485 CString suffix = res.substr(pos);
486 if (suffix == EXT_NAME_JS || suffix == EXT_NAME_TS || suffix == EXT_NAME_ETS || suffix == EXT_NAME_JSON) {
487 res.erase(pos, suffix.length());
488 }
489 }
490 return res;
491 }
492 } // namespace panda::ecmascript::base