Add support for named intersections

master
Paul Loyd 2017-11-03 10:34:36 +03:00
parent a49624fb6e
commit 29348f75e0
2 changed files with 142 additions and 1 deletions

View File

@ -49,9 +49,19 @@ const extractors = {
let type = node.leadingComments && (yield* extractLastPragma(node.leadingComments));
if (!type) {
type = yield node.typeAnnotation;
}
if (type.type === 'record') {
type.namespace = yield namespace();
yield provide(type);
type = type.name;
}
return {
name: yield node.key,
type: type || (yield node.typeAnnotation),
type,
};
},
@ -96,6 +106,12 @@ const extractors = {
return null;
}
if (type.type === 'record') {
type.namespace = yield namespace();
yield provide(type);
type = type.name;
}
return {
name: yield node.key,
type,
@ -157,6 +173,19 @@ const extractors = {
return variants;
},
* IntersectionTypeAnnotation(node) {
const schemas = [];
for (const type of node.types) {
const name = yield type;
const schema = yield query(name);
schemas.push(schema);
}
return mergeSchemas(schemas);
},
* NullableTypeAnnotation(node) {
return ['null', yield node.typeAnnotation];
},
@ -294,4 +323,37 @@ function makeFullname(schema) {
return `${schema.namespace}.${schema.name}`;
}
function mergeSchemas(schemas) {
const map = new Map;
// TODO: overriding?
let name = '';
for (const schema of schemas) {
// TODO: enums?
assert.equal(schema.type, 'record');
for (const field of schema.fields) {
const stored = map.get(field.name);
if (stored) {
// TODO: what about enums?
// TODO: improve checking.
assert.equal(stored.type, field.type);
continue;
}
map.set(field.name, field);
}
name += '_' + schema.name;
}
return {
type: 'record',
name,
fields: Array.from(map.values()),
};
}
module.exports = extractors;

79
tests/intersections.js Normal file
View File

@ -0,0 +1,79 @@
type A = {a: number};
type B = {b: string};
type C = {c: boolean};
type X = A & B;
type Y = {
y: A & B & C,
};
class Z {
z: A & C;
}
// ###
[
{
type: 'record',
name: 'A',
namespace: 'intersections',
fields: [{name: 'a', type: 'double'}],
},
{
type: 'record',
name: 'B',
namespace: 'intersections',
fields: [{name: 'b', type: 'string'}],
},
{
type: 'record',
name: 'C',
namespace: 'intersections',
fields: [{name: 'c', type: 'boolean'}],
},
{
type: 'record',
name: 'X',
namespace: 'intersections',
fields: [
{name: 'a', type: 'double'},
{name: 'b', type: 'string'},
],
},
{
type: 'record',
name: '_A_B_C',
namespace: 'intersections',
fields: [
{name: 'a', type: 'double'},
{name: 'b', type: 'string'},
{name: 'c', type: 'boolean'},
],
},
{
type: 'record',
name: 'Y',
namespace: 'intersections',
fields: [
{name: 'y', type: '_A_B_C'},
],
},
{
type: 'record',
name: '_A_C',
namespace: 'intersections',
fields: [
{name: 'a', type: 'double'},
{name: 'c', type: 'boolean'},
],
},
{
type: 'record',
name: 'Z',
namespace: 'intersections',
fields: [
{name: 'z', type: '_A_C'},
],
},
]