📄 generateArrayType.ts
¶
📊 Analysis Summary¶
Metric | Count |
---|---|
🔧 Functions | 2 |
📦 Imports | 12 |
📊 Variables & Constants | 8 |
📚 Table of Contents¶
🛠️ File Location:¶
📂 packages/rule-schema-to-typescript-types/src/generateArrayType.ts
📦 Imports¶
Name | Source |
---|---|
JSONSchema4 |
@typescript-eslint/utils/json-schema |
JSONSchema4ArraySchema |
@typescript-eslint/utils/json-schema |
TSUtils |
@typescript-eslint/utils |
ArrayAST |
./types |
AST |
./types |
RefMap |
./types |
TupleAST |
./types |
UnionAST |
./types |
NotSupportedError |
./errors |
UnexpectedError |
./errors |
generateType |
./generateType |
getCommentLines |
./getCommentLines |
Variables & Constants¶
Name | Type | Kind | Value | Exported |
---|---|---|---|---|
MAX_ITEMS_TO_TUPLIZE |
20 |
const | 20 |
✗ |
minItems |
any |
const | schema.minItems ?? 0 |
✗ |
maxItems |
any |
const | `schema.maxItems != null && schema.maxItems < MAX_ITEMS_TO_TUPLIZE | |
? schema.maxItems | ||||
: -1` | ✗ | |||
hasMaxItems |
boolean |
const | maxItems >= 0 |
✗ |
items |
JSONSchema4[] |
const | schema.items |
✗ |
spreadItemSchema |
JSONSchema4 | null |
let/var | null |
✗ |
spreadItem |
AST |
const | spreadItemSchema == null ? null : generateType(spreadItemSchema, refMap) |
✗ |
typesToUnion |
AST[] |
const | [] |
✗ |
Functions¶
generateArrayType(schema: JSONSchema4ArraySchema, refMap: RefMap): ArrayAST | TupleAST | UnionAST
¶
Code
export function generateArrayType(
schema: JSONSchema4ArraySchema,
refMap: RefMap,
): ArrayAST | TupleAST | UnionAST {
if (!schema.items) {
// it's technically valid to declare things like {type: 'array'} -> any[]
// but that's obviously dumb and loose so let's not even bother with it
throw new UnexpectedError('Unexpected missing items', schema);
}
if (!TSUtils.isArray(schema.items) && schema.additionalItems) {
throw new NotSupportedError(
'singlely-typed array with additionalItems',
schema,
);
}
const commentLines = getCommentLines(schema);
const minItems = schema.minItems ?? 0;
const maxItems =
schema.maxItems != null && schema.maxItems < MAX_ITEMS_TO_TUPLIZE
? schema.maxItems
: -1;
const hasMaxItems = maxItems >= 0;
if (!TSUtils.isArray(schema.items)) {
// While we could support `minItems` and `maxItems` with tuple types,
// for example `[T, ...T[]]`, it harms readability for documentation purposes.
// See https://github.com/typescript-eslint/typescript-eslint/issues/11117
return {
commentLines,
elementType: generateType(schema.items, refMap),
type: 'array',
};
}
// treat as a tuple
const items: JSONSchema4[] = schema.items;
let spreadItemSchema: JSONSchema4 | null = null;
if (hasMaxItems && items.length < maxItems) {
spreadItemSchema =
typeof schema.additionalItems === 'object'
? schema.additionalItems
: { type: 'any' };
}
// quick validation so we generate sensible types
if (hasMaxItems && maxItems < items.length) {
throw new UnexpectedError(
`maxItems (${maxItems}) is smaller than the number of items schemas provided (${items.length})`,
schema,
);
}
if (maxItems > items.length && spreadItemSchema == null) {
throw new UnexpectedError(
'maxItems is larger than the number of items schemas, but there was not an additionalItems schema provided',
schema,
);
}
const itemTypes = items.map(i => generateType(i, refMap));
const spreadItem =
spreadItemSchema == null ? null : generateType(spreadItemSchema, refMap);
if (itemTypes.length > minItems) {
/*
if there are more items than the min, we return a union of tuples instead of
using the optional element operator. This is done because it is more type-safe.
// optional element operator
type A = [string, string?, string?]
const a: A = ['a', undefined, 'c'] // no error
// union of tuples
type B = [string] | [string, string] | [string, string, string]
const b: B = ['a', undefined, 'c'] // TS error
*/
const cumulativeTypesList = itemTypes.slice(0, minItems);
const typesToUnion: AST[] = [];
if (cumulativeTypesList.length > 0) {
// actually has minItems, so add the initial state
typesToUnion.push(createTupleType(cumulativeTypesList));
} else {
// no minItems means it's acceptable to have an empty tuple type
typesToUnion.push(createTupleType([]));
}
for (let i = minItems; i < itemTypes.length; i += 1) {
cumulativeTypesList.push(itemTypes[i]);
if (i === itemTypes.length - 1) {
// only the last item in the union should have the spread parameter
typesToUnion.push(createTupleType(cumulativeTypesList, spreadItem));
} else {
typesToUnion.push(createTupleType(cumulativeTypesList));
}
}
return {
commentLines,
elements: typesToUnion,
type: 'union',
};
}
return {
commentLines,
elements: itemTypes,
spreadType: spreadItem,
type: 'tuple',
};
}
- Parameters:
schema: JSONSchema4ArraySchema
refMap: RefMap
- Return Type:
ArrayAST | TupleAST | UnionAST
- Calls:
TSUtils.isArray
getCommentLines (from ./getCommentLines)
generateType (from ./generateType)
items.map
itemTypes.slice
typesToUnion.push
createTupleType
cumulativeTypesList.push
- Internal Comments:
// it's technically valid to declare things like {type: 'array'} -> any[] // but that's obviously dumb and loose so let's not even bother with it // While we could support `minItems` and `maxItems` with tuple types, // for example `[T, ...T[]]`, it harms readability for documentation purposes. // See https://github.com/typescript-eslint/typescript-eslint/issues/11117 // treat as a tuple (x2) // quick validation so we generate sensible types /* if there are more items than the min, we return a union of tuples instead of using the optional element operator. This is done because it is more type-safe. // optional element operator type A = [string, string?, string?] const a: A = ['a', undefined, 'c'] // no error // union of tuples type B = [string] | [string, string] | [string, string, string] const b: B = ['a', undefined, 'c'] // TS error */ (x2) // actually has minItems, so add the initial state (x4) // no minItems means it's acceptable to have an empty tuple type (x4) // only the last item in the union should have the spread parameter (x4)
createTupleType(elements: AST[], spreadType: AST | null): TupleAST
¶
Code
- Parameters:
elements: AST[]
spreadType: AST | null
- Return Type:
TupleAST
- Internal Comments: