From fb3f9c70436d4f81bcd0bf62b71af4d253390e4f Mon Sep 17 00:00:00 2001 From: dcodeIO Date: Tue, 18 Apr 2017 14:28:36 +0200 Subject: [PATCH] CLI: Additional tsd-jsdoc handling of properties inside of namespaces and TS specific API exposure --- cli/lib/tsd-jsdoc/publish.js | 30 ++++-- config/tslint.json | 11 ++- index.d.ts | 186 +++++++++++++++++++++++++++++++++-- src/common.js | 32 ++++-- src/tokenize.js | 3 +- src/type.js | 6 +- 6 files changed, 243 insertions(+), 25 deletions(-) diff --git a/cli/lib/tsd-jsdoc/publish.js b/cli/lib/tsd-jsdoc/publish.js index d73180393..4c4c39593 100644 --- a/cli/lib/tsd-jsdoc/publish.js +++ b/cli/lib/tsd-jsdoc/publish.js @@ -143,7 +143,7 @@ var keepTags = [ // parses a comment into text and tags function parseComment(comment) { - var lines = comment.replace(/^ *\/\*\* *|^ *\*\/| *\*\/ *$|^ *\* */mg, "").trim().split(/\r?\n/g); + var lines = comment.replace(/^ *\/\*\* *|^ *\*\/| *\*\/ *$|^ *\* */mg, "").trim().split(/\r?\n|\r/g); // property.description has just "\r" ?! var desc; var text = []; var tags = null; @@ -174,7 +174,6 @@ function writeComment(comment, otherwiseNewline) { writeln(); return; } - if (typeof comment !== "object") comment = parseComment(comment); comment.tags = comment.tags.filter(function(tag) { @@ -187,7 +186,10 @@ function writeComment(comment, otherwiseNewline) { } writeln("/**"); comment.text.forEach(function(line) { - writeln(" * ", line); + if (line.length) + writeln(" * ", line); + else + writeln(" *"); }); comment.tags.forEach(function(tag) { var started = false; @@ -393,8 +395,12 @@ function writeInterfaceBody(element) { write("}"); } -function writeProperty(property) { - writeComment(property.comment); +function writeProperty(property, withLet) { + writeComment(property.description); + if (!/^[\w$]+$/.test(property.name)) // incompatible + write("// "); + if (withLet) + write("let "); write(property.name); if (property.optional) write("?"); @@ -454,6 +460,16 @@ function handleNamespace(element/*, parent*/) { if (!children.length) return; var first = true; + if (element.properties) + element.properties.forEach(function(property) { + if (first) { + begin(element); + writeln("namespace ", element.name, " {"); + ++indent; + first = false; + } + writeProperty(property, true); + }); children.forEach(function(child) { if (child.scope === "inner" || seen[child.longname]) return; @@ -521,7 +537,9 @@ function handleClass(element, parent) { // properties if (is_interface && element.properties) - element.properties.forEach(writeProperty); + element.properties.forEach(function(property) { + writeProperty(property); + }); // class-compatible members var incompatible = []; diff --git a/config/tslint.json b/config/tslint.json index 7af59004c..d3d9bb62b 100644 --- a/config/tslint.json +++ b/config/tslint.json @@ -13,6 +13,15 @@ "member-ordering": [ false ], "object-literal-sort-keys": false, "no-string-literal": false, - "prefer-const": false + "prefer-const": false, + "ban-types": [ + true, + ["Object", "Avoid using the `Object` type. Did you mean `object`?"], + // ["Function", "Avoid using the `Function` type. Prefer a specific function type, like `() => void`."], + ["Boolean", "Avoid using the `Boolean` type. Did you mean `boolean`?"], + ["Number", "Avoid using the `Number` type. Did you mean `number`?"], + ["String", "Avoid using the `String` type. Did you mean `string`?"], + ["Symbol", "Avoid using the `Symbol` type. Did you mean `symbol`?"] + ] } } \ No newline at end of file diff --git a/index.d.ts b/index.d.ts index a9f72e2f7..7234fda3b 100644 --- a/index.d.ts +++ b/index.d.ts @@ -10,6 +10,40 @@ export function common(name: string, json: { [k: string]: any }): void; export namespace common { + /** Any */ + // let google/protobuf/any.proto: INamespace; + + /** Duration */ + // let google/protobuf/duration.proto: INamespace; + + /** Empty */ + // let google/protobuf/empty.proto: INamespace; + + /** Struct, Value, NullValue and ListValue */ + // let google/protobuf/struct.proto: INamespace; + + /** Timestamp */ + // let google/protobuf/timestamp.proto: INamespace; + + /** Wrappers */ + // let google/protobuf/wrappers.proto: INamespace; + + /** + * Gets the root definition of the specified common proto file. + * + * Bundled definitions are: + * - google/protobuf/any.proto + * - google/protobuf/duration.proto + * - google/protobuf/empty.proto + * - google/protobuf/struct.proto + * - google/protobuf/timestamp.proto + * - google/protobuf/wrappers.proto + * + * @param file Proto file name + * @returns Root definition or `null` if not defined + */ + function get(file: string): INamespace; + /** Properties of a google.protobuf.Any message. */ interface IAny { typeUrl?: string; @@ -189,7 +223,11 @@ export class Enum extends ReflectionObject { /** Enum descriptor. */ export interface IEnum { + + /** Enum values */ values: { [k: string]: number }; + + /** Enum options */ options?: { [k: string]: any }; } @@ -320,14 +358,24 @@ export class FieldBase extends ReflectionObject { /** Field descriptor. */ export interface IField { + + /** Field rule */ rule?: string; + + /** Field type */ type: string; + + /** Field id */ id: number; + + /** Field options */ options?: { [k: string]: any }; } /** Extension field descriptor. */ export interface IExtensionField extends IField { + + /** Extended type */ extend: string; } @@ -433,11 +481,15 @@ export class MapField extends FieldBase { /** Map field descriptor. */ export interface IMapField extends IField { + + /** Key type */ keyType: string; } /** Extension map field descriptor. */ export interface IExtensionMapField extends IMapField { + + /** Extended type */ extend: string; } @@ -576,11 +628,23 @@ export class Method extends ReflectionObject { /** Method descriptor. */ export interface IMethod { + + /** Method type */ type?: string; + + /** Request type */ requestType: string; + + /** Response type */ responseType: string; + + /** Whether requests are streamed */ requestStream?: boolean; + + /** Whether responses are streamed */ responseStream?: boolean; + + /** Method options */ options?: { [k: string]: any }; } @@ -737,7 +801,11 @@ export abstract class NamespaceBase extends ReflectionObject { /** Namespace descriptor. */ export interface INamespace { + + /** Namespace options */ options?: { [k: string]: any }; + + /** Nested object descriptors */ nested?: { [k: string]: AnyNestedObject }; } @@ -885,7 +953,11 @@ export class OneOf extends ReflectionObject { /** Oneof descriptor. */ export interface IOneOf { + + /** Oneof field names */ oneof: string[]; + + /** Oneof options */ options?: { [k: string]: any }; } @@ -898,15 +970,27 @@ type OneOfDecorator = (prototype: object, oneofName: string) => void; /** Result object returned from {@link parse}. */ export interface IParserResult { + + /** Package name, if declared */ package: (string|undefined); + + /** Imports, if any */ imports: (string[]|undefined); + + /** Weak imports, if any */ weakImports: (string[]|undefined); + + /** Syntax, if specified (either `"proto2"` or `"proto3"`) */ syntax: (string|undefined); + + /** Populated root instance */ root: Root; } /** Options modifying the behavior of {@link parse}. */ export interface IParseOptions { + + /** Keeps field casing instead of converting to camel case */ keepCase?: boolean; } @@ -1147,7 +1231,7 @@ export namespace rpc { /** * A service method callback as used by {@link rpc.ServiceMethod|ServiceMethod}. - * + * * Differs from {@link RPCImplCallback} in that it is an actual callback of a service method which may not return `response = null`. * @param error Error, if any * @param [response] Response message @@ -1260,6 +1344,8 @@ export class Service extends NamespaceBase { /** Service descriptor. */ export interface IService extends INamespace { + + /** Method descriptors */ methods: { [k: string]: IMethod }; } @@ -1305,11 +1391,23 @@ type TokenizerHandleCmnt = (line?: number) => string; /** Handle object returned from {@link tokenize}. */ export interface ITokenizerHandle { + + /** Gets the current line number */ line: TokenizerHandleLine; + + /** Gets the next token and advances (`null` on eof) */ next: TokenizerHandleNext; + + /** Peeks for the next token (`null` on eof) */ peek: TokenizerHandlePeek; + + /** Pushes a token back to the stack */ push: TokenizerHandlePush; + + /** Skips a token, returns its presence and advances or, if non-optional and not present, throws */ skip: TokenizerHandleSkip; + + /** Gets the comment on the previous line or the line comment on the specified line, if any */ cmnt: TokenizerHandleCmnt; } @@ -1320,6 +1418,16 @@ export interface ITokenizerHandle { */ export function tokenize(source: string): ITokenizerHandle; +export namespace tokenize { + + /** + * Unescapes a string. + * @param str String to unescape + * @returns Unescaped string + */ + function unescape(str: string): string; +} + /** Reflected message type. */ export class Type extends NamespaceBase { @@ -1490,22 +1598,60 @@ export class Type extends NamespaceBase { /** Message type descriptor. */ export interface IType extends INamespace { + + /** Oneof descriptors */ oneofs?: { [k: string]: IOneOf }; + + /** Field descriptors */ fields: { [k: string]: IField }; + + /** Extension ranges */ extensions?: number[][]; + + /** Reserved ranges */ reserved?: number[][]; + + /** Whether a legacy group or not */ group?: boolean; } /** Conversion options as used by {@link Type#toObject} and {@link Message.toObject}. */ export interface IConversionOptions { - longs?: any; - enums?: any; - bytes?: any; + + /** + * Long conversion type. + * Valid values are `String` and `Number` (the global types). + * Defaults to copy the present value, which is a possibly unsafe number without and a {@link Long} with a long library. + */ + longs?: Function; + + /** + * Enum value conversion type. + * Only valid value is `String` (the global type). + * Defaults to copy the present value, which is the numeric id. + */ + enums?: Function; + + /** + * Bytes value conversion type. + * Valid values are `Array` and (a base64 encoded) `String` (the global types). + * Defaults to copy the present value, which usually is a Buffer under node and an Uint8Array in the browser. + */ + bytes?: Function; + + /** Also sets default values on the resulting object */ defaults?: boolean; + + /** Sets empty arrays for missing repeated fields even if `defaults=false` */ arrays?: boolean; + + /** Sets empty objects for missing map fields even if `defaults=false` */ objects?: boolean; + + /** Includes virtual oneof properties set to the present field's name, if any */ oneofs?: boolean; + + /** Performs additional JSON compatibility conversions, i.e. NaN and Infinity to strings */ json?: boolean; } @@ -1620,8 +1766,14 @@ export interface Buffer extends Uint8Array { * This is a minimal stand-alone definition of a Long instance. The actual type is that exported by long.js. */ export interface Long { + + /** Low bits */ low: number; + + /** High bits */ high: number; + + /** Whether unsigned or not */ unsigned: boolean; } @@ -1862,9 +2014,9 @@ export namespace util { /** * Default conversion options used for {@link Message#toJSON} implementations. - * + * * These options are close to proto3's JSON mapping with the exception that internal types like Any are handled just like messages. More precisely: - * + * * - Longs become strings * - Enums become string keys * - Bytes become base64 encoded strings @@ -1872,7 +2024,7 @@ export namespace util { * - Maps become plain objects with all string keys * - Repeated fields become arrays * - NaN and Infinity for float and double fields become strings - * + * * @see https://developers.google.com/protocol-buffers/docs/proto3?hl=en#json */ let toJSONOptions: IConversionOptions; @@ -1987,6 +2139,18 @@ export namespace util { */ function codegen(...params: string[]): Codegen; + namespace codegen { + + /** Whether code generation is supported by the environment. */ + let supported: boolean; + + /** When set to true, codegen will log generated code to console. Useful for debugging. */ + let verbose: boolean; + + /** Underlying sprintf implementation */ + let sprintf: Function; + } + /** A minimal event emitter. */ class EventEmitter { @@ -2210,7 +2374,11 @@ type WrapperToObjectConverter = (this: Type, message: Message<{}>, options?: ICo /** Common type wrapper part of {@link wrappers}. */ export interface IWrapper { + + /** From object converter */ fromObject?: WrapperFromObjectConverter; + + /** To object converter */ toObject?: WrapperToObjectConverter; } @@ -2431,7 +2599,11 @@ type FetchCallback = (error: Error, contents?: string) => void; /** Options as used by {@link util.fetch}. */ export interface IFetchOptions { + + /** Whether expecting a binary response */ binary?: boolean; + + /** If `true`, forces the use of XMLHttpRequest */ xhr?: boolean; } diff --git a/src/common.js b/src/common.js index 6902c837e..a6f0005dc 100644 --- a/src/common.js +++ b/src/common.js @@ -7,12 +7,12 @@ module.exports = common; * @param {string} name Short name as in `google/protobuf/[name].proto` or full file name * @param {Object.} json JSON definition within `google.protobuf` if a short name, otherwise the file's root definition * @returns {undefined} - * @property {Object.} google/protobuf/any.proto Any - * @property {Object.} google/protobuf/duration.proto Duration - * @property {Object.} google/protobuf/empty.proto Empty - * @property {Object.} google/protobuf/struct.proto Struct, Value, NullValue and ListValue - * @property {Object.} google/protobuf/timestamp.proto Timestamp - * @property {Object.} google/protobuf/wrappers.proto Wrappers + * @property {INamespace} google/protobuf/any.proto Any + * @property {INamespace} google/protobuf/duration.proto Duration + * @property {INamespace} google/protobuf/empty.proto Empty + * @property {INamespace} google/protobuf/struct.proto Struct, Value, NullValue and ListValue + * @property {INamespace} google/protobuf/timestamp.proto Timestamp + * @property {INamespace} google/protobuf/wrappers.proto Wrappers * @example * // manually provides descriptor.proto (assumes google/protobuf/ namespace and .proto extension) * protobuf.common("descriptor", descriptorJson); @@ -28,6 +28,26 @@ function common(name, json) { common[name] = json; } +/** + * Gets the root definition of the specified common proto file. + * + * Bundled definitions are: + * - google/protobuf/any.proto + * - google/protobuf/duration.proto + * - google/protobuf/empty.proto + * - google/protobuf/struct.proto + * - google/protobuf/timestamp.proto + * - google/protobuf/wrappers.proto + * + * @name common.get + * @function + * @param {string} file Proto file name + * @returns {?INamespace} Root definition or `null` if not defined + */ +common.get = function get(file) { + return common[file] || null; +}; + var commonRe = /\/|\./; // Not provided because of limited use (feel free to discuss or to provide yourself): diff --git a/src/tokenize.js b/src/tokenize.js index dae4db087..1b9c9e182 100644 --- a/src/tokenize.js +++ b/src/tokenize.js @@ -22,7 +22,7 @@ var unescapeMap = { * @param {string} str String to unescape * @returns {string} Unescaped string * @property {Object.} map Special characters map - * @ignore + * @memberof tokenize */ function unescape(str) { return str.replace(unescapeRe, function($0, $1) { @@ -100,7 +100,6 @@ tokenize.unescape = unescape; * Tokenizes the given .proto source and returns an object with useful utility functions. * @param {string} source Source contents * @returns {ITokenizerHandle} Tokenizer handle - * @property {function(string):string} unescape Unescapes a string */ function tokenize(source) { /* eslint-disable callback-return */ diff --git a/src/type.js b/src/type.js index 12ba8e78f..170f3e487 100644 --- a/src/type.js +++ b/src/type.js @@ -544,13 +544,13 @@ Type.prototype.fromObject = function fromObject(object) { /** * Conversion options as used by {@link Type#toObject} and {@link Message.toObject}. * @interface IConversionOptions - * @property {*} [longs] Long conversion type. + * @property {Function} [longs] Long conversion type. * Valid values are `String` and `Number` (the global types). * Defaults to copy the present value, which is a possibly unsafe number without and a {@link Long} with a long library. - * @property {*} [enums] Enum value conversion type. + * @property {Function} [enums] Enum value conversion type. * Only valid value is `String` (the global type). * Defaults to copy the present value, which is the numeric id. - * @property {*} [bytes] Bytes value conversion type. + * @property {Function} [bytes] Bytes value conversion type. * Valid values are `Array` and (a base64 encoded) `String` (the global types). * Defaults to copy the present value, which usually is a Buffer under node and an Uint8Array in the browser. * @property {boolean} [defaults=false] Also sets default values on the resulting object