From 48819c54e69817adc9bf6173c22350ca0823709e Mon Sep 17 00:00:00 2001 From: Bryan Mishkin <698306+bmish@users.noreply.github.com> Date: Sat, 4 Nov 2023 20:20:11 -0400 Subject: [PATCH] fix: handle when option type is an array of types in rule options lists --- lib/rule-options-list.ts | 6 +- lib/rule-options.ts | 17 ++++- .../rule-options-list-test.ts.snap | 19 +++-- test/lib/generate/rule-options-list-test.ts | 14 +++- test/lib/rule-options-test.ts | 75 ++++++++++++++++--- 5 files changed, 106 insertions(+), 25 deletions(-) diff --git a/lib/rule-options-list.ts b/lib/rule-options-list.ts index 18c92945..bab4e121 100644 --- a/lib/rule-options-list.ts +++ b/lib/rule-options-list.ts @@ -5,7 +5,7 @@ import { import { markdownTable } from 'markdown-table'; import type { RuleModule } from './types.js'; import { RuleOption, getAllNamedOptions } from './rule-options.js'; -import { capitalizeOnlyFirstLetter, sanitizeMarkdownTable } from './string.js'; +import { sanitizeMarkdownTable } from './string.js'; export enum COLUMN_TYPE { // Alphabetical order. @@ -64,9 +64,7 @@ function ruleOptionToColumnValues(ruleOption: RuleOption): { : undefined, [COLUMN_TYPE.NAME]: `\`${ruleOption.name}\``, [COLUMN_TYPE.REQUIRED]: ruleOption.required ? 'Yes' : undefined, - [COLUMN_TYPE.TYPE]: ruleOption.type - ? capitalizeOnlyFirstLetter(ruleOption.type) - : undefined, + [COLUMN_TYPE.TYPE]: ruleOption.type || undefined, }; return columns; diff --git a/lib/rule-options.ts b/lib/rule-options.ts index c27e14c8..58114a39 100644 --- a/lib/rule-options.ts +++ b/lib/rule-options.ts @@ -1,5 +1,6 @@ import traverse from 'json-schema-traverse'; import type { JSONSchema } from '@typescript-eslint/utils'; +import { capitalizeOnlyFirstLetter } from './string.js'; export type RuleOption = { name: string; @@ -11,6 +12,14 @@ export type RuleOption = { deprecated?: boolean; }; +function typeToString( + type: JSONSchema.JSONSchema4TypeName[] | JSONSchema.JSONSchema4TypeName +): string { + return Array.isArray(type) + ? type.map((item) => capitalizeOnlyFirstLetter(item)).join(', ') + : capitalizeOnlyFirstLetter(type); +} + /** * Gather a list of named options from a rule schema. * @param jsonSchema - the JSON schema to check @@ -43,9 +52,13 @@ export function getAllNamedOptions( value.type === 'array' && !Array.isArray(value.items) && value.items?.type - ? `${value.items.type.toString()}[]` + ? `${ + Array.isArray(value.items.type) && value.items.type.length > 1 + ? `(${typeToString(value.items.type)})` + : typeToString(value.items.type) + }[]` : value.type - ? value.type.toString() + ? typeToString(value.type) : undefined, description: value.description, default: value.default, diff --git a/test/lib/generate/__snapshots__/rule-options-list-test.ts.snap b/test/lib/generate/__snapshots__/rule-options-list-test.ts.snap index a16ab73b..146e9793 100644 --- a/test/lib/generate/__snapshots__/rule-options-list-test.ts.snap +++ b/test/lib/generate/__snapshots__/rule-options-list-test.ts.snap @@ -7,14 +7,17 @@ exports[`generate (rule options list) basic generates the documentation 1`] = ` ## Options -| Name | Description | Type | Choices | Default | Required | Deprecated | -| :----- | :---------------------------- | :------- | :---------------- | :------- | :------- | :--------- | -| \`arr1\` | | Array | | | | | -| \`arr2\` | | String[] | | | | | -| \`bar\` | Choose how to use the rule. | String | \`always\`, \`never\` | \`always\` | Yes | | -| \`baz\` | | | | \`true\` | Yes | | -| \`biz\` | | | | | | | -| \`foo\` | Enable some kind of behavior. | Boolean | | \`false\` | | Yes | +| Name | Description | Type | Choices | Default | Required | Deprecated | +| :------------------------- | :---------------------------- | :------------------ | :---------------- | :------- | :------- | :--------- | +| \`arr1\` | | Array | | | | | +| \`arrWithArrType\` | | String, Boolean | | | | | +| \`arrWithArrTypeSingleItem\` | | String | | | | | +| \`arrWithItemsArrayType\` | | (String, Boolean)[] | | | | | +| \`arrWithItemsType\` | | String[] | | | | | +| \`bar\` | Choose how to use the rule. | String | \`always\`, \`never\` | \`always\` | Yes | | +| \`baz\` | | | | \`true\` | Yes | | +| \`biz\` | | | | | | | +| \`foo\` | Enable some kind of behavior. | Boolean | | \`false\` | | Yes | " `; diff --git a/test/lib/generate/rule-options-list-test.ts b/test/lib/generate/rule-options-list-test.ts index 93bb5e79..1e813a4f 100644 --- a/test/lib/generate/rule-options-list-test.ts +++ b/test/lib/generate/rule-options-list-test.ts @@ -48,12 +48,24 @@ describe('generate (rule options list)', function () { arr1: { type: "array", }, - arr2: { + arrWithArrType: { + type: ["string", "boolean"], + }, + arrWithArrTypeSingleItem: { + type: ["string"], + }, + arrWithItemsType: { type: "array", items: { type: "string" } }, + arrWithItemsArrayType: { + type: "array", + items: { + type: ["string", "boolean"] + } + }, }, required: ["bar"], additionalProperties: false diff --git a/test/lib/rule-options-test.ts b/test/lib/rule-options-test.ts index 0239405b..83375bb1 100644 --- a/test/lib/rule-options-test.ts +++ b/test/lib/rule-options-test.ts @@ -52,7 +52,7 @@ describe('rule options', function () { "enum": undefined, "name": "optionToDoSomething1", "required": false, - "type": "boolean", + "type": "Boolean", }, { "default": undefined, @@ -64,7 +64,7 @@ describe('rule options', function () { ], "name": "optionToDoSomething2", "required": false, - "type": "string", + "type": "String", }, { "default": undefined, @@ -102,7 +102,7 @@ describe('rule options', function () { "enum": undefined, "name": "optionToDoSomething", "required": false, - "type": "boolean", + "type": "Boolean", }, ] `); @@ -141,7 +141,7 @@ describe('rule options', function () { "enum": undefined, "name": "optionToDoSomething1", "required": false, - "type": "boolean", + "type": "Boolean", }, { "default": false, @@ -150,7 +150,7 @@ describe('rule options', function () { "enum": undefined, "name": "optionToDoSomething2", "required": false, - "type": "boolean", + "type": "Boolean", }, ] `); @@ -182,7 +182,7 @@ describe('rule options', function () { "enum": undefined, "name": "optionToDoSomething", "required": false, - "type": "boolean", + "type": "Boolean", }, ] `); @@ -214,7 +214,7 @@ describe('rule options', function () { "enum": undefined, "name": "optionToDoSomething", "required": false, - "type": "boolean", + "type": "Boolean", }, ] `); @@ -255,7 +255,7 @@ describe('rule options', function () { "enum": undefined, "name": "optionToDoSomething1", "required": false, - "type": "object[]", + "type": "Object[]", }, { "default": undefined, @@ -264,7 +264,7 @@ describe('rule options', function () { "enum": undefined, "name": "optionToDoSomething2", "required": false, - "type": "array", + "type": "Array", }, { "default": false, @@ -273,7 +273,62 @@ describe('rule options', function () { "enum": undefined, "name": "optionToDoSomething2", "required": false, - "type": "boolean", + "type": "Boolean", + }, + ] + `); + }); + + it('handles when type is an array', function () { + expect( + getAllNamedOptions([ + { + type: 'object', + properties: { + optionToDoSomething1: { + type: 'array', + items: { + type: ['boolean', 'string'], + }, + }, + optionToDoSomething2: { + type: ['boolean', 'string'], + }, + optionToDoSomething3: { + type: ['boolean'], + }, + }, + additionalProperties: false, + }, + ]) + ).toMatchInlineSnapshot(` + [ + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "name": "optionToDoSomething1", + "required": false, + "type": "(Boolean, String)[]", + }, + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "name": "optionToDoSomething2", + "required": false, + "type": "Boolean, String", + }, + { + "default": undefined, + "deprecated": undefined, + "description": undefined, + "enum": undefined, + "name": "optionToDoSomething3", + "required": false, + "type": "Boolean", }, ] `);