Purpose

This page documents the linting policy for dataquieR and the internal QualityIndicatorFunctions (QIF) implementation repository. It complements the dataquieR development policy with the current lintr baseline, the QIF-specific configuration choices, and the linters that are intentionally not enabled.

Configuration

The package lint configuration lives in the internal QIF repository at QualityIndicatorFunctions/.lintr. CI runs the configuration through the lint_qif job using Rscript .lint.R.

Lint results are review feedback for readability, maintainability, and small correctness risks. They must not be applied mechanically when doing so would make the code harder to understand, change semantics, obscure domain-specific names, or introduce noisy global suppressions.

Current baseline

The current baseline enables the low-risk style and correctness checks used by CI, including:

  • 80-character source line length;
  • indentation and brace placement;
  • commented-code detection;
  • object naming with QIF-specific exceptions;
  • sequence and vector-logic checks;
  • assignment style;
  • pipe continuation;
  • pipe consistency.

The current package tree has no findings from the enabled linters. CI exposes future findings as an allowed warning and supplies GitLab with a machine-readable Code Quality report.

Configured linters

Some linters are deliberately configured rather than used with their defaults.

Object names

object_name_linter allows snake case, upper snake case, dataquieR option names, result slot names, metric abbreviations, metadata names, REDCap rule names, S3 methods, JavaScript/DataTables option names, and other package/domain-specific names that are not free to rename.

Do not rename these names just to satisfy a generic style rule. Many of them are part of public APIs, result structures, metadata conventions, external configuration languages, or browser/report integration code.

Object length

object_length_linter(length = 70L) keeps a guardrail against excessive new names. The default 30-character limit is too strict for QIF’s descriptive domain, API, option, and report-slot names, but names above 70 characters should remain exceptional.

Pipe consistency

pipe_consistency_linter(pipe = "%>%") keeps the established magrittr pipe style. Do not mix in native pipes (|>) opportunistically. Migrating all pipelines to the native pipe is a separate semantic style migration and needs review on its own.

Line length

The maximum source line length is 80 characters. Use focused # nolint comments only for local exceptions that would become less readable or less faithful to external/domain-specific text if wrapped.

Condition helpers

Package implementation code should not call base stop(), warning(), or message() directly. Use util_error(), util_warning(), and util_message() instead, so conditions keep their dataquieR classes, metadata, and report/rendering behavior. Direct base calls are legitimate inside the wrapper implementations themselves and in rare compatibility shims with an explicit rationale. QIF includes a source-level test for this rule when the package R/ sources are available.

Disabled linters

Two high-conflict linters remain intentionally disabled.

return_linter

return_linter is deliberately disabled. Explicit return() is allowed when it improves readability, especially for early exits and control-flow-heavy code. In small lambda-like helpers an implicit return often reads better; use judgement rather than a package-wide rule.

object_usage_linter

object_usage_linter is deliberately disabled. This codetools-style linter is similar to R CMD check “no visible binding” warnings. It produces many false positives for non-standard evaluation, data masks, tidy evaluation, generated metadata environments, REDCap/report domain-specific languages, and code such as subset(cars, speed > dist) where names are resolved in a data context.

Prefer local, readable fixes for true findings. Avoid broad utils::globalVariables() suppressions because they can hide real problems and make the check ineffective.

Exception style

Use local # nolint exceptions when a specific line is intentionally outside a generic lint rule. Keep exceptions narrow, name the linter when useful, and prefer prose explanations over commented-out code.

For larger removed code blocks, keep the history in Git rather than in source comments. A short source comment can point to the relevant commit or diff if that history is useful for maintainers.

Deferred work markers

TODO, FIXME, IDEA, and QUESTION comments are permitted only as a short-lived pointer to a tracked work item. Before adding one, create or enrich the relevant issue with enough source context to implement the work: file and function, the relevant code excerpt, the complete multi-line marker text when applicable, and the intended outcome.

Do not use marker comments as an untracked backlog. Remove them when the issue has the needed context, the work is resolved, or the idea is rejected. For a large historical inventory, group related markers under a reviewed umbrella issue rather than creating hundreds of duplicate issues.

QIF CI uses todor to count these four marker types early in lint_qif. The current ceiling is deliberately small; a change that exceeds it must include the corresponding issue work and an explicit review decision.

CI behavior

The lint_qif CI job uploads text, RDS, and GitLab Code Quality artifacts. It is intentionally allow_failure: true, so lint regressions are visible in pipelines but do not block merge requests by themselves.

During dedicated lint-cleanup work it can be useful to make lint_qif fail hard temporarily, so expensive tests do not run behind known lint failures. The default after the cleanup is warning-only linting with visible CI output and Code Quality artifacts.