From f175bcd1b9582a128dfb24ac65bfabc65f85ec59 Mon Sep 17 00:00:00 2001 From: york yao Date: Mon, 24 Jul 2017 15:56:05 +0800 Subject: [PATCH] add support for interface, boolean; fix number type --- demo/cases-debug.json | 187 ++++++++++++++++++++++++++++++++++++ demo/cases.json | 117 ++++++++++++++++++++++ demo/cases.proto | 26 +++++ demo/cases.ts | 76 +++++++++++++++ demo/debug.json | 22 ++--- demo/flow-protocol.json | 8 +- demo/request-protocol.json | 12 ++- demo/response-protocol.json | 32 ++++-- demo/types.ts | 33 +++++++ package.json | 1 + src/index.ts | 174 +++++++++++++++++++-------------- 11 files changed, 593 insertions(+), 95 deletions(-) create mode 100644 demo/cases-debug.json create mode 100644 demo/cases.json create mode 100644 demo/cases.proto create mode 100644 demo/cases.ts diff --git a/demo/cases-debug.json b/demo/cases-debug.json new file mode 100644 index 0000000..6654847 --- /dev/null +++ b/demo/cases-debug.json @@ -0,0 +1,187 @@ +[ + { + "kind": "object", + "name": "Foo", + "members": [ + { + "name": "bar", + "type": { + "kind": "number", + "type": "number" + }, + "optional": false, + "tag": 2 + }, + { + "name": "baz", + "type": { + "kind": "string" + }, + "optional": false, + "tag": 3 + } + ], + "minProperties": 2, + "maxProperties": 2 + }, + { + "kind": "object", + "name": "Foo2", + "members": [ + { + "name": "booleanBar", + "type": { + "kind": "boolean" + }, + "optional": false, + "tag": 1 + }, + { + "name": "stringBar", + "type": { + "kind": "string" + }, + "optional": false, + "tag": 2 + }, + { + "name": "numberBar", + "type": { + "kind": "number", + "type": "number" + }, + "optional": false, + "tag": 3 + }, + { + "name": "integerBar", + "type": { + "kind": "number", + "type": "integer" + }, + "optional": false, + "tag": 4 + }, + { + "name": "uint32Bar", + "type": { + "kind": "number", + "type": "uint32" + }, + "optional": false, + "tag": 5 + }, + { + "name": "int32Bar", + "type": { + "kind": "number", + "type": "int32" + }, + "optional": false, + "tag": 6 + }, + { + "name": "sint32Bar", + "type": { + "kind": "number", + "type": "sint32" + }, + "optional": false, + "tag": 7 + }, + { + "name": "fixed32Bar", + "type": { + "kind": "number", + "type": "fixed32" + }, + "optional": false, + "tag": 8 + }, + { + "name": "sfixed32Bar", + "type": { + "kind": "number", + "type": "sfixed32" + }, + "optional": false, + "tag": 9 + }, + { + "name": "uint64Bar", + "type": { + "kind": "number", + "type": "uint64" + }, + "optional": false, + "tag": 10 + }, + { + "name": "int64Bar", + "type": { + "kind": "number", + "type": "int64" + }, + "optional": false, + "tag": 11 + }, + { + "name": "sint64Bar", + "type": { + "kind": "number", + "type": "sint64" + }, + "optional": false, + "tag": 12 + }, + { + "name": "fixed64Bar", + "type": { + "kind": "number", + "type": "fixed64" + }, + "optional": false, + "tag": 13 + }, + { + "name": "sfixed64Bar", + "type": { + "kind": "number", + "type": "sfixed64" + }, + "optional": false, + "tag": 14 + }, + { + "name": "floatBar", + "type": { + "kind": "number", + "type": "float" + }, + "optional": false, + "tag": 15 + }, + { + "name": "doubleBar", + "type": { + "kind": "number", + "type": "double" + }, + "optional": false, + "tag": 16 + }, + { + "name": "referenceBar", + "type": { + "kind": "reference", + "name": "Foo" + }, + "optional": false, + "tag": 17 + } + ], + "minProperties": 17, + "maxProperties": 17, + "entry": "cases.json" + } +] \ No newline at end of file diff --git a/demo/cases.json b/demo/cases.json new file mode 100644 index 0000000..d292e7a --- /dev/null +++ b/demo/cases.json @@ -0,0 +1,117 @@ +{ + "$ref": "#/definitions/Foo2", + "definitions": { + "Foo2": { + "type": "object", + "properties": { + "booleanBar": { + "type": "boolean" + }, + "stringBar": { + "type": "string" + }, + "numberBar": { + "type": "number" + }, + "integerBar": { + "type": "integer" + }, + "uint32Bar": { + "type": "integer", + "minimum": 0, + "maximum": 4294967295 + }, + "int32Bar": { + "type": "integer", + "minimum": -2147483648, + "maximum": 2147483647 + }, + "sint32Bar": { + "type": "integer", + "minimum": -2147483648, + "maximum": 2147483647 + }, + "fixed32Bar": { + "type": "integer", + "minimum": 0, + "maximum": 4294967295 + }, + "sfixed32Bar": { + "type": "integer", + "minimum": -2147483648, + "maximum": 2147483647 + }, + "uint64Bar": { + "type": "integer", + "minimum": 0, + "maximum": 18446744073709552000 + }, + "int64Bar": { + "type": "integer", + "minimum": -9223372036854776000, + "maximum": 9223372036854776000 + }, + "sint64Bar": { + "type": "integer", + "minimum": -9223372036854776000, + "maximum": 9223372036854776000 + }, + "fixed64Bar": { + "type": "integer", + "minimum": 0, + "maximum": 18446744073709552000 + }, + "sfixed64Bar": { + "type": "integer", + "minimum": -9223372036854776000, + "maximum": 9223372036854776000 + }, + "floatBar": { + "type": "number" + }, + "doubleBar": { + "type": "number" + }, + "referenceBar": { + "$ref": "#/definitions/Foo" + } + }, + "required": [ + "booleanBar", + "stringBar", + "numberBar", + "integerBar", + "uint32Bar", + "int32Bar", + "sint32Bar", + "fixed32Bar", + "sfixed32Bar", + "uint64Bar", + "int64Bar", + "sint64Bar", + "fixed64Bar", + "sfixed64Bar", + "floatBar", + "doubleBar", + "referenceBar" + ], + "additionalProperties": false + }, + "Foo": { + "type": "object", + "properties": { + "bar": { + "type": "number" + }, + "baz": { + "type": "string" + } + }, + "required": [ + "bar", + "baz" + ], + "additionalProperties": false + } + } +} \ No newline at end of file diff --git a/demo/cases.proto b/demo/cases.proto new file mode 100644 index 0000000..4be1d81 --- /dev/null +++ b/demo/cases.proto @@ -0,0 +1,26 @@ +syntax = "proto3"; + +message Foo { + double bar = 2; + string baz = 3; +} + +message Foo2 { + bool booleanBar = 1; + string stringBar = 2; + double numberBar = 3; + int32 integerBar = 4; + uint32 uint32Bar = 5; + int32 int32Bar = 6; + sint32 sint32Bar = 7; + fixed32 fixed32Bar = 8; + sfixed32 sfixed32Bar = 9; + uint64 uint64Bar = 10; + int64 int64Bar = 11; + sint64 sint64Bar = 12; + fixed64 fixed64Bar = 13; + sfixed64 sfixed64Bar = 14; + float floatBar = 15; + double doubleBar = 16; + Foo referenceBar = 17; +} diff --git a/demo/cases.ts b/demo/cases.ts new file mode 100644 index 0000000..bd21110 --- /dev/null +++ b/demo/cases.ts @@ -0,0 +1,76 @@ +export interface Foo { + /** + * @tag 2 + */ + bar: number; + baz: string; +} + +/** + * @entry cases.json + */ +export type Foo2 = { + booleanBar: boolean; + + stringBar: string; + + numberBar: number; + + /** + * @type integer + */ + integerBar: number; + + /** + * @type uint32 + */ + uint32Bar: number; + /** + * @type int32 + */ + int32Bar: number; + /** + * @type sint32 + */ + sint32Bar: number; + /** + * @type fixed32 + */ + fixed32Bar: number; + /** + * @type sfixed32 + */ + sfixed32Bar: number; + + /** + * @type uint64 + */ + uint64Bar: number; + /** + * @type int64 + */ + int64Bar: number; + /** + * @type sint64 + */ + sint64Bar: number; + /** + * @type fixed64 + */ + fixed64Bar: number; + /** + * @type sfixed64 + */ + sfixed64Bar: number; + + /** + * @type float + */ + floatBar: number; + /** + * @type double + */ + doubleBar: number; + + referenceBar: Foo; +}; diff --git a/demo/debug.json b/demo/debug.json index 00f23c0..343e8c5 100644 --- a/demo/debug.json +++ b/demo/debug.json @@ -47,7 +47,7 @@ "name": "requestId", "type": { "kind": "number", - "type": "number" + "type": "uint32" }, "optional": false, "tag": 1 @@ -121,7 +121,7 @@ "name": "from", "type": { "kind": "number", - "type": "number" + "type": "uint32" }, "optional": false, "tag": 4 @@ -130,7 +130,7 @@ "name": "size", "type": { "kind": "number", - "type": "number" + "type": "uint32" }, "optional": false, "tag": 5 @@ -272,7 +272,7 @@ "name": "requestId", "type": { "kind": "number", - "type": "number" + "type": "uint32" }, "optional": false, "tag": 1 @@ -294,7 +294,7 @@ "name": "total", "type": { "kind": "number", - "type": "number" + "type": "uint32" }, "optional": true, "tag": 3 @@ -331,7 +331,7 @@ "name": "requestId", "type": { "kind": "number", - "type": "number" + "type": "uint32" }, "optional": false, "tag": 1 @@ -381,7 +381,7 @@ "name": "requestId", "type": { "kind": "number", - "type": "number" + "type": "uint32" }, "optional": false, "tag": 1 @@ -403,7 +403,7 @@ "name": "savedCount", "type": { "kind": "number", - "type": "number" + "type": "uint32" }, "optional": true, "tag": 3 @@ -412,7 +412,7 @@ "name": "totalCount", "type": { "kind": "number", - "type": "number" + "type": "uint32" }, "optional": true, "tag": 4 @@ -573,7 +573,7 @@ "name": "port", "type": { "kind": "number", - "type": "number" + "type": "uint32" }, "optional": true, "tag": 2 @@ -587,7 +587,7 @@ }, "value": { "kind": "number", - "type": "number" + "type": "uint32" } }, "optional": false, diff --git a/demo/flow-protocol.json b/demo/flow-protocol.json index d5aa5de..d90357b 100644 --- a/demo/flow-protocol.json +++ b/demo/flow-protocol.json @@ -71,12 +71,16 @@ "type": "string" }, "port": { - "type": "number" + "type": "integer", + "minimum": 0, + "maximum": 4294967295 }, "values": { "type": "object", "additionalProperties": { - "type": "number" + "type": "integer", + "minimum": 0, + "maximum": 4294967295 } } }, diff --git a/demo/request-protocol.json b/demo/request-protocol.json index 51c58eb..2b8ef5b 100644 --- a/demo/request-protocol.json +++ b/demo/request-protocol.json @@ -5,7 +5,9 @@ "type": "object", "properties": { "requestId": { - "type": "number" + "type": "integer", + "minimum": 0, + "maximum": 4294967295 }, "kind": { "type": "string", @@ -42,10 +44,14 @@ "type": "string" }, "from": { - "type": "number" + "type": "integer", + "minimum": 0, + "maximum": 4294967295 }, "size": { - "type": "number" + "type": "integer", + "minimum": 0, + "maximum": 4294967295 } }, "required": [ diff --git a/demo/response-protocol.json b/demo/response-protocol.json index 7303c72..9a17d7f 100644 --- a/demo/response-protocol.json +++ b/demo/response-protocol.json @@ -113,12 +113,16 @@ "type": "string" }, "port": { - "type": "number" + "type": "integer", + "minimum": 0, + "maximum": 4294967295 }, "values": { "type": "object", "additionalProperties": { - "type": "number" + "type": "integer", + "minimum": 0, + "maximum": 4294967295 } } }, @@ -150,7 +154,9 @@ "type": "object", "properties": { "requestId": { - "type": "number" + "type": "integer", + "minimum": 0, + "maximum": 4294967295 }, "kind": { "type": "string", @@ -160,7 +166,9 @@ ] }, "total": { - "type": "number" + "type": "integer", + "minimum": 0, + "maximum": 4294967295 }, "logs": { "type": "array", @@ -184,7 +192,9 @@ "type": "object", "properties": { "requestId": { - "type": "number" + "type": "integer", + "minimum": 0, + "maximum": 4294967295 }, "kind": { "type": "string", @@ -214,7 +224,9 @@ "type": "object", "properties": { "requestId": { - "type": "number" + "type": "integer", + "minimum": 0, + "maximum": 4294967295 }, "kind": { "type": "string", @@ -224,10 +236,14 @@ ] }, "savedCount": { - "type": "number" + "type": "integer", + "minimum": 0, + "maximum": 4294967295 }, "totalCount": { - "type": "number" + "type": "integer", + "minimum": 0, + "maximum": 4294967295 }, "error": { "type": "string" diff --git a/demo/types.ts b/demo/types.ts index 5e178e9..dfb3869 100644 --- a/demo/types.ts +++ b/demo/types.ts @@ -2,6 +2,9 @@ * @entry request-protocol.json */ export type RequestProtocol = { + /** + * @type uint32 + */ requestId: number; } & ( { @@ -25,7 +28,13 @@ export type SearchLogs = { content: string; time: string; hostname: string; + /** + * @type uint32 + */ from: number; + /** + * @type uint32 + */ size: number; }; @@ -69,10 +78,16 @@ type Flows = { }; export type SearchLogsResult = { + /** + * @type uint32 + */ requestId: number; } & ( { kind: ResultKind.success; + /** + * @type uint32 + */ total: number; logs?: Log[]; } | { @@ -82,6 +97,9 @@ export type SearchLogsResult = { ); type SearchSamplesResult = { + /** + * @type uint32 + */ requestId: number; } & ( { @@ -94,11 +112,20 @@ type SearchSamplesResult = { ); export type ResaveFailedLogsResult = { + /** + * @type uint32 + */ requestId: number; } & ( { kind: ResultKind.success; + /** + * @type uint32 + */ savedCount: number; + /** + * @type uint32 + */ totalCount: number; } | { kind: ResultKind.fail @@ -146,6 +173,12 @@ export type Log = { export type Sample = { hostname: string; + /** + * @type uint32 + */ port?: number; + /** + * @mapValueType uint32 + */ values: { [name: string]: number }; }; diff --git a/package.json b/package.json index c6dd9f6..1aa581d 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "tslint": "tslint \"src/**/*.ts\"", "demoTest": "./bin/types-as-schema demo/types.ts --json demo/ --debug demo/debug.json --protobuf demo/types.proto", "demoMatch": "./bin/types-as-schema demo/match.ts --json demo/ --debug demo/match-debug.json", + "demoCases": "./bin/types-as-schema demo/cases.ts --json demo/ --debug demo/cases-debug.json --protobuf demo/cases.proto", "test": "tsc -p spec && jasmine", "standard": "standard \"**/*.config.js\"", "fix": "standard --fix \"**/*.config.js\"", diff --git a/src/index.ts b/src/index.ts index 5c5c76f..3b84a89 100644 --- a/src/index.ts +++ b/src/index.ts @@ -104,6 +104,17 @@ async function executeCommandLine() { entry: entry ? entry.comment : undefined, }); } + } else if (node.kind === ts.SyntaxKind.InterfaceDeclaration) { + const declaration = node as ts.InterfaceDeclaration; + const { members, minProperties, maxProperties } = getObjectMembers(declaration.members, models); + models.push({ + kind: "object", + name: declaration.name.text, + members, + minProperties, + maxProperties, + entry: entry ? entry.comment : undefined, + }); } }); @@ -148,76 +159,7 @@ function getMembersInfo(node: ts.TypeNode, models: Model[]): MembersInfo { let lastTag = 0; if (node.kind === ts.SyntaxKind.TypeLiteral) { const typeLiteral = node as ts.TypeLiteralNode; - for (const element of typeLiteral.members) { - if (element.kind === ts.SyntaxKind.PropertySignature) { - const property = element as ts.PropertySignature; - const name = property.name as ts.Identifier; - const member: Member = { - name: name.text, - type: { - kind: "unknown", - }, - optional: false, - tag: 0, - }; - members.push(member); - - if (property.questionToken) { - member.optional = true; - } else { - minProperties++; - } - maxProperties++; - - if (property.type) { - member.type = getType(property.type, models); - } - - const propertyJsDocs = getJsDocs(property); - for (const propertyJsDoc of propertyJsDocs) { - if (propertyJsDoc.name === "tag") { - if (propertyJsDoc.comment) { - member.tag = +propertyJsDoc.comment; - } - lastTag = member.tag; - } else if (propertyJsDoc.name === "mapValueType") { - if (propertyJsDoc.comment && member.type.kind === "map") { - member.type.value = { - kind: "string", - value: propertyJsDoc.comment, - }; - } - } else if (propertyJsDoc.name === "type") { - overrideType(member.type, propertyJsDoc); - } else if (propertyJsDoc.name === "uniqueItems") { - const arrayType = member.type as ArrayType; - if (arrayType) { - arrayType.uniqueItems = true; - } - } else if (propertyJsDoc.name === "minItems") { - const arrayType = member.type as ArrayType; - if (arrayType && propertyJsDoc.comment) { - arrayType.minItems = +propertyJsDoc.comment; - } - } else if (propertyJsDoc.name === "itemType") { - if (propertyJsDoc.comment && member.type.kind === "array") { - overrideType(member.type, propertyJsDoc); - } - } else if (propertyJsDoc.name === "itemMinimum") { - if (propertyJsDoc.comment - && member.type.kind === "array" - && member.type.type.kind === "number") { - member.type.type.minimum = +propertyJsDoc.comment; - } - } - } - - if (!member.tag) { - member.tag = lastTag + 1; - lastTag = member.tag; - } - } - } + return getObjectMembers(typeLiteral.members, models); } else if (node.kind === ts.SyntaxKind.UnionType) { const unionType = node as ts.UnionTypeNode; minProperties = Infinity; @@ -279,6 +221,83 @@ function getMembersInfo(node: ts.TypeNode, models: Model[]): MembersInfo { return { members, minProperties, maxProperties }; } +function getObjectMembers(elements: ts.NodeArray, models: Model[]): MembersInfo { + const members: Member[] = []; + let minProperties = 0; + let maxProperties = 0; + let lastTag = 0; + for (const element of elements) { + if (element.kind === ts.SyntaxKind.PropertySignature) { + const property = element as ts.PropertySignature; + const name = property.name as ts.Identifier; + const member: Member = { + name: name.text, + type: { + kind: "unknown", + }, + optional: false, + tag: 0, + }; + members.push(member); + + if (property.questionToken) { + member.optional = true; + } else { + minProperties++; + } + maxProperties++; + + if (property.type) { + member.type = getType(property.type, models); + } + + const propertyJsDocs = getJsDocs(property); + for (const propertyJsDoc of propertyJsDocs) { + if (propertyJsDoc.name === "tag") { + if (propertyJsDoc.comment) { + member.tag = +propertyJsDoc.comment; + } + lastTag = member.tag; + } else if (propertyJsDoc.name === "mapValueType") { + if (propertyJsDoc.comment && member.type.kind === "map") { + if (member.type.value.kind === "number") { + member.type.value.type = propertyJsDoc.comment; + } + } + } else if (propertyJsDoc.name === "type") { + overrideType(member.type, propertyJsDoc); + } else if (propertyJsDoc.name === "uniqueItems") { + const arrayType = member.type as ArrayType; + if (arrayType) { + arrayType.uniqueItems = true; + } + } else if (propertyJsDoc.name === "minItems") { + const arrayType = member.type as ArrayType; + if (arrayType && propertyJsDoc.comment) { + arrayType.minItems = +propertyJsDoc.comment; + } + } else if (propertyJsDoc.name === "itemType") { + if (propertyJsDoc.comment && member.type.kind === "array") { + overrideType(member.type, propertyJsDoc); + } + } else if (propertyJsDoc.name === "itemMinimum") { + if (propertyJsDoc.comment + && member.type.kind === "array" + && member.type.type.kind === "number") { + member.type.type.minimum = +propertyJsDoc.comment; + } + } + } + + if (!member.tag) { + member.tag = lastTag + 1; + lastTag = member.tag; + } + } + } + return { members, minProperties, maxProperties }; +} + function getType(type: ts.TypeNode, models: Model[]): Type { if (type.kind === ts.SyntaxKind.StringKeyword) { return { @@ -289,6 +308,10 @@ function getType(type: ts.TypeNode, models: Model[]): Type { kind: "number", type: "number", }; + } else if (type.kind === ts.SyntaxKind.BooleanKeyword) { + return { + kind: "boolean", + }; } else if (type.kind === ts.SyntaxKind.TypeLiteral) { const literal = type as ts.TypeLiteralNode; if (literal.members.length === 1 && literal.members[0].kind === ts.SyntaxKind.IndexSignature) { @@ -478,9 +501,18 @@ function getProtobufProperty(memberType: Type): { modifier: string, propertyType } else if (memberType.kind === "reference") { propertyType = memberType.name; } else if (memberType.kind === "number") { - propertyType = memberType.type === "number" ? "uint32" : memberType.type; + // tslint:disable-next-line:prefer-conditional-expression + if (memberType.type === "number") { + propertyType = "double"; + } else if (memberType.type === "integer") { + propertyType = "int32"; + } else { + propertyType = memberType.type; + } } else if (memberType.kind === "string") { propertyType = memberType.kind; + } else if (memberType.kind === "boolean") { + propertyType = "bool"; } return { modifier, propertyType }; }