Skip to content

match_pattern

v1.2.0WarningFixConfigurableCode Quality

Write your own lint as a regular expression, with a quick fix, in many_lints.yaml.

Use it for the conventions no published lint will ever ship: “call our Clock, not DateTime.now()”, “use context.theme, not Theme.of(context)”, “that helper moved”.

This rule is in no preset and reports nothing until you add patterns:. Every example below shows the configuration that produces it.

analysis_options.yaml
many_lints:
rules:
match_pattern:
patterns:
- find: '^unawaited\((.+)\)$'
replace: '$1.unawaited()'

replace is optional — omit it to report without offering a rewrite.

find is matched against the source text of one call, anchored end to end. $1…$9 in replace are its capture groups.

- find: '^unawaited\((.+)\)$'
replace: '$1.unawaited()'
message: 'Use the trailing form from lib/src/extensions.'
// Don't
unawaited(cart.refresh());
// Do — offered as a quick fix
cart.refresh().unawaited();
- find: '^DateTime\.now\(\)$'
replace: 'clock.now()'
message: 'Inject the Clock seam so tests can freeze time.'
// Don't
final startedAt = DateTime.now();
// Do
final startedAt = clock.now();

Omit replace when the fix needs a human decision:

- find: '^jsonDecode\(.+\)$'
message: 'Parse through ApiCodec so errors are typed.'
// Reported, but nothing is auto-applied
final data = jsonDecode(body);

A call match ends at the closing bracket. To reach .textTheme, match the property instead:

- node: propertyAccess
find: '^Theme\.of\(context\)\.textTheme$'
replace: 'context.textTheme'
// Don't
final titleStyle = Theme.of(context).textTheme;
// Do
final titleStyle = context.textTheme;

in: takes globs, so a convention can be scoped to the layer it belongs to:

- find: '^print\((.+)\)$'
replace: 'logger.debug($1)'
in: ['lib/**'] # leave tool/ and test/ alone
- find: '^formatMoney\((.+), (.+)\)$'
replace: 'Money($1).format($2)'
message: 'formatMoney moved to Money.format in 2.0.'
// Don't
final label = formatMoney(total, locale);
// Do
final label = Money(total).format(locale);
Option Type Default Description
patterns list of entries [] The patterns to match

Per entry:

Key Type Default Description
find string required Regular expression, anchored to the whole node’s source text
replace string — Quick-fix template. $1…$9 are capture groups, $0 the whole match, $$ a literal $. Omit to report only
node string methodInvocation methodInvocation (a call) or propertyAccess (a property read)
message string — Appended to the diagnostic
in list of globs everywhere Limits where the entry applies

Text, not types. unawaited from any library looks identical, so a pattern cannot tell the SDK function from your own helper of the same name.

Formatting counts. A call split across lines will not match a pattern written on one.

Imports are yours. A replacement naming a symbol that is not imported produces code that parses but does not compile.

The fix is never bulk-applied — dart fix --apply will not sweep a hand-written regex across the project — and a replacement that would not parse is dropped rather than offered. A malformed entry (bad regex, unknown node:) is skipped silently, since a plugin cannot report against a YAML file.