Introduce intermediate representation
parent
777d8a0acd
commit
317f8e6e1c
|
@ -16,3 +16,7 @@ module.use_strict=true
|
|||
munge_underscores=true
|
||||
include_warnings=true
|
||||
unsafe.enable_getters_and_setters=true
|
||||
suppress_comment= \\(.\\|\n\\)*\\$FlowFixMe
|
||||
suppress_comment= \\(.\\|\n\\)*\\$FlowIssue
|
||||
suppress_type=$FlowFixMe
|
||||
suppress_type=$FlowIssue
|
||||
|
|
37
README.md
37
README.md
|
@ -5,43 +5,6 @@
|
|||
[![Windows Build](https://ci.appveyor.com/api/projects/status/github/loyd/flow2schema?branch=master&svg=true)](https://ci.appveyor.com/project/loyd/flow2schema)
|
||||
[![Coverage Status](https://coveralls.io/repos/github/loyd/flow2schema/badge.svg?branch=master)](https://coveralls.io/r/loyd/flow2schema?branch=master)
|
||||
|
||||
Currently avro is the only supported target.
|
||||
|
||||
## Example
|
||||
|
||||
Input (`$ cat example.js`):
|
||||
```javascript
|
||||
export interface Foo {
|
||||
foo: string,
|
||||
// $avro long
|
||||
bar: number,
|
||||
opt: ?number,
|
||||
baz: 'one' | 'two',
|
||||
mix: 'one' | 'two' | number,
|
||||
}
|
||||
```
|
||||
|
||||
Output (`$ ./bin/flow2schema example.js`):
|
||||
```json
|
||||
[
|
||||
{
|
||||
"type": "record",
|
||||
"fields": [
|
||||
{"name": "foo", "type": "string"},
|
||||
{"name": "bar", "type": "double"},
|
||||
{"name": "opt", "type": ["null", "double"]},
|
||||
{"name": "baz", "type": {"type": "enum", "symbols": ["one", "two"]}},
|
||||
{
|
||||
"name": "mix",
|
||||
"type": ["double", {"type": "enum", "symbols": ["one", "two"]}]
|
||||
}
|
||||
],
|
||||
"name": "Foo",
|
||||
"namespace": "example"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## TODO
|
||||
* Complete generics support.
|
||||
* Errors and warnings.
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
declare module 'wu' {
|
||||
declare type DeepIterable<U> = Iterable<U | DeepIterable<U>>;
|
||||
declare type Flat<T> = $Call<<U>(Iterable<U> | U) => U, T>;
|
||||
declare type DeepFlat<T> = $Call<<U>(DeepIterable<U> | U) => U, T>;
|
||||
|
||||
declare export default class Wu<T> {
|
||||
static <T>(Iterable<T>): Wu<T>;
|
||||
|
||||
tap(T => mixed): Wu<T>;
|
||||
|
||||
map<U>(T => U): Wu<U>;
|
||||
|
||||
filter(): Wu<$NonMaybeType<T>>;
|
||||
filter(T => boolean): Wu<T>;
|
||||
|
||||
flatten(): Wu<DeepFlat<T>>;
|
||||
flatten(true): Wu<DeepFlat<T>>;
|
||||
flatten(false): Wu<Flat<T>>;
|
||||
|
||||
find(T => boolean): T | void;
|
||||
|
||||
pluck<K: $Keys<T>>(K): Wu<$ElementType<T, K>>;
|
||||
|
||||
toArray(): T[];
|
||||
}
|
||||
}
|
|
@ -27,7 +27,8 @@
|
|||
"babylon": "^7.0.0-beta.32",
|
||||
"json-stringify-pretty-compact": "^1.0.4",
|
||||
"optimist": "^0.6.1",
|
||||
"resolve": "^1.5.0"
|
||||
"resolve": "^1.5.0",
|
||||
"wu": "^2.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.0.0-beta.32",
|
||||
|
|
|
@ -15,9 +15,9 @@ function run(path: string) {
|
|||
}
|
||||
|
||||
try {
|
||||
const {schemas} = collect(path);
|
||||
const {types} = collect(path);
|
||||
|
||||
console.log(stringify(schemas, {maxLength: 100}));
|
||||
console.log(stringify(types, {maxLength: 100}));
|
||||
} catch (ex) {
|
||||
console.error(ex.message);
|
||||
console.error(ex.stack);
|
||||
|
|
|
@ -10,28 +10,24 @@ import declarationGroup from './declarations';
|
|||
import Module from './module';
|
||||
import Scope from './scope';
|
||||
import Context from './context';
|
||||
import {invariant, get, map} from './utils';
|
||||
import {invariant} from './utils';
|
||||
import type Parser from './parser';
|
||||
import type {Schema, Type} from './schema';
|
||||
|
||||
type InstanceParam = {
|
||||
name: string,
|
||||
value: ?Type,
|
||||
};
|
||||
import type {Type, TypeId} from './types';
|
||||
import type {TemplateParam} from './query';
|
||||
|
||||
const VISITOR = Object.assign({}, definitionGroup, declarationGroup);
|
||||
|
||||
export default class Collector {
|
||||
+root: string;
|
||||
+parser: Parser;
|
||||
+schemas: Schema[];
|
||||
+types: Type[];
|
||||
_modules: Map<string, Module>;
|
||||
_global: Scope;
|
||||
|
||||
constructor(parser: Parser, root: string = '.') {
|
||||
this.root = root;
|
||||
this.parser = parser;
|
||||
this.schemas = [];
|
||||
this.types = [];
|
||||
this._modules = new Map;
|
||||
this._global = Scope.global(globals);
|
||||
}
|
||||
|
@ -51,9 +47,9 @@ export default class Collector {
|
|||
const ast = this.parser.parse(code);
|
||||
|
||||
// TODO: customize it.
|
||||
const namespace = pathToNamespace(pathlib.relative('.', path));
|
||||
const id = pathToId(path);
|
||||
|
||||
module = new Module(path, namespace);
|
||||
module = new Module(id, path);
|
||||
|
||||
const scope = this._global.extend(module);
|
||||
|
||||
|
@ -66,7 +62,7 @@ export default class Collector {
|
|||
}
|
||||
}
|
||||
|
||||
_freestyle(root: Node, scope: Scope, params: InstanceParam[]) {
|
||||
_freestyle(root: Node, scope: Scope, params: TemplateParam[]) {
|
||||
const ctx = new Context(this, scope, params);
|
||||
|
||||
const iter = traverse(root);
|
||||
|
@ -88,7 +84,7 @@ export default class Collector {
|
|||
let result = scope.query(name, params);
|
||||
|
||||
// TODO: warning.
|
||||
invariant(result.type !== 'unknown');
|
||||
invariant(result.kind !== 'unknown');
|
||||
|
||||
// Resulting scope is always the best choice for waiting.
|
||||
scope = result.scope;
|
||||
|
@ -96,7 +92,7 @@ export default class Collector {
|
|||
// It's only valid the sequence: E*[CT]?F,
|
||||
// where E - external, C - declaration, T - template, F - definition.
|
||||
|
||||
switch (result.type) {
|
||||
switch (result.kind) {
|
||||
case 'external':
|
||||
const modulePath = scope.resolve(result.info.path);
|
||||
|
||||
|
@ -110,12 +106,12 @@ export default class Collector {
|
|||
|
||||
result = module.query(imported, params);
|
||||
|
||||
if (result.type === 'definition') {
|
||||
return result.schema;
|
||||
if (result.kind === 'definition') {
|
||||
return result.type;
|
||||
}
|
||||
|
||||
// TODO: reexports.
|
||||
invariant(result.type === 'declaration' || result.type === 'template');
|
||||
invariant(result.kind === 'declaration' || result.kind === 'template');
|
||||
|
||||
scope = result.scope;
|
||||
name = result.name;
|
||||
|
@ -125,26 +121,26 @@ export default class Collector {
|
|||
case 'template':
|
||||
const tmplParams = [];
|
||||
|
||||
if (result.type === 'template') {
|
||||
if (result.kind === 'template') {
|
||||
for (const [i, p] of result.params.entries()) {
|
||||
tmplParams.push({
|
||||
name: p.name,
|
||||
value: params[i] === undefined ? p.default : params[i],
|
||||
value: params[i] === undefined ? p.value : params[i],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
invariant(result.type === 'declaration' || result.type === 'template');
|
||||
invariant(result.kind === 'declaration' || result.kind === 'template');
|
||||
|
||||
this._freestyle(result.node, scope, tmplParams);
|
||||
|
||||
result = scope.query(name, params);
|
||||
|
||||
invariant(result.type === 'definition');
|
||||
invariant(result.kind === 'definition');
|
||||
|
||||
// Fallthrough.
|
||||
case 'definition':
|
||||
return result.schema;
|
||||
return result.type;
|
||||
}
|
||||
|
||||
invariant(false);
|
||||
|
@ -157,14 +153,14 @@ export default class Collector {
|
|||
}
|
||||
}
|
||||
|
||||
function pathToNamespace(path: string): string {
|
||||
const pathObj = pathlib.parse(path);
|
||||
function pathToId(path: string): TypeId {
|
||||
const relPath = pathlib.relative('.', path);
|
||||
const pathObj = pathlib.parse(relPath);
|
||||
|
||||
return pathlib.format({
|
||||
dir: pathObj.dir,
|
||||
name: pathObj.name,
|
||||
})
|
||||
// TODO: replace invalid chars.
|
||||
.split(pathlib.sep)
|
||||
.join('.');
|
||||
.split(pathlib.sep);
|
||||
}
|
||||
|
|
|
@ -1,31 +1,23 @@
|
|||
import wu from 'wu';
|
||||
import type {Node} from '@babel/types';
|
||||
|
||||
import Scope from './scope';
|
||||
import Collector from './collector';
|
||||
import {invariant, get, map} from './utils';
|
||||
import type {Schema, Type, ComplexType} from './schema';
|
||||
import {invariant} from './utils';
|
||||
import type {Type} from './types';
|
||||
import type {TemplateParam, ExternalInfo} from './query';
|
||||
|
||||
type InstanceParam = {
|
||||
name: string,
|
||||
value: ?Type,
|
||||
};
|
||||
|
||||
export default class Context {
|
||||
_collector: Collector;
|
||||
_scope: Scope;
|
||||
_params: InstanceParam[];
|
||||
_params: TemplateParam[];
|
||||
|
||||
constructor(collector: Collector, scope: Scope, params: InstanceParam[]) {
|
||||
constructor(collector: Collector, scope: Scope, params: TemplateParam[]) {
|
||||
this._collector = collector;
|
||||
this._scope = scope;
|
||||
this._params = params;
|
||||
}
|
||||
|
||||
get namespace(): string {
|
||||
return this._scope.namespace;
|
||||
}
|
||||
|
||||
freestyle(node: Node) {
|
||||
this._collector._freestyle(node, this._scope, this._params);
|
||||
}
|
||||
|
@ -34,26 +26,18 @@ export default class Context {
|
|||
this._scope.addDeclaration(name, node, params || []);
|
||||
}
|
||||
|
||||
define(name: string, type: ComplexType, declared: boolean = true): Schema {
|
||||
// TODO: dirty support for intersections.
|
||||
const _name = type.name != null ? type.name : name;
|
||||
|
||||
const schema: $FlowFixMe = Object.assign({}, type, {
|
||||
name,
|
||||
namespace: this._scope.namespace,
|
||||
});
|
||||
|
||||
define(name: string, type: Type, declared: boolean = true): Type {
|
||||
if (declared && this._params.length > 0) {
|
||||
schema.name = generateGenericName(name, this._params);
|
||||
const params = wu(this._params).pluck('value').toArray();
|
||||
|
||||
this._scope.addInstance(name, schema, map(this._params, get('value')));
|
||||
this._scope.addInstance(name, type, params);
|
||||
} else {
|
||||
this._scope.addDefinition(schema, declared);
|
||||
this._scope.addDefinition(name, type, declared);
|
||||
}
|
||||
|
||||
this._collector.schemas.push(schema);
|
||||
this._collector.types.push(type);
|
||||
|
||||
return schema;
|
||||
return type;
|
||||
}
|
||||
|
||||
external(external: ExternalInfo) {
|
||||
|
@ -65,7 +49,7 @@ export default class Context {
|
|||
}
|
||||
|
||||
query(name: string, params: ?(?Type)[]): Type {
|
||||
const param = this._params.find(p => p.name === name);
|
||||
const param = wu(this._params).find(p => p.name === name);
|
||||
|
||||
if (param) {
|
||||
// TODO: warning about missing param.
|
||||
|
@ -86,14 +70,3 @@ export default class Context {
|
|||
this._scope = this._scope.parent;
|
||||
}
|
||||
}
|
||||
|
||||
function generateGenericName(base: string, params: InstanceParam[]): string {
|
||||
let name = base + '_';
|
||||
|
||||
for (const {value} of params) {
|
||||
invariant(typeof value === 'string');
|
||||
name += '_' + value;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
// flow#5376.
|
||||
import wu from 'wu';
|
||||
|
||||
// @see flow#5376.
|
||||
import type {
|
||||
Block, ClassDeclaration, ExportDefaultDeclaration, ExportNamedDeclaration, Identifier,
|
||||
ImportDeclaration, ImportDefaultSpecifier, ImportSpecifier, InterfaceDeclaration,
|
||||
|
@ -12,7 +14,7 @@ import {
|
|||
isStringLiteral, isTypeAlias, isVariableDeclaration,
|
||||
} from '@babel/types';
|
||||
|
||||
import {invariant, map, filter} from './utils';
|
||||
import {invariant} from './utils';
|
||||
import Context from './context';
|
||||
import type {ExternalInfo, TemplateParam} from './query';
|
||||
|
||||
|
@ -146,7 +148,10 @@ function extractCommonjsNamedExternals<+T: Node>(nodes: T[], path: string): Exte
|
|||
path,
|
||||
});
|
||||
|
||||
return map(filter(nodes, pred), make);
|
||||
return wu(nodes)
|
||||
.filter(pred)
|
||||
.map(make)
|
||||
.toArray();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -201,7 +206,7 @@ function processDeclaration(ctx: Context, node: Declaration) {
|
|||
|
||||
// TODO: do it only for "all"-mode.
|
||||
if (isClassDeclaration(node)) {
|
||||
const methods = filter(node.body.body, isClassMethod);
|
||||
const methods = wu(node.body.body).filter(isClassMethod).toArray();
|
||||
|
||||
for (const method of methods) {
|
||||
ctx.freestyle(method);
|
||||
|
@ -214,10 +219,13 @@ function processDeclaration(ctx: Context, node: Declaration) {
|
|||
}
|
||||
|
||||
function extractTemplateParams(node: TypeParameterDeclaration): TemplateParam[] {
|
||||
return map(node.params, param => ({
|
||||
name: param.name,
|
||||
default: null,
|
||||
}));
|
||||
return wu(node.params)
|
||||
.map(param => ({
|
||||
name: param.name,
|
||||
// TODO: default params.
|
||||
value: null,
|
||||
}))
|
||||
.toArray();
|
||||
}
|
||||
|
||||
export default {
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
// flow#5376.
|
||||
import wu from 'wu';
|
||||
|
||||
// @see flow#5376.
|
||||
import type {
|
||||
ArrayTypeAnnotation, ClassDeclaration, ClassProperty, Comment, FlowTypeAnnotation,
|
||||
GenericTypeAnnotation, InterfaceDeclaration, IntersectionTypeAnnotation, TypeAlias,
|
||||
UnionTypeAnnotation, NullableTypeAnnotation, ObjectTypeIndexer, ObjectTypeProperty,
|
||||
StringLiteralTypeAnnotation,
|
||||
StringLiteralTypeAnnotation, ObjectTypeAnnotation,
|
||||
} from '@babel/types';
|
||||
|
||||
import {
|
||||
|
@ -13,98 +15,104 @@ import {
|
|||
import Context from './context';
|
||||
|
||||
import type {
|
||||
Schema, Type, ReferenceType, ComplexType, RecordType, FixedType,
|
||||
FieldType, ArrayType, MapType, UnionType, EnumType,
|
||||
} from './schema';
|
||||
Type, RecordType, Field, ArrayType, TupleType, MapType, UnionType, IntersectionType,
|
||||
MaybeType, NumberType, StringType, BooleanType, LiteralType, ReferenceType,
|
||||
} from './types';
|
||||
|
||||
import {isPrimitiveType, isComplexType, makeFullname, mergeTypes} from './schema';
|
||||
import {invariant, compose, last, get, partition, map, filter, filterMap, compact} from './utils';
|
||||
import {extractPragmas} from './pragmas';
|
||||
|
||||
import {invariant} from './utils';
|
||||
|
||||
function processTypeAlias(ctx: Context, node: TypeAlias) {
|
||||
let type = makeType(ctx, node.right);
|
||||
const {name} = node.id;
|
||||
const type = makeType(ctx, node.right);
|
||||
|
||||
// TODO: support function aliases.
|
||||
invariant(type != null);
|
||||
// TODO: support top-level unions.
|
||||
invariant(!(type instanceof Array));
|
||||
invariant(type);
|
||||
|
||||
if (typeof type === 'string') {
|
||||
type = {type: type};
|
||||
}
|
||||
|
||||
ctx.define(node.id.name, type);
|
||||
ctx.define(name, type);
|
||||
}
|
||||
|
||||
// TODO: type params.
|
||||
function processInterfaceDeclaration(ctx: Context, node: InterfaceDeclaration) {
|
||||
let type = makeType(ctx, node.body);
|
||||
const {name} = node.id;
|
||||
const type = makeType(ctx, node.body);
|
||||
|
||||
invariant(type != null)
|
||||
invariant(isComplexType(type));
|
||||
invariant(type);
|
||||
|
||||
if (node.extends.length > 0) {
|
||||
const types = [];
|
||||
|
||||
for (const extend of node.extends) {
|
||||
const name = extend.id.name;
|
||||
const type = ctx.query(name);
|
||||
|
||||
invariant(isComplexType(type));
|
||||
|
||||
types.push((type: $FlowFixMe));
|
||||
}
|
||||
|
||||
types.push((type: $FlowFixMe));
|
||||
|
||||
[, type] = mergeTypes(types);
|
||||
if (node.extends.length === 0) {
|
||||
ctx.define(name, type);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.define(node.id.name, type);
|
||||
const parts = [];
|
||||
|
||||
for (const extend of node.extends) {
|
||||
const {name} = extend.id;
|
||||
const type = ctx.query(name);
|
||||
|
||||
invariant(type.id);
|
||||
|
||||
parts.push({
|
||||
kind: 'reference',
|
||||
to: type.id,
|
||||
});
|
||||
}
|
||||
|
||||
parts.push(type);
|
||||
|
||||
ctx.define(name, {
|
||||
kind: 'intersection',
|
||||
parts,
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: type params.
|
||||
function processClassDeclaration(ctx: Context, node: ClassDeclaration) {
|
||||
const props: $FlowFixMe = filter(node.body.body, isClassProperty);
|
||||
const props: $FlowFixMe = wu(node.body.body).filter(isClassProperty).toArray();
|
||||
|
||||
let type = makeRecord(ctx, props);
|
||||
const {name} = node.id;
|
||||
const type = makeRecord(ctx, props);
|
||||
|
||||
if (node.superClass) {
|
||||
// TODO: warning about expressions here.
|
||||
invariant(isIdentifier(node.superClass));
|
||||
|
||||
const {name} = node.superClass;
|
||||
const superSchema = ctx.query(name);
|
||||
|
||||
invariant(isComplexType(superSchema));
|
||||
|
||||
[, type] = mergeTypes([(superSchema: $FlowFixMe), (type: $FlowFixMe)]);
|
||||
if (!node.superClass) {
|
||||
ctx.define(name, type);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.define(node.id.name, type);
|
||||
// TODO: warning about expressions here.
|
||||
invariant(isIdentifier(node.superClass));
|
||||
|
||||
const base = ctx.query(node.superClass.name);
|
||||
|
||||
invariant(base.id);
|
||||
|
||||
const baseRef = {
|
||||
kind: 'reference',
|
||||
to: base.id,
|
||||
};
|
||||
|
||||
ctx.define(name, {
|
||||
kind: 'intersection',
|
||||
parts: [baseRef, type],
|
||||
});
|
||||
}
|
||||
|
||||
function makeType(ctx: Context, node: FlowTypeAnnotation): ?Type {
|
||||
switch (node.type) {
|
||||
case 'NullLiteralTypeAnnotation':
|
||||
return 'null';
|
||||
return {kind: 'literal', value: null};
|
||||
case 'BooleanTypeAnnotation':
|
||||
return 'boolean';
|
||||
return {kind: 'boolean'};
|
||||
case 'NumberTypeAnnotation':
|
||||
return 'double';
|
||||
return {kind: 'number', repr: 'f64'};
|
||||
case 'StringTypeAnnotation':
|
||||
return 'string';
|
||||
return {kind: 'string'};
|
||||
case 'TypeAnnotation':
|
||||
return makeType(ctx, node.typeAnnotation);
|
||||
case 'NullableTypeAnnotation':
|
||||
return makeNullable(ctx, node);
|
||||
return makeMaybe(ctx, node);
|
||||
case 'ObjectTypeAnnotation':
|
||||
const map = makeMap(ctx, node.indexers);
|
||||
const record = makeRecord(ctx, node.properties);
|
||||
|
||||
// TODO: warning about this.
|
||||
invariant(!map || record.fields.length === 0);
|
||||
|
||||
return map || record;
|
||||
return makeComplexType(ctx, node);
|
||||
case 'ArrayTypeAnnotation':
|
||||
return makeArrayType(ctx, node);
|
||||
case 'UnionTypeAnnotation':
|
||||
|
@ -112,50 +120,85 @@ function makeType(ctx: Context, node: FlowTypeAnnotation): ?Type {
|
|||
case 'IntersectionTypeAnnotation':
|
||||
return makeIntersection(ctx, node);
|
||||
case 'StringLiteralTypeAnnotation':
|
||||
return makeEnum(node);
|
||||
return {kind: 'literal', value: node.value};
|
||||
case 'GenericTypeAnnotation':
|
||||
return makeReference(ctx, node);
|
||||
case 'FunctionTypeAnnotation':
|
||||
return null;
|
||||
default:
|
||||
invariant(false, `Unknown type: ${node.type}`);
|
||||
invariant(false, `Unknown node: ${node.type}`);
|
||||
}
|
||||
}
|
||||
|
||||
function makeNullable(ctx: Context, node: NullableTypeAnnotation): ?UnionType {
|
||||
function makeMaybe(ctx: Context, node: NullableTypeAnnotation): ?MaybeType {
|
||||
const type = makeType(ctx, node.typeAnnotation);
|
||||
|
||||
if (type == null) {
|
||||
if (!type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ['null', type];
|
||||
return {
|
||||
kind: 'maybe',
|
||||
value: type,
|
||||
};
|
||||
}
|
||||
|
||||
function makeComplexType(ctx: Context, node: ObjectTypeAnnotation): Type {
|
||||
const maps = wu(node.indexers)
|
||||
.map(node => makeMap(ctx, node))
|
||||
.filter()
|
||||
.toArray();
|
||||
|
||||
const record = makeRecord(ctx, node.properties);
|
||||
|
||||
if (maps.length === 1 && record.fields.length === 0) {
|
||||
return maps[0];
|
||||
}
|
||||
|
||||
if (maps.length === 0) {
|
||||
return record;
|
||||
}
|
||||
|
||||
const parts = record.fields.length > 0 ? [record, ...maps] : maps;
|
||||
|
||||
return {
|
||||
kind: 'intersection',
|
||||
parts,
|
||||
};
|
||||
}
|
||||
|
||||
function makeRecord<T: ObjectTypeProperty | ClassProperty>(ctx: Context, nodes: T[]): RecordType {
|
||||
const fields = compact(map(nodes, node => makeField(ctx, node)));
|
||||
const fields = wu(nodes)
|
||||
.map(node => makeField(ctx, node))
|
||||
.filter()
|
||||
.toArray();
|
||||
|
||||
return {
|
||||
type: 'record',
|
||||
kind: 'record',
|
||||
fields,
|
||||
};
|
||||
}
|
||||
|
||||
function makeField(ctx: Context, node: ObjectTypeProperty | ClassProperty): ?FieldType {
|
||||
// $FlowFixMe
|
||||
if (node.static) {
|
||||
function makeField(ctx: Context, node: ObjectTypeProperty | ClassProperty): ?Field {
|
||||
if ((node: $FlowIssue<3129>).static) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let type = null;
|
||||
|
||||
if (node.leadingComments) {
|
||||
const pragmas = extractPragmas(node.leadingComments);
|
||||
const pragma = (wu: $FlowIssue<4431>)(node.leadingComments)
|
||||
.pluck('value')
|
||||
.map(extractPragmas)
|
||||
.flatten()
|
||||
.find(pragma => pragma.kind === 'type');
|
||||
|
||||
type = last(pragmas);
|
||||
if (pragma) {
|
||||
type = pragma.value;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == null) {
|
||||
if (!type) {
|
||||
const value = isObjectTypeProperty(node) ? node.value : node.typeAnnotation;
|
||||
|
||||
// TODO: no type annotation for the class property.
|
||||
|
@ -164,17 +207,10 @@ function makeField(ctx: Context, node: ObjectTypeProperty | ClassProperty): ?Fie
|
|||
type = makeType(ctx, value);
|
||||
}
|
||||
|
||||
if (type == null) {
|
||||
if (!type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isComplexType(type) && type.type === 'record') {
|
||||
const name = (type: $FlowFixMe).name;
|
||||
ctx.define(name, type, false);
|
||||
type = name;
|
||||
}
|
||||
|
||||
// TODO: support optional fields.
|
||||
// TODO: warning about computed properties.
|
||||
|
||||
invariant(isObjectTypeProperty(node) || !node.computed);
|
||||
|
@ -182,30 +218,22 @@ function makeField(ctx: Context, node: ObjectTypeProperty | ClassProperty): ?Fie
|
|||
|
||||
return {
|
||||
name: node.key.name,
|
||||
type,
|
||||
value: type,
|
||||
required: node.optional == null || !node.optional,
|
||||
};
|
||||
}
|
||||
|
||||
function makeMap(ctx: Context, nodes: ObjectTypeIndexer[]): ?MapType {
|
||||
if (nodes.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: what to do in this case?
|
||||
invariant(nodes.length === 1);
|
||||
|
||||
const node = nodes[0];
|
||||
|
||||
invariant(makeType(ctx, node.key) === 'string');
|
||||
|
||||
function makeMap(ctx: Context, node: ObjectTypeIndexer): ?MapType {
|
||||
const keys = makeType(ctx, node.key);
|
||||
const values = makeType(ctx, node.value);
|
||||
|
||||
if (values == null) {
|
||||
if (!(keys && values)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'map',
|
||||
kind: 'map',
|
||||
keys,
|
||||
values,
|
||||
};
|
||||
}
|
||||
|
@ -213,151 +241,68 @@ function makeMap(ctx: Context, nodes: ObjectTypeIndexer[]): ?MapType {
|
|||
function makeArrayType(ctx: Context, node: ArrayTypeAnnotation): ?ArrayType {
|
||||
const items = makeType(ctx, node.elementType);
|
||||
|
||||
if (items == null) {
|
||||
if (!items) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'array',
|
||||
kind: 'array',
|
||||
items,
|
||||
};
|
||||
}
|
||||
|
||||
function makeUnionType(ctx: Context, node: UnionTypeAnnotation): ?(UnionType | EnumType) {
|
||||
// TODO: flatten variants.
|
||||
// TODO: refactor it.
|
||||
|
||||
let [symbols, variants] = partition(node.types, isStringLiteralTypeAnnotation);
|
||||
|
||||
// $FlowFixMe
|
||||
symbols = map(symbols, get('value'));
|
||||
variants = compact(map(variants, node => makeType(ctx, node)));
|
||||
|
||||
if (symbols.length > 0) {
|
||||
const enumeration: EnumType = {
|
||||
type: 'enum',
|
||||
symbols,
|
||||
};
|
||||
|
||||
if (variants.length === 0) {
|
||||
return enumeration;
|
||||
}
|
||||
|
||||
variants.push(enumeration);
|
||||
}
|
||||
function makeUnionType(ctx: Context, node: UnionTypeAnnotation): ?UnionType {
|
||||
const variants = wu(node.types)
|
||||
.map(node => makeType(ctx, node))
|
||||
.filter()
|
||||
.toArray();
|
||||
|
||||
if (variants.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return variants;
|
||||
}
|
||||
|
||||
function makeIntersection(ctx: Context, node: IntersectionTypeAnnotation): ?Type {
|
||||
const types = [];
|
||||
|
||||
// TODO: refactor it.
|
||||
for (const typeNode of node.types) {
|
||||
const type = makeType(ctx, typeNode);
|
||||
|
||||
if (type == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: support arbitrary types, not only references.
|
||||
invariant(typeof type === 'string');
|
||||
|
||||
const queried = ctx.query(type);
|
||||
|
||||
invariant(isComplexType(queried));
|
||||
|
||||
types.push((queried: $FlowFixMe));
|
||||
}
|
||||
|
||||
if (types.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const [name, intersection] = mergeTypes(types);
|
||||
|
||||
// TODO: dirty support for intersections.
|
||||
(intersection: $FlowFixMe).name = name;
|
||||
|
||||
return intersection;
|
||||
}
|
||||
|
||||
function makeEnum(node: StringLiteralTypeAnnotation): EnumType {
|
||||
return {
|
||||
type: 'enum',
|
||||
symbols: [node.value],
|
||||
kind: 'union',
|
||||
variants,
|
||||
};
|
||||
}
|
||||
|
||||
function makeReference(ctx: Context, node: GenericTypeAnnotation): ReferenceType {
|
||||
const {name} = node.id;
|
||||
const params = node.typeParameters && map(node.typeParameters.params, n => makeType(ctx, n));
|
||||
function makeIntersection(ctx: Context, node: IntersectionTypeAnnotation): ?Type {
|
||||
// TODO: warning about nulls.
|
||||
const parts = wu(node.types)
|
||||
.map(node => makeType(ctx, node))
|
||||
.filter()
|
||||
.toArray();
|
||||
|
||||
const type = ctx.query(name, params);
|
||||
|
||||
if (typeof type === 'string') {
|
||||
return type;
|
||||
}
|
||||
|
||||
// TODO: generalized it.
|
||||
if ((type: $FlowFixMe).$unwrap) {
|
||||
invariant(typeof type.type === 'string');
|
||||
|
||||
return type.type;
|
||||
}
|
||||
|
||||
invariant(isComplexType(type));
|
||||
|
||||
if (type.namespace === ctx.namespace) {
|
||||
return (type: $FlowFixMe).name;
|
||||
}
|
||||
|
||||
return makeFullname((type: $FlowFixMe));
|
||||
}
|
||||
|
||||
function extractPragmas(comments: Comment[]): Type[] {
|
||||
return filterMap(comments, compose(get('value'), extractPragma));
|
||||
}
|
||||
|
||||
function extractPragma(text: string): ?Type {
|
||||
const marker = '$avro ';
|
||||
|
||||
const value = text.trimLeft();
|
||||
|
||||
if (!value.startsWith(marker)) {
|
||||
if (parts.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const pragma = value.slice(marker.length).trim();
|
||||
if (parts.length === 1) {
|
||||
return parts[0];
|
||||
}
|
||||
|
||||
return parsePragma(pragma);
|
||||
return {
|
||||
kind: 'intersection',
|
||||
parts,
|
||||
};
|
||||
}
|
||||
|
||||
function parsePragma(pragma: string): Type {
|
||||
let [type, arg] = pragma.split(/\s+/);
|
||||
function makeReference(ctx: Context, node: GenericTypeAnnotation): ?Type {
|
||||
const {name} = node.id;
|
||||
const params = node.typeParameters
|
||||
&& wu(node.typeParameters.params).map(n => makeType(ctx, n)).toArray();
|
||||
|
||||
if (isPrimitiveType(type)) {
|
||||
invariant(arg == null);
|
||||
const type = ctx.query(name, params);
|
||||
|
||||
if (!type.id) {
|
||||
return type;
|
||||
}
|
||||
|
||||
if (type === 'fixed') {
|
||||
arg = Number(arg);
|
||||
|
||||
invariant(Number.isInteger(arg));
|
||||
|
||||
return ({
|
||||
type: 'fixed',
|
||||
size: arg,
|
||||
}: FixedType);
|
||||
}
|
||||
|
||||
invariant(false);
|
||||
return {
|
||||
kind: 'reference',
|
||||
to: type.id,
|
||||
};
|
||||
}
|
||||
|
||||
export default {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
export default [
|
||||
{
|
||||
name: 'Buffer',
|
||||
type: 'bytes',
|
||||
$unwrap: true,
|
||||
id: ['Buffer'],
|
||||
kind: 'record',
|
||||
fields: [],
|
||||
},
|
||||
];
|
||||
|
|
|
@ -2,24 +2,29 @@ import * as pathlib from 'path';
|
|||
import * as resolve from 'resolve';
|
||||
|
||||
import type Scope from './scope';
|
||||
import type {Schema, Type} from './schema';
|
||||
import type {Type, TypeId} from './types';
|
||||
import type {Query} from './query';
|
||||
|
||||
export default class Module {
|
||||
+id: TypeId;
|
||||
+path: string;
|
||||
+namespace: string;
|
||||
_scopeCount: number;
|
||||
_exports: Map<?string, [Scope, string]>;
|
||||
|
||||
constructor(path: string, namespace: string) {
|
||||
constructor(id: TypeId, path: string) {
|
||||
this.id = id;
|
||||
this.path = path;
|
||||
this.namespace = namespace;
|
||||
this._scopeCount = 0;
|
||||
this._exports = new Map;
|
||||
}
|
||||
|
||||
generateScopeId(): number {
|
||||
return this._scopeCount++;
|
||||
generateScopeId(): TypeId {
|
||||
if (this._scopeCount === 0) {
|
||||
++this._scopeCount;
|
||||
return this.id;
|
||||
}
|
||||
|
||||
return this.id.concat(String(this._scopeCount++));
|
||||
}
|
||||
|
||||
addExport(name: ?string, scope: Scope, reference: string) {
|
||||
|
@ -31,7 +36,7 @@ export default class Module {
|
|||
|
||||
if (!result) {
|
||||
return {
|
||||
type: 'unknown',
|
||||
kind: 'unknown',
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
import {invariant} from './utils';
|
||||
|
||||
import type {Type} from './types';
|
||||
|
||||
export type Pragma =
|
||||
| TypePragma;
|
||||
|
||||
export type TypePragma = {
|
||||
kind: 'type',
|
||||
value: Type,
|
||||
};
|
||||
|
||||
const PRAGMA_RE = /^\s*@repr\s+\{\s*(.+?)\s*\}\s*$/gm;
|
||||
|
||||
export function extractPragmas(text: string): Pragma[] {
|
||||
const pragmas = [];
|
||||
let match;
|
||||
|
||||
while ((match = PRAGMA_RE.exec(text))) {
|
||||
const repr = match[1];
|
||||
|
||||
invariant(['i32', 'i64', 'u32', 'u64', 'f32', 'f64'].includes(repr));
|
||||
|
||||
const pragma = {
|
||||
kind: 'type',
|
||||
value: {
|
||||
kind: 'number',
|
||||
repr,
|
||||
},
|
||||
};
|
||||
|
||||
if (pragma) {
|
||||
pragmas.push(pragma);
|
||||
}
|
||||
}
|
||||
|
||||
return pragmas;
|
||||
}
|
18
src/query.js
18
src/query.js
|
@ -1,7 +1,7 @@
|
|||
import type {Node} from '@babel/types';
|
||||
|
||||
import type Scope from './scope';
|
||||
import type {Schema, Type} from './schema';
|
||||
import type {Type} from './types';
|
||||
|
||||
export type Query =
|
||||
| Unknown
|
||||
|
@ -11,18 +11,18 @@ export type Query =
|
|||
| External;
|
||||
|
||||
export type Unknown = {
|
||||
type: 'unknown',
|
||||
kind: 'unknown',
|
||||
};
|
||||
|
||||
export type Declaration = {
|
||||
type: 'declaration',
|
||||
kind: 'declaration',
|
||||
name: string,
|
||||
node: Node,
|
||||
scope: Scope,
|
||||
};
|
||||
|
||||
export type Template = {
|
||||
type: 'template',
|
||||
kind: 'template',
|
||||
name: string,
|
||||
params: TemplateParam[],
|
||||
instances: Instance[],
|
||||
|
@ -31,25 +31,25 @@ export type Template = {
|
|||
};
|
||||
|
||||
export type Definition = {
|
||||
type: 'definition',
|
||||
schema: Schema,
|
||||
kind: 'definition',
|
||||
type: Type,
|
||||
scope: Scope,
|
||||
};
|
||||
|
||||
export type External = {
|
||||
type: 'external',
|
||||
kind: 'external',
|
||||
info: ExternalInfo,
|
||||
scope: Scope,
|
||||
};
|
||||
|
||||
export type TemplateParam = {
|
||||
name: string,
|
||||
default: ?Type,
|
||||
value: ?Type,
|
||||
};
|
||||
|
||||
export type Instance = {
|
||||
params: (?Type)[],
|
||||
schema: Schema,
|
||||
type: Type,
|
||||
};
|
||||
|
||||
export type ExternalInfo = {
|
||||
|
|
147
src/schema.js
147
src/schema.js
|
@ -1,147 +0,0 @@
|
|||
import {invariant} from './utils';
|
||||
|
||||
// @see flow#3912.
|
||||
export type Schema =
|
||||
| RecordType & Top
|
||||
| EnumType & Top
|
||||
| ArrayType & Top
|
||||
| MapType & Top
|
||||
// TODO: support top-level unions.
|
||||
//| UnionType & Top
|
||||
| FixedType & Top
|
||||
| WrappedType & Top;
|
||||
|
||||
export type Top = {
|
||||
name: string,
|
||||
namespace?: string,
|
||||
$unwrap?: boolean,
|
||||
};
|
||||
|
||||
export type Type =
|
||||
| ComplexType
|
||||
| UnionType
|
||||
| PrimitiveType
|
||||
| ReferenceType;
|
||||
|
||||
export type WrappedType = {type: Type};
|
||||
|
||||
export type ComplexType =
|
||||
| RecordType
|
||||
| EnumType
|
||||
| ArrayType
|
||||
| MapType
|
||||
// TODO: unions should be complex types.
|
||||
//| UnionType & Top
|
||||
| FixedType
|
||||
| WrappedType;
|
||||
|
||||
export type PrimitiveType =
|
||||
| 'null'
|
||||
| 'boolean'
|
||||
| 'int'
|
||||
| 'long'
|
||||
| 'float'
|
||||
| 'double'
|
||||
| 'bytes'
|
||||
| 'string';
|
||||
|
||||
export type ReferenceType = string;
|
||||
|
||||
export type RecordType = {
|
||||
type: 'record',
|
||||
fields: FieldType[],
|
||||
};
|
||||
|
||||
export type FieldType = {
|
||||
name: string,
|
||||
type: Type,
|
||||
};
|
||||
|
||||
export type EnumType = {
|
||||
type: 'enum',
|
||||
symbols: string[],
|
||||
};
|
||||
|
||||
export type ArrayType = {
|
||||
type: 'array',
|
||||
items: Type,
|
||||
};
|
||||
|
||||
export type MapType = {
|
||||
type: 'map',
|
||||
values: Type,
|
||||
};
|
||||
|
||||
export type UnionType = Type[];
|
||||
|
||||
export type FixedType = {
|
||||
type: 'fixed',
|
||||
size: number,
|
||||
};
|
||||
|
||||
export function isPrimitiveType(type: Type): boolean %checks {
|
||||
// Switch operator is not allowed in %checks functions.
|
||||
return type === 'null'
|
||||
|| type === 'int'
|
||||
|| type === 'long'
|
||||
|| type === 'float'
|
||||
|| type === 'double'
|
||||
|| type === 'bytes'
|
||||
|| type === 'string'
|
||||
|| type === 'boolean';
|
||||
}
|
||||
|
||||
export function isComplexType(type: Type): boolean %checks {
|
||||
return typeof type !== 'string' && !(type instanceof Array);
|
||||
}
|
||||
|
||||
export function makeFullname(schema: Top): string {
|
||||
invariant(schema.namespace != null);
|
||||
|
||||
return `${schema.namespace}.${schema.name}`;
|
||||
}
|
||||
|
||||
export function mergeTypes<+T: ComplexType & {+name?: string}>(types: T[]): [string, ComplexType] {
|
||||
invariant(types.length > 1);
|
||||
|
||||
if (types.length === 1) {
|
||||
const type = types[0];
|
||||
// TODO: anonymous?
|
||||
invariant(type.name != null);
|
||||
|
||||
return [type.name, (type: $FlowFixMe)];
|
||||
}
|
||||
|
||||
const map = new Map;
|
||||
|
||||
// TODO: overriding?
|
||||
let name = '';
|
||||
|
||||
for (const type of types) {
|
||||
// TODO: enums?
|
||||
invariant(type.type === 'record');
|
||||
|
||||
for (const field of (type: $FlowFixMe).fields) {
|
||||
const stored = map.get(field.name);
|
||||
|
||||
if (stored) {
|
||||
// TODO: what about enums?
|
||||
// TODO: improve checking.
|
||||
invariant(stored.type === field.type);
|
||||
continue;
|
||||
}
|
||||
|
||||
map.set(field.name, field);
|
||||
}
|
||||
|
||||
// TODO: anonymous?
|
||||
name += '_' + (type.name != null ? type.name : 'unnamed');
|
||||
}
|
||||
|
||||
const type = {
|
||||
type: 'record',
|
||||
fields: Array.from(map.values()),
|
||||
};
|
||||
|
||||
return [name, (type: $FlowFixMe)];
|
||||
}
|
109
src/scope.js
109
src/scope.js
|
@ -1,46 +1,39 @@
|
|||
import wu from 'wu';
|
||||
import type {Node} from '@babel/types';
|
||||
|
||||
import {invariant} from './utils';
|
||||
import {invariant, last} from './utils';
|
||||
import type Module from './module';
|
||||
import type {Schema, Type} from './schema';
|
||||
import type {Type, TypeId} from './types';
|
||||
import type {Query, Template, TemplateParam, ExternalInfo} from './query';
|
||||
|
||||
export default class Scope {
|
||||
+id: TypeId;
|
||||
+parent: ?Scope;
|
||||
+module: ?Module;
|
||||
+scopeId: ?number;
|
||||
_entries: Map<string, Query>;
|
||||
|
||||
static global(schemas: Schema[]) {
|
||||
static global(types: Type[]) {
|
||||
const global = new Scope(null, null);
|
||||
|
||||
for (const schema of schemas) {
|
||||
global.addDefinition(schema, false);
|
||||
for (const type of types) {
|
||||
invariant(type.id);
|
||||
|
||||
const name = last(type.id);
|
||||
invariant(name != null);
|
||||
|
||||
global.addDefinition(name, type, false);
|
||||
}
|
||||
|
||||
return global;
|
||||
}
|
||||
|
||||
constructor(parent: ?Scope, module: ?Module) {
|
||||
this.id = module ? module.generateScopeId() : [];
|
||||
this.parent = parent;
|
||||
this.module = module;
|
||||
this.scopeId = module && module.generateScopeId();
|
||||
this._entries = new Map;
|
||||
}
|
||||
|
||||
get namespace(): string {
|
||||
invariant(this.module);
|
||||
|
||||
let namespace = this.module.namespace;
|
||||
|
||||
// Nested scopes.
|
||||
if (this.scopeId != null && this.scopeId > 0) {
|
||||
namespace += '._' + this.scopeId;
|
||||
}
|
||||
|
||||
return namespace;
|
||||
}
|
||||
|
||||
extend(module: ?Module = null): Scope {
|
||||
return new Scope(this, module || this.module);
|
||||
}
|
||||
|
@ -49,14 +42,14 @@ export default class Scope {
|
|||
invariant(!this._entries.has(name));
|
||||
|
||||
const entry = params.length > 0 ? {
|
||||
type: 'template',
|
||||
kind: 'template',
|
||||
name,
|
||||
params,
|
||||
instances: [],
|
||||
node,
|
||||
scope: this,
|
||||
} : {
|
||||
type: 'declaration',
|
||||
kind: 'declaration',
|
||||
name,
|
||||
node,
|
||||
scope: this,
|
||||
|
@ -65,28 +58,34 @@ export default class Scope {
|
|||
this._entries.set(name, entry);
|
||||
}
|
||||
|
||||
addInstance(name: string, schema: Schema, params: (?Type)[]) {
|
||||
addInstance(name: string, type: Type, params: (?Type)[]) {
|
||||
const template = this._entries.get(name);
|
||||
|
||||
invariant(template);
|
||||
invariant(template.type === 'template');
|
||||
invariant(template.kind === 'template');
|
||||
|
||||
template.instances.push({params, schema});
|
||||
const iname = generateGenericName(params);
|
||||
|
||||
type.id = this.id.concat(name, iname);
|
||||
|
||||
template.instances.push({params, type});
|
||||
}
|
||||
|
||||
addDefinition(schema: Schema, declared: boolean) {
|
||||
const decl = this._entries.get(schema.name);
|
||||
addDefinition(name: string, type: Type, declared: boolean) {
|
||||
const decl = this._entries.get(name);
|
||||
|
||||
if (declared) {
|
||||
invariant(decl);
|
||||
invariant(decl.type === 'declaration');
|
||||
invariant(decl.kind === 'declaration');
|
||||
} else {
|
||||
invariant(!decl);
|
||||
}
|
||||
|
||||
this._entries.set(schema.name, {
|
||||
type: 'definition',
|
||||
schema,
|
||||
type.id = this.id.concat(name);
|
||||
|
||||
this._entries.set(name, {
|
||||
kind: 'definition',
|
||||
type,
|
||||
scope: this,
|
||||
});
|
||||
}
|
||||
|
@ -95,7 +94,7 @@ export default class Scope {
|
|||
invariant(!this._entries.has(info.local));
|
||||
|
||||
this._entries.set(info.local, {
|
||||
type: 'external',
|
||||
kind: 'external',
|
||||
info,
|
||||
scope: this,
|
||||
});
|
||||
|
@ -116,14 +115,14 @@ export default class Scope {
|
|||
query(name: string, params: (?Type)[]): Query {
|
||||
const entry = this._entries.get(name);
|
||||
|
||||
if (entry && entry.type === 'template') {
|
||||
const augmented = entry.params.map((p, i) => params[i] === undefined ? p.default : params[i]);
|
||||
const schema = findInstance(entry, augmented);
|
||||
if (entry && entry.kind === 'template') {
|
||||
const augmented = entry.params.map((p, i) => params[i] === undefined ? p.value : params[i]);
|
||||
const type = findInstance(entry, augmented);
|
||||
|
||||
if (schema) {
|
||||
if (type) {
|
||||
return {
|
||||
type: 'definition',
|
||||
schema,
|
||||
kind: 'definition',
|
||||
type,
|
||||
scope: entry.scope,
|
||||
};
|
||||
}
|
||||
|
@ -138,20 +137,46 @@ export default class Scope {
|
|||
}
|
||||
|
||||
return {
|
||||
type: 'unknown',
|
||||
kind: 'unknown',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function findInstance(template: Template, queried: (?Type)[]): ?Schema {
|
||||
for (const {schema, params} of template.instances) {
|
||||
function findInstance(template: Template, queried: (?Type)[]): ?Type {
|
||||
for (const {type, params} of template.instances) {
|
||||
// TODO: compare complex structures.
|
||||
const same = params.every((p, i) => p === queried[i]);
|
||||
|
||||
if (same) {
|
||||
return schema;
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function generateGenericName(params: (?Type)[]): TypeId {
|
||||
return wu(params)
|
||||
.map(type => {
|
||||
invariant(type);
|
||||
return getTypeName(type);
|
||||
})
|
||||
.toArray();
|
||||
}
|
||||
|
||||
function getTypeName(type: Type): string {
|
||||
switch (type.kind) {
|
||||
case 'reference':
|
||||
const name = last(type.to);
|
||||
invariant(name != null);
|
||||
|
||||
return name;
|
||||
case 'number':
|
||||
return type.repr;
|
||||
case 'string':
|
||||
case 'boolean':
|
||||
return type.kind;
|
||||
default:
|
||||
invariant(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
export type Type =
|
||||
| RecordType
|
||||
| ArrayType
|
||||
| TupleType
|
||||
| MapType
|
||||
| UnionType
|
||||
| IntersectionType
|
||||
| MaybeType
|
||||
| NumberType
|
||||
| StringType
|
||||
| BooleanType
|
||||
| LiteralType
|
||||
| ReferenceType;
|
||||
|
||||
export type TypeId = string[];
|
||||
|
||||
export type BaseType = {
|
||||
id?: TypeId,
|
||||
};
|
||||
|
||||
export type RecordType = BaseType & {
|
||||
kind: 'record',
|
||||
fields: Field[],
|
||||
};
|
||||
|
||||
export type Field = {
|
||||
name: string,
|
||||
value: Type,
|
||||
required: boolean,
|
||||
};
|
||||
|
||||
export type ArrayType = BaseType & {
|
||||
kind: 'array',
|
||||
items: Type,
|
||||
};
|
||||
|
||||
export type TupleType = BaseType & {
|
||||
kind: 'tuple',
|
||||
items: Type[],
|
||||
};
|
||||
|
||||
export type MapType = BaseType & {
|
||||
kind: 'map',
|
||||
keys: Type,
|
||||
values: Type,
|
||||
};
|
||||
|
||||
export type UnionType = BaseType & {
|
||||
kind: 'union',
|
||||
variants: Type[],
|
||||
};
|
||||
|
||||
export type IntersectionType = BaseType & {
|
||||
kind: 'intersection',
|
||||
parts: Type[],
|
||||
}
|
||||
|
||||
export type MaybeType = BaseType & {
|
||||
kind: 'maybe',
|
||||
value: Type,
|
||||
};
|
||||
|
||||
export type NumberType = BaseType & {
|
||||
kind: 'number',
|
||||
repr: 'i32' | 'i64' | 'u32' | 'u64' | 'f32' | 'f64',
|
||||
};
|
||||
|
||||
export type StringType = BaseType & {
|
||||
kind: 'string',
|
||||
};
|
||||
|
||||
export type BooleanType = BaseType & {
|
||||
kind: 'boolean',
|
||||
};
|
||||
|
||||
export type LiteralType = BaseType & {
|
||||
kind: 'literal',
|
||||
value: string | number | boolean | null | void,
|
||||
};
|
||||
|
||||
export type ReferenceType = BaseType & {
|
||||
kind: 'reference',
|
||||
to: TypeId,
|
||||
};
|
61
src/utils.js
61
src/utils.js
|
@ -4,67 +4,6 @@ import * as assert from 'assert';
|
|||
// @see flow#112.
|
||||
export const invariant = assert.ok;
|
||||
|
||||
export function partition<T>(iter: Iterable<T>, predicate: T => boolean): [T[], T[]] {
|
||||
const left = [];
|
||||
const right = [];
|
||||
|
||||
for (const item of iter) {
|
||||
(predicate(item) ? left : right).push(item);
|
||||
}
|
||||
|
||||
return [left, right];
|
||||
}
|
||||
|
||||
export function map<T, R>(iter: Iterable<T>, mapper: T => R): R[] {
|
||||
const result = [];
|
||||
|
||||
for (const item of iter) {
|
||||
result.push(mapper(item));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function filter<T>(iter: Iterable<T>, predicate: T => boolean): T[] {
|
||||
const result = [];
|
||||
|
||||
for (const item of iter) {
|
||||
if (predicate(item)) {
|
||||
result.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function filterMap<T, R>(iter: Iterable<T>, mapper: T => ?R): R[] {
|
||||
const result = [];
|
||||
|
||||
for (const item of iter) {
|
||||
const it = mapper(item);
|
||||
|
||||
if (it != null) {
|
||||
result.push(it);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function compact<T>(iter: Iterable<?T>): T[] {
|
||||
// $FlowFixMe
|
||||
return filter(iter, Boolean);
|
||||
}
|
||||
|
||||
// $FlowFixMe
|
||||
export function get<T: Object, K: $Keys<T>>(key: K): T => $ElementType<T, K> {
|
||||
return obj => obj[key];
|
||||
}
|
||||
|
||||
export function compose<X, Y, Z>(a: X => Y, b: Y => Z): X => Z {
|
||||
return x => b(a(x));
|
||||
}
|
||||
|
||||
export function last<T>(list: T[]): T | void {
|
||||
return list.length > 0 ? list[list.length - 1] : undefined;
|
||||
}
|
||||
|
|
|
@ -13,8 +13,8 @@ function run(title) {
|
|||
expected = JSON.parse(fs.readFileSync(title + '.json', 'utf8'));
|
||||
});
|
||||
|
||||
it('should provide expected schemas', () => {
|
||||
assert.deepEqual(actual.schemas, expected.schemas);
|
||||
it('should provide expected types', () => {
|
||||
assert.deepEqual(actual.types, expected.types);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
type Type = {
|
||||
a: number[],
|
||||
a: string[],
|
||||
};
|
||||
|
||||
interface Interface {
|
||||
a: number[];
|
||||
a: string[];
|
||||
}
|
||||
|
||||
class Class {
|
||||
a: number[];
|
||||
a: string[];
|
||||
}
|
||||
|
||||
export {Type, Interface, Class};
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
{
|
||||
"schemas": [
|
||||
"types": [
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Type",
|
||||
"namespace": "arrays",
|
||||
"id": ["arrays", "Type"],
|
||||
"kind": "record",
|
||||
"fields": [{
|
||||
"name": "a",
|
||||
"type": {"type": "array", "items": "double"}
|
||||
"value": {"kind": "array", "items": {"kind": "string"}},
|
||||
"required": true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Interface",
|
||||
"namespace": "arrays",
|
||||
"id": ["arrays", "Interface"],
|
||||
"kind": "record",
|
||||
"fields": [{
|
||||
"name": "a",
|
||||
"type": {"type": "array", "items": "double"}
|
||||
"value": {"kind": "array", "items": {"kind": "string"}},
|
||||
"required": true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Class",
|
||||
"namespace": "arrays",
|
||||
"id": ["arrays", "Class"],
|
||||
"kind": "record",
|
||||
"fields": [{
|
||||
"name": "a",
|
||||
"type": {"type": "array", "items": "double"}
|
||||
"value": {"kind": "array", "items": {"kind": "string"}},
|
||||
"required": true
|
||||
}]
|
||||
}
|
||||
]
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
{
|
||||
"schemas": [
|
||||
"types": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "Z",
|
||||
"namespace": "disorder"
|
||||
"id": ["disorder", "Z"],
|
||||
"kind": "string"
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Y",
|
||||
"namespace": "disorder",
|
||||
"fields": [{"name": "z", "type": "Z"}]
|
||||
"id": ["disorder", "Y"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "z", "value": {"kind": "reference", "to": ["disorder", "Z"]}, "required": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "X",
|
||||
"namespace": "disorder",
|
||||
"fields": [{"name": "y", "type": "Y"}]
|
||||
"id": ["disorder", "X"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "y", "value": {"kind": "reference", "to": ["disorder", "Y"]}, "required": true}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"schemas": []
|
||||
"types": []
|
||||
}
|
||||
|
|
|
@ -1,30 +1,48 @@
|
|||
{
|
||||
"schemas": [
|
||||
"types": [
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Type",
|
||||
"namespace": "enums",
|
||||
"id": ["enums", "Type"],
|
||||
"kind": "record",
|
||||
"fields": [{
|
||||
"name": "a",
|
||||
"type": {"type": "enum", "symbols": ["one", "two"]}
|
||||
"value": {
|
||||
"kind": "union",
|
||||
"variants": [
|
||||
{"kind": "literal", "value": "one"},
|
||||
{"kind": "literal", "value": "two"}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Interface",
|
||||
"namespace": "enums",
|
||||
"id": ["enums", "Interface"],
|
||||
"kind": "record",
|
||||
"fields": [{
|
||||
"name": "a",
|
||||
"type": {"type": "enum", "symbols": ["one", "two"]}
|
||||
"value": {
|
||||
"kind": "union",
|
||||
"variants": [
|
||||
{"kind": "literal", "value": "one"},
|
||||
{"kind": "literal", "value": "two"}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Class",
|
||||
"namespace": "enums",
|
||||
"id": ["enums", "Class"],
|
||||
"kind": "record",
|
||||
"fields": [{
|
||||
"name": "a",
|
||||
"type": {"type": "enum", "symbols": ["one", "two"]}
|
||||
"value": {
|
||||
"kind": "union",
|
||||
"variants": [
|
||||
{"kind": "literal", "value": "one"},
|
||||
{"kind": "literal", "value": "two"}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}]
|
||||
}
|
||||
]
|
||||
|
|
|
@ -1,73 +1,63 @@
|
|||
{
|
||||
"schemas": [
|
||||
"types": [
|
||||
{
|
||||
"type": "record",
|
||||
"name": "A",
|
||||
"namespace": "externals.first",
|
||||
"fields": [{"name": "a", "type": "boolean"}]
|
||||
"id": ["externals", "first", "A"],
|
||||
"kind": "record",
|
||||
"fields": [{"name": "a", "value": {"kind": "boolean"}, "required": true}]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "B",
|
||||
"namespace": "externals.first",
|
||||
"fields": [{"name": "b", "type": "string"}]
|
||||
"id": ["externals", "first", "B"],
|
||||
"kind": "record",
|
||||
"fields": [{"name": "b", "value": {"kind": "string"}, "required": true}]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "CC",
|
||||
"namespace": "externals.first",
|
||||
"fields": [{"name": "c", "type": "double"}]
|
||||
"id": ["externals", "first", "CC"],
|
||||
"kind": "record",
|
||||
"fields": [{"name": "c", "value": {"kind": "number", "repr": "f64"}, "required": true}]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "D",
|
||||
"namespace": "externals.first",
|
||||
"fields": [{"name": "d", "type": "double"}]
|
||||
"id": ["externals", "first", "D"],
|
||||
"kind": "record",
|
||||
"fields": [{"name": "d", "value": {"kind": "number", "repr": "f64"}, "required": true}]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "X",
|
||||
"namespace": "externals",
|
||||
"id": ["externals", "X"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "a", "type": "externals.first.A"},
|
||||
{"name": "b", "type": "externals.first.B"},
|
||||
{"name": "c", "type": "externals.first.CC"},
|
||||
{"name": "d", "type": "externals.first.D"}
|
||||
{"name": "a", "value": {"kind": "reference", "to": ["externals", "first", "A"]}, "required": true},
|
||||
{"name": "b", "value": {"kind": "reference", "to": ["externals", "first", "B"]}, "required": true},
|
||||
{"name": "c", "value": {"kind": "reference", "to": ["externals", "first", "CC"]}, "required": true},
|
||||
{"name": "d", "value": {"kind": "reference", "to": ["externals", "first", "D"]}, "required": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "N",
|
||||
"namespace": "externals.second",
|
||||
"fields": [{"name": "n", "type": "boolean"}]
|
||||
"id": ["externals", "second", "N"],
|
||||
"kind": "record",
|
||||
"fields": [{"name": "n", "value": {"kind": "boolean"}, "required": true}]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "M",
|
||||
"namespace": "externals.second",
|
||||
"fields": [{"name": "m", "type": "string"}]
|
||||
"id": ["externals", "second", "M"],
|
||||
"kind": "record",
|
||||
"fields": [{"name": "m", "value": {"kind": "string"}, "required": true}]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "KK",
|
||||
"namespace": "externals.second",
|
||||
"fields": [{"name": "k", "type": "double"}]
|
||||
"id": ["externals", "second", "KK"],
|
||||
"kind": "record",
|
||||
"fields": [{"name": "k", "value": {"kind": "number", "repr": "f64"}, "required": true}]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "P",
|
||||
"namespace": "externals.second",
|
||||
"fields": [{"name": "p", "type": "double"}]
|
||||
"id": ["externals", "second", "P"],
|
||||
"kind": "record",
|
||||
"fields": [{"name": "p", "value": {"kind": "number", "repr": "f64"}, "required": true}]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Y",
|
||||
"namespace": "externals",
|
||||
"id": ["externals", "Y"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "n", "type": "externals.second.N"},
|
||||
{"name": "m", "type": "externals.second.M"},
|
||||
{"name": "k", "type": "externals.second.KK"},
|
||||
{"name": "p", "type": "externals.second.P"}
|
||||
{"name": "n", "value": {"kind": "reference", "to": ["externals", "second", "N"]}, "required": true},
|
||||
{"name": "m", "value": {"kind": "reference", "to": ["externals", "second", "M"]}, "required": true},
|
||||
{"name": "k", "value": {"kind": "reference", "to": ["externals", "second", "KK"]}, "required": true},
|
||||
{"name": "p", "value": {"kind": "reference", "to": ["externals", "second", "P"]}, "required": true}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
@ -4,7 +4,7 @@ type A<T, K> = {
|
|||
};
|
||||
|
||||
type X = {
|
||||
a: A<string, number>,
|
||||
a: A<string, boolean>,
|
||||
};
|
||||
|
||||
export {X};
|
||||
|
|
|
@ -1,19 +1,21 @@
|
|||
{
|
||||
"schemas": [
|
||||
"types": [
|
||||
{
|
||||
"type": "record",
|
||||
"name": "A__string_double",
|
||||
"namespace": "generics",
|
||||
"id": ["generics", "A", "string", "boolean"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "t", "type": "string"},
|
||||
{"name": "k", "type": "double"}
|
||||
{"name": "t", "value": {"kind": "string"}, "required": true},
|
||||
{"name": "k", "value": {"kind": "boolean"}, "required": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "X",
|
||||
"namespace": "generics",
|
||||
"fields": [{"name": "a", "type": "A__string_double"}]
|
||||
"id": ["generics", "X"],
|
||||
"kind": "record",
|
||||
"fields": [{
|
||||
"name": "a",
|
||||
"value": {"kind": "reference", "to": ["generics", "A", "string", "boolean"]},
|
||||
"required": true
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,53 +1,57 @@
|
|||
{
|
||||
"schemas": [
|
||||
"types": [
|
||||
{
|
||||
"type": "record",
|
||||
"name": "A",
|
||||
"namespace": "inheritance",
|
||||
"fields": [{"name": "a", "type": "double"}]
|
||||
"id": ["inheritance", "A"],
|
||||
"kind": "record",
|
||||
"fields": [{"name": "a", "value": {"kind": "number", "repr": "f64"}, "required": true}]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "B",
|
||||
"namespace": "inheritance",
|
||||
"fields": [
|
||||
{"name": "a", "type": "double"},
|
||||
{"name": "b", "type": "string"}
|
||||
"id": ["inheritance", "B"],
|
||||
"kind": "intersection",
|
||||
"parts": [
|
||||
{"kind": "reference", "to": ["inheritance", "A"]},
|
||||
{
|
||||
"kind": "record",
|
||||
"fields": [{"name": "b", "value": {"kind": "string"}, "required": true}]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "C",
|
||||
"namespace": "inheritance",
|
||||
"fields": [
|
||||
{"name": "a", "type": "double"},
|
||||
{"name": "b", "type": "string"},
|
||||
{"name": "c", "type": "boolean"}
|
||||
"id": ["inheritance", "C"],
|
||||
"kind": "intersection",
|
||||
"parts": [
|
||||
{"kind": "reference", "to": ["inheritance", "B"]},
|
||||
{
|
||||
"kind": "record",
|
||||
"fields": [{"name": "c", "value": {"kind": "boolean"}, "required": true}]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "X",
|
||||
"namespace": "inheritance",
|
||||
"fields": [{"name": "x", "type": "double"}]
|
||||
"id": ["inheritance", "X"],
|
||||
"kind": "record",
|
||||
"fields": [{"name": "x", "value": {"kind": "number", "repr": "f64"}, "required": true}]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Y",
|
||||
"namespace": "inheritance",
|
||||
"fields": [
|
||||
{"name": "x", "type": "double"},
|
||||
{"name": "y", "type": "string"}
|
||||
"id": ["inheritance", "Y"],
|
||||
"kind": "intersection",
|
||||
"parts": [
|
||||
{"kind": "reference", "to": ["inheritance", "X"]},
|
||||
{
|
||||
"kind": "record",
|
||||
"fields": [{"name": "y", "value": {"kind": "string"}, "required": true}]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Z",
|
||||
"namespace": "inheritance",
|
||||
"fields": [
|
||||
{"name": "x", "type": "double"},
|
||||
{"name": "y", "type": "string"},
|
||||
{"name": "z", "type": "boolean"}
|
||||
"id": ["inheritance", "Z"],
|
||||
"kind": "intersection",
|
||||
"parts": [
|
||||
{"kind": "reference", "to": ["inheritance", "Y"]},
|
||||
{
|
||||
"kind": "record",
|
||||
"fields": [{"name": "z", "value": {"kind": "boolean"}, "required": true}]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
@ -1,66 +1,64 @@
|
|||
{
|
||||
"schemas": [
|
||||
"types": [
|
||||
{
|
||||
"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": "X",
|
||||
"namespace": "intersections",
|
||||
"id": ["intersections", "A"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "a", "type": "double"},
|
||||
{"name": "b", "type": "string"}
|
||||
{"name": "a", "value": {"kind": "number", "repr": "f64"}, "required": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "C",
|
||||
"namespace": "intersections",
|
||||
"fields": [{"name": "c", "type": "boolean"}]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "_A_B_C",
|
||||
"namespace": "intersections",
|
||||
"id": ["intersections", "B"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "a", "type": "double"},
|
||||
{"name": "b", "type": "string"},
|
||||
{"name": "c", "type": "boolean"}
|
||||
{"name": "b", "value": {"kind": "string"}, "required": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Y",
|
||||
"namespace": "intersections",
|
||||
"fields": [
|
||||
{"name": "y", "type": "_A_B_C"}
|
||||
"id": ["intersections", "X"],
|
||||
"kind": "intersection",
|
||||
"parts": [
|
||||
{"kind": "reference", "to": ["intersections", "A"]},
|
||||
{"kind": "reference", "to": ["intersections", "B"]}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "_A_C",
|
||||
"namespace": "intersections",
|
||||
"id": ["intersections", "C"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "a", "type": "double"},
|
||||
{"name": "c", "type": "boolean"}
|
||||
{"name": "c", "value": {"kind": "boolean"}, "required": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Z",
|
||||
"namespace": "intersections",
|
||||
"fields": [
|
||||
{"name": "z", "type": "_A_C"}
|
||||
]
|
||||
"id": ["intersections", "Y"],
|
||||
"kind": "record",
|
||||
"fields": [{
|
||||
"name": "y",
|
||||
"value": {
|
||||
"kind": "intersection",
|
||||
"parts": [
|
||||
{"kind": "reference", "to": ["intersections", "A"]},
|
||||
{"kind": "reference", "to": ["intersections", "B"]},
|
||||
{"kind": "reference", "to": ["intersections", "C"]}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"id": ["intersections", "Z"],
|
||||
"kind": "record",
|
||||
"fields": [{
|
||||
"name": "z",
|
||||
"value": {
|
||||
"kind": "intersection",
|
||||
"parts": [
|
||||
{"kind": "reference", "to": ["intersections", "A"]},
|
||||
{"kind": "reference", "to": ["intersections", "C"]}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
type Type = {
|
||||
[string]: number,
|
||||
[string]: boolean,
|
||||
};
|
||||
|
||||
interface Interface {
|
||||
[string]: number;
|
||||
[string]: boolean;
|
||||
}
|
||||
|
||||
export {Type, Interface};
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
{
|
||||
"schemas": [
|
||||
"types": [
|
||||
{
|
||||
"type": "map",
|
||||
"name": "Type",
|
||||
"namespace": "maps",
|
||||
"values": "double"
|
||||
"id": ["maps", "Type"],
|
||||
"kind": "map",
|
||||
"keys": {"kind": "string"},
|
||||
"values": {"kind": "boolean"}
|
||||
},
|
||||
{
|
||||
"type": "map",
|
||||
"name": "Interface",
|
||||
"namespace": "maps",
|
||||
"values": "double"
|
||||
"id": ["maps", "Interface"],
|
||||
"kind": "map",
|
||||
"keys": {"kind": "string"},
|
||||
"values": {"kind": "boolean"}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,40 +1,34 @@
|
|||
type Type = {
|
||||
// $avro int
|
||||
// @repr {i32}
|
||||
a: number,
|
||||
/* $avro long */
|
||||
/* @repr {i64} */
|
||||
b: number,
|
||||
// $avro float
|
||||
// @repr {f32}
|
||||
c: number,
|
||||
// $avro double
|
||||
// @repr {f64}
|
||||
d: number,
|
||||
/* $avro fixed 10 */
|
||||
e: Buffer,
|
||||
};
|
||||
|
||||
interface Interface {
|
||||
// $avro int
|
||||
// @repr {i32}
|
||||
a: number;
|
||||
/* $avro long */
|
||||
/* @repr {i64} */
|
||||
b: number;
|
||||
// $avro float
|
||||
// @repr {f32}
|
||||
c: number;
|
||||
// $avro double
|
||||
// @repr {f64}
|
||||
d: number;
|
||||
/* $avro fixed 10 */
|
||||
e: Buffer;
|
||||
}
|
||||
|
||||
class Class {
|
||||
// $avro int
|
||||
// @repr {i32}
|
||||
a: number;
|
||||
/* $avro long */
|
||||
/* @repr {i64} */
|
||||
b: number;
|
||||
// $avro float
|
||||
// @repr {f32}
|
||||
c: number;
|
||||
// $avro double
|
||||
// @repr {f64}
|
||||
d: number;
|
||||
/* $avro fixed 10 */
|
||||
e: Buffer;
|
||||
}
|
||||
|
||||
export {Type, Interface, Class};
|
||||
|
|
|
@ -1,39 +1,33 @@
|
|||
{
|
||||
"schemas": [
|
||||
"types": [
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Type",
|
||||
"namespace": "pragmas",
|
||||
"id": ["pragmas", "Type"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "a", "type": "int"},
|
||||
{"name": "b", "type": "long"},
|
||||
{"name": "c", "type": "float"},
|
||||
{"name": "d", "type": "double"},
|
||||
{"name": "e", "type": {"type": "fixed", "size": 10}}
|
||||
{"name": "a", "value": {"kind": "number", "repr": "i32"}, "required": true},
|
||||
{"name": "b", "value": {"kind": "number", "repr": "i64"}, "required": true},
|
||||
{"name": "c", "value": {"kind": "number", "repr": "f32"}, "required": true},
|
||||
{"name": "d", "value": {"kind": "number", "repr": "f64"}, "required": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Interface",
|
||||
"namespace": "pragmas",
|
||||
"id": ["pragmas", "Interface"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "a", "type": "int"},
|
||||
{"name": "b", "type": "long"},
|
||||
{"name": "c", "type": "float"},
|
||||
{"name": "d", "type": "double"},
|
||||
{"name": "e", "type": {"type": "fixed", "size": 10}}
|
||||
{"name": "a", "value": {"kind": "number", "repr": "i32"}, "required": true},
|
||||
{"name": "b", "value": {"kind": "number", "repr": "i64"}, "required": true},
|
||||
{"name": "c", "value": {"kind": "number", "repr": "f32"}, "required": true},
|
||||
{"name": "d", "value": {"kind": "number", "repr": "f64"}, "required": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Class",
|
||||
"namespace": "pragmas",
|
||||
"id": ["pragmas", "Class"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "a", "type": "int"},
|
||||
{"name": "b", "type": "long"},
|
||||
{"name": "c", "type": "float"},
|
||||
{"name": "d", "type": "double"},
|
||||
{"name": "e", "type": {"type": "fixed", "size": 10}}
|
||||
{"name": "a", "value": {"kind": "number", "repr": "i32"}, "required": true},
|
||||
{"name": "b", "value": {"kind": "number", "repr": "i64"}, "required": true},
|
||||
{"name": "c", "value": {"kind": "number", "repr": "f32"}, "required": true},
|
||||
{"name": "d", "value": {"kind": "number", "repr": "f64"}, "required": true}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
@ -3,7 +3,6 @@ type Type = {
|
|||
b: number,
|
||||
c: boolean,
|
||||
d: null,
|
||||
e: Buffer,
|
||||
};
|
||||
|
||||
interface Interface {
|
||||
|
@ -11,7 +10,6 @@ interface Interface {
|
|||
b: number;
|
||||
c: boolean;
|
||||
d: null;
|
||||
e: Buffer;
|
||||
};
|
||||
|
||||
class Class {
|
||||
|
@ -19,7 +17,6 @@ class Class {
|
|||
b: number;
|
||||
c: boolean;
|
||||
d: null;
|
||||
e: Buffer;
|
||||
}
|
||||
|
||||
export {Type, Interface, Class};
|
||||
|
|
|
@ -1,39 +1,33 @@
|
|||
{
|
||||
"schemas": [
|
||||
"types": [
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Type",
|
||||
"namespace": "primitives",
|
||||
"id": ["primitives", "Type"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "a", "type": "string"},
|
||||
{"name": "b", "type": "double"},
|
||||
{"name": "c", "type": "boolean"},
|
||||
{"name": "d", "type": "null"},
|
||||
{"name": "e", "type": "bytes"}
|
||||
{"name": "a", "value": {"kind": "string"}, "required": true},
|
||||
{"name": "b", "value": {"kind": "number", "repr": "f64"}, "required": true},
|
||||
{"name": "c", "value": {"kind": "boolean"}, "required": true},
|
||||
{"name": "d", "value": {"kind": "literal", "value": null}, "required": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Interface",
|
||||
"namespace": "primitives",
|
||||
"id": ["primitives", "Interface"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "a", "type": "string"},
|
||||
{"name": "b", "type": "double"},
|
||||
{"name": "c", "type": "boolean"},
|
||||
{"name": "d", "type": "null"},
|
||||
{"name": "e", "type": "bytes"}
|
||||
{"name": "a", "value": {"kind": "string"}, "required": true},
|
||||
{"name": "b", "value": {"kind": "number", "repr": "f64"}, "required": true},
|
||||
{"name": "c", "value": {"kind": "boolean"}, "required": true},
|
||||
{"name": "d", "value": {"kind": "literal", "value": null}, "required": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Class",
|
||||
"namespace": "primitives",
|
||||
"id": ["primitives", "Class"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "a", "type": "string"},
|
||||
{"name": "b", "type": "double"},
|
||||
{"name": "c", "type": "boolean"},
|
||||
{"name": "d", "type": "null"},
|
||||
{"name": "e", "type": "bytes"}
|
||||
{"name": "a", "value": {"kind": "string"}, "required": true},
|
||||
{"name": "b", "value": {"kind": "number", "repr": "f64"}, "required": true},
|
||||
{"name": "c", "value": {"kind": "boolean"}, "required": true},
|
||||
{"name": "d", "value": {"kind": "literal", "value": null}, "required": true}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
@ -1,35 +1,55 @@
|
|||
{
|
||||
"schemas": [
|
||||
"types": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "A",
|
||||
"namespace": "references"
|
||||
"id": ["references", "A"],
|
||||
"kind": "string"
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Type",
|
||||
"namespace": "references",
|
||||
"id": ["references", "Type"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "a", "type": "A"},
|
||||
{"name": "b", "type": {"type": "array", "items": "A"}}
|
||||
{
|
||||
"name": "a",
|
||||
"value": {"kind": "reference", "to": ["references", "A"]},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "b",
|
||||
"value": {"kind": "array", "items": {"kind": "reference", "to": ["references", "A"]}},
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Interface",
|
||||
"namespace": "references",
|
||||
"id": ["references", "Interface"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "a", "type": "A"},
|
||||
{"name": "b", "type": {"type": "array", "items": "A"}}
|
||||
{
|
||||
"name": "a",
|
||||
"value": {"kind": "reference", "to": ["references", "A"]},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "b",
|
||||
"value": {"kind": "array", "items": {"kind": "reference", "to": ["references", "A"]}},
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Class",
|
||||
"namespace": "references",
|
||||
"id": ["references", "Class"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "a", "type": "A"},
|
||||
{"name": "b", "type": {"type": "array", "items": "A"}}
|
||||
{
|
||||
"name": "a",
|
||||
"value": {"kind": "reference", "to": ["references", "A"]},
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "b",
|
||||
"value": {"kind": "array", "items": {"kind": "reference", "to": ["references", "A"]}},
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
@ -1,73 +1,68 @@
|
|||
{
|
||||
"schemas": [
|
||||
"types": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"name": "X",
|
||||
"namespace": "scopes._2"
|
||||
"id": ["scopes", "2", "X"],
|
||||
"kind": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "Z",
|
||||
"namespace": "scopes._1"
|
||||
"id": ["scopes", "1", "Z"],
|
||||
"kind": "string"
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Y",
|
||||
"namespace": "scopes._2",
|
||||
"id": ["scopes", "2", "Y"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "x", "type": "X"},
|
||||
{"name": "z", "type": "scopes._1.Z"}
|
||||
{"name": "x", "value": {"kind": "reference", "to": ["scopes", "2", "X"]}, "required": true},
|
||||
{"name": "z", "value": {"kind": "reference", "to": ["scopes", "1", "Z"]}, "required": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "double",
|
||||
"name": "X",
|
||||
"namespace": "scopes._3"
|
||||
"id": ["scopes", "3", "X"],
|
||||
"kind": "number",
|
||||
"repr": "f64"
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Y",
|
||||
"namespace": "scopes._3",
|
||||
"id": ["scopes", "3", "Y"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "x", "type": "X"},
|
||||
{"name": "z", "type": "scopes._1.Z"}
|
||||
{"name": "x", "value": {"kind": "reference", "to": ["scopes", "3", "X"]}, "required": true},
|
||||
{"name": "z", "value": {"kind": "reference", "to": ["scopes", "1", "Z"]}, "required": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "X",
|
||||
"namespace": "scopes._4"
|
||||
"id": ["scopes", "4", "X"],
|
||||
"kind": "string"
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Y",
|
||||
"namespace": "scopes._4",
|
||||
"id": ["scopes", "4", "Y"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "x", "type": "X"},
|
||||
{"name": "z", "type": "scopes._1.Z"}
|
||||
{"name": "x", "value": {"kind": "reference", "to": ["scopes", "4", "X"]}, "required": true},
|
||||
{"name": "z", "value": {"kind": "reference", "to": ["scopes", "1", "Z"]}, "required": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "double",
|
||||
"name": "X",
|
||||
"namespace": "scopes._1"
|
||||
"id": ["scopes", "1", "X"],
|
||||
"kind": "number",
|
||||
"repr": "f64"
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Y",
|
||||
"namespace": "scopes._1",
|
||||
"fields": [{"name": "x", "type": "X"}]
|
||||
"id": ["scopes", "1", "Y"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "x", "value": {"kind": "reference", "to": ["scopes", "1", "X"]}, "required": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "X",
|
||||
"namespace": "scopes"
|
||||
"id": ["scopes", "X"],
|
||||
"kind": "string"
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Y",
|
||||
"namespace": "scopes",
|
||||
"fields": [{"name": "x", "type": "X"}]
|
||||
"id": ["scopes", "Y"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "x", "value": {"kind": "reference", "to": ["scopes", "X"]}, "required": true}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,25 +1,30 @@
|
|||
{
|
||||
"schemas": [
|
||||
"types": [
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Buffer",
|
||||
"namespace": "shadowing._1",
|
||||
"id": ["shadowing", "1", "Buffer"],
|
||||
"kind": "record",
|
||||
"fields": []
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Y",
|
||||
"namespace": "shadowing._1",
|
||||
"id": ["shadowing", "1", "Y"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "y", "type": "Buffer"}
|
||||
{
|
||||
"name": "y",
|
||||
"value": {"kind": "reference", "to": ["shadowing", "1", "Buffer"]},
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "X",
|
||||
"namespace": "shadowing",
|
||||
"id": ["shadowing", "X"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "x", "type": "bytes"}
|
||||
{
|
||||
"name": "x",
|
||||
"value": {"kind": "reference", "to": ["Buffer"]},
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
@ -3,7 +3,7 @@ type Type = {
|
|||
|
||||
foo(): void,
|
||||
|
||||
b: number,
|
||||
b: boolean,
|
||||
|
||||
bar: () => void,
|
||||
};
|
||||
|
@ -13,7 +13,7 @@ interface Interface {
|
|||
|
||||
foo(): void;
|
||||
|
||||
b: number;
|
||||
b: boolean;
|
||||
|
||||
bar: () => void;
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ class Class {
|
|||
get bar() {}
|
||||
set bar(a) {}
|
||||
|
||||
b: number;
|
||||
b: boolean;
|
||||
|
||||
baz: () => void;
|
||||
}
|
||||
|
|
|
@ -1,30 +1,27 @@
|
|||
{
|
||||
"schemas": [
|
||||
"types": [
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Type",
|
||||
"namespace": "skipFunctions",
|
||||
"id": ["skipFunctions", "Type"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "a", "type": "string"},
|
||||
{"name": "b", "type": "double"}
|
||||
{"name": "a", "value": {"kind": "string"}, "required": true},
|
||||
{"name": "b", "value": {"kind": "boolean"}, "required": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Interface",
|
||||
"namespace": "skipFunctions",
|
||||
"id": ["skipFunctions", "Interface"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "a", "type": "string"},
|
||||
{"name": "b", "type": "double"}
|
||||
{"name": "a", "value": {"kind": "string"}, "required": true},
|
||||
{"name": "b", "value": {"kind": "boolean"}, "required": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Class",
|
||||
"namespace": "skipFunctions",
|
||||
"id": ["skipFunctions", "Class"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "a", "type": "string"},
|
||||
{"name": "b", "type": "double"}
|
||||
{"name": "a", "value": {"kind": "string"}, "required": true},
|
||||
{"name": "b", "value": {"kind": "boolean"}, "required": true}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
{
|
||||
"schemas": [
|
||||
"types": [
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Test",
|
||||
"namespace": "typeInMethod",
|
||||
"id": ["typeInMethod", "Test"],
|
||||
"kind": "record",
|
||||
"fields": []
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "X",
|
||||
"namespace": "typeInMethod._1",
|
||||
"fields": [{"name": "t", "type": "typeInMethod.Test"}]
|
||||
"id": ["typeInMethod", "1", "X"],
|
||||
"kind": "record",
|
||||
"fields": [{
|
||||
"name": "t",
|
||||
"value": {"kind": "reference", "to": ["typeInMethod", "Test"]},
|
||||
"required": true
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
type Type = {
|
||||
a: string | number,
|
||||
b: ?string,
|
||||
a: string | boolean,
|
||||
};
|
||||
|
||||
interface Interface {
|
||||
a: string | number;
|
||||
b: ?string;
|
||||
a: string | boolean | number;
|
||||
}
|
||||
|
||||
class Class {
|
||||
a: string | number;
|
||||
b: ?string;
|
||||
a: string | boolean;
|
||||
}
|
||||
|
||||
export {Type, Interface, Class};
|
||||
|
|
|
@ -1,47 +1,44 @@
|
|||
{
|
||||
"schemas": [
|
||||
"types": [
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Type",
|
||||
"namespace": "unions",
|
||||
"id": ["unions", "Type"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{
|
||||
"name": "a",
|
||||
"type": ["string", "double"]
|
||||
},
|
||||
{
|
||||
"name": "b",
|
||||
"type": ["null", "string"]
|
||||
"value": {
|
||||
"kind": "union",
|
||||
"variants": [{"kind": "string"}, {"kind": "boolean"}]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Interface",
|
||||
"namespace": "unions",
|
||||
"id": ["unions", "Interface"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{
|
||||
"name": "a",
|
||||
"type": ["string", "double"]
|
||||
},
|
||||
{
|
||||
"name": "b",
|
||||
"type": ["null", "string"]
|
||||
"value": {
|
||||
"kind": "union",
|
||||
"variants": [{"kind": "string"}, {"kind": "boolean"}, {"kind": "number", "repr": "f64"}]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Class",
|
||||
"namespace": "unions",
|
||||
"id": ["unions", "Class"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{
|
||||
"name": "a",
|
||||
"type": ["string", "double"]
|
||||
},
|
||||
{
|
||||
"name": "b",
|
||||
"type": ["null", "string"]
|
||||
"value": {
|
||||
"kind": "union",
|
||||
"variants": [{"kind": "string"}, {"kind": "boolean"}]
|
||||
},
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
type Type = {
|
||||
a: 'one' | 'two' | number,
|
||||
a: 'one' | 'two' | string,
|
||||
};
|
||||
|
||||
interface Interface {
|
||||
a: 'one' | 'two' | number;
|
||||
a: 'one' | 'two' | string;
|
||||
}
|
||||
|
||||
class Class {
|
||||
a: 'one' | 'two' | number;
|
||||
a: 'one' | 'two' | string;
|
||||
}
|
||||
|
||||
export {Type, Interface, Class};
|
||||
|
|
|
@ -1,39 +1,51 @@
|
|||
{
|
||||
"schemas": [
|
||||
"types": [
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Type",
|
||||
"namespace": "unionsAndEnums",
|
||||
"id": ["unionsAndEnums", "Type"],
|
||||
"kind": "record",
|
||||
"fields": [{
|
||||
"name": "a",
|
||||
"type": [
|
||||
"double",
|
||||
{"type": "enum", "symbols": ["one", "two"]}
|
||||
]
|
||||
"value": {
|
||||
"kind": "union",
|
||||
"variants": [
|
||||
{"kind": "literal", "value": "one"},
|
||||
{"kind": "literal", "value": "two"},
|
||||
{"kind": "string"}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Interface",
|
||||
"namespace": "unionsAndEnums",
|
||||
"id": ["unionsAndEnums", "Interface"],
|
||||
"kind": "record",
|
||||
"fields": [{
|
||||
"name": "a",
|
||||
"type": [
|
||||
"double",
|
||||
{"type": "enum", "symbols": ["one", "two"]}
|
||||
]
|
||||
"value": {
|
||||
"kind": "union",
|
||||
"variants": [
|
||||
{"kind": "literal", "value": "one"},
|
||||
{"kind": "literal", "value": "two"},
|
||||
{"kind": "string"}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Class",
|
||||
"namespace": "unionsAndEnums",
|
||||
"id": ["unionsAndEnums", "Class"],
|
||||
"kind": "record",
|
||||
"fields": [{
|
||||
"name": "a",
|
||||
"type": [
|
||||
"double",
|
||||
{"type": "enum", "symbols": ["one", "two"]}
|
||||
]
|
||||
"value": {
|
||||
"kind": "union",
|
||||
"variants": [
|
||||
{"kind": "literal", "value": "one"},
|
||||
{"kind": "literal", "value": "two"},
|
||||
{"kind": "string"}
|
||||
]
|
||||
},
|
||||
"required": true
|
||||
}]
|
||||
}
|
||||
]
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"schemas": []
|
||||
"types": []
|
||||
}
|
||||
|
|
|
@ -1,27 +1,24 @@
|
|||
{
|
||||
"schemas": [
|
||||
"types": [
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Type",
|
||||
"namespace": "valueAsType",
|
||||
"id": ["valueAsType", "Type"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "a", "type": {"type": "enum", "symbols": ["one"]}}
|
||||
{"name": "a", "value": {"kind": "literal", "value": "one"}, "required": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Interface",
|
||||
"namespace": "valueAsType",
|
||||
"id": ["valueAsType", "Interface"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "a", "type": {"type": "enum", "symbols": ["one"]}}
|
||||
{"name": "a", "value": {"kind": "literal", "value": "one"}, "required": true}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "record",
|
||||
"name": "Class",
|
||||
"namespace": "valueAsType",
|
||||
"id": ["valueAsType", "Class"],
|
||||
"kind": "record",
|
||||
"fields": [
|
||||
{"name": "a", "type": {"type": "enum", "symbols": ["one"]}}
|
||||
{"name": "a", "value": {"kind": "literal", "value": "one"}, "required": true}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue