diff --git a/server/src/DefinitionProvider.ts b/server/src/DefinitionProvider.ts deleted file mode 100644 index 1514028d..00000000 --- a/server/src/DefinitionProvider.ts +++ /dev/null @@ -1,192 +0,0 @@ -/* -------------------------------------------------------------------------------------------- - * Copyright (c) Eugen Wiens. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * ------------------------------------------------------------------------------------------ */ - -import { - type Definition, - Location, - Range -} from 'vscode-languageserver' - -import { - type ElementInfo, - type PathInfo -} from './lib/src/types/BitbakeScanResult' - -import { - type SymbolScanner, - type SymbolContent -} from './SymbolScanner' - -import { logger } from './lib/src/utils/OutputLogger' - -import path from 'path' -import { bitBakeProjectScannerClient } from './BitbakeProjectScannerClient' - -export class DefinitionProvider { - private _symbolScanner: SymbolScanner | null = null - - // eslint-disable-next-line accessor-pairs - set symbolScanner (symbolScanner: SymbolScanner | null) { - this._symbolScanner = symbolScanner - } - - createDefinitionForKeyword (keyword: string, restOfLine: string, selectedSympbol?: string): Definition { - let definition: Definition = [] - restOfLine = restOfLine.trim() - - switch (keyword) { - case 'inherit': - { - let searchString: string - if (selectedSympbol === undefined) { - searchString = restOfLine - } else { - searchString = selectedSympbol - } - - const elementInfos: ElementInfo[] = bitBakeProjectScannerClient.bitbakeScanResult._classes.filter((obj: ElementInfo): boolean => { - return obj.name === searchString - }) - definition = this.createDefinitionForElementInfo(elementInfos) - } - break - - case 'require': - case 'include': - { - const includeFile: PathInfo = path.parse(restOfLine) - let elementInfos: ElementInfo[] = bitBakeProjectScannerClient.bitbakeScanResult._includes.filter((obj: ElementInfo): boolean => { - return obj.name === includeFile.name - }) - - if (elementInfos.length === 0) { - elementInfos = bitBakeProjectScannerClient.bitbakeScanResult._recipes.filter((obj: ElementInfo): boolean => { - return obj.name === includeFile.name - }) - } - definition = this.createDefinitionForElementInfo(elementInfos) - } - break - - default: - } - - return definition - } - - createDefinitionForSymbol (symbol: string): Definition { - let definitions: Definition = this.createDefinitionForSymbolRecipes(symbol) - - if (definitions === null) { - definitions = this.createDefinitionForSymbolVariables(symbol) - } - - return definitions - } - - private createDefinitionForSymbolRecipes (symbol: string): Definition { - let definitions: Definition = [] - - const recipe: ElementInfo | undefined = bitBakeProjectScannerClient.bitbakeScanResult._recipes.find((obj: ElementInfo): boolean => { - return obj.name === symbol - }) - - if (recipe?.path !== undefined) { - let definitionsList: PathInfo[] = new Array < PathInfo >(recipe.path) - - if ((recipe.appends !== undefined) && (recipe.appends.length > 0)) { - definitionsList = definitionsList.concat(recipe.appends) - } - definitions = this.createDefinitionLocationForPathInfoList(definitionsList) - } - - return definitions - } - - private createDefinitionForSymbolVariables (symbol: string): Definition { - let definitions: Definition = [] - - if (this._symbolScanner !== null) { - const symbols: SymbolContent[] = this._symbolScanner.symbols.filter((obj: SymbolContent): boolean => { - return obj.symbolName === symbol - }) - definitions = this.createDefinitionForSymbolContentList(symbols) - } else { - logger.debug(`Cannot create definitions for symbol ${symbol}: symbol scanner is null`) - } - - return definitions - } - - private createDefinitionForElementInfo (elementInfos: ElementInfo[]): Definition { - const definition: Definition = [] - - for (const elementInfo of elementInfos) { - logger.debug(`definition ${JSON.stringify(elementInfo)}`) - if (elementInfo.path !== undefined) { - const location: Location = this.createDefinitionLocationForPathInfo(elementInfo.path) - definition.push(location) - } - } - - return definition - } - - private createDefinitionLocationForPathInfoList (pathInfoList: PathInfo[]): Definition { - let definition: Definition = [] - - if ((pathInfoList !== undefined) && (pathInfoList.length > 0)) { - if (pathInfoList.length > 1) { - definition = new Array < Location >() - - for (const pathInfo of pathInfoList) { - logger.debug(`definition ${JSON.stringify(pathInfo)}`) - const location: Location = this.createDefinitionLocationForPathInfo(pathInfo) - - definition.push(location) - } - } else { - definition = this.createDefinitionLocationForPathInfo(pathInfoList[0]) - } - } - - return definition - } - - private createDefinitionLocationForPathInfo (path: PathInfo): Location { - const url: string = 'file://' + path.dir + '/' + path.base - const location: Location = Location.create(encodeURI(url), Range.create(0, 0, 0, 0)) - - return location - } - - private createDefinitionForSymbolContentList (symbolContent: SymbolContent[]): Definition { - const definition: Definition = [] - - for (const element of symbolContent) { - logger.debug(`definition ${JSON.stringify(element)}`) - const location = this.createDefinitionForSymbolContent(element) - if (location !== undefined) { - definition.push(location) - } - } - - return definition - } - - private createDefinitionForSymbolContent (symbolContent: SymbolContent): Location | undefined { - const url: string = 'file://' + symbolContent.filePath - if (symbolContent.lineNumber === undefined) { - return undefined - } - const range: Range = Range.create(symbolContent.lineNumber, symbolContent.startPosition, - symbolContent.lineNumber, symbolContent.endPostion - ) - - return Location.create(encodeURI(url), range) - } -} - -export const definitionProvider = new DefinitionProvider() diff --git a/server/src/SymbolScanner.ts b/server/src/SymbolScanner.ts deleted file mode 100644 index f01e7516..00000000 --- a/server/src/SymbolScanner.ts +++ /dev/null @@ -1,181 +0,0 @@ -/* -------------------------------------------------------------------------------------------- - * Copyright (c) Eugen Wiens. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * ------------------------------------------------------------------------------------------ */ - -import fs from 'fs' - -import type { - Definition, - Location -} from 'vscode-languageserver' - -import type { - DefinitionProvider -} from './DefinitionProvider' - -import { logger } from './lib/src/utils/OutputLogger' -import { DIRECTIVE_STATEMENT_KEYWORDS } from './lib/src/types/directiveKeywords' - -interface FileContent { - filePath: string - fileContent: string[] -} - -export interface SymbolContent { - symbolName: string - startPosition: number - endPostion: number - filePath?: string - lineNumber?: number -} - -export class SymbolScanner { - private readonly _fileContent: FileContent[] = new Array < FileContent >() - private readonly _definitionProvider: DefinitionProvider - private readonly _symbolsDefinition: SymbolContent[] = new Array < SymbolContent >() - - constructor (fileUrlAsString: string, definitionProvider: DefinitionProvider) { - logger.debug(`scan for symbols file: ${fileUrlAsString}`) - - this._definitionProvider = definitionProvider - - this.extendsFile(this.convertUriStringToFilePath(fileUrlAsString)) - this.scanForSymbols() - } - - get symbols (): SymbolContent[] { - return this._symbolsDefinition - } - - private extendsFile (filePath: string): void { - logger.debug(`extendsFile file: ${filePath}`) - - try { - const data: Buffer = fs.readFileSync(filePath) - const file: string[] = data.toString().split(/\r?\n/g) - - this._fileContent.push({ - filePath, - fileContent: file - }) - - for (const line of file) { - const words = line.split(' ') - - if (new Set(DIRECTIVE_STATEMENT_KEYWORDS).has(words[0])) { - logger.debug(`Directive statement keyword found: ${words[0]}`) - this.handleKeyword(words[0], line) - } - } - } catch (error) { - if (error instanceof Error) { // Check if error is an instance of the native JavaScript Error class - logger.error(`Error reading file at ${filePath}: ${error.message}`) - } else if (typeof error === 'string') { - logger.error(`Error reading file at ${filePath}: ${error}`) - } else { - logger.error(`An unknown error occurred while reading the file at ${filePath}`) - } - } - } - - private handleKeyword (keyword: string, line: string): void { - const restOfLine: string[] = line.split(keyword).filter(String) - - if (restOfLine.length === 1) { - const listOfSymbols: string[] = restOfLine[0].split(' ').filter(String) - let definition: Definition = new Array < Location >() - - if (listOfSymbols.length === 1) { - definition = definition.concat(this._definitionProvider.createDefinitionForKeyword(keyword, restOfLine[0])) - } else if (listOfSymbols.length > 1) { - for (const symbol of listOfSymbols) { - definition = definition.concat(this._definitionProvider.createDefinitionForKeyword(keyword, restOfLine[0], symbol)) - } - } - - for (const location of definition) { - if (location !== null) { - this.extendsFile(this.convertUriStringToFilePath(location.uri)) - } - } - } - } - - private convertUriStringToFilePath (fileUrlAsString: string): string { - const fileUrl = new URL(fileUrlAsString) - // Use decodeURIComponent to properly decode each part of the URL - // This correctly decodes url in Windows such as %3A -> : - let filePath: string = decodeURIComponent(fileUrl.pathname) - - // For Windows, remove the leading slash if it exists - if (process.platform === 'win32' && filePath.startsWith('/')) { - filePath = filePath.substring(1) - } - - return filePath - } - - private scanForSymbols (): void { - for (const file of this._fileContent) { - for (const line of file.fileContent) { - const lineIndex: number = file.fileContent.indexOf(line) - const regex = /^\s*(?:export)?\s*(\w*(?:\[\w*\])?)\s*(?:=|:=|\+=|=\+|-=|=-|\?=|\?\?=|\.=|=\.)/g - const symbolContent = this.investigateLine(line, regex) - - if (symbolContent !== undefined) { - symbolContent.filePath = file.filePath - symbolContent.lineNumber = lineIndex - - this._symbolsDefinition.push(symbolContent) - } - } - } - } - - private investigateLine (lineString: string, regex: RegExp): SymbolContent | undefined { - let m - - while ((m = regex.exec(lineString)) !== null) { - // This is necessary to avoid infinite loops with zero-width matches - if (m.index === regex.lastIndex) { - regex.lastIndex++ - } - - if (m.length === 2) { - const symbol: string = m[1] - const filterdSymbolName = this.filterSymbolName(symbol) - if (filterdSymbolName === undefined) { - return undefined - } - const symbolStartPosition: number = lineString.indexOf(symbol) - const symbolEndPosition: number = symbolStartPosition + symbol.length - - return { - symbolName: filterdSymbolName, - startPosition: symbolStartPosition, - endPostion: symbolEndPosition - } - } - } - - return undefined - } - - private filterSymbolName (symbol: string): string | undefined { - const regex = /^\w*/g - let m - let filterdSymbolName: string | undefined - - while ((m = regex.exec(symbol)) !== null) { - // This is necessary to avoid infinite loops with zero-width matches - if (m.index === regex.lastIndex) { - regex.lastIndex++ - } - - filterdSymbolName = m[0] - } - - return filterdSymbolName - } -}