go-jsonnet/linter
Rudo Thomas 1c79f577ba fix: Fix error messages when a comprehension iterates over a non-array.
Problems:
 - When iterating over an empty string in a list comprehension, the
   result is an empty string. This is a bug, it should be an error.
 - When iterating over a non-empty string in a list comprehension, the
   expected and unexpected types in the error message are swapped.
 - Error messages mention "std.flatMap" when object/list comprehensions
   would iterate over a value that is neither array nor string.

```
$ jsonnet --version
Jsonnet commandline interpreter (Go implementation) v0.21.0-rc2
$ jsonnet -e '[a for a in ""]'
""
$ jsonnet -e '[a for a in "b"]'
RUNTIME ERROR: Unexpected type array, expected string
	<cmdline>:1:1-17
	During evaluation
$ jsonnet -e '{[a]: 1 for a in 2}'
RUNTIME ERROR: std.flatMap second param must be array / string, got number
	<cmdline>:1:1-20
	<cmdline>:1:1-20
	During evaluation
$ jsonnet -e '[a for a in 1]'
RUNTIME ERROR: std.flatMap second param must be array / string, got number
	<cmdline>:1:1-15
	During evaluation
```

FWIW, the C++ implementation does not have any of these problems. It
gives:
```
RUNTIME ERROR: In comprehension, can only iterate over array.
```

In the Go implementation comprehensions are desugared to a call to
std.flatMap which does accept a string in the "arr" parameter.

The fix: Desugar comprehensions to a call to a new hidden builtin which
only accepts arrays.
2025-03-21 16:37:59 +00:00
..
internal fix: Fix error messages when a comprehension iterates over a non-array. 2025-03-21 16:37:59 +00:00
testdata Fix linter: using a local in an assertion. (#723) 2024-06-10 21:28:17 +01:00
BUILD.bazel Fix jsonnet-lint bazel build 2022-10-26 13:02:57 +01:00
linter_test.go chore: remove refs to deprecated io/ioutil (#716) 2024-06-10 21:27:07 +01:00
linter.go Add 'importbin' statement 2022-03-03 22:49:02 +00:00
README.md Linter README – replace unicode asterisks 2021-02-21 20:59:24 +01:00

jsonnet-lint

This is a linter for Jsonnet. It is alpha stage, but it should be already useful.

Features

The linter detect the following kinds of issues:

  • "Type" problems, such as:
    • Accessing nonexistent fields
    • Calling a function with a wrong number of arguments or named arguments which do not match the parameters
    • Trying to call a value which is not a function
    • Trying to index a value which is not an object, array or a string
  • Unused variables
  • Endlessly looping constructs, which are always invalid, but often appear as a result of confusion about language semantics (e.g. local x = x + 1)
  • Anything that is statically detected during normal execution, such as syntax errors and undeclared variables.

Usage

jsonnet-lint [options] <filename>

Design

Goals

The purpose of the linter is to aid development by providing quick and clear feedback about simple problems. With that in mind I defined the following goals:

  • It should find common problems, especially the kinds resulting from typos, trivial omissions and issues resulting from misunderstanding of the semantics.
  • It should find problems in the parts of code which are not reached by the tests (especially important due to the lazy evaluation).
  • It must be practical to use with the existing Jsonnet code, without any need for modification.
  • It must be fast enough so it is practical to always run the linter before execution during development. The overhead required to run the linter prior to running the program in real world conditions should be comparable with parsing and desugaring.
  • It must be conservative regarding the reported problems. False negatives are preferable to false positives. False positives are allowed as long as they relate to code which is going to be confusing for humans to read or if they can be worked around easily while preserving readability.
  • Its results must be stable, i.e. trivial changes such as changing the order of variables in local expressions should not change the result nontrivially.
  • It must preserve the abstractions. Validity of the definitions should not depend on their use. In particular calling functions with specific arguments or accessing fields of objects should not cause errors in their definitions.
  • It should be possible to explicitly silence individual errors, so that occasional acknowledged false positives do not distract the users. This is espcially important if a clean pass is enforced in Continuous Integration.

Rules

The above goals naturally lead to the some more specific code-level rules which all analyses must obey:

  • All expressions should be checked, even the provably dead code.
  • Always consider both branches of the if expression possible (even if the condition is trivially always true or always false).
  • Correctness of a function definition should not depend on how it is used. In particular when analyzing the definition assume that function arguments can take arbitrary values.
  • Correctness of an object definition should not depend on how it is used. In particular when analyzing the definition assume that the object may be part of an arbitrary inheritance chain