Add support for $ElementType and $PropertyType

master
Paul Loyd 2017-11-29 00:45:18 +03:00
parent 87979aa328
commit c95581329e
6 changed files with 102 additions and 4 deletions

View File

@ -1,5 +1,6 @@
import * as fs from 'fs';
import * as pathlib from 'path';
import wu from 'wu';
import {isNode} from '@babel/types';
import type {Node} from '@babel/types';
@ -145,7 +146,8 @@ export default class Collector {
return result.type;
case 'special':
const type = result.call(params);
const resolve = id => this._findTypeById(id);
const type = result.call(params, resolve);
invariant(type);
@ -160,6 +162,22 @@ export default class Collector {
this._query(scope, name, []);
}
}
_findTypeById(id: TypeId): Type {
// TODO: get rid of the linear search.
for (const type of this.types) {
invariant(type.id);
const is = type.id.join('::') === id.join('::');
if (is) {
return type;
}
}
invariant(false);
}
}
function pathToId(path: string): TypeId {

View File

@ -1,5 +1,7 @@
import wu from 'wu';
import {invariant} from './utils';
import type {Type} from './types';
import type {Type, TypeId} from './types';
function object(params: (?Type)[]): ?Type {
invariant(params.length === 0);
@ -30,9 +32,32 @@ function array(params: (?Type)[]): ?Type {
};
}
function elemType(params: (?Type)[], resolve: TypeId => Type): ?Type {
invariant(params.length === 2);
const [ref, key] = params;
invariant(ref && key);
invariant(ref.kind === 'reference');
const record = resolve(ref.to);
invariant(record.kind === 'record');
// TODO: support for references.
invariant(key.kind === 'literal');
invariant(typeof key.value === 'string');
const field = wu(record.fields).find(field => field.name === key.value);
return field ? Object.assign({}, (field.value: $FlowFixMe)) : null;
}
export default {
Object: object,
Buffer: buffer,
Array: array,
$ReadOnlyArray: array,
$PropertyType: elemType,
$ElementType: elemType,
};

View File

@ -1,7 +1,7 @@
import type {Node} from '@babel/types';
import type Scope from './scope';
import type {Type} from './types';
import type {Type, TypeId} from './types';
export type Query =
| Unknown
@ -48,7 +48,7 @@ export type Special = {
call: SpecialFn,
};
export type SpecialFn = (?Type)[] => ?Type;
export type SpecialFn = ((?Type)[], TypeId => Type) => ?Type;
export type TemplateParam = {
name: string,

View File

@ -182,6 +182,8 @@ function getTypeName(type: Type): string {
case 'string':
case 'boolean':
return type.kind;
case 'literal':
return String(type.value);
default:
invariant(false);
}

View File

@ -0,0 +1,11 @@
type X<T> = {
x: T | string,
};
type Y<T> = {
y: $ElementType<X<boolean>, T>,
};
type Z = $PropertyType<Y<'x'>, 'y'>;
export {Z};

View File

@ -0,0 +1,42 @@
{
"types": [
{
"id": ["elementType", "X", "boolean"],
"kind": "record",
"fields": [{
"name": "x",
"value": {
"kind": "union",
"variants": [
{"kind": "boolean"},
{"kind": "string"}
]
},
"required": true
}]
},
{
"id": ["elementType", "Y", "x"],
"kind": "record",
"fields": [{
"name": "y",
"value": {
"kind": "union",
"variants": [
{"kind": "boolean"},
{"kind": "string"}
]
},
"required": true
}]
},
{
"id": ["elementType", "Z"],
"kind": "union",
"variants": [
{"kind": "boolean"},
{"kind": "string"}
]
}
]
}