13af6ab5fSopenharmony_ci/** 23af6ab5fSopenharmony_ci * Copyright (c) 2023-2024 Huawei Device Co., Ltd. 33af6ab5fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 43af6ab5fSopenharmony_ci * you may not use this file except in compliance with the License. 53af6ab5fSopenharmony_ci * You may obtain a copy of the License at 63af6ab5fSopenharmony_ci * 73af6ab5fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 83af6ab5fSopenharmony_ci * 93af6ab5fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 103af6ab5fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 113af6ab5fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 123af6ab5fSopenharmony_ci * See the License for the specific language governing permissions and 133af6ab5fSopenharmony_ci * limitations under the License. 143af6ab5fSopenharmony_ci */ 153af6ab5fSopenharmony_ci 163af6ab5fSopenharmony_ci#include "arktsconfig.h" 173af6ab5fSopenharmony_ci#include "libpandabase/utils/json_builder.h" 183af6ab5fSopenharmony_ci#include "libpandabase/utils/json_parser.h" 193af6ab5fSopenharmony_ci#include "libpandabase/os/filesystem.h" 203af6ab5fSopenharmony_ci#include "util/language.h" 213af6ab5fSopenharmony_ci#include "generated/signatures.h" 223af6ab5fSopenharmony_ci 233af6ab5fSopenharmony_ci#include <fstream> 243af6ab5fSopenharmony_ci#include <regex> 253af6ab5fSopenharmony_ci#include <sstream> 263af6ab5fSopenharmony_ci#include <system_error> 273af6ab5fSopenharmony_ci 283af6ab5fSopenharmony_ci#ifndef ARKTSCONFIG_USE_FILESYSTEM 293af6ab5fSopenharmony_ci#include <dirent.h> 303af6ab5fSopenharmony_ci#include <sys/types.h> 313af6ab5fSopenharmony_ci#include <unistd.h> 323af6ab5fSopenharmony_ci#else 333af6ab5fSopenharmony_ci#if __has_include(<filesystem>) 343af6ab5fSopenharmony_ci#include <filesystem> 353af6ab5fSopenharmony_cinamespace fs = std::filesystem; 363af6ab5fSopenharmony_ci#elif __has_include(<experimental/filesystem>) 373af6ab5fSopenharmony_ci#include <experimental/filesystem> 383af6ab5fSopenharmony_cinamespace fs = std::experimental::filesystem; 393af6ab5fSopenharmony_ci#endif 403af6ab5fSopenharmony_ci#endif 413af6ab5fSopenharmony_ci 423af6ab5fSopenharmony_cinamespace ark::es2panda { 433af6ab5fSopenharmony_ci 443af6ab5fSopenharmony_citemplate <class... Ts> 453af6ab5fSopenharmony_cistatic bool Check(bool cond, const Ts &...msgs) 463af6ab5fSopenharmony_ci{ 473af6ab5fSopenharmony_ci if (!cond) { 483af6ab5fSopenharmony_ci ((std::cerr << "ArkTsConfig error: ") << ... << msgs); 493af6ab5fSopenharmony_ci return false; 503af6ab5fSopenharmony_ci } 513af6ab5fSopenharmony_ci 523af6ab5fSopenharmony_ci return true; 533af6ab5fSopenharmony_ci} 543af6ab5fSopenharmony_ci 553af6ab5fSopenharmony_cistatic bool IsAbsolute(const std::string &path) 563af6ab5fSopenharmony_ci{ 573af6ab5fSopenharmony_ci#ifndef ARKTSCONFIG_USE_FILESYSTEM 583af6ab5fSopenharmony_ci return !path.empty() && path[0] == '/'; 593af6ab5fSopenharmony_ci#else 603af6ab5fSopenharmony_ci return fs::path(path).is_absolute(); 613af6ab5fSopenharmony_ci#endif // ARKTSCONFIG_USE_FILESYSTEM 623af6ab5fSopenharmony_ci} 633af6ab5fSopenharmony_ci 643af6ab5fSopenharmony_cistd::string JoinPaths(const std::string &a, const std::string &b) 653af6ab5fSopenharmony_ci{ 663af6ab5fSopenharmony_ci#ifndef ARKTSCONFIG_USE_FILESYSTEM 673af6ab5fSopenharmony_ci return a + '/' + b; 683af6ab5fSopenharmony_ci#else 693af6ab5fSopenharmony_ci return (fs::path(a) / b).string(); 703af6ab5fSopenharmony_ci#endif // ARKTSCONFIG_USE_FILESYSTEM 713af6ab5fSopenharmony_ci} 723af6ab5fSopenharmony_ci 733af6ab5fSopenharmony_cistd::string ParentPath(const std::string &path) 743af6ab5fSopenharmony_ci{ 753af6ab5fSopenharmony_ci#ifndef ARKTSCONFIG_USE_FILESYSTEM 763af6ab5fSopenharmony_ci auto pos = path.find('/'); 773af6ab5fSopenharmony_ci return pos == std::string::npos ? path : path.substr(0, pos); 783af6ab5fSopenharmony_ci#else 793af6ab5fSopenharmony_ci return fs::path(path).parent_path().string(); 803af6ab5fSopenharmony_ci#endif // ARKTSCONFIG_USE_FILESYSTEM 813af6ab5fSopenharmony_ci} 823af6ab5fSopenharmony_ci 833af6ab5fSopenharmony_cistatic std::string MakeAbsolute(const std::string &path, const std::string &base) 843af6ab5fSopenharmony_ci{ 853af6ab5fSopenharmony_ci return IsAbsolute(path) ? path : JoinPaths(base, path); 863af6ab5fSopenharmony_ci} 873af6ab5fSopenharmony_ci 883af6ab5fSopenharmony_ci#ifdef ARKTSCONFIG_USE_FILESYSTEM 893af6ab5fSopenharmony_ci 903af6ab5fSopenharmony_ciArkTsConfig::Pattern::Pattern(std::string value, std::string base) : value_(std::move(value)), base_(std::move(base)) 913af6ab5fSopenharmony_ci{ 923af6ab5fSopenharmony_ci ASSERT(fs::path(base_).is_absolute()); 933af6ab5fSopenharmony_ci} 943af6ab5fSopenharmony_ci 953af6ab5fSopenharmony_cibool ArkTsConfig::Pattern::IsPattern() const 963af6ab5fSopenharmony_ci{ 973af6ab5fSopenharmony_ci return (value_.find('*') != std::string::npos) || (value_.find('?') != std::string::npos); 983af6ab5fSopenharmony_ci} 993af6ab5fSopenharmony_ci 1003af6ab5fSopenharmony_cistd::string ArkTsConfig::Pattern::GetSearchRoot() const 1013af6ab5fSopenharmony_ci{ 1023af6ab5fSopenharmony_ci fs::path relative; 1033af6ab5fSopenharmony_ci if (!IsPattern()) { 1043af6ab5fSopenharmony_ci relative = value_; 1053af6ab5fSopenharmony_ci } else { 1063af6ab5fSopenharmony_ci auto foundStar = value_.find_first_of('*'); 1073af6ab5fSopenharmony_ci auto foundQuestion = value_.find_first_of('?'); 1083af6ab5fSopenharmony_ci relative = value_.substr(0, std::min(foundStar, foundQuestion)); 1093af6ab5fSopenharmony_ci relative = relative.parent_path(); 1103af6ab5fSopenharmony_ci } 1113af6ab5fSopenharmony_ci return MakeAbsolute(relative.string(), base_); 1123af6ab5fSopenharmony_ci} 1133af6ab5fSopenharmony_ci 1143af6ab5fSopenharmony_cibool ArkTsConfig::Pattern::Match(const std::string &path) const 1153af6ab5fSopenharmony_ci{ 1163af6ab5fSopenharmony_ci ASSERT(fs::path(path).is_absolute()); 1173af6ab5fSopenharmony_ci fs::path value = fs::path(value_); 1183af6ab5fSopenharmony_ci std::string pattern = value.is_absolute() ? value.string() : (base_ / value).string(); 1193af6ab5fSopenharmony_ci 1203af6ab5fSopenharmony_ci // Replace arktsconfig special symbols with regular expressions 1213af6ab5fSopenharmony_ci if (IsPattern()) { 1223af6ab5fSopenharmony_ci // '**' matches any directory nested to any level 1233af6ab5fSopenharmony_ci pattern = std::regex_replace(pattern, std::regex("\\*\\*/"), ".*"); 1243af6ab5fSopenharmony_ci // '*' matches zero or more characters (excluding directory separators) 1253af6ab5fSopenharmony_ci pattern = std::regex_replace(pattern, std::regex("([^\\.])\\*"), "$1[^/]*"); 1263af6ab5fSopenharmony_ci // '?' matches any one character (excluding directory separators) 1273af6ab5fSopenharmony_ci pattern = std::regex_replace(pattern, std::regex("\\?"), "[^/]"); 1283af6ab5fSopenharmony_ci } 1293af6ab5fSopenharmony_ci if (!value.has_extension()) { 1303af6ab5fSopenharmony_ci // default extensions to match 1313af6ab5fSopenharmony_ci pattern += R"(.*(\.ts|\.d\.ts|\.sts)$)"; 1323af6ab5fSopenharmony_ci } 1333af6ab5fSopenharmony_ci std::smatch m; 1343af6ab5fSopenharmony_ci auto res = std::regex_match(path, m, std::regex(pattern)); 1353af6ab5fSopenharmony_ci return res; 1363af6ab5fSopenharmony_ci} 1373af6ab5fSopenharmony_ci 1383af6ab5fSopenharmony_cistatic std::string ResolveConfigLocation(const std::string &relPath, const std::string &base) 1393af6ab5fSopenharmony_ci{ 1403af6ab5fSopenharmony_ci auto resolvedPath = MakeAbsolute(relPath, base); 1413af6ab5fSopenharmony_ci auto newBase = base; 1423af6ab5fSopenharmony_ci while (!fs::exists(resolvedPath)) { 1433af6ab5fSopenharmony_ci resolvedPath = MakeAbsolute(relPath, JoinPaths(newBase, "node_modules")); 1443af6ab5fSopenharmony_ci if (newBase == ParentPath(newBase)) { 1453af6ab5fSopenharmony_ci return ""; 1463af6ab5fSopenharmony_ci } 1473af6ab5fSopenharmony_ci newBase = ParentPath(newBase); 1483af6ab5fSopenharmony_ci } 1493af6ab5fSopenharmony_ci return resolvedPath; 1503af6ab5fSopenharmony_ci} 1513af6ab5fSopenharmony_ci 1523af6ab5fSopenharmony_cibool ArkTsConfig::ParseExtends(const std::string &extends, const std::string &configDir) 1533af6ab5fSopenharmony_ci{ 1543af6ab5fSopenharmony_ci auto basePath = ResolveConfigLocation(extends, configDir); 1553af6ab5fSopenharmony_ci if (!Check(!basePath.empty(), "Can't resolve config path: ", extends)) { 1563af6ab5fSopenharmony_ci return false; 1573af6ab5fSopenharmony_ci } 1583af6ab5fSopenharmony_ci 1593af6ab5fSopenharmony_ci auto base = ArkTsConfig(basePath); 1603af6ab5fSopenharmony_ci if (!Check(base.Parse(), "Failed to parse base config: ", extends)) { 1613af6ab5fSopenharmony_ci return false; 1623af6ab5fSopenharmony_ci } 1633af6ab5fSopenharmony_ci 1643af6ab5fSopenharmony_ci Inherit(base); 1653af6ab5fSopenharmony_ci return true; 1663af6ab5fSopenharmony_ci} 1673af6ab5fSopenharmony_ci#endif // ARKTSCONFIG_USE_FILESYSTEM 1683af6ab5fSopenharmony_ci 1693af6ab5fSopenharmony_cistatic std::string ValidDynamicLanguages() 1703af6ab5fSopenharmony_ci{ 1713af6ab5fSopenharmony_ci JsonArrayBuilder builder; 1723af6ab5fSopenharmony_ci for (auto &l : Language::All()) { 1733af6ab5fSopenharmony_ci if (l.IsDynamic()) { 1743af6ab5fSopenharmony_ci builder.Add(l.ToString()); 1753af6ab5fSopenharmony_ci } 1763af6ab5fSopenharmony_ci } 1773af6ab5fSopenharmony_ci return std::move(builder).Build(); 1783af6ab5fSopenharmony_ci} 1793af6ab5fSopenharmony_ci 1803af6ab5fSopenharmony_citemplate <class PathsMap> 1813af6ab5fSopenharmony_cistatic bool ParsePaths(const JsonObject::JsonObjPointer *options, PathsMap &pathsMap, const std::string &baseUrl) 1823af6ab5fSopenharmony_ci{ 1833af6ab5fSopenharmony_ci if (options == nullptr) { 1843af6ab5fSopenharmony_ci return true; 1853af6ab5fSopenharmony_ci } 1863af6ab5fSopenharmony_ci 1873af6ab5fSopenharmony_ci auto paths = options->get()->GetValue<JsonObject::JsonObjPointer>("paths"); 1883af6ab5fSopenharmony_ci if (paths == nullptr) { 1893af6ab5fSopenharmony_ci return true; 1903af6ab5fSopenharmony_ci } 1913af6ab5fSopenharmony_ci 1923af6ab5fSopenharmony_ci for (size_t keyIdx = 0; keyIdx < paths->get()->GetSize(); ++keyIdx) { 1933af6ab5fSopenharmony_ci auto &key = paths->get()->GetKeyByIndex(keyIdx); 1943af6ab5fSopenharmony_ci if (pathsMap.count(key) == 0U) { 1953af6ab5fSopenharmony_ci pathsMap.insert({key, {}}); 1963af6ab5fSopenharmony_ci } 1973af6ab5fSopenharmony_ci 1983af6ab5fSopenharmony_ci auto values = paths->get()->GetValue<JsonObject::ArrayT>(key); 1993af6ab5fSopenharmony_ci if (!Check(values, "Invalid value for 'path' with key '", key, "'")) { 2003af6ab5fSopenharmony_ci return false; 2013af6ab5fSopenharmony_ci } 2023af6ab5fSopenharmony_ci 2033af6ab5fSopenharmony_ci if (!Check(!values->empty(), "Substitutions for pattern '", key, "' shouldn't be an empty array")) { 2043af6ab5fSopenharmony_ci return false; 2053af6ab5fSopenharmony_ci } 2063af6ab5fSopenharmony_ci 2073af6ab5fSopenharmony_ci for (auto &v : *values) { 2083af6ab5fSopenharmony_ci auto p = *v.Get<JsonObject::StringT>(); 2093af6ab5fSopenharmony_ci pathsMap[key].emplace_back(MakeAbsolute(p, baseUrl)); 2103af6ab5fSopenharmony_ci } 2113af6ab5fSopenharmony_ci } 2123af6ab5fSopenharmony_ci 2133af6ab5fSopenharmony_ci return true; 2143af6ab5fSopenharmony_ci} 2153af6ab5fSopenharmony_ci 2163af6ab5fSopenharmony_citemplate <class PathsMap> 2173af6ab5fSopenharmony_cistatic bool ParseDynamicPaths(const JsonObject::JsonObjPointer *options, PathsMap &dynamicPathsMap) 2183af6ab5fSopenharmony_ci{ 2193af6ab5fSopenharmony_ci static const std::string LANGUAGE = "language"; 2203af6ab5fSopenharmony_ci static const std::string HAS_DECL = "hasDecl"; 2213af6ab5fSopenharmony_ci 2223af6ab5fSopenharmony_ci if (options == nullptr) { 2233af6ab5fSopenharmony_ci return true; 2243af6ab5fSopenharmony_ci } 2253af6ab5fSopenharmony_ci 2263af6ab5fSopenharmony_ci auto dynamicPaths = options->get()->GetValue<JsonObject::JsonObjPointer>("dynamicPaths"); 2273af6ab5fSopenharmony_ci if (dynamicPaths == nullptr) { 2283af6ab5fSopenharmony_ci return true; 2293af6ab5fSopenharmony_ci } 2303af6ab5fSopenharmony_ci 2313af6ab5fSopenharmony_ci for (size_t keyIdx = 0; keyIdx < dynamicPaths->get()->GetSize(); ++keyIdx) { 2323af6ab5fSopenharmony_ci auto &key = dynamicPaths->get()->GetKeyByIndex(keyIdx); 2333af6ab5fSopenharmony_ci auto data = dynamicPaths->get()->GetValue<JsonObject::JsonObjPointer>(key); 2343af6ab5fSopenharmony_ci if (!Check(data != nullptr, "Invalid value for for dynamic path with key '", key, "'")) { 2353af6ab5fSopenharmony_ci return false; 2363af6ab5fSopenharmony_ci } 2373af6ab5fSopenharmony_ci 2383af6ab5fSopenharmony_ci auto langValue = data->get()->GetValue<JsonObject::StringT>(LANGUAGE); 2393af6ab5fSopenharmony_ci if (!Check(langValue != nullptr, "Invalid '", LANGUAGE, "' value for dynamic path with key '", key, "'")) { 2403af6ab5fSopenharmony_ci return false; 2413af6ab5fSopenharmony_ci } 2423af6ab5fSopenharmony_ci 2433af6ab5fSopenharmony_ci auto lang = Language::FromString(*langValue); 2443af6ab5fSopenharmony_ci if (!Check(lang && lang->IsDynamic(), "Invalid '", LANGUAGE, "' value for dynamic path with key '", key, 2453af6ab5fSopenharmony_ci "'. Should be one of ", ValidDynamicLanguages())) { 2463af6ab5fSopenharmony_ci return false; 2473af6ab5fSopenharmony_ci } 2483af6ab5fSopenharmony_ci 2493af6ab5fSopenharmony_ci if (!Check(compiler::Signatures::Dynamic::IsSupported(*lang), "Interoperability with language '", 2503af6ab5fSopenharmony_ci lang->ToString(), "' is not supported")) { 2513af6ab5fSopenharmony_ci return false; 2523af6ab5fSopenharmony_ci } 2533af6ab5fSopenharmony_ci 2543af6ab5fSopenharmony_ci auto hasDeclValue = data->get()->GetValue<JsonObject::BoolT>(HAS_DECL); 2553af6ab5fSopenharmony_ci if (!Check(hasDeclValue != nullptr, "Invalid '", HAS_DECL, "' value for dynamic path with key '", key, "'")) { 2563af6ab5fSopenharmony_ci return false; 2573af6ab5fSopenharmony_ci } 2583af6ab5fSopenharmony_ci 2593af6ab5fSopenharmony_ci auto normalizedKey = ark::os::NormalizePath(key); 2603af6ab5fSopenharmony_ci auto res = dynamicPathsMap.insert({normalizedKey, ArkTsConfig::DynamicImportData(*lang, *hasDeclValue)}); 2613af6ab5fSopenharmony_ci if (!Check(res.second, "Duplicated dynamic path '", key, "' for key '", key, "'")) { 2623af6ab5fSopenharmony_ci return false; 2633af6ab5fSopenharmony_ci } 2643af6ab5fSopenharmony_ci } 2653af6ab5fSopenharmony_ci 2663af6ab5fSopenharmony_ci return true; 2673af6ab5fSopenharmony_ci} 2683af6ab5fSopenharmony_ci 2693af6ab5fSopenharmony_citemplate <class Collection, class Function> 2703af6ab5fSopenharmony_cistatic bool ParseCollection(const JsonObject *config, Collection &out, const std::string &target, 2713af6ab5fSopenharmony_ci Function &&constructor) 2723af6ab5fSopenharmony_ci{ 2733af6ab5fSopenharmony_ci auto arr = config->GetValue<JsonObject::ArrayT>(target); 2743af6ab5fSopenharmony_ci if (arr != nullptr) { 2753af6ab5fSopenharmony_ci out = {}; 2763af6ab5fSopenharmony_ci if (!Check(!arr->empty(), "The '", target, "' list in config file is empty")) { 2773af6ab5fSopenharmony_ci return false; 2783af6ab5fSopenharmony_ci } 2793af6ab5fSopenharmony_ci 2803af6ab5fSopenharmony_ci for (auto &i : *arr) { 2813af6ab5fSopenharmony_ci out.emplace_back(constructor(*i.Get<JsonObject::StringT>())); 2823af6ab5fSopenharmony_ci } 2833af6ab5fSopenharmony_ci } 2843af6ab5fSopenharmony_ci 2853af6ab5fSopenharmony_ci return true; 2863af6ab5fSopenharmony_ci} 2873af6ab5fSopenharmony_ci 2883af6ab5fSopenharmony_cistatic std::optional<std::string> ReadConfig(const std::string &path) 2893af6ab5fSopenharmony_ci{ 2903af6ab5fSopenharmony_ci std::ifstream inputStream(path); 2913af6ab5fSopenharmony_ci if (!Check(!inputStream.fail(), "Failed to open file: ", path)) { 2923af6ab5fSopenharmony_ci return {}; 2933af6ab5fSopenharmony_ci } 2943af6ab5fSopenharmony_ci 2953af6ab5fSopenharmony_ci std::stringstream ss; 2963af6ab5fSopenharmony_ci ss << inputStream.rdbuf(); 2973af6ab5fSopenharmony_ci return ss.str(); 2983af6ab5fSopenharmony_ci} 2993af6ab5fSopenharmony_ci 3003af6ab5fSopenharmony_cistatic void ParseRelDir(std::string &dst, const std::string &key, const JsonObject::JsonObjPointer *options, 3013af6ab5fSopenharmony_ci const std::string &configDir) 3023af6ab5fSopenharmony_ci{ 3033af6ab5fSopenharmony_ci if (options != nullptr) { 3043af6ab5fSopenharmony_ci auto path = options->get()->GetValue<JsonObject::StringT>(key); 3053af6ab5fSopenharmony_ci dst = ((path != nullptr) ? *path : ""); 3063af6ab5fSopenharmony_ci } 3073af6ab5fSopenharmony_ci 3083af6ab5fSopenharmony_ci dst = MakeAbsolute(dst, configDir); 3093af6ab5fSopenharmony_ci} 3103af6ab5fSopenharmony_ci 3113af6ab5fSopenharmony_cibool ArkTsConfig::Parse() 3123af6ab5fSopenharmony_ci{ 3133af6ab5fSopenharmony_ci static const std::string BASE_URL = "baseUrl"; 3143af6ab5fSopenharmony_ci static const std::string COMPILER_OPTIONS = "compilerOptions"; 3153af6ab5fSopenharmony_ci static const std::string EXCLUDE = "exclude"; 3163af6ab5fSopenharmony_ci static const std::string EXTENDS = "extends"; 3173af6ab5fSopenharmony_ci static const std::string FILES = "files"; 3183af6ab5fSopenharmony_ci static const std::string INCLUDE = "include"; 3193af6ab5fSopenharmony_ci static const std::string OUT_DIR = "outDir"; 3203af6ab5fSopenharmony_ci static const std::string ROOT_DIR = "rootDir"; 3213af6ab5fSopenharmony_ci 3223af6ab5fSopenharmony_ci ASSERT(!isParsed_); 3233af6ab5fSopenharmony_ci isParsed_ = true; 3243af6ab5fSopenharmony_ci auto arktsConfigDir = ParentPath(ark::os::GetAbsolutePath(configPath_)); 3253af6ab5fSopenharmony_ci 3263af6ab5fSopenharmony_ci // Read input 3273af6ab5fSopenharmony_ci auto tsConfigSource = ReadConfig(configPath_); 3283af6ab5fSopenharmony_ci if (!tsConfigSource) { 3293af6ab5fSopenharmony_ci return false; 3303af6ab5fSopenharmony_ci } 3313af6ab5fSopenharmony_ci 3323af6ab5fSopenharmony_ci // Parse json 3333af6ab5fSopenharmony_ci auto arktsConfig = std::make_unique<JsonObject>(*tsConfigSource); 3343af6ab5fSopenharmony_ci if (!Check(arktsConfig->IsValid(), "ArkTsConfig is not valid json")) { 3353af6ab5fSopenharmony_ci return false; 3363af6ab5fSopenharmony_ci } 3373af6ab5fSopenharmony_ci 3383af6ab5fSopenharmony_ci#ifdef ARKTSCONFIG_USE_FILESYSTEM 3393af6ab5fSopenharmony_ci // Parse "extends" 3403af6ab5fSopenharmony_ci auto extends = arktsConfig->GetValue<JsonObject::StringT>(EXTENDS); 3413af6ab5fSopenharmony_ci if (extends != nullptr && !ParseExtends(*extends, arktsConfigDir)) { 3423af6ab5fSopenharmony_ci return false; 3433af6ab5fSopenharmony_ci } 3443af6ab5fSopenharmony_ci#endif // ARKTSCONFIG_USE_FILESYSTEM 3453af6ab5fSopenharmony_ci 3463af6ab5fSopenharmony_ci auto compilerOptions = arktsConfig->GetValue<JsonObject::JsonObjPointer>(COMPILER_OPTIONS); 3473af6ab5fSopenharmony_ci 3483af6ab5fSopenharmony_ci // Parse "baseUrl", "outDir", "rootDir" 3493af6ab5fSopenharmony_ci ParseRelDir(baseUrl_, BASE_URL, compilerOptions, arktsConfigDir); 3503af6ab5fSopenharmony_ci ParseRelDir(outDir_, OUT_DIR, compilerOptions, arktsConfigDir); 3513af6ab5fSopenharmony_ci ParseRelDir(rootDir_, ROOT_DIR, compilerOptions, arktsConfigDir); 3523af6ab5fSopenharmony_ci 3533af6ab5fSopenharmony_ci // Parse "paths" 3543af6ab5fSopenharmony_ci if (!ParsePaths(compilerOptions, paths_, baseUrl_) || !ParseDynamicPaths(compilerOptions, dynamicPaths_)) { 3553af6ab5fSopenharmony_ci return false; 3563af6ab5fSopenharmony_ci } 3573af6ab5fSopenharmony_ci 3583af6ab5fSopenharmony_ci // Parse "files" 3593af6ab5fSopenharmony_ci auto concatPath = [&arktsConfigDir](const auto &val) { return MakeAbsolute(val, arktsConfigDir); }; 3603af6ab5fSopenharmony_ci if (!ParseCollection(arktsConfig.get(), files_, FILES, concatPath)) { 3613af6ab5fSopenharmony_ci return false; 3623af6ab5fSopenharmony_ci } 3633af6ab5fSopenharmony_ci 3643af6ab5fSopenharmony_ci#ifdef ARKTSCONFIG_USE_FILESYSTEM 3653af6ab5fSopenharmony_ci // Parse "include" and "exclude" 3663af6ab5fSopenharmony_ci auto consPattern = [&arktsConfigDir](const auto &val) { return Pattern {val, arktsConfigDir}; }; 3673af6ab5fSopenharmony_ci return ParseCollection(arktsConfig.get(), include_, INCLUDE, consPattern) && 3683af6ab5fSopenharmony_ci ParseCollection(arktsConfig.get(), exclude_, EXCLUDE, consPattern); 3693af6ab5fSopenharmony_ci#else 3703af6ab5fSopenharmony_ci return true; 3713af6ab5fSopenharmony_ci#endif // ARKTSCONFIG_USE_FILESYSTEM 3723af6ab5fSopenharmony_ci} 3733af6ab5fSopenharmony_ci 3743af6ab5fSopenharmony_civoid ArkTsConfig::Inherit(const ArkTsConfig &base) 3753af6ab5fSopenharmony_ci{ 3763af6ab5fSopenharmony_ci baseUrl_ = base.baseUrl_; 3773af6ab5fSopenharmony_ci outDir_ = base.outDir_; 3783af6ab5fSopenharmony_ci rootDir_ = base.rootDir_; 3793af6ab5fSopenharmony_ci paths_ = base.paths_; 3803af6ab5fSopenharmony_ci files_ = base.files_; 3813af6ab5fSopenharmony_ci#ifdef ARKTSCONFIG_USE_FILESYSTEM 3823af6ab5fSopenharmony_ci include_ = base.include_; 3833af6ab5fSopenharmony_ci exclude_ = base.exclude_; 3843af6ab5fSopenharmony_ci#endif // ARKTSCONFIG_USE_FILESYSTEM 3853af6ab5fSopenharmony_ci} 3863af6ab5fSopenharmony_ci 3873af6ab5fSopenharmony_ci// Remove '/' and '*' from the end of path 3883af6ab5fSopenharmony_cistatic std::string TrimPath(const std::string &path) 3893af6ab5fSopenharmony_ci{ 3903af6ab5fSopenharmony_ci std::string trimmedPath = path; 3913af6ab5fSopenharmony_ci while (!trimmedPath.empty() && (trimmedPath.back() == '*' || trimmedPath.back() == '/')) { 3923af6ab5fSopenharmony_ci trimmedPath.pop_back(); 3933af6ab5fSopenharmony_ci } 3943af6ab5fSopenharmony_ci return trimmedPath; 3953af6ab5fSopenharmony_ci} 3963af6ab5fSopenharmony_ci 3973af6ab5fSopenharmony_cistd::optional<std::string> ArkTsConfig::ResolvePath(const std::string &path) const 3983af6ab5fSopenharmony_ci{ 3993af6ab5fSopenharmony_ci for (const auto &[alias, paths] : paths_) { 4003af6ab5fSopenharmony_ci auto trimmedAlias = TrimPath(alias); 4013af6ab5fSopenharmony_ci size_t pos = path.rfind(trimmedAlias, 0); 4023af6ab5fSopenharmony_ci if (pos == 0) { 4033af6ab5fSopenharmony_ci std::string resolved = path; 4043af6ab5fSopenharmony_ci // NOTE(ivagin): arktsconfig contains array of paths for each prefix, for now just get first one 4053af6ab5fSopenharmony_ci std::string newPrefix = TrimPath(paths[0]); 4063af6ab5fSopenharmony_ci resolved.replace(pos, trimmedAlias.length(), newPrefix); 4073af6ab5fSopenharmony_ci return resolved; 4083af6ab5fSopenharmony_ci } 4093af6ab5fSopenharmony_ci } 4103af6ab5fSopenharmony_ci return std::nullopt; 4113af6ab5fSopenharmony_ci} 4123af6ab5fSopenharmony_ci 4133af6ab5fSopenharmony_ci#ifdef ARKTSCONFIG_USE_FILESYSTEM 4143af6ab5fSopenharmony_cistatic bool MatchExcludes(const fs::path &path, const std::vector<ArkTsConfig::Pattern> &excludes) 4153af6ab5fSopenharmony_ci{ 4163af6ab5fSopenharmony_ci for (auto &e : excludes) { 4173af6ab5fSopenharmony_ci if (e.Match(path.string())) { 4183af6ab5fSopenharmony_ci return true; 4193af6ab5fSopenharmony_ci } 4203af6ab5fSopenharmony_ci } 4213af6ab5fSopenharmony_ci return false; 4223af6ab5fSopenharmony_ci} 4233af6ab5fSopenharmony_ci 4243af6ab5fSopenharmony_cistatic std::vector<fs::path> GetSourceList(const std::shared_ptr<ArkTsConfig> &arktsConfig) 4253af6ab5fSopenharmony_ci{ 4263af6ab5fSopenharmony_ci auto includes = arktsConfig->Include(); 4273af6ab5fSopenharmony_ci auto excludes = arktsConfig->Exclude(); 4283af6ab5fSopenharmony_ci auto files = arktsConfig->Files(); 4293af6ab5fSopenharmony_ci 4303af6ab5fSopenharmony_ci // If "files" and "includes" are empty - include everything from tsconfig root 4313af6ab5fSopenharmony_ci auto configDir = fs::absolute(fs::path(arktsConfig->ConfigPath())).parent_path(); 4323af6ab5fSopenharmony_ci if (files.empty() && includes.empty()) { 4333af6ab5fSopenharmony_ci includes = {ArkTsConfig::Pattern("**/*", configDir.string())}; 4343af6ab5fSopenharmony_ci } 4353af6ab5fSopenharmony_ci // If outDir in not default add it into exclude 4363af6ab5fSopenharmony_ci if (!fs::equivalent(arktsConfig->OutDir(), configDir)) { 4373af6ab5fSopenharmony_ci excludes.emplace_back("**/*", arktsConfig->OutDir()); 4383af6ab5fSopenharmony_ci } 4393af6ab5fSopenharmony_ci 4403af6ab5fSopenharmony_ci // Collect "files" 4413af6ab5fSopenharmony_ci std::vector<fs::path> sourceList; 4423af6ab5fSopenharmony_ci for (auto &f : files) { 4433af6ab5fSopenharmony_ci if (!Check(fs::exists(f) && fs::path(f).has_filename(), "No such file: ", f)) { 4443af6ab5fSopenharmony_ci return {}; 4453af6ab5fSopenharmony_ci } 4463af6ab5fSopenharmony_ci 4473af6ab5fSopenharmony_ci sourceList.emplace_back(f); 4483af6ab5fSopenharmony_ci } 4493af6ab5fSopenharmony_ci 4503af6ab5fSopenharmony_ci // Collect "include" 4513af6ab5fSopenharmony_ci // TSC traverses folders for sources starting from 'include' rather than from 'rootDir', so we do the same 4523af6ab5fSopenharmony_ci for (auto &include : includes) { 4533af6ab5fSopenharmony_ci auto traverseRoot = fs::path(include.GetSearchRoot()); 4543af6ab5fSopenharmony_ci if (!fs::exists(traverseRoot)) { 4553af6ab5fSopenharmony_ci continue; 4563af6ab5fSopenharmony_ci } 4573af6ab5fSopenharmony_ci if (!fs::is_directory(traverseRoot)) { 4583af6ab5fSopenharmony_ci if (include.Match(traverseRoot.string()) && !MatchExcludes(traverseRoot, excludes)) { 4593af6ab5fSopenharmony_ci sourceList.emplace_back(traverseRoot); 4603af6ab5fSopenharmony_ci } 4613af6ab5fSopenharmony_ci continue; 4623af6ab5fSopenharmony_ci } 4633af6ab5fSopenharmony_ci for (const auto &dirEntry : fs::recursive_directory_iterator(traverseRoot)) { 4643af6ab5fSopenharmony_ci if (include.Match(dirEntry.path().string()) && !MatchExcludes(dirEntry, excludes)) { 4653af6ab5fSopenharmony_ci sourceList.emplace_back(dirEntry); 4663af6ab5fSopenharmony_ci } 4673af6ab5fSopenharmony_ci } 4683af6ab5fSopenharmony_ci } 4693af6ab5fSopenharmony_ci return sourceList; 4703af6ab5fSopenharmony_ci} 4713af6ab5fSopenharmony_ci 4723af6ab5fSopenharmony_ci// Analogue of 'std::filesystem::relative()' 4733af6ab5fSopenharmony_ci// Example: Relative("/a/b/c", "/a/b") returns "c" 4743af6ab5fSopenharmony_cistatic fs::path Relative(const fs::path &src, const fs::path &base) 4753af6ab5fSopenharmony_ci{ 4763af6ab5fSopenharmony_ci fs::path tmpPath = src; 4773af6ab5fSopenharmony_ci fs::path relPath; 4783af6ab5fSopenharmony_ci while (!fs::equivalent(tmpPath, base)) { 4793af6ab5fSopenharmony_ci relPath = relPath.empty() ? tmpPath.filename() : tmpPath.filename() / relPath; 4803af6ab5fSopenharmony_ci if (tmpPath == tmpPath.parent_path()) { 4813af6ab5fSopenharmony_ci return fs::path(); 4823af6ab5fSopenharmony_ci } 4833af6ab5fSopenharmony_ci tmpPath = tmpPath.parent_path(); 4843af6ab5fSopenharmony_ci } 4853af6ab5fSopenharmony_ci return relPath; 4863af6ab5fSopenharmony_ci} 4873af6ab5fSopenharmony_ci 4883af6ab5fSopenharmony_ci// Compute path to destination file and create subfolders 4893af6ab5fSopenharmony_cistatic fs::path ComputeDestination(const fs::path &src, const fs::path &rootDir, const fs::path &outDir) 4903af6ab5fSopenharmony_ci{ 4913af6ab5fSopenharmony_ci auto rel = Relative(src, rootDir); 4923af6ab5fSopenharmony_ci if (!Check(!rel.empty(), rootDir, " is not root directory for ", src)) { 4933af6ab5fSopenharmony_ci return {}; 4943af6ab5fSopenharmony_ci } 4953af6ab5fSopenharmony_ci 4963af6ab5fSopenharmony_ci auto dst = outDir / rel; 4973af6ab5fSopenharmony_ci fs::create_directories(dst.parent_path()); 4983af6ab5fSopenharmony_ci return dst.replace_extension("abc"); 4993af6ab5fSopenharmony_ci} 5003af6ab5fSopenharmony_ci 5013af6ab5fSopenharmony_cistd::vector<std::pair<std::string, std::string>> FindProjectSources(const std::shared_ptr<ArkTsConfig> &arktsConfig) 5023af6ab5fSopenharmony_ci{ 5033af6ab5fSopenharmony_ci auto sourceFiles = GetSourceList(arktsConfig); 5043af6ab5fSopenharmony_ci std::vector<std::pair<std::string, std::string>> compilationList; 5053af6ab5fSopenharmony_ci for (auto &src : sourceFiles) { 5063af6ab5fSopenharmony_ci auto dst = ComputeDestination(src, arktsConfig->RootDir(), arktsConfig->OutDir()); 5073af6ab5fSopenharmony_ci if (!Check(!dst.empty(), "Invalid destination file")) { 5083af6ab5fSopenharmony_ci return {}; 5093af6ab5fSopenharmony_ci } 5103af6ab5fSopenharmony_ci 5113af6ab5fSopenharmony_ci compilationList.emplace_back(src.string(), dst.string()); 5123af6ab5fSopenharmony_ci } 5133af6ab5fSopenharmony_ci 5143af6ab5fSopenharmony_ci return compilationList; 5153af6ab5fSopenharmony_ci} 5163af6ab5fSopenharmony_ci#else 5173af6ab5fSopenharmony_cistd::vector<std::pair<std::string, std::string>> FindProjectSources( 5183af6ab5fSopenharmony_ci [[maybe_unused]] const std::shared_ptr<ArkTsConfig> &arkts_config) 5193af6ab5fSopenharmony_ci{ 5203af6ab5fSopenharmony_ci ASSERT(false); 5213af6ab5fSopenharmony_ci return {}; 5223af6ab5fSopenharmony_ci} 5233af6ab5fSopenharmony_ci#endif // ARKTSCONFIG_USE_FILESYSTEM 5243af6ab5fSopenharmony_ci 5253af6ab5fSopenharmony_ci} // namespace ark::es2panda 526