eslint 8.57.0 → 9.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/README.md +31 -28
  2. package/bin/eslint.js +4 -3
  3. package/conf/ecma-version.js +16 -0
  4. package/conf/globals.js +1 -0
  5. package/conf/rule-type-list.json +3 -1
  6. package/lib/api.js +7 -11
  7. package/lib/cli-engine/cli-engine.js +14 -3
  8. package/lib/cli-engine/formatters/formatters-meta.json +1 -29
  9. package/lib/cli-engine/lint-result-cache.js +2 -2
  10. package/lib/cli.js +115 -36
  11. package/lib/config/default-config.js +3 -0
  12. package/lib/config/flat-config-array.js +110 -24
  13. package/lib/config/flat-config-helpers.js +41 -20
  14. package/lib/config/flat-config-schema.js +1 -7
  15. package/lib/config/rule-validator.js +42 -6
  16. package/lib/eslint/eslint-helpers.js +116 -58
  17. package/lib/eslint/eslint.js +892 -377
  18. package/lib/eslint/index.js +2 -2
  19. package/lib/eslint/legacy-eslint.js +728 -0
  20. package/lib/linter/apply-disable-directives.js +59 -31
  21. package/lib/linter/code-path-analysis/code-path-analyzer.js +0 -1
  22. package/lib/linter/code-path-analysis/code-path.js +32 -30
  23. package/lib/linter/code-path-analysis/fork-context.js +1 -1
  24. package/lib/linter/config-comment-parser.js +8 -11
  25. package/lib/linter/index.js +1 -3
  26. package/lib/linter/interpolate.js +24 -2
  27. package/lib/linter/linter.js +428 -207
  28. package/lib/linter/report-translator.js +3 -3
  29. package/lib/linter/rules.js +6 -15
  30. package/lib/linter/source-code-fixer.js +1 -1
  31. package/lib/linter/timing.js +16 -8
  32. package/lib/options.js +35 -3
  33. package/lib/rule-tester/index.js +3 -1
  34. package/lib/rule-tester/rule-tester.js +424 -347
  35. package/lib/rules/array-bracket-newline.js +1 -1
  36. package/lib/rules/array-bracket-spacing.js +1 -1
  37. package/lib/rules/block-scoped-var.js +1 -1
  38. package/lib/rules/callback-return.js +2 -2
  39. package/lib/rules/camelcase.js +3 -5
  40. package/lib/rules/capitalized-comments.js +10 -7
  41. package/lib/rules/comma-dangle.js +1 -1
  42. package/lib/rules/comma-style.js +2 -2
  43. package/lib/rules/complexity.js +14 -1
  44. package/lib/rules/constructor-super.js +99 -100
  45. package/lib/rules/default-case.js +1 -1
  46. package/lib/rules/eol-last.js +2 -2
  47. package/lib/rules/function-paren-newline.js +2 -2
  48. package/lib/rules/indent-legacy.js +5 -5
  49. package/lib/rules/indent.js +5 -5
  50. package/lib/rules/index.js +1 -2
  51. package/lib/rules/key-spacing.js +2 -2
  52. package/lib/rules/line-comment-position.js +1 -1
  53. package/lib/rules/lines-around-directive.js +2 -2
  54. package/lib/rules/max-depth.js +1 -1
  55. package/lib/rules/max-len.js +3 -3
  56. package/lib/rules/max-lines.js +3 -3
  57. package/lib/rules/max-nested-callbacks.js +1 -1
  58. package/lib/rules/max-params.js +1 -1
  59. package/lib/rules/max-statements.js +1 -1
  60. package/lib/rules/multiline-comment-style.js +7 -7
  61. package/lib/rules/new-cap.js +1 -1
  62. package/lib/rules/newline-after-var.js +1 -1
  63. package/lib/rules/newline-before-return.js +1 -1
  64. package/lib/rules/no-case-declarations.js +13 -1
  65. package/lib/rules/no-constant-binary-expression.js +7 -8
  66. package/lib/rules/no-constant-condition.js +18 -7
  67. package/lib/rules/no-constructor-return.js +2 -2
  68. package/lib/rules/no-dupe-class-members.js +2 -2
  69. package/lib/rules/no-else-return.js +1 -1
  70. package/lib/rules/no-empty-function.js +2 -2
  71. package/lib/rules/no-empty-static-block.js +1 -1
  72. package/lib/rules/no-extend-native.js +1 -2
  73. package/lib/rules/no-extra-semi.js +1 -1
  74. package/lib/rules/no-fallthrough.js +41 -16
  75. package/lib/rules/no-implicit-coercion.js +66 -24
  76. package/lib/rules/no-inner-declarations.js +23 -2
  77. package/lib/rules/no-invalid-regexp.js +1 -1
  78. package/lib/rules/no-invalid-this.js +1 -1
  79. package/lib/rules/no-lone-blocks.js +3 -3
  80. package/lib/rules/no-loss-of-precision.js +1 -1
  81. package/lib/rules/no-misleading-character-class.js +225 -69
  82. package/lib/rules/no-mixed-spaces-and-tabs.js +1 -1
  83. package/lib/rules/no-multiple-empty-lines.js +1 -1
  84. package/lib/rules/no-new-native-nonconstructor.js +1 -1
  85. package/lib/rules/no-new-symbol.js +8 -1
  86. package/lib/rules/no-restricted-globals.js +1 -1
  87. package/lib/rules/no-restricted-imports.js +186 -40
  88. package/lib/rules/no-restricted-modules.js +2 -2
  89. package/lib/rules/no-return-await.js +1 -1
  90. package/lib/rules/no-sequences.js +1 -0
  91. package/lib/rules/no-this-before-super.js +45 -13
  92. package/lib/rules/no-trailing-spaces.js +2 -3
  93. package/lib/rules/no-unneeded-ternary.js +1 -1
  94. package/lib/rules/no-unsafe-optional-chaining.js +1 -1
  95. package/lib/rules/no-unused-private-class-members.js +1 -1
  96. package/lib/rules/no-unused-vars.js +197 -36
  97. package/lib/rules/no-useless-assignment.js +566 -0
  98. package/lib/rules/no-useless-backreference.js +1 -1
  99. package/lib/rules/no-useless-computed-key.js +2 -2
  100. package/lib/rules/no-useless-return.js +7 -2
  101. package/lib/rules/object-curly-spacing.js +3 -3
  102. package/lib/rules/object-property-newline.js +1 -1
  103. package/lib/rules/one-var.js +5 -5
  104. package/lib/rules/padded-blocks.js +7 -7
  105. package/lib/rules/prefer-arrow-callback.js +3 -3
  106. package/lib/rules/prefer-reflect.js +1 -1
  107. package/lib/rules/prefer-regex-literals.js +1 -1
  108. package/lib/rules/prefer-template.js +1 -1
  109. package/lib/rules/radix.js +2 -2
  110. package/lib/rules/semi-style.js +1 -1
  111. package/lib/rules/sort-imports.js +1 -1
  112. package/lib/rules/sort-keys.js +1 -1
  113. package/lib/rules/sort-vars.js +1 -1
  114. package/lib/rules/space-unary-ops.js +1 -1
  115. package/lib/rules/strict.js +1 -1
  116. package/lib/rules/use-isnan.js +101 -7
  117. package/lib/rules/utils/ast-utils.js +16 -7
  118. package/lib/rules/utils/char-source.js +240 -0
  119. package/lib/rules/utils/lazy-loading-rule-map.js +1 -1
  120. package/lib/rules/utils/unicode/index.js +9 -4
  121. package/lib/rules/yield-star-spacing.js +1 -1
  122. package/lib/shared/runtime-info.js +1 -0
  123. package/lib/shared/serialization.js +55 -0
  124. package/lib/shared/stats.js +30 -0
  125. package/lib/shared/string-utils.js +9 -11
  126. package/lib/shared/types.js +35 -1
  127. package/lib/source-code/index.js +3 -1
  128. package/lib/source-code/source-code.js +299 -85
  129. package/lib/source-code/token-store/backward-token-cursor.js +3 -3
  130. package/lib/source-code/token-store/cursors.js +4 -2
  131. package/lib/source-code/token-store/forward-token-comment-cursor.js +3 -3
  132. package/lib/source-code/token-store/forward-token-cursor.js +3 -3
  133. package/lib/source-code/token-store/index.js +2 -2
  134. package/lib/unsupported-api.js +3 -5
  135. package/messages/no-config-found.js +1 -1
  136. package/messages/plugin-conflict.js +1 -1
  137. package/messages/plugin-invalid.js +1 -1
  138. package/messages/plugin-missing.js +1 -1
  139. package/package.json +32 -29
  140. package/conf/config-schema.js +0 -93
  141. package/lib/cli-engine/formatters/checkstyle.js +0 -60
  142. package/lib/cli-engine/formatters/compact.js +0 -60
  143. package/lib/cli-engine/formatters/jslint-xml.js +0 -41
  144. package/lib/cli-engine/formatters/junit.js +0 -82
  145. package/lib/cli-engine/formatters/tap.js +0 -95
  146. package/lib/cli-engine/formatters/unix.js +0 -58
  147. package/lib/cli-engine/formatters/visualstudio.js +0 -63
  148. package/lib/cli-engine/xml-escape.js +0 -34
  149. package/lib/eslint/flat-eslint.js +0 -1155
  150. package/lib/rule-tester/flat-rule-tester.js +0 -1131
  151. package/lib/rules/require-jsdoc.js +0 -122
  152. package/lib/rules/utils/patterns/letters.js +0 -36
  153. package/lib/rules/valid-jsdoc.js +0 -516
  154. package/lib/shared/config-validator.js +0 -347
  155. package/lib/shared/deprecation-warnings.js +0 -58
  156. package/lib/shared/relative-module-resolver.js +0 -50
@@ -15,6 +15,11 @@ const astUtils = require("./utils/ast-utils");
15
15
  // Typedefs
16
16
  //------------------------------------------------------------------------------
17
17
 
18
+ /**
19
+ * A simple name for the types of variables that this rule supports
20
+ * @typedef {'array-destructure'|'catch-clause'|'parameter'|'variable'} VariableType
21
+ */
22
+
18
23
  /**
19
24
  * Bag of data used for formatting the `unusedVar` lint message.
20
25
  * @typedef {Object} UnusedVarMessageData
@@ -23,6 +28,13 @@ const astUtils = require("./utils/ast-utils");
23
28
  * @property {string} additional Any additional info to be appended at the end.
24
29
  */
25
30
 
31
+ /**
32
+ * Bag of data used for formatting the `usedIgnoredVar` lint message.
33
+ * @typedef {Object} UsedIgnoredVarMessageData
34
+ * @property {string} varName The name of the unused var.
35
+ * @property {string} additional Any additional info to be appended at the end.
36
+ */
37
+
26
38
  //------------------------------------------------------------------------------
27
39
  // Rule Definition
28
40
  //------------------------------------------------------------------------------
@@ -70,6 +82,12 @@ module.exports = {
70
82
  },
71
83
  destructuredArrayIgnorePattern: {
72
84
  type: "string"
85
+ },
86
+ ignoreClassWithStaticInitBlock: {
87
+ type: "boolean"
88
+ },
89
+ reportUsedIgnorePattern: {
90
+ type: "boolean"
73
91
  }
74
92
  },
75
93
  additionalProperties: false
@@ -79,7 +97,8 @@ module.exports = {
79
97
  ],
80
98
 
81
99
  messages: {
82
- unusedVar: "'{{varName}}' is {{action}} but never used{{additional}}."
100
+ unusedVar: "'{{varName}}' is {{action}} but never used{{additional}}.",
101
+ usedIgnoredVar: "'{{varName}}' is marked as ignored but is used{{additional}}."
83
102
  }
84
103
  },
85
104
 
@@ -92,7 +111,9 @@ module.exports = {
92
111
  vars: "all",
93
112
  args: "after-used",
94
113
  ignoreRestSiblings: false,
95
- caughtErrors: "none"
114
+ caughtErrors: "all",
115
+ ignoreClassWithStaticInitBlock: false,
116
+ reportUsedIgnorePattern: false
96
117
  };
97
118
 
98
119
  const firstOption = context.options[0];
@@ -105,6 +126,8 @@ module.exports = {
105
126
  config.args = firstOption.args || config.args;
106
127
  config.ignoreRestSiblings = firstOption.ignoreRestSiblings || config.ignoreRestSiblings;
107
128
  config.caughtErrors = firstOption.caughtErrors || config.caughtErrors;
129
+ config.ignoreClassWithStaticInitBlock = firstOption.ignoreClassWithStaticInitBlock || config.ignoreClassWithStaticInitBlock;
130
+ config.reportUsedIgnorePattern = firstOption.reportUsedIgnorePattern || config.reportUsedIgnorePattern;
108
131
 
109
132
  if (firstOption.varsIgnorePattern) {
110
133
  config.varsIgnorePattern = new RegExp(firstOption.varsIgnorePattern, "u");
@@ -124,6 +147,50 @@ module.exports = {
124
147
  }
125
148
  }
126
149
 
150
+ /**
151
+ * Gets a given variable's description and configured ignore pattern
152
+ * based on the provided variableType
153
+ * @param {VariableType} variableType a simple name for the types of variables that this rule supports
154
+ * @throws {Error} (Unreachable)
155
+ * @returns {[string | undefined, string | undefined]} the given variable's description and
156
+ * ignore pattern
157
+ */
158
+ function getVariableDescription(variableType) {
159
+ let pattern;
160
+ let variableDescription;
161
+
162
+ switch (variableType) {
163
+ case "array-destructure":
164
+ pattern = config.destructuredArrayIgnorePattern;
165
+ variableDescription = "elements of array destructuring";
166
+ break;
167
+
168
+ case "catch-clause":
169
+ pattern = config.caughtErrorsIgnorePattern;
170
+ variableDescription = "args";
171
+ break;
172
+
173
+ case "parameter":
174
+ pattern = config.argsIgnorePattern;
175
+ variableDescription = "args";
176
+ break;
177
+
178
+ case "variable":
179
+ pattern = config.varsIgnorePattern;
180
+ variableDescription = "vars";
181
+ break;
182
+
183
+ default:
184
+ throw new Error(`Unexpected variable type: ${variableType}`);
185
+ }
186
+
187
+ if (pattern) {
188
+ pattern = pattern.toString();
189
+ }
190
+
191
+ return [variableDescription, pattern];
192
+ }
193
+
127
194
  /**
128
195
  * Generates the message data about the variable being defined and unused,
129
196
  * including the ignore pattern if configured.
@@ -131,27 +198,42 @@ module.exports = {
131
198
  * @returns {UnusedVarMessageData} The message data to be used with this unused variable.
132
199
  */
133
200
  function getDefinedMessageData(unusedVar) {
134
- const defType = unusedVar.defs && unusedVar.defs[0] && unusedVar.defs[0].type;
135
- let type;
136
- let pattern;
201
+ const def = unusedVar.defs && unusedVar.defs[0];
202
+ let additionalMessageData = "";
137
203
 
138
- if (defType === "CatchClause" && config.caughtErrorsIgnorePattern) {
139
- type = "args";
140
- pattern = config.caughtErrorsIgnorePattern.toString();
141
- } else if (defType === "Parameter" && config.argsIgnorePattern) {
142
- type = "args";
143
- pattern = config.argsIgnorePattern.toString();
144
- } else if (defType !== "Parameter" && config.varsIgnorePattern) {
145
- type = "vars";
146
- pattern = config.varsIgnorePattern.toString();
147
- }
204
+ if (def) {
205
+ let pattern;
206
+ let variableDescription;
148
207
 
149
- const additional = type ? `. Allowed unused ${type} must match ${pattern}` : "";
208
+ switch (def.type) {
209
+ case "CatchClause":
210
+ if (config.caughtErrorsIgnorePattern) {
211
+ [variableDescription, pattern] = getVariableDescription("catch-clause");
212
+ }
213
+ break;
214
+
215
+ case "Parameter":
216
+ if (config.argsIgnorePattern) {
217
+ [variableDescription, pattern] = getVariableDescription("parameter");
218
+ }
219
+ break;
220
+
221
+ default:
222
+ if (config.varsIgnorePattern) {
223
+ [variableDescription, pattern] = getVariableDescription("variable");
224
+ }
225
+ break;
226
+ }
227
+
228
+ if (pattern && variableDescription) {
229
+ additionalMessageData = `. Allowed unused ${variableDescription} must match ${pattern}`;
230
+ }
231
+ }
150
232
 
151
233
  return {
152
234
  varName: unusedVar.name,
153
235
  action: "defined",
154
- additional
236
+ additional: additionalMessageData
155
237
  };
156
238
  }
157
239
 
@@ -162,19 +244,51 @@ module.exports = {
162
244
  * @returns {UnusedVarMessageData} The message data to be used with this unused variable.
163
245
  */
164
246
  function getAssignedMessageData(unusedVar) {
165
- const def = unusedVar.defs[0];
166
- let additional = "";
247
+ const def = unusedVar.defs && unusedVar.defs[0];
248
+ let additionalMessageData = "";
249
+
250
+ if (def) {
251
+ let pattern;
252
+ let variableDescription;
167
253
 
168
- if (config.destructuredArrayIgnorePattern && def && def.name.parent.type === "ArrayPattern") {
169
- additional = `. Allowed unused elements of array destructuring patterns must match ${config.destructuredArrayIgnorePattern.toString()}`;
170
- } else if (config.varsIgnorePattern) {
171
- additional = `. Allowed unused vars must match ${config.varsIgnorePattern.toString()}`;
254
+ if (def.name.parent.type === "ArrayPattern" && config.destructuredArrayIgnorePattern) {
255
+ [variableDescription, pattern] = getVariableDescription("array-destructure");
256
+ } else if (config.varsIgnorePattern) {
257
+ [variableDescription, pattern] = getVariableDescription("variable");
258
+ }
259
+
260
+ if (pattern && variableDescription) {
261
+ additionalMessageData = `. Allowed unused ${variableDescription} must match ${pattern}`;
262
+ }
172
263
  }
173
264
 
174
265
  return {
175
266
  varName: unusedVar.name,
176
267
  action: "assigned a value",
177
- additional
268
+ additional: additionalMessageData
269
+ };
270
+ }
271
+
272
+ /**
273
+ * Generate the warning message about a variable being used even though
274
+ * it is marked as being ignored.
275
+ * @param {Variable} variable eslint-scope variable object
276
+ * @param {VariableType} variableType a simple name for the types of variables that this rule supports
277
+ * @returns {UsedIgnoredVarMessageData} The message data to be used with
278
+ * this used ignored variable.
279
+ */
280
+ function getUsedIgnoredMessageData(variable, variableType) {
281
+ const [variableDescription, pattern] = getVariableDescription(variableType);
282
+
283
+ let additionalMessageData = "";
284
+
285
+ if (pattern && variableDescription) {
286
+ additionalMessageData = `. Used ${variableDescription} must not match ${pattern}`;
287
+ }
288
+
289
+ return {
290
+ varName: variable.name,
291
+ additional: additionalMessageData
178
292
  };
179
293
  }
180
294
 
@@ -218,7 +332,7 @@ module.exports = {
218
332
  function hasRestSibling(node) {
219
333
  return node.type === "Property" &&
220
334
  node.parent.type === "ObjectPattern" &&
221
- REST_PROPERTY_TYPE.test(node.parent.properties[node.parent.properties.length - 1].type);
335
+ REST_PROPERTY_TYPE.test(node.parent.properties.at(-1).type);
222
336
  }
223
337
 
224
338
  /**
@@ -323,7 +437,7 @@ module.exports = {
323
437
  }
324
438
 
325
439
  if (parent.type === "SequenceExpression") {
326
- const isLastExpression = parent.expressions[parent.expressions.length - 1] === node;
440
+ const isLastExpression = parent.expressions.at(-1) === node;
327
441
 
328
442
  if (!isLastExpression) {
329
443
  return true;
@@ -392,7 +506,7 @@ module.exports = {
392
506
  while (parent && isInside(parent, rhsNode)) {
393
507
  switch (parent.type) {
394
508
  case "SequenceExpression":
395
- if (parent.expressions[parent.expressions.length - 1] !== node) {
509
+ if (parent.expressions.at(-1) !== node) {
396
510
  return false;
397
511
  }
398
512
  break;
@@ -527,8 +641,13 @@ module.exports = {
527
641
  * @private
528
642
  */
529
643
  function isUsedVariable(variable) {
530
- const functionNodes = getFunctionDefinitions(variable),
531
- isFunctionDefinition = functionNodes.length > 0;
644
+ if (variable.eslintUsed) {
645
+ return true;
646
+ }
647
+
648
+ const functionNodes = getFunctionDefinitions(variable);
649
+ const isFunctionDefinition = functionNodes.length > 0;
650
+
532
651
  let rhsNode = null;
533
652
 
534
653
  return variable.references.some(ref => {
@@ -584,8 +703,13 @@ module.exports = {
584
703
  continue;
585
704
  }
586
705
 
587
- // skip function expression names and variables marked with markVariableAsUsed()
588
- if (scope.functionExpressionScope || variable.eslintUsed) {
706
+ // skip function expression names
707
+ if (scope.functionExpressionScope) {
708
+ continue;
709
+ }
710
+
711
+ // skip variables marked with markVariableAsUsed()
712
+ if (!config.reportUsedIgnorePattern && variable.eslintUsed) {
589
713
  continue;
590
714
  }
591
715
 
@@ -610,9 +734,25 @@ module.exports = {
610
734
  config.destructuredArrayIgnorePattern &&
611
735
  config.destructuredArrayIgnorePattern.test(def.name.name)
612
736
  ) {
737
+ if (config.reportUsedIgnorePattern && isUsedVariable(variable)) {
738
+ context.report({
739
+ node: def.name,
740
+ messageId: "usedIgnoredVar",
741
+ data: getUsedIgnoredMessageData(variable, "array-destructure")
742
+ });
743
+ }
744
+
613
745
  continue;
614
746
  }
615
747
 
748
+ if (type === "ClassName") {
749
+ const hasStaticBlock = def.node.body.body.some(node => node.type === "StaticBlock");
750
+
751
+ if (config.ignoreClassWithStaticInitBlock && hasStaticBlock) {
752
+ continue;
753
+ }
754
+ }
755
+
616
756
  // skip catch variables
617
757
  if (type === "CatchClause") {
618
758
  if (config.caughtErrors === "none") {
@@ -621,11 +761,17 @@ module.exports = {
621
761
 
622
762
  // skip ignored parameters
623
763
  if (config.caughtErrorsIgnorePattern && config.caughtErrorsIgnorePattern.test(def.name.name)) {
764
+ if (config.reportUsedIgnorePattern && isUsedVariable(variable)) {
765
+ context.report({
766
+ node: def.name,
767
+ messageId: "usedIgnoredVar",
768
+ data: getUsedIgnoredMessageData(variable, "catch-clause")
769
+ });
770
+ }
771
+
624
772
  continue;
625
773
  }
626
- }
627
-
628
- if (type === "Parameter") {
774
+ } else if (type === "Parameter") {
629
775
 
630
776
  // skip any setter argument
631
777
  if ((def.node.parent.type === "Property" || def.node.parent.type === "MethodDefinition") && def.node.parent.kind === "set") {
@@ -639,6 +785,14 @@ module.exports = {
639
785
 
640
786
  // skip ignored parameters
641
787
  if (config.argsIgnorePattern && config.argsIgnorePattern.test(def.name.name)) {
788
+ if (config.reportUsedIgnorePattern && isUsedVariable(variable)) {
789
+ context.report({
790
+ node: def.name,
791
+ messageId: "usedIgnoredVar",
792
+ data: getUsedIgnoredMessageData(variable, "parameter")
793
+ });
794
+ }
795
+
642
796
  continue;
643
797
  }
644
798
 
@@ -650,6 +804,14 @@ module.exports = {
650
804
 
651
805
  // skip ignored variables
652
806
  if (config.varsIgnorePattern && config.varsIgnorePattern.test(def.name.name)) {
807
+ if (config.reportUsedIgnorePattern && isUsedVariable(variable)) {
808
+ context.report({
809
+ node: def.name,
810
+ messageId: "usedIgnoredVar",
811
+ data: getUsedIgnoredMessageData(variable, "variable")
812
+ });
813
+ }
814
+
653
815
  continue;
654
816
  }
655
817
  }
@@ -688,7 +850,7 @@ module.exports = {
688
850
  let referenceToReport;
689
851
 
690
852
  if (writeReferences.length > 0) {
691
- referenceToReport = writeReferences[writeReferences.length - 1];
853
+ referenceToReport = writeReferences.at(-1);
692
854
  }
693
855
 
694
856
  context.report({
@@ -713,6 +875,5 @@ module.exports = {
713
875
  }
714
876
  }
715
877
  };
716
-
717
878
  }
718
879
  };