eslint 9.27.0 → 9.29.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 (37) hide show
  1. package/README.md +1 -1
  2. package/conf/ecma-version.js +1 -1
  3. package/conf/globals.js +10 -0
  4. package/lib/cli.js +20 -23
  5. package/lib/config/config-loader.js +32 -21
  6. package/lib/config/config.js +34 -11
  7. package/lib/eslint/eslint.js +18 -21
  8. package/lib/languages/js/source-code/source-code.js +104 -27
  9. package/lib/linter/apply-disable-directives.js +2 -4
  10. package/lib/linter/code-path-analysis/code-path-analyzer.js +8 -9
  11. package/lib/linter/linter.js +30 -61
  12. package/lib/linter/source-code-traverser.js +327 -0
  13. package/lib/linter/source-code-visitor.js +81 -0
  14. package/lib/options.js +7 -0
  15. package/lib/rules/class-methods-use-this.js +7 -0
  16. package/lib/rules/func-style.js +57 -7
  17. package/lib/rules/no-implicit-globals.js +31 -15
  18. package/lib/rules/no-magic-numbers.js +98 -5
  19. package/lib/rules/no-promise-executor-return.js +4 -35
  20. package/lib/rules/no-restricted-globals.js +35 -2
  21. package/lib/rules/no-restricted-properties.js +24 -10
  22. package/lib/rules/no-setter-return.js +13 -48
  23. package/lib/rules/no-shadow.js +262 -6
  24. package/lib/rules/no-unassigned-vars.js +14 -6
  25. package/lib/rules/no-use-before-define.js +99 -1
  26. package/lib/rules/no-var.js +14 -2
  27. package/lib/rules/prefer-arrow-callback.js +9 -0
  28. package/lib/rules/prefer-regex-literals.js +1 -18
  29. package/lib/services/suppressions-service.js +8 -0
  30. package/lib/services/warning-service.js +85 -0
  31. package/lib/shared/naming.js +109 -0
  32. package/lib/shared/relative-module-resolver.js +28 -0
  33. package/lib/types/index.d.ts +18 -7
  34. package/lib/types/rules.d.ts +52 -2
  35. package/package.json +12 -10
  36. package/lib/linter/node-event-generator.js +0 -256
  37. package/lib/linter/safe-emitter.js +0 -52
@@ -111,6 +111,7 @@ module.exports = {
111
111
  switch (node.type) {
112
112
  case "MethodDefinition":
113
113
  return !node.static && node.kind !== "constructor";
114
+ case "AccessorProperty":
114
115
  case "PropertyDefinition":
115
116
  return !node.static && enforceForClassFields;
116
117
  default:
@@ -218,6 +219,8 @@ module.exports = {
218
219
  /*
219
220
  * Class field value are implicit functions.
220
221
  */
222
+ "AccessorProperty > *.key:exit": pushContext,
223
+ "AccessorProperty:exit": popContext,
221
224
  "PropertyDefinition > *.key:exit": pushContext,
222
225
  "PropertyDefinition:exit": popContext,
223
226
 
@@ -233,6 +236,10 @@ module.exports = {
233
236
  ThisExpression: markThisUsed,
234
237
  Super: markThisUsed,
235
238
  ...(enforceForClassFields && {
239
+ "AccessorProperty > ArrowFunctionExpression.value":
240
+ enterFunction,
241
+ "AccessorProperty > ArrowFunctionExpression.value:exit":
242
+ exitFunction,
236
243
  "PropertyDefinition > ArrowFunctionExpression.value":
237
244
  enterFunction,
238
245
  "PropertyDefinition > ArrowFunctionExpression.value:exit":
@@ -11,12 +11,15 @@
11
11
  /** @type {import('../types').Rule.RuleModule} */
12
12
  module.exports = {
13
13
  meta: {
14
+ dialects: ["javascript", "typescript"],
15
+ language: "javascript",
14
16
  type: "suggestion",
15
17
 
16
18
  defaultOptions: [
17
19
  "expression",
18
20
  {
19
21
  allowArrowFunctions: false,
22
+ allowTypeAnnotation: false,
20
23
  overrides: {},
21
24
  },
22
25
  ],
@@ -39,6 +42,9 @@ module.exports = {
39
42
  allowArrowFunctions: {
40
43
  type: "boolean",
41
44
  },
45
+ allowTypeAnnotation: {
46
+ type: "boolean",
47
+ },
42
48
  overrides: {
43
49
  type: "object",
44
50
  properties: {
@@ -60,11 +66,49 @@ module.exports = {
60
66
  },
61
67
 
62
68
  create(context) {
63
- const [style, { allowArrowFunctions, overrides }] = context.options;
69
+ const [style, { allowArrowFunctions, allowTypeAnnotation, overrides }] =
70
+ context.options;
64
71
  const enforceDeclarations = style === "declaration";
65
72
  const { namedExports: exportFunctionStyle } = overrides;
66
73
  const stack = [];
67
74
 
75
+ /**
76
+ * Checks if a function declaration is part of an overloaded function
77
+ * @param {ASTNode} node The function declaration node to check
78
+ * @returns {boolean} True if the function is overloaded
79
+ */
80
+ function isOverloadedFunction(node) {
81
+ const functionName = node.id.name;
82
+
83
+ if (node.parent.type === "ExportNamedDeclaration") {
84
+ return node.parent.parent.body.some(
85
+ member =>
86
+ member.type === "ExportNamedDeclaration" &&
87
+ member.declaration?.type === "TSDeclareFunction" &&
88
+ member.declaration.id.name === functionName,
89
+ );
90
+ }
91
+
92
+ if (node.parent.type === "SwitchCase") {
93
+ return node.parent.parent.cases.some(switchCase =>
94
+ switchCase.consequent.some(
95
+ member =>
96
+ member.type === "TSDeclareFunction" &&
97
+ member.id.name === functionName,
98
+ ),
99
+ );
100
+ }
101
+
102
+ return (
103
+ Array.isArray(node.parent.body) &&
104
+ node.parent.body.some(
105
+ member =>
106
+ member.type === "TSDeclareFunction" &&
107
+ member.id.name === functionName,
108
+ )
109
+ );
110
+ }
111
+
68
112
  const nodesToCheck = {
69
113
  FunctionDeclaration(node) {
70
114
  stack.push(false);
@@ -73,14 +117,16 @@ module.exports = {
73
117
  !enforceDeclarations &&
74
118
  node.parent.type !== "ExportDefaultDeclaration" &&
75
119
  (typeof exportFunctionStyle === "undefined" ||
76
- node.parent.type !== "ExportNamedDeclaration")
120
+ node.parent.type !== "ExportNamedDeclaration") &&
121
+ !isOverloadedFunction(node)
77
122
  ) {
78
123
  context.report({ node, messageId: "expression" });
79
124
  }
80
125
 
81
126
  if (
82
127
  node.parent.type === "ExportNamedDeclaration" &&
83
- exportFunctionStyle === "expression"
128
+ exportFunctionStyle === "expression" &&
129
+ !isOverloadedFunction(node)
84
130
  ) {
85
131
  context.report({ node, messageId: "expression" });
86
132
  }
@@ -97,7 +143,8 @@ module.exports = {
97
143
  node.parent.type === "VariableDeclarator" &&
98
144
  (typeof exportFunctionStyle === "undefined" ||
99
145
  node.parent.parent.parent.type !==
100
- "ExportNamedDeclaration")
146
+ "ExportNamedDeclaration") &&
147
+ !(allowTypeAnnotation && node.parent.id.typeAnnotation)
101
148
  ) {
102
149
  context.report({
103
150
  node: node.parent,
@@ -109,7 +156,8 @@ module.exports = {
109
156
  node.parent.type === "VariableDeclarator" &&
110
157
  node.parent.parent.parent.type ===
111
158
  "ExportNamedDeclaration" &&
112
- exportFunctionStyle === "declaration"
159
+ exportFunctionStyle === "declaration" &&
160
+ !(allowTypeAnnotation && node.parent.id.typeAnnotation)
113
161
  ) {
114
162
  context.report({
115
163
  node: node.parent,
@@ -144,7 +192,8 @@ module.exports = {
144
192
  enforceDeclarations &&
145
193
  (typeof exportFunctionStyle === "undefined" ||
146
194
  node.parent.parent.parent.type !==
147
- "ExportNamedDeclaration")
195
+ "ExportNamedDeclaration") &&
196
+ !(allowTypeAnnotation && node.parent.id.typeAnnotation)
148
197
  ) {
149
198
  context.report({
150
199
  node: node.parent,
@@ -155,7 +204,8 @@ module.exports = {
155
204
  if (
156
205
  node.parent.parent.parent.type ===
157
206
  "ExportNamedDeclaration" &&
158
- exportFunctionStyle === "declaration"
207
+ exportFunctionStyle === "declaration" &&
208
+ !(allowTypeAnnotation && node.parent.id.typeAnnotation)
159
209
  ) {
160
210
  context.report({
161
211
  node: node.parent,
@@ -5,6 +5,12 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ const ASSIGNMENT_NODES = new Set([
9
+ "AssignmentExpression",
10
+ "ForInStatement",
11
+ "ForOfStatement",
12
+ ]);
13
+
8
14
  //------------------------------------------------------------------------------
9
15
  // Rule Definition
10
16
  //------------------------------------------------------------------------------
@@ -142,27 +148,37 @@ module.exports = {
142
148
  }
143
149
  }
144
150
  });
145
- });
146
151
 
147
- // Undeclared assigned variables.
148
- scope.implicit.variables.forEach(variable => {
149
- const scopeVariable = scope.set.get(variable.name);
150
- let messageId;
152
+ if (
153
+ isReadonlyEslintGlobalVariable &&
154
+ variable.defs.length === 0
155
+ ) {
156
+ variable.references.forEach(reference => {
157
+ if (reference.isWrite() && !reference.isRead()) {
158
+ let assignmentParent =
159
+ reference.identifier.parent;
160
+
161
+ while (
162
+ assignmentParent &&
163
+ !ASSIGNMENT_NODES.has(assignmentParent.type)
164
+ ) {
165
+ assignmentParent = assignmentParent.parent;
166
+ }
151
167
 
152
- if (scopeVariable) {
153
- // ESLint global variable
154
- if (scopeVariable.writeable) {
155
- return;
156
- }
157
- messageId = "assignmentToReadonlyGlobal";
158
- } else {
159
- // Reference to an unknown variable, possible global leak.
160
- messageId = "globalVariableLeak";
168
+ report(
169
+ assignmentParent ?? reference.identifier,
170
+ "assignmentToReadonlyGlobal",
171
+ );
172
+ }
173
+ });
161
174
  }
175
+ });
162
176
 
177
+ // Undeclared assigned variables.
178
+ scope.implicit.variables.forEach(variable => {
163
179
  // def.node is an AssignmentExpression, ForInStatement or ForOfStatement.
164
180
  variable.defs.forEach(def => {
165
- report(def.node, messageId);
181
+ report(def.node, "globalVariableLeak");
166
182
  });
167
183
  });
168
184
  },
@@ -26,10 +26,73 @@ function normalizeIgnoreValue(x) {
26
26
  return x;
27
27
  }
28
28
 
29
+ /**
30
+ * Checks if the node parent is a TypeScript enum member
31
+ * @param {ASTNode} node The node to be validated
32
+ * @returns {boolean} True if the node parent is a TypeScript enum member
33
+ */
34
+ function isParentTSEnumDeclaration(node) {
35
+ return node.parent.type === "TSEnumMember";
36
+ }
37
+
38
+ /**
39
+ * Checks if the node is a valid TypeScript numeric literal type.
40
+ * @param {ASTNode} node The node to be validated
41
+ * @returns {boolean} True if the node is a TypeScript numeric literal type
42
+ */
43
+ function isTSNumericLiteralType(node) {
44
+ let ancestor = node.parent;
45
+
46
+ // Go up while we're part of a type union
47
+ while (ancestor.parent.type === "TSUnionType") {
48
+ ancestor = ancestor.parent;
49
+ }
50
+
51
+ // Check if the final ancestor is in a type alias declaration
52
+ return ancestor.parent.type === "TSTypeAliasDeclaration";
53
+ }
54
+
55
+ /**
56
+ * Checks if the node parent is a readonly class property
57
+ * @param {ASTNode} node The node to be validated
58
+ * @returns {boolean} True if the node parent is a readonly class property
59
+ */
60
+ function isParentTSReadonlyPropertyDefinition(node) {
61
+ if (node.parent?.type === "PropertyDefinition" && node.parent.readonly) {
62
+ return true;
63
+ }
64
+
65
+ return false;
66
+ }
67
+
68
+ /**
69
+ * Checks if the node is part of a type indexed access (eg. Foo[4])
70
+ * @param {ASTNode} node The node to be validated
71
+ * @returns {boolean} True if the node is part of an indexed access
72
+ */
73
+ function isAncestorTSIndexedAccessType(node) {
74
+ let ancestor = node.parent;
75
+
76
+ /*
77
+ * Go up another level while we're part of a type union (eg. 1 | 2) or
78
+ * intersection (eg. 1 & 2)
79
+ */
80
+ while (
81
+ ancestor.parent.type === "TSUnionType" ||
82
+ ancestor.parent.type === "TSIntersectionType"
83
+ ) {
84
+ ancestor = ancestor.parent;
85
+ }
86
+
87
+ return ancestor.parent.type === "TSIndexedAccessType";
88
+ }
89
+
29
90
  /** @type {import('../types').Rule.RuleModule} */
30
91
  module.exports = {
31
92
  meta: {
32
93
  type: "suggestion",
94
+ dialects: ["typescript", "javascript"],
95
+ language: "javascript",
33
96
 
34
97
  docs: {
35
98
  description: "Disallow magic numbers",
@@ -75,6 +138,22 @@ module.exports = {
75
138
  type: "boolean",
76
139
  default: false,
77
140
  },
141
+ ignoreEnums: {
142
+ type: "boolean",
143
+ default: false,
144
+ },
145
+ ignoreNumericLiteralTypes: {
146
+ type: "boolean",
147
+ default: false,
148
+ },
149
+ ignoreReadonlyClassProperties: {
150
+ type: "boolean",
151
+ default: false,
152
+ },
153
+ ignoreTypeIndexes: {
154
+ type: "boolean",
155
+ default: false,
156
+ },
78
157
  },
79
158
  additionalProperties: false,
80
159
  },
@@ -94,7 +173,12 @@ module.exports = {
94
173
  ignoreArrayIndexes = !!config.ignoreArrayIndexes,
95
174
  ignoreDefaultValues = !!config.ignoreDefaultValues,
96
175
  ignoreClassFieldInitialValues =
97
- !!config.ignoreClassFieldInitialValues;
176
+ !!config.ignoreClassFieldInitialValues,
177
+ ignoreEnums = !!config.ignoreEnums,
178
+ ignoreNumericLiteralTypes = !!config.ignoreNumericLiteralTypes,
179
+ ignoreReadonlyClassProperties =
180
+ !!config.ignoreReadonlyClassProperties,
181
+ ignoreTypeIndexes = !!config.ignoreTypeIndexes;
98
182
 
99
183
  const okTypes = detectObjects
100
184
  ? []
@@ -217,14 +301,15 @@ module.exports = {
217
301
  let value;
218
302
  let raw;
219
303
 
220
- // Treat unary minus as a part of the number
304
+ // Treat unary minus/plus as a part of the number
221
305
  if (
222
306
  node.parent.type === "UnaryExpression" &&
223
- node.parent.operator === "-"
307
+ ["-", "+"].includes(node.parent.operator)
224
308
  ) {
225
309
  fullNumberNode = node.parent;
226
- value = -node.value;
227
- raw = `-${node.raw}`;
310
+ value =
311
+ node.parent.operator === "-" ? -node.value : node.value;
312
+ raw = `${node.parent.operator}${node.raw}`;
228
313
  } else {
229
314
  fullNumberNode = node;
230
315
  value = node.value;
@@ -239,6 +324,14 @@ module.exports = {
239
324
  (ignoreDefaultValues && isDefaultValue(fullNumberNode)) ||
240
325
  (ignoreClassFieldInitialValues &&
241
326
  isClassFieldInitialValue(fullNumberNode)) ||
327
+ (ignoreEnums &&
328
+ isParentTSEnumDeclaration(fullNumberNode)) ||
329
+ (ignoreNumericLiteralTypes &&
330
+ isTSNumericLiteralType(fullNumberNode)) ||
331
+ (ignoreTypeIndexes &&
332
+ isAncestorTSIndexedAccessType(fullNumberNode)) ||
333
+ (ignoreReadonlyClassProperties &&
334
+ isParentTSReadonlyPropertyDefinition(fullNumberNode)) ||
242
335
  isParseIntRadix(fullNumberNode) ||
243
336
  isJSXNumber(fullNumberNode) ||
244
337
  (ignoreArrayIndexes && isArrayIndex(fullNumberNode, value))
@@ -9,7 +9,6 @@
9
9
  // Requirements
10
10
  //------------------------------------------------------------------------------
11
11
 
12
- const { findVariable } = require("@eslint-community/eslint-utils");
13
12
  const astUtils = require("./utils/ast-utils");
14
13
 
15
14
  //------------------------------------------------------------------------------
@@ -21,43 +20,13 @@ const functionTypesToCheck = new Set([
21
20
  "FunctionExpression",
22
21
  ]);
23
22
 
24
- /**
25
- * Determines whether the given identifier node is a reference to a global variable.
26
- * @param {ASTNode} node `Identifier` node to check.
27
- * @param {Scope} scope Scope to which the node belongs.
28
- * @returns {boolean} True if the identifier is a reference to a global variable.
29
- */
30
- function isGlobalReference(node, scope) {
31
- const variable = findVariable(scope, node);
32
-
33
- return (
34
- variable !== null &&
35
- variable.scope.type === "global" &&
36
- variable.defs.length === 0
37
- );
38
- }
39
-
40
- /**
41
- * Finds function's outer scope.
42
- * @param {Scope} scope Function's own scope.
43
- * @returns {Scope} Function's outer scope.
44
- */
45
- function getOuterScope(scope) {
46
- const upper = scope.upper;
47
-
48
- if (upper.type === "function-expression-name") {
49
- return upper.upper;
50
- }
51
- return upper;
52
- }
53
-
54
23
  /**
55
24
  * Determines whether the given function node is used as a Promise executor.
56
25
  * @param {ASTNode} node The node to check.
57
- * @param {Scope} scope Function's own scope.
26
+ * @param {SourceCode} sourceCode Source code to which the node belongs.
58
27
  * @returns {boolean} `true` if the node is a Promise executor.
59
28
  */
60
- function isPromiseExecutor(node, scope) {
29
+ function isPromiseExecutor(node, sourceCode) {
61
30
  const parent = node.parent;
62
31
 
63
32
  return (
@@ -65,7 +34,7 @@ function isPromiseExecutor(node, scope) {
65
34
  parent.arguments[0] === node &&
66
35
  parent.callee.type === "Identifier" &&
67
36
  parent.callee.name === "Promise" &&
68
- isGlobalReference(parent.callee, getOuterScope(scope))
37
+ sourceCode.isGlobalReference(parent.callee)
69
38
  );
70
39
  }
71
40
 
@@ -203,7 +172,7 @@ module.exports = {
203
172
  upper: funcInfo,
204
173
  shouldCheck:
205
174
  functionTypesToCheck.has(node.type) &&
206
- isPromiseExecutor(node, sourceCode.getScope(node)),
175
+ isPromiseExecutor(node, sourceCode),
207
176
  };
208
177
 
209
178
  if (
@@ -4,6 +4,18 @@
4
4
  */
5
5
  "use strict";
6
6
 
7
+ //------------------------------------------------------------------------------
8
+ // Helpers
9
+ //------------------------------------------------------------------------------
10
+
11
+ const TYPE_NODES = new Set([
12
+ "TSTypeReference",
13
+ "TSInterfaceHeritage",
14
+ "TSClassImplements",
15
+ "TSTypeQuery",
16
+ "TSQualifiedName",
17
+ ]);
18
+
7
19
  //------------------------------------------------------------------------------
8
20
  // Rule Definition
9
21
  //------------------------------------------------------------------------------
@@ -11,6 +23,8 @@
11
23
  /** @type {import('../types').Rule.RuleModule} */
12
24
  module.exports = {
13
25
  meta: {
26
+ dialects: ["javascript", "typescript"],
27
+ language: "javascript",
14
28
  type: "suggestion",
15
29
 
16
30
  docs: {
@@ -100,6 +114,18 @@ module.exports = {
100
114
  return Object.hasOwn(restrictedGlobalMessages, name);
101
115
  }
102
116
 
117
+ /**
118
+ * Check if the given reference occurs within a TypeScript type context.
119
+ * @param {Reference} reference The variable reference to check.
120
+ * @returns {boolean} Whether the reference is in a type context.
121
+ * @private
122
+ */
123
+ function isInTypeContext(reference) {
124
+ const parent = reference.identifier.parent;
125
+
126
+ return TYPE_NODES.has(parent.type);
127
+ }
128
+
103
129
  return {
104
130
  Program(node) {
105
131
  const scope = sourceCode.getScope(node);
@@ -107,13 +133,20 @@ module.exports = {
107
133
  // Report variables declared elsewhere (ex: variables defined as "global" by eslint)
108
134
  scope.variables.forEach(variable => {
109
135
  if (!variable.defs.length && isRestricted(variable.name)) {
110
- variable.references.forEach(reportReference);
136
+ variable.references.forEach(reference => {
137
+ if (!isInTypeContext(reference)) {
138
+ reportReference(reference);
139
+ }
140
+ });
111
141
  }
112
142
  });
113
143
 
114
144
  // Report variables not declared at all
115
145
  scope.through.forEach(reference => {
116
- if (isRestricted(reference.identifier.name)) {
146
+ if (
147
+ isRestricted(reference.identifier.name) &&
148
+ !isInTypeContext(reference)
149
+ ) {
117
150
  reportReference(reference);
118
151
  }
119
152
  });
@@ -40,6 +40,13 @@ module.exports = {
40
40
  },
41
41
  uniqueItems: true,
42
42
  },
43
+ allowProperties: {
44
+ type: "array",
45
+ items: {
46
+ type: "string",
47
+ },
48
+ uniqueItems: true,
49
+ },
43
50
  message: {
44
51
  type: "string",
45
52
  },
@@ -53,7 +60,10 @@ module.exports = {
53
60
  },
54
61
  ],
55
62
  not: {
56
- required: ["allowObjects", "object"],
63
+ anyOf: [
64
+ { required: ["allowObjects", "object"] },
65
+ { required: ["allowProperties", "property"] },
66
+ ],
57
67
  },
58
68
  additionalProperties: false,
59
69
  },
@@ -92,6 +102,7 @@ module.exports = {
92
102
  });
93
103
  } else if (typeof propertyName === "undefined") {
94
104
  globallyRestrictedObjects.set(objectName, {
105
+ allowProperties: option.allowProperties,
95
106
  message: option.message,
96
107
  });
97
108
  } else {
@@ -106,17 +117,17 @@ module.exports = {
106
117
  });
107
118
 
108
119
  /**
109
- * Checks if an object name is in the allowed objects list.
110
- * @param {string} objectName The name of the object to check
111
- * @param {string[]} [allowObjects] The list of objects to allow
112
- * @returns {boolean} True if the object is allowed, false otherwise
120
+ * Checks if a name is in the allowed list.
121
+ * @param {string} name The name to check
122
+ * @param {string[]} [allowedList] The list of allowed names
123
+ * @returns {boolean} True if the name is allowed, false otherwise
113
124
  */
114
- function isAllowedObject(objectName, allowObjects) {
115
- if (!allowObjects) {
125
+ function isAllowed(name, allowedList) {
126
+ if (!allowedList) {
116
127
  return false;
117
128
  }
118
129
 
119
- return allowObjects.includes(objectName);
130
+ return allowedList.includes(name);
120
131
  }
121
132
 
122
133
  /**
@@ -137,7 +148,10 @@ module.exports = {
137
148
  const globalMatchedProperty =
138
149
  globallyRestrictedProperties.get(propertyName);
139
150
 
140
- if (matchedObjectProperty) {
151
+ if (
152
+ matchedObjectProperty &&
153
+ !isAllowed(propertyName, matchedObjectProperty.allowProperties)
154
+ ) {
141
155
  const message = matchedObjectProperty.message
142
156
  ? ` ${matchedObjectProperty.message}`
143
157
  : "";
@@ -153,7 +167,7 @@ module.exports = {
153
167
  });
154
168
  } else if (
155
169
  globalMatchedProperty &&
156
- !isAllowedObject(objectName, globalMatchedProperty.allowObjects)
170
+ !isAllowed(objectName, globalMatchedProperty.allowObjects)
157
171
  ) {
158
172
  const message = globalMatchedProperty.message
159
173
  ? ` ${globalMatchedProperty.message}`