Skip to content

Commit

Permalink
feat: Add flag to throw on cyclic dependencies between named types (#101
Browse files Browse the repository at this point in the history
)
  • Loading branch information
runeh authored May 31, 2021
1 parent e344f86 commit 2e33303
Show file tree
Hide file tree
Showing 8 changed files with 430 additions and 20 deletions.
25 changes: 19 additions & 6 deletions docs/interfaces/main.generateoptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
- [formatTypeName](main.generateoptions.md#formattypename)
- [includeImport](main.generateoptions.md#includeimport)
- [includeTypes](main.generateoptions.md#includetypes)
- [rejectCyclicDependencies](main.generateoptions.md#rejectcyclicdependencies)

## Properties

Expand All @@ -23,7 +24,7 @@

Apply formatting to the output using prettier. Default: true

Defined in: [src/main.ts:58](https://github.com/cobraz/generate-runtypes/blob/e397a85/src/main.ts#L58)
Defined in: [src/main.ts:59](https://github.com/cobraz/generate-runtypes/blob/0a259e5/src/main.ts#L59)

___

Expand All @@ -33,7 +34,7 @@ ___

Options to use for prettier formatting. Default: undefined

Defined in: [src/main.ts:61](https://github.com/cobraz/generate-runtypes/blob/e397a85/src/main.ts#L61)
Defined in: [src/main.ts:62](https://github.com/cobraz/generate-runtypes/blob/0a259e5/src/main.ts#L62)

___

Expand All @@ -45,7 +46,7 @@ Function used to format the names of generated runtypes.
The function is passed in a name and must return a string that will be
used in place of that name.

Defined in: [src/main.ts:95](https://github.com/cobraz/generate-runtypes/blob/e397a85/src/main.ts#L95)
Defined in: [src/main.ts:96](https://github.com/cobraz/generate-runtypes/blob/0a259e5/src/main.ts#L96)

___

Expand All @@ -57,7 +58,7 @@ Function used to format the names of generated type.
The function is passed in a name and must return a string that will be
used in place of that name.

Defined in: [src/main.ts:102](https://github.com/cobraz/generate-runtypes/blob/e397a85/src/main.ts#L102)
Defined in: [src/main.ts:103](https://github.com/cobraz/generate-runtypes/blob/0a259e5/src/main.ts#L103)

___

Expand All @@ -70,7 +71,7 @@ When turned on, `import * as rt from "runtypes";` will be added at the
top of the generated code.
Default: true

Defined in: [src/main.ts:69](https://github.com/cobraz/generate-runtypes/blob/e397a85/src/main.ts#L69)
Defined in: [src/main.ts:70](https://github.com/cobraz/generate-runtypes/blob/0a259e5/src/main.ts#L70)

___

Expand All @@ -94,4 +95,16 @@ const myRuntype = rt.Record({ name: rt.String });
type MyRuntype = rt.Static<typeof myRuntype>;
```

Defined in: [src/main.ts:88](https://github.com/cobraz/generate-runtypes/blob/e397a85/src/main.ts#L88)
Defined in: [src/main.ts:89](https://github.com/cobraz/generate-runtypes/blob/0a259e5/src/main.ts#L89)

___

### rejectCyclicDependencies

`Optional` **rejectCyclicDependencies**: *boolean*

Whether to throw when encountering root types with cyclic dependencies,
or emit possibly broken code for them.
Default: false

Defined in: [src/main.ts:110](https://github.com/cobraz/generate-runtypes/blob/0a259e5/src/main.ts#L110)
2 changes: 1 addition & 1 deletion docs/modules/main.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,4 @@ Re-exports: [rootTypeRt](types.md#roottypert)

**Returns:** *string*

Defined in: [src/main.ts:118](https://github.com/cobraz/generate-runtypes/blob/e397a85/src/main.ts#L118)
Defined in: [src/main.ts:127](https://github.com/cobraz/generate-runtypes/blob/0a259e5/src/main.ts#L127)
24 changes: 12 additions & 12 deletions docs/modules/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

Ƭ **AnyType**: *rt.Static*<*typeof* anyTypeRt\>

Defined in: [src/types.ts:162](https://github.com/cobraz/generate-runtypes/blob/e397a85/src/types.ts#L162)
Defined in: [src/types.ts:162](https://github.com/cobraz/generate-runtypes/blob/0a259e5/src/types.ts#L162)

___

Expand All @@ -44,7 +44,7 @@ ___
| `readonly?` | *boolean* |
| `type` | [*AnyType*](types.md#anytype) |

Defined in: [src/types.ts:78](https://github.com/cobraz/generate-runtypes/blob/e397a85/src/types.ts#L78)
Defined in: [src/types.ts:78](https://github.com/cobraz/generate-runtypes/blob/0a259e5/src/types.ts#L78)

___

Expand All @@ -59,7 +59,7 @@ ___
| `kind` | ``"dictionary"`` |
| `valueType` | [*AnyType*](types.md#anytype) |

Defined in: [src/types.ts:95](https://github.com/cobraz/generate-runtypes/blob/e397a85/src/types.ts#L95)
Defined in: [src/types.ts:95](https://github.com/cobraz/generate-runtypes/blob/0a259e5/src/types.ts#L95)

___

Expand All @@ -74,23 +74,23 @@ ___
| `kind` | ``"intersect"`` |
| `types` | [*AnyType*](types.md#anytype)[] |

Defined in: [src/types.ts:130](https://github.com/cobraz/generate-runtypes/blob/e397a85/src/types.ts#L130)
Defined in: [src/types.ts:130](https://github.com/cobraz/generate-runtypes/blob/0a259e5/src/types.ts#L130)

___

### LiteralType

Ƭ **LiteralType**: *rt.Static*<*typeof* literalTypeRt\>

Defined in: [src/types.ts:32](https://github.com/cobraz/generate-runtypes/blob/e397a85/src/types.ts#L32)
Defined in: [src/types.ts:32](https://github.com/cobraz/generate-runtypes/blob/0a259e5/src/types.ts#L32)

___

### NamedType

Ƭ **NamedType**: *rt.Static*<*typeof* namedTypeRt\>

Defined in: [src/types.ts:46](https://github.com/cobraz/generate-runtypes/blob/e397a85/src/types.ts#L46)
Defined in: [src/types.ts:46](https://github.com/cobraz/generate-runtypes/blob/0a259e5/src/types.ts#L46)

___

Expand All @@ -108,7 +108,7 @@ ___
| `readonly?` | *boolean* |
| `type` | [*AnyType*](types.md#anytype) |

Defined in: [src/types.ts:48](https://github.com/cobraz/generate-runtypes/blob/e397a85/src/types.ts#L48)
Defined in: [src/types.ts:48](https://github.com/cobraz/generate-runtypes/blob/0a259e5/src/types.ts#L48)

___

Expand All @@ -123,23 +123,23 @@ ___
| `fields` | [*RecordField*](types.md#recordfield)[] |
| `kind` | ``"record"`` |

Defined in: [src/types.ts:56](https://github.com/cobraz/generate-runtypes/blob/e397a85/src/types.ts#L56)
Defined in: [src/types.ts:56](https://github.com/cobraz/generate-runtypes/blob/0a259e5/src/types.ts#L56)

___

### RootType

Ƭ **RootType**: *rt.Static*<*typeof* [*rootTypeRt*](types.md#roottypert)\>

Defined in: [src/types.ts:174](https://github.com/cobraz/generate-runtypes/blob/e397a85/src/types.ts#L174)
Defined in: [src/types.ts:174](https://github.com/cobraz/generate-runtypes/blob/0a259e5/src/types.ts#L174)

___

### SimpleType

Ƭ **SimpleType**: *rt.Static*<*typeof* simpleTypeRt\>

Defined in: [src/types.ts:21](https://github.com/cobraz/generate-runtypes/blob/e397a85/src/types.ts#L21)
Defined in: [src/types.ts:21](https://github.com/cobraz/generate-runtypes/blob/0a259e5/src/types.ts#L21)

___

Expand All @@ -154,12 +154,12 @@ ___
| `kind` | ``"union"`` |
| `types` | [*AnyType*](types.md#anytype)[] |

Defined in: [src/types.ts:110](https://github.com/cobraz/generate-runtypes/blob/e397a85/src/types.ts#L110)
Defined in: [src/types.ts:110](https://github.com/cobraz/generate-runtypes/blob/0a259e5/src/types.ts#L110)

## Variables

### rootTypeRt

`Const` **rootTypeRt**: *Intersect*<[*Record*<{ `name`: *String* ; `type`: *Union*<[*Runtype*<[*ArrayType*](types.md#arraytype)\>, *Runtype*<[*DictionaryType*](types.md#dictionarytype)\>, *Runtype*<[*IntersectionType*](types.md#intersectiontype)\>, *Record*<{ `kind`: *Literal*<``"literal"``\> ; `value`: *Union*<[*Boolean*, *Literal*<``null``\>, *Number*, *String*, *Literal*<undefined\>]\> }, ``false``\>, *Record*<{ `kind`: *Literal*<``"named"``\> ; `name`: *String* }, ``false``\>, *Runtype*<[*RecordType*](types.md#recordtype)\>, *Record*<{ `kind`: *Union*<[*Literal*<``"boolean"``\>, *Literal*<``"function"``\>, *Literal*<``"never"``\>, *Literal*<``"null"``\>, *Literal*<``"number"``\>, *Literal*<``"string"``\>, *Literal*<``"symbol"``\>, *Literal*<``"undefined"``\>, *Literal*<``"unknown"``\>]\> }, ``false``\>, *Runtype*<[*UnionType*](types.md#uniontype)\>]\> }, ``false``\>, *InternalRecord*<{ `comment`: *Union*<[*String*, *Arr*<String, ``false``\>]\> ; `export`: *Boolean* }, ``true``, ``false``\>]\>

Defined in: [src/types.ts:164](https://github.com/cobraz/generate-runtypes/blob/e397a85/src/types.ts#L164)
Defined in: [src/types.ts:164](https://github.com/cobraz/generate-runtypes/blob/0a259e5/src/types.ts#L164)
48 changes: 47 additions & 1 deletion docs/modules/util.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,56 @@

### Functions

- [getCyclicDependencies](util.md#getcyclicdependencies)
- [getNamedTypes](util.md#getnamedtypes)
- [groupFieldKinds](util.md#groupfieldkinds)

## Functions

### getCyclicDependencies

**getCyclicDependencies**(`roots`: [*RootType*](types.md#roottype)[]): [*string*, *string*][]

Finds root type that reference each other cyclicly. Returns an array of
tuples. Each tuple contains two strings; the name of the roots that reference
each other.

Dependencies can either be a root referencing itself, two roots directly
referencing each other, or roots referencing each other via other named
types.

#### Parameters

| Name | Type |
| :------ | :------ |
| `roots` | [*RootType*](types.md#roottype)[] |

**Returns:** [*string*, *string*][]

Defined in: [src/util.ts:123](https://github.com/cobraz/generate-runtypes/blob/0a259e5/src/util.ts#L123)

___

### getNamedTypes

`Private` **getNamedTypes**(`t`: [*AnyType*](types.md#anytype)): readonly *string*[]

Get a list of all named named types referenced in a type

public for testing

#### Parameters

| Name | Type |
| :------ | :------ |
| `t` | [*AnyType*](types.md#anytype) |

**Returns:** readonly *string*[]

Defined in: [src/util.ts:72](https://github.com/cobraz/generate-runtypes/blob/0a259e5/src/util.ts#L72)

___

### groupFieldKinds

`Private` **groupFieldKinds**(`fields`: readonly [*RecordField*](types.md#recordfield)[]): { `fields`: [*RecordField*](types.md#recordfield)[] ; `nullable`: *boolean* ; `readonly`: *boolean* }[]
Expand All @@ -26,4 +72,4 @@ Used to evaluate if `Record` type include `readonly` and/or `nullable`

**Returns:** { `fields`: [*RecordField*](types.md#recordfield)[] ; `nullable`: *boolean* ; `readonly`: *boolean* }[]

Defined in: [src/util.ts:9](https://github.com/cobraz/generate-runtypes/blob/e397a85/src/util.ts#L9)
Defined in: [src/util.ts:10](https://github.com/cobraz/generate-runtypes/blob/0a259e5/src/util.ts#L10)
45 changes: 45 additions & 0 deletions src/__tests__/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -668,4 +668,49 @@ describe('runtype generation', () => {
"
`);
});

describe('cyclical dependencies', () => {
it('emits code for cyclical dependencies when allowed', () => {
const source = generateRuntypes(
{
name: 'person',
type: {
kind: 'record',
fields: [
{ name: 'name', type: { kind: 'string' } },
{ name: 'parent', type: { kind: 'named', name: 'person' } },
],
},
},
{ rejectCyclicDependencies: false },
);

expect(source).toMatchInlineSnapshot(`
"import * as rt from \\"runtypes\\";
const person = rt.Record({ name: rt.String, parent: person });
type Person = rt.Static<typeof person>;
"
`);
});

it('throws when not allowed', () => {
expect(() => {
generateRuntypes(
{
name: 'person',
type: {
kind: 'record',
fields: [
{ name: 'name', type: { kind: 'string' } },
{ name: 'parent', type: { kind: 'named', name: 'person' } },
],
},
},
{ rejectCyclicDependencies: true },
);
}).toThrow();
});
});
});
Loading

0 comments on commit 2e33303

Please sign in to comment.