diff --git a/declarations/babel.js b/declarations/babel.js index a96a823..aff2220 100644 --- a/declarations/babel.js +++ b/declarations/babel.js @@ -550,6 +550,7 @@ declare module '@babel/types' { declare class BooleanLiteralTypeAnnotation extends Node { type: 'BooleanLiteralTypeAnnotation'; + value: boolean; } declare class NullLiteralTypeAnnotation extends Node { diff --git a/src/collector/declarations.js b/src/collector/declarations.js index df22ccc..ad1af0d 100644 --- a/src/collector/declarations.js +++ b/src/collector/declarations.js @@ -166,8 +166,8 @@ function extractCommonjsNamedExternals<+T: Node>(nodes: T[], path: string): Exte function processExportNamedDeclaration(ctx: Context, node: ExportNamedDeclaration) { if (isDeclaration(node.declaration)) { + node.declaration.leadingComments = node.leadingComments; const reference = processDeclaration(ctx, node.declaration); - ctx.provide(reference, reference); } diff --git a/src/collector/definitions.js b/src/collector/definitions.js index c4dd86a..6916182 100644 --- a/src/collector/definitions.js +++ b/src/collector/definitions.js @@ -4,7 +4,7 @@ import wu from 'wu'; // @see flow#5376. import type { - ArrayTypeAnnotation, ClassDeclaration, ClassProperty, Comment, FlowTypeAnnotation, + Node, ArrayTypeAnnotation, ClassDeclaration, ClassProperty, Comment, FlowTypeAnnotation, GenericTypeAnnotation, InterfaceDeclaration, IntersectionTypeAnnotation, TypeAlias, UnionTypeAnnotation, NullableTypeAnnotation, ObjectTypeIndexer, ObjectTypeProperty, StringLiteralTypeAnnotation, ObjectTypeAnnotation, AnyTypeAnnotation, MixedTypeAnnotation, @@ -31,12 +31,28 @@ import {invariant} from '../utils'; function processTypeAlias(ctx: Context, node: TypeAlias | DeclareTypeAlias) { const {name} = node.id; - const type = makeType(ctx, node.right); - // TODO: support function aliases. - invariant(type); + if (name != 'integer') { + // Forward declaration for the recursive types + ctx.define(name, t.createAny()); + + const type = makeType(ctx, node.right); + addComment(node, type); - ctx.define(name, type); + // TODO: support function aliases. + invariant(type); + + ctx.define(name, type); + } +} + +function addComment(node: Node, type: Type) { + if (node.leadingComments) { + const cmt = node.leadingComments.map(c => c.value).join('\n').trim(); + if (cmt) { + type.comment = cmt; + } + } } // TODO: type params. @@ -46,6 +62,7 @@ function processInterfaceDeclaration( ) { const {name} = node.id; const type = makeType(ctx, node.body); + addComment(node, type); invariant(type); @@ -108,6 +125,8 @@ function makeType(ctx: Context, node: FlowTypeAnnotation): ?Type { return t.createLiteral(null); case 'BooleanTypeAnnotation': return t.createBoolean(); + case 'BooleanLiteralTypeAnnotation': + return t.createLiteral(node.value); case 'NumberTypeAnnotation': return t.createNumber('f64'); case 'StringTypeAnnotation': @@ -135,7 +154,7 @@ function makeType(ctx: Context, node: FlowTypeAnnotation): ?Type { case 'MixedTypeAnnotation': return t.createMixed(); case 'FunctionTypeAnnotation': - return null; + return t.createAny(); default: invariant(false, `Unknown node: ${node.type}`); } @@ -207,6 +226,7 @@ function makeField(ctx: Context, node: ObjectTypeProperty | ClassProperty): ?Fie invariant(value); type = makeType(ctx, value); + addComment(node, type); } if (!type) { @@ -230,12 +250,14 @@ function makeField(ctx: Context, node: ObjectTypeProperty | ClassProperty): ?Fie function makeMap(ctx: Context, node: ObjectTypeIndexer): ?MapType { const keys = makeType(ctx, node.key); const values = makeType(ctx, node.value); + addComment(node, values); return keys && values ? t.createMap(keys, values) : null; } function makeArray(ctx: Context, node: ArrayTypeAnnotation): ?ArrayType { const items = makeType(ctx, node.elementType); + addComment(node, items); return items != null ? t.createArray(items) : null; } @@ -276,6 +298,9 @@ function makeIntersection(ctx: Context, node: IntersectionTypeAnnotation): ?Type function makeReference(ctx: Context, node: GenericTypeAnnotation): ?Type { const {name} = node.id; + if (name == 'integer') { + return t.createNumber('i64'); + } const params = node.typeParameters && wu(node.typeParameters.params).map(n => makeType(ctx, n)).toArray(); diff --git a/src/collector/scope.js b/src/collector/scope.js index 3aa6409..08bb432 100644 --- a/src/collector/scope.js +++ b/src/collector/scope.js @@ -84,7 +84,7 @@ export default class Scope { if (declared) { invariant(decl); - invariant(decl.kind === 'declaration'); + invariant(decl.kind === 'declaration' || decl.kind === 'definition'); } else { invariant(!decl); } diff --git a/src/generators/jsonSchema.js b/src/generators/jsonSchema.js index 9b4ce9c..2476cf1 100644 --- a/src/generators/jsonSchema.js +++ b/src/generators/jsonSchema.js @@ -12,6 +12,7 @@ export type Schema = boolean | { id?: string, $ref?: string, $schema?: string, + $comment?: string, title?: string, description?: string, default?: mixed, @@ -45,6 +46,18 @@ export type Schema = boolean | { }; function convert(fund: Fund, type: ?Type): Schema { + let schema = convertType(fund, type); + if (type && type.comment) { + if (schema === true) { + schema = { $comment: type.comment }; + } else { + schema.$comment = type.comment; + } + } + return schema; +} + +function convertType(fund: Fund, type: ?Type): Schema { if (!type) { return { type: 'null', @@ -90,13 +103,13 @@ function convert(fund: Fund, type: ?Type): Schema { }; case 'union': const enumerate = wu(type.variants) - .filter(variant => variant.kind === 'literal') + .filter(variant => variant.kind === 'literal' && variant.value !== null) .map(literal => (literal: $FlowFixMe).value) .tap(value => invariant(value !== undefined)) .toArray(); const schemas = wu(type.variants) - .filter(variant => variant.kind !== 'literal') + .filter(variant => variant.kind !== 'literal' || variant.value === null) .map(variant => convert(fund, variant)) .toArray(); diff --git a/src/types.js b/src/types.js index 34b75d4..51458a8 100644 --- a/src/types.js +++ b/src/types.js @@ -21,6 +21,7 @@ export type TypeId = string[]; export type BaseType = { id?: TypeId, + comment?: string, }; export type RecordType = BaseType & {