From 67afc373c908089e044bed6c4ef0433b77e3d44a Mon Sep 17 00:00:00 2001 From: HawDevelopment <70876593+HawDevelopment@users.noreply.github.com> Date: Tue, 5 Jul 2022 12:13:27 +0200 Subject: [PATCH] Initial implementation --- Analysis/include/Luau/Config.h | 1 + Analysis/src/Config.cpp | 13 +++++++++++++ Analysis/src/Frontend.cpp | 13 +++++++++++++ tests/Config.test.cpp | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+) diff --git a/Analysis/include/Luau/Config.h b/Analysis/include/Luau/Config.h index 56cdfe78..413a74b2 100644 --- a/Analysis/include/Luau/Config.h +++ b/Analysis/include/Luau/Config.h @@ -33,6 +33,7 @@ struct Config bool typeErrors = true; std::vector globals; + std::vector globalTypePaths; }; struct ConfigResolver diff --git a/Analysis/src/Config.cpp b/Analysis/src/Config.cpp index 35a2259d..03854c61 100644 --- a/Analysis/src/Config.cpp +++ b/Analysis/src/Config.cpp @@ -4,6 +4,8 @@ #include "Luau/Lexer.h" #include "Luau/StringUtils.h" +#include + namespace { @@ -107,6 +109,15 @@ Error parseLintRuleString(LintOptions& enabledLints, LintOptions& fatalLints, co return std::nullopt; } +Error parseFilePath(std::vector& paths, const std::string& value) { + // The exists check could be invalid, since we use the frontend file resolver to read the contents. + if (value.empty() || !std::filesystem::exists(value)) + return Error{"Unkown file path: " + value}; + + paths.push_back(value); + return std::nullopt; +} + static void next(Lexer& lexer) { lexer.next(); @@ -260,6 +271,8 @@ Error parseConfig(const std::string& contents, Config& config, bool compat) config.globals.push_back(value); return std::nullopt; } + else if (keys.size() == 1 && keys[0] == "globalTypePaths") + return parseFilePath(config.globalTypePaths, value); else if (compat && keys.size() == 2 && keys[0] == "language" && keys[1] == "mode") return parseModeString(config.mode, value, compat); else diff --git a/Analysis/src/Frontend.cpp b/Analysis/src/Frontend.cpp index 4cfaa112..e2998c55 100644 --- a/Analysis/src/Frontend.cpp +++ b/Analysis/src/Frontend.cpp @@ -642,6 +642,19 @@ ScopePtr Frontend::getModuleEnvironment(const SourceModule& module, const Config result->bindings[name].typeId = typeChecker.anyType; } } + + if (!config.globalTypePaths.empty()) + { + result = std::make_shared(result); + for (const std::string& path : config.globalTypePaths) + { + auto source = fileResolver->readSource(path); + if (!source) + continue; + + loadDefinitionFile(typeChecker, typeChecker.globalScope, source->source, path); + } + } return result; } diff --git a/tests/Config.test.cpp b/tests/Config.test.cpp index e6a72672..52d48e5f 100644 --- a/tests/Config.test.cpp +++ b/tests/Config.test.cpp @@ -8,6 +8,7 @@ #include "doctest.h" #include +#include using namespace Luau; @@ -134,6 +135,37 @@ TEST_CASE("extra_globals") CHECK(config.globals[1] == "__DEV__"); } +TEST_CASE("global_type_paths") +{ + // This could be done with a temp file! + std::ofstream file("./globalTypePathsTest.lua"); + file.close(); + + Config config; + auto err = parseConfig(R"( + {"globalTypePaths": ["./globalTypePathsTest.lua"]} + )", + config); + + std::remove("./globalTypePathsTest.lua"); + + REQUIRE(!err); + + CHECK(config.globalTypePaths.size() == 1); + CHECK(config.globalTypePaths[0] == "./globalTypePathsTest.lua"); +} + +TEST_CASE("global_type_paths_unable_to_find_file") { + Config config; + auto err = parseConfig(R"( + {"globalTypePaths": ["./THIS_FILE_SHOULD_NOT_EXIST.lua"]} + )", + config); + + REQUIRE(err); + CHECK(err.value() == "Unkown file path: ./THIS_FILE_SHOULD_NOT_EXIST.lua"); +} + TEST_CASE("lint_rules_compat") { Config config;