Repository: stoplightio/spectral (ts)

Issue:
Bug: Validation Error with @stoplight/spectral-rulesets 1.19.0
**Describe the bug**
After upgrading to `@stoplight/spectral-rulesets` version 1.19.0, we encountered a validation error that was not present in version 1.18.1. 

The error message indicates a problem with `spectral`, specifically a `TypeError: Cannot read properties of null (reading 'type')`.

```
[ERROR] There was a problem with spectral.
[ERROR] Cannot read properties of null (reading 'type')
[ERROR] Additional error details:
[ERROR] TypeError: Cannot read properties of null (reading 'type')
at $..[?(@.type === 'array')] (eval at query (/data/node_modules/nimma/dist/legacy/cjs/core/index.js:66:71), <anonymous>:10:31)
at eval (eval at query (/data/node_modules/nimma/dist/legacy/cjs/core/index.js:66:71), <anonymous>:182:41)
at _traverseBody (/data/node_modules/nimma/dist/legacy/cjs/runtime/traverse.js:13:5)
at _traverse (/data/node_modules/nimma/dist/legacy/cjs/runtime/traverse.js:41:7)
at _traverseBody (/data/node_modules/nimma/dist/legacy/cjs/runtime/traverse.js:17:5)
at _traverse (/data/node_modules/nimma/dist/legacy/cjs/runtime/traverse.js:41:7)
at _traverseBody (/data/node_modules/nimma/dist/legacy/cjs/runtime/traverse.js:17:5)
at _traverse (/data/node_modules/nimma/dist/legacy/cjs/runtime/traverse.js:41:7)
at _traverseBody (/data/node_modules/nimma/dist/legacy/cjs/runtime/traverse.js:17:5)
at _traverse **(/data/node_modules/nimma/dist/legacy/cjs/runtime/traverse.js:41:7)
```

**To Reproduce**

1. Upgrade to `@stoplight/spectral-rulesets` version 1.19.0.
2. Run the OpenAPI validation using `ibm-openapi-validator` or `spectral`.
3. Observe the validation error

**Expected behavior**
The OpenAPI validation should pass without any errors, as it did with `@stoplight/spectral-rulesets` version 1.18.1.


Pull request description:
fix(rulesets): fixed array-items type property selector
Fixes #2637.

This PR fixes an issue that was introduced by #2632. New `array-items` rule selector which causes the following error:

```
ERROR] There was a problem with spectral.
[ERROR] Cannot read properties of null (reading 'type')
[ERROR] Additional error details:
[ERROR] TypeError: Cannot read properties of null (reading 'type')
at $..[?(@.type === 'array')] (eval at query (/data/node_modules/nimma/dist/legacy/cjs/core/index.js:66:71), <anonymous>:10:31)
at eval (eval at query (/data/node_modules/nimma/dist/legacy/cjs/core/index.js:66:71), <anonymous>:182:41)
at _traverseBody (/data/node_modules/nimma/dist/legacy/cjs/runtime/traverse.js:13:5)
at _traverse (/data/node_modules/nimma/dist/legacy/cjs/runtime/traverse.js:41:7)
at _traverseBody (/data/node_modules/nimma/dist/legacy/cjs/runtime/traverse.js:17:5)
at _traverse (/data/node_modules/nimma/dist/legacy/cjs/runtime/traverse.js:41:7)
at _traverseBody (/data/node_modules/nimma/dist/legacy/cjs/runtime/traverse.js:17:5)
at _traverse (/data/node_modules/nimma/dist/legacy/cjs/runtime/traverse.js:41:7)
at _traverseBody (/data/node_modules/nimma/dist/legacy/cjs/runtime/traverse.js:17:5)
at _traverse **(/data/node_modules/nimma/dist/legacy/cjs/runtime/traverse.js:41:7)
```

**Checklist**

- [x] Tests added / updated
- [ ] Docs added / updated

**Does this PR introduce a breaking change?**

- [ ] Yes
- [x] No

Patch:
diff --git a/packages/rulesets/src/oas/index.ts b/packages/rulesets/src/oas/index.ts
index d59122c2..62057d45 100644
--- a/packages/rulesets/src/oas/index.ts
+++ b/packages/rulesets/src/oas/index.ts
@@ -57,6 +57,27 @@ const ruleset = {
         },
       ],
     },
+    ArrayProperties: {
+      targets: [
+        {
+          formats: [oas2, oas3_0],
+          given: [
+            // Check for type: 'array'
+            '$..[?(@ && @.type=="array")]',
+          ],
+        },
+        {
+          formats: [oas3_1],
+          given: [
+            // Still check for type: 'array'
+            '$..[?(@ && @.type=="array")]',
+
+            // also check for type: ['array', ...]
+            '$..[?(@ && @.type && @.type.constructor.name === "Array" && @.type.includes("array"))]',
+          ],
+        },
+      ],
+    },
   },
   rules: {
     'operation-success-response': {
@@ -362,12 +383,11 @@ const ruleset = {
       },
     },
     'array-items': {
-      formats: [oas3_0],
       message: 'Schemas with "type: array", require a sibling "items" field',
       severity: 0,
       recommended: true,
       resolved: false,
-      given: "$..[?(@.type === 'array')]",
+      given: '#ArrayProperties',
       then: {
         function: truthy,
         field: 'items',


Test patch:
diff --git a/packages/rulesets/src/oas/__tests__/array-items.test.ts b/packages/rulesets/src/oas/__tests__/array-items.test.ts
index 144ca5d6..a0ae12da 100644
--- a/packages/rulesets/src/oas/__tests__/array-items.test.ts
+++ b/packages/rulesets/src/oas/__tests__/array-items.test.ts
@@ -26,7 +26,41 @@ testRule('array-items', [
   },
 
   {
-    name: 'array items sibling is present',
+    name: 'array items sibling is present in a oas2 document',
+    document: {
+      swagger: '2.0',
+      securityDefinitions: {
+        apikey: {},
+        $ref: '#/securityDefinitions/apikey',
+      },
+      paths: {
+        $ref: '#/securityDefinitions/apikey',
+        '/path': {
+          get: {
+            '200': {
+              schema: {
+                type: 'array',
+                items: {},
+              },
+            },
+          },
+          post: {
+            '201': {
+              type: 'array',
+              items: {
+                type: 'array',
+                items: {},
+              },
+            },
+          },
+        },
+      },
+    },
+    errors: [],
+  },
+
+  {
+    name: 'array items sibling is present in oas3 document',
     document: {
       $ref: '#/',
       responses: {
@@ -46,8 +80,85 @@ testRule('array-items', [
     },
     errors: [],
   },
+
+  {
+    name: 'array items sibling is present in oas3.1 document',
+    document: {
+      openapi: '3.1.0',
+      paths: {
+        '/path': {
+          get: {
+            responses: {
+              '200': {
+                type: 'array',
+                items: {},
+              },
+            },
+          },
+          post: {
+            responses: {
+              '201': {
+                type: 'array',
+                items: {
+                  type: 'array',
+                  items: {},
+                },
+              },
+            },
+          },
+        },
+      },
+    },
+    errors: [],
+  },
+
   {
-    name: 'array items sibling is missing',
+    name: 'array items sibling is missing in a oas2 document',
+    document: {
+      swagger: '2.0',
+      securityDefinitions: {
+        apikey: {},
+        $ref: '#/securityDefinitions/apikey',
+      },
+      paths: {
+        $ref: '#/securityDefinitions/apikey',
+        '/path': {
+          get: {
+            '200': {
+              schema: {
+                type: 'array',
+              },
+            },
+          },
+          post: {
+            '201': {
+              type: 'array',
+              items: {
+                type: 'array',
+              },
+            },
+          },
+        },
+      },
+    },
+    errors: [
+      {
+        code: 'array-items',
+        message: 'Schemas with "type: array", require a sibling "items" field',
+        path: ['paths', '/path', 'get', '200', 'schema'],
+        severity: DiagnosticSeverity.Error,
+      },
+      {
+        code: 'array-items',
+        message: 'Schemas with "type: array", require a sibling "items" field',
+        path: ['paths', '/path', 'post', '201', 'items'],
+        severity: DiagnosticSeverity.Error,
+      },
+    ],
+  },
+
+  {
+    name: 'array items sibling is missing in oas3 document',
     document: {
       $ref: '#/',
       responses: {
@@ -78,4 +189,46 @@ testRule('array-items', [
       },
     ],
   },
+
+  {
+    name: 'array items sibling is missing in oas3.1 document',
+    document: {
+      openapi: '3.1.0',
+      paths: {
+        '/path': {
+          get: {
+            responses: {
+              '200': {
+                type: 'array',
+              },
+            },
+          },
+          post: {
+            responses: {
+              '201': {
+                type: 'array',
+                items: {
+                  type: 'array',
+                },
+              },
+            },
+          },
+        },
+      },
+    },
+    errors: [
+      {
+        code: 'array-items',
+        message: 'Schemas with "type: array", require a sibling "items" field',
+        path: ['paths', '/path', 'get', 'responses', '200'],
+        severity: DiagnosticSeverity.Error,
+      },
+      {
+        code: 'array-items',
+        message: 'Schemas with "type: array", require a sibling "items" field',
+        path: ['paths', '/path', 'post', 'responses', '201', 'items'],
+        severity: DiagnosticSeverity.Error,
+      },
+    ],
+  },
 ]);