Skip to content

Commit 0023555

Browse files
committed
feat(models): union types for properties of enum like union strings and numbers
example GitHub Blob `encoding: any` is now `'utf-8' | 'base64'` and its TS quard is `['utf-8', 'base64'].includes(arg.encoding)` instead of "any" check
1 parent 324a95a commit 0023555

29 files changed

+66
-55
lines changed

src/parser.ts

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -326,16 +326,22 @@ function parseInterfaceProperties(
326326
typeof propSchema.additionalProperties !== 'boolean'
327327
? propSchema.additionalProperties.$ref
328328
: propSchema.$ref;
329-
const typescriptType = toTypescriptType(
330-
isArray
331-
? determineArrayType(propSchema)
332-
: ref
333-
? dereferenceType(ref)
334-
: propSchema.additionalProperties &&
335-
typeof propSchema.additionalProperties !== 'boolean'
336-
? propSchema.additionalProperties.type
337-
: propSchema.type,
338-
);
329+
const typescriptType =
330+
'enum' in propSchema
331+
? (propSchema.type === 'number'
332+
? propSchema.enum || []
333+
: (propSchema.enum || []).map(str => `'${str}'`)
334+
).join(' | ')
335+
: toTypescriptType(
336+
isArray
337+
? determineArrayType(propSchema)
338+
: ref
339+
? dereferenceType(ref)
340+
: propSchema.additionalProperties &&
341+
typeof propSchema.additionalProperties !== 'boolean'
342+
? propSchema.additionalProperties.type
343+
: propSchema.type,
344+
);
339345
const isRef = !!parseReference(propSchema);
340346
const propertyAllOf =
341347
propSchema.allOf && propSchema.allOf.length
@@ -387,6 +393,11 @@ function parseInterfaceProperties(
387393
guardFn(() => `is${prop.typescriptType}(arg.${name})`, prop),
388394
)
389395
.join(' && ')})`
396+
: / \| /.test(typescriptType)
397+
? `[${(typescriptType || '').replace(
398+
/ \| /g,
399+
', ',
400+
)}].includes(arg.${name})`
390401
: `is${typescriptType}(arg.${name})`,
391402
).replace(/\s+/g, ' ')}) &&`;
392403

@@ -579,9 +590,9 @@ function transformParameters(
579590
const isArray = /^array$/i.test(type);
580591
const typescriptType =
581592
'enum' in param
582-
? (param.type === 'string'
583-
? (param.enum || []).map(str => `'${str}'`)
584-
: param.enum || []
593+
? (param.type === 'number'
594+
? param.enum || []
595+
: (param.enum || []).map(str => `'${str}'`)
585596
).join(' | ')
586597
: toTypescriptType(
587598
isArray

tests/custom/api/guards/dog.model.guard.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ export function isDog(arg: any): arg is Dog {
1212
typeof arg === 'object' &&
1313
// bark?: boolean
1414
( typeof arg.bark === 'undefined' || typeof arg.bark === 'boolean' ) &&
15-
// breed?: string
16-
( typeof arg.breed === 'undefined' || typeof arg.breed === 'string' ) &&
15+
// breed?: 'Dingo' | 'Husky' | 'Retriever' | 'Shepherd'
16+
( typeof arg.breed === 'undefined' || ['Dingo', 'Husky', 'Retriever', 'Shepherd'].includes(arg.breed) ) &&
1717
// extends Pet
1818
isPet(arg) &&
1919

tests/custom/api/models/dog.model.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ import {
55

66
export interface Dog extends Pet {
77
bark?: boolean;
8-
breed?: string;
8+
breed?: 'Dingo' | 'Husky' | 'Retriever' | 'Shepherd';
99
}

tests/gcloud-firestore/api/guards/composite-filter.model.guard.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ export function isCompositeFilter(arg: any): arg is CompositeFilter {
1212
typeof arg === 'object' &&
1313
// filters?: Filter[]
1414
( typeof arg.filters === 'undefined' || (Array.isArray(arg.filters) && arg.filters.every(item => isFilter(item))) ) &&
15-
// op?: string
16-
( typeof arg.op === 'undefined' || typeof arg.op === 'string' ) &&
15+
// op?: 'OPERATOR_UNSPECIFIED' | 'AND'
16+
( typeof arg.op === 'undefined' || ['OPERATOR_UNSPECIFIED', 'AND'].includes(arg.op) ) &&
1717

1818
true
1919
);

tests/gcloud-firestore/api/guards/field-filter.model.guard.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ export function isFieldFilter(arg: any): arg is FieldFilter {
1313
typeof arg === 'object' &&
1414
// field?: FieldReference
1515
( typeof arg.field === 'undefined' || isFieldReference(arg.field) ) &&
16-
// op?: string
17-
( typeof arg.op === 'undefined' || typeof arg.op === 'string' ) &&
16+
// op?: 'OPERATOR_UNSPECIFIED' | 'LESS_THAN' | 'LESS_THAN_OR_EQUAL' | 'GREATER_THAN' | 'GREATER_THAN_OR_EQUAL' | 'EQUAL'
17+
( typeof arg.op === 'undefined' || ['OPERATOR_UNSPECIFIED', 'LESS_THAN', 'LESS_THAN_OR_EQUAL', 'GREATER_THAN', 'GREATER_THAN_OR_EQUAL', 'EQUAL'].includes(arg.op) ) &&
1818
// value?: Value
1919
( typeof arg.value === 'undefined' || isValue(arg.value) ) &&
2020

tests/gcloud-firestore/api/guards/field-transform.model.guard.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ export function isFieldTransform(arg: any): arg is FieldTransform {
99
typeof arg === 'object' &&
1010
// fieldPath?: string
1111
( typeof arg.fieldPath === 'undefined' || typeof arg.fieldPath === 'string' ) &&
12-
// setToServerValue?: string
13-
( typeof arg.setToServerValue === 'undefined' || typeof arg.setToServerValue === 'string' ) &&
12+
// setToServerValue?: 'SERVER_VALUE_UNSPECIFIED' | 'REQUEST_TIME'
13+
( typeof arg.setToServerValue === 'undefined' || ['SERVER_VALUE_UNSPECIFIED', 'REQUEST_TIME'].includes(arg.setToServerValue) ) &&
1414

1515
true
1616
);

tests/gcloud-firestore/api/guards/index-field.model.guard.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ export function isIndexField(arg: any): arg is IndexField {
99
typeof arg === 'object' &&
1010
// fieldPath?: string
1111
( typeof arg.fieldPath === 'undefined' || typeof arg.fieldPath === 'string' ) &&
12-
// mode?: string
13-
( typeof arg.mode === 'undefined' || typeof arg.mode === 'string' ) &&
12+
// mode?: 'MODE_UNSPECIFIED' | 'ASCENDING' | 'DESCENDING'
13+
( typeof arg.mode === 'undefined' || ['MODE_UNSPECIFIED', 'ASCENDING', 'DESCENDING'].includes(arg.mode) ) &&
1414

1515
true
1616
);

tests/gcloud-firestore/api/guards/index.model.guard.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ export function isIndex(arg: any): arg is Index {
1616
( typeof arg.fields === 'undefined' || (Array.isArray(arg.fields) && arg.fields.every(item => isIndexField(item))) ) &&
1717
// name?: string
1818
( typeof arg.name === 'undefined' || typeof arg.name === 'string' ) &&
19-
// state?: string
20-
( typeof arg.state === 'undefined' || typeof arg.state === 'string' ) &&
19+
// state?: 'STATE_UNSPECIFIED' | 'CREATING' | 'READY' | 'ERROR'
20+
( typeof arg.state === 'undefined' || ['STATE_UNSPECIFIED', 'CREATING', 'READY', 'ERROR'].includes(arg.state) ) &&
2121

2222
true
2323
);

tests/gcloud-firestore/api/guards/order.model.guard.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ export function isOrder(arg: any): arg is Order {
1010
return (
1111
arg != null &&
1212
typeof arg === 'object' &&
13-
// direction?: string
14-
( typeof arg.direction === 'undefined' || typeof arg.direction === 'string' ) &&
13+
// direction?: 'DIRECTION_UNSPECIFIED' | 'ASCENDING' | 'DESCENDING'
14+
( typeof arg.direction === 'undefined' || ['DIRECTION_UNSPECIFIED', 'ASCENDING', 'DESCENDING'].includes(arg.direction) ) &&
1515
// field?: FieldReference
1616
( typeof arg.field === 'undefined' || isFieldReference(arg.field) ) &&
1717

tests/gcloud-firestore/api/guards/target-change.model.guard.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ export function isTargetChange(arg: any): arg is TargetChange {
1616
( typeof arg.readTime === 'undefined' || typeof arg.readTime === 'string' ) &&
1717
// resumeToken?: string
1818
( typeof arg.resumeToken === 'undefined' || typeof arg.resumeToken === 'string' ) &&
19-
// targetChangeType?: string
20-
( typeof arg.targetChangeType === 'undefined' || typeof arg.targetChangeType === 'string' ) &&
19+
// targetChangeType?: 'NO_CHANGE' | 'ADD' | 'REMOVE' | 'CURRENT' | 'RESET'
20+
( typeof arg.targetChangeType === 'undefined' || ['NO_CHANGE', 'ADD', 'REMOVE', 'CURRENT', 'RESET'].includes(arg.targetChangeType) ) &&
2121
// targetIds?: number[]
2222
( typeof arg.targetIds === 'undefined' || (Array.isArray(arg.targetIds) && arg.targetIds.every(item => typeof item === 'number')) ) &&
2323

0 commit comments

Comments
 (0)