UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

167 lines 7.21 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FlowrAnalyzerBuilder = void 0; const config_1 = require("../config"); const flowr_analyzer_1 = require("./flowr-analyzer"); const engines_1 = require("../engines"); const assert_1 = require("../util/assert"); const flowr_analyzer_context_1 = require("./context/flowr-analyzer-context"); const flowr_analyzer_cache_1 = require("./cache/flowr-analyzer-cache"); const flowr_analyzer_plugin_defaults_1 = require("./plugins/flowr-analyzer-plugin-defaults"); const plugin_registry_1 = require("./plugins/plugin-registry"); /** * Builder for the {@link FlowrAnalyzer}, use it to configure all analysis aspects before creating the analyzer instance * with {@link FlowrAnalyzerBuilder#build|`.build()`} or {@link FlowrAnalyzerBuilder#buildSync|`.buildSync()`}. * * You can add new files and folders to analyze using the {@link FlowrAnalyzer#addRequest|`.addRequest()`} method on the resulting analyzer. * @example Let's create an analyzer for a single R script file: * * ```ts * const analyzer = new FlowrAnalyzerBuilder() * .setParser(new TreeSitterExecutor()) * .buildSync() * .addRequest('file:///path/to/script.R') * * ``` * * If you now want to get the dataflow information for the file, you can do this: * * ```ts * const dfInfo = await analyzer.dataflow(); * console.log(dfInfo); * ``` * @see https://github.com/flowr-analysis/flowr/wiki/Analyzer */ class FlowrAnalyzerBuilder { flowrConfig = config_1.FlowrConfig.default(); parser; input; plugins = new Map(); /** * Creates a new builder for the {@link FlowrAnalyzer}. * By default, the standard set of plugins as returned by {@link FlowrAnalyzerPluginDefaults} are registered. * @param withDefaultPlugins - Whether to register the default plugins upon creation. Default is `true`. * @see {@link FlowrAnalyzerPluginDefaults} - for the default plugin set. * @see {@link FlowrAnalyzerBuilder#registerPlugins} - to add more plugins. * @see {@link FlowrAnalyzerBuilder#unregisterPlugins} - to remove plugins. */ constructor(withDefaultPlugins = true) { if (withDefaultPlugins) { this.registerPlugins(...(0, flowr_analyzer_plugin_defaults_1.FlowrAnalyzerPluginDefaults)()); } } /** * Apply an amendment to the configuration the builder currently holds. * This is mostly intended for more complex logic to transform the config. * Please consider using {@link FlowrAnalyzerBuilder.configure} to set/amend individual values * Per default, the value returned by {@link FlowrConfig.default} is used. * @param func - Receives the current configuration of the builder and allows for amendment. */ // eslint-disable-next-line @typescript-eslint/no-invalid-void-type amendConfig(func) { this.flowrConfig = config_1.FlowrConfig.amend(this.flowrConfig, func); return this; } /** * Overwrite the configuration used by the resulting analyzer. * @param config - The new configuration. */ setConfig(config) { this.flowrConfig = config; return this; } /** * Set a specific value in the configuration used by the resulting analyzer. */ configure(key, value) { config_1.FlowrConfig.setInConfigInPlace(this.flowrConfig, key, value); return this; } /** * Set the parser instance used by the analyzer. * This is an alternative to {@link FlowrAnalyzerBuilder#setEngine} if you already have a parser instance. * Please be aware, that if you want to parallelize multiple analyzers, there should be separate parser instances. */ setParser(parser) { this.parser = parser; return this; } /** * Set the engine and hence the parser that will be used by the analyzer. * This is an alternative to {@link FlowrAnalyzerBuilder#setParser} if you do not have a parser instance at hand. */ setEngine(engine) { this.flowrConfig.defaultEngine = engine; return this; } /** * Additional parameters for the analyses. * @param input - The input. */ setInput(input) { this.input = input; return this; } /** * Register one or multiple additional plugins. * For the default plugin set, please refer to {@link FlowrAnalyzerPluginDefaults}, they can be registered * by passing `true` to the {@link FlowrAnalyzerBuilder} constructor. * @param plugin - One or multiple plugins to register. * @see {@link FlowrAnalyzerBuilder#unregisterPlugins} to remove plugins. */ registerPlugins(...plugin) { for (const p of plugin) { const s = (0, plugin_registry_1.makePlugin)(p); const g = this.plugins.get(s.type) ?? []; g.push(s); this.plugins.set(s.type, g); } return this; } /** * Remove one or multiple plugins. * @see {@link FlowrAnalyzerBuilder#registerPlugins} to add plugins. */ unregisterPlugins(...plugin) { for (const p of plugin) { const name = typeof p === 'string' ? p : p.name; for (const [type, plugins] of this.plugins) { this.plugins.set(type, plugins.filter((pl) => pl.name !== name)); } } return this; } /** * Create the {@link FlowrAnalyzer} instance using the given information. * Please note that the only reason this is `async` is that if no parser is set, * we need to retrieve the default engine instance which is an async operation. * If you have already initialized the engine (e.g., with {@link TreeSitterExecutor#initTreeSitter}), * you can use the synchronous version {@link FlowrAnalyzerBuilder#buildSync} instead. */ async build() { if (!this.parser) { const engines = await (0, engines_1.retrieveEngineInstances)(this.flowrConfig, true); this.parser = engines.engines[engines.default]; } return this.buildSync(); } /** * Synchronous version of {@link FlowrAnalyzerBuilder#build}, please only use this if you have set the parser using * {@link FlowrAnalyzerBuilder#setParser} before, otherwise an error will be thrown. */ buildSync() { (0, assert_1.guard)(this.parser !== undefined, 'No parser set, please use the setParser or setEngine method to set a parser before building the analyzer'); const context = new flowr_analyzer_context_1.FlowrAnalyzerContext(this.flowrConfig, this.plugins); const cache = flowr_analyzer_cache_1.FlowrAnalyzerCache.create({ parser: this.parser, context, ...(this.input ?? {}) }); const analyzer = new flowr_analyzer_1.FlowrAnalyzer(this.parser, context, cache); // we do it here to save time later if the analyzer is to be duplicated context.resolvePreAnalysis(); return analyzer; } } exports.FlowrAnalyzerBuilder = FlowrAnalyzerBuilder; //# sourceMappingURL=flowr-analyzer-builder.js.map