diff --git a/src/collector/globals.js b/src/collector/globals.js index 24d744a..e5501e8 100644 --- a/src/collector/globals.js +++ b/src/collector/globals.js @@ -135,6 +135,39 @@ function values(params: (?Type)[], resolve: TypeId => Type): ?Type { return t.createUnion(variants); } +function diff(params: (?Type)[], resolve: TypeId => Type): ?Type { + invariant(params.length === 2); + + let [minuend, subtrahend] = params; + + invariant(minuend && subtrahend); + invariant(minuend.kind === 'reference'); + + minuend = resolve(minuend.to); + + invariant(minuend.kind === 'record'); + + if (subtrahend.kind === 'reference') { + subtrahend = resolve(subtrahend.to); + } + + invariant(subtrahend.kind === 'record'); + + // TODO: more clever subtraction. + const blacklist = wu(subtrahend.fields).pluck('name').toArray(); + + const fields = wu(minuend.fields) + .filter(field => !blacklist.includes(field.name)) + .map(field => ({ + name: field.name, + value: t.clone(field.value), + required: field.required, + })) + .toArray(); + + return t.createRecord(fields); +} + export default { Object: object, Buffer: buffer, @@ -148,7 +181,7 @@ export default { $Exact: unwrap, // TODO: another semantic for exact types? $Keys: keys, $Values: values, - // TODO: $Diff + $Diff: diff, // TODO: $All // TODO: $Either }; diff --git a/tests/samples/diffs/source.js b/tests/samples/diffs/source.js new file mode 100644 index 0000000..b619672 --- /dev/null +++ b/tests/samples/diffs/source.js @@ -0,0 +1,13 @@ +type A = { + x: string, + y: boolean, +}; + +type B = { + y: boolean, +}; + +type X = $Diff; +type Y = $Diff; + +export {X, Y}; diff --git a/tests/samples/diffs/types.yaml b/tests/samples/diffs/types.yaml new file mode 100644 index 0000000..2d8bc94 --- /dev/null +++ b/tests/samples/diffs/types.yaml @@ -0,0 +1,27 @@ +- kind: record + fields: + - name: x + value: {kind: string} + required: true + - name: y + value: {kind: boolean} + required: true + id: [diffs, A] +- kind: record + fields: + - name: y + value: {kind: boolean} + required: true + id: [diffs, B] +- kind: record + fields: + - name: x + value: {kind: string} + required: true + id: [diffs, X] +- kind: record + fields: + - name: y + value: {kind: boolean} + required: true + id: [diffs, Y]