diff --git a/declarations/babel.js b/declarations/babel.js index a96a823..ec51f16 100644 --- a/declarations/babel.js +++ b/declarations/babel.js @@ -737,6 +737,11 @@ declare module '@babel/types' { callProperties: ObjectTypeCallProperty[]; } + declare class ObjectTypeSpreadProperty extends Node { + type: 'ObjectTypeSpreadProperty'; + argument: GenericTypeAnnotation; + } + declare class ObjectTypeCallProperty extends Node { type: 'ObjectTypeCallProperty'; value: FlowTypeAnnotation; @@ -1219,6 +1224,7 @@ declare module '@babel/types' { declare function isObjectTypeCallProperty(node: mixed, opts: Object | void): boolean %checks (node instanceof ObjectTypeCallProperty); declare function isObjectTypeIndexer(node: mixed, opts: Object | void): boolean %checks (node instanceof ObjectTypeIndexer); declare function isObjectTypeProperty(node: mixed, opts: Object | void): boolean %checks (node instanceof ObjectTypeProperty); + declare function isObjectTypeSpreadProperty(node: mixed, opts: Object | void): boolean %checks (node instanceof ObjectTypeSpreadProperty); declare function isQualifiedTypeIdentifier(node: mixed, opts: Object | void): boolean %checks (node instanceof QualifiedTypeIdentifier); declare function isUnionTypeAnnotation(node: mixed, opts: Object | void): boolean %checks (node instanceof UnionTypeAnnotation); declare function isVoidTypeAnnotation(node: mixed, opts: Object | void): boolean %checks (node instanceof VoidTypeAnnotation); diff --git a/package.json b/package.json index 25f8388..f326e85 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "bin/" ], "dependencies": { - "@babel/types": "^7.0.0-beta.32", + "@babel/types": "^7.4.4", "babylon": "^7.0.0-beta.32", "json-stringify-pretty-compact": "^1.0.4", "resolve": "^1.5.0", diff --git a/src/collector/definitions.js b/src/collector/definitions.js index c4dd86a..e49379c 100644 --- a/src/collector/definitions.js +++ b/src/collector/definitions.js @@ -9,11 +9,12 @@ import type { UnionTypeAnnotation, NullableTypeAnnotation, ObjectTypeIndexer, ObjectTypeProperty, StringLiteralTypeAnnotation, ObjectTypeAnnotation, AnyTypeAnnotation, MixedTypeAnnotation, TupleTypeAnnotation, DeclareTypeAlias, DeclareInterface, DeclareClass, + ObjectTypeSpreadProperty, } from '@babel/types'; import { isIdentifier, isStringLiteral, isObjectTypeProperty, - isStringLiteralTypeAnnotation, isClassProperty, + isStringLiteralTypeAnnotation, isClassProperty, isObjectTypeSpreadProperty, } from '@babel/types'; import Context from './context'; @@ -157,6 +158,13 @@ function makeComplex(ctx: Context, node: ObjectTypeAnnotation): Type { .filter() .toArray(); + if (node.properties.some(node => isObjectTypeSpreadProperty(node))) { + return t.createIntersection([ + ...makeSpreadTypes(ctx, node.properties), + ...maps, + ]) + } + const record = makeRecord(ctx, node.properties); if (maps.length === 1 && record.fields.length === 0) { @@ -181,6 +189,19 @@ function makeRecord(ctx: Context, nodes: return t.createRecord(fields); } +function makeSpreadTypes(ctx: Context, nodes: T[]): Type[] { + return wu(nodes) + .map(node => { + if (!isObjectTypeSpreadProperty(node)) { + return makeRecord(ctx, [node]); + } + + return makeReference(ctx, node.argument); + }) + .filter() + .toArray(); +} + function makeField(ctx: Context, node: ObjectTypeProperty | ClassProperty): ?Field { if ((node: $FlowIssue<3129>).static) { return null; diff --git a/tests/samples/spread/schema.json b/tests/samples/spread/schema.json new file mode 100644 index 0000000..9672807 --- /dev/null +++ b/tests/samples/spread/schema.json @@ -0,0 +1,34 @@ +{ + "$schema": "http://json-schema.org/draft-06/schema#", + "definitions": { + "spread::Base": { + "type": "object", + "properties": { + "foo": {"type": "string"}, + "bar": {"type": "boolean"} + }, + "required": ["foo", "bar"] + }, + "spread::Type": { + "allOf": [ + { + "$ref": "#/definitions/spread::Base" + }, + { + "type": "object", + "properties": { + "baz": {"type": "number"} + }, + "required": ["baz"] + }, + { + "type": "object", + "properties": { + "bim": {"type": "string"} + }, + "required": ["bim"] + } + ] + } + } +} diff --git a/tests/samples/spread/source.js b/tests/samples/spread/source.js new file mode 100644 index 0000000..cf30311 --- /dev/null +++ b/tests/samples/spread/source.js @@ -0,0 +1,12 @@ +type Base = { + foo: string, + bar: boolean, +}; + +type Type = { + ...Base, + baz: number, + bim: string, +}; + +export {Type}; diff --git a/tests/samples/spread/types.yaml b/tests/samples/spread/types.yaml new file mode 100644 index 0000000..6252309 --- /dev/null +++ b/tests/samples/spread/types.yaml @@ -0,0 +1,29 @@ +- kind: record + fields: + - name: foo + value: + kind: string + required: true + - name: bar + value: + kind: boolean + required: true + id: [spread, Base] +- kind: intersection + parts: + - kind: reference + to: [spread, Base] + - kind: record + fields: + - name: baz + value: + kind: number + repr: f64 + required: true + - kind: record + fields: + - name: bim + value: + kind: string + required: true + id: [spread, Type]