1 | # @fluentui/eslint-plugin
|
2 |
|
3 | **ESLint configuration and custom rules for Fluent UI**
|
4 |
|
5 | ## Configs
|
6 |
|
7 | Usage: in your [ESLint config file](https://eslint.org/docs/user-guide/configuring), add `{ "extends": ["plugin:@fluentui/<name>"] }` or `{ "extends": ["plugin:@fluentui/eslint-plugin/<name>"] }` (the two are equivalent).
|
8 |
|
9 | - `react`: react specific configuration for fluentui vNext
|
10 | - `node`: node specific configuration for fluentui vNext
|
11 | - `react--legacy`: react specific configuration for fluentui v7,8
|
12 | - `node--legacy`: node specific configuration for fluentui v7,8
|
13 | - `react-northstar`: For `@fluentui/react-northstar` and related packages
|
14 | - `imports`: auto import statements sorting configuration
|
15 |
|
16 | Helpers for customizing configuration are exported under a `configHelpers` object.
|
17 |
|
18 | ## Rules
|
19 |
|
20 | ### `ban-context-export`
|
21 |
|
22 | Exporting context objects as a part of the public API can lead to unexpected usages of context by customers and might
|
23 | impede future refactoring. To allow customers use context while encapsulating our internals correctly, the developer
|
24 | should export a provider and hook.
|
25 |
|
26 | **❌ Don't**
|
27 |
|
28 | ```ts
|
29 | // src/context.ts
|
30 | import * as React from 'react';
|
31 | export const MyContext = React.createContext();
|
32 |
|
33 | // src/index.ts
|
34 | export { MyContext } from './context';
|
35 | ```
|
36 |
|
37 | **✅ Do**
|
38 |
|
39 | ```ts
|
40 | // src/context.ts
|
41 | import * as React from 'react';
|
42 | const MyContext = React.createContext();
|
43 | export const MyContextProvider = MyContext.Provider;
|
44 | export const useMyContext = () => React.useContext(MyContext);
|
45 |
|
46 | // src/index.ts
|
47 | export { MyContextProvider, useMyContext } from './context';
|
48 | ```
|
49 |
|
50 | ### `ban-imports`
|
51 |
|
52 | Ban importing or re-exporting from certain paths or modules. You can either ban the entire path, or only certain names. (Inspired by TSLint's [`import-blacklist`](https://palantir.github.io/tslint/rules/import-blacklist/).)
|
53 |
|
54 | Requires one or more options objects. Either `path` or `pathRegex` is required.
|
55 |
|
56 | - `path` (`string`): Path or module to ban importing from (non-regex)
|
57 | - `pathRegex` (`string`): Regex for path or module to ban importing from
|
58 | - `names` (`(string | { regex: string })[]`, optional): If provided, only ban imports of these names and/or regular expressions. Otherwise, ban all imports from the path.
|
59 | - `message` (`string[]`, optional): Custom message to show with errors
|
60 |
|
61 | Example:
|
62 |
|
63 | ```
|
64 | "@fluentui/ban-imports": [
|
65 | "error",
|
66 | { "path": "lodash" },
|
67 | { "path": "foo", "names": ["bar", { "regex": "^baz" }] },
|
68 | { "pathRegex": "^\.", message: "no relative imports" },
|
69 | { "pathRegex": "^\.\./(foo|bar)$", "names": ["baz"] }
|
70 | ]
|
71 | ```
|
72 |
|
73 | ### `deprecated-keyboard-event-props`
|
74 |
|
75 | Prevent using deprecated `KeyboardEvent` props `which` and `keyCode`, and recommend using `@fluentui/keyboard-key` instead.
|
76 |
|
77 | ### `max-len`
|
78 |
|
79 | Enforces max line length, more performantly than [ESLint's `max-len`](https://eslint.org/docs/rules/max-len).
|
80 |
|
81 | This rule is significantly faster than the default `max-len` rule because it **does not** support:
|
82 |
|
83 | - Expanding tabs (only handles spaces for indentation)
|
84 | - Multi-byte unicode characters (they will be counted as multiple characters)
|
85 | - Extra options for handling comments, strings, or URLs
|
86 |
|
87 | (Skipping these extra features lets us do a basic string length check before running any regular expressions or other extra logic, which makes the huge majority of line length checks very fast.)
|
88 |
|
89 | #### Options
|
90 |
|
91 | The rule requires an options object containing:
|
92 |
|
93 | - `max` (required): the maximum line length
|
94 | - `ignorePatterns` (optional): ignore the line if it matches any of these regular expressions
|
95 |
|
96 | ### `no-global-react`
|
97 |
|
98 | Ban references to the `React` global namespace (in favor of explicitly importing React). Implicit global references cause problems for API Extractor and potentially other tools.
|
99 |
|
100 | ### `no-restricted-imports`
|
101 |
|
102 | Prevents imports from `forbidden` packages. If a corresponding `preferred` import is provided, the lint error will be automatically fixable.
|
103 |
|
104 | **Example Configuration:**
|
105 |
|
106 | ```
|
107 | "@fluentui/no-restricted-imports": [
|
108 | 'error',
|
109 | {
|
110 | paths: [
|
111 | {
|
112 | forbidden: ['@fluentui/react-theme', '@griffel/react`],
|
113 | preferred: '@fluentui/react-components',
|
114 | },
|
115 | ],
|
116 | },
|
117 | ],
|
118 | ```
|
119 |
|
120 | **❌ Don't**
|
121 |
|
122 | ```ts
|
123 | import * as React from 'react';
|
124 | import { webDarkTheme } from '@fluentui/react-theme';
|
125 | import { makeStyles } from '@griffel/react';
|
126 | ```
|
127 |
|
128 | **✅ Do**
|
129 |
|
130 | ```ts
|
131 | import * as React from 'react';
|
132 | import { makeStyles, webDarkTheme } from '@fluentui/react-components';
|
133 | ```
|
134 |
|
135 | ### `no-tslint-comments`
|
136 |
|
137 | Ban `tslint:disable` and `tslint:enable` comments.
|
138 |
|
139 | ### `no-visibility-modifiers`
|
140 |
|
141 | Prevent visibility modifiers (`public`, `protected`, `private`) from being specified on class members/methods.
|
142 |
|
143 | Used in Fluent UI only by [`@fluentui/react-northstar`](https://aka.ms/fluent-ui), not `@fluentui/react`.
|
144 |
|
145 | ### `no-context-default-value`
|
146 |
|
147 | Restricts usage of default values on React context creation. Imports should be provided to declare where the `createContext` function is coming from. For more information why this is necessary please consult [#23624](https://github.com/microsoft/fluentui/issues/23624)
|
148 |
|
149 | **Example Configuration:**
|
150 |
|
151 | ```
|
152 | "@fluentui/no-context-default-value": [
|
153 | "error",
|
154 | {
|
155 | imports: ["react", "@fluentui/react-context-selector"]
|
156 | }
|
157 | ]
|
158 | ```
|
159 |
|
160 | **❌ Don't**
|
161 |
|
162 | ```ts
|
163 | import * as React from 'react';
|
164 | const context = React.createContext({ someValue: undefined });
|
165 | ```
|
166 |
|
167 | **✅ Do**
|
168 |
|
169 | ```ts
|
170 | import * as React from 'react';
|
171 | const context = React.createContext(undefined);
|
172 | ```
|
173 |
|
174 | ### `ban-instanceof-html-element`
|
175 |
|
176 | Bans usage of `instanceof HTMLElement` binary expressions as they might cause problems on [multiple realms](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof#instanceof_and_multiple_realms) environments.
|
177 |
|
178 | The alternative is to use `isHTMLElement` helper method provided by `@fluentui/react-utilities` packages, since that method does the proper verifications to ensure proper instance comparison.
|
179 |
|
180 | **❌ Don't**
|
181 |
|
182 | ```ts
|
183 | event.target instanceof HTMLElement;
|
184 |
|
185 | event.target instanceof HTMLInputElement;
|
186 | ```
|
187 |
|
188 | **✅ Do**
|
189 |
|
190 | ```ts
|
191 | import { isHTMLElement } from '@fluentui/react-components';
|
192 |
|
193 | isHTMLElement(event.target);
|
194 |
|
195 | isHTMLElement(event.target, { constructorName: 'HTMLInputElement' });
|
196 | ```
|