feat(nix): lint let binding order

This commit was merged in pull request #59.
This commit is contained in:
alexion committed 2026-09-16 18:13:35 -04:00
1 parent 7b09cea3af
commit 885124c240
8 files changed
+467 -24

No files matched your search

+148
View File
@@ -19,6 +19,154 @@ fn malformed_file_reports_parse_error() {
"{}:1:9: parse-error: unexpected TOKEN_SEMICOLON at 8..9",
workspace.path("broken.nix").display()
)));
assert!(!output.stdout.contains("let-order"));
}
#[test]
fn forward_reference_reports_let_order() {
let workspace = TestWorkspace::new("forward_reference_reports_let_order");
let path = workspace.write(
"forward.nix",
"let\n app = package;\n package = \"hello\";\nin app\n",
);
let output = run_linter(&[path]);
assert_eq!(output.status, RunStatus::Diagnostics);
assert_eq!(output.stderr, "");
assert_eq!(
output.stdout,
format!(
"{}:2:3: let-order: `app` references later let binding `package`\n",
workspace.path("forward.nix").display()
)
);
}
#[test]
fn dependency_ordered_bindings_exit_clean() {
let workspace = TestWorkspace::new("dependency_ordered_bindings_exit_clean");
let path = workspace.write(
"ordered.nix",
"let\n package = \"hello\";\n app = package;\nin app\n",
);
let output = run_linter(&[path]);
assert_eq!(output.status, RunStatus::Clean);
assert_eq!(output.stdout, "");
assert_eq!(output.stderr, "");
}
#[test]
fn outer_scope_reference_exits_clean() {
let workspace = TestWorkspace::new("outer_scope_reference_exits_clean");
let path = workspace.write(
"outer.nix",
"let\n package = \"hello\";\nin\nlet\n app = package;\nin app\n",
);
let output = run_linter(&[path]);
assert_eq!(output.status, RunStatus::Clean);
assert_eq!(output.stdout, "");
assert_eq!(output.stderr, "");
}
#[test]
fn nested_lambda_parameter_shadows_later_binding() {
let workspace = TestWorkspace::new("nested_lambda_parameter_shadows_later_binding");
let path = workspace.write(
"lambda.nix",
"let\n call = package: package;\n package = \"hello\";\nin call\n",
);
let output = run_linter(&[path]);
assert_eq!(output.status, RunStatus::Clean);
assert_eq!(output.stdout, "");
assert_eq!(output.stderr, "");
}
#[test]
fn nested_let_binding_shadows_later_binding() {
let workspace = TestWorkspace::new("nested_let_binding_shadows_later_binding");
let path = workspace.write(
"nested-let.nix",
"let\n app = let package = \"inner\"; in package;\n package = \"outer\";\nin app\n",
);
let output = run_linter(&[path]);
assert_eq!(output.status, RunStatus::Clean);
assert_eq!(output.stdout, "");
assert_eq!(output.stderr, "");
}
#[test]
fn earlier_sibling_constant_shared_by_multiple_bindings_exits_clean() {
let workspace = TestWorkspace::new("earlier_sibling_constant_shared_by_multiple_bindings");
let path = workspace.write(
"shared.nix",
"let\n package = \"hello\";\n app = package;\n shell = package;\nin [ app shell ]\n",
);
let output = run_linter(&[path]);
assert_eq!(output.status, RunStatus::Clean);
assert_eq!(output.stdout, "");
assert_eq!(output.stderr, "");
}
#[test]
fn previous_line_suppression_disables_let_order() {
let workspace = TestWorkspace::new("previous_line_suppression_disables_let_order");
let path = workspace.write(
"suppressed.nix",
"let\n # nix-style-linter: disable-next-line let-order -- intentional recursion\n app = package;\n package = app;\nin app\n",
);
let output = run_linter(&[path]);
assert_eq!(output.status, RunStatus::Clean);
assert_eq!(output.stdout, "");
assert_eq!(output.stderr, "");
}
#[test]
fn malformed_suppression_does_not_disable_let_order() {
let workspace = TestWorkspace::new("malformed_suppression_does_not_disable_let_order");
let path = workspace.write(
"unsuppressed.nix",
"let\n # nix-style-linter: disable-next-line let-order\n app = package;\n package = \"hello\";\nin app\n",
);
let output = run_linter(&[path]);
assert_eq!(output.status, RunStatus::Diagnostics);
assert_eq!(
output.stdout,
format!(
"{}:3:3: let-order: `app` references later let binding `package`\n",
workspace.path("unsuppressed.nix").display()
)
);
assert_eq!(output.stderr, "");
}
#[test]
fn unsupported_binding_syntax_is_skipped() {
let workspace = TestWorkspace::new("unsupported_binding_syntax_is_skipped");
let path = workspace.write(
"unsupported.nix",
"let\n attrs.value = package;\n inherit package;\n package = \"hello\";\nin attrs\n",
);
let output = run_linter(&[path]);
assert_eq!(output.status, RunStatus::Clean);
assert_eq!(output.stdout, "");
assert_eq!(output.stderr, "");
}
#[test]