@eagleoutice/flowr 2.4.6 → 2.4.8
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 +37 -33
- package/abstract-interpretation/data-frame/absint-visitor.js +3 -2
- package/abstract-interpretation/data-frame/dataframe-domain.d.ts +40 -0
- package/abstract-interpretation/data-frame/dataframe-domain.js +62 -0
- package/abstract-interpretation/data-frame/domain.js +1 -1
- package/abstract-interpretation/domains/abstract-domain.d.ts +56 -0
- package/abstract-interpretation/domains/abstract-domain.js +19 -0
- package/abstract-interpretation/domains/bounded-set-domain.d.ts +43 -0
- package/abstract-interpretation/domains/bounded-set-domain.js +121 -0
- package/abstract-interpretation/domains/interval-domain.d.ts +61 -0
- package/abstract-interpretation/domains/interval-domain.js +208 -0
- package/abstract-interpretation/domains/lattice.d.ts +62 -0
- package/abstract-interpretation/domains/lattice.js +12 -0
- package/abstract-interpretation/domains/positive-interval-domain.d.ts +32 -0
- package/abstract-interpretation/domains/positive-interval-domain.js +91 -0
- package/abstract-interpretation/domains/product-domain.d.ts +37 -0
- package/abstract-interpretation/domains/product-domain.js +133 -0
- package/abstract-interpretation/domains/set-bounded-set-domain.d.ts +43 -0
- package/abstract-interpretation/domains/set-bounded-set-domain.js +164 -0
- package/abstract-interpretation/domains/singleton-domain.d.ts +38 -0
- package/abstract-interpretation/domains/singleton-domain.js +115 -0
- package/abstract-interpretation/domains/state-abstract-domain.d.ts +32 -0
- package/abstract-interpretation/domains/state-abstract-domain.js +179 -0
- package/benchmark/slicer.js +1 -1
- package/benchmark/summarizer/first-phase/process.js +1 -1
- package/cli/repl/commands/repl-query.js +11 -2
- package/cli/repl/core.d.ts +2 -2
- package/cli/repl/core.js +26 -7
- package/cli/repl/server/connection.js +3 -1
- package/cli/repl/server/messages/message-slice.d.ts +3 -0
- package/cli/repl/server/messages/message-slice.js +2 -0
- package/control-flow/extract-cfg.d.ts +3 -3
- package/control-flow/extract-cfg.js +4 -4
- package/control-flow/useless-loop.js +30 -21
- package/dataflow/environments/built-in.d.ts +1 -1
- package/dataflow/environments/default-builtin-config.d.ts +9 -0
- package/dataflow/environments/default-builtin-config.js +21 -21
- package/dataflow/environments/environment.js +18 -9
- package/dataflow/environments/overwrite.js +2 -2
- package/dataflow/extractor.js +1 -1
- package/dataflow/graph/diff-dataflow-graph.js +4 -4
- package/dataflow/graph/graph.d.ts +3 -3
- package/dataflow/graph/graph.js +4 -1
- package/dataflow/graph/quads.js +4 -4
- package/dataflow/info.js +1 -1
- package/dataflow/internal/linker.d.ts +2 -0
- package/dataflow/internal/linker.js +18 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.d.ts +3 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +68 -21
- package/dataflow/internal/process/functions/call/built-in/built-in-expression-list.js +1 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-for-loop.js +4 -4
- package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +5 -18
- package/dataflow/internal/process/functions/call/built-in/built-in-repeat-loop.js +1 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-while-loop.js +4 -5
- package/dataflow/internal/process/functions/call/common.js +4 -3
- package/documentation/doc-util/doc-query.js +6 -2
- package/documentation/doc-util/doc-types.d.ts +7 -2
- package/documentation/doc-util/doc-types.js +20 -4
- package/documentation/print-core-wiki.js +5 -1
- package/documentation/print-dataflow-graph-wiki.js +21 -12
- package/documentation/print-faq-wiki.js +5 -0
- package/documentation/print-interface-wiki.js +2 -0
- package/documentation/print-linter-wiki.js +2 -3
- package/documentation/print-query-wiki.js +22 -7
- package/linter/linter-executor.js +25 -17
- package/linter/linter-format.d.ts +10 -1
- package/linter/linter-format.js +8 -0
- package/linter/linter-rules.d.ts +1 -0
- package/linter/rules/absolute-path.js +8 -8
- package/linter/rules/dataframe-access-validation.js +1 -1
- package/linter/rules/file-path-validity.js +8 -11
- package/linter/rules/naming-convention.d.ts +5 -1
- package/linter/rules/naming-convention.js +24 -8
- package/linter/rules/seeded-randomness.js +2 -2
- package/linter/rules/unused-definition.js +1 -1
- package/package.json +17 -15
- package/queries/catalog/call-context-query/call-context-query-executor.d.ts +5 -1
- package/queries/catalog/call-context-query/call-context-query-executor.js +14 -12
- package/queries/catalog/call-context-query/call-context-query-format.d.ts +6 -5
- package/queries/catalog/call-context-query/call-context-query-format.js +1 -1
- package/queries/catalog/call-context-query/identify-link-to-last-call-relation.d.ts +2 -1
- package/queries/catalog/call-context-query/identify-link-to-last-call-relation.js +1 -1
- package/queries/catalog/config-query/config-query-executor.js +7 -1
- package/queries/catalog/config-query/config-query-format.d.ts +7 -0
- package/queries/catalog/config-query/config-query-format.js +72 -1
- package/queries/catalog/dependencies-query/dependencies-query-executor.js +50 -75
- package/queries/catalog/dependencies-query/dependencies-query-format.d.ts +50 -26
- package/queries/catalog/dependencies-query/dependencies-query-format.js +75 -20
- package/queries/catalog/dependencies-query/function-info/function-info.d.ts +2 -2
- package/queries/catalog/dependencies-query/function-info/visualize-functions.d.ts +2 -0
- package/queries/catalog/dependencies-query/function-info/visualize-functions.js +13 -0
- package/queries/catalog/happens-before-query/happens-before-query-executor.js +1 -1
- package/queries/catalog/linter-query/linter-query-format.js +4 -0
- package/queries/query-print.d.ts +2 -2
- package/queries/query-print.js +3 -2
- package/queries/query.d.ts +28 -21
- package/search/flowr-search-builder.d.ts +1 -1
- package/search/flowr-search-builder.js +1 -1
- package/search/flowr-search-filters.d.ts +20 -10
- package/search/flowr-search-filters.js +19 -3
- package/search/search-executor/search-enrichers.d.ts +1 -1
- package/search/search-executor/search-enrichers.js +3 -2
- package/search/search-executor/search-generators.js +1 -1
- package/search/search-executor/search-transformer.js +1 -1
- package/util/objects.d.ts +11 -0
- package/util/objects.js +26 -0
- package/util/version.js +1 -1
|
@@ -5,22 +5,30 @@ const linter_rules_1 = require("./linter-rules");
|
|
|
5
5
|
const flowr_search_executor_1 = require("../search/flowr-search-executor");
|
|
6
6
|
const objects_1 = require("../util/objects");
|
|
7
7
|
function executeLintingRule(ruleName, input, lintingRuleConfig) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
8
|
+
try {
|
|
9
|
+
const rule = linter_rules_1.LintingRules[ruleName];
|
|
10
|
+
const fullConfig = (0, objects_1.deepMergeObject)(rule.info.defaultConfig, lintingRuleConfig);
|
|
11
|
+
const ruleSearch = rule.createSearch(fullConfig, input);
|
|
12
|
+
const searchStart = Date.now();
|
|
13
|
+
const searchResult = (0, flowr_search_executor_1.runSearch)(ruleSearch, input);
|
|
14
|
+
const searchTime = Date.now() - searchStart;
|
|
15
|
+
const processStart = Date.now();
|
|
16
|
+
const result = rule.processSearchResult(searchResult, fullConfig, input);
|
|
17
|
+
const processTime = Date.now() - processStart;
|
|
18
|
+
return {
|
|
19
|
+
...result,
|
|
20
|
+
'.meta': {
|
|
21
|
+
...result['.meta'],
|
|
22
|
+
searchTimeMs: searchTime,
|
|
23
|
+
processTimeMs: processTime
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
catch (e) {
|
|
28
|
+
const msg = typeof e === 'string' ? e : e instanceof Error ? e.message : JSON.stringify(e);
|
|
29
|
+
return {
|
|
30
|
+
error: msg
|
|
31
|
+
};
|
|
32
|
+
}
|
|
25
33
|
}
|
|
26
34
|
//# sourceMappingURL=linter-executor.js.map
|
|
@@ -105,13 +105,22 @@ export interface ConfiguredLintingRule<Name extends LintingRuleNames = LintingRu
|
|
|
105
105
|
readonly name: Name;
|
|
106
106
|
readonly config: DeepPartial<LintingRuleConfig<Name>>;
|
|
107
107
|
}
|
|
108
|
-
|
|
108
|
+
/**
|
|
109
|
+
* For when a linting rule throws an error during execution
|
|
110
|
+
*/
|
|
111
|
+
export interface LintingResultsError {
|
|
112
|
+
readonly error: string;
|
|
113
|
+
}
|
|
114
|
+
export interface LintingResultsSuccess<Name extends LintingRuleNames> {
|
|
109
115
|
results: LintingRuleResult<Name>[];
|
|
110
116
|
'.meta': LintingRuleMetadata<Name> & {
|
|
111
117
|
readonly searchTimeMs: number;
|
|
112
118
|
readonly processTimeMs: number;
|
|
113
119
|
};
|
|
114
120
|
}
|
|
121
|
+
export declare function isLintingResultsError<Name extends LintingRuleNames>(o: LintingResults<Name>): o is LintingResultsError;
|
|
122
|
+
export declare function isLintingResultsSuccess<Name extends LintingRuleNames>(o: LintingResults<Name>): o is LintingResultsSuccess<Name>;
|
|
123
|
+
export type LintingResults<Name extends LintingRuleNames> = LintingResultsSuccess<Name> | LintingResultsError;
|
|
115
124
|
export declare enum LintingResultCertainty {
|
|
116
125
|
/**
|
|
117
126
|
* The linting rule cannot say for sure whether the result is correct or not.
|
package/linter/linter-format.js
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.LintingPrettyPrintContext = exports.LintingRuleCertainty = exports.LintingResultCertainty = void 0;
|
|
4
|
+
exports.isLintingResultsError = isLintingResultsError;
|
|
5
|
+
exports.isLintingResultsSuccess = isLintingResultsSuccess;
|
|
6
|
+
function isLintingResultsError(o) {
|
|
7
|
+
return 'error' in o;
|
|
8
|
+
}
|
|
9
|
+
function isLintingResultsSuccess(o) {
|
|
10
|
+
return 'results' in o;
|
|
11
|
+
}
|
|
4
12
|
var LintingResultCertainty;
|
|
5
13
|
(function (LintingResultCertainty) {
|
|
6
14
|
/**
|
package/linter/linter-rules.d.ts
CHANGED
|
@@ -173,6 +173,7 @@ export declare const LintingRules: {
|
|
|
173
173
|
readonly tags: readonly [import("./linter-tags").LintingRuleTag.Style, import("./linter-tags").LintingRuleTag.QuickFix];
|
|
174
174
|
readonly defaultConfig: {
|
|
175
175
|
readonly caseing: "auto";
|
|
176
|
+
readonly ignoreNonAlpha: true;
|
|
176
177
|
};
|
|
177
178
|
};
|
|
178
179
|
};
|
|
@@ -52,8 +52,7 @@ const PathFunctions = {
|
|
|
52
52
|
'file.path': (df, vtx, config) => {
|
|
53
53
|
const fsep = (0, resolve_argument_1.getArgumentStringValue)(config.solver.variables, df, vtx, undefined, 'fsep', true);
|
|
54
54
|
// in the future we can access `.Platform$file.sep` here
|
|
55
|
-
const
|
|
56
|
-
const sepValues = v ? [...v].flatMap(s => [...s].filter(assert_1.isNotUndefined)) : [path_1.default.sep];
|
|
55
|
+
const sepValues = new Array(...fsep?.values()?.flatMap(s => [...s].filter(assert_1.isNotUndefined)) ?? [path_1.default.sep]);
|
|
57
56
|
if (sepValues.some(s => s === dependencies_query_format_1.Unknown || (0, assert_1.isUndefined)(s))) {
|
|
58
57
|
// if we have no fsep, we cannot construct a path
|
|
59
58
|
return undefined;
|
|
@@ -119,19 +118,19 @@ exports.ABSOLUTE_PATH = {
|
|
|
119
118
|
}
|
|
120
119
|
else if ((0, search_enrichers_1.enrichmentContent)(element, search_enrichers_1.Enrichment.QueryData)) {
|
|
121
120
|
const result = queryResults[(0, search_enrichers_1.enrichmentContent)(element, search_enrichers_1.Enrichment.QueryData).query];
|
|
122
|
-
const mappedStrings = result.
|
|
121
|
+
const mappedStrings = result.read.filter(r => r.value !== undefined && r.value !== dependencies_query_format_1.Unknown && (0, strings_1.isAbsolutePath)(r.value, regex)).map(r => {
|
|
123
122
|
const elem = data.normalize.idMap.get(r.nodeId);
|
|
124
123
|
return {
|
|
125
124
|
certainty: linter_format_1.LintingResultCertainty.Certain,
|
|
126
|
-
filePath: r.
|
|
125
|
+
filePath: r.value,
|
|
127
126
|
range: elem?.info.fullRange ?? elem?.location ?? (0, range_1.rangeFrom)(-1, -1, -1, -1),
|
|
128
|
-
quickFix: buildQuickFix(elem, r.
|
|
127
|
+
quickFix: buildQuickFix(elem, r.value, wd)
|
|
129
128
|
};
|
|
130
129
|
});
|
|
131
130
|
if (mappedStrings.length > 0) {
|
|
132
131
|
return mappedStrings;
|
|
133
132
|
}
|
|
134
|
-
else if (result.
|
|
133
|
+
else if (result.read.every(r => r.value !== dependencies_query_format_1.Unknown)) {
|
|
135
134
|
// if we have no absolute paths, but all paths are known, we can return an empty array
|
|
136
135
|
return [];
|
|
137
136
|
}
|
|
@@ -145,7 +144,8 @@ exports.ABSOLUTE_PATH = {
|
|
|
145
144
|
return strings.filter(s => (0, strings_1.isAbsolutePath)(s, regex)).map(str => ({
|
|
146
145
|
certainty: linter_format_1.LintingResultCertainty.Uncertain,
|
|
147
146
|
filePath: str,
|
|
148
|
-
range: node.info.fullRange ?? node.location ?? (0, range_1.rangeFrom)(-1, -1, -1, -1)
|
|
147
|
+
range: node.info.fullRange ?? node.location ?? (0, range_1.rangeFrom)(-1, -1, -1, -1),
|
|
148
|
+
quickFix: undefined
|
|
149
149
|
}));
|
|
150
150
|
}
|
|
151
151
|
}
|
|
@@ -159,7 +159,7 @@ exports.ABSOLUTE_PATH = {
|
|
|
159
159
|
},
|
|
160
160
|
prettyPrint: {
|
|
161
161
|
[linter_format_1.LintingPrettyPrintContext.Query]: result => `Path \`${result.filePath}\` at ${(0, dfg_1.formatRange)(result.range)}`,
|
|
162
|
-
[linter_format_1.LintingPrettyPrintContext.Full]: result => `Path \`${result.filePath}\` at ${(0, dfg_1.formatRange)(result.range)} is
|
|
162
|
+
[linter_format_1.LintingPrettyPrintContext.Full]: result => `Path \`${result.filePath}\` at ${(0, dfg_1.formatRange)(result.range)} is absolute`
|
|
163
163
|
},
|
|
164
164
|
info: {
|
|
165
165
|
name: 'Absolute Paths',
|
|
@@ -42,7 +42,7 @@ exports.DATA_FRAME_ACCESS_VALIDATION = {
|
|
|
42
42
|
}
|
|
43
43
|
accesses.push(access);
|
|
44
44
|
}
|
|
45
|
-
const operations =
|
|
45
|
+
const operations = accessOperations.entries().flatMap(([, operations]) => operations).toArray();
|
|
46
46
|
const metadata = {
|
|
47
47
|
numOperations: accessOperations.size,
|
|
48
48
|
numAccesses: operations.length,
|
|
@@ -8,18 +8,15 @@ const dependencies_query_format_1 = require("../../queries/catalog/dependencies-
|
|
|
8
8
|
const built_in_source_1 = require("../../dataflow/internal/process/functions/call/built-in/built-in-source");
|
|
9
9
|
const logic_1 = require("../../util/logic");
|
|
10
10
|
const retriever_1 = require("../../r-bridge/retriever");
|
|
11
|
-
const read_functions_1 = require("../../queries/catalog/dependencies-query/function-info/read-functions");
|
|
12
|
-
const write_functions_1 = require("../../queries/catalog/dependencies-query/function-info/write-functions");
|
|
13
11
|
const happens_before_1 = require("../../control-flow/happens-before");
|
|
14
12
|
const linter_tags_1 = require("../linter-tags");
|
|
15
13
|
const search_enrichers_1 = require("../../search/search-executor/search-enrichers");
|
|
16
14
|
exports.FILE_PATH_VALIDITY = {
|
|
17
15
|
createSearch: (config) => flowr_search_builder_1.Q.fromQuery({
|
|
18
16
|
type: 'dependencies',
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
writeFunctions: write_functions_1.WriteFunctions.concat(config.additionalWriteFunctions)
|
|
17
|
+
enabledCategories: ['read', 'write'],
|
|
18
|
+
readFunctions: config.additionalReadFunctions,
|
|
19
|
+
writeFunctions: config.additionalWriteFunctions
|
|
23
20
|
}).with(search_enrichers_1.Enrichment.CfgInformation),
|
|
24
21
|
processSearchResult: (elements, config, data) => {
|
|
25
22
|
const cfg = elements.enrichmentContent(search_enrichers_1.Enrichment.CfgInformation).cfg.graph;
|
|
@@ -32,14 +29,14 @@ exports.FILE_PATH_VALIDITY = {
|
|
|
32
29
|
return {
|
|
33
30
|
results: elements.getElements().flatMap(element => {
|
|
34
31
|
const results = elements.enrichmentContent(search_enrichers_1.Enrichment.QueryData).queries['dependencies'];
|
|
35
|
-
const matchingRead = results.
|
|
32
|
+
const matchingRead = results.read.find(r => r.nodeId == element.node.info.id);
|
|
36
33
|
if (!matchingRead) {
|
|
37
34
|
return [];
|
|
38
35
|
}
|
|
39
36
|
metadata.totalReads++;
|
|
40
37
|
const range = element.node.info.fullRange;
|
|
41
38
|
// check if we can't parse the file path statically
|
|
42
|
-
if (matchingRead.
|
|
39
|
+
if (matchingRead.value === dependencies_query_format_1.Unknown) {
|
|
43
40
|
metadata.totalUnknown++;
|
|
44
41
|
if (config.includeUnknown) {
|
|
45
42
|
return [{
|
|
@@ -53,14 +50,14 @@ exports.FILE_PATH_VALIDITY = {
|
|
|
53
50
|
}
|
|
54
51
|
}
|
|
55
52
|
// check if any write to the same file happens before the read, and exclude this case if so
|
|
56
|
-
const writesToFile = results.
|
|
53
|
+
const writesToFile = results.write.filter(r => samePath(r.value, matchingRead.value, data.config.solver.resolveSource?.ignoreCapitalization));
|
|
57
54
|
const writesBefore = writesToFile.map(w => (0, happens_before_1.happensBefore)(cfg, w.nodeId, element.node.info.id));
|
|
58
55
|
if (writesBefore.some(w => w === logic_1.Ternary.Always)) {
|
|
59
56
|
metadata.totalWritesBeforeAlways++;
|
|
60
57
|
return [];
|
|
61
58
|
}
|
|
62
59
|
// check if the file exists!
|
|
63
|
-
const paths = (0, built_in_source_1.findSource)(data.config.solver.resolveSource, matchingRead.
|
|
60
|
+
const paths = (0, built_in_source_1.findSource)(data.config.solver.resolveSource, matchingRead.value, {
|
|
64
61
|
referenceChain: element.node.info.file ? [(0, retriever_1.requestFromInput)(`file://${element.node.info.file}`)] : []
|
|
65
62
|
});
|
|
66
63
|
if (paths && paths.length) {
|
|
@@ -69,7 +66,7 @@ exports.FILE_PATH_VALIDITY = {
|
|
|
69
66
|
}
|
|
70
67
|
return [{
|
|
71
68
|
range,
|
|
72
|
-
filePath: matchingRead.
|
|
69
|
+
filePath: matchingRead.value,
|
|
73
70
|
certainty: writesBefore && writesBefore.length && writesBefore.every(w => w === logic_1.Ternary.Maybe) ? linter_format_1.LintingResultCertainty.Uncertain : linter_format_1.LintingResultCertainty.Certain
|
|
74
71
|
}];
|
|
75
72
|
}),
|
|
@@ -23,7 +23,10 @@ export interface NamingConventionResult extends LintingResult {
|
|
|
23
23
|
* It is planned to have a config like ESLint
|
|
24
24
|
*/
|
|
25
25
|
export interface NamingConventionConfig extends MergeableRecord {
|
|
26
|
+
/** which casing convention to enforce */
|
|
26
27
|
caseing: CasingConvention | 'auto';
|
|
28
|
+
/** if true non alphabetic characters are ignored */
|
|
29
|
+
ignoreNonAlpha: boolean;
|
|
27
30
|
}
|
|
28
31
|
export interface NamingConventionMetadata extends MergeableRecord {
|
|
29
32
|
/** number of symbols matching the casing convetion */
|
|
@@ -35,7 +38,7 @@ export declare function detectCasing(identifier: string): CasingConvention;
|
|
|
35
38
|
export declare function getMostUsedCasing(symbols: {
|
|
36
39
|
detectedCasing: CasingConvention;
|
|
37
40
|
}[]): CasingConvention;
|
|
38
|
-
export declare function fixCasing(identifier: string, convention: CasingConvention): string;
|
|
41
|
+
export declare function fixCasing(identifier: string, convention: CasingConvention): string | undefined;
|
|
39
42
|
export declare function createNamingConventionQuickFixes(graph: DataflowGraph, nodeId: NodeId, replacement: string, conv: CasingConvention): LintQuickFixReplacement[] | undefined;
|
|
40
43
|
export declare const NAMING_CONVENTION: {
|
|
41
44
|
readonly createSearch: (_config: NamingConventionConfig) => import("../../search/flowr-search-builder").FlowrSearchBuilder<"all", ["filter"], import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, import("../../search/flowr-search").FlowrSearchElements<import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, [] | import("../../search/flowr-search").FlowrSearchElement<import("../../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>[]>>;
|
|
@@ -67,6 +70,7 @@ export declare const NAMING_CONVENTION: {
|
|
|
67
70
|
readonly tags: readonly [LintingRuleTag.Style, LintingRuleTag.QuickFix];
|
|
68
71
|
readonly defaultConfig: {
|
|
69
72
|
readonly caseing: "auto";
|
|
73
|
+
readonly ignoreNonAlpha: true;
|
|
70
74
|
};
|
|
71
75
|
};
|
|
72
76
|
};
|
|
@@ -22,8 +22,11 @@ var CasingConvention;
|
|
|
22
22
|
CasingConvention["PascalSnakeCase"] = "Pascal_Snake_Case";
|
|
23
23
|
CasingConvention["Unknown"] = "unknown";
|
|
24
24
|
})(CasingConvention || (exports.CasingConvention = CasingConvention = {}));
|
|
25
|
+
function containsAlpha(s) {
|
|
26
|
+
return /[A-Za-z]/.test(s);
|
|
27
|
+
}
|
|
25
28
|
function detectCasing(identifier) {
|
|
26
|
-
if (identifier.trim() === '') {
|
|
29
|
+
if (identifier.trim() === '' || !containsAlpha(identifier)) {
|
|
27
30
|
return CasingConvention.Unknown;
|
|
28
31
|
}
|
|
29
32
|
const upper = identifier.toUpperCase();
|
|
@@ -78,8 +81,16 @@ function getMostUsedCasing(symbols) {
|
|
|
78
81
|
return [...map].reduce((p, c) => p[1] > c[1] ? p : c)[0];
|
|
79
82
|
}
|
|
80
83
|
function fixCasing(identifier, convention) {
|
|
84
|
+
if (!containsAlpha(identifier)) {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
81
87
|
const tokens = identifier.split(/(?=[A-Z])|_/).map(s => s.toLowerCase());
|
|
82
|
-
const firstUp = (s) =>
|
|
88
|
+
const firstUp = (s) => {
|
|
89
|
+
if (s.length < 1) {
|
|
90
|
+
return s.toUpperCase();
|
|
91
|
+
}
|
|
92
|
+
return `${s[0].toUpperCase()}${s.substring(1)}`;
|
|
93
|
+
};
|
|
83
94
|
switch (convention) {
|
|
84
95
|
case CasingConvention.CamelCase: // camelCase
|
|
85
96
|
return `${tokens[0]}${tokens.slice(1).map(firstUp).join('')}`;
|
|
@@ -139,11 +150,15 @@ exports.NAMING_CONVENTION = {
|
|
|
139
150
|
id: m.node.info.id
|
|
140
151
|
}));
|
|
141
152
|
const casing = config.caseing === 'auto' ? getMostUsedCasing(symbols) : config.caseing;
|
|
142
|
-
const results = symbols
|
|
143
|
-
.
|
|
144
|
-
...m
|
|
145
|
-
|
|
146
|
-
|
|
153
|
+
const results = symbols
|
|
154
|
+
.filter(m => (m.detectedCasing !== casing) && (!config.ignoreNonAlpha || containsAlpha(m.name)))
|
|
155
|
+
.map(({ id, ...m }) => {
|
|
156
|
+
const fix = fixCasing(m.name, casing);
|
|
157
|
+
return {
|
|
158
|
+
...m,
|
|
159
|
+
quickFix: fix ? createNamingConventionQuickFixes(data.dataflow.graph, id, fix, casing) : undefined
|
|
160
|
+
};
|
|
161
|
+
});
|
|
147
162
|
return {
|
|
148
163
|
results: results,
|
|
149
164
|
'.meta': {
|
|
@@ -163,7 +178,8 @@ exports.NAMING_CONVENTION = {
|
|
|
163
178
|
description: 'Checks wether the symbols conform to a certain naming convention',
|
|
164
179
|
tags: [linter_tags_1.LintingRuleTag.Style, linter_tags_1.LintingRuleTag.QuickFix],
|
|
165
180
|
defaultConfig: {
|
|
166
|
-
caseing: 'auto'
|
|
181
|
+
caseing: 'auto',
|
|
182
|
+
ignoreNonAlpha: true
|
|
167
183
|
}
|
|
168
184
|
}
|
|
169
185
|
};
|
|
@@ -27,8 +27,8 @@ exports.SEEDED_RANDOMNESS = {
|
|
|
27
27
|
}
|
|
28
28
|
})
|
|
29
29
|
.with(search_enrichers_1.Enrichment.LastCall, [
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
{ callName: config.randomnessProducers.filter(p => p.type === 'function').map(p => p.name) },
|
|
31
|
+
{ callName: getDefaultAssignments().flatMap(b => b.names), cascadeIf: () => cascade_action_1.CascadeAction.Continue }
|
|
32
32
|
]),
|
|
33
33
|
processSearchResult: (elements, config, { dataflow }) => {
|
|
34
34
|
const assignmentProducers = new Set(config.randomnessProducers.filter(p => p.type == 'assignment').map(p => p.name));
|
|
@@ -73,7 +73,7 @@ exports.UNUSED_DEFINITION = {
|
|
|
73
73
|
}
|
|
74
74
|
const ingoingEdges = data.dataflow.graph.ingoingEdges(dfgVertex.id);
|
|
75
75
|
const interestedIn = (0, vertex_1.isVariableDefinitionVertex)(dfgVertex) ? InterestingEdgesVariable : InterestingEdgesFunction;
|
|
76
|
-
const ingoingInteresting =
|
|
76
|
+
const ingoingInteresting = ingoingEdges?.values().some(e => (0, edge_1.edgeIncludesType)(e.types, interestedIn));
|
|
77
77
|
if (ingoingInteresting) {
|
|
78
78
|
return undefined;
|
|
79
79
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eagleoutice/flowr",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.8",
|
|
4
4
|
"description": "Static Dataflow Analyzer and Program Slicer for the R Programming Language",
|
|
5
5
|
"types": "dist/src/index.d.ts",
|
|
6
6
|
"repository": {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"setup:dev": "git lfs fetch && npm ci && git config --local core.hooksPath .githooks/ && git push --dry-run",
|
|
16
16
|
"main": "npm run build:bundle-flowr && node dist/src/cli/flowr.min.js",
|
|
17
17
|
"flowr": "npm run main --",
|
|
18
|
-
"main-dev": "ts-node src/cli/flowr.ts",
|
|
18
|
+
"main-dev": "ts-node-dev src/cli/flowr.ts",
|
|
19
19
|
"publish-library": "cp .npmignore package.json README.md LICENSE dist/src/ && cd dist/src && npm publish --access public",
|
|
20
20
|
"release": "npx release-it --ci",
|
|
21
21
|
"stats": "ts-node src/cli/statistics-app.ts",
|
|
@@ -51,8 +51,9 @@
|
|
|
51
51
|
"test": "vitest --exclude \"test/system-tests/**\" --config test/vitest.config.mts",
|
|
52
52
|
"test:system": "vitest --dir test/system-tests --config test/system-tests/vitest.config.mts",
|
|
53
53
|
"test:coverage": "npm run test -- --coverage",
|
|
54
|
-
"
|
|
54
|
+
"test:full": "npm run test-full",
|
|
55
55
|
"test-full": "npm run test:coverage -- --no-watch -- --make-summary --test-installation",
|
|
56
|
+
"performance-test": "func() { cd test/performance/ && bash run-all-suites.sh $1 $2 $3 $4; cd ../../; }; func",
|
|
56
57
|
"detect-circular-deps": "npx madge --extensions ts,tsx --circular src/",
|
|
57
58
|
"checkup": "npm run flowr -- --execute \":version\" && npm run lint && npm run test-full -- --allowOnly=false && npm run test:system -- --no-watch && docker build -t test-flowr -f scripts/Dockerfile . && npm run doc && npm run gen:readme && npm-run-all wiki:*"
|
|
58
59
|
},
|
|
@@ -177,32 +178,33 @@
|
|
|
177
178
|
"@commitlint/cli": "^19.7.1",
|
|
178
179
|
"@commitlint/config-angular": "^19.7.1",
|
|
179
180
|
"@eagleoutice/eslint-config-flowr": "^1.0.19",
|
|
180
|
-
"@eslint/eslintrc": "^3.
|
|
181
|
-
"@eslint/js": "^9.
|
|
181
|
+
"@eslint/eslintrc": "^3.3.1",
|
|
182
|
+
"@eslint/js": "^9.34.0",
|
|
182
183
|
"@j-ulrich/release-it-regex-bumper": "^5.3.0",
|
|
183
184
|
"@types/command-line-args": "^5.2.3",
|
|
184
185
|
"@types/command-line-usage": "^5.0.4",
|
|
185
186
|
"@types/n-readlines": "^1.0.6",
|
|
186
|
-
"@types/n3": "^1.
|
|
187
|
+
"@types/n3": "^1.26.0",
|
|
187
188
|
"@types/object-hash": "^3.0.6",
|
|
188
189
|
"@types/seedrandom": "^3.0.8",
|
|
189
|
-
"@types/semver": "^7.
|
|
190
|
+
"@types/semver": "^7.7.0",
|
|
190
191
|
"@types/tmp": "^0.2.6",
|
|
191
|
-
"@types/ws": "^8.
|
|
192
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
193
|
-
"@vitest/coverage-v8": "^3.
|
|
194
|
-
"esbuild": "^0.25.
|
|
195
|
-
"eslint": "^9.
|
|
192
|
+
"@types/ws": "^8.18.1",
|
|
193
|
+
"@typescript-eslint/eslint-plugin": "^8.40.0",
|
|
194
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
195
|
+
"esbuild": "^0.25.9",
|
|
196
|
+
"eslint": "^9.34.0",
|
|
196
197
|
"license-checker": "^25.0.1",
|
|
197
198
|
"npm-run-all": "^4.1.5",
|
|
198
199
|
"release-it": "^19.0.2",
|
|
199
200
|
"ts-node": "^10.9.2",
|
|
201
|
+
"ts-node-dev": "^2.0.0",
|
|
200
202
|
"typedoc": "^0.27.7",
|
|
201
203
|
"typedoc-plugin-missing-exports": "^3.1.0",
|
|
202
204
|
"typedoc-theme-hierarchy": "^5.0.4",
|
|
203
205
|
"typedoc-umlclass": "^0.10.1",
|
|
204
206
|
"typescript": "^5.7.3",
|
|
205
|
-
"vitest": "^3.
|
|
207
|
+
"vitest": "^3.2.4"
|
|
206
208
|
},
|
|
207
209
|
"dependencies": {
|
|
208
210
|
"@eagleoutice/tree-sitter-r": "^1.1.2",
|
|
@@ -210,7 +212,7 @@
|
|
|
210
212
|
"clipboardy": "^4.0.0",
|
|
211
213
|
"command-line-args": "^6.0.1",
|
|
212
214
|
"command-line-usage": "^7.0.3",
|
|
213
|
-
"joi": "^
|
|
215
|
+
"joi": "^18.0.1",
|
|
214
216
|
"lz-string": "^1.5.0",
|
|
215
217
|
"n-readlines": "^1.0.1",
|
|
216
218
|
"n3": "^1.23.1",
|
|
@@ -221,7 +223,7 @@
|
|
|
221
223
|
"semver": "^7.7.1",
|
|
222
224
|
"tar": "^7.4.3",
|
|
223
225
|
"tmp": "^0.2.3",
|
|
224
|
-
"ts-essentials": "^10.
|
|
226
|
+
"ts-essentials": "^10.1.1",
|
|
225
227
|
"tslog": "^4.9.3",
|
|
226
228
|
"web-tree-sitter": "^0.24.7",
|
|
227
229
|
"ws": "^8.18.0",
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import type { CallContextQuery, CallContextQueryResult } from './call-context-query-format';
|
|
1
|
+
import type { CallContextQuery, CallContextQueryResult, CallNameTypes, LinkTo } from './call-context-query-format';
|
|
2
2
|
import type { BasicQueryData } from '../../base-query-format';
|
|
3
|
+
export declare function promoteCallName(callName: CallNameTypes, exact?: boolean): RegExp | Set<string>;
|
|
4
|
+
export type PromotedLinkTo = Omit<LinkTo, 'callName'> & {
|
|
5
|
+
callName: RegExp | Set<string>;
|
|
6
|
+
};
|
|
3
7
|
/**
|
|
4
8
|
* Multi-stage call context query resolve.
|
|
5
9
|
*
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.promoteCallName = promoteCallName;
|
|
3
4
|
exports.executeCallContextQueries = executeCallContextQueries;
|
|
4
5
|
const node_id_1 = require("../../../r-bridge/lang-4.x/ast/model/processing/node-id");
|
|
5
6
|
const vertex_1 = require("../../../dataflow/graph/vertex");
|
|
@@ -42,6 +43,9 @@ function isSubCallQuery(query) {
|
|
|
42
43
|
function exactCallNameRegex(name) {
|
|
43
44
|
return new RegExp(`^(${name})$`);
|
|
44
45
|
}
|
|
46
|
+
function promoteCallName(callName, exact = false) {
|
|
47
|
+
return Array.isArray(callName) ? new Set(callName) : exact ? exactCallNameRegex(callName) : new RegExp(callName);
|
|
48
|
+
}
|
|
45
49
|
function promoteQueryCallNames(queries) {
|
|
46
50
|
let requiresCfg = false;
|
|
47
51
|
const promotedQueries = queries.map(q => {
|
|
@@ -49,30 +53,28 @@ function promoteQueryCallNames(queries) {
|
|
|
49
53
|
requiresCfg = true;
|
|
50
54
|
return {
|
|
51
55
|
...q,
|
|
52
|
-
callName: q.
|
|
53
|
-
: new RegExp(q.callName),
|
|
56
|
+
callName: promoteCallName(q.callName, q.callNameExact),
|
|
54
57
|
fileFilter: q.fileFilter && {
|
|
55
58
|
...q.fileFilter,
|
|
56
|
-
filter:
|
|
59
|
+
filter: promoteCallName(q.fileFilter.filter)
|
|
57
60
|
},
|
|
58
61
|
linkTo: Array.isArray(q.linkTo) ? q.linkTo.map(l => ({
|
|
59
62
|
...l,
|
|
60
|
-
callName:
|
|
63
|
+
callName: promoteCallName(l.callName)
|
|
61
64
|
})) : {
|
|
62
65
|
...q.linkTo,
|
|
63
66
|
/* we have to add another promotion layer whenever we add something without this call name */
|
|
64
|
-
callName:
|
|
67
|
+
callName: promoteCallName(q.linkTo.callName)
|
|
65
68
|
}
|
|
66
69
|
};
|
|
67
70
|
}
|
|
68
71
|
else {
|
|
69
72
|
return {
|
|
70
73
|
...q,
|
|
71
|
-
callName: q.
|
|
72
|
-
: new RegExp(q.callName),
|
|
74
|
+
callName: promoteCallName(q.callName, q.callNameExact),
|
|
73
75
|
fileFilter: q.fileFilter && {
|
|
74
76
|
...q.fileFilter,
|
|
75
|
-
filter:
|
|
77
|
+
filter: promoteCallName(q.fileFilter.filter)
|
|
76
78
|
}
|
|
77
79
|
};
|
|
78
80
|
}
|
|
@@ -150,7 +152,7 @@ function doesFilepathMatch(file, filter) {
|
|
|
150
152
|
if (file === undefined) {
|
|
151
153
|
return filter.includeUndefinedFiles ?? true;
|
|
152
154
|
}
|
|
153
|
-
return filter.filter.test(file);
|
|
155
|
+
return filter.filter instanceof RegExp ? filter.filter.test(file) : filter.filter.has(file);
|
|
154
156
|
}
|
|
155
157
|
function isParameterDefaultValue(nodeId, ast) {
|
|
156
158
|
let node = ast.idMap.get(nodeId);
|
|
@@ -197,13 +199,13 @@ function executeCallContextQueries({ dataflow: { graph }, ast, config }, queries
|
|
|
197
199
|
const targets = retrieveAllCallAliases(nodeId, graph);
|
|
198
200
|
for (const [l, ids] of targets.entries()) {
|
|
199
201
|
for (const query of queriesWhichWantAliases) {
|
|
200
|
-
if (query.callName.test(l)) {
|
|
202
|
+
if (query.callName instanceof RegExp ? query.callName.test(l) : query.callName.has(l)) {
|
|
201
203
|
initialIdCollector.add(query.kind ?? '.', query.subkind ?? '.', (0, objects_1.compactRecord)({ id: nodeId, name: info.name, aliasRoots: ids }));
|
|
202
204
|
}
|
|
203
205
|
}
|
|
204
206
|
}
|
|
205
207
|
}
|
|
206
|
-
for (const query of promotedQueries.filter(q => !q.includeAliases && q.callName.test(info.name))) {
|
|
208
|
+
for (const query of promotedQueries.filter(q => !q.includeAliases && (q.callName instanceof RegExp ? q.callName.test(info.name) : q.callName.has(info.name)))) {
|
|
207
209
|
const file = ast.idMap.get(nodeId)?.info.file;
|
|
208
210
|
if (!doesFilepathMatch(file, query.fileFilter)) {
|
|
209
211
|
continue;
|
|
@@ -223,7 +225,7 @@ function executeCallContextQueries({ dataflow: { graph }, ast, config }, queries
|
|
|
223
225
|
continue;
|
|
224
226
|
}
|
|
225
227
|
let linkedIds = undefined;
|
|
226
|
-
if (cfg &&
|
|
228
|
+
if (cfg && 'linkTo' in query && query.linkTo !== undefined) {
|
|
227
229
|
const linked = Array.isArray(query.linkTo) ? query.linkTo : [query.linkTo];
|
|
228
230
|
for (const link of linked) {
|
|
229
231
|
/* if we have a linkTo query, we have to find the last call */
|
|
@@ -20,7 +20,7 @@ export interface FileFilter<FilterType> {
|
|
|
20
20
|
*/
|
|
21
21
|
readonly includeUndefinedFiles?: boolean;
|
|
22
22
|
}
|
|
23
|
-
export interface DefaultCallContextQueryFormat<RegexType extends
|
|
23
|
+
export interface DefaultCallContextQueryFormat<RegexType extends CallNameTypes> extends BaseQueryFormat {
|
|
24
24
|
readonly type: 'call-context';
|
|
25
25
|
/** Regex regarding the function name, please note that strings will be interpreted as regular expressions too! */
|
|
26
26
|
readonly callName: RegexType;
|
|
@@ -50,13 +50,14 @@ export interface DefaultCallContextQueryFormat<RegexType extends RegExp | string
|
|
|
50
50
|
*/
|
|
51
51
|
readonly fileFilter?: FileFilter<RegexType>;
|
|
52
52
|
}
|
|
53
|
+
export type CallNameTypes = RegExp | string | string[];
|
|
53
54
|
/**
|
|
54
55
|
* Links the current call to the last call of the given kind.
|
|
55
56
|
* This way, you can link a call like `points` to the latest graphics plot etc.
|
|
56
57
|
* For now, this uses the static Control-Flow-Graph produced by flowR as the FD over-approximation is still not stable (see #1005).
|
|
57
58
|
* In short, this means that we are unable to detect origins over function call boundaries but plan on being more precise in the future.
|
|
58
59
|
*/
|
|
59
|
-
export interface LinkToLastCall<CallName extends
|
|
60
|
+
export interface LinkToLastCall<CallName extends CallNameTypes = CallNameTypes> extends BaseQueryFormat {
|
|
60
61
|
readonly type: 'link-to-last-call';
|
|
61
62
|
/** Regex regarding the function name of the last call. Similar to {@link DefaultCallContextQueryFormat#callName}, strings are interpreted as a `RegExp`. */
|
|
62
63
|
readonly callName: CallName;
|
|
@@ -71,10 +72,10 @@ export interface LinkToLastCall<CallName extends RegExp | string = RegExp | stri
|
|
|
71
72
|
*/
|
|
72
73
|
readonly cascadeIf?: (target: DataflowGraphVertexInfo, from: NodeId, graph: DataflowGraph) => CascadeAction;
|
|
73
74
|
}
|
|
74
|
-
export type LinkTo<CallName extends
|
|
75
|
+
export type LinkTo<CallName extends CallNameTypes = CallNameTypes, AttachLinkInfo = NoInfo> = (LinkToLastCall<CallName>) & {
|
|
75
76
|
attachLinkInfo?: AttachLinkInfo;
|
|
76
77
|
};
|
|
77
|
-
export interface SubCallContextQueryFormat<CallName extends
|
|
78
|
+
export interface SubCallContextQueryFormat<CallName extends CallNameTypes = CallNameTypes, AttachLinkInfo = NoInfo> extends DefaultCallContextQueryFormat<CallName> {
|
|
78
79
|
readonly linkTo: LinkTo<CallName, AttachLinkInfo> | LinkTo<CallName, AttachLinkInfo>[];
|
|
79
80
|
}
|
|
80
81
|
export interface CallContextQuerySubKindResult {
|
|
@@ -105,7 +106,7 @@ export type CallContextQueryKindResult = Record<string, {
|
|
|
105
106
|
export interface CallContextQueryResult extends BaseQueryResult {
|
|
106
107
|
readonly kinds: CallContextQueryKindResult;
|
|
107
108
|
}
|
|
108
|
-
export type CallContextQuery<CallName extends
|
|
109
|
+
export type CallContextQuery<CallName extends CallNameTypes = CallNameTypes, AttachLinkInfo = NoInfo> = DefaultCallContextQueryFormat<CallName> | SubCallContextQueryFormat<CallName, AttachLinkInfo>;
|
|
109
110
|
export declare const CallContextQueryDefinition: {
|
|
110
111
|
readonly executor: typeof executeCallContextQueries;
|
|
111
112
|
readonly asciiSummarizer: (formatter: OutputFormatter, processed: PipelineOutput<typeof DEFAULT_DATAFLOW_PIPELINE>, queryResults: BaseQueryResult, result: string[]) => boolean;
|
|
@@ -12,7 +12,7 @@ const query_print_1 = require("../../query-print");
|
|
|
12
12
|
const identify_link_to_last_call_relation_1 = require("./identify-link-to-last-call-relation");
|
|
13
13
|
const CallContextQueryLinkTo = joi_1.default.object({
|
|
14
14
|
type: joi_1.default.string().valid('link-to-last-call').required().description('The type of the linkTo sub-query.'),
|
|
15
|
-
callName: joi_1.default.string().required().description('
|
|
15
|
+
callName: joi_1.default.alternatives(joi_1.default.string(), joi_1.default.array().items(joi_1.default.string())).required().description('Test regarding the function name of the last call. Similar to `callName`, strings are interpreted as a regular expression, and string arrays are checked for containment.'),
|
|
16
16
|
ignoreIf: joi_1.default.function().optional().description('Should we ignore this (source) call? Currently, there is no well working serialization for this.'),
|
|
17
17
|
cascadeIf: joi_1.default.function().optional().description('Should we continue searching after the link was created? Currently, there is no well working serialization for this.'),
|
|
18
18
|
attachLinkInfo: joi_1.default.object().optional().description('Additional information to attach to the link.')
|
|
@@ -5,6 +5,7 @@ import { RType } from '../../../r-bridge/lang-4.x/ast/model/type';
|
|
|
5
5
|
import type { RNodeWithParent } from '../../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
6
6
|
import type { LinkTo } from './call-context-query-format';
|
|
7
7
|
import type { ControlFlowGraph } from '../../../control-flow/control-flow-graph';
|
|
8
|
+
import type { PromotedLinkTo } from './call-context-query-executor';
|
|
8
9
|
export declare enum CallTargets {
|
|
9
10
|
/** call targets a function that is not defined locally in the script (e.g., the call targets a library function) */
|
|
10
11
|
OnlyGlobal = "global",
|
|
@@ -24,4 +25,4 @@ export declare function getValueOfArgument<Types extends readonly RType[] = read
|
|
|
24
25
|
}, additionalAllowedTypes?: Types): (RNodeWithParent & {
|
|
25
26
|
type: Types[number];
|
|
26
27
|
}) | undefined;
|
|
27
|
-
export declare function identifyLinkToLastCallRelation(from: NodeId, cfg: ControlFlowGraph, graph: DataflowGraph, { callName, ignoreIf, cascadeIf }: LinkTo<RegExp>): NodeId[];
|
|
28
|
+
export declare function identifyLinkToLastCallRelation(from: NodeId, cfg: ControlFlowGraph, graph: DataflowGraph, { callName, ignoreIf, cascadeIf }: LinkTo<RegExp> | PromotedLinkTo): NodeId[];
|
|
@@ -121,7 +121,7 @@ function identifyLinkToLastCallRelation(from, cfg, graph, { callName, ignoreIf,
|
|
|
121
121
|
if (vertex === undefined || vertex.tag !== vertex_1.VertexType.FunctionCall) {
|
|
122
122
|
return;
|
|
123
123
|
}
|
|
124
|
-
if (callName.test(vertex.name)) {
|
|
124
|
+
if (callName instanceof RegExp ? callName.test(vertex.name) : callName.has(vertex.name)) {
|
|
125
125
|
const act = cascadeIf ? cascadeIf(vertex, from, graph) : cascade_action_1.CascadeAction.Stop;
|
|
126
126
|
if (act === cascade_action_1.CascadeAction.Skip) {
|
|
127
127
|
return;
|
|
@@ -2,9 +2,15 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.executeConfigQuery = executeConfigQuery;
|
|
4
4
|
const log_1 = require("../../../util/log");
|
|
5
|
+
const assert_1 = require("../../../util/assert");
|
|
6
|
+
const objects_1 = require("../../../util/objects");
|
|
5
7
|
function executeConfigQuery({ config }, queries) {
|
|
6
8
|
if (queries.length !== 1) {
|
|
7
|
-
log_1.log.warn('Config query expects only up to one query, but got', queries.length);
|
|
9
|
+
log_1.log.warn('Config query usually expects only up to one query, but got', queries.length);
|
|
10
|
+
}
|
|
11
|
+
const updates = queries.map(q => q.update).filter(assert_1.isNotUndefined);
|
|
12
|
+
for (const update of updates) {
|
|
13
|
+
(0, objects_1.deepMergeObjectInPlace)(config, update);
|
|
8
14
|
}
|
|
9
15
|
return {
|
|
10
16
|
'.meta': {
|