@eagleoutice/flowr 2.9.12 → 2.9.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -27
- package/benchmark/slicer.d.ts +4 -2
- package/benchmark/slicer.js +20 -6
- package/benchmark/stats/print.js +12 -0
- package/benchmark/stats/stats.d.ts +3 -2
- package/benchmark/stats/stats.js +1 -1
- package/benchmark/summarizer/data.d.ts +1 -0
- package/benchmark/summarizer/second-phase/process.js +5 -0
- package/cli/benchmark-app.d.ts +1 -0
- package/cli/benchmark-app.js +1 -0
- package/cli/benchmark-helper-app.d.ts +2 -1
- package/cli/benchmark-helper-app.js +6 -3
- package/cli/common/options.d.ts +8 -0
- package/cli/common/options.js +3 -1
- package/cli/common/scripts-info.d.ts +8 -0
- package/cli/export-quads-app.js +1 -1
- package/cli/flowr.js +3 -3
- package/cli/repl/core.d.ts +3 -3
- package/cli/repl/server/connection.d.ts +2 -2
- package/cli/repl/server/server.d.ts +2 -2
- package/cli/script-core/statistics-core.d.ts +2 -2
- package/cli/script-core/statistics-helper-core.d.ts +2 -2
- package/cli/script-core/statistics-helper-core.js +1 -1
- package/cli/slicer-app.js +2 -2
- package/cli/statistics-app.js +1 -1
- package/cli/statistics-helper-app.js +1 -1
- package/cli/wiki.js +2 -2
- package/config.d.ts +65 -24
- package/config.js +197 -161
- package/control-flow/extract-cfg.js +5 -8
- package/core/steps/pipeline-step.d.ts +2 -2
- package/dataflow/eval/resolve/alias-tracking.js +12 -15
- package/dataflow/graph/graph.js +8 -8
- package/dataflow/internal/process/functions/call/built-in/built-in-eval.js +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-source.d.ts +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-source.js +20 -9
- package/documentation/doc-readme.js +2 -2
- package/documentation/wiki-analyzer.js +7 -5
- package/documentation/wiki-core.js +1 -3
- package/documentation/wiki-dataflow-graph.js +1 -1
- package/documentation/wiki-interface.js +5 -3
- package/documentation/wiki-linter.js +5 -5
- package/documentation/wiki-mk/doc-context.js +3 -4
- package/engines.d.ts +2 -2
- package/engines.js +4 -4
- package/linter/rules/dataframe-access-validation.js +5 -5
- package/linter/rules/naming-convention.d.ts +1 -1
- package/linter/rules/naming-convention.js +7 -3
- package/package.json +3 -1
- package/project/context/flowr-analyzer-context.d.ts +6 -6
- package/project/context/flowr-analyzer-context.js +2 -2
- package/project/context/flowr-analyzer-files-context.d.ts +2 -2
- package/project/context/flowr-analyzer-files-context.js +28 -8
- package/project/flowr-analyzer-builder.d.ts +10 -6
- package/project/flowr-analyzer-builder.js +12 -3
- package/project/flowr-analyzer.d.ts +3 -3
- package/queries/catalog/config-query/config-query-format.d.ts +5 -5
- package/queries/catalog/df-shape-query/df-shape-query-format.d.ts +2 -2
- package/queries/catalog/does-call-query/does-call-query-format.d.ts +2 -2
- package/queries/catalog/files-query/files-query-format.d.ts +3 -3
- package/queries/catalog/inspect-exceptions-query/inspect-exception-query-format.d.ts +2 -2
- package/queries/catalog/inspect-higher-order-query/inspect-higher-order-query-format.d.ts +2 -2
- package/queries/catalog/inspect-recursion-query/inspect-recursion-query-format.d.ts +2 -2
- package/queries/catalog/linter-query/linter-query-format.d.ts +3 -3
- package/queries/catalog/location-map-query/location-map-query-format.d.ts +2 -2
- package/queries/catalog/origin-query/origin-query-format.d.ts +2 -2
- package/queries/catalog/resolve-value-query/resolve-value-query-executor.js +3 -3
- package/queries/catalog/resolve-value-query/resolve-value-query-format.d.ts +2 -2
- package/queries/catalog/resolve-value-query/resolve-value-query-format.js +4 -0
- package/queries/catalog/static-slice-query/static-slice-query-format.d.ts +2 -2
- package/queries/query.d.ts +18 -18
- package/r-bridge/lang-4.x/ast/model/model.d.ts +7 -2
- package/r-bridge/lang-4.x/ast/model/model.js +13 -0
- package/r-bridge/lang-4.x/ast/parser/json/parser.d.ts +2 -2
- package/r-bridge/lang-4.x/ast/parser/json/parser.js +2 -2
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.js +6 -2
- package/statistics/statistics.d.ts +2 -2
- package/util/objects.d.ts +12 -0
- package/util/objects.js +28 -0
- package/util/summarizer.js +1 -1
- package/util/version.js +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { StatsCliOptions } from '../statistics-app';
|
|
2
|
-
import type {
|
|
2
|
+
import type { FlowrConfig } from '../../config';
|
|
3
3
|
/**
|
|
4
4
|
* The core function for the 'flowr stats' script.
|
|
5
5
|
*/
|
|
6
|
-
export declare function flowrScriptGetStats(options: StatsCliOptions, config:
|
|
6
|
+
export declare function flowrScriptGetStats(options: StatsCliOptions, config: FlowrConfig): Promise<void>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { StatsHelperCliOptions } from '../statistics-helper-app';
|
|
2
|
-
import {
|
|
2
|
+
import { FlowrConfig } from '../../config';
|
|
3
3
|
/**
|
|
4
4
|
* Get statistics for a single file
|
|
5
5
|
*/
|
|
6
|
-
export declare function getStatsForSingleFile(options: StatsHelperCliOptions, config:
|
|
6
|
+
export declare function getStatsForSingleFile(options: StatsHelperCliOptions, config: FlowrConfig): Promise<void>;
|
|
@@ -55,7 +55,7 @@ async function getStatsForSingleFile(options, config) {
|
|
|
55
55
|
}
|
|
56
56
|
// assume correct
|
|
57
57
|
const processedFeatures = new Set(options.features);
|
|
58
|
-
const shell = new shell_1.RShell(
|
|
58
|
+
const shell = new shell_1.RShell(config_1.FlowrConfig.getForEngine(config, 'r-shell'));
|
|
59
59
|
(0, statistics_file_1.initFileProvider)(options['output-dir']);
|
|
60
60
|
await shell.obtainTmpDir();
|
|
61
61
|
const stats = await (0, statistics_1.extractUsageStatistics)(shell, config, () => { }, processedFeatures, (0, statistics_1.staticRequests)({ request: 'file', content: options.input }), options['root-dir']);
|
package/cli/slicer-app.js
CHANGED
|
@@ -29,7 +29,7 @@ async function getSlice() {
|
|
|
29
29
|
const slicer = new slicer_1.BenchmarkSlicer('r-shell');
|
|
30
30
|
(0, assert_1.guard)(options.input !== undefined, 'input must be given');
|
|
31
31
|
(0, assert_1.guard)(options.criterion !== undefined, 'a slicing criterion must be given');
|
|
32
|
-
const config =
|
|
32
|
+
const config = config_1.FlowrConfig.fromFile();
|
|
33
33
|
await slicer.init(options['input-is-text']
|
|
34
34
|
? { request: 'text', content: options.input.replaceAll('\\n', '\n') }
|
|
35
35
|
: { request: 'file', content: options.input }, config, options['no-magic-comments'] ? auto_select_defaults_1.doNotAutoSelect : (0, magic_comments_1.makeMagicCommentHandler)(auto_select_defaults_1.doNotAutoSelect));
|
|
@@ -60,7 +60,7 @@ async function getSlice() {
|
|
|
60
60
|
const { stats, normalize, parse, tokenMap, dataflow } = slicer.finish();
|
|
61
61
|
const mappedCriteria = mappedSlices.map(c => ` ${c.criterion} => ${c.id} (${JSON.stringify(normalize.idMap.get(c.id)?.location)})`).join('\n');
|
|
62
62
|
log_1.log.info(`Mapped criteria:\n${mappedCriteria}`);
|
|
63
|
-
const sliceStatsAsString = (0, print_1.stats2string)(await (0, process_1.summarizeSlicerStats)(stats, undefined,
|
|
63
|
+
const sliceStatsAsString = (0, print_1.stats2string)(await (0, process_1.summarizeSlicerStats)(stats, undefined, config_1.FlowrConfig.getForEngine(config, 'r-shell')));
|
|
64
64
|
if (options.api) {
|
|
65
65
|
const output = {
|
|
66
66
|
tokenMap,
|
package/cli/statistics-app.js
CHANGED
|
@@ -12,5 +12,5 @@ const scriptOptions = (0, script_1.processCommandLineArgs)('stats', [], {
|
|
|
12
12
|
'{bold --help}'
|
|
13
13
|
]
|
|
14
14
|
});
|
|
15
|
-
void (0, statistics_core_1.flowrScriptGetStats)(scriptOptions,
|
|
15
|
+
void (0, statistics_core_1.flowrScriptGetStats)(scriptOptions, config_1.FlowrConfig.fromFile());
|
|
16
16
|
//# sourceMappingURL=statistics-app.js.map
|
|
@@ -10,5 +10,5 @@ const scriptOptions = (0, script_1.processCommandLineArgs)('stats-helper', [], {
|
|
|
10
10
|
'{bold --help}'
|
|
11
11
|
]
|
|
12
12
|
});
|
|
13
|
-
void (0, statistics_helper_core_1.getStatsForSingleFile)(scriptOptions,
|
|
13
|
+
void (0, statistics_helper_core_1.getStatsForSingleFile)(scriptOptions, config_1.FlowrConfig.fromFile());
|
|
14
14
|
//# sourceMappingURL=statistics-helper-app.js.map
|
package/cli/wiki.js
CHANGED
|
@@ -86,7 +86,7 @@ async function makeAllWikis(force, filter) {
|
|
|
86
86
|
},
|
|
87
87
|
writeFileSync: fs_1.default.writeFileSync
|
|
88
88
|
};
|
|
89
|
-
console.log(`Setup for wiki generation took ${(
|
|
89
|
+
console.log(`Setup for wiki generation took ${(Date.now() - setupStart.getTime())}ms`);
|
|
90
90
|
const changedWikis = new Set();
|
|
91
91
|
try {
|
|
92
92
|
const sortedDocs = sortByLeastRecentChanged(exports.AllWikiDocuments);
|
|
@@ -105,7 +105,7 @@ async function makeAllWikis(force, filter) {
|
|
|
105
105
|
changedWikis.add(doc.getTarget());
|
|
106
106
|
}
|
|
107
107
|
const color = changed ? 2 /* Colors.Green */ : 7 /* Colors.White */;
|
|
108
|
-
console.log(ansi_1.ansiFormatter.format(` [${doc.getTarget()}] ${text}: ${doc.getTarget()} (took ${
|
|
108
|
+
console.log(ansi_1.ansiFormatter.format(` [${doc.getTarget()}] ${text}: ${doc.getTarget()} (took ${Date.now() - now.getTime()}ms)`, { color, effect: ansi_1.ColorEffect.Foreground }));
|
|
109
109
|
for (const out of doc.getWrittenSubfiles()) {
|
|
110
110
|
changedWikis.add(out);
|
|
111
111
|
console.log(` - Also updated: ${out}`);
|
package/config.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { type MergeableRecord } from './util/objects';
|
|
|
2
2
|
import Joi from 'joi';
|
|
3
3
|
import type { BuiltInDefinitions } from './dataflow/environments/built-in-config';
|
|
4
4
|
import type { KnownParser } from './r-bridge/parser';
|
|
5
|
-
import type { DeepWritable } from 'ts-essentials';
|
|
5
|
+
import type { DeepWritable, Paths, PathValue } from 'ts-essentials';
|
|
6
6
|
import type { DataflowProcessors } from './dataflow/processor';
|
|
7
7
|
import type { ParentInformation } from './r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
8
8
|
import type { FlowrAnalyzerContext } from './project/context/flowr-analyzer-context';
|
|
@@ -83,7 +83,12 @@ export interface FlowrLaxSourcingOptions extends MergeableRecord {
|
|
|
83
83
|
*/
|
|
84
84
|
readonly applyReplacements?: Record<string, string>[];
|
|
85
85
|
}
|
|
86
|
-
|
|
86
|
+
/**
|
|
87
|
+
* The configuration file format for flowR.
|
|
88
|
+
* @see {@link FlowrConfig.default} for the default configuration.
|
|
89
|
+
* @see {@link FlowrConfig.Schema} for the Joi schema for validation.
|
|
90
|
+
*/
|
|
91
|
+
export interface FlowrConfig extends MergeableRecord {
|
|
87
92
|
/**
|
|
88
93
|
* Whether source calls should be ignored, causing {@link processSourceCall}'s behavior to be skipped
|
|
89
94
|
*/
|
|
@@ -188,6 +193,9 @@ export interface FlowrConfigOptions extends MergeableRecord {
|
|
|
188
193
|
};
|
|
189
194
|
};
|
|
190
195
|
}
|
|
196
|
+
export type ValidFlowrConfigPaths = Paths<FlowrConfig, {
|
|
197
|
+
depth: 9;
|
|
198
|
+
}>;
|
|
191
199
|
export interface TreeSitterEngineConfig extends MergeableRecord {
|
|
192
200
|
readonly type: 'tree-sitter';
|
|
193
201
|
/**
|
|
@@ -214,27 +222,60 @@ export type EngineConfig = TreeSitterEngineConfig | RShellEngineConfig;
|
|
|
214
222
|
export type KnownEngines = {
|
|
215
223
|
[T in EngineConfig['type']]?: KnownParser;
|
|
216
224
|
};
|
|
217
|
-
export declare const defaultConfigOptions: FlowrConfigOptions;
|
|
218
|
-
export declare const flowrConfigFileSchema: Joi.ObjectSchema<any>;
|
|
219
|
-
/**
|
|
220
|
-
* Parses the given JSON string as a flowR config file.
|
|
221
|
-
*/
|
|
222
|
-
export declare function parseConfig(jsonString: string): FlowrConfigOptions | undefined;
|
|
223
|
-
/**
|
|
224
|
-
* Creates a new flowr config that has the updated values.
|
|
225
|
-
*/
|
|
226
|
-
export declare function amendConfig(config: FlowrConfigOptions, amendmentFunc: (config: DeepWritable<FlowrConfigOptions>) => FlowrConfigOptions | void): FlowrConfigOptions;
|
|
227
|
-
/**
|
|
228
|
-
* Clones the given flowr config object.
|
|
229
|
-
*/
|
|
230
|
-
export declare function cloneConfig(config: FlowrConfigOptions): FlowrConfigOptions;
|
|
231
225
|
/**
|
|
232
|
-
*
|
|
226
|
+
* Helper Object to work with {@link FlowrConfig}, provides the default config and the Joi schema for validation.
|
|
233
227
|
*/
|
|
234
|
-
export declare
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
228
|
+
export declare const FlowrConfig: {
|
|
229
|
+
readonly name: "FlowrConfig";
|
|
230
|
+
/**
|
|
231
|
+
* The default configuration for flowR, used when no config file is found or when a config file is missing some options.
|
|
232
|
+
* You can use this as a base for your own config and only specify the options you want to change.
|
|
233
|
+
*/
|
|
234
|
+
readonly default: () => FlowrConfig;
|
|
235
|
+
/**
|
|
236
|
+
* The Joi schema for validating a config file, use this to validate your config file before using it. You can also use this to generate documentation for the config file format.
|
|
237
|
+
*/
|
|
238
|
+
readonly Schema: Joi.ObjectSchema<any>;
|
|
239
|
+
/**
|
|
240
|
+
* Parses the given JSON string as a flowR config file, returning the resulting config object if the parsing and validation were successful, or `undefined` if there was an error.
|
|
241
|
+
*/
|
|
242
|
+
readonly parse: (jsonString: string) => FlowrConfig | undefined;
|
|
243
|
+
/**
|
|
244
|
+
* Creates a new flowr config that has the updated values.
|
|
245
|
+
*/
|
|
246
|
+
readonly amend: (config: FlowrConfig, amendmentFunc: (config: DeepWritable<FlowrConfig>) => FlowrConfig | void) => FlowrConfig;
|
|
247
|
+
/**
|
|
248
|
+
* Clones the given flowr config object.
|
|
249
|
+
*/
|
|
250
|
+
readonly clone: (config: FlowrConfig) => FlowrConfig;
|
|
251
|
+
/**
|
|
252
|
+
* Loads the flowr config from the given file or the default locations.
|
|
253
|
+
* Please note that you can also use this without a path parameter to
|
|
254
|
+
* infer the config from flowR's default locations.
|
|
255
|
+
* This is mostly useful for user-facing features.
|
|
256
|
+
*/
|
|
257
|
+
readonly fromFile: (configFile?: string, configWorkingDirectory?: string) => FlowrConfig;
|
|
258
|
+
/**
|
|
259
|
+
* Gets the configuration for the given engine type from the config.
|
|
260
|
+
*/
|
|
261
|
+
readonly getForEngine: <T extends EngineConfig["type"]>(config: FlowrConfig, engine: T) => (EngineConfig & {
|
|
262
|
+
type: T;
|
|
263
|
+
}) | undefined;
|
|
264
|
+
/**
|
|
265
|
+
* Returns a new config object with the given value set at the given key, where the key is a dot-separated path to the value in the config object.
|
|
266
|
+
* @see {@link setInConfigInPlace} for a version that modifies the config object in place instead of returning a new one.
|
|
267
|
+
* @example
|
|
268
|
+
* ```ts
|
|
269
|
+
* const config = FlowrConfig.default();
|
|
270
|
+
* const newConfig = FlowrConfig.setInConfig(config, 'solver.variables', VariableResolve.Builtin);
|
|
271
|
+
* console.log(config.solver.variables); // Output: "alias"
|
|
272
|
+
* console.log(newConfig.solver.variables); // Output: "builtin"
|
|
273
|
+
* ```
|
|
274
|
+
*/
|
|
275
|
+
readonly setInConfig: <Path extends ValidFlowrConfigPaths>(config: FlowrConfig, key: Path, value: PathValue<FlowrConfig, Path>) => FlowrConfig;
|
|
276
|
+
/**
|
|
277
|
+
* Modifies the given config object in place by setting the given value at the given key, where the key is a dot-separated path to the value in the config object.
|
|
278
|
+
* @see {@link setInConfig} for a version that returns a new config object instead of modifying the given one in place.
|
|
279
|
+
*/
|
|
280
|
+
readonly setInConfigInPlace: <Path extends ValidFlowrConfigPaths>(config: FlowrConfig, key: Path, value: PathValue<FlowrConfig, Path>) => void;
|
|
281
|
+
};
|
package/config.js
CHANGED
|
@@ -3,18 +3,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
7
|
-
exports.parseConfig = parseConfig;
|
|
8
|
-
exports.amendConfig = amendConfig;
|
|
9
|
-
exports.cloneConfig = cloneConfig;
|
|
10
|
-
exports.getConfig = getConfig;
|
|
11
|
-
exports.getEngineConfig = getEngineConfig;
|
|
6
|
+
exports.FlowrConfig = exports.DropPathsOption = exports.InferWorkingDirectory = exports.VariableResolve = void 0;
|
|
12
7
|
const objects_1 = require("./util/objects");
|
|
13
8
|
const path_1 = __importDefault(require("path"));
|
|
14
9
|
const fs_1 = __importDefault(require("fs"));
|
|
15
10
|
const log_1 = require("./util/log");
|
|
16
11
|
const files_1 = require("./util/files");
|
|
17
12
|
const joi_1 = __importDefault(require("joi"));
|
|
13
|
+
const object_path_1 = __importDefault(require("object-path"));
|
|
18
14
|
var VariableResolve;
|
|
19
15
|
(function (VariableResolve) {
|
|
20
16
|
/** Don't resolve constants at all */
|
|
@@ -54,173 +50,213 @@ const defaultEngineConfigs = {
|
|
|
54
50
|
'tree-sitter': { type: 'tree-sitter' },
|
|
55
51
|
'r-shell': { type: 'r-shell' }
|
|
56
52
|
};
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Helper Object to work with {@link FlowrConfig}, provides the default config and the Joi schema for validation.
|
|
55
|
+
*/
|
|
56
|
+
exports.FlowrConfig = {
|
|
57
|
+
name: 'FlowrConfig',
|
|
58
|
+
/**
|
|
59
|
+
* The default configuration for flowR, used when no config file is found or when a config file is missing some options.
|
|
60
|
+
* You can use this as a base for your own config and only specify the options you want to change.
|
|
61
|
+
*/
|
|
62
|
+
default() {
|
|
63
|
+
return {
|
|
64
|
+
ignoreSourceCalls: false,
|
|
65
|
+
semantics: {
|
|
66
|
+
environment: {
|
|
67
|
+
overwriteBuiltIns: {
|
|
68
|
+
loadDefaults: true,
|
|
69
|
+
definitions: []
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
repl: {
|
|
74
|
+
quickStats: false,
|
|
75
|
+
dfProcessorHeat: false
|
|
76
|
+
},
|
|
77
|
+
project: {
|
|
78
|
+
resolveUnknownPathsOnDisk: true
|
|
79
|
+
},
|
|
80
|
+
engines: [],
|
|
81
|
+
defaultEngine: 'tree-sitter',
|
|
82
|
+
solver: {
|
|
83
|
+
variables: VariableResolve.Alias,
|
|
84
|
+
evalStrings: true,
|
|
85
|
+
resolveSource: {
|
|
86
|
+
dropPaths: DropPathsOption.No,
|
|
87
|
+
ignoreCapitalization: true,
|
|
88
|
+
inferWorkingDirectory: InferWorkingDirectory.ActiveScript,
|
|
89
|
+
searchPath: [],
|
|
90
|
+
repeatedSourceLimit: 2
|
|
91
|
+
},
|
|
92
|
+
instrument: {
|
|
93
|
+
dataflowExtractors: undefined
|
|
94
|
+
},
|
|
95
|
+
slicer: {
|
|
96
|
+
threshold: 50
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
abstractInterpretation: {
|
|
100
|
+
wideningThreshold: 4,
|
|
101
|
+
dataFrame: {
|
|
102
|
+
maxColNames: 50,
|
|
103
|
+
readLoadedData: {
|
|
104
|
+
readExternalFiles: true,
|
|
105
|
+
maxReadLines: 1e6
|
|
106
|
+
}
|
|
107
|
+
}
|
|
64
108
|
}
|
|
109
|
+
};
|
|
110
|
+
},
|
|
111
|
+
/**
|
|
112
|
+
* The Joi schema for validating a config file, use this to validate your config file before using it. You can also use this to generate documentation for the config file format.
|
|
113
|
+
*/
|
|
114
|
+
Schema: joi_1.default.object({
|
|
115
|
+
ignoreSourceCalls: joi_1.default.boolean().optional().description('Whether source calls should be ignored, causing {@link processSourceCall}\'s behavior to be skipped.'),
|
|
116
|
+
semantics: joi_1.default.object({
|
|
117
|
+
environment: joi_1.default.object({
|
|
118
|
+
overwriteBuiltIns: joi_1.default.object({
|
|
119
|
+
loadDefaults: joi_1.default.boolean().optional().description('Should the default configuration still be loaded?'),
|
|
120
|
+
definitions: joi_1.default.array().items(joi_1.default.object()).optional().description('The definitions to load/overwrite.')
|
|
121
|
+
}).optional().description('Do you want to overwrite (parts) of the builtin definition?')
|
|
122
|
+
}).optional().description('Semantics regarding how to handle the R environment.')
|
|
123
|
+
}).description('Configure language semantics and how flowR handles them.'),
|
|
124
|
+
repl: joi_1.default.object({
|
|
125
|
+
quickStats: joi_1.default.boolean().optional().description('Whether to show quick stats in the REPL after each evaluation.'),
|
|
126
|
+
dfProcessorHeat: joi_1.default.boolean().optional().description('This instruments the dataflow processors to count how often each processor is called.')
|
|
127
|
+
}).description('Configuration options for the REPL.'),
|
|
128
|
+
project: joi_1.default.object({
|
|
129
|
+
resolveUnknownPathsOnDisk: joi_1.default.boolean().optional().description('Whether to resolve unknown paths loaded by the r project disk when trying to source/analyze files.')
|
|
130
|
+
}).description('Project specific configuration options.'),
|
|
131
|
+
engines: joi_1.default.array().items(joi_1.default.alternatives(joi_1.default.object({
|
|
132
|
+
type: joi_1.default.string().required().valid('tree-sitter').description('Use the tree sitter engine.'),
|
|
133
|
+
wasmPath: joi_1.default.string().optional().description('The path to the tree-sitter-r WASM binary to use. If this is undefined, this uses the default path.'),
|
|
134
|
+
treeSitterWasmPath: joi_1.default.string().optional().description('The path to the tree-sitter WASM binary to use. If this is undefined, this uses the default path.'),
|
|
135
|
+
lax: joi_1.default.boolean().optional().description('Whether to use the lax parser for parsing R code (allowing for syntax errors). If this is undefined, the strict parser will be used.')
|
|
136
|
+
}).description('The configuration for the tree sitter engine.'), joi_1.default.object({
|
|
137
|
+
type: joi_1.default.string().required().valid('r-shell').description('Use the R shell engine.'),
|
|
138
|
+
rPath: joi_1.default.string().optional().description('The path to the R executable to use. If this is undefined, this uses the default path.')
|
|
139
|
+
}).description('The configuration for the R shell engine.'))).description('The engine or set of engines to use for interacting with R code. An empty array means all available engines will be used.'),
|
|
140
|
+
defaultEngine: joi_1.default.string().optional().valid('tree-sitter', 'r-shell').description('The default engine to use for interacting with R code. If this is undefined, an arbitrary engine from the specified list will be used.'),
|
|
141
|
+
solver: joi_1.default.object({
|
|
142
|
+
variables: joi_1.default.string().valid(...Object.values(VariableResolve)).description('How to resolve variables and their values.'),
|
|
143
|
+
evalStrings: joi_1.default.boolean().description('Should we include eval(parse(text="...")) calls in the dataflow graph?'),
|
|
144
|
+
instrument: joi_1.default.object({
|
|
145
|
+
dataflowExtractors: joi_1.default.any().optional().description('These keys are only intended for use within code, allowing to instrument the dataflow analyzer!')
|
|
146
|
+
}),
|
|
147
|
+
resolveSource: joi_1.default.object({
|
|
148
|
+
dropPaths: joi_1.default.string().valid(...Object.values(DropPathsOption)).description('Allow to drop the first or all parts of the sourced path, if it is relative.'),
|
|
149
|
+
ignoreCapitalization: joi_1.default.boolean().description('Search for filenames matching in the lowercase.'),
|
|
150
|
+
inferWorkingDirectory: joi_1.default.string().valid(...Object.values(InferWorkingDirectory)).description('Try to infer the working directory from the main or any script to analyze.'),
|
|
151
|
+
searchPath: joi_1.default.array().items(joi_1.default.string()).description('Additionally search in these paths.'),
|
|
152
|
+
repeatedSourceLimit: joi_1.default.number().optional().description('How often the same file can be sourced within a single run? Please be aware: in case of cyclic sources this may not reach a fixpoint so give this a sensible limit.'),
|
|
153
|
+
applyReplacements: joi_1.default.array().items(joi_1.default.object()).description('Provide name replacements for loaded files')
|
|
154
|
+
}).optional().description('If lax source calls are active, flowR searches for sourced files much more freely, based on the configurations you give it. This option is only in effect if `ignoreSourceCalls` is set to false.'),
|
|
155
|
+
slicer: joi_1.default.object({
|
|
156
|
+
threshold: joi_1.default.number().optional().description('The maximum number of iterations to perform on a single function call during slicing.')
|
|
157
|
+
}).optional().description('The configuration for the slicer.')
|
|
158
|
+
}).description('How to resolve constants, constraints, cells, ...'),
|
|
159
|
+
abstractInterpretation: joi_1.default.object({
|
|
160
|
+
wideningThreshold: joi_1.default.number().min(1).description('The threshold for the number of visitations of a node at which widening should be performed to ensure the termination of the fixpoint iteration.'),
|
|
161
|
+
dataFrame: joi_1.default.object({
|
|
162
|
+
maxColNames: joi_1.default.number().min(0).description('The maximum number of columns names to infer for data frames before over-approximating the column names to top.'),
|
|
163
|
+
readLoadedData: joi_1.default.object({
|
|
164
|
+
readExternalFiles: joi_1.default.boolean().description('Whether data frame shapes should be extracted from loaded external files, such as CSV files.'),
|
|
165
|
+
maxReadLines: joi_1.default.number().min(1).description('The maximum number of lines to read when extracting data frame shapes from loaded files, such as CSV files.')
|
|
166
|
+
}).description('Configuration options for reading data frame shapes from loaded external data files, such as CSV files.')
|
|
167
|
+
}).description('The configuration of the shape inference for data frames.')
|
|
168
|
+
}).description('The configuration options for abstract interpretation.')
|
|
169
|
+
}).description('The configuration file format for flowR.'),
|
|
170
|
+
/**
|
|
171
|
+
* Parses the given JSON string as a flowR config file, returning the resulting config object if the parsing and validation were successful, or `undefined` if there was an error.
|
|
172
|
+
*/
|
|
173
|
+
parse(jsonString) {
|
|
174
|
+
try {
|
|
175
|
+
const parsed = JSON.parse(jsonString);
|
|
176
|
+
const validate = exports.FlowrConfig.Schema.validate(parsed);
|
|
177
|
+
if (!validate.error) {
|
|
178
|
+
// assign default values to all config options except for the specified ones
|
|
179
|
+
return (0, objects_1.deepMergeObject)(exports.FlowrConfig.default(), parsed);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
log_1.log.error(`Failed to validate config ${jsonString}: ${validate.error.message}`);
|
|
183
|
+
return undefined;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
catch (e) {
|
|
187
|
+
log_1.log.error(`Failed to parse config ${jsonString}: ${e.message}`);
|
|
65
188
|
}
|
|
66
189
|
},
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
190
|
+
/**
|
|
191
|
+
* Creates a new flowr config that has the updated values.
|
|
192
|
+
*/
|
|
193
|
+
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type
|
|
194
|
+
amend(config, amendmentFunc) {
|
|
195
|
+
const newConfig = exports.FlowrConfig.clone(config);
|
|
196
|
+
return amendmentFunc(newConfig) ?? newConfig;
|
|
70
197
|
},
|
|
71
|
-
|
|
72
|
-
|
|
198
|
+
/**
|
|
199
|
+
* Clones the given flowr config object.
|
|
200
|
+
*/
|
|
201
|
+
clone(config) {
|
|
202
|
+
return (0, objects_1.deepClonePreserveUnclonable)(config);
|
|
73
203
|
},
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
searchPath: [],
|
|
84
|
-
repeatedSourceLimit: 2
|
|
85
|
-
},
|
|
86
|
-
instrument: {
|
|
87
|
-
dataflowExtractors: undefined
|
|
88
|
-
},
|
|
89
|
-
slicer: {
|
|
90
|
-
threshold: 50
|
|
204
|
+
/**
|
|
205
|
+
* Loads the flowr config from the given file or the default locations.
|
|
206
|
+
* Please note that you can also use this without a path parameter to
|
|
207
|
+
* infer the config from flowR's default locations.
|
|
208
|
+
* This is mostly useful for user-facing features.
|
|
209
|
+
*/
|
|
210
|
+
fromFile(configFile, configWorkingDirectory = process.cwd()) {
|
|
211
|
+
try {
|
|
212
|
+
return loadConfigFromFile(configFile, configWorkingDirectory);
|
|
91
213
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
dataFrame: {
|
|
96
|
-
maxColNames: 50,
|
|
97
|
-
readLoadedData: {
|
|
98
|
-
readExternalFiles: true,
|
|
99
|
-
maxReadLines: 1e6
|
|
100
|
-
}
|
|
214
|
+
catch (e) {
|
|
215
|
+
log_1.log.error(`Failed to load config: ${e.message}`);
|
|
216
|
+
return exports.FlowrConfig.default();
|
|
101
217
|
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
definitions: joi_1.default.array().items(joi_1.default.object()).optional().description('The definitions to load/overwrite.')
|
|
111
|
-
}).optional().description('Do you want to overwrite (parts) of the builtin definition?')
|
|
112
|
-
}).optional().description('Semantics regarding how to handle the R environment.')
|
|
113
|
-
}).description('Configure language semantics and how flowR handles them.'),
|
|
114
|
-
repl: joi_1.default.object({
|
|
115
|
-
quickStats: joi_1.default.boolean().optional().description('Whether to show quick stats in the REPL after each evaluation.'),
|
|
116
|
-
dfProcessorHeat: joi_1.default.boolean().optional().description('This instruments the dataflow processors to count how often each processor is called.')
|
|
117
|
-
}).description('Configuration options for the REPL.'),
|
|
118
|
-
project: joi_1.default.object({
|
|
119
|
-
resolveUnknownPathsOnDisk: joi_1.default.boolean().optional().description('Whether to resolve unknown paths loaded by the r project disk when trying to source/analyze files.')
|
|
120
|
-
}).description('Project specific configuration options.'),
|
|
121
|
-
engines: joi_1.default.array().items(joi_1.default.alternatives(joi_1.default.object({
|
|
122
|
-
type: joi_1.default.string().required().valid('tree-sitter').description('Use the tree sitter engine.'),
|
|
123
|
-
wasmPath: joi_1.default.string().optional().description('The path to the tree-sitter-r WASM binary to use. If this is undefined, this uses the default path.'),
|
|
124
|
-
treeSitterWasmPath: joi_1.default.string().optional().description('The path to the tree-sitter WASM binary to use. If this is undefined, this uses the default path.'),
|
|
125
|
-
lax: joi_1.default.boolean().optional().description('Whether to use the lax parser for parsing R code (allowing for syntax errors). If this is undefined, the strict parser will be used.')
|
|
126
|
-
}).description('The configuration for the tree sitter engine.'), joi_1.default.object({
|
|
127
|
-
type: joi_1.default.string().required().valid('r-shell').description('Use the R shell engine.'),
|
|
128
|
-
rPath: joi_1.default.string().optional().description('The path to the R executable to use. If this is undefined, this uses the default path.')
|
|
129
|
-
}).description('The configuration for the R shell engine.'))).min(1).description('The engine or set of engines to use for interacting with R code. An empty array means all available engines will be used.'),
|
|
130
|
-
defaultEngine: joi_1.default.string().optional().valid('tree-sitter', 'r-shell').description('The default engine to use for interacting with R code. If this is undefined, an arbitrary engine from the specified list will be used.'),
|
|
131
|
-
solver: joi_1.default.object({
|
|
132
|
-
variables: joi_1.default.string().valid(...Object.values(VariableResolve)).description('How to resolve variables and their values.'),
|
|
133
|
-
evalStrings: joi_1.default.boolean().description('Should we include eval(parse(text="...")) calls in the dataflow graph?'),
|
|
134
|
-
instrument: joi_1.default.object({
|
|
135
|
-
dataflowExtractors: joi_1.default.any().optional().description('These keys are only intended for use within code, allowing to instrument the dataflow analyzer!')
|
|
136
|
-
}),
|
|
137
|
-
resolveSource: joi_1.default.object({
|
|
138
|
-
dropPaths: joi_1.default.string().valid(...Object.values(DropPathsOption)).description('Allow to drop the first or all parts of the sourced path, if it is relative.'),
|
|
139
|
-
ignoreCapitalization: joi_1.default.boolean().description('Search for filenames matching in the lowercase.'),
|
|
140
|
-
inferWorkingDirectory: joi_1.default.string().valid(...Object.values(InferWorkingDirectory)).description('Try to infer the working directory from the main or any script to analyze.'),
|
|
141
|
-
searchPath: joi_1.default.array().items(joi_1.default.string()).description('Additionally search in these paths.'),
|
|
142
|
-
repeatedSourceLimit: joi_1.default.number().optional().description('How often the same file can be sourced within a single run? Please be aware: in case of cyclic sources this may not reach a fixpoint so give this a sensible limit.'),
|
|
143
|
-
applyReplacements: joi_1.default.array().items(joi_1.default.object()).description('Provide name replacements for loaded files')
|
|
144
|
-
}).optional().description('If lax source calls are active, flowR searches for sourced files much more freely, based on the configurations you give it. This option is only in effect if `ignoreSourceCalls` is set to false.'),
|
|
145
|
-
slicer: joi_1.default.object({
|
|
146
|
-
threshold: joi_1.default.number().optional().description('The maximum number of iterations to perform on a single function call during slicing.')
|
|
147
|
-
}).optional().description('The configuration for the slicer.')
|
|
148
|
-
}).description('How to resolve constants, constraints, cells, ...'),
|
|
149
|
-
abstractInterpretation: joi_1.default.object({
|
|
150
|
-
dataFrame: joi_1.default.object({
|
|
151
|
-
maxColNames: joi_1.default.number().min(0).description('The maximum number of columns names to infer for data frames before over-approximating the column names to top.'),
|
|
152
|
-
wideningThreshold: joi_1.default.number().min(1).description('The threshold for the number of visitations of a node at which widening should be performed to ensure the termination of the fixpoint iteration.'),
|
|
153
|
-
readLoadedData: joi_1.default.object({
|
|
154
|
-
readExternalFiles: joi_1.default.boolean().description('Whether data frame shapes should be extracted from loaded external files, such as CSV files.'),
|
|
155
|
-
maxReadLines: joi_1.default.number().min(1).description('The maximum number of lines to read when extracting data frame shapes from loaded files, such as CSV files.')
|
|
156
|
-
}).description('Configuration options for reading data frame shapes from loaded external data files, such as CSV files.')
|
|
157
|
-
}).description('The configuration of the shape inference for data frames.')
|
|
158
|
-
}).description('The configuration options for abstract interpretation.')
|
|
159
|
-
}).description('The configuration file format for flowR.');
|
|
160
|
-
/**
|
|
161
|
-
* Parses the given JSON string as a flowR config file.
|
|
162
|
-
*/
|
|
163
|
-
function parseConfig(jsonString) {
|
|
164
|
-
try {
|
|
165
|
-
const parsed = JSON.parse(jsonString);
|
|
166
|
-
const validate = exports.flowrConfigFileSchema.validate(parsed);
|
|
167
|
-
if (!validate.error) {
|
|
168
|
-
// assign default values to all config options except for the specified ones
|
|
169
|
-
return (0, objects_1.deepMergeObject)(exports.defaultConfigOptions, parsed);
|
|
218
|
+
},
|
|
219
|
+
/**
|
|
220
|
+
* Gets the configuration for the given engine type from the config.
|
|
221
|
+
*/
|
|
222
|
+
getForEngine(config, engine) {
|
|
223
|
+
const engines = config.engines;
|
|
224
|
+
if (engines.length > 0) {
|
|
225
|
+
return engines.find(e => e.type === engine);
|
|
170
226
|
}
|
|
171
227
|
else {
|
|
172
|
-
|
|
173
|
-
return undefined;
|
|
228
|
+
return defaultEngineConfigs[engine];
|
|
174
229
|
}
|
|
230
|
+
},
|
|
231
|
+
/**
|
|
232
|
+
* Returns a new config object with the given value set at the given key, where the key is a dot-separated path to the value in the config object.
|
|
233
|
+
* @see {@link setInConfigInPlace} for a version that modifies the config object in place instead of returning a new one.
|
|
234
|
+
* @example
|
|
235
|
+
* ```ts
|
|
236
|
+
* const config = FlowrConfig.default();
|
|
237
|
+
* const newConfig = FlowrConfig.setInConfig(config, 'solver.variables', VariableResolve.Builtin);
|
|
238
|
+
* console.log(config.solver.variables); // Output: "alias"
|
|
239
|
+
* console.log(newConfig.solver.variables); // Output: "builtin"
|
|
240
|
+
* ```
|
|
241
|
+
*/
|
|
242
|
+
setInConfig(config, key, value) {
|
|
243
|
+
const clone = exports.FlowrConfig.clone(config);
|
|
244
|
+
object_path_1.default.set(clone, key, value);
|
|
245
|
+
return clone;
|
|
246
|
+
},
|
|
247
|
+
/**
|
|
248
|
+
* Modifies the given config object in place by setting the given value at the given key, where the key is a dot-separated path to the value in the config object.
|
|
249
|
+
* @see {@link setInConfig} for a version that returns a new config object instead of modifying the given one in place.
|
|
250
|
+
*/
|
|
251
|
+
setInConfigInPlace(config, key, value) {
|
|
252
|
+
object_path_1.default.set(config, key, value);
|
|
175
253
|
}
|
|
176
|
-
|
|
177
|
-
log_1.log.error(`Failed to parse config ${jsonString}: ${e.message}`);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
/**
|
|
181
|
-
* Creates a new flowr config that has the updated values.
|
|
182
|
-
*/
|
|
183
|
-
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type
|
|
184
|
-
function amendConfig(config, amendmentFunc) {
|
|
185
|
-
const newConfig = cloneConfig(config);
|
|
186
|
-
amendmentFunc(newConfig);
|
|
187
|
-
return newConfig;
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* Clones the given flowr config object.
|
|
191
|
-
*/
|
|
192
|
-
function cloneConfig(config) {
|
|
193
|
-
return JSON.parse(JSON.stringify(config));
|
|
194
|
-
}
|
|
195
|
-
/**
|
|
196
|
-
* Loads the flowr config from the given file or the default locations.
|
|
197
|
-
*/
|
|
198
|
-
function getConfig(configFile, configWorkingDirectory = process.cwd()) {
|
|
199
|
-
try {
|
|
200
|
-
return loadConfigFromFile(configFile, configWorkingDirectory);
|
|
201
|
-
}
|
|
202
|
-
catch (e) {
|
|
203
|
-
log_1.log.error(`Failed to load config: ${e.message}`);
|
|
204
|
-
return exports.defaultConfigOptions;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
/**
|
|
208
|
-
* Gets the configuration for the given engine type from the config.
|
|
209
|
-
*/
|
|
210
|
-
function getEngineConfig(config, engine) {
|
|
211
|
-
const engines = config.engines;
|
|
212
|
-
if (!engines.length) {
|
|
213
|
-
return defaultEngineConfigs[engine];
|
|
214
|
-
}
|
|
215
|
-
else {
|
|
216
|
-
return engines.find(e => e.type === engine);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
254
|
+
};
|
|
219
255
|
function loadConfigFromFile(configFile, workingDirectory) {
|
|
220
256
|
if (configFile !== undefined) {
|
|
221
257
|
if (path_1.default.isAbsolute(configFile) && fs_1.default.existsSync(configFile)) {
|
|
222
258
|
log_1.log.trace(`Found config at ${configFile} (absolute)`);
|
|
223
|
-
const ret =
|
|
259
|
+
const ret = exports.FlowrConfig.parse(fs_1.default.readFileSync(configFile, { encoding: 'utf-8' }));
|
|
224
260
|
if (ret) {
|
|
225
261
|
log_1.log.info(`Using config ${JSON.stringify(ret)}`);
|
|
226
262
|
return ret;
|
|
@@ -231,7 +267,7 @@ function loadConfigFromFile(configFile, workingDirectory) {
|
|
|
231
267
|
const configPath = path_1.default.join(searchPath, configFile);
|
|
232
268
|
if (fs_1.default.existsSync(configPath)) {
|
|
233
269
|
log_1.log.trace(`Found config at ${configPath}`);
|
|
234
|
-
const ret =
|
|
270
|
+
const ret = exports.FlowrConfig.parse(fs_1.default.readFileSync(configPath, { encoding: 'utf-8' }));
|
|
235
271
|
if (ret) {
|
|
236
272
|
log_1.log.info(`Using config ${JSON.stringify(ret)}`);
|
|
237
273
|
return ret;
|
|
@@ -241,7 +277,7 @@ function loadConfigFromFile(configFile, workingDirectory) {
|
|
|
241
277
|
searchPath = (0, files_1.getParentDirectory)(searchPath);
|
|
242
278
|
} while (fs_1.default.existsSync(searchPath));
|
|
243
279
|
}
|
|
244
|
-
log_1.log.info(
|
|
245
|
-
return exports.
|
|
280
|
+
log_1.log.info('Using default config');
|
|
281
|
+
return exports.FlowrConfig.default();
|
|
246
282
|
}
|
|
247
283
|
//# sourceMappingURL=config.js.map
|
|
@@ -292,14 +292,11 @@ function cfgFor(forLoop, variable, vector, body) {
|
|
|
292
292
|
for (const breakPoint of body.breaks) {
|
|
293
293
|
graph.addEdge(control_flow_graph_1.CfgVertex.toExitId(forLoopId), breakPoint, control_flow_graph_1.CfgEdge.makeFd());
|
|
294
294
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
graph.
|
|
298
|
-
for (const e of variable.exitPoints) {
|
|
299
|
-
graph.addEdge(control_flow_graph_1.CfgVertex.toExitId(forLoopId), e, control_flow_graph_1.CfgEdge.makeCdFalse(forLoopId));
|
|
300
|
-
}
|
|
295
|
+
graph.addVertex(control_flow_graph_1.CfgVertex.makeExitMarker(forLoopId));
|
|
296
|
+
for (const e of variable.exitPoints) {
|
|
297
|
+
graph.addEdge(control_flow_graph_1.CfgVertex.toExitId(forLoopId), e, control_flow_graph_1.CfgEdge.makeCdFalse(forLoopId));
|
|
301
298
|
}
|
|
302
|
-
return { graph, breaks: [], nexts: [], returns: body.returns, exitPoints:
|
|
299
|
+
return { graph, breaks: [], nexts: [], returns: body.returns, exitPoints: [control_flow_graph_1.CfgVertex.toExitId(forLoopId)], entryPoints: [forLoopId] };
|
|
303
300
|
}
|
|
304
301
|
function cfgFunctionDefinition(fn, params, body) {
|
|
305
302
|
const fnId = fn.info.id;
|
|
@@ -336,7 +333,7 @@ function cfgFunctionDefinition(fn, params, body) {
|
|
|
336
333
|
return { graph: graph, breaks: [], nexts: [], returns: [], exitPoints: [fnId], entryPoints: [fnId] };
|
|
337
334
|
}
|
|
338
335
|
function cfgFunctionCall(call, name, args, down) {
|
|
339
|
-
if (call.named && call.functionName.content === 'ifelse') {
|
|
336
|
+
if (call.named && call.functionName.content === 'ifelse' && args.length > 1) {
|
|
340
337
|
// special built-in handling for ifelse as it is an expression that does not short-circuit
|
|
341
338
|
return cfgIfThenElse(call, args[0] === r_function_call_1.EmptyArgument ? (0, control_flow_graph_1.emptyControlFlowInformation)() : args[0], args[1] === r_function_call_1.EmptyArgument ? (0, control_flow_graph_1.emptyControlFlowInformation)() : args[1], args[2] === r_function_call_1.EmptyArgument ? (0, control_flow_graph_1.emptyControlFlowInformation)() : args[2]);
|
|
342
339
|
}
|