UNPKG

16 kBJavaScriptView Raw
1/*!
2 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3 * Licensed under the MIT License.
4 */
5
6/**
7 * Shared list of permitted imports for configuring and override the `import/no-internal-modules` rule.
8 */
9const permittedImports = [
10 // Within Fluid Framework allow import of '/internal' from other FF packages.
11 "@fluid-example/*/internal",
12 "@fluid-experimental/*/internal",
13 "@fluid-internal/*/internal",
14 "@fluid-private/*/internal",
15 "@fluid-tools/*/internal",
16 "@fluidframework/*/internal",
17
18 // Experimental package APIs and exports are unknown, so allow any imports from them.
19 "@fluid-experimental/**",
20
21 // Allow imports from sibling and ancestral sibling directories,
22 // but not from cousin directories. Parent is allowed but only
23 // because there isn't a known way to deny it.
24 "*/index.js",
25];
26
27/**
28 * "Minimal" eslint configuration.
29 *
30 * This configuration is primarily intended for use in packages during prototyping / initial setup.
31 * Ideally, all of packages in the fluid-framework repository should derive from either the "Recommended" or
32 * "Strict" configuration.
33 *
34 * Production packages **should not** use this configuration.
35 *
36 * @deprecated This config is too permissive and should not be used. It will be removed in a future release.
37 * Use the "Recommended" or "Strict" configuration instead.
38 *
39 * @privateRemarks TODO: Once this config is ready for deletion, its rules can be moved into `recommended.js`.
40 */
41module.exports = {
42 env: {
43 browser: true,
44 es6: true,
45 es2024: false,
46 node: true,
47 },
48 extends: [
49 "./base",
50 "plugin:eslint-comments/recommended",
51 "plugin:import/errors",
52 "plugin:import/warnings",
53 "plugin:import/typescript",
54 "prettier",
55 ],
56 globals: {
57 Atomics: "readonly",
58 SharedArrayBuffer: "readonly",
59 },
60 parser: "@typescript-eslint/parser",
61 parserOptions: {
62 ecmaFeatures: {
63 jsx: true,
64 },
65 ecmaVersion: 2018,
66 sourceType: "module",
67 project: "./tsconfig.json",
68 },
69 plugins: [
70 // Plugin documentation: https://www.npmjs.com/package/@rushstack/eslint-plugin
71 "@rushstack/eslint-plugin",
72 // Plugin documentation: https://www.npmjs.com/package/@rushstack/eslint-plugin-security
73 "@rushstack/eslint-plugin-security",
74 // Plugin documentation: https://www.npmjs.com/package/@typescript-eslint/eslint-plugin
75 "@typescript-eslint/eslint-plugin",
76 // Plugin documentation: https://www.npmjs.com/package/eslint-plugin-jsdoc
77 "eslint-plugin-jsdoc",
78 // Plugin documentation: https://www.npmjs.com/package/eslint-plugin-promise
79 "eslint-plugin-promise",
80 // Plugin documentation: https://www.npmjs.com/package/eslint-plugin-tsdoc
81 "eslint-plugin-tsdoc",
82 // Plugin documentation: https://www.npmjs.com/package/eslint-plugin-unused-imports
83 "unused-imports",
84 // Plugin documentation: https://www.npmjs.com/package/eslint-plugin-unicorn
85 "unicorn",
86 // Custom ESLint rules
87 "@fluid-internal/eslint-plugin-fluid",
88 ],
89 reportUnusedDisableDirectives: true,
90 ignorePatterns: [
91 // Don't lint generated packageVersion files.
92 "**/packageVersion.ts",
93 ],
94 rules: {
95 /**
96 * Restricts including release tags inside the member class / interface.
97 *
98 * Refer to the rule by the unprefixed plugin name in the consumed package.
99 * {@link https://eslint.org/docs/latest/extend/plugins#rules-in-plugins}
100 */
101 "@fluid-internal/fluid/no-member-release-tags": "error",
102
103 /**
104 * The @rushstack rules are documented in the package README:
105 * {@link https://www.npmjs.com/package/@rushstack/eslint-plugin}
106 */
107 "@rushstack/no-new-null": "warn",
108
109 /**
110 * RATIONALE: Harmless.
111 *
112 * Our guideline is to only use leading underscores on private members when required to avoid a conflict
113 * between private fields and a public property.
114 *
115 * Docs: {@link https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/naming-convention.md}
116 */
117 "@typescript-eslint/naming-convention": [
118 "error",
119 {
120 selector: "accessor",
121 modifiers: ["private"],
122 format: ["camelCase"],
123 leadingUnderscore: "allow",
124 },
125 ],
126
127 /**
128 * Encourages minimal disabling of eslint rules, while still permitting whole-file exclusions.
129 */
130 "eslint-comments/disable-enable-pair": [
131 "error",
132 {
133 allowWholeFile: true,
134 },
135 ],
136
137 // ENABLED INTENTIONALLY
138 "@typescript-eslint/ban-types": "error",
139 "@typescript-eslint/dot-notation": "error",
140 "@typescript-eslint/no-non-null-assertion": "error",
141 "@typescript-eslint/no-unnecessary-type-assertion": "error",
142
143 "eqeqeq": ["error", "smart"],
144 "import/no-deprecated": "error",
145 "max-len": [
146 "error",
147 {
148 code: 120,
149 ignoreTrailingComments: true,
150 ignoreUrls: true,
151 ignoreStrings: true,
152 ignoreTemplateLiterals: true,
153 ignoreRegExpLiterals: true,
154 },
155 ],
156 "no-multi-spaces": [
157 "error",
158 {
159 ignoreEOLComments: true,
160 },
161 ],
162
163 /**
164 * Note: this can be replaced altogether by `@typescript-eslint/no-unused-vars`,
165 * but that rule covers many more scenarios than this one does, and there are many violations
166 * currently in the repository, so it has not been enabled yet.
167 */
168 "unused-imports/no-unused-imports": "error",
169
170 "valid-typeof": "error",
171
172 /**
173 * Catches a common coding mistake where "resolve" and "reject" are confused.
174 */
175 "promise/param-names": "warn",
176
177 "unicorn/better-regex": "error",
178 "unicorn/filename-case": [
179 "error",
180 {
181 cases: {
182 camelCase: true,
183 pascalCase: true,
184 },
185 },
186 ],
187 "unicorn/no-new-buffer": "error",
188 "unicorn/prefer-switch": "error",
189 "unicorn/prefer-ternary": "error",
190 "unicorn/prefer-type-error": "error",
191
192 // #region DISABLED INTENTIONALLY
193
194 /**
195 * Disabled because we don't require that all variable declarations be explicitly typed.
196 */
197 "@rushstack/typedef-var": "off",
198 "@typescript-eslint/explicit-function-return-type": "off",
199 "@typescript-eslint/explicit-member-accessibility": "off",
200
201 /**
202 * Disabled because we will lean on the formatter (i.e. prettier) to enforce indentation policy.
203 */
204 "@typescript-eslint/indent": "off",
205 "@typescript-eslint/member-ordering": "off",
206 "@typescript-eslint/no-explicit-any": "off",
207 "@typescript-eslint/no-unused-vars": "off",
208 "@typescript-eslint/no-use-before-define": "off",
209 "@typescript-eslint/typedef": "off",
210
211 /**
212 * Disabled because we want to encourage documenting different events separately.
213 */
214 "@typescript-eslint/unified-signatures": "off",
215
216 // Requires a lot of changes
217 "@typescript-eslint/no-duplicate-type-constituents": "off",
218
219 // Lots of false positives
220 "@typescript-eslint/non-nullable-type-assertion-style": "off",
221
222 // Requires breaking changes; enabled in the strict config
223 "@typescript-eslint/consistent-indexed-object-style": "off",
224
225 // Requires a lot of changes; enabled in the strict config
226 "@typescript-eslint/no-unsafe-enum-comparison": "off",
227
228 // Requires a lot of changes; enabled in the strict config
229 "@typescript-eslint/no-redundant-type-constituents": "off",
230
231 // Requires a lot of changes; enabled in the strict config
232 "@typescript-eslint/consistent-generic-constructors": "off",
233
234 // Off for minimal and recommended; enabled in the strict config
235 "@typescript-eslint/consistent-type-exports": "off",
236 "@typescript-eslint/consistent-type-imports": "off",
237
238 "func-call-spacing": "off", // Off because it conflicts with typescript-formatter
239 "no-empty": "off",
240 "no-void": "off",
241 "require-atomic-updates": "off",
242
243 /**
244 * Superseded by `@typescript-eslint/dot-notation`.
245 */
246 "dot-notation": "off",
247
248 /**
249 * Superseded by `@typescript-eslint/no-unused-expressions`.
250 */
251 "no-unused-expressions": "off",
252
253 // #endregion
254
255 // #region FORMATTING RULES
256
257 // Disabled because it conflicts with formatter rules
258 "@typescript-eslint/brace-style": "off",
259 "@typescript-eslint/comma-spacing": "error",
260 "@typescript-eslint/func-call-spacing": "error",
261 "@typescript-eslint/keyword-spacing": "error",
262 "@typescript-eslint/member-delimiter-style": [
263 "error",
264 {
265 multiline: {
266 delimiter: "semi",
267 requireLast: true,
268 },
269 singleline: {
270 delimiter: "semi",
271 requireLast: true,
272 },
273 multilineDetection: "brackets",
274 },
275 ],
276 "@typescript-eslint/object-curly-spacing": ["error", "always"],
277 "@typescript-eslint/semi": ["error", "always"],
278 "@typescript-eslint/space-before-function-paren": [
279 "error",
280 {
281 anonymous: "never",
282 asyncArrow: "always",
283 named: "never",
284 },
285 ],
286 "@typescript-eslint/space-infix-ops": "error",
287 "@typescript-eslint/type-annotation-spacing": "error",
288 "array-bracket-spacing": "error",
289 "arrow-spacing": "error",
290 "block-spacing": "error",
291 "dot-location": ["error", "property"],
292 "jsx-quotes": "error",
293 "key-spacing": "error",
294 "space-unary-ops": "error",
295 "switch-colon-spacing": "error",
296
297 // #endregion
298
299 // #region DOCUMENTATION RULES
300
301 /**
302 * This rule ensures that our Intellisense looks good by verifying the TSDoc syntax.
303 */
304 "tsdoc/syntax": "error",
305
306 // #region eslint-plugin-jsdoc rules
307
308 /**
309 * Ensures that conflicting access tags don't exist in the same comment.
310 * See <https://github.com/gajus/eslint-plugin-jsdoc#check-access>.
311 */
312 "jsdoc/check-access": "error",
313
314 /**
315 * Ensures consistent line formatting in JSDoc/TSDoc comments
316 * See <https://github.com/gajus/eslint-plugin-jsdoc#user-content-eslint-plugin-jsdoc-rules-check-alignment>
317 *
318 * TODO: This is temporarily set to "warn" because there are a lot of false positives with code blocks in
319 * particular.
320 */
321 "jsdoc/check-line-alignment": "warn",
322
323 /**
324 * The syntax this validates does not accommodate the syntax used by API-Extractor
325 * See <https://api-extractor.com/pages/tsdoc/tag_example/>
326 */
327 "jsdoc/check-examples": "off",
328
329 /**
330 * Ensures correct indentation within JSDoc/TSDoc comment body
331 * See <https://github.com/gajus/eslint-plugin-jsdoc#user-content-eslint-plugin-jsdoc-rules-check-indentation>
332 */
333 "jsdoc/check-indentation": "error",
334
335 /**
336 * Covered by `tsdoc/syntax`
337 */
338 "jsdoc/check-tag-names": "off",
339
340 /**
341 * Ensures that JSDoc/TSDoc "modifier" tags are empty.
342 * See <https://github.com/gajus/eslint-plugin-jsdoc#user-content-eslint-plugin-jsdoc-rules-empty-tags>
343 */
344 "jsdoc/empty-tags": "error",
345
346 /**
347 * Ensures multi-line formatting meets JSDoc/TSDoc requirements.
348 * See <https://github.com/gajus/eslint-plugin-jsdoc#user-content-eslint-plugin-jsdoc-rules-no-bad-blocks>
349 */
350 "jsdoc/no-bad-blocks": "error",
351
352 /**
353 * Requires that each line in a JSDoc/TSDoc comment starts with a `*`.
354 * See <https://github.com/gajus/eslint-plugin-jsdoc#user-content-eslint-plugin-jsdoc-rules-require-asterisk-prefix>
355 */
356 "jsdoc/require-asterisk-prefix": "error",
357
358 /**
359 * Ensure function/method parameter comments include a `-` between name and description.
360 * Useful to ensure API-Extractor compatability.
361 * See <https://github.com/gajus/eslint-plugin-jsdoc#user-content-eslint-plugin-jsdoc-rules-require-hyphen-before-param-description>.
362 */
363 "jsdoc/require-hyphen-before-param-description": "error",
364
365 /**
366 * Require `@param` tags be non-empty.
367 * See <https://github.com/gajus/eslint-plugin-jsdoc#user-content-eslint-plugin-jsdoc-rules-require-param-description>
368 */
369 "jsdoc/require-param-description": "error",
370
371 /**
372 * Requires `@returns` tags to be non-empty.
373 * See <https://github.com/gajus/eslint-plugin-jsdoc#user-content-eslint-plugin-jsdoc-rules-require-returns-description>
374 */
375 "jsdoc/require-returns-description": "error",
376
377 // #endregion
378
379 // #endregion
380
381 "@typescript-eslint/prefer-includes": "error",
382 "@typescript-eslint/prefer-nullish-coalescing": "error",
383 "@typescript-eslint/prefer-optional-chain": "error",
384
385 /**
386 * By default, libraries should not take dependencies on node libraries.
387 * This rule can be disabled at the project level for libraries that are intended to be used only in node.
388 */
389 "import/no-nodejs-modules": ["error"],
390
391 /**
392 * Allow Fluid Framework to import from its own internal packages.
393 * https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-internal-modules.md
394 */
395 "import/no-internal-modules": [
396 "error",
397 {
398 allow: permittedImports,
399 },
400 ],
401 },
402 overrides: [
403 {
404 // Rules only for TypeScript files
405 files: ["*.ts", "*.tsx"],
406 rules: {
407 "dot-notation": "off", // Superseded by @typescript-eslint/dot-notation
408 "no-unused-expressions": "off", // Superseded by @typescript-eslint/no-unused-expressions
409 },
410 settings: {
411 jsdoc: {
412 mode: "typescript",
413 },
414 },
415 },
416 {
417 // Rules only for React files
418 files: ["*.jsx", "*.tsx"],
419 plugins: [
420 // Plugin documentation: https://www.npmjs.com/package/eslint-plugin-react
421 "react",
422
423 // Plugin documentation: https://www.npmjs.com/package/eslint-plugin-react-hooks
424 "react-hooks",
425 ],
426 extends: ["plugin:react/recommended", "plugin:react-hooks/recommended"],
427 settings: {
428 react: {
429 version: "detect",
430 },
431 },
432 },
433 {
434 // Rules only for test files
435 files: ["*.spec.ts", "*.test.ts", "**/test/**"],
436 rules: {
437 "@typescript-eslint/no-invalid-this": "off",
438 "@typescript-eslint/unbound-method": "off", // This rule has false positives in many of our test projects.
439 "import/no-nodejs-modules": "off", // Node libraries are OK for test files.
440 "import/no-deprecated": "off", // Deprecated APIs are OK to use in test files.
441
442 // Disabled for test files
443 "@typescript-eslint/consistent-type-exports": "off",
444 "@typescript-eslint/consistent-type-imports": "off",
445
446 // For test files only, additionally allow import of '/test*' and '/internal/test*' exports.
447 "import/no-internal-modules": [
448 "error",
449 {
450 allow: ["@fluid*/*/test*", "@fluid*/*/internal/test*"].concat(
451 permittedImports,
452 ),
453 },
454 ],
455 },
456 },
457 ],
458 settings: {
459 "import/extensions": [".ts", ".tsx", ".d.ts", ".js", ".jsx"],
460 "import/parsers": {
461 "@typescript-eslint/parser": [".ts", ".tsx", ".d.ts"],
462 },
463 "import/resolver": {
464 /**
465 * Note: the key order of import/resolver is relevant in the completely resolved eslint config (see ./printed-configs).
466 * Resolvers are tried in key order, and the first one to successfully resolve the import wins. See:
467 * https://github.com/import-js/eslint-plugin-import/blob/c0ac54b8a721c2b1c9048838acc4d6282f4fe7a7/utils/resolve.js#L196
468 *
469 * It's important that the typescript resolver is first, as the node resolver legitimately resolves some imports to modules
470 * with stripped type information, which can cause silent negatives in lint rules. For example, import/no-deprecated fails
471 * to lint against import and usage of deprecated types when the import is resolvable and resolved using the node resolver.
472 */
473 typescript: {
474 extensions: [".ts", ".tsx", ".d.ts", ".js", ".jsx"],
475 conditionNames: [
476 // This supports the test-only conditional export pattern used in merge-tree and id-compressor.
477 "allow-ff-test-exports",
478
479 // Default condition names below, see https://www.npmjs.com/package/eslint-import-resolver-typescript#conditionnames
480 "types",
481 "import",
482
483 // APF: https://angular.io/guide/angular-package-format
484 "esm2020",
485 "es2020",
486 "es2015",
487
488 "require",
489 "node",
490 "node-addons",
491 "browser",
492 "default",
493 ],
494 },
495 },
496 "jsdoc": {
497 // The following are intended to keep js/jsx JSDoc comments in line with TSDoc syntax used in ts/tsx code.
498 tagNamePreference: {
499 arg: {
500 message: "Please use @param instead of @arg.",
501 replacement: "param",
502 },
503 argument: {
504 message: "Please use @param instead of @argument.",
505 replacement: "param",
506 },
507 return: {
508 message: "Please use @returns instead of @return.",
509 replacement: "returns",
510 },
511 },
512 },
513 },
514};