Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/LanguageServer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,8 @@ describe('LanguageServer', () => {
languageServer: {
enableThreading: false,
enableProjectDiscovery: true,
logLevel: 'info'
logLevel: 'info',
projectDiscoveryMaxDepth: 15
}
}
]);
Expand Down
4 changes: 3 additions & 1 deletion src/LanguageServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,8 @@ export class LanguageServer {
languageServer: {
enableThreading: brightscriptConfig.languageServer?.enableThreading ?? LanguageServer.enableThreadingDefault,
enableProjectDiscovery: brightscriptConfig.languageServer?.enableProjectDiscovery ?? LanguageServer.enableProjectDiscoveryDefault,
logLevel: brightscriptConfig?.languageServer?.logLevel
logLevel: brightscriptConfig?.languageServer?.logLevel,
projectDiscoveryMaxDepth: brightscriptConfig?.languageServer?.projectDiscoveryMaxDepth ?? 15
}
};
})
Expand Down Expand Up @@ -825,6 +826,7 @@ export interface BrightScriptClientConfiguration {
enableThreading: boolean;
enableProjectDiscovery: boolean;
logLevel: LogLevel | string;
projectDiscoveryMaxDepth?: number;
};
}

Expand Down
189 changes: 189 additions & 0 deletions src/lsp/ProjectManager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,195 @@ describe('ProjectManager', () => {
});
});

describe('maxDepth configuration', () => {
function writeTestFiles(files: Record<string, string>) {
for (const [filePath, content] of Object.entries(files)) {
fsExtra.outputFileSync(`${rootDir}/${filePath}`, content);
}
}

it('respects maxDepth of 1 when discovering projects', async () => {
// Create bsconfig.json files at different depths
writeTestFiles({
'bsconfig.json': '',
'level1/bsconfig.json': '',
'level1/level2/bsconfig.json': '',
'level1/level2/level3/bsconfig.json': ''
});

await manager.syncProjects([{
...workspaceSettings,
languageServer: {
...workspaceSettings.languageServer,
projectDiscoveryMaxDepth: 1
}
}]);

// maxDepth: 1 should find files at depth 0 only
expect(
manager.projects.map(x => x.projectKey).sort()
).to.eql([
s`${rootDir}/bsconfig.json`
]);
});

it('respects maxDepth of 5 when discovering projects', async () => {
// Create bsconfig.json files at different depths
writeTestFiles({
'bsconfig.json': '',
'level1/bsconfig.json': '',
'level1/level2/bsconfig.json': '',
'level1/level2/level3/bsconfig.json': '',
'level1/level2/level3/level4/bsconfig.json': '',
'level1/level2/level3/level4/level5/bsconfig.json': '',
'level1/level2/level3/level4/level5/level6/bsconfig.json': ''
});

await manager.syncProjects([{
...workspaceSettings,
languageServer: {
...workspaceSettings.languageServer,
projectDiscoveryMaxDepth: 5
}
}]);

// maxDepth: 5 should find files at depths 0, 1, 2, 3, 4
expect(
manager.projects.map(x => x.projectKey).sort()
).to.eql([
s`${rootDir}/bsconfig.json`,
s`${rootDir}/level1/bsconfig.json`,
s`${rootDir}/level1/level2/bsconfig.json`,
s`${rootDir}/level1/level2/level3/bsconfig.json`,
s`${rootDir}/level1/level2/level3/level4/bsconfig.json`
]);
});

it('respects maxDepth of 20 when discovering projects', async () => {
// Create bsconfig.json files at different depths, skipping some levels in between
// and proving it stops at level 20 by creating files at level 20 and 21
// Note: depth 20 means the file is in the 20th directory level from root
writeTestFiles({
'bsconfig.json': '',
'level1/bsconfig.json': '',
'level1/level2/level3/level4/level5/bsconfig.json': '',
'level1/level2/level3/level4/level5/level6/level7/level8/level9/level10/level11/level12/level13/level14/level15/level16/level17/level18/level19/bsconfig.json': '',
'level1/level2/level3/level4/level5/level6/level7/level8/level9/level10/level11/level12/level13/level14/level15/level16/level17/level18/level19/level20/bsconfig.json': ''
});

await manager.syncProjects([{
...workspaceSettings,
languageServer: {
...workspaceSettings.languageServer,
projectDiscoveryMaxDepth: 20
}
}]);

// maxDepth: 20 should find file at level 19 (depth 20) but not at level 20 (depth 21)
expect(
manager.projects.map(x => x.projectKey).sort()
).to.eql([
s`${rootDir}/bsconfig.json`,
s`${rootDir}/level1/bsconfig.json`,
s`${rootDir}/level1/level2/level3/level4/level5/bsconfig.json`,
s`${rootDir}/level1/level2/level3/level4/level5/level6/level7/level8/level9/level10/level11/level12/level13/level14/level15/level16/level17/level18/level19/bsconfig.json`
]);
});

it('uses default maxDepth of 15 when no maxDepth is specified', async () => {
// Create bsconfig.json files at different depths, skipping some levels in between
// and proving it stops at level 15 by creating files at level 15 and 16
// Note: depth 15 means the file is in the 15th directory level from root
writeTestFiles({
'bsconfig.json': '',
'level1/bsconfig.json': '',
'level1/level2/level3/level4/level5/bsconfig.json': '',
'level1/level2/level3/level4/level5/level6/level7/level8/level9/level10/level11/level12/level13/level14/bsconfig.json': '',
'level1/level2/level3/level4/level5/level6/level7/level8/level9/level10/level11/level12/level13/level14/level15/bsconfig.json': ''
});

await manager.syncProjects([workspaceSettings]);

// Default maxDepth: 15 should find file at level 14 (depth 15) but not at level 15 (depth 16)
expect(
manager.projects.map(x => x.projectKey).sort()
).to.eql([
s`${rootDir}/bsconfig.json`,
s`${rootDir}/level1/bsconfig.json`,
s`${rootDir}/level1/level2/level3/level4/level5/bsconfig.json`,
s`${rootDir}/level1/level2/level3/level4/level5/level6/level7/level8/level9/level10/level11/level12/level13/level14/bsconfig.json`
]);
});

it('respects maxDepth of 1 when discovering roku projects with manifest files', async () => {
// Create manifest files at different depths
writeTestFiles({
'manifest': '',
'source/main.brs': '',
'level1/manifest': '',
'level1/source/main.brs': '',
'level1/level2/manifest': '',
'level1/level2/source/main.brs': '',
'level1/level2/level3/manifest': '',
'level1/level2/level3/source/main.brs': ''
});

await manager.syncProjects([{
...workspaceSettings,
languageServer: {
...workspaceSettings.languageServer,
projectDiscoveryMaxDepth: 1
}
}]);

// maxDepth: 1 should find projects at depth 0 only
expect(
manager.projects.map(x => x.projectKey).sort()
).to.eql([
s`${rootDir}`
]);
});

it('respects maxDepth of 5 when discovering roku projects with manifest files', async () => {
// Create manifest files at different depths
writeTestFiles({
'manifest': '',
'source/main.brs': '',
'level1/manifest': '',
'level1/source/main.brs': '',
'level1/level2/manifest': '',
'level1/level2/source/main.brs': '',
'level1/level2/level3/manifest': '',
'level1/level2/level3/source/main.brs': '',
'level1/level2/level3/level4/manifest': '',
'level1/level2/level3/level4/source/main.brs': '',
'level1/level2/level3/level4/level5/manifest': '',
'level1/level2/level3/level4/level5/source/main.brs': '',
'level1/level2/level3/level4/level5/level6/manifest': '',
'level1/level2/level3/level4/level5/level6/source/main.brs': ''
});

await manager.syncProjects([{
...workspaceSettings,
languageServer: {
...workspaceSettings.languageServer,
projectDiscoveryMaxDepth: 5
}
}]);

// maxDepth: 5 should find projects at depths 0, 1, 2, 3, 4
expect(
manager.projects.map(x => x.projectKey).sort()
).to.eql([
s`${rootDir}`,
s`${rootDir}/level1`,
s`${rootDir}/level1/level2`,
s`${rootDir}/level1/level2/level3`,
s`${rootDir}/level1/level2/level3/level4`
]);
});
});

describe('getCompletions', () => {
it('works for quick file changes', async () => {
//set up the project
Expand Down
10 changes: 8 additions & 2 deletions src/lsp/ProjectManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,8 @@ export class ProjectManager {
cwd: workspaceConfig.workspaceFolder,
followSymbolicLinks: false,
absolute: true,
onlyFiles: true
onlyFiles: true,
deep: workspaceConfig.languageServer.projectDiscoveryMaxDepth ?? 15
});

//filter the files to only include those that are allowed by the path filterer
Expand All @@ -733,7 +734,8 @@ export class ProjectManager {
cwd: workspaceConfig.workspaceFolder,
followSymbolicLinks: false,
absolute: true,
onlyFiles: true
onlyFiles: true,
deep: workspaceConfig.languageServer.projectDiscoveryMaxDepth ?? 15
})).map(async manifestEntry => {
const manifestDir = path.dirname(manifestEntry);
//TODO validate that manifest is a Roku manifest
Expand Down Expand Up @@ -949,6 +951,10 @@ export interface WorkspaceConfig {
* The log level to use for this workspace
*/
logLevel?: LogLevel | string;
/**
* Maximum depth to search for Roku projects
*/
projectDiscoveryMaxDepth?: number;
};
}

Expand Down
Loading