@eagleoutice/flowr 2.3.0 → 2.4.0
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 +41 -29
- package/abstract-interpretation/data-frame/absint-visitor.d.ts +2 -3
- package/abstract-interpretation/data-frame/absint-visitor.js +14 -16
- package/abstract-interpretation/data-frame/mappers/function-mapper.js +3 -3
- package/abstract-interpretation/data-frame/semantics.d.ts +1 -1
- package/abstract-interpretation/data-frame/semantics.js +7 -10
- package/abstract-interpretation/data-frame/shape-inference.js +2 -8
- package/benchmark/slicer.js +7 -5
- package/benchmark/summarizer/second-phase/graph.js +1 -1
- package/benchmark/summarizer/second-phase/process.js +1 -1
- package/cli/benchmark-app.d.ts +1 -0
- package/cli/benchmark-app.js +1 -0
- package/cli/benchmark-helper-app.d.ts +1 -0
- package/cli/benchmark-helper-app.js +4 -3
- package/cli/common/options.js +2 -0
- package/cli/repl/commands/repl-query.js +1 -1
- package/cli/repl/server/connection.js +14 -5
- package/control-flow/basic-cfg-guided-visitor.d.ts +1 -2
- package/control-flow/basic-cfg-guided-visitor.js +0 -6
- package/control-flow/cfg-simplification.d.ts +6 -0
- package/control-flow/cfg-simplification.js +18 -9
- package/control-flow/control-flow-graph.d.ts +2 -8
- package/control-flow/control-flow-graph.js +1 -6
- package/control-flow/extract-cfg.d.ts +2 -2
- package/control-flow/extract-cfg.js +52 -63
- package/core/steps/all/static-slicing/00-slice.d.ts +7 -1
- package/core/steps/all/static-slicing/00-slice.js +9 -3
- package/core/steps/pipeline/default-pipelines.d.ts +74 -74
- package/dataflow/environments/built-in.d.ts +2 -2
- package/dataflow/environments/built-in.js +13 -12
- package/dataflow/graph/dataflowgraph-builder.js +2 -2
- package/dataflow/graph/graph.js +1 -1
- package/dataflow/graph/invert-dfg.d.ts +2 -0
- package/dataflow/graph/invert-dfg.js +17 -0
- package/documentation/doc-util/doc-query.js +1 -1
- package/documentation/doc-util/doc-search.js +2 -2
- package/documentation/print-cfg-wiki.js +3 -4
- package/documentation/print-core-wiki.js +2 -2
- package/documentation/print-dataflow-graph-wiki.js +7 -0
- package/documentation/print-faq-wiki.js +4 -0
- package/documentation/print-linter-wiki.js +32 -4
- package/documentation/print-linting-and-testing-wiki.js +13 -1
- package/documentation/print-onboarding-wiki.js +4 -0
- package/documentation/print-query-wiki.js +12 -3
- package/linter/linter-executor.js +1 -2
- package/linter/linter-format.d.ts +26 -4
- package/linter/linter-format.js +25 -6
- package/linter/linter-rules.d.ts +40 -12
- package/linter/linter-rules.js +3 -1
- package/linter/rules/absolute-path.d.ts +4 -7
- package/linter/rules/absolute-path.js +9 -6
- package/linter/rules/dataframe-access-validation.d.ts +3 -1
- package/linter/rules/dataframe-access-validation.js +3 -1
- package/linter/rules/dead-code.d.ts +43 -0
- package/linter/rules/dead-code.js +50 -0
- package/linter/rules/deprecated-functions.d.ts +3 -2
- package/linter/rules/deprecated-functions.js +3 -1
- package/linter/rules/file-path-validity.d.ts +4 -4
- package/linter/rules/file-path-validity.js +8 -6
- package/linter/rules/naming-convention.d.ts +4 -3
- package/linter/rules/naming-convention.js +3 -1
- package/linter/rules/seeded-randomness.d.ts +4 -3
- package/linter/rules/seeded-randomness.js +3 -1
- package/linter/rules/unused-definition.d.ts +2 -0
- package/linter/rules/unused-definition.js +3 -1
- package/package.json +1 -1
- package/queries/catalog/dependencies-query/dependencies-query-executor.js +6 -1
- package/queries/catalog/dependencies-query/function-info/read-functions.js +1 -0
- package/queries/catalog/dependencies-query/function-info/write-functions.js +1 -0
- package/queries/catalog/linter-query/linter-query-format.js +1 -1
- package/queries/catalog/location-map-query/location-map-query-executor.js +7 -5
- package/queries/catalog/location-map-query/location-map-query-format.d.ts +3 -0
- package/queries/catalog/location-map-query/location-map-query-format.js +1 -0
- package/queries/catalog/search-query/search-query-executor.js +1 -1
- package/queries/catalog/static-slice-query/static-slice-query-executor.js +2 -1
- package/queries/catalog/static-slice-query/static-slice-query-format.d.ts +3 -0
- package/queries/catalog/static-slice-query/static-slice-query-format.js +3 -1
- package/queries/query-print.d.ts +1 -1
- package/queries/query-print.js +0 -1
- package/queries/query.d.ts +16 -5
- package/queries/query.js +24 -11
- package/search/flowr-search-builder.d.ts +6 -6
- package/search/flowr-search-executor.d.ts +2 -2
- package/search/flowr-search-executor.js +1 -1
- package/search/flowr-search.d.ts +13 -8
- package/search/flowr-search.js +21 -0
- package/search/search-executor/search-enrichers.d.ts +87 -20
- package/search/search-executor/search-enrichers.js +44 -5
- package/search/search-executor/search-generators.d.ts +4 -4
- package/search/search-executor/search-generators.js +12 -7
- package/search/search-executor/search-mappers.js +3 -2
- package/search/search-executor/search-transformer.d.ts +3 -3
- package/search/search-executor/search-transformer.js +2 -2
- package/slicing/static/static-slicer.d.ts +4 -2
- package/slicing/static/static-slicer.js +10 -4
- package/util/collections/arrays.d.ts +2 -0
- package/util/collections/arrays.js +9 -0
- package/util/mermaid/dfg.js +4 -2
- package/util/range.d.ts +1 -0
- package/util/range.js +5 -1
- package/util/version.js +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { LintingResult } from '../linter-format';
|
|
2
|
-
import {
|
|
2
|
+
import { LintingResultCertainty, LintingRuleCertainty } from '../linter-format';
|
|
3
3
|
import type { MergeableRecord } from '../../util/objects';
|
|
4
4
|
import type { SourceRange } from '../../util/range';
|
|
5
5
|
import type { Identifier } from '../../dataflow/environments/identifier';
|
|
@@ -22,7 +22,7 @@ export declare const DEPRECATED_FUNCTIONS: {
|
|
|
22
22
|
readonly createSearch: (config: DeprecatedFunctionsConfig) => import("../../search/flowr-search-builder").FlowrSearchBuilder<"all", ["with", "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>[]>>;
|
|
23
23
|
readonly processSearchResult: (elements: 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>[]>) => {
|
|
24
24
|
results: {
|
|
25
|
-
certainty:
|
|
25
|
+
certainty: LintingResultCertainty.Certain;
|
|
26
26
|
function: Identifier;
|
|
27
27
|
range: SourceRange;
|
|
28
28
|
}[];
|
|
@@ -35,6 +35,7 @@ export declare const DEPRECATED_FUNCTIONS: {
|
|
|
35
35
|
readonly info: {
|
|
36
36
|
readonly name: "Deprecated Functions";
|
|
37
37
|
readonly tags: readonly [LintingRuleTag.Deprecated, LintingRuleTag.Smell, LintingRuleTag.Usability, LintingRuleTag.Reproducibility];
|
|
38
|
+
readonly certainty: LintingRuleCertainty.BestEffort;
|
|
38
39
|
readonly description: "Marks deprecated functions that should not be used anymore.";
|
|
39
40
|
readonly defaultConfig: {
|
|
40
41
|
readonly deprecatedFunctions: readonly ["all_equal", "arrange_all", "distinct_all", "filter_all", "group_by_all", "summarise_all", "mutate_all", "select_all", "vars", "all_vars", "id", "failwith", "select_vars", "rename_vars", "select_var", "current_vars", "bench_tbls", "compare_tbls", "compare_tbls2", "eval_tbls", "eval_tbls2", "location", "changes", "combine", "do", "funs", "add_count_", "add_tally_", "arrange_", "count_", "distinct_", "do_", "filter_", "funs_", "group_by_", "group_indices_", "mutate_", "tally_", "transmute_", "rename_", "rename_vars_", "select_", "select_vars_", "slice_", "summarise_", "summarize_", "summarise_each", "src_local", "tbl_df", "add_rownames", "group_nest", "group_split", "with_groups", "nest_by", "progress_estimated", "recode", "sample_n", "top_n", "transmute", "fct_explicit_na", "aes_", "aes_auto", "annotation_logticks", "is.Coord", "coord_flip", "coord_map", "is.facet", "fortify", "is.ggproto", "guide_train", "is.ggplot", "qplot", "is.theme", "gg_dep", "liply", "isplit2", "list_along", "cross", "invoke", "at_depth", "prepend", "rerun", "splice", "`%@%`", "rbernoulli", "rdunif", "when", "update_list", "map_raw", "accumulate", "reduce_right", "flatten", "map_dfr", "as_vector", "transpose", "melt_delim", "melt_fwf", "melt_table", "read_table2", "str_interp", "as_tibble", "data_frame", "tibble_", "data_frame_", "lst_", "as_data_frame", "as.tibble", "frame_data", "trunc_mat", "is.tibble", "tidy_names", "set_tidy_names", "repair_names", "extract_numeric", "complete_", "drop_na_", "expand_", "crossing_", "nesting_", "extract_", "fill_", "gather_", "nest_", "separate_rows_", "separate_", "spread_", "unite_", "unnest_", "extract", "gather", "nest_legacy", "separate_rows", "separate", "spread"];
|
|
@@ -35,7 +35,7 @@ exports.DEPRECATED_FUNCTIONS = {
|
|
|
35
35
|
});
|
|
36
36
|
})
|
|
37
37
|
.map(element => ({
|
|
38
|
-
certainty: linter_format_1.
|
|
38
|
+
certainty: linter_format_1.LintingResultCertainty.Certain,
|
|
39
39
|
function: element.target,
|
|
40
40
|
range: element.range
|
|
41
41
|
})),
|
|
@@ -49,6 +49,8 @@ exports.DEPRECATED_FUNCTIONS = {
|
|
|
49
49
|
info: {
|
|
50
50
|
name: 'Deprecated Functions',
|
|
51
51
|
tags: [linter_tags_1.LintingRuleTag.Deprecated, linter_tags_1.LintingRuleTag.Smell, linter_tags_1.LintingRuleTag.Usability, linter_tags_1.LintingRuleTag.Reproducibility],
|
|
52
|
+
// ensures all deprecated functions found are actually deprecated through its limited config, but doesn't find all deprecated functions since the config is pre-crawled
|
|
53
|
+
certainty: linter_format_1.LintingRuleCertainty.BestEffort,
|
|
52
54
|
description: 'Marks deprecated functions that should not be used anymore.',
|
|
53
55
|
defaultConfig: {
|
|
54
56
|
deprecatedFunctions: ['all_equal', 'arrange_all', 'distinct_all', 'filter_all', 'group_by_all', 'summarise_all', 'mutate_all', 'select_all', 'vars', 'all_vars', 'id', 'failwith', 'select_vars', 'rename_vars', 'select_var', 'current_vars', 'bench_tbls', 'compare_tbls', 'compare_tbls2', 'eval_tbls', 'eval_tbls2', 'location', 'changes', 'combine', 'do', 'funs', 'add_count_', 'add_tally_', 'arrange_', 'count_', 'distinct_', 'do_', 'filter_', 'funs_', 'group_by_', 'group_indices_', 'mutate_', 'tally_', 'transmute_', 'rename_', 'rename_vars_', 'select_', 'select_vars_', 'slice_', 'summarise_', 'summarize_', 'summarise_each', 'src_local', 'tbl_df', 'add_rownames', 'group_nest', 'group_split', 'with_groups', 'nest_by', 'progress_estimated', 'recode', 'sample_n', 'top_n', 'transmute', 'fct_explicit_na', 'aes_', 'aes_auto', 'annotation_logticks', 'is.Coord', 'coord_flip', 'coord_map', 'is.facet', 'fortify', 'is.ggproto', 'guide_train', 'is.ggplot', 'qplot', 'is.theme', 'gg_dep', 'liply', 'isplit2', 'list_along', 'cross', 'invoke', 'at_depth', 'prepend', 'rerun', 'splice', '`%@%`', 'rbernoulli', 'rdunif', 'when', 'update_list', 'map_raw', 'accumulate', 'reduce_right', 'flatten', 'map_dfr', 'as_vector', 'transpose', 'melt_delim', 'melt_fwf', 'melt_table', 'read_table2', 'str_interp', 'as_tibble', 'data_frame', 'tibble_', 'data_frame_', 'lst_', 'as_data_frame', 'as.tibble', 'frame_data', 'trunc_mat', 'is.tibble', 'tidy_names', 'set_tidy_names', 'repair_names', 'extract_numeric', 'complete_', 'drop_na_', 'expand_', 'crossing_', 'nesting_', 'extract_', 'fill_', 'gather_', 'nest_', 'separate_rows_', 'separate_', 'spread_', 'unite_', 'unnest_', 'extract', 'gather', 'nest_legacy', 'separate_rows', 'separate', 'spread',]
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { LintingResult } from '../linter-format';
|
|
2
|
+
import { LintingRuleCertainty } from '../linter-format';
|
|
2
3
|
import type { MergeableRecord } from '../../util/objects';
|
|
3
4
|
import type { SourceRange } from '../../util/range';
|
|
4
|
-
import type { ParentInformation } from '../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
5
|
-
import type { FlowrSearchElementFromQuery } from '../../search/flowr-search';
|
|
6
5
|
import type { FunctionInfo } from '../../queries/catalog/dependencies-query/function-info/function-info';
|
|
7
6
|
import { LintingRuleTag } from '../linter-tags';
|
|
8
7
|
export interface FilePathValidityResult extends LintingResult {
|
|
@@ -32,8 +31,8 @@ export interface FilePathValidityMetadata extends MergeableRecord {
|
|
|
32
31
|
totalValid: number;
|
|
33
32
|
}
|
|
34
33
|
export declare const FILE_PATH_VALIDITY: {
|
|
35
|
-
readonly createSearch: (config: FilePathValidityConfig) => import("../../search/flowr-search-builder").FlowrSearchBuilder<"from-query", [], ParentInformation, import("../../search/flowr-search").FlowrSearchElements<ParentInformation,
|
|
36
|
-
readonly processSearchResult: (elements: import("../../search/flowr-search").FlowrSearchElements<ParentInformation,
|
|
34
|
+
readonly createSearch: (config: FilePathValidityConfig) => import("../../search/flowr-search-builder").FlowrSearchBuilder<"from-query", ["with"], 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>[]>>;
|
|
35
|
+
readonly processSearchResult: (elements: 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>[]>, config: FilePathValidityConfig, data: {
|
|
37
36
|
normalize: import("../../r-bridge/lang-4.x/ast/model/processing/decorate").NormalizedAst;
|
|
38
37
|
dataflow: import("../../dataflow/info").DataflowInformation;
|
|
39
38
|
config: import("../../config").FlowrConfigOptions;
|
|
@@ -44,6 +43,7 @@ export declare const FILE_PATH_VALIDITY: {
|
|
|
44
43
|
readonly info: {
|
|
45
44
|
readonly name: "File Path Validity";
|
|
46
45
|
readonly description: "Checks whether file paths used in read and write operations are valid and point to existing files.";
|
|
46
|
+
readonly certainty: LintingRuleCertainty.BestEffort;
|
|
47
47
|
readonly tags: readonly [LintingRuleTag.Robustness, LintingRuleTag.Reproducibility, LintingRuleTag.Bug];
|
|
48
48
|
readonly defaultConfig: {
|
|
49
49
|
readonly additionalReadFunctions: readonly [];
|
|
@@ -10,9 +10,9 @@ const logic_1 = require("../../util/logic");
|
|
|
10
10
|
const retriever_1 = require("../../r-bridge/retriever");
|
|
11
11
|
const read_functions_1 = require("../../queries/catalog/dependencies-query/function-info/read-functions");
|
|
12
12
|
const write_functions_1 = require("../../queries/catalog/dependencies-query/function-info/write-functions");
|
|
13
|
-
const extract_cfg_1 = require("../../control-flow/extract-cfg");
|
|
14
13
|
const happens_before_1 = require("../../control-flow/happens-before");
|
|
15
14
|
const linter_tags_1 = require("../linter-tags");
|
|
15
|
+
const search_enrichers_1 = require("../../search/search-executor/search-enrichers");
|
|
16
16
|
exports.FILE_PATH_VALIDITY = {
|
|
17
17
|
createSearch: (config) => flowr_search_builder_1.Q.fromQuery({
|
|
18
18
|
type: 'dependencies',
|
|
@@ -20,9 +20,9 @@ exports.FILE_PATH_VALIDITY = {
|
|
|
20
20
|
ignoreDefaultFunctions: true,
|
|
21
21
|
readFunctions: read_functions_1.ReadFunctions.concat(config.additionalReadFunctions),
|
|
22
22
|
writeFunctions: write_functions_1.WriteFunctions.concat(config.additionalWriteFunctions)
|
|
23
|
-
}),
|
|
23
|
+
}).with(search_enrichers_1.Enrichment.CfgInformation),
|
|
24
24
|
processSearchResult: (elements, config, data) => {
|
|
25
|
-
const cfg =
|
|
25
|
+
const cfg = elements.enrichmentContent(search_enrichers_1.Enrichment.CfgInformation).cfg.graph;
|
|
26
26
|
const metadata = {
|
|
27
27
|
totalReads: 0,
|
|
28
28
|
totalUnknown: 0,
|
|
@@ -31,7 +31,7 @@ exports.FILE_PATH_VALIDITY = {
|
|
|
31
31
|
};
|
|
32
32
|
return {
|
|
33
33
|
results: elements.getElements().flatMap(element => {
|
|
34
|
-
const results =
|
|
34
|
+
const results = elements.enrichmentContent(search_enrichers_1.Enrichment.QueryData).queries['dependencies'];
|
|
35
35
|
const matchingRead = results.readData.find(r => r.nodeId == element.node.info.id);
|
|
36
36
|
if (!matchingRead) {
|
|
37
37
|
return [];
|
|
@@ -45,7 +45,7 @@ exports.FILE_PATH_VALIDITY = {
|
|
|
45
45
|
return [{
|
|
46
46
|
range,
|
|
47
47
|
filePath: dependencies_query_format_1.Unknown,
|
|
48
|
-
certainty: linter_format_1.
|
|
48
|
+
certainty: linter_format_1.LintingResultCertainty.Uncertain
|
|
49
49
|
}];
|
|
50
50
|
}
|
|
51
51
|
else {
|
|
@@ -70,7 +70,7 @@ exports.FILE_PATH_VALIDITY = {
|
|
|
70
70
|
return [{
|
|
71
71
|
range,
|
|
72
72
|
filePath: matchingRead.source,
|
|
73
|
-
certainty: writesBefore && writesBefore.length && writesBefore.every(w => w === logic_1.Ternary.Maybe) ? linter_format_1.
|
|
73
|
+
certainty: writesBefore && writesBefore.length && writesBefore.every(w => w === logic_1.Ternary.Maybe) ? linter_format_1.LintingResultCertainty.Uncertain : linter_format_1.LintingResultCertainty.Certain
|
|
74
74
|
}];
|
|
75
75
|
}),
|
|
76
76
|
'.meta': metadata
|
|
@@ -79,6 +79,8 @@ exports.FILE_PATH_VALIDITY = {
|
|
|
79
79
|
info: {
|
|
80
80
|
name: 'File Path Validity',
|
|
81
81
|
description: 'Checks whether file paths used in read and write operations are valid and point to existing files.',
|
|
82
|
+
// checks all found paths for whether they're valid to ensure correctness, but doesn't handle non-constant paths so not all will be returned
|
|
83
|
+
certainty: linter_format_1.LintingRuleCertainty.BestEffort,
|
|
82
84
|
tags: [linter_tags_1.LintingRuleTag.Robustness, linter_tags_1.LintingRuleTag.Reproducibility, linter_tags_1.LintingRuleTag.Bug],
|
|
83
85
|
defaultConfig: {
|
|
84
86
|
additionalReadFunctions: [],
|
|
@@ -2,8 +2,8 @@ import type { DataflowGraph } from '../../dataflow/graph/graph';
|
|
|
2
2
|
import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
3
3
|
import type { MergeableRecord } from '../../util/objects';
|
|
4
4
|
import type { SourceRange } from '../../util/range';
|
|
5
|
-
import type {
|
|
6
|
-
import {
|
|
5
|
+
import type { LintingResult, LintQuickFixReplacement } from '../linter-format';
|
|
6
|
+
import { LintingResultCertainty, LintingRuleCertainty } from '../linter-format';
|
|
7
7
|
import { LintingRuleTag } from '../linter-tags';
|
|
8
8
|
export declare enum CasingConvention {
|
|
9
9
|
CamelCase = "camelCase",
|
|
@@ -46,7 +46,7 @@ export declare const NAMING_CONVENTION: {
|
|
|
46
46
|
}) => {
|
|
47
47
|
results: {
|
|
48
48
|
quickFix: LintQuickFixReplacement[] | undefined;
|
|
49
|
-
certainty:
|
|
49
|
+
certainty: LintingResultCertainty;
|
|
50
50
|
detectedCasing: CasingConvention;
|
|
51
51
|
name: string;
|
|
52
52
|
range: SourceRange;
|
|
@@ -62,6 +62,7 @@ export declare const NAMING_CONVENTION: {
|
|
|
62
62
|
};
|
|
63
63
|
readonly info: {
|
|
64
64
|
readonly name: "Naming Convention";
|
|
65
|
+
readonly certainty: LintingRuleCertainty.OverApproximative;
|
|
65
66
|
readonly description: "Checks wether the symbols conform to a certain naming convention";
|
|
66
67
|
readonly tags: readonly [LintingRuleTag.Style, LintingRuleTag.QuickFix];
|
|
67
68
|
readonly defaultConfig: {
|
|
@@ -132,7 +132,7 @@ exports.NAMING_CONVENTION = {
|
|
|
132
132
|
processSearchResult: (elements, config, data) => {
|
|
133
133
|
const symbols = elements.getElements()
|
|
134
134
|
.map(m => ({
|
|
135
|
-
certainty: linter_format_1.
|
|
135
|
+
certainty: linter_format_1.LintingResultCertainty.Certain,
|
|
136
136
|
detectedCasing: detectCasing(m.node.lexeme),
|
|
137
137
|
name: m.node.lexeme,
|
|
138
138
|
range: m.node.info.fullRange,
|
|
@@ -158,6 +158,8 @@ exports.NAMING_CONVENTION = {
|
|
|
158
158
|
},
|
|
159
159
|
info: {
|
|
160
160
|
name: 'Naming Convention',
|
|
161
|
+
// detects casing heuristically so correctness is not ensured using default config, but checks all identifiers in the code for naming convention match
|
|
162
|
+
certainty: linter_format_1.LintingRuleCertainty.OverApproximative,
|
|
161
163
|
description: 'Checks wether the symbols conform to a certain naming convention',
|
|
162
164
|
tags: [linter_tags_1.LintingRuleTag.Style, linter_tags_1.LintingRuleTag.QuickFix],
|
|
163
165
|
defaultConfig: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { LintingResult } from '../linter-format';
|
|
2
|
-
import {
|
|
2
|
+
import { LintingResultCertainty, LintingRuleCertainty } from '../linter-format';
|
|
3
3
|
import type { SourceRange } from '../../util/range';
|
|
4
4
|
import type { MergeableRecord } from '../../util/objects';
|
|
5
5
|
import type { Identifier } from '../../dataflow/environments/identifier';
|
|
@@ -30,14 +30,14 @@ export interface SeededRandomnessMeta extends MergeableRecord {
|
|
|
30
30
|
callsWithNonConstantProducers: number;
|
|
31
31
|
}
|
|
32
32
|
export declare const SEEDED_RANDOMNESS: {
|
|
33
|
-
readonly createSearch: (config: SeededRandomnessConfig) => import("../../search/flowr-search-builder").FlowrSearchBuilder<"all", ["with", "filter", "with"], 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/
|
|
33
|
+
readonly createSearch: (config: SeededRandomnessConfig) => import("../../search/flowr-search-builder").FlowrSearchBuilder<"all", ["with", "filter", "with"], 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>[]>>;
|
|
34
34
|
readonly processSearchResult: (elements: 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>[]>, config: SeededRandomnessConfig, { dataflow }: {
|
|
35
35
|
normalize: import("../../r-bridge/lang-4.x/ast/model/processing/decorate").NormalizedAst;
|
|
36
36
|
dataflow: import("../../dataflow/info").DataflowInformation;
|
|
37
37
|
config: import("../../config").FlowrConfigOptions;
|
|
38
38
|
}) => {
|
|
39
39
|
results: {
|
|
40
|
-
certainty:
|
|
40
|
+
certainty: LintingResultCertainty.Certain;
|
|
41
41
|
function: Identifier;
|
|
42
42
|
range: SourceRange;
|
|
43
43
|
}[];
|
|
@@ -55,6 +55,7 @@ export declare const SEEDED_RANDOMNESS: {
|
|
|
55
55
|
readonly randomnessConsumers: readonly ["jitter", "sample", "sample.int", "arima.sim", "kmeans", "princomp", "rcauchy", "rchisq", "rexp", "rgamma", "rgeom", "rlnorm", "rlogis", "rmultinom", "rnbinom", "rnorm", "rpois", "runif", "pointLabel", "some", "rbernoulli", "rdunif", "generateSeedVectors"];
|
|
56
56
|
};
|
|
57
57
|
readonly tags: readonly [LintingRuleTag.Robustness, LintingRuleTag.Reproducibility];
|
|
58
|
+
readonly certainty: LintingRuleCertainty.BestEffort;
|
|
58
59
|
readonly name: "Seeded Randomness";
|
|
59
60
|
readonly description: "Checks whether randomness-based function calls are preceded by a random seed generation function. For consistent reproducibility, functions that use randomness should only be called after a constant random seed is set using a function like `set.seed`.";
|
|
60
61
|
};
|
|
@@ -86,7 +86,7 @@ exports.SEEDED_RANDOMNESS = {
|
|
|
86
86
|
return true;
|
|
87
87
|
})
|
|
88
88
|
.map(element => ({
|
|
89
|
-
certainty: linter_format_1.
|
|
89
|
+
certainty: linter_format_1.LintingResultCertainty.Certain,
|
|
90
90
|
function: element.target,
|
|
91
91
|
range: element.range
|
|
92
92
|
})),
|
|
@@ -99,6 +99,8 @@ exports.SEEDED_RANDOMNESS = {
|
|
|
99
99
|
randomnessConsumers: ['jitter', 'sample', 'sample.int', 'arima.sim', 'kmeans', 'princomp', 'rcauchy', 'rchisq', 'rexp', 'rgamma', 'rgeom', 'rlnorm', 'rlogis', 'rmultinom', 'rnbinom', 'rnorm', 'rpois', 'runif', 'pointLabel', 'some', 'rbernoulli', 'rdunif', 'generateSeedVectors'],
|
|
100
100
|
},
|
|
101
101
|
tags: [linter_tags_1.LintingRuleTag.Robustness, linter_tags_1.LintingRuleTag.Reproducibility],
|
|
102
|
+
// only finds proper randomness producers and consumers due to its config, but will not find all producers/consumers since not all existing deprecated functions will be in the config
|
|
103
|
+
certainty: linter_format_1.LintingRuleCertainty.BestEffort,
|
|
102
104
|
name: 'Seeded Randomness',
|
|
103
105
|
description: 'Checks whether randomness-based function calls are preceded by a random seed generation function. For consistent reproducibility, functions that use randomness should only be called after a constant random seed is set using a function like `set.seed`.'
|
|
104
106
|
},
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { LintingResult } from '../linter-format';
|
|
2
|
+
import { LintingRuleCertainty } from '../linter-format';
|
|
2
3
|
import type { MergeableRecord } from '../../util/objects';
|
|
3
4
|
import type { SourceRange } from '../../util/range';
|
|
4
5
|
import { LintingRuleTag } from '../linter-tags';
|
|
@@ -34,6 +35,7 @@ export declare const UNUSED_DEFINITION: {
|
|
|
34
35
|
readonly name: "Unused Definitions";
|
|
35
36
|
readonly description: "Checks for unused definitions.";
|
|
36
37
|
readonly tags: readonly [LintingRuleTag.Readability, LintingRuleTag.Smell, LintingRuleTag.QuickFix];
|
|
38
|
+
readonly certainty: LintingRuleCertainty.BestEffort;
|
|
37
39
|
readonly defaultConfig: {
|
|
38
40
|
readonly includeFunctionDefinitions: true;
|
|
39
41
|
};
|
|
@@ -80,7 +80,7 @@ exports.UNUSED_DEFINITION = {
|
|
|
80
80
|
// found an unused definition
|
|
81
81
|
const variableName = element.node.lexeme;
|
|
82
82
|
return [{
|
|
83
|
-
certainty: linter_format_1.
|
|
83
|
+
certainty: linter_format_1.LintingResultCertainty.Uncertain,
|
|
84
84
|
variableName,
|
|
85
85
|
range: element.node.info.fullRange ?? element.node.location ?? (0, range_1.rangeFrom)(-1, -1, -1, -1),
|
|
86
86
|
quickFix: buildQuickFix(element.node, data.dataflow.graph, data.normalize)
|
|
@@ -97,6 +97,8 @@ exports.UNUSED_DEFINITION = {
|
|
|
97
97
|
name: 'Unused Definitions',
|
|
98
98
|
description: 'Checks for unused definitions.',
|
|
99
99
|
tags: [linter_tags_1.LintingRuleTag.Readability, linter_tags_1.LintingRuleTag.Smell, linter_tags_1.LintingRuleTag.QuickFix],
|
|
100
|
+
// our limited analysis causes unused definitions involving complex reflection etc. not to be included in our result, but unused definitions are correctly validated
|
|
101
|
+
certainty: linter_format_1.LintingRuleCertainty.BestEffort,
|
|
100
102
|
defaultConfig: {
|
|
101
103
|
includeFunctionDefinitions: true
|
|
102
104
|
}
|
package/package.json
CHANGED
|
@@ -40,7 +40,12 @@ function executeDependenciesQuery(data, queries) {
|
|
|
40
40
|
const readFunctions = getFunctionsToCheck(query.readFunctions, ignoreDefault, read_functions_1.ReadFunctions);
|
|
41
41
|
const writeFunctions = getFunctionsToCheck(query.writeFunctions, ignoreDefault, write_functions_1.WriteFunctions);
|
|
42
42
|
const numberOfFunctions = libraryFunctions.length + sourceFunctions.length + readFunctions.length + writeFunctions.length;
|
|
43
|
-
const results = numberOfFunctions === 0 ? { kinds: {}, '.meta': { timing: 0 } } : (0, query_1.executeQueriesOfSameType)(data,
|
|
43
|
+
const results = numberOfFunctions === 0 ? { kinds: {}, '.meta': { timing: 0 } } : (0, query_1.executeQueriesOfSameType)(data, [
|
|
44
|
+
makeCallContextQuery(libraryFunctions, 'library'),
|
|
45
|
+
makeCallContextQuery(sourceFunctions, 'source'),
|
|
46
|
+
makeCallContextQuery(readFunctions, 'read'),
|
|
47
|
+
makeCallContextQuery(writeFunctions, 'write')
|
|
48
|
+
].flat());
|
|
44
49
|
function getLexeme(argument, id) {
|
|
45
50
|
if ((argument && argument !== dependencies_query_format_1.Unknown) || !id) {
|
|
46
51
|
return undefined;
|
|
@@ -97,5 +97,6 @@ exports.ReadFunctions = [
|
|
|
97
97
|
{ package: 'stats', name: 'read.ftable', argIdx: 0, argName: 'file', resolveValue: true },
|
|
98
98
|
{ package: 'DBI', name: 'dbReadTable', argIdx: 1, argName: 'name', resolveValue: true },
|
|
99
99
|
{ package: 'DBI', name: 'dbReadTableArrow', argIdx: 1, argName: 'name', resolveValue: true },
|
|
100
|
+
{ package: 'jsonlite', name: 'read_json', argIdx: 0, argName: 'path', resolveValue: true },
|
|
100
101
|
];
|
|
101
102
|
//# sourceMappingURL=read-functions.js.map
|
|
@@ -83,5 +83,6 @@ exports.WriteFunctions = [
|
|
|
83
83
|
{ package: 'rasterpdf', name: 'raster_pdf', argIdx: 0, argName: 'filename', resolveValue: true },
|
|
84
84
|
{ package: 'rasterpdf', name: 'agg_pdf', argIdx: 0, argName: 'filename', resolveValue: true },
|
|
85
85
|
{ package: 'highcharter', name: 'hc_exporting', argName: 'filename', resolveValue: true },
|
|
86
|
+
{ package: 'jsonlite', name: 'write_json', argIdx: 1, argName: 'path', resolveValue: true },
|
|
86
87
|
];
|
|
87
88
|
//# sourceMappingURL=write-functions.js.map
|
|
@@ -33,7 +33,7 @@ exports.LinterQueryDefinition = {
|
|
|
33
33
|
function addLintingRuleResult(ruleName, results, result) {
|
|
34
34
|
const rule = linter_rules_1.LintingRules[ruleName];
|
|
35
35
|
result.push(` ╰ **${rule.info.name}** (${ruleName}):`);
|
|
36
|
-
for (const certainty of [linter_format_1.
|
|
36
|
+
for (const certainty of [linter_format_1.LintingResultCertainty.Certain, linter_format_1.LintingResultCertainty.Uncertain]) {
|
|
37
37
|
const certaintyResults = results.results.filter(r => r.certainty === certainty);
|
|
38
38
|
if (certaintyResults.length) {
|
|
39
39
|
result.push(` ╰ ${certainty}:`);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.executeLocationMapQuery = executeLocationMapQuery;
|
|
4
|
-
const
|
|
4
|
+
const parse_1 = require("../../../slicing/criterion/parse");
|
|
5
|
+
const assert_1 = require("../../../util/assert");
|
|
5
6
|
const fileIdRegex = /^(?<file>.*(\.[rR]))-/;
|
|
6
7
|
function fuzzyFindFile(node, idMap) {
|
|
7
8
|
if (node?.info.file) {
|
|
@@ -22,10 +23,11 @@ function fuzzyFindFile(node, idMap) {
|
|
|
22
23
|
return '<inline>';
|
|
23
24
|
}
|
|
24
25
|
function executeLocationMapQuery({ ast, dataflow: { graph } }, queries) {
|
|
25
|
-
if (queries.length !== 1) {
|
|
26
|
-
log_1.log.warn('Id-Map query expects only up to one query, but got', queries.length);
|
|
27
|
-
}
|
|
28
26
|
const start = Date.now();
|
|
27
|
+
const criteriaOfInterest = new Set(queries
|
|
28
|
+
.flatMap(q => q.ids ?? [])
|
|
29
|
+
.map(c => (0, parse_1.tryResolveSliceCriterionToId)(c, ast.idMap))
|
|
30
|
+
.filter(assert_1.isNotUndefined));
|
|
29
31
|
const locationMap = {
|
|
30
32
|
files: {},
|
|
31
33
|
ids: {}
|
|
@@ -38,7 +40,7 @@ function executeLocationMapQuery({ ast, dataflow: { graph } }, queries) {
|
|
|
38
40
|
count++;
|
|
39
41
|
}
|
|
40
42
|
for (const [id, node] of ast.idMap.entries()) {
|
|
41
|
-
if (node.location) {
|
|
43
|
+
if (node.location && (criteriaOfInterest.size === 0 || criteriaOfInterest.has(id))) {
|
|
42
44
|
const file = fuzzyFindFile(node, ast.idMap);
|
|
43
45
|
locationMap.ids[id] = [
|
|
44
46
|
inverseMap.get(file) ?? -1,
|
|
@@ -4,8 +4,11 @@ import { type OutputFormatter } from '../../../util/text/ansi';
|
|
|
4
4
|
import Joi from 'joi';
|
|
5
5
|
import type { NodeId } from '../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
6
6
|
import type { SourceRange } from '../../../util/range';
|
|
7
|
+
import type { SingleSlicingCriterion } from '../../../slicing/criterion/parse';
|
|
7
8
|
export interface LocationMapQuery extends BaseQueryFormat {
|
|
8
9
|
readonly type: 'location-map';
|
|
10
|
+
/** Optional list of ids to filter the results by. If not provided, all ids will be included. */
|
|
11
|
+
readonly ids?: readonly SingleSlicingCriterion[];
|
|
9
12
|
}
|
|
10
13
|
export type FileId = number & {
|
|
11
14
|
readonly __fileId?: unique symbol;
|
|
@@ -23,6 +23,7 @@ exports.LocationMapQueryDefinition = {
|
|
|
23
23
|
},
|
|
24
24
|
schema: joi_1.default.object({
|
|
25
25
|
type: joi_1.default.string().valid('location-map').required().description('The type of the query.'),
|
|
26
|
+
ids: joi_1.default.array().items(joi_1.default.string()).optional().description('Optional list of ids to filter the results by.')
|
|
26
27
|
}).description('The location map query retrieves the location of every id in the ast.'),
|
|
27
28
|
flattenInvolvedNodes: () => []
|
|
28
29
|
};
|
|
@@ -9,7 +9,7 @@ function executeSearch({ ast, dataflow, config }, queries) {
|
|
|
9
9
|
const { search } = query;
|
|
10
10
|
results.push({
|
|
11
11
|
ids: (0, flowr_search_executor_1.runSearch)(search, { normalize: ast, dataflow, config })
|
|
12
|
-
.map(({ node }) => node.info.id),
|
|
12
|
+
.getElements().map(({ node }) => node.info.id),
|
|
13
13
|
search
|
|
14
14
|
});
|
|
15
15
|
}
|
|
@@ -7,6 +7,7 @@ const reconstruct_1 = require("../../../reconstruct/reconstruct");
|
|
|
7
7
|
const auto_select_defaults_1 = require("../../../reconstruct/auto-select/auto-select-defaults");
|
|
8
8
|
const magic_comments_1 = require("../../../reconstruct/auto-select/magic-comments");
|
|
9
9
|
const log_1 = require("../../../util/log");
|
|
10
|
+
const _00_slice_1 = require("../../../core/steps/all/static-slicing/00-slice");
|
|
10
11
|
function fingerPrintOfQuery(query) {
|
|
11
12
|
return JSON.stringify(query);
|
|
12
13
|
}
|
|
@@ -20,7 +21,7 @@ function executeStaticSliceQuery({ dataflow: { graph }, ast, config }, queries)
|
|
|
20
21
|
}
|
|
21
22
|
const { criteria, noReconstruction, noMagicComments } = query;
|
|
22
23
|
const sliceStart = Date.now();
|
|
23
|
-
const slice = (0, static_slicer_1.
|
|
24
|
+
const slice = (0, static_slicer_1.staticSlice)(graph, ast, criteria, query.direction ?? _00_slice_1.SliceDirection.Backward, config.solver.slicer?.threshold);
|
|
24
25
|
const sliceEnd = Date.now();
|
|
25
26
|
if (noReconstruction) {
|
|
26
27
|
results[key] = { slice: { ...slice, '.meta': { timing: sliceEnd - sliceStart } } };
|
|
@@ -4,6 +4,7 @@ import type { DEFAULT_DATAFLOW_PIPELINE, DEFAULT_SLICE_WITHOUT_RECONSTRUCT_PIPEL
|
|
|
4
4
|
import type { SlicingCriteria } from '../../../slicing/criterion/parse';
|
|
5
5
|
import Joi from 'joi';
|
|
6
6
|
import { executeStaticSliceQuery } from './static-slice-query-executor';
|
|
7
|
+
import { SliceDirection } from '../../../core/steps/all/static-slicing/00-slice';
|
|
7
8
|
import type { NodeId } from '../../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
8
9
|
/** Calculates and returns all clusters encountered in the dataflow graph. */
|
|
9
10
|
export interface StaticSliceQuery extends BaseQueryFormat {
|
|
@@ -14,6 +15,8 @@ export interface StaticSliceQuery extends BaseQueryFormat {
|
|
|
14
15
|
readonly noReconstruction?: boolean;
|
|
15
16
|
/** Should the magic comments (force-including lines within the slice) be ignored? */
|
|
16
17
|
readonly noMagicComments?: boolean;
|
|
18
|
+
/** The direction to slice in. Defaults to backward slicing if unset. */
|
|
19
|
+
readonly direction?: SliceDirection;
|
|
17
20
|
}
|
|
18
21
|
export interface StaticSliceQueryResult extends BaseQueryResult {
|
|
19
22
|
/**
|
|
@@ -9,6 +9,7 @@ const time_1 = require("../../../util/text/time");
|
|
|
9
9
|
const joi_1 = __importDefault(require("joi"));
|
|
10
10
|
const static_slice_query_executor_1 = require("./static-slice-query-executor");
|
|
11
11
|
const query_print_1 = require("../../query-print");
|
|
12
|
+
const _00_slice_1 = require("../../../core/steps/all/static-slicing/00-slice");
|
|
12
13
|
exports.StaticSliceQueryDefinition = {
|
|
13
14
|
executor: static_slice_query_executor_1.executeStaticSliceQuery,
|
|
14
15
|
asciiSummarizer: (formatter, _processed, queryResults, result) => {
|
|
@@ -37,7 +38,8 @@ exports.StaticSliceQueryDefinition = {
|
|
|
37
38
|
type: joi_1.default.string().valid('static-slice').required().description('The type of the query.'),
|
|
38
39
|
criteria: joi_1.default.array().items(joi_1.default.string()).min(0).required().description('The slicing criteria to use.'),
|
|
39
40
|
noReconstruction: joi_1.default.boolean().optional().description('Do not reconstruct the slice into readable code.'),
|
|
40
|
-
noMagicComments: joi_1.default.boolean().optional().description('Should the magic comments (force-including lines within the slice) be ignored?')
|
|
41
|
+
noMagicComments: joi_1.default.boolean().optional().description('Should the magic comments (force-including lines within the slice) be ignored?'),
|
|
42
|
+
direction: joi_1.default.string().valid(...Object.values(_00_slice_1.SliceDirection)).optional().description('The direction to slice in. Defaults to backward slicing if unset.')
|
|
41
43
|
}).description('Slice query used to slice the dataflow graph'),
|
|
42
44
|
flattenInvolvedNodes: (queryResults) => {
|
|
43
45
|
const flattened = [];
|
package/queries/query-print.d.ts
CHANGED
|
@@ -5,4 +5,4 @@ import type { DEFAULT_DATAFLOW_PIPELINE } from '../core/steps/pipeline/default-p
|
|
|
5
5
|
import type { NodeId } from '../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
6
6
|
export declare function asciiCallContext(formatter: OutputFormatter, results: QueryResults<'call-context'>['call-context'], processed: PipelineOutput<typeof DEFAULT_DATAFLOW_PIPELINE>): string;
|
|
7
7
|
export declare function summarizeIdsIfTooLong(formatter: OutputFormatter, ids: readonly NodeId[]): string;
|
|
8
|
-
export declare function asciiSummaryOfQueryResult(formatter: OutputFormatter, totalInMs: number, results: QueryResults<
|
|
8
|
+
export declare function asciiSummaryOfQueryResult<S extends SupportedQueryTypes>(formatter: OutputFormatter, totalInMs: number, results: Awaited<QueryResults<S>>, processed: PipelineOutput<typeof DEFAULT_DATAFLOW_PIPELINE>): string;
|
package/queries/query-print.js
CHANGED
|
@@ -81,7 +81,6 @@ function asciiSummaryOfQueryResult(formatter, totalInMs, results, processed) {
|
|
|
81
81
|
}
|
|
82
82
|
result.push(`Query: ${(0, ansi_1.bold)(query, formatter)}`);
|
|
83
83
|
let timing = -1;
|
|
84
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
85
84
|
for (const [key, value] of Object.entries(queryResults)) {
|
|
86
85
|
if (key === '.meta') {
|
|
87
86
|
timing = value.timing;
|
package/queries/query.d.ts
CHANGED
|
@@ -25,11 +25,20 @@ import type { LinterQuery } from './catalog/linter-query/linter-query-format';
|
|
|
25
25
|
import type { NodeId } from '../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
26
26
|
import type { ControlFlowQuery } from './catalog/control-flow-query/control-flow-query-format';
|
|
27
27
|
import type { DfShapeQuery } from './catalog/df-shape-query/df-shape-query-format';
|
|
28
|
+
import type { AsyncOrSync, AsyncOrSyncType } from 'ts-essentials';
|
|
29
|
+
/**
|
|
30
|
+
* These are all queries that can be executed from within flowR
|
|
31
|
+
* {@link SynchronousQuery} are queries that can be executed synchronously, i.e., they do not return a Promise.
|
|
32
|
+
*/
|
|
28
33
|
export type Query = CallContextQuery | ConfigQuery | SearchQuery | DataflowQuery | ControlFlowQuery | DataflowLensQuery | DfShapeQuery | NormalizedAstQuery | IdMapQuery | DataflowClusterQuery | StaticSliceQuery | LineageQuery | DependenciesQuery | LocationMapQuery | HappensBeforeQuery | ResolveValueQuery | ProjectQuery | OriginQuery | LinterQuery;
|
|
34
|
+
export type SynchronousQuery = Exclude<Query, {
|
|
35
|
+
executor: (query: Query) => Promise<unknown>;
|
|
36
|
+
}>;
|
|
37
|
+
export type SupportedSynchronousQueryTypes = SynchronousQuery['type'];
|
|
29
38
|
export type QueryArgumentsWithType<QueryType extends BaseQueryFormat['type']> = Query & {
|
|
30
39
|
type: QueryType;
|
|
31
40
|
};
|
|
32
|
-
export type QueryExecutor<Query extends BaseQueryFormat, Result extends BaseQueryResult> = (data: BasicQueryData, query: readonly Query[]) => Result
|
|
41
|
+
export type QueryExecutor<Query extends BaseQueryFormat, Result extends BaseQueryResult> = (data: BasicQueryData, query: readonly Query[]) => AsyncOrSync<Result>;
|
|
33
42
|
type SupportedQueries = {
|
|
34
43
|
[QueryType in Query['type']]: SupportedQuery<QueryType>;
|
|
35
44
|
};
|
|
@@ -1008,17 +1017,19 @@ export declare const SupportedQueries: {
|
|
|
1008
1017
|
};
|
|
1009
1018
|
};
|
|
1010
1019
|
export type SupportedQueryTypes = keyof typeof SupportedQueries;
|
|
1011
|
-
export type QueryResult<Type extends Query['type']> = ReturnType<typeof SupportedQueries[Type]['executor']
|
|
1012
|
-
export declare function executeQueriesOfSameType<SpecificQuery extends
|
|
1020
|
+
export type QueryResult<Type extends Query['type']> = AsyncOrSync<ReturnType<typeof SupportedQueries[Type]['executor']>>;
|
|
1021
|
+
export declare function executeQueriesOfSameType<SpecificQuery extends SynchronousQuery>(data: BasicQueryData, queries: readonly SpecificQuery[]): AsyncOrSyncType<QueryResult<SpecificQuery['type']>>;
|
|
1022
|
+
export declare function executeQueriesOfSameType<SpecificQuery extends Query>(data: BasicQueryData, queries: readonly SpecificQuery[]): QueryResult<SpecificQuery['type']>;
|
|
1013
1023
|
export type QueryResults<Base extends SupportedQueryTypes> = {
|
|
1014
|
-
readonly [QueryType in Base]: QueryResult<QueryType
|
|
1024
|
+
readonly [QueryType in Base]: Awaited<QueryResult<QueryType>>;
|
|
1015
1025
|
} & BaseQueryResult;
|
|
1016
1026
|
type OmitFromValues<T, K extends string | number | symbol> = {
|
|
1017
1027
|
[P in keyof T]?: Omit<T[P], K>;
|
|
1018
1028
|
};
|
|
1019
1029
|
export type QueryResultsWithoutMeta<Queries extends Query> = OmitFromValues<Omit<QueryResults<Queries['type']>, '.meta'>, '.meta'>;
|
|
1020
1030
|
export type Queries<Base extends SupportedQueryTypes, VirtualArguments extends VirtualCompoundConstraint<Base> = VirtualCompoundConstraint<Base>> = readonly (QueryArgumentsWithType<Base> | VirtualQueryArgumentsWithType<Base, VirtualArguments>)[];
|
|
1021
|
-
export declare function executeQueries<Base extends
|
|
1031
|
+
export declare function executeQueries<Base extends SupportedSynchronousQueryTypes, VirtualArguments extends VirtualCompoundConstraint<Base> = VirtualCompoundConstraint<Base>>(data: BasicQueryData, queries: Queries<Base, VirtualArguments>): QueryResults<Base>;
|
|
1032
|
+
export declare function executeQueries<Base extends SupportedQueryTypes, VirtualArguments extends VirtualCompoundConstraint<Base> = VirtualCompoundConstraint<Base>>(data: BasicQueryData, queries: Queries<Base, VirtualArguments>): AsyncOrSync<QueryResults<Base>>;
|
|
1022
1033
|
export declare function SupportedQueriesSchema(): Joi.AlternativesSchema<any>;
|
|
1023
1034
|
export declare const CompoundQuerySchema: Joi.ObjectSchema<any>;
|
|
1024
1035
|
export declare function VirtualQuerySchema(): Joi.AlternativesSchema<any>;
|
package/queries/query.js
CHANGED
|
@@ -53,7 +53,7 @@ exports.SupportedQueries = {
|
|
|
53
53
|
'origin': origin_query_format_1.OriginQueryDefinition,
|
|
54
54
|
'linter': linter_query_format_1.LinterQueryDefinition
|
|
55
55
|
};
|
|
56
|
-
function executeQueriesOfSameType(data,
|
|
56
|
+
function executeQueriesOfSameType(data, queries) {
|
|
57
57
|
(0, assert_1.guard)(queries.length > 0, 'At least one query must be provided');
|
|
58
58
|
/* every query must have the same type */
|
|
59
59
|
(0, assert_1.guard)(queries.every(q => q.type === queries[0].type), 'All queries must have the same type');
|
|
@@ -67,9 +67,7 @@ function isVirtualQuery(query) {
|
|
|
67
67
|
function groupQueriesByType(queries) {
|
|
68
68
|
const grouped = {};
|
|
69
69
|
function addQuery(query) {
|
|
70
|
-
|
|
71
|
-
grouped[query.type] = [];
|
|
72
|
-
}
|
|
70
|
+
grouped[query.type] ??= [];
|
|
73
71
|
grouped[query.type].push(query);
|
|
74
72
|
}
|
|
75
73
|
for (const query of queries) {
|
|
@@ -86,17 +84,32 @@ function groupQueriesByType(queries) {
|
|
|
86
84
|
}
|
|
87
85
|
return grouped;
|
|
88
86
|
}
|
|
87
|
+
function isPromiseLike(value) {
|
|
88
|
+
return value !== null && typeof value === 'object' && typeof value.then === 'function';
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* This is the main query execution function that takes a set of queries and executes them on the given data.
|
|
92
|
+
*/
|
|
89
93
|
function executeQueries(data, queries) {
|
|
90
94
|
const now = Date.now();
|
|
91
95
|
const grouped = groupQueriesByType(queries);
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
96
|
+
const entries = Object.entries(grouped);
|
|
97
|
+
const results = entries.map(([type, group]) => [type, executeQueriesOfSameType(data, group)]);
|
|
98
|
+
if (results.length === 0 || results.every(([_, r]) => !isPromiseLike(r))) {
|
|
99
|
+
// all results are synchronous, we can return them directly
|
|
100
|
+
const r = Object.fromEntries(results);
|
|
101
|
+
r['.meta'] = {
|
|
102
|
+
timing: Date.now() - now
|
|
103
|
+
};
|
|
104
|
+
return r;
|
|
95
105
|
}
|
|
96
|
-
results[
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
106
|
+
return Promise.all(results.map(([type, result]) => Promise.resolve(result).then(resolvedResult => [type, resolvedResult]))).then(resultsArray => {
|
|
107
|
+
const results = Object.fromEntries(resultsArray);
|
|
108
|
+
results['.meta'] = {
|
|
109
|
+
timing: Date.now() - now
|
|
110
|
+
};
|
|
111
|
+
return results;
|
|
112
|
+
});
|
|
100
113
|
}
|
|
101
114
|
function SupportedQueriesSchema() {
|
|
102
115
|
return joi_1.default.alternatives(Object.values(exports.SupportedQueries).map(q => q.schema)).description('Supported queries');
|