-
Notifications
You must be signed in to change notification settings - Fork 10
Add NAMESPACE-file-plugin #1983
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
01a2d88
cd40cbd
2544701
d62c6c3
3717b1e
d8a96bf
28f3a4f
d2cc9ac
9fe038c
1716193
50aa15c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,6 +19,8 @@ import type { | |
| FlowrAnalyzerProjectDiscoveryPlugin | ||
| } from '../plugins/project-discovery/flowr-analyzer-project-discovery-plugin'; | ||
| import type { FlowrAnalyzerFilePlugin } from '../plugins/file-plugins/flowr-analyzer-file-plugin'; | ||
| import type { ReadOnlyFlowrAnalyzerFunctionsContext } from './flowr-analyzer-functions-context'; | ||
| import { FlowrAnalyzerFunctionsContext } from './flowr-analyzer-functions-context'; | ||
| import { arraysGroupBy } from '../../util/collections/arrays'; | ||
| import type { fileProtocol, RParseRequestFromFile, RParseRequests } from '../../r-bridge/retriever'; | ||
| import { requestFromInput } from '../../r-bridge/retriever'; | ||
|
|
@@ -45,6 +47,8 @@ export interface ReadOnlyFlowrAnalyzerContext { | |
| * The configuration options used by the analyzer. | ||
| */ | ||
| readonly config: FlowrConfigOptions; | ||
|
|
||
| readonly functions: ReadOnlyFlowrAnalyzerFunctionsContext; | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -60,16 +64,19 @@ export interface ReadOnlyFlowrAnalyzerContext { | |
| * If you are just interested in inspecting the context, you can use {@link ReadOnlyFlowrAnalyzerContext} instead (e.g., via {@link inspect}). | ||
| */ | ||
| export class FlowrAnalyzerContext implements ReadOnlyFlowrAnalyzerContext { | ||
| public readonly files: FlowrAnalyzerFilesContext; | ||
| public readonly deps: FlowrAnalyzerDependenciesContext; | ||
| public readonly config: FlowrConfigOptions; | ||
| public readonly files: FlowrAnalyzerFilesContext; | ||
| public readonly deps: FlowrAnalyzerDependenciesContext; | ||
| public readonly config: FlowrConfigOptions; | ||
| public readonly functions: FlowrAnalyzerFunctionsContext; | ||
|
|
||
|
|
||
| constructor(config: FlowrConfigOptions, plugins: ReadonlyMap<PluginType, readonly FlowrAnalyzerPlugin[]>) { | ||
| this.config = config; | ||
| const loadingOrder = new FlowrAnalyzerLoadingOrderContext(this, plugins.get(PluginType.LoadingOrder) as FlowrAnalyzerLoadingOrderPlugin[]); | ||
| this.files = new FlowrAnalyzerFilesContext(loadingOrder, (plugins.get(PluginType.ProjectDiscovery) ?? []) as FlowrAnalyzerProjectDiscoveryPlugin[], | ||
| (plugins.get(PluginType.FileLoad) ?? []) as FlowrAnalyzerFilePlugin[]); | ||
| this.deps = new FlowrAnalyzerDependenciesContext(this, (plugins.get(PluginType.DependencyIdentification) ?? []) as FlowrAnalyzerPackageVersionsPlugin[]); | ||
| this.functions = new FlowrAnalyzerFunctionsContext(this, (plugins.get(PluginType.DependencyIdentification) ?? []) as FlowrAnalyzerPackageVersionsPlugin[]); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The functions context should not directly rely on the package versions, but maybe be a child of the analyzer dependencies context similar to the loading order |
||
| } | ||
|
|
||
| /** delegate request addition */ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| import { AbstractFlowrAnalyzerContext } from './abstract-flowr-analyzer-context'; | ||
| import type { FlowrAnalyzerContext } from './flowr-analyzer-context'; | ||
| import { | ||
| FlowrAnalyzerPackageVersionsPlugin | ||
| } from '../plugins/package-version-plugins/flowr-analyzer-package-versions-plugin'; | ||
|
|
||
| export enum FunctionTypes { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it is weird to have a function type |
||
| Function = 'function', | ||
| Symbol = 'symbol', | ||
| S3 = 'S3' | ||
| } | ||
|
|
||
| export interface FunctionInfo { | ||
| name: string; | ||
| packageOrigin: string; | ||
| isExported: boolean; | ||
| isS3Generic: boolean; | ||
| className?: string; | ||
| inferredType?: string; | ||
| } | ||
|
|
||
| export interface ReadOnlyFlowrAnalyzerFunctionsContext { | ||
| readonly name: string; | ||
|
|
||
| getFunctionInfo(name: string, className?: string): FunctionInfo | undefined; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the function info must be scoped by the package namespace! |
||
| } | ||
|
|
||
| export class FlowrAnalyzerFunctionsContext extends AbstractFlowrAnalyzerContext<undefined, void, FlowrAnalyzerPackageVersionsPlugin> implements ReadOnlyFlowrAnalyzerFunctionsContext { | ||
| public readonly name = 'flowr-analyzer-functions-context'; | ||
|
|
||
| private functionInfo: Map<string, FunctionInfo> = new Map<string, FunctionInfo>(); | ||
|
|
||
| public constructor(ctx: FlowrAnalyzerContext, plugins?: readonly FlowrAnalyzerPackageVersionsPlugin[]) { | ||
| super(ctx, FlowrAnalyzerPackageVersionsPlugin.defaultPlugin(), plugins); | ||
| } | ||
|
|
||
| public addFunctionInfo(functionInfo: FunctionInfo) { | ||
| const fi = this.functionInfo.get(functionInfo.name); | ||
| if(fi) { | ||
| // merge? | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, and at least warn |
||
| } else { | ||
| this.functionInfo.set(functionInfo.name, functionInfo); | ||
| } | ||
| } | ||
|
|
||
| public getFunctionInfo(name: string, className?: string): FunctionInfo | undefined { | ||
| if(className) { | ||
| return this.functionInfo.get(`${name}.${className}`); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not what i expected with className maybe |
||
| } else if(name.includes('.')){ | ||
| const parts = name.split('.'); | ||
| const splitClassName = parts.pop(); | ||
| const splitName = parts.join('.'); | ||
| if(this.functionInfo.has(splitName)) { | ||
| const value = this.functionInfo.get(splitName); | ||
| return value?.className === splitClassName ? value : undefined; | ||
| } | ||
| } | ||
| return this.functionInfo.get(name); | ||
| } | ||
|
|
||
| public reset(): void { | ||
| this.functionInfo = new Map<string, FunctionInfo>(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| import { FlowrAnalyzerFilePlugin } from './flowr-analyzer-file-plugin'; | ||
| import { SemVer } from 'semver'; | ||
| import type { PathLike } from 'fs'; | ||
| import type { FlowrAnalyzerContext } from '../../context/flowr-analyzer-context'; | ||
| import type { FlowrFileProvider } from '../../context/flowr-file'; | ||
| import { FileRole } from '../../context/flowr-file'; | ||
| import { FlowrNamespaceFile } from './flowr-namespace-file'; | ||
| import { platformBasename } from '../../../dataflow/internal/process/functions/call/built-in/built-in-source'; | ||
|
|
||
| const NamespaceFilePattern = /^(NAMESPACE(\.txt)?)$/i; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I dont think we need the outer parens |
||
|
|
||
| /** | ||
| * This plugin provides support for R `NAMESPACE` files. | ||
| */ | ||
| export class FlowrAnalyzerNamespaceFilePlugin extends FlowrAnalyzerFilePlugin { | ||
| public readonly name = 'flowr-analyzer-namespace-file-plugin'; | ||
| public readonly description = 'This plugin provides support for NAMESPACE files and extracts their content into the NAMESPACEFormat.'; | ||
| public readonly version = new SemVer('0.1.0'); | ||
| private readonly pattern: RegExp; | ||
|
|
||
| /** | ||
| * Creates a new instance of the NAMESPACE file plugin. | ||
| * @param filePattern - The pattern to identify NAMESPACE files, see {@link NamespaceFilePattern} for the default pattern. | ||
| */ | ||
| constructor(filePattern: RegExp = NamespaceFilePattern) { | ||
| super(); | ||
| this.pattern = filePattern; | ||
| } | ||
|
|
||
| public applies(file: PathLike): boolean { | ||
| return this.pattern.test(platformBasename(file.toString())); | ||
| } | ||
|
|
||
| public process(_ctx: FlowrAnalyzerContext, file: FlowrFileProvider): FlowrNamespaceFile { | ||
| return FlowrNamespaceFile.from(file, FileRole.Namespace); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| import type { FileRole, FlowrFileProvider } from '../../context/flowr-file'; | ||
| import { FlowrFile } from '../../context/flowr-file'; | ||
| import { parseNamespace } from '../../../util/files'; | ||
|
|
||
| export interface NamespaceInfo { | ||
| exportedSymbols: string[]; | ||
| exportedFunctions: string[]; | ||
| exportS3Generics: Map<string, string[]>; | ||
| loadsWithSideEffects: boolean; | ||
| } | ||
|
|
||
| export interface NamespaceFormat { | ||
| current: NamespaceInfo; | ||
| [packageName: string]: NamespaceInfo; | ||
| } | ||
|
|
||
| /** | ||
| * | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could you please fill in these? |
||
| */ | ||
| export class FlowrNamespaceFile extends FlowrFile<NamespaceFormat> { | ||
| private readonly wrapped: FlowrFileProvider; | ||
|
|
||
| /** | ||
| * | ||
| */ | ||
| constructor(file: FlowrFileProvider) { | ||
| super(file.path(), file.role); | ||
| this.wrapped = file; | ||
| } | ||
|
|
||
| /** | ||
| * @see {@link parseNamespace} for details on the parsing logic. | ||
| */ | ||
| protected loadContent(): NamespaceFormat { | ||
| return parseNamespace(this.wrapped); | ||
| } | ||
|
|
||
|
|
||
| /** | ||
| * Namespace file lifter, this does not re-create if already a namespace file | ||
| */ | ||
| public static from(file: FlowrFileProvider | FlowrNamespaceFile, role?: FileRole): FlowrNamespaceFile { | ||
| if(role) { | ||
| file.assignRole(role); | ||
| } | ||
EagleoutIce marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return file instanceof FlowrNamespaceFile ? file : new FlowrNamespaceFile(file); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| import { FlowrAnalyzerPackageVersionsPlugin } from './flowr-analyzer-package-versions-plugin'; | ||
| import { | ||
| descriptionFileLog | ||
| } from '../file-plugins/flowr-analyzer-description-file-plugin'; | ||
| import { SemVer } from 'semver'; | ||
| import { Package } from './package'; | ||
| import type { FlowrAnalyzerContext } from '../../context/flowr-analyzer-context'; | ||
| import { FileRole } from '../../context/flowr-file'; | ||
| import type { NamespaceFormat } from '../file-plugins/flowr-namespace-file'; | ||
|
|
||
| export class FlowrAnalyzerPackageVersionsNamespaceFilePlugin extends FlowrAnalyzerPackageVersionsPlugin { | ||
| public readonly name = 'flowr-analyzer-package-version-namespace-file-plugin'; | ||
| public readonly description = 'This plugin does...'; | ||
| public readonly version = new SemVer('0.1.0'); | ||
|
|
||
| process(ctx: FlowrAnalyzerContext): void { | ||
| const nmspcFiles = ctx.files.getFilesByRole(FileRole.Namespace); | ||
| if(nmspcFiles.length !== 1) { | ||
| descriptionFileLog.warn(`Supporting only exactly one NAMESPACE file, found ${nmspcFiles.length}`); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we? why? namespace files can be merged, we just have to throw errors if things are incompatible, but we have to that as well if it happens in the same namespace file |
||
| return; | ||
| } | ||
|
|
||
| /** this will do the caching etc. for me */ | ||
| const deps = nmspcFiles[0].content() as NamespaceFormat; | ||
|
|
||
| for(const pkg in deps) { | ||
| const info = deps[pkg]; | ||
| ctx.deps.addDependency(new Package( | ||
| { | ||
| name: pkg, | ||
| namespaceInfo: info | ||
| } | ||
| )); | ||
| for(const exportedSymbol of info.exportedSymbols) { | ||
| ctx.functions.addFunctionInfo({ | ||
| name: exportedSymbol, | ||
| packageOrigin: pkg, | ||
| isExported: true, | ||
| isS3Generic: false, | ||
| }); | ||
| } | ||
| for(const exportedFunction of info.exportedFunctions) { | ||
| ctx.functions.addFunctionInfo({ | ||
| name: exportedFunction, | ||
| packageOrigin: pkg, | ||
| isExported: true, | ||
| isS3Generic: false, | ||
| }); | ||
| } | ||
| for(const [genericName, classes] of info.exportS3Generics.entries()) { | ||
| for(const className of classes) { | ||
| ctx.functions.addFunctionInfo({ | ||
| name: genericName, | ||
| packageOrigin: pkg, | ||
| isExported: true, | ||
| isS3Generic: true, | ||
| className: className, | ||
| }); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a doc comment