From e86a2d2483cc63e937c9b4fbb1fc1b8a4c6d7515 Mon Sep 17 00:00:00 2001 From: Jack Martin Date: Mon, 27 Jan 2020 10:54:23 +0000 Subject: [PATCH] build: add interface export --- lib/renderTypeScript.js | 80 ++++++++++---------- samples/chat.ts | 22 +++--- samples/children-by-nesting.ts | 4 +- samples/children.ts | 4 +- samples/generics.ts | 10 +-- samples/map-scalar.ts | 6 +- samples/serialized.ts | 6 +- samples/type-extension.ts | 10 +-- samples/user-security.ts | 10 +-- spec/lib/renderTypeScriptSpec.js | 122 +++++++++++++++++-------------- 10 files changed, 145 insertions(+), 129 deletions(-) diff --git a/lib/renderTypeScript.js b/lib/renderTypeScript.js index 4c7907e..43e557d 100644 --- a/lib/renderTypeScript.js +++ b/lib/renderTypeScript.js @@ -1,61 +1,60 @@ -const _ = require('lodash'); +const _ = require("lodash"); // Private: Mappings from some Bolt built-in types to their TypeScript equivalents const BOLT_BUILTIN_MAPPING = { - Any: 'any', - Boolean: 'boolean', - Number: 'number', - Null: 'void', - Object: 'Object', - String: 'string', + Any: "any", + Boolean: "boolean", + Number: "number", + Null: "void", + Object: "Object", + String: "string" }; function convertBuiltin(builtin) { return BOLT_BUILTIN_MAPPING[builtin] || builtin; } - function ts(type) { - if (typeof type === 'string') { + if (typeof type === "string") { return convertBuiltin(type); } let str = convertBuiltin(type.name); if (type.params && type.params.length > 0) { - str += '<'; - str += type.params.map(ts).join(', '); - str += '>'; + str += "<"; + str += type.params.map(ts).join(", "); + str += ">"; } return str; } function tse(type) { - if (typeof type === 'string') { + if (typeof type === "string") { return convertBuiltin(type); } let str = type.name; if (type.params && type.params.length > 0) { - str += '<'; - str += type.params.map(ts).join(', '); - str += '>'; + str += "<"; + str += type.params.map(ts).join(", "); + str += ">"; } return str; } // Private: function unionPropertyLine(name, types) { - const isNullable = _.some(types, type => type.name === 'Null'); - const tsTypes = types.filter(type => type.name !== 'Null'); + const isNullable = _.some(types, type => type.name === "Null"); + const tsTypes = types.filter(type => type.name !== "Null"); - let str = ''; + let str = ""; str += name; - str += isNullable ? '?' : ''; - str += ': '; - str += tsTypes.map(ts).join(' | '); - str += ';'; + str += isNullable ? "?" : ""; + str += ": "; + str += tsTypes.map(ts).join(" | "); + str += ";"; return str; } @@ -66,7 +65,7 @@ function mapPropertyLine(name, typeDefiniton) { function genericPropertyLine(name, typeDef) { switch (typeDef.name) { - case 'Map': + case "Map": return mapPropertyLine(name, typeDef); default: return `${name}: ${ts(typeDef)};`; @@ -78,11 +77,11 @@ function propertyLine(property) { const typeDef = property.definition; switch (typeDef.type) { - case 'type': + case "type": return `${name}: ${convertBuiltin(typeDef.name)};`; - case 'union': + case "union": return unionPropertyLine(name, typeDef.types); - case 'generic': + case "generic": return genericPropertyLine(name, typeDef); default: throw new Error(`Unknown type ${typeDef.type}`); @@ -97,37 +96,40 @@ function propertyLine(property) { // Note this will return `extends Any` for any Bolt defintion without any // defined parent or properties. function interfaceExtension(type) { - if (type.parent !== 'Object') { - if (type.parent !== 'Any' || type.parent === 'Any' && type.properties !== []) { + if (type.parent !== "Object") { + if ( + type.parent !== "Any" || + (type.parent === "Any" && type.properties !== []) + ) { return ` extends ${tse(type.definition.derivedFrom)}`; } - return ''; + return ""; } - return ''; + return ""; } // type - TopLevelType function interfaceOpen(type) { - let str = ''; - str += 'interface '; + let str = ""; + str += "export interface "; str += tse(type); str += interfaceExtension(type); - str += ' {'; + str += " {"; return str; } // simpleBoltSchema - SimpleBoltSchema function render(simpleBoltSchema) { - let str = ''; + let str = ""; simpleBoltSchema.types.forEach(type => { str += interfaceOpen(type); - str += '\n'; + str += "\n"; type.properties.forEach(property => { - str += ' '; + str += " "; str += propertyLine(property); - str += '\n'; + str += "\n"; }); - str += '}\n'; + str += "}\n"; }); return str; } diff --git a/samples/chat.ts b/samples/chat.ts index c58c876..8827fb3 100644 --- a/samples/chat.ts +++ b/samples/chat.ts @@ -1,30 +1,30 @@ -interface RoomInfo { +export interface RoomInfo { name: NameString; creator: UserID; members: { [key: string]: Member; }; } -interface Post { +export interface Post { from: UserID; message: MessageString; } -interface MessageString extends String { +export interface MessageString extends String { } -interface Member { +export interface Member { nickname: NameString; isBanned: boolean; } -interface NameString extends Any { +export interface NameString extends Any { } -interface Timestamped extends T { +export interface Timestamped extends T { created: Created; } -interface Created extends Number { +export interface Created extends Number { } -interface Modified extends Number { +export interface Modified extends Number { } -interface PushID extends String { +export interface PushID extends String { } -interface RoomID extends String { +export interface RoomID extends String { } -interface UserID extends String { +export interface UserID extends String { } diff --git a/samples/children-by-nesting.ts b/samples/children-by-nesting.ts index 72ded40..66d9104 100644 --- a/samples/children-by-nesting.ts +++ b/samples/children-by-nesting.ts @@ -1,6 +1,6 @@ -interface Child { +export interface Child { age: number; } -interface Parent { +export interface Parent { children: { [key: string]: Child; }; } diff --git a/samples/children.ts b/samples/children.ts index f5c0961..94fbdea 100644 --- a/samples/children.ts +++ b/samples/children.ts @@ -1,5 +1,5 @@ -interface Child { +export interface Child { age: number; } -interface Parent extends Any { +export interface Parent extends Any { } diff --git a/samples/generics.ts b/samples/generics.ts index 26f9f91..db207e0 100644 --- a/samples/generics.ts +++ b/samples/generics.ts @@ -1,16 +1,16 @@ -interface App { +export interface App { users: { [key: string]: User; }; products: { [key: string]: Product; }; } -interface User { +export interface User { name: string; age: number; } -interface Product { +export interface Product { id: ProductID; cost: number; } -interface ProductID extends String { +export interface ProductID extends String { } -interface PushID extends String { +export interface PushID extends String { } diff --git a/samples/map-scalar.ts b/samples/map-scalar.ts index 6909642..c03944e 100644 --- a/samples/map-scalar.ts +++ b/samples/map-scalar.ts @@ -1,10 +1,10 @@ -interface Test { +export interface Test { s1: ShortString; s2: AliasString; m1: { [key: string]: number; }; m2: { [key: string]: number; }; } -interface AliasString extends ShortString { +export interface AliasString extends ShortString { } -interface ShortString extends String { +export interface ShortString extends String { } diff --git a/samples/serialized.ts b/samples/serialized.ts index 846bbc2..8e8cd77 100644 --- a/samples/serialized.ts +++ b/samples/serialized.ts @@ -1,9 +1,9 @@ -interface Product { +export interface Product { name: string; cost: number; } -interface Serialized extends T { +export interface Serialized extends T { counter: Counter; } -interface Counter extends Number { +export interface Counter extends Number { } diff --git a/samples/type-extension.ts b/samples/type-extension.ts index 599a290..73fd7f9 100644 --- a/samples/type-extension.ts +++ b/samples/type-extension.ts @@ -1,12 +1,12 @@ -interface PositiveInteger extends Number { +export interface PositiveInteger extends Number { } -interface UnixTimestamp extends PositiveInteger { +export interface UnixTimestamp extends PositiveInteger { } -interface NonEmptyString extends String { +export interface NonEmptyString extends String { } -interface URL extends String { +export interface URL extends String { } -interface Test { +export interface Test { time: UnixTimestamp; name: NonEmptyString; url: URL; diff --git a/samples/user-security.ts b/samples/user-security.ts index efc5a4c..93b0ade 100644 --- a/samples/user-security.ts +++ b/samples/user-security.ts @@ -1,12 +1,12 @@ -interface Nickname extends String { +export interface Nickname extends String { } -interface UserID extends String { +export interface UserID extends String { } -interface MessageString extends String { +export interface MessageString extends String { } -interface Timestamp extends Number { +export interface Timestamp extends Number { } -interface Message { +export interface Message { user: UserID; message: MessageString; timestamp: Timestamp; diff --git a/spec/lib/renderTypeScriptSpec.js b/spec/lib/renderTypeScriptSpec.js index 1d57f4d..59b45ad 100644 --- a/spec/lib/renderTypeScriptSpec.js +++ b/spec/lib/renderTypeScriptSpec.js @@ -1,7 +1,7 @@ -const bolt = require('firebase-bolt'); -const SimpleBoltSchema = require('../../lib/SimpleBoltSchema.js'); -const renderTypeScript = require('../../lib/renderTypeScript.js'); -const _ = require('lodash'); +const bolt = require("firebase-bolt"); +const SimpleBoltSchema = require("../../lib/SimpleBoltSchema.js"); +const renderTypeScript = require("../../lib/renderTypeScript.js"); +const _ = require("lodash"); const boltExample = ` type Type {} @@ -48,8 +48,8 @@ type PropertyLineCheck { `; const schema = new SimpleBoltSchema(bolt.parse(boltExample).schema); -const typesByName = _.keyBy(schema.types, 'name'); -const propsByName = _.keyBy(typesByName.PropertyLineCheck.properties, 'name'); +const typesByName = _.keyBy(schema.types, "name"); +const propsByName = _.keyBy(typesByName.PropertyLineCheck.properties, "name"); function interfaceOpen(interfaceName) { return renderTypeScript.interfaceOpen(typesByName[interfaceName]); @@ -58,31 +58,34 @@ function propertyLine(propName) { return renderTypeScript.propertyLine(propsByName[propName]); } -describe('renderTypeScript', () => { - describe('interfaceOpen', () => { - it('simple type with properties', () => { - expect(interfaceOpen('SimpleType')) - .toEqual('interface SimpleType {'); +describe("renderTypeScript", () => { + describe("interfaceOpen", () => { + it("simple type with properties", () => { + expect(interfaceOpen("SimpleType")).toEqual( + "export interface SimpleType {" + ); }); - it('generic type with properties', () => { - expect(interfaceOpen('GenericType')) - .toEqual('interface GenericType {'); + it("generic type with properties", () => { + expect(interfaceOpen("GenericType")).toEqual( + "export interface GenericType {" + ); }); - it('generic type with multiple parameters', () => { - expect(interfaceOpen('Pairs')) - .toEqual('interface Pairs {'); + it("generic type with multiple parameters", () => { + expect(interfaceOpen("Pairs")).toEqual("export interface Pairs {"); }); - it('type without any properties (should extend Any)', () => { - expect(interfaceOpen('NoDefinedProperties')) - .toEqual('interface NoDefinedProperties extends Any {'); + it("type without any properties (should extend Any)", () => { + expect(interfaceOpen("NoDefinedProperties")).toEqual( + "export interface NoDefinedProperties extends Any {" + ); }); - it('type which extends another type', () => { - expect(interfaceOpen('StringExtension')) - .toEqual('interface StringExtension extends String {'); + it("type which extends another type", () => { + expect(interfaceOpen("StringExtension")).toEqual( + "export interface StringExtension extends String {" + ); }); // it('type which extends Object', () => { @@ -90,25 +93,27 @@ describe('renderTypeScript', () => { // .toEqual('interface ObjectExtension extends Object {'); // }); - it('type which extends a generic with a single parameter', () => { - expect(interfaceOpen('GenericExtension')) - .toEqual('interface GenericExtension extends GenericType {'); + it("type which extends a generic with a single parameter", () => { + expect(interfaceOpen("GenericExtension")).toEqual( + "export interface GenericExtension extends GenericType {" + ); }); - it('type which extends a generic with multiple parameters', () => { - expect(interfaceOpen('PairExtension')) - .toEqual('interface PairExtension extends Pair {'); + it("type which extends a generic with multiple parameters", () => { + expect(interfaceOpen("PairExtension")).toEqual( + "export interface PairExtension extends Pair {" + ); }); }); - describe('propertyLine', () => { - it('renders builtins appropriately', () => { - expect(propertyLine('any')).toEqual('any: any;'); - expect(propertyLine('boolean')).toEqual('boolean: boolean;'); - expect(propertyLine('number')).toEqual('number: number;'); - expect(propertyLine('null')).toEqual('null: void;'); - expect(propertyLine('object')).toEqual('object: Object;'); - expect(propertyLine('string')).toEqual('string: string;'); + describe("propertyLine", () => { + it("renders builtins appropriately", () => { + expect(propertyLine("any")).toEqual("any: any;"); + expect(propertyLine("boolean")).toEqual("boolean: boolean;"); + expect(propertyLine("number")).toEqual("number: number;"); + expect(propertyLine("null")).toEqual("null: void;"); + expect(propertyLine("object")).toEqual("object: Object;"); + expect(propertyLine("string")).toEqual("string: string;"); }); }); @@ -116,40 +121,49 @@ describe('renderTypeScript', () => { // Generics // - it('arrays', () => { - expect(propertyLine('objects')).toEqual('objects: { [key: string]: Object; };'); + it("arrays", () => { + expect(propertyLine("objects")).toEqual( + "objects: { [key: string]: Object; };" + ); }); - it('maps', () => { - expect(propertyLine('map')).toEqual('map: { [key: string]: number; };'); + it("maps", () => { + expect(propertyLine("map")).toEqual("map: { [key: string]: number; };"); }); - it('pair', () => { - expect(propertyLine('pair')).toEqual('pair: Pair;'); + it("pair", () => { + expect(propertyLine("pair")).toEqual("pair: Pair;"); }); // // Unions // - it('union', () => { - expect(propertyLine('union')).toEqual('union: Type | string | number;'); + it("union", () => { + expect(propertyLine("union")).toEqual("union: Type | string | number;"); }); - it('union with null', () => { - expect(propertyLine('nullable_union')).toEqual('nullable_union?: Type | string | number;'); + it("union with null", () => { + expect(propertyLine("nullable_union")).toEqual( + "nullable_union?: Type | string | number;" + ); }); - it('nullable', () => { - expect(propertyLine('nullable_string')).toEqual('nullable_string?: string;'); + it("nullable", () => { + expect(propertyLine("nullable_string")).toEqual( + "nullable_string?: string;" + ); }); - it('union with generic', () => { - expect(propertyLine('generic_union')).toEqual('generic_union: Pair | number;'); + it("union with generic", () => { + expect(propertyLine("generic_union")).toEqual( + "generic_union: Pair | number;" + ); }); - it('nested union with generic', () => { - expect(propertyLine('nested_generic_union')) - .toEqual('nested_generic_union: Pair, string> | number;'); + it("nested union with generic", () => { + expect(propertyLine("nested_generic_union")).toEqual( + "nested_generic_union: Pair, string> | number;" + ); }); });