eslint 8.13.0 → 8.16.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 (55) hide show
  1. package/README.md +17 -12
  2. package/lib/cli-engine/cli-engine.js +2 -4
  3. package/lib/cli-engine/lint-result-cache.js +1 -1
  4. package/lib/linter/code-path-analysis/code-path-segment.js +1 -1
  5. package/lib/linter/code-path-analysis/code-path-state.js +1 -1
  6. package/lib/linter/code-path-analysis/code-path.js +1 -1
  7. package/lib/rules/accessor-pairs.js +4 -4
  8. package/lib/rules/callback-return.js +2 -2
  9. package/lib/rules/capitalized-comments.js +1 -1
  10. package/lib/rules/consistent-this.js +1 -1
  11. package/lib/rules/dot-notation.js +2 -2
  12. package/lib/rules/function-paren-newline.js +7 -4
  13. package/lib/rules/global-require.js +3 -3
  14. package/lib/rules/indent-legacy.js +2 -2
  15. package/lib/rules/indent.js +1 -1
  16. package/lib/rules/index.js +1 -0
  17. package/lib/rules/jsx-quotes.js +1 -1
  18. package/lib/rules/lines-around-comment.js +3 -3
  19. package/lib/rules/max-lines.js +2 -2
  20. package/lib/rules/newline-before-return.js +1 -1
  21. package/lib/rules/no-bitwise.js +2 -2
  22. package/lib/rules/no-console.js +1 -1
  23. package/lib/rules/no-constant-binary-expression.js +500 -0
  24. package/lib/rules/no-constant-condition.js +4 -197
  25. package/lib/rules/no-control-regex.js +23 -10
  26. package/lib/rules/no-empty-function.js +1 -1
  27. package/lib/rules/no-extra-boolean-cast.js +3 -3
  28. package/lib/rules/no-extra-semi.js +1 -1
  29. package/lib/rules/no-global-assign.js +1 -1
  30. package/lib/rules/no-implicit-coercion.js +6 -6
  31. package/lib/rules/no-magic-numbers.js +3 -3
  32. package/lib/rules/no-misleading-character-class.js +90 -17
  33. package/lib/rules/no-mixed-operators.js +1 -1
  34. package/lib/rules/no-mixed-requires.js +1 -1
  35. package/lib/rules/no-multi-spaces.js +1 -1
  36. package/lib/rules/no-native-reassign.js +1 -1
  37. package/lib/rules/no-new-wrappers.js +1 -1
  38. package/lib/rules/no-prototype-builtins.js +3 -3
  39. package/lib/rules/no-shadow.js +5 -5
  40. package/lib/rules/no-sparse-arrays.js +1 -1
  41. package/lib/rules/no-underscore-dangle.js +31 -2
  42. package/lib/rules/no-unused-expressions.js +1 -1
  43. package/lib/rules/no-unused-vars.js +1 -1
  44. package/lib/rules/operator-assignment.js +2 -2
  45. package/lib/rules/prefer-const.js +1 -1
  46. package/lib/rules/prefer-reflect.js +2 -2
  47. package/lib/rules/prefer-regex-literals.js +3 -3
  48. package/lib/rules/quote-props.js +2 -2
  49. package/lib/rules/quotes.js +1 -1
  50. package/lib/rules/spaced-comment.js +1 -1
  51. package/lib/rules/utils/ast-utils.js +203 -7
  52. package/lib/rules/valid-jsdoc.js +1 -1
  53. package/lib/rules/valid-typeof.js +4 -4
  54. package/lib/rules/yoda.js +1 -1
  55. package/package.json +23 -8
package/README.md CHANGED
@@ -235,15 +235,15 @@ Milos Djermanovic
235
235
  The people who review and implement new features.
236
236
 
237
237
  <table><tbody><tr><td align="center" valign="top" width="11%">
238
- <a href="https://github.com/mysticatea">
239
- <img src="https://github.com/mysticatea.png?s=75" width="75" height="75"><br />
240
- Toru Nagashima
241
- </a>
242
- </td><td align="center" valign="top" width="11%">
243
238
  <a href="https://github.com/aladdin-add">
244
239
  <img src="https://github.com/aladdin-add.png?s=75" width="75" height="75"><br />
245
240
  唯然
246
241
  </a>
242
+ </td><td align="center" valign="top" width="11%">
243
+ <a href="https://github.com/snitin315">
244
+ <img src="https://github.com/snitin315.png?s=75" width="75" height="75"><br />
245
+ Nitin Kumar
246
+ </a>
247
247
  </td></tr></tbody></table>
248
248
 
249
249
  ### Committers
@@ -261,6 +261,16 @@ Brett Zamir
261
261
  Bryan Mishkin
262
262
  </a>
263
263
  </td><td align="center" valign="top" width="11%">
264
+ <a href="https://github.com/mysticatea">
265
+ <img src="https://github.com/mysticatea.png?s=75" width="75" height="75"><br />
266
+ Toru Nagashima
267
+ </a>
268
+ </td><td align="center" valign="top" width="11%">
269
+ <a href="https://github.com/SaraSoueidan">
270
+ <img src="https://github.com/SaraSoueidan.png?s=75" width="75" height="75"><br />
271
+ Sara Soueidan
272
+ </a>
273
+ </td><td align="center" valign="top" width="11%">
264
274
  <a href="https://github.com/g-plane">
265
275
  <img src="https://github.com/g-plane.png?s=75" width="75" height="75"><br />
266
276
  Pig Fang
@@ -275,11 +285,6 @@ Anix
275
285
  <img src="https://github.com/yeonjuan.png?s=75" width="75" height="75"><br />
276
286
  YeonJuan
277
287
  </a>
278
- </td><td align="center" valign="top" width="11%">
279
- <a href="https://github.com/snitin315">
280
- <img src="https://github.com/snitin315.png?s=75" width="75" height="75"><br />
281
- Nitin Kumar
282
- </a>
283
288
  </td></tr></tbody></table>
284
289
 
285
290
  <!--teamend-->
@@ -292,9 +297,9 @@ The following companies, organizations, and individuals support ESLint's ongoing
292
297
  <!--sponsorsstart-->
293
298
  <h3>Platinum Sponsors</h3>
294
299
  <p><a href="https://automattic.com"><img src="https://images.opencollective.com/automattic/d0ef3e1/logo.png" alt="Automattic" height="undefined"></a></p><h3>Gold Sponsors</h3>
295
- <p><a href="https://contra.com"><img src="https://images.opencollective.com/contra1/c70f93f/logo.png" alt="Contra" height="96"></a> <a href="https://nx.dev"><img src="https://images.opencollective.com/nx/0efbe42/logo.png" alt="Nx (by Nrwl)" height="96"></a> <a href="https://www.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="96"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301?v=4" alt="American Express" height="96"></a> <a href="https://substack.com/"><img src="https://avatars.githubusercontent.com/u/53023767?v=4" alt="Substack" height="96"></a></p><h3>Silver Sponsors</h3>
300
+ <p><a href="https://www.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="96"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301?v=4" alt="American Express" height="96"></a> <a href="https://substack.com/"><img src="https://avatars.githubusercontent.com/u/53023767?v=4" alt="Substack" height="96"></a></p><h3>Silver Sponsors</h3>
296
301
  <p><a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a></p><h3>Bronze Sponsors</h3>
297
- <p><a href="https://launchdarkly.com"><img src="https://images.opencollective.com/launchdarkly/574bb9e/logo.png" alt="launchdarkly" height="32"></a> <a href="https://www.crosswordsolver.org/anagram-solver/"><img src="https://images.opencollective.com/anagram-solver/2666271/logo.png" alt="Anagram Solver" height="32"></a> <a href="https://www.vpsserver.com"><img src="https://images.opencollective.com/vpsservercom/logo.png" alt="VPS" height="32"></a> <a href="https://icons8.com"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8: free icons, photos, illustrations, and music" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://www.ignitionapp.com"><img src="https://avatars.githubusercontent.com/u/5753491?v=4" alt="Ignition" height="32"></a></p>
302
+ <p><a href="https://launchdarkly.com"><img src="https://images.opencollective.com/launchdarkly/574bb9e/logo.png" alt="launchdarkly" height="32"></a> <a href="https://nx.dev"><img src="https://images.opencollective.com/nx/0efbe42/logo.png" alt="Nx (by Nrwl)" height="32"></a> <a href="https://www.crosswordsolver.org/anagram-solver/"><img src="https://images.opencollective.com/anagram-solver/2666271/logo.png" alt="Anagram Solver" height="32"></a> <a href="https://www.vpsserver.com"><img src="https://images.opencollective.com/vpsservercom/logo.png" alt="VPS" height="32"></a> <a href="https://icons8.com"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8: free icons, photos, illustrations, and music" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://www.ignitionapp.com"><img src="https://avatars.githubusercontent.com/u/5753491?v=4" alt="Ignition" height="32"></a></p>
298
303
  <!--sponsorsend-->
299
304
 
300
305
  ## <a name="technology-sponsors"></a>Technology Sponsors
@@ -366,9 +366,7 @@ function *iterateRuleDeprecationWarnings(usedConfigArrays) {
366
366
 
367
367
  // Flatten used configs.
368
368
  /** @type {ExtractedConfig[]} */
369
- const configs = [].concat(
370
- ...usedConfigArrays.map(getUsedExtractedConfigs)
371
- );
369
+ const configs = usedConfigArrays.flatMap(getUsedExtractedConfigs);
372
370
 
373
371
  // Traverse rule configs.
374
372
  for (const config of configs) {
@@ -1023,7 +1021,7 @@ class CLIEngine {
1023
1021
  let formatterPath;
1024
1022
 
1025
1023
  // if there's a slash, then it's a file (TODO: this check seems dubious for scoped npm packages)
1026
- if (!namespace && normalizedFormatName.indexOf("/") > -1) {
1024
+ if (!namespace && normalizedFormatName.includes("/")) {
1027
1025
  formatterPath = path.resolve(cwd, normalizedFormatName);
1028
1026
  } else {
1029
1027
  try {
@@ -36,7 +36,7 @@ const invalidCacheStrategyErrorMessage = `Cache strategy must be one of: ${valid
36
36
  */
37
37
  function isValidCacheStrategy(cacheStrategy) {
38
38
  return (
39
- validCacheStrategies.indexOf(cacheStrategy) !== -1
39
+ validCacheStrategies.includes(cacheStrategy)
40
40
  );
41
41
  }
42
42
 
@@ -100,7 +100,7 @@ class CodePathSegment {
100
100
  * @returns {boolean} `true` if the segment is coming from the end of a loop.
101
101
  */
102
102
  isLoopedPrevSegment(segment) {
103
- return this.internal.loopedPrevSegments.indexOf(segment) !== -1;
103
+ return this.internal.loopedPrevSegments.includes(segment);
104
104
  }
105
105
 
106
106
  /**
@@ -33,7 +33,7 @@ function addToReturnedOrThrown(dest, others, all, segments) {
33
33
  const segment = segments[i];
34
34
 
35
35
  dest.push(segment);
36
- if (others.indexOf(segment) === -1) {
36
+ if (!others.includes(segment)) {
37
37
  all.push(segment);
38
38
  }
39
39
  }
@@ -212,7 +212,7 @@ class CodePath {
212
212
  }
213
213
 
214
214
  // Reset the flag of skipping if all branches have been skipped.
215
- if (skippedSegment && segment.prevSegments.indexOf(skippedSegment) !== -1) {
215
+ if (skippedSegment && segment.prevSegments.includes(skippedSegment)) {
216
216
  skippedSegment = null;
217
217
  }
218
218
  visited[segment.id] = true;
@@ -299,12 +299,12 @@ module.exports = {
299
299
  * @private
300
300
  */
301
301
  function checkPropertyDescriptor(node) {
302
- const namesToCheck = node.properties
302
+ const namesToCheck = new Set(node.properties
303
303
  .filter(p => p.type === "Property" && p.kind === "init" && !p.computed)
304
- .map(({ key }) => key.name);
304
+ .map(({ key }) => key.name));
305
305
 
306
- const hasGetter = namesToCheck.includes("get");
307
- const hasSetter = namesToCheck.includes("set");
306
+ const hasGetter = namesToCheck.has("get");
307
+ const hasSetter = namesToCheck.has("set");
308
308
 
309
309
  if (checkSetWithoutGet && hasSetter && !hasGetter) {
310
310
  report(node, "missingGetter");
@@ -53,7 +53,7 @@ module.exports = {
53
53
  if (!node.parent) {
54
54
  return null;
55
55
  }
56
- if (types.indexOf(node.parent.type) === -1) {
56
+ if (!types.includes(node.parent.type)) {
57
57
  return findClosestParentOfType(node.parent, types);
58
58
  }
59
59
  return node.parent;
@@ -87,7 +87,7 @@ module.exports = {
87
87
  * @returns {boolean} Whether or not this function matches our callback name.
88
88
  */
89
89
  function isCallback(node) {
90
- return containsOnlyIdentifiers(node.callee) && callbacks.indexOf(sourceCode.getText(node.callee)) > -1;
90
+ return containsOnlyIdentifiers(node.callee) && callbacks.includes(sourceCode.getText(node.callee));
91
91
  }
92
92
 
93
93
  /**
@@ -185,7 +185,7 @@ module.exports = {
185
185
 
186
186
  return Boolean(
187
187
  previousTokenOrComment &&
188
- ["Block", "Line"].indexOf(previousTokenOrComment.type) !== -1
188
+ ["Block", "Line"].includes(previousTokenOrComment.type)
189
189
  );
190
190
  }
191
191
 
@@ -65,7 +65,7 @@ module.exports = {
65
65
  function checkAssignment(node, name, value) {
66
66
  const isThis = value.type === "ThisExpression";
67
67
 
68
- if (aliases.indexOf(name) !== -1) {
68
+ if (aliases.includes(name)) {
69
69
  if (!isThis || node.operator && node.operator !== "=") {
70
70
  reportBadAssignment(node, name);
71
71
  }
@@ -76,7 +76,7 @@ module.exports = {
76
76
  function checkComputedProperty(node, value) {
77
77
  if (
78
78
  validIdentifier.test(value) &&
79
- (allowKeywords || keywords.indexOf(String(value)) === -1) &&
79
+ (allowKeywords || !keywords.includes(String(value))) &&
80
80
  !(allowPattern && allowPattern.test(value))
81
81
  ) {
82
82
  const formattedValue = node.property.type === "Literal" ? JSON.stringify(value) : `\`${value}\``;
@@ -142,7 +142,7 @@ module.exports = {
142
142
  !allowKeywords &&
143
143
  !node.computed &&
144
144
  node.property.type === "Identifier" &&
145
- keywords.indexOf(String(node.property.name)) !== -1
145
+ keywords.includes(String(node.property.name))
146
146
  ) {
147
147
  context.report({
148
148
  node: node.property,
@@ -191,10 +191,13 @@ module.exports = {
191
191
  function getParenTokens(node) {
192
192
  switch (node.type) {
193
193
  case "NewExpression":
194
- if (!node.arguments.length && !(
195
- astUtils.isOpeningParenToken(sourceCode.getLastToken(node, { skip: 1 })) &&
196
- astUtils.isClosingParenToken(sourceCode.getLastToken(node))
197
- )) {
194
+ if (!node.arguments.length &&
195
+ !(
196
+ astUtils.isOpeningParenToken(sourceCode.getLastToken(node, { skip: 1 })) &&
197
+ astUtils.isClosingParenToken(sourceCode.getLastToken(node)) &&
198
+ node.callee.range[1] < node.range[1]
199
+ )
200
+ ) {
198
201
 
199
202
  // If the NewExpression does not have parens (e.g. `new Foo`), return null.
200
203
  return null;
@@ -6,7 +6,7 @@
6
6
 
7
7
  "use strict";
8
8
 
9
- const ACCEPTABLE_PARENTS = [
9
+ const ACCEPTABLE_PARENTS = new Set([
10
10
  "AssignmentExpression",
11
11
  "VariableDeclarator",
12
12
  "MemberExpression",
@@ -16,7 +16,7 @@ const ACCEPTABLE_PARENTS = [
16
16
  "Program",
17
17
  "VariableDeclaration",
18
18
  "ChainExpression"
19
- ];
19
+ ]);
20
20
 
21
21
  /**
22
22
  * Finds the eslint-scope reference in the given scope.
@@ -75,7 +75,7 @@ module.exports = {
75
75
  const currentScope = context.getScope();
76
76
 
77
77
  if (node.callee.name === "require" && !isShadowed(currentScope, node.callee)) {
78
- const isGoodRequire = context.getAncestors().every(parent => ACCEPTABLE_PARENTS.indexOf(parent.type) > -1);
78
+ const isGoodRequire = context.getAncestors().every(parent => ACCEPTABLE_PARENTS.has(parent.type));
79
79
 
80
80
  if (!isGoodRequire) {
81
81
  context.report({ node, messageId: "unexpected" });
@@ -753,7 +753,7 @@ module.exports = {
753
753
  if (typeof options.CallExpression.arguments === "number") {
754
754
  nodeIndent += options.CallExpression.arguments * indentSize;
755
755
  } else if (options.CallExpression.arguments === "first") {
756
- if (parent.arguments.indexOf(node) !== -1) {
756
+ if (parent.arguments.includes(node)) {
757
757
  nodeIndent = parent.arguments[0].loc.start.column;
758
758
  }
759
759
  } else {
@@ -840,7 +840,7 @@ module.exports = {
840
840
  "IfStatement", "WhileStatement", "ForStatement", "ForInStatement", "ForOfStatement", "DoWhileStatement", "ClassDeclaration", "TryStatement"
841
841
  ];
842
842
 
843
- if (node.parent && statementsWithProperties.indexOf(node.parent.type) !== -1 && isNodeBodyBlock(node)) {
843
+ if (node.parent && statementsWithProperties.includes(node.parent.type) && isNodeBodyBlock(node)) {
844
844
  indent = getNodeIndent(node.parent).goodChar;
845
845
  } else if (node.parent && node.parent.type === "CatchClause") {
846
846
  indent = getNodeIndent(node.parent.parent).goodChar;
@@ -796,7 +796,7 @@ module.exports = {
796
796
  let statement = node.parent && node.parent.parent;
797
797
 
798
798
  while (
799
- statement.type === "UnaryExpression" && ["!", "~", "+", "-"].indexOf(statement.operator) > -1 ||
799
+ statement.type === "UnaryExpression" && ["!", "~", "+", "-"].includes(statement.operator) ||
800
800
  statement.type === "AssignmentExpression" ||
801
801
  statement.type === "LogicalExpression" ||
802
802
  statement.type === "SequenceExpression" ||
@@ -103,6 +103,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
103
103
  "no-confusing-arrow": () => require("./no-confusing-arrow"),
104
104
  "no-console": () => require("./no-console"),
105
105
  "no-const-assign": () => require("./no-const-assign"),
106
+ "no-constant-binary-expression": () => require("./no-constant-binary-expression"),
106
107
  "no-constant-condition": () => require("./no-constant-condition"),
107
108
  "no-constructor-return": () => require("./no-constructor-return"),
108
109
  "no-continue": () => require("./no-continue"),
@@ -70,7 +70,7 @@ module.exports = {
70
70
  * @public
71
71
  */
72
72
  function usesExpectedQuotes(node) {
73
- return node.value.indexOf(setting.quote) !== -1 || astUtils.isSurroundedBy(node.raw, setting.quote);
73
+ return node.value.includes(setting.quote) || astUtils.isSurroundedBy(node.raw, setting.quote);
74
74
  }
75
75
 
76
76
  return {
@@ -141,7 +141,7 @@ module.exports = {
141
141
  comments = sourceCode.getAllComments(),
142
142
  commentLines = getCommentLineNums(comments),
143
143
  emptyLines = getEmptyLineNums(lines),
144
- commentAndEmptyLines = commentLines.concat(emptyLines);
144
+ commentAndEmptyLines = new Set(commentLines.concat(emptyLines));
145
145
 
146
146
  /**
147
147
  * Returns whether or not comments are on lines starting with or ending with code
@@ -393,7 +393,7 @@ module.exports = {
393
393
  const nextTokenOrComment = sourceCode.getTokenAfter(token, { includeComments: true });
394
394
 
395
395
  // check for newline before
396
- if (!exceptionStartAllowed && before && !commentAndEmptyLines.includes(prevLineNum) &&
396
+ if (!exceptionStartAllowed && before && !commentAndEmptyLines.has(prevLineNum) &&
397
397
  !(astUtils.isCommentToken(previousTokenOrComment) && astUtils.isTokenOnSameLine(previousTokenOrComment, token))) {
398
398
  const lineStart = token.range[0] - token.loc.start.column;
399
399
  const range = [lineStart, lineStart];
@@ -408,7 +408,7 @@ module.exports = {
408
408
  }
409
409
 
410
410
  // check for newline after
411
- if (!exceptionEndAllowed && after && !commentAndEmptyLines.includes(nextLineNum) &&
411
+ if (!exceptionEndAllowed && after && !commentAndEmptyLines.has(nextLineNum) &&
412
412
  !(astUtils.isCommentToken(nextTokenOrComment) && astUtils.isTokenOnSameLine(token, nextTokenOrComment))) {
413
413
  context.report({
414
414
  node: token,
@@ -159,10 +159,10 @@ module.exports = {
159
159
  if (skipComments) {
160
160
  const comments = sourceCode.getAllComments();
161
161
 
162
- const commentLines = comments.flatMap(getLinesWithoutCode);
162
+ const commentLines = new Set(comments.flatMap(getLinesWithoutCode));
163
163
 
164
164
  lines = lines.filter(
165
- l => !commentLines.includes(l.lineNumber)
165
+ l => !commentLines.has(l.lineNumber)
166
166
  );
167
167
  }
168
168
 
@@ -47,7 +47,7 @@ module.exports = {
47
47
  function isPrecededByTokens(node, testTokens) {
48
48
  const tokenBefore = sourceCode.getTokenBefore(node);
49
49
 
50
- return testTokens.some(token => tokenBefore.value === token);
50
+ return testTokens.includes(tokenBefore.value);
51
51
  }
52
52
 
53
53
  /**
@@ -76,7 +76,7 @@ module.exports = {
76
76
  * @returns {boolean} Whether or not the node has a bitwise operator.
77
77
  */
78
78
  function hasBitwiseOperator(node) {
79
- return BITWISE_OPERATORS.indexOf(node.operator) !== -1;
79
+ return BITWISE_OPERATORS.includes(node.operator);
80
80
  }
81
81
 
82
82
  /**
@@ -85,7 +85,7 @@ module.exports = {
85
85
  * @returns {boolean} Whether or not the node has a bitwise operator.
86
86
  */
87
87
  function allowedOperator(node) {
88
- return allowed.indexOf(node.operator) !== -1;
88
+ return allowed.includes(node.operator);
89
89
  }
90
90
 
91
91
  /**
@@ -72,7 +72,7 @@ module.exports = {
72
72
  function isAllowed(node) {
73
73
  const propertyName = astUtils.getStaticPropertyName(node);
74
74
 
75
- return propertyName && allowed.indexOf(propertyName) !== -1;
75
+ return propertyName && allowed.includes(propertyName);
76
76
  }
77
77
 
78
78
  /**