Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
c097974
feat(lint): add structure for deprectaed args - #1870
gigalasr Jul 9, 2026
9116b6e
feat(lint): only detect when deprectaed arg is present - #1870
gigalasr Jul 9, 2026
05e92b8
feat(lint): allow new metadata in functions as well - #1870
gigalasr Jul 10, 2026
a43d0bc
feat(lint): pretty print new deprecation info - #1870
gigalasr Jul 10, 2026
493606b
feat(lint): use source location of arg - #1870
gigalasr Jul 10, 2026
5efa7cc
Merge remote-tracking branch 'origin/main' into 1870-deprecated-args-…
gigalasr Jul 10, 2026
e59b179
Merge remote-tracking branch 'origin/main' into 1870-deprecated-args-…
gigalasr Jul 16, 2026
b4a79ba
feat-fix(lint): use new RRange util - #1870
gigalasr Jul 16, 2026
ae5965b
docs(eval): describe interface and deprecation state - #1870
gigalasr Jul 16, 2026
314adc7
feat(dep): cleaner config - #1870
gigalasr Jul 23, 2026
1172cd3
Merge remote-tracking branch 'origin/main' into 1870-deprecated-args-…
gigalasr Jul 23, 2026
2c89bc7
feat(dep): support for version checking - #1870
gigalasr Jul 24, 2026
118a07d
Merge remote-tracking branch 'origin/main' into 1870-deprecated-args-…
gigalasr Jul 24, 2026
6f0049e
feat(dep): version check for functions #1870
gigalasr Jul 24, 2026
e36782b
feat(lint): ifValue support for deprecated args - #1870
gigalasr Jul 24, 2026
7a80a2a
Merge remote-tracking branch 'origin/main' into 1870-deprecated-args-…
gigalasr Aug 6, 2026
6bb30fc
lint(linter): eslint fixes - #1870
gigalasr Aug 6, 2026
fa811e5
feat(lint): use identifier - #1870
gigalasr Aug 6, 2026
ae6c74f
feat(lint): try to fix derrived range - #1870
gigalasr Aug 7, 2026
f69a89b
Merge remote-tracking branch 'origin/main' into 1870-deprecated-args-…
gigalasr Aug 7, 2026
8d9cbfd
feat(depr): use guess-dep querry - #1870
gigalasr Aug 7, 2026
f05e5e0
Merge remote-tracking branch 'origin/main' into 1870-deprecated-args-…
gigalasr Aug 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
195 changes: 185 additions & 10 deletions src/linter/rules/deprecated-functions.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,194 @@
import { LintingRuleCertainty, type LintingRule } from '../linter-format';
import type { Range } from 'semver';
import type { BrandedIdentifier } from '../../dataflow/environments/identifier';
import { FunctionArgument } from '../../dataflow/graph/graph';
import { isFunctionCallVertex } from '../../dataflow/graph/vertex';
import { EmptyArgument } from '../../r-bridge/lang-4.x/ast/model/nodes/r-function-call';
import { Enrichment, enrichmentContent } from '../../search/search-executor/search-enrichers';
import { isNotUndefined } from '../../util/assert';
import type { MergeableRecord } from '../../util/objects';
import { SourceLocation } from '../../util/range';
import type { LintingResult, LintingRule } from '../linter-format';
import { LintingPrettyPrintContext, LintingResultCertainty, LintingRuleCertainty } from '../linter-format';
import { LintingRuleTag } from '../linter-tags';
import { type FunctionsMetadata, type FunctionsResult, type FunctionsToDetectConfig, functionFinderUtil } from './function-finder-util';
import { type FunctionsMetadata, functionFinderUtil } from './function-finder-util';
import { parseRRange } from '../../util/r-version';

/**
* Information about an argument of a function that should be flagged as deprecated if it is called with this argument
*/
export interface DeprecatedArgumentInformation {
argIdx?: number,
argName?: string
ifValue?: RegExp | string
replacedBy?: string
Comment thread
gigalasr marked this conversation as resolved.
Outdated
sinceVersion?: Range
state?: DeprecationState
}

/**
* Information about a deprecated function
*/
export interface DeprecatedFunctionInformation {
name: string
/** Used to mark specific arguments as deprecated */
whenArgs?: DeprecatedArgumentInformation[]
Comment thread
gigalasr marked this conversation as resolved.
Outdated
replacedBy?: string
sinceVersion?: Range
state?: DeprecationState
}

export interface DeprecatedFunctionResultBase extends LintingResult {
Comment thread
gigalasr marked this conversation as resolved.
function: BrandedIdentifier
Comment thread
gigalasr marked this conversation as resolved.
Outdated
replacedBy?: string
sinceVersion?: Range
state?: DeprecationState
}

export interface DeprecatedFunctionResult extends DeprecatedFunctionResultBase {
type: 'deprecated-function'
}

export interface DeprecatedArgumentResult extends DeprecatedFunctionResultBase {
type: 'deprecated-argument'
arg: string | number
}

export type DeprecatedFunctionRuleResult = DeprecatedFunctionResult | DeprecatedArgumentResult;

export enum DeprecationState {
/** Still works, but marked for removal */
Deprecated = 'deprecated',
Comment thread
gigalasr marked this conversation as resolved.
/** No longer works, and marked for removal */
Defunct = 'defunct',
/** Replaced by another function but kept for compatibility */
Superseeded = 'superseeded'
}

export interface DeprecatedFunctionsConfig extends MergeableRecord{
/** Functions to mark as deprecated */
fns: (string | DeprecatedFunctionInformation)[]
Comment thread
gigalasr marked this conversation as resolved.
Outdated
}


const DeprecatedFunctions = [
{ name: 'geom_violin', whenArgs: [{ argName: 'draw_quantiles', state: DeprecationState.Deprecated, replacedBy: 'quantile.linetype', sinceVersion: parseRRange('>= 4.0.0') }] },
'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_', 'arrange1_', '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'
] satisfies (string | DeprecatedFunctionInformation)[];

export const DEPRECATED_FUNCTIONS = {
createSearch: (config) => functionFinderUtil.createSearch(config.fns),
processSearchResult: functionFinderUtil.processSearchResult,
prettyPrint: functionFinderUtil.prettyPrint('deprecated'),
info: {
createSearch: (config) => functionFinderUtil.createSearch(config.fns.map(fn => typeof fn === 'string' ? fn : fn.name)),
processSearchResult: async(elements, config, data) => {
const fnInfosEx = Object.fromEntries(
config.fns
.filter(f => typeof f === 'object')
.map(f => [f.name, f])
Comment thread
gigalasr marked this conversation as resolved.
Outdated
);

const dataflow = (await data.dataflow()).graph;
const idMap = (await data.normalize()).idMap;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could also use the idmap from the graph.


const metadata: FunctionsMetadata = {
totalCalls: 0,
totalFunctionDefinitions: 0
};

const detectedFunctions = elements.getElements().flatMap(e => {
metadata.totalCalls++;
return enrichmentContent(e, Enrichment.CallTargets).targets.map(target => {
metadata.totalFunctionDefinitions++;
const sourceLocation = SourceLocation.fromNode(e.node);
if(sourceLocation !== undefined) {
return {
node: e.node, target: target as BrandedIdentifier, sourceLocation
};
}
});
}).filter(p => isNotUndefined(p));

const results = detectedFunctions.map(e => {
const info = fnInfosEx[e.target];
if(info === undefined) {
// No extra info => function is always marked as deprecated
return [{
type: 'deprecated-function',
certainty: LintingResultCertainty.Certain,
involvedId: e.node.info.id,
loc: e.sourceLocation,
function: e.target,
} satisfies DeprecatedFunctionResult];
} else if(info.whenArgs !== undefined) {
// If whenArgs is set, the function should only be deprecated if it has one of the provided args
return info.whenArgs.map(deprecatedArgInfo => {
const vertex = dataflow.getVertex(e.node.info.id);
if(vertex === undefined || !isFunctionCallVertex(vertex)) {
return undefined;
}

const arg = vertex.args.find((arg, idx) =>
Comment thread
gigalasr marked this conversation as resolved.
Outdated
FunctionArgument.isNamed(arg) && arg.name === deprecatedArgInfo.argName ||
FunctionArgument.isPositional(arg) && idx === deprecatedArgInfo.argIdx
);
const argNode = arg === undefined || arg === EmptyArgument ? undefined : idMap.get(arg.nodeId);

if(argNode !== undefined) {
return {
type: 'deprecated-argument',
certainty: LintingResultCertainty.Certain,
involvedId: argNode.info.id,
function: e.target,
arg: (deprecatedArgInfo.argName ?? deprecatedArgInfo.argIdx) as string | number,
Comment thread
gigalasr marked this conversation as resolved.
Outdated
state: deprecatedArgInfo.state,
replacedBy: deprecatedArgInfo.replacedBy,
sinceVersion: deprecatedArgInfo.sinceVersion,
loc: SourceLocation.fromNode(argNode) ?? e.sourceLocation
} satisfies DeprecatedArgumentResult;
}

// Don't mark function as deprecated, if we didn't find any deprecated args
}).filter(p => p !== undefined);
Comment thread
gigalasr marked this conversation as resolved.
Outdated
} else {
// Extra Info but no whenArgs => always marked as deprecated and extra info is provided
return [{
type: 'deprecated-function',
certainty: LintingResultCertainty.Certain,
involvedId: e.node.info.id,
loc: e.sourceLocation,
function: e.target,
state: info.state,
replacedBy: info.replacedBy,
sinceVersion: info.sinceVersion
} satisfies DeprecatedFunctionResult];
}
}).flat();

return {
results, '.meta': metadata
};
},
prettyPrint: {
[LintingPrettyPrintContext.Query]: (result: DeprecatedFunctionRuleResult) => `${result.type === 'deprecated-argument' ? `Argument \`${result.arg}\` of ` : ''}Function \`${result.function}\` at ${SourceLocation.format(result.loc)}`,
[LintingPrettyPrintContext.Full]: (result: DeprecatedFunctionRuleResult) => {
const str: string[] = [];
if(result.type === 'deprecated-argument') {
const argStr = typeof result.arg === 'number' ? `at position \`${result.arg}\`` : result.arg;
str.push(`Argument \`${argStr}\` of`);
}
str.push(`Function \`${result.function}\` is ${result.state ?? 'deprecated'}`);
if(result.sinceVersion) {
str.push(`since version ${result.sinceVersion.format()}`);
Comment thread
gigalasr marked this conversation as resolved.
}
if(result.replacedBy) {
str.push(`and is replaced by \`${result.replacedBy}\``);
}
return str.join(' ');
}
},
info: {
name: 'Deprecated Functions',
tags: [LintingRuleTag.Deprecated, LintingRuleTag.Smell, LintingRuleTag.Usability, LintingRuleTag.Reproducibility],
// 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
certainty: LintingRuleCertainty.BestEffort,
description: 'Marks deprecated functions that should not be used anymore.',
defaultConfig: {
fns: ['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']
}
defaultConfig: { fns: DeprecatedFunctions }
}
} as const satisfies LintingRule<FunctionsResult, FunctionsMetadata, FunctionsToDetectConfig>;
} as const satisfies LintingRule<DeprecatedFunctionRuleResult, FunctionsMetadata, DeprecatedFunctionsConfig>;
2 changes: 1 addition & 1 deletion src/linter/rules/naming-convention.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export function getMostUsedCasing(symbols: { detectedCasing: CasingConvention }[
map.set(symbol.detectedCasing, o + 1);
}

// Return element with most occurances
// Return element with most occurrences
return [...map].reduce((p, c) => p[1] > c[1] ? p : c)[0];
}

Expand Down
8 changes: 3 additions & 5 deletions src/linter/rules/network-functions.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import { LintingResultCertainty, type LintingRule, LintingRuleCertainty } from '../linter-format';
import { functionFinderUtil, type FunctionsMetadata, type FunctionsResult } from './function-finder-util';
import type { FunctionsToDetectConfig, FunctionsMetadata, FunctionsResult } from './function-finder-util';
import { functionFinderUtil } from './function-finder-util';
import { LintingRuleTag } from '../linter-tags';
import type { MergeableRecord } from '../../util/objects';
import { ReadFunctions } from '../../queries/catalog/dependencies-query/function-info/read-functions';
import type { FlowrSearchElement } from '../../search/flowr-search';
import type { ParentInformation } from '../../r-bridge/lang-4.x/ast/model/processing/decorate';
import { Ternary } from '../../util/logic';
import { SourceFunctions } from '../../queries/catalog/dependencies-query/function-info/source-functions';
import { WriteFunctions } from '../../queries/catalog/dependencies-query/function-info/write-functions';

export interface NetworkFunctionsConfig extends MergeableRecord {
/** The list of function names that should be marked in the given context if their arguments match. */
fns: readonly string[]
export interface NetworkFunctionsConfig extends FunctionsToDetectConfig {
/** only trigger if the function's read argument is linked to a value that matches this pattern */
onlyTriggerWithArgument?: RegExp | string
}
Expand Down
4 changes: 3 additions & 1 deletion test/functionality/_helper/linter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ export function controlledPkgDb(pkg: string, exports: readonly string[]): PkgDb
}


type DistributiveOmit<T, K extends keyof T> = T extends unknown ? Omit<T, K> : never;

/**
* Asserts correct linting results while ignoring each linting result's {@link LintingRuleResult.involvedId}.
*/
Expand All @@ -52,7 +54,7 @@ export function assertLinter<Name extends LintingRuleNames>(
parser: KnownParser,
code: string,
ruleName: Name,
expected: Omit<LintingRuleResult<Name>, 'involvedId'>[] | ((df: DataflowInformation, ast: NormalizedAst) => Omit<LintingRuleResult<Name>, 'involvedId'>[]),
expected: DistributiveOmit<LintingRuleResult<Name>, 'involvedId'>[] | ((df: DataflowInformation, ast: NormalizedAst) => Omit<LintingRuleResult<Name>, 'involvedId'>[]),
expectedMetadata?: LintingRuleMetadata<Name>,
lintingRuleConfig?: DeepPartial<LintingRuleConfig<Name>> & LinterTestSetup
) {
Expand Down
43 changes: 35 additions & 8 deletions test/functionality/linter/lint-deprecated-functions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { describe } from 'vitest';
import { withTreeSitter } from '../_helper/shell';
import { assertLinter, controlledPkgDb } from '../_helper/linter';
import { LintingResultCertainty } from '../../../src/linter/linter-format';
import { DeprecationState } from '../../../src/linter/rules/deprecated-functions';
import { parseRRange } from '../../../src/util/r-version';

describe('flowR linter', withTreeSitter(parser => {
describe('deprecated functions', () => {
Expand All @@ -14,31 +16,31 @@ describe('flowR linter', withTreeSitter(parser => {
/* Given that we declare `cat` as deprecated, we expect all uses to be marked! */
assertLinter('cat', parser, 'cat("hello")\nprint("hello")\nx <- 1\ncat(x)',
'deprecated-functions', [
{ certainty: LintingResultCertainty.Certain, function: 'cat', loc: [1, 1, 1, 12] },
{ certainty: LintingResultCertainty.Certain, function: 'cat', loc: [4, 1, 4, 6] },
{ certainty: LintingResultCertainty.Certain, function: 'cat', loc: [1, 1, 1, 12], type: 'deprecated-function' },
{ certainty: LintingResultCertainty.Certain, function: 'cat', loc: [4, 1, 4, 6], type: 'deprecated-function' },
],
{ totalCalls: 2, totalFunctionDefinitions: 2 },
{ fns: ['cat'] }
);
/* Overwriting the `cat` function with a user defined implementation (even though it is useless), should cause the linter to not mark calls to the custom `cat` function as deprecated */
assertLinter('custom cat', parser, 'cat("hello")\nprint("hello")\ncat <- function(x) { }\nx <- 1\ncat(x)',
'deprecated-functions', [
{ certainty: LintingResultCertainty.Certain, function: 'cat', loc: [1, 1, 1, 12] }
{ certainty: LintingResultCertainty.Certain, function: 'cat', loc: [1, 1, 1, 12], type: 'deprecated-function' }
],
{ totalCalls: 1, totalFunctionDefinitions: 1 },
{ fns: ['cat'] }
);
/* Using the default linter configuration, a function such as `all_equal` should be marked as deprecated */
assertLinter('with defaults', parser, 'all_equal(foo)',
'deprecated-functions', [
{ certainty: LintingResultCertainty.Certain, function: 'all_equal', loc: [1, 1, 1, 14] }
{ certainty: LintingResultCertainty.Certain, function: 'all_equal', loc: [1, 1, 1, 14], type: 'deprecated-function' }
],
{ totalCalls: 1, totalFunctionDefinitions: 1 }
);
/* We should find deprecated functions even if they are nested in other function calls */
assertLinter('with defaults nested', parser, 'foo(all_equal(foo))',
'deprecated-functions', [
{ certainty: LintingResultCertainty.Certain, function: 'all_equal', loc: [1, 5, 1, 18] }
{ certainty: LintingResultCertainty.Certain, function: 'all_equal', loc: [1, 5, 1, 18], type: 'deprecated-function' }
],
{ totalCalls: 1, totalFunctionDefinitions: 1 }
);
Expand All @@ -47,23 +49,48 @@ describe('flowR linter', withTreeSitter(parser => {
first <- data.frame(x = c(1, 2, 3), y = c(1, 2, 3))
second <- data.frame(x = c(1, 3, 2), y = c(1, 3, 2))
dplyr::all_equal(first, second)`, 'deprecated-functions',
[{ certainty: LintingResultCertainty.Certain, function: 'dplyr::all_equal', loc: [4, 1, 4, 31] }],
[{ certainty: LintingResultCertainty.Certain, function: 'dplyr::all_equal', loc: [4, 1, 4, 31], type: 'deprecated-function' }],
{ totalCalls: 1, totalFunctionDefinitions: 1 });

describe('a deprecated function resolved via a loaded package is still flagged', () => {
// regression: the loaded-package export must still count as a built-in call target
assertLinter('with a (controlled) package database', parser, 'library(dplyr)\nrecode(x)',
'deprecated-functions',
[{ certainty: LintingResultCertainty.Certain, function: 'recode', loc: [2, 1, 2, 9] }],
[{ certainty: LintingResultCertainty.Certain, function: 'recode', loc: [2, 1, 2, 9], type: 'deprecated-function' }],
{ totalCalls: 1, totalFunctionDefinitions: 1 },
{ fns: ['recode'], pkgDb: controlledPkgDb('dplyr', ['recode', 'filter']) }
);
assertLinter('without any package database', parser, 'library(dplyr)\nrecode(x)',
'deprecated-functions',
[{ certainty: LintingResultCertainty.Certain, function: 'recode', loc: [2, 1, 2, 9] }],
[{ certainty: LintingResultCertainty.Certain, function: 'recode', loc: [2, 1, 2, 9], type: 'deprecated-function' }],
{ totalCalls: 1, totalFunctionDefinitions: 1 },
{ fns: ['recode'], noPkgDb: true }
);
});

describe('only detect deprecated args when present', () => {
assertLinter('deprecated arg but not present', parser, 'testFn()',
'deprecated-functions',
[],
{ totalCalls: 1, totalFunctionDefinitions: 1 },
{ fns: [{ name: 'testFn', whenArgs: [{ argName: 'badArg', state: DeprecationState.Deprecated }] } ] }
);

assertLinter('deprecated arg present', parser, 'testFn(badArg=5)',
'deprecated-functions',
[{
type: 'deprecated-argument',
certainty: LintingResultCertainty.Certain,
arg: 'badArg',
replacedBy: 'foo',
function: 'testFn',
state: DeprecationState.Deprecated,
sinceVersion: parseRRange('>= 4.0.0'),
loc: [1, 8, 1, 13]
}],
{ totalCalls: 1, totalFunctionDefinitions: 1 },
{ fns: [{ name: 'testFn', whenArgs: [{ argName: 'badArg', state: DeprecationState.Deprecated, replacedBy: 'foo', sinceVersion: parseRRange('>= 4.0.0') }] } ] }
);
});
});
}));
Loading