diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c00cbd0..f646c77 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,3 +21,11 @@ If any entity institutes patent litigation - including cross-claim or countercla **3. Source of Contribution.** Your contribution is either your original creation, based upon previous work that, to the best of your knowledge, is covered under an appropriate open source license and you have the right under that license to submit that work with modifications, whether created in whole or in part by you, or you have clearly identified the source of the contribution and any license or other restriction (like related patents, trademarks, and license agreements) of which you are personally aware. + +## Releasing a new version + +1. Update [HISTORY.md](./HISTORY.md) with the changes since the last release. +2. Run `yarn version` to pick the new version. +3. Create a new pull request with these changes. +4. After the pull request has been merged to `main` run `yarn publish`. Pick the same version as above. +5. Create a [Github release](https://github.com/cruise-automation/rosbag.js/releases/new) for the version. diff --git a/HISTORY.md b/HISTORY.md index f2b9acc..4416384 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,12 @@ +# 4.0.1 + +* Add explicit exports so that types match code. +* Export `OpenBag` type. + +# 4.0.0 + +* Convert to Typescript + # 2.5.0 * Added MessageWriter functionality, and deprecated passing the unparsed message definitions direction to MessageReader. diff --git a/package.json b/package.json index 448e51e..2dd2baa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rosbag", - "version": "4.0.0", + "version": "4.0.1", "license": "Apache-2.0", "repository": "cruise-automation/rosbag.js", "dependencies": { diff --git a/src/bag.ts b/src/bag.ts index 9f38c3e..82779e2 100644 --- a/src/bag.ts +++ b/src/bag.ts @@ -22,6 +22,16 @@ export type ReadOptions = { freeze?: boolean; }; +/** + * Represents a bag that has been opened, which guarantees certain properties are available. + */ +// eslint-disable-next-line no-use-before-define +export interface OpenBag extends Bag { + header: BagHeader; + connections: Record; + chunkInfos: ChunkInfo[]; +} + /** * The high level rosbag interface. * @@ -46,7 +56,7 @@ export default class Bag { this.reader = bagReader; } - static open = (_file: File | string): Promise => + static open = (_file: File | string): Promise => Promise.reject( new Error( "This method should have been overridden based on the environment. Make sure you are correctly importing the node or web version of Bag." @@ -62,9 +72,11 @@ export default class Bag { /** * If the bag is manually created with the constructor, you must call `await open()` on the bag. - * Generally this is called for you if you're using `const bag = await Bag.open()` + * Generally this is called for you if you're using `const bag = await Bag.open()`. + * + * Returns `this` with the type of `OpenBag`. */ - async open() { + async open(): Promise { this.header = await this.reader.readHeaderAsync(); const { connectionCount, chunkCount, indexPosition } = this.header; @@ -89,6 +101,8 @@ export default class Bag { .map((x) => x.endTime) .reduce((prev, current) => (TimeUtil.compare(prev, current) > 0 ? prev : current)); } + + return this as OpenBag; } async readMessages(opts: ReadOptions, callback: (msg: ReadResult) => void) { @@ -149,9 +163,3 @@ export default class Bag { } } } - -interface OpenBag extends Bag { - header: BagHeader; - connections: Record; - chunkInfos: ChunkInfo[]; -} diff --git a/src/index.test.ts b/src/index.test.ts new file mode 100644 index 0000000..9a188b2 --- /dev/null +++ b/src/index.test.ts @@ -0,0 +1,21 @@ +import * as TypeExports from "."; +import * as NodeExports from "./node"; +import * as WebExports from "./web"; + +describe("exports", () => { + it("matches web and node exports", () => { + // Remove exports that are implemented differently between Node and Web. + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { open: _typeOpen, ...TypeSharedExports } = TypeExports; + const { open: nodeOpen, Reader: NodeReader, ...NodeSharedExports } = NodeExports; + const { open: webOpen, Reader: WebReader, ...WebSharedExports } = WebExports; + + expect(nodeOpen).toEqual(expect.any(Function)); + expect(NodeReader).toEqual(expect.any(Function)); + expect(webOpen).toEqual(expect.any(Function)); + expect(WebReader).toEqual(expect.any(Function)); + + expect(NodeSharedExports).toEqual(TypeSharedExports); + expect(WebSharedExports).toEqual(TypeSharedExports); + }); +}); diff --git a/src/index.ts b/src/index.ts index c745b8e..4c8cb26 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,13 +4,35 @@ // found in the LICENSE file in the root directory of this source tree. // You may not use this file except in compliance with the License. +import BagReader from "./BagReader"; +import { MessageReader } from "./MessageReader"; +import { MessageWriter } from "./MessageWriter"; import * as TimeUtil from "./TimeUtil"; +import Bag, { OpenBag } from "./bag"; +import { extractFields, extractTime } from "./fields"; +import { parseMessageDefinition, rosPrimitiveTypes } from "./parseMessageDefinition"; +import { Filelike } from "./types"; -export * from "./bag"; -export * from "./BagReader"; -export * from "./MessageReader"; -export * from "./MessageWriter"; -export * from "./parseMessageDefinition"; +const { open } = Bag; + +export declare class Reader implements Filelike { + read(): void; + size(): number; +} + +// These exports must match node/index.ts and web/index.ts export * from "./types"; -export * from "./fields"; -export { TimeUtil }; +export { + TimeUtil, + Bag, + OpenBag, + BagReader, + MessageReader, + MessageWriter, + open, + parseMessageDefinition, + rosPrimitiveTypes, + extractFields, + extractTime, +}; +export default Bag; diff --git a/src/node/index.ts b/src/node/index.ts index 6266789..82b2b40 100644 --- a/src/node/index.ts +++ b/src/node/index.ts @@ -16,7 +16,7 @@ import { extractTime, } from "../index"; import type { Callback } from "../types"; -import Bag from "../bag"; +import Bag, { OpenBag } from "../bag"; import BagReader from "../BagReader"; // reader using nodejs fs api @@ -78,7 +78,7 @@ export class Reader { } } -const open = async (filename: File | string) => { +const open = async (filename: File | string): Promise => { if (typeof filename !== "string") { throw new Error( "Expected filename to be a string. Make sure you are correctly importing the node or web version of Bag." @@ -87,14 +87,16 @@ const open = async (filename: File | string) => { const bag = new Bag(new BagReader(new Reader(filename))); await bag.open(); - return bag; + return bag as OpenBag; }; Bag.open = open; +// These exports must match ../index.ts export * from "../types"; export { TimeUtil, + Bag, BagReader, MessageReader, MessageWriter, diff --git a/src/web/index.ts b/src/web/index.ts index f3171be..05579d6 100644 --- a/src/web/index.ts +++ b/src/web/index.ts @@ -15,7 +15,7 @@ import { extractTime, } from "../index"; import type { Callback } from "../types"; -import Bag from "../bag"; +import Bag, { OpenBag } from "../bag"; import BagReader from "../BagReader"; // browser reader for Blob|File objects @@ -54,7 +54,7 @@ export class Reader { } } -const open = async (file: File | string) => { +const open = async (file: File | string): Promise => { if (!(file instanceof Blob)) { throw new Error( "Expected file to be a File or Blob. Make sure you are correctly importing the node or web version of Bag." @@ -63,14 +63,16 @@ const open = async (file: File | string) => { const bag = new Bag(new BagReader(new Reader(file))); await bag.open(); - return bag; + return bag as OpenBag; }; Bag.open = open; +// These exports must match ../index.ts export * from "../types"; export { TimeUtil, + Bag, BagReader, MessageReader, MessageWriter,