Skip to content

Commit 1725496

Browse files
committed
README: Add installation and linter documentation.
Update documentation on how to use Zulint. Describe RuleList, Rule and how to properly write them. Recommend pip for installation.
1 parent 8cb430b commit 1725496

File tree

1 file changed

+132
-5
lines changed

1 file changed

+132
-5
lines changed

README.md

+132-5
Original file line numberDiff line numberDiff line change
@@ -93,17 +93,144 @@ run the hook from outside Vagrant).
9393

9494
## Adding zulint to a codebase
9595

96-
TODO. Will roughly include `pip install zulint`, copying an example
97-
`lint` script, and adding your rules.
96+
TODO: Make a pypi release
9897

98+
Add `zulint` to your codebase requirements file or just do:
99+
100+
```
101+
pip install zulint
102+
```
103+
104+
See [example-lint](./example-lint) file for a simple example of adding zulint to
105+
your codebase. For a more advanced usage example, you can look at
106+
[Zulip's linter](https://github.com/zulip/zulip/blob/master/tools/lint).
107+
108+
**NOTE**
109+
110+
* Remember to mark your lint file executable using:
111+
112+
```bash
113+
> chmod +x <YOUR LINT FILE>
114+
```
115+
116+
* Add `<YOUR LINTER VARIABLE NAME>.do_lint()` add the end of your lint file.
99117

100118
## Adding third-party linters
101119

102-
TODO: Document the linter_config API.
120+
First import the `LinterConfig` and initialize it with default arguments.
121+
You can then use the `external_linter` method to register the linter.
122+
123+
eg:
124+
125+
```python
126+
import argparse
127+
from zulint.command import add_default_linter_arguments, LinterConfig
128+
parser = argparse.ArgumentParser()
129+
# Add custom parser arguments here.
130+
131+
add_default_linter_arguments(parser)
132+
args = parser.parse_args()
133+
134+
linter_config = LinterConfig(args)
135+
136+
# Add your external litner:
137+
linter_config.external_linter('eslint', ['node', 'node_modules/.bin/eslint',
138+
'--quiet', '--cache', '--ext', '.js,.ts'], ['js', 'ts'],
139+
fix_arg='--fix',
140+
description="Standard JavaScript style and formatting linter"
141+
"(config: .eslintrc).")
142+
143+
linter_config.do_lint()
144+
```
145+
146+
Please make sure external linter (here `eslint`) is accessible via bash or in the
147+
virtual env where this linter will run.
103148

104149
## Writing custom rules
105150

106-
TODO: Document all the features of the `RuleList` and `custom_check` system.
151+
You can write your own custom rules for any language using regular expression
152+
in zulint. Doing it is very simple and there are tons of examples available
153+
in [Zulip's custom_check.py file](https://github.com/zulip/zulip/blob/master/tools/linter_lib/custom_check.py).
154+
155+
In the [above example](#adding-third-party-linters) you can add custom rules via `@linter_config.lint` decorator.
156+
For eg:
157+
158+
```python
159+
160+
from zulint.custom_rules import RuleList
161+
162+
@linter_config.lint
163+
def check_custom_rules():
164+
# type: () -> int
165+
"""Check trailing whitespace for specified files"""
166+
trailing_whitespace_rule = RuleList(
167+
langs=file_types,
168+
rules=[{
169+
'pattern': r'\s+$',
170+
'strip': '\n',
171+
'description': 'Fix trailing whitespace'
172+
}]
173+
)
174+
failed = trailing_whitespace_rule.check(by_lang, verbose=args.verbose)
175+
return 1 if failed else 0
176+
```
177+
178+
#### RuleList
179+
A new custom rule is defined via the `RuleList` class. `RuleList` takes the following arguments:
180+
181+
```python
182+
langs # The languages this rule will run on. eg: ['py', 'bash']
183+
rules # List of custom `Rule`s to run. See definition of Rule below for more details.
184+
max_length # Set a max length value for each line in the files. eg: 79
185+
length_exclude # List of files to exclude from `max_length` limit. eg: ["README"]
186+
shebang_rules # List of shebang `Rule`s to run in `langs`. Default: []
187+
exclude_files_in # Directory to exclude from all rules. eg: 'app/' Default: None
188+
exclude_max_length_fns # List of file names to exclude from max_length limit. eg: [test, example] Defautl: []
189+
exclude_max_length_line_patterns # List of line patterns to exclude from max_length limit. eg: ["`\{\{ api_url \}\}[^`]+`"]
190+
```
191+
192+
#### Rule
193+
A rule is a python dictionary containing regular expression,
194+
which will be run on each line in the `langs`' files specified in the `RuleList`.
195+
It has a lot of additional features which you can use to run the pattern in
196+
specific areas of your codebase.
197+
198+
Find below all the keys that a `Rule` can have along with the
199+
type of inputs they take.
200+
201+
```python
202+
Rule = TypedDict("Rule", {
203+
"bad_lines": List[str],
204+
"description": str,
205+
"exclude": Set[str],
206+
"exclude_line": Set[Tuple[str, str]],
207+
"exclude_pattern": str,
208+
"good_lines": List[str],
209+
"include_only": Set[str],
210+
"pattern": str,
211+
"strip": str,
212+
"strip_rule": str,
213+
}, total=False)
214+
```
215+
216+
* `pattern` is your regular expression to be run on all the eligible lines (i.e. lines which haven't been excluded by you).
217+
* `description` is the message that will be displayed if a pattern match is found.
218+
* `good_lines` are the list of sample lines which shouldn't match the pattern.
219+
* `bad_lines` are like `good_lines` but they match the pattern.
220+
221+
**NOTE**: `patten` is run on `bad_lines` and `good_lines` and you can use them as an example to tell the developer
222+
what is wrong with their code and how to fix it.
223+
224+
* `exclude` List of folders to exclude.
225+
* `exclude_line` Tuple of filename and pattern to exclude from pattern check.
226+
eg:
227+
228+
```python
229+
('zerver/lib/actions.py', "user_profile.save() # Can't use update_fields because of how the foreign key works.")`
230+
```
231+
232+
* `exclude_pattern`: pattern to exclude from the matching patterns.
233+
* `include_only`: `pattern` is only run on these files.
107234

108235
## Development Setup
109236

@@ -112,5 +239,5 @@ Run the following commands in a terminal to install zulint.
112239
git clone [email protected]:zulip/zulint.git
113240
python3 -m venv zulint_env
114241
source zulint_env/bin/activate
115-
python3 setup.py install
242+
pip install -e .
116243
```

0 commit comments

Comments
 (0)