Skip to content

Commit 35620ec

Browse files
Require a name for definitions files (#885)
Require a name for definition files
1 parent 9e8cf33 commit 35620ec

19 files changed

+218
-53
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
1515

1616
- Sync to upstream Luau 0.698
1717
- Auto-imports are now enabled by default. Configure `luau-lsp.completion.imports.enabled` if you wish to disable it ([#619](https://github.com/JohnnyMorganz/luau-lsp/issues/619))
18+
- Definitions files must now provide a name for the file in settings and command line: i.e.
19+
`--definitions:@roblox=path/to/globalTypes.d.luau`. This is to support mapping global types back to their original
20+
definitions file for documentation features. Please update your LSP settings (`luau-lsp.types.definitionFiles`) and command line arguments.
21+
Backwards compatibility has been temporarily preserved, with random names generated.
1822
- Table properties are now prioritised above other autocomplete entries (again, fixing a dormant bug)
1923
- Contextual keywords (`else` / `elseif` / `end`) are prioritised over other autocomplete entries when inside of the relevant statement
2024

editors/README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,12 @@ $ luau-lsp --help
2525

2626
## Configuring Definitions and Documentation
2727

28-
You can add in built-in definitions by passing the `--definitions=PATH` argument.
28+
You can add in built-in definitions by passing the `--definitions:@name=PATH` argument.
29+
The `name` should be a unique reference to the definitions file.
2930
This can be done multiple times:
3031

3132
```sh
32-
$ luau-lsp lsp --definitions=/path/to/globalTypes.d.luau
33+
$ luau-lsp lsp --definition:@roblox=/path/to/globalTypes.d.luau
3334
```
3435

3536
> NOTE: Definitions file syntax is unstable and undocumented. It may change at any time

editors/code/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -328,10 +328,10 @@
328328
"scope": "resource"
329329
},
330330
"luau-lsp.types.definitionFiles": {
331-
"markdownDescription": "A list of paths to definition files to load in to the type checker. Note that definition file syntax is currently unstable and may change at any time",
332-
"type": "array",
331+
"markdownDescription": "A mapping of package names to paths of definition files to load in to the type checker. Note that definition file syntax is currently unstable and may change at any time",
332+
"type": "object",
333333
"default": [],
334-
"items": {
334+
"additionalProperties": {
335335
"type": "string"
336336
},
337337
"scope": "window"

editors/code/src/extension.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,18 @@ const startLanguageServer = async (context: vscode.ExtensionContext) => {
176176
const typesConfig = vscode.workspace.getConfiguration("luau-lsp.types");
177177

178178
// Load extra type definitions
179-
const definitionFiles = typesConfig.get<string[]>("definitionFiles");
179+
// TODO: deprecate and remove support of array-based definitionFiles configuration
180+
let definitionFiles = typesConfig.get<
181+
{ [packageName: string]: string } | string[]
182+
>("definitionFiles");
180183
if (definitionFiles) {
181-
for (let definitionPath of definitionFiles) {
184+
if (Array.isArray(definitionFiles)) {
185+
definitionFiles = Object.fromEntries(
186+
definitionFiles.map((path, index) => ["roblox" + index, path]),
187+
);
188+
}
189+
190+
for (let [packageName, definitionPath] of Object.entries(definitionFiles)) {
182191
definitionPath = utils.resolvePath(definitionPath);
183192
let uri;
184193
if (vscode.workspace.workspaceFolders) {
@@ -190,10 +199,10 @@ const startLanguageServer = async (context: vscode.ExtensionContext) => {
190199
uri = vscode.Uri.file(definitionPath);
191200
}
192201
if (await utils.exists(uri)) {
193-
addArg(`--definitions=${uri.fsPath}`);
202+
addArg(`--definitions:${packageName}=${uri.fsPath}`);
194203
} else {
195204
vscode.window.showWarningMessage(
196-
`Definitions file at ${definitionPath} does not exist, types will not be provided from this file`,
205+
`Definitions file '${packageName}' at ${definitionPath} does not exist, types will not be provided from this file`,
197206
);
198207
}
199208
}

editors/code/src/roblox.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -603,11 +603,11 @@ export const preLanguageServerStart = async (
603603
typesConfig.get<string>("robloxSecurityLevel") ?? "PluginSecurity";
604604
await updateApiInfo(context);
605605
addArg(
606-
`--definitions=${globalTypesUri(context, securityLevel, "Prod").fsPath}`,
606+
`--definitions:@roblox=${globalTypesUri(context, securityLevel, "Prod").fsPath}`,
607607
"Prod",
608608
);
609609
addArg(
610-
`--definitions=${globalTypesUri(context, securityLevel, "Debug").fsPath}`,
610+
`--definitions:@roblox=${globalTypesUri(context, securityLevel, "Debug").fsPath}`,
611611
"Debug",
612612
);
613613
addArg(`--docs=${apiDocsUri(context).fsPath}`);

src/AnalyzeCli.cpp

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,8 @@ std::vector<std::string> getFilesToAnalyze(const std::vector<std::string>& paths
183183
return files;
184184
}
185185

186-
void applySettings(
187-
const std::string& settingsContents, CliClient& client, std::vector<std::string>& ignoreGlobPatterns, std::vector<std::string>& definitionsPaths)
186+
void applySettings(const std::string& settingsContents, CliClient& client, std::vector<std::string>& ignoreGlobPatterns,
187+
std::unordered_map<std::string, std::string>& definitionsPaths)
188188
{
189189
client.configuration = dottedToClientConfiguration(settingsContents);
190190

@@ -194,7 +194,7 @@ void applySettings(
194194
ignoreGlobPatterns.reserve(ignoreGlobPatterns.size() + ignoreGlobsConfiguration.size());
195195
ignoreGlobPatterns.insert(ignoreGlobPatterns.end(), ignoreGlobsConfiguration.cbegin(), ignoreGlobsConfiguration.cend());
196196
definitionsPaths.reserve(definitionsPaths.size() + definitionsFilesConfiguration.size());
197-
definitionsPaths.insert(definitionsPaths.end(), definitionsFilesConfiguration.cbegin(), definitionsFilesConfiguration.cend());
197+
definitionsPaths.insert(definitionsFilesConfiguration.begin(), definitionsFilesConfiguration.end());
198198

199199
// Process any fflags
200200
registerFastFlagsCLI(client.configuration.fflags.override);
@@ -206,12 +206,45 @@ void applySettings(
206206
"Please manually configure necessary FFlags\n";
207207
}
208208

209+
std::unordered_map<std::string, std::string> processDefinitionsFilePaths(const argparse::ArgumentParser& program)
210+
{
211+
std::unordered_map<std::string, std::string> definitionsFiles{};
212+
size_t backwardsCompatibilityNameSuffix = 0;
213+
for (const auto& definition : program.get<std::vector<std::string>>("--definitions"))
214+
{
215+
std::string packageName = definition;
216+
std::string filePath = definition;
217+
218+
size_t eqIndex = definition.find('=');
219+
if (eqIndex == std::string::npos)
220+
{
221+
// TODO: Remove Me - backwards compatibility
222+
packageName = "@roblox";
223+
if (backwardsCompatibilityNameSuffix > 0)
224+
packageName += std::to_string(backwardsCompatibilityNameSuffix);
225+
backwardsCompatibilityNameSuffix += 1;
226+
}
227+
else
228+
{
229+
packageName = definition.substr(0, eqIndex);
230+
filePath = definition.substr(eqIndex + 1, definition.length());
231+
}
232+
233+
if (!Luau::startsWith(packageName, "@"))
234+
packageName = "@" + packageName;
235+
236+
definitionsFiles.emplace(packageName, filePath);
237+
}
238+
239+
return definitionsFiles;
240+
}
241+
209242
int startAnalyze(const argparse::ArgumentParser& program)
210243
{
211244
ReportFormat format = ReportFormat::Default;
212245
bool annotate = program.is_used("--annotate");
213246
auto sourcemapPath = program.present<std::string>("--sourcemap");
214-
auto definitionsPaths = program.get<std::vector<std::string>>("--definitions");
247+
auto definitionsPaths = processDefinitionsFilePaths(program);
215248
auto ignoreGlobPatterns = program.get<std::vector<std::string>>("--ignore");
216249
auto baseLuaurc = program.present<std::string>("--base-luaurc");
217250
auto settingsPath = program.present<std::string>("--settings");
@@ -325,7 +358,7 @@ int startAnalyze(const argparse::ArgumentParser& program)
325358
"definitions files; use `--platform=standard` to silence\n");
326359
}
327360

328-
for (auto& definitionsPath : definitionsPaths)
361+
for (const auto& [packageName, definitionsPath] : definitionsPaths)
329362
{
330363
auto uri = fileResolver.rootUri.resolvePath(definitionsPath);
331364
if (!uri.exists())
@@ -341,7 +374,7 @@ int startAnalyze(const argparse::ArgumentParser& program)
341374
return 1;
342375
}
343376

344-
auto loadResult = types::registerDefinitions(frontend, frontend.globals, *definitionsContents);
377+
auto loadResult = types::registerDefinitions(frontend, frontend.globals, packageName, *definitionsContents);
345378
if (!loadResult.success)
346379
{
347380
fprintf(stderr, "Failed to load definitions\n");

src/LuauExt.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,10 @@ std::optional<nlohmann::json> parseDefinitionsFileMetadata(const std::string& de
5353
return std::nullopt;
5454
}
5555

56-
Luau::LoadDefinitionFileResult registerDefinitions(Luau::Frontend& frontend, Luau::GlobalTypes& globals, const std::string& definitions)
56+
Luau::LoadDefinitionFileResult registerDefinitions(
57+
Luau::Frontend& frontend, Luau::GlobalTypes& globals, const std::string& packageName, const std::string& definitions)
5758
{
58-
// TODO: packageName shouldn't just be "@roblox"
59-
return frontend.loadDefinitionFile(globals, globals.globalScope, definitions, "@roblox", /* captureComments = */ false);
59+
return frontend.loadDefinitionFile(globals, globals.globalScope, definitions, packageName, /* captureComments = */ false);
6060
}
6161

6262
using NameOrExpr = std::variant<std::string, Luau::AstExpr*>;

src/Workspace.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ void WorkspaceFolder::updateTextDocument(const lsp::DocumentUri& uri, const lsp:
8080
!isIgnoredFile(dirtyUri, config))
8181
{
8282
auto dependencyDiags = documentDiagnostics(
83-
lsp::DocumentDiagnosticParams{{dirtyUri}}, /* cancellationToken=*/ nullptr, /* allowUnmanagedFiles= */ true);
83+
lsp::DocumentDiagnosticParams{{dirtyUri}}, /* cancellationToken=*/nullptr, /* allowUnmanagedFiles= */ true);
8484
client->publishDiagnostics(lsp::PublishDiagnosticsParams{dirtyUri, std::nullopt, dependencyDiags.items});
8585
}
8686
}
@@ -283,7 +283,7 @@ bool WorkspaceFolder::isDefinitionFile(const Uri& path, const std::optional<Clie
283283
{
284284
auto config = givenConfig ? *givenConfig : client->getConfiguration(rootUri);
285285

286-
for (auto& file : config.types.definitionFiles)
286+
for (auto& [_, file] : config.types.definitionFiles)
287287
{
288288
if (rootUri.resolvePath(resolvePath(file)) == path)
289289
{
@@ -474,10 +474,21 @@ void WorkspaceFolder::registerTypes(const std::vector<std::string>& disabledGlob
474474
if (client->definitionsFiles.empty())
475475
client->sendLogMessage(lsp::MessageType::Warning, "No definitions file provided by client");
476476

477-
for (const auto& definitionsFile : client->definitionsFiles)
477+
// For backwards compatibility, we need to keep an ordering where a definitions file for '@roblox' is always processed first
478+
std::vector<std::pair<std::string, std::string>> definitionsFilesToProcess{};
479+
definitionsFilesToProcess.reserve(client->definitionsFiles.size());
480+
if (auto it = client->definitionsFiles.find("@roblox"); it != client->definitionsFiles.end())
481+
definitionsFilesToProcess.emplace_back(*it);
482+
for (const auto& pair : client->definitionsFiles)
483+
{
484+
if (pair.first != "@roblox")
485+
definitionsFilesToProcess.emplace_back(pair);
486+
}
487+
488+
for (const auto& [packageName, definitionsFile] : definitionsFilesToProcess)
478489
{
479490
auto resolvedFilePath = resolvePath(definitionsFile);
480-
client->sendLogMessage(lsp::MessageType::Info, "Loading definitions file: " + resolvedFilePath);
491+
client->sendLogMessage(lsp::MessageType::Info, "Loading definitions file: " + packageName + " - " + resolvedFilePath);
481492

482493
auto definitionsContents = Luau::FileUtils::readFile(resolvedFilePath);
483494
if (!definitionsContents)
@@ -495,9 +506,9 @@ void WorkspaceFolder::registerTypes(const std::vector<std::string>& disabledGlob
495506
client->sendTrace("workspace initialization: parsing definitions file metadata COMPLETED", json(definitionsFileMetadata).dump());
496507

497508
client->sendTrace("workspace initialization: registering types definition");
498-
auto result = types::registerDefinitions(frontend, frontend.globals, *definitionsContents);
509+
auto result = types::registerDefinitions(frontend, frontend.globals, packageName, *definitionsContents);
499510
if (!FFlag::LuauSolverV2)
500-
types::registerDefinitions(frontend, frontend.globalsForAutocomplete, *definitionsContents);
511+
types::registerDefinitions(frontend, frontend.globalsForAutocomplete, packageName, *definitionsContents);
501512
client->sendTrace("workspace initialization: registering types definition COMPLETED");
502513

503514
client->sendTrace("workspace: applying platform mutations on definitions");

src/include/Analyze/AnalyzeCli.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
struct WorkspaceFileResolver;
1111

12+
std::unordered_map<std::string, std::string> processDefinitionsFilePaths(const argparse::ArgumentParser& program);
13+
1214
struct FilePathInformation
1315
{
1416
Uri uri;
@@ -18,6 +20,6 @@ struct FilePathInformation
1820
FilePathInformation getFilePath(const WorkspaceFileResolver* fileResolver, const std::string& moduleName);
1921

2022
std::vector<std::string> getFilesToAnalyze(const std::vector<std::string>& paths, const std::vector<std::string>& ignoreGlobPatterns);
21-
void applySettings(
22-
const std::string& settingsContents, CliClient& client, std::vector<std::string>& ignoreGlobPatterns, std::vector<std::string>& definitionsPaths);
23+
void applySettings(const std::string& settingsContents, CliClient& client, std::vector<std::string>& ignoreGlobPatterns,
24+
std::unordered_map<std::string, std::string>& definitionsPaths);
2325
int startAnalyze(const argparse::ArgumentParser& program);

src/include/LSP/Client.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class Client : public BaseClient
3030
lsp::ClientCapabilities capabilities;
3131
lsp::TraceValue traceMode = lsp::TraceValue::Off;
3232
/// A registered definitions file passed by the client
33-
std::vector<std::string> definitionsFiles{};
33+
std::unordered_map<std::string, std::string> definitionsFiles{};
3434
/// A registered documentation file passed by the client
3535
std::vector<std::string> documentationFiles{};
3636
/// Parsed documentation database

0 commit comments

Comments
 (0)