diff --git a/README.md b/README.md index 96522640..4f507386 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ will install lerna locally and bootstrap all packages. ### Scripts -* `npm run build`: build `@yume-chan/event`, `@yume-chan/adb` and `@yume-chan/adb-backend-web` packages. -* `npm run build:watch`: build and watch changes for `@yume-chan/event`, `@yume-chan/adb` and `@yume-chan/adb-backend-web` packages. +* `npm run build`: build all npm packages. +* `npm run build:watch`: build and watch changes for all npm packages. * `npm run start:demo`: start webpack-dev-server for the `demo` package. * `npm run build:demo`: build the `demo` package. diff --git a/packages/adb/src/commands/framebuffer.ts b/packages/adb/src/commands/framebuffer.ts index 6f738ad4..6cfe8652 100644 --- a/packages/adb/src/commands/framebuffer.ts +++ b/packages/adb/src/commands/framebuffer.ts @@ -1,4 +1,4 @@ -import { Struct, StructValueType } from "@yume-chan/struct"; +import Struct from "@yume-chan/struct"; import { Adb } from '../adb'; import { AdbBufferedStream } from '../stream'; @@ -35,7 +35,7 @@ export const AdbFrameBufferV1 = .uint32('alpha_length') .uint8ClampedArray('data', { lengthField: 'size' }); -export type AdbFrameBufferV1 = StructValueType; +export type AdbFrameBufferV1 = typeof AdbFrameBufferV1['deserializedType']; export const AdbFrameBufferV2 = new Struct({ littleEndian: true }) @@ -54,7 +54,7 @@ export const AdbFrameBufferV2 = .uint32('alpha_length') .uint8ClampedArray('data', { lengthField: 'size' }); -export type AdbFrameBufferV2 = StructValueType; +export type AdbFrameBufferV2 = typeof AdbFrameBufferV2['deserializedType']; export async function framebuffer(adb: Adb) { const socket = await adb.createSocket('framebuffer:'); diff --git a/packages/adb/src/commands/reverse.ts b/packages/adb/src/commands/reverse.ts index 15a0f7a1..968743c3 100644 --- a/packages/adb/src/commands/reverse.ts +++ b/packages/adb/src/commands/reverse.ts @@ -1,5 +1,5 @@ import { AutoDisposable } from '@yume-chan/event'; -import { Struct } from '@yume-chan/struct'; +import Struct from '@yume-chan/struct'; import { AdbPacket } from '../packet'; import { AdbIncomingSocketEventArgs, AdbPacketDispatcher, AdbSocket } from '../socket'; import { AdbBufferedStream } from '../stream'; diff --git a/packages/adb/src/commands/sync/list.ts b/packages/adb/src/commands/sync/list.ts index cfa555da..499488c8 100644 --- a/packages/adb/src/commands/sync/list.ts +++ b/packages/adb/src/commands/sync/list.ts @@ -1,4 +1,4 @@ -import { Struct, StructValueType } from '@yume-chan/struct'; +import Struct from '@yume-chan/struct'; import { AdbBufferedStream } from '../../stream'; import { AdbSyncRequestId, adbSyncWriteRequest } from './request'; import { AdbSyncDoneResponse, adbSyncReadResponse, AdbSyncResponseId } from './response'; @@ -11,7 +11,7 @@ export const AdbSyncEntryResponse = .string('name', { lengthField: 'nameLength' }) .extra({ id: AdbSyncResponseId.Entry as const }); -export type AdbSyncEntryResponse = StructValueType; +export type AdbSyncEntryResponse = typeof AdbSyncEntryResponse['deserializedType']; const ResponseTypes = { [AdbSyncResponseId.Entry]: AdbSyncEntryResponse, diff --git a/packages/adb/src/commands/sync/pull.ts b/packages/adb/src/commands/sync/pull.ts index d3f3bb78..51aa19b5 100644 --- a/packages/adb/src/commands/sync/pull.ts +++ b/packages/adb/src/commands/sync/pull.ts @@ -1,4 +1,4 @@ -import { Struct } from '@yume-chan/struct'; +import Struct from '@yume-chan/struct'; import { AdbBufferedStream } from '../../stream'; import { AdbSyncRequestId, adbSyncWriteRequest } from './request'; import { AdbSyncDoneResponse, adbSyncReadResponse, AdbSyncResponseId } from './response'; diff --git a/packages/adb/src/commands/sync/push.ts b/packages/adb/src/commands/sync/push.ts index a3a3dcca..c4dee2ec 100644 --- a/packages/adb/src/commands/sync/push.ts +++ b/packages/adb/src/commands/sync/push.ts @@ -1,4 +1,4 @@ -import { Struct } from '@yume-chan/struct'; +import Struct from '@yume-chan/struct'; import { AdbBufferedStream } from '../../stream'; import { chunkArrayLike, chunkAsyncIterable } from '../../utils'; import { AdbSyncRequestId, adbSyncWriteRequest } from './request'; diff --git a/packages/adb/src/commands/sync/request.ts b/packages/adb/src/commands/sync/request.ts index 8cead237..6c8025ab 100644 --- a/packages/adb/src/commands/sync/request.ts +++ b/packages/adb/src/commands/sync/request.ts @@ -1,4 +1,4 @@ -import { Struct } from '@yume-chan/struct'; +import Struct from '@yume-chan/struct'; import { AdbBufferedStream } from '../../stream'; export enum AdbSyncRequestId { diff --git a/packages/adb/src/commands/sync/response.ts b/packages/adb/src/commands/sync/response.ts index 99f60514..27d2492d 100644 --- a/packages/adb/src/commands/sync/response.ts +++ b/packages/adb/src/commands/sync/response.ts @@ -1,4 +1,4 @@ -import { Struct, StructDeserializationContext, StructValueType } from '@yume-chan/struct'; +import Struct, { StructDeserializationContext, StructLike, StructValueType } from '@yume-chan/struct'; import { AdbBufferedStream } from '../../stream'; export enum AdbSyncResponseId { @@ -16,7 +16,7 @@ export enum AdbSyncResponseId { // For example DONE responses for LIST requests are 16 bytes (same as DENT responses), // but DONE responses for STAT requests are 12 bytes (same as STAT responses) // So we need to know responses' size in advance. -export class AdbSyncDoneResponse { +export class AdbSyncDoneResponse implements StructLike { private length: number; public readonly id = AdbSyncResponseId.Done; @@ -39,7 +39,7 @@ export const AdbSyncFailResponse = throw new Error(object.message); }); -export async function adbSyncReadResponse; }>>( +export async function adbSyncReadResponse>>( stream: AdbBufferedStream, types: T, ): Promise> { diff --git a/packages/adb/src/commands/sync/stat.ts b/packages/adb/src/commands/sync/stat.ts index f2a584e4..3833060e 100644 --- a/packages/adb/src/commands/sync/stat.ts +++ b/packages/adb/src/commands/sync/stat.ts @@ -1,4 +1,4 @@ -import { placeholder, Struct, StructValueType } from '@yume-chan/struct'; +import Struct, { placeholder } from '@yume-chan/struct'; import { AdbBufferedStream } from '../../stream'; import { AdbSyncRequestId, adbSyncWriteRequest } from './request'; import { adbSyncReadResponse, AdbSyncResponseId } from './response'; @@ -29,7 +29,7 @@ export const AdbSyncLstatResponse = } }); -export type AdbSyncLstatResponse = StructValueType; +export type AdbSyncLstatResponse = typeof AdbSyncLstatResponse['deserializedType']; export enum AdbSyncStatErrorCode { EACCES = 13, @@ -78,7 +78,7 @@ export const AdbSyncStatResponse = } }); -export type AdbSyncStatResponse = StructValueType; +export type AdbSyncStatResponse = typeof AdbSyncStatResponse['deserializedType']; const StatResponseType = { [AdbSyncResponseId.Stat]: AdbSyncStatResponse, diff --git a/packages/adb/src/packet.ts b/packages/adb/src/packet.ts index 9fd82800..9f901419 100644 --- a/packages/adb/src/packet.ts +++ b/packages/adb/src/packet.ts @@ -1,4 +1,4 @@ -import { Struct, StructInitType, StructValueType } from '@yume-chan/struct'; +import Struct from '@yume-chan/struct'; import { AdbBackend } from './backend'; import { BufferedStream } from './stream'; @@ -25,9 +25,9 @@ const AdbPacketStruct = .fields(AdbPacketHeader) .arrayBuffer('payload', { lengthField: 'payloadLength' }); -export type AdbPacket = StructValueType; +export type AdbPacket = typeof AdbPacketStruct['deserializedType']; -export type AdbPacketInit = Omit, 'checksum' | 'magic'>; +export type AdbPacketInit = Omit; export namespace AdbPacket { export function create( diff --git a/packages/demo/package-lock.json b/packages/demo/package-lock.json index 96c380d5..c4249a89 100644 --- a/packages/demo/package-lock.json +++ b/packages/demo/package-lock.json @@ -769,7 +769,17 @@ "@yume-chan/async-operation-manager": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/@yume-chan/async-operation-manager/-/async-operation-manager-2.1.3.tgz", - "integrity": "sha512-YUGrCXEADvaM1tJgQ0ek/a5eSg0ovdpL5ZhfXS6ZRnV3Xn0q5y/j/xzl+yBFFQ+nWclWh8of5f8Qm8y/y0YdQQ==" + "integrity": "sha512-YUGrCXEADvaM1tJgQ0ek/a5eSg0ovdpL5ZhfXS6ZRnV3Xn0q5y/j/xzl+yBFFQ+nWclWh8of5f8Qm8y/y0YdQQ==", + "requires": { + "tslib": "2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", + "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + } + } }, "abab": { "version": "2.0.5", diff --git a/packages/demo/src/routes/scrcpy/server/client.ts b/packages/demo/src/routes/scrcpy/server/client.ts index efca7555..f2735bd9 100644 --- a/packages/demo/src/routes/scrcpy/server/client.ts +++ b/packages/demo/src/routes/scrcpy/server/client.ts @@ -1,7 +1,7 @@ import { Adb, AdbBufferedStream, AdbSocket, DataEventEmitter, EventQueue } from '@yume-chan/adb'; import { PromiseResolver } from '@yume-chan/async-operation-manager'; import { DisposableList, EventEmitter } from '@yume-chan/event'; -import { Struct, StructValueType } from '@yume-chan/struct'; +import Struct from '@yume-chan/struct'; import { AndroidCodecLevel, AndroidCodecProfile } from './codec'; import { AndroidKeyEventAction, AndroidMotionEventAction, ScrcpyControlMessageType, ScrcpyInjectKeyCodeControlMessage, ScrcpyInjectTextControlMessage, ScrcpyInjectTouchControlMessage, ScrcpySimpleControlMessage } from './message'; import { parse_sequence_parameter_set } from './sps'; @@ -159,7 +159,7 @@ const VideoPacket = export const NoPts = BigInt(-1); -export type VideoPacket = StructValueType; +export type VideoPacket = typeof VideoPacket['deserializedType']; const ClipboardMessage = new Struct() diff --git a/packages/demo/src/routes/scrcpy/server/message.ts b/packages/demo/src/routes/scrcpy/server/message.ts index 41d705ce..04b34ada 100644 --- a/packages/demo/src/routes/scrcpy/server/message.ts +++ b/packages/demo/src/routes/scrcpy/server/message.ts @@ -1,4 +1,4 @@ -import { placeholder, Struct, StructInitType } from '@yume-chan/struct'; +import Struct, { placeholder } from '@yume-chan/struct'; export enum ScrcpyControlMessageType { InjectKeycode, @@ -18,7 +18,7 @@ export const ScrcpySimpleControlMessage = new Struct() .uint8('type', placeholder()); -export type ScrcpySimpleControlMessage = StructInitType; +export type ScrcpySimpleControlMessage = typeof ScrcpySimpleControlMessage['initType']; export enum AndroidMotionEventAction { Down, @@ -48,7 +48,7 @@ export const ScrcpyInjectTouchControlMessage = .uint16('pressure') .uint32('buttons'); -export type ScrcpyInjectTouchControlMessage = StructInitType; +export type ScrcpyInjectTouchControlMessage = typeof ScrcpyInjectTouchControlMessage['initType']; export const ScrcpyInjectTextControlMessage = new Struct() @@ -57,7 +57,7 @@ export const ScrcpyInjectTextControlMessage = .string('text', { lengthField: 'length' }); export type ScrcpyInjectTextControlMessage = - StructInitType; + typeof ScrcpyInjectTextControlMessage['initType']; export enum AndroidKeyEventAction { Down = 0, @@ -106,7 +106,7 @@ export const ScrcpyInjectKeyCodeControlMessage = .uint32('metaState'); export type ScrcpyInjectKeyCodeControlMessage = - StructInitType; + typeof ScrcpyInjectKeyCodeControlMessage['initType']; export type ScrcpyControlMessage = ScrcpySimpleControlMessage | diff --git a/packages/event/.npmignore b/packages/event/.npmignore new file mode 100644 index 00000000..cb82bc53 --- /dev/null +++ b/packages/event/.npmignore @@ -0,0 +1,10 @@ +.github +.vscode +coverage +src/**.spec.ts + +jest.config.js +pnpm-lock.yaml +renovate.json +tsconfig.json +*.tsbuildinfo diff --git a/packages/event/LICENSE b/packages/event/LICENSE deleted file mode 100644 index acc76b98..00000000 --- a/packages/event/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2020 Simon Chan - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/packages/event/jest.config.js b/packages/event/jest.config.js new file mode 100644 index 00000000..4a5b465e --- /dev/null +++ b/packages/event/jest.config.js @@ -0,0 +1,4 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', +}; diff --git a/packages/event/package.json b/packages/event/package.json index e80311ee..05fce4d3 100644 --- a/packages/event/package.json +++ b/packages/event/package.json @@ -1,10 +1,11 @@ { "name": "@yume-chan/event", - "private": true, "version": "0.0.4", "description": "Event/EventEmitter", "keywords": [ - "event" + "event", + "eventemitter", + "typescript" ], "license": "MIT", "author": { @@ -27,6 +28,7 @@ "scripts": { "build": "rimraf {cjs,esm,dts,*.tsbuildinfo} && tsc -b tsconfig.esm.json tsconfig.cjs.json", "build:watch": "tsc -b -w tsconfig.esm.json tsconfig.cjs.json", + "test": "jest", "coverage": "jest --coverage", "prepublishOnly": "npm run build" }, diff --git a/packages/event/src/disposable.spec.ts b/packages/event/src/disposable.spec.ts new file mode 100644 index 00000000..45e9a405 --- /dev/null +++ b/packages/event/src/disposable.spec.ts @@ -0,0 +1,21 @@ +import { AutoDisposable, Disposable } from './disposable'; + +describe('Event', () => { + describe('AutoDisposable', () => { + it('should dispose its dependencies', () => { + const myDisposable = { + dispose: jest.fn(), + }; + class MyAutoDisposable extends AutoDisposable { + constructor(disposable: Disposable) { + super(); + this.addDisposable(disposable); + } + } + + const myAutoDisposable = new MyAutoDisposable(myDisposable); + myAutoDisposable.dispose(); + expect(myDisposable.dispose).toBeCalledTimes(1); + }); + }); +}); diff --git a/packages/struct/README.md b/packages/struct/README.md index 65525a2f..e11ab03f 100644 --- a/packages/struct/README.md +++ b/packages/struct/README.md @@ -581,7 +581,7 @@ All above built-in methods are alias of `field`. To add a field of a custom type ### `FieldDefinition` ```ts -abstract class FieldDefinition { +abstract class FieldDefinition { readonly options: TOptions; constructor(options: TOptions); diff --git a/packages/struct/package.json b/packages/struct/package.json index 83eff401..51a0f85c 100644 --- a/packages/struct/package.json +++ b/packages/struct/package.json @@ -4,6 +4,8 @@ "description": "C-style structure serializer and deserializer.", "keywords": [ "structure", + "serialization", + "deserialization", "typescript" ], "license": "MIT", diff --git a/packages/struct/src/basic/definition.ts b/packages/struct/src/basic/definition.ts index df9d30de..b50318cf 100644 --- a/packages/struct/src/basic/definition.ts +++ b/packages/struct/src/basic/definition.ts @@ -16,12 +16,12 @@ type ValueOrPromise = T | Promise; * * @template TOptions TypeScript type of this definition's `options`. * @template TValueType TypeScript type of this field. - * @template TRemoveInitFields Optional remove some field from the `TInit` type. Should be a union of string literal types. + * @template TOmitInit Optionally remove some fields from the init type. Should be a union of string literal types. */ export abstract class FieldDefinition< TOptions = void, TValueType = unknown, - TRemoveInitFields = never, + TOmitInit = never, > { public readonly options: TOptions; @@ -33,9 +33,9 @@ export abstract class FieldDefinition< /** * When `T` is a type initiated `FieldDefinition`, - * use `T['removeInitFields']` to retrieve its `TRemoveInitFields` type parameter. + * use `T['omitInitType']` to retrieve its `TOmitInit` type parameter. */ - public readonly removeInitFields!: TRemoveInitFields; + public readonly omitInitType!: TOmitInit; public constructor(options: TOptions) { this.options = options; @@ -55,7 +55,7 @@ export abstract class FieldDefinition< options: Readonly, context: StructDeserializationContext, object: any, - ): ValueOrPromise>>; + ): ValueOrPromise>>; /** * When implemented in derived classes, creates a `FieldRuntimeValue` from a given `value`. @@ -65,5 +65,5 @@ export abstract class FieldDefinition< context: StructSerializationContext, object: any, value: TValueType, - ): FieldRuntimeValue>; + ): FieldRuntimeValue>; } diff --git a/packages/struct/src/index.spec.ts b/packages/struct/src/index.spec.ts new file mode 100644 index 00000000..4f263d9d --- /dev/null +++ b/packages/struct/src/index.spec.ts @@ -0,0 +1,9 @@ +import Struct from './index'; + +describe('Struct', () => { + describe("Index", () => { + it('should export default Struct', () => { + expect(Struct).toBeDefined(); + }); + }); +}); diff --git a/packages/struct/src/index.ts b/packages/struct/src/index.ts index 84edfb58..c79576dc 100644 --- a/packages/struct/src/index.ts +++ b/packages/struct/src/index.ts @@ -1,4 +1,4 @@ export * from './basic'; export * from './struct'; -export { default as Struct } from './struct'; +export { Struct as default } from './struct'; export * from './types'; diff --git a/packages/struct/src/struct.ts b/packages/struct/src/struct.ts index aad7b602..de398741 100644 --- a/packages/struct/src/struct.ts +++ b/packages/struct/src/struct.ts @@ -1,26 +1,26 @@ import { createRuntimeObject, FieldDefinition, FieldRuntimeValue, getRuntimeValue, setRuntimeValue, StructDefaultOptions, StructDeserializationContext, StructOptions, StructSerializationContext } from './basic'; import { ArrayBufferFieldType, ArrayBufferLikeFieldType, Evaluate, FixedLengthArrayBufferLikeFieldDefinition, FixedLengthArrayBufferLikeFieldOptions, Identity, KeysOfType, NumberFieldDefinition, NumberFieldType, Overwrite, StringFieldType, Uint8ClampedArrayFieldType, VariableLengthArrayBufferLikeFieldDefinition, VariableLengthArrayBufferLikeFieldOptions } from './types'; +export interface StructLike { + deserialize(context: StructDeserializationContext): Promise; +} + +export type Awaited = T extends Promise ? Awaited : T; + /** * Extract the value type of the specified `Struct` * * The lack of generic constraint is on purpose to allow `StructLike` types */ -export type StructValueType = - T extends { deserialize(context: StructDeserializationContext): Promise; } ? R : never; - -/** - * Extract the init type of the specified `Struct` - */ -export type StructInitType> = - T extends { create(value: infer R, ...args: any): any; } ? Evaluate : never; +export type StructValueType> = + Awaited>; /** * Create a new `Struct` type with `TDescriptor` appended */ type AddFieldDescriptor< - TValue extends object, - TInit extends object, + TFields extends object, + TOmitInit extends string, TExtra extends object, TPostDeserialized, TFieldName extends PropertyKey, @@ -28,10 +28,9 @@ type AddFieldDescriptor< Identity>, - // There is no `Evaluate` here, because otherwise the type of a `Struct` with many fields - // can become too complex for TypeScript to compute - Evaluate & Record>, + Evaluate>, + // Merge two `TOmitInit + TOmitInit | TDefinition['omitInitType'], TExtra, TPostDeserialized >>; @@ -40,8 +39,8 @@ type AddFieldDescriptor< * Overload methods to add an array buffer like field */ interface ArrayBufferLikeFieldCreator< - TValue extends object, - TInit extends object, + TFields extends object, + TOmitInit extends string, TExtra extends object, TPostDeserialized > { @@ -64,8 +63,8 @@ interface ArrayBufferLikeFieldCreator< options: FixedLengthArrayBufferLikeFieldOptions, typescriptType?: TTypeScriptType, ): AddFieldDescriptor< - TValue, - TInit, + TFields, + TOmitInit, TExtra, TPostDeserialized, TName, @@ -81,7 +80,7 @@ interface ArrayBufferLikeFieldCreator< < TName extends PropertyKey, TType extends ArrayBufferLikeFieldType, - TOptions extends VariableLengthArrayBufferLikeFieldOptions, + TOptions extends VariableLengthArrayBufferLikeFieldOptions, TTypeScriptType = TType['valueType'], >( name: TName, @@ -89,8 +88,8 @@ interface ArrayBufferLikeFieldCreator< options: TOptions, typescriptType?: TTypeScriptType, ): AddFieldDescriptor< - TValue, - TInit, + TFields, + TOmitInit, TExtra, TPostDeserialized, TName, @@ -105,8 +104,8 @@ interface ArrayBufferLikeFieldCreator< * Similar to `ArrayBufferLikeFieldCreator`, but bind to a `ArrayBufferLikeFieldType` */ interface ArrayBufferTypeFieldDefinitionCreator< - TValue extends object, - TInit extends object, + TFields extends object, + TOmitInit extends string, TExtra extends object, TPostDeserialized, TType extends ArrayBufferLikeFieldType @@ -119,8 +118,8 @@ interface ArrayBufferTypeFieldDefinitionCreator< options: FixedLengthArrayBufferLikeFieldOptions, typescriptType?: TTypeScriptType, ): AddFieldDescriptor< - TValue, - TInit, + TFields, + TOmitInit, TExtra, TPostDeserialized, TName, @@ -132,16 +131,16 @@ interface ArrayBufferTypeFieldDefinitionCreator< < TName extends PropertyKey, - TLengthField extends KeysOfType, - TOptions extends VariableLengthArrayBufferLikeFieldOptions, + TLengthField extends KeysOfType, + TOptions extends VariableLengthArrayBufferLikeFieldOptions, TTypeScriptType = TType['valueType'], >( name: TName, options: TOptions, typescriptType?: TTypeScriptType, ): AddFieldDescriptor< - TValue, - TInit, + TFields, + TOmitInit, TExtra, TPostDeserialized, TName, @@ -155,18 +154,25 @@ interface ArrayBufferTypeFieldDefinitionCreator< export type StructPostDeserialized = (this: TValue, object: TValue) => TPostDeserialized; -export default class Struct< - TValue extends object = {}, - TInit extends object = {}, +export type StructDeserializedType = + TPostDeserialized extends undefined ? Overwrite : TPostDeserialized; + +export class Struct< + TFields extends object = {}, + TOmitInit extends string = never, TExtra extends object = {}, TPostDeserialized = undefined, - > { - public readonly valueType!: TValue; + > implements StructLike>{ + public readonly fieldsType!: TFields; - public readonly initType!: TInit; + public readonly omitInitType!: TOmitInit; public readonly extraType!: TExtra; + public readonly initType!: Evaluate>; + + public readonly deserializedType!: StructDeserializedType; + public readonly options: Readonly; private _size = 0; @@ -179,7 +185,7 @@ export default class Struct< private _extra: PropertyDescriptorMap = {}; - private _postDeserialized?: StructPostDeserialized; + private _postDeserialized?: StructPostDeserialized; public constructor(options?: Partial) { this.options = { ...StructDefaultOptions, ...options }; @@ -195,8 +201,8 @@ export default class Struct< name: TName, definition: TDefinition, ): AddFieldDescriptor< - TValue, - TInit, + TFields, + TOmitInit, TExtra, TPostDeserialized, TName, @@ -217,8 +223,8 @@ export default class Struct< public fields>( other: TOther ): Struct< - TValue & TOther['valueType'], - TInit & TOther['initType'], + TFields & TOther['fieldsType'], + TOmitInit | TOther['omitInitType'], TExtra & TOther['extraType'], TPostDeserialized > { @@ -385,27 +391,32 @@ export default class Struct< ); } - private arrayBufferLike: ArrayBufferLikeFieldCreator = ( + private arrayBufferLike: ArrayBufferLikeFieldCreator< + TFields, + TOmitInit, + TExtra, + TPostDeserialized + > = ( name: PropertyKey, type: ArrayBufferLikeFieldType, options: FixedLengthArrayBufferLikeFieldOptions | VariableLengthArrayBufferLikeFieldOptions ): any => { - if ('length' in options) { - return this.field( - name, - new FixedLengthArrayBufferLikeFieldDefinition(type, options), - ); - } else { - return this.field( - name, - new VariableLengthArrayBufferLikeFieldDefinition(type, options), - ); - } - }; + if ('length' in options) { + return this.field( + name, + new FixedLengthArrayBufferLikeFieldDefinition(type, options), + ); + } else { + return this.field( + name, + new VariableLengthArrayBufferLikeFieldDefinition(type, options), + ); + } + }; public arrayBuffer: ArrayBufferTypeFieldDefinitionCreator< - TValue, - TInit, + TFields, + TOmitInit, TExtra, TPostDeserialized, ArrayBufferFieldType @@ -417,8 +428,8 @@ export default class Struct< }; public uint8ClampedArray: ArrayBufferTypeFieldDefinitionCreator< - TValue, - TInit, + TFields, + TOmitInit, TExtra, TPostDeserialized, Uint8ClampedArrayFieldType @@ -430,8 +441,8 @@ export default class Struct< }; public string: ArrayBufferTypeFieldDefinitionCreator< - TValue, - TInit, + TFields, + TOmitInit, TExtra, TPostDeserialized, StringFieldType @@ -456,14 +467,14 @@ export default class Struct< // This trick disallows any keys that are already in `TValue` Exclude< keyof T, - Exclude + Exclude >, never >>( - value: T & ThisType, TValue>> + value: T & ThisType, TFields>> ): Struct< - TValue, - TInit, + TFields, + TOmitInit, Overwrite, TPostDeserialized > { @@ -478,8 +489,8 @@ export default class Struct< * will also change the return type of `deserialize` to `never`. */ public postDeserialize( - callback: StructPostDeserialized - ): Struct; + callback: StructPostDeserialized + ): Struct; /** * Registers (or replaces) a custom callback to be run after deserialized. * @@ -487,8 +498,8 @@ export default class Struct< * (or doesn't modify it at all), so `deserialize` will still return the result object. */ public postDeserialize( - callback?: StructPostDeserialized - ): Struct; + callback?: StructPostDeserialized + ): Struct; /** * Registers (or replaces) a custom callback to be run after deserialized. * @@ -496,10 +507,10 @@ export default class Struct< * will `deserialize` to return that object instead. */ public postDeserialize( - callback?: StructPostDeserialized - ): Struct; + callback?: StructPostDeserialized + ): Struct; public postDeserialize( - callback?: StructPostDeserialized + callback?: StructPostDeserialized ) { this._postDeserialized = callback; return this as any; @@ -511,7 +522,7 @@ export default class Struct< return object; } - public create(init: TInit, context: StructSerializationContext): Overwrite { + public create(init: Evaluate>, context: StructSerializationContext): Overwrite { const object = this.initializeObject(); for (const [name, definition] of this._fields) { @@ -524,7 +535,7 @@ export default class Struct< public async deserialize( context: StructDeserializationContext - ): Promise : TPostDeserialized> { + ): Promise> { const object = this.initializeObject(); for (const [name, definition] of this._fields) { @@ -533,7 +544,7 @@ export default class Struct< } if (this._postDeserialized) { - const result = this._postDeserialized.call(object as TValue, object as TValue); + const result = this._postDeserialized.call(object as TFields, object as TFields); if (result) { return result; } @@ -542,7 +553,7 @@ export default class Struct< return object as any; } - public serialize(init: TInit, context: StructSerializationContext): ArrayBuffer { + public serialize(init: Evaluate>, context: StructSerializationContext): ArrayBuffer { const object = this.create(init, context) as any; let structSize = 0; diff --git a/packages/struct/src/types/array-buffer.ts b/packages/struct/src/types/array-buffer.ts index fb731251..973d0c1a 100644 --- a/packages/struct/src/types/array-buffer.ts +++ b/packages/struct/src/types/array-buffer.ts @@ -102,11 +102,11 @@ const EmptyArrayBuffer = new ArrayBuffer(0); export abstract class ArrayBufferLikeFieldDefinition< TType extends ArrayBufferLikeFieldType = ArrayBufferLikeFieldType, TOptions = void, - TRemoveInitFields = never, + TOmitInit = never, > extends FieldDefinition< TOptions, TType['valueType'], - TRemoveInitFields + TOmitInit >{ public readonly type: TType; @@ -123,7 +123,7 @@ export abstract class ArrayBufferLikeFieldDefinition< options: Readonly, context: StructDeserializationContext, object: any, - ): Promise>> { + ): Promise>> { const size = this.getDeserializeSize(object); let arrayBuffer: ArrayBuffer; @@ -147,7 +147,7 @@ export abstract class ArrayBufferLikeFieldDefinition< context: StructSerializationContext, object: any, value: TType['valueType'], - ): ArrayBufferLikeFieldRuntimeValue>; + ): ArrayBufferLikeFieldRuntimeValue>; } export class ArrayBufferLikeFieldRuntimeValue< diff --git a/packages/struct/src/types/number.ts b/packages/struct/src/types/number.ts index c3db4fb6..fd5427c0 100644 --- a/packages/struct/src/types/number.ts +++ b/packages/struct/src/types/number.ts @@ -47,8 +47,7 @@ export class NumberFieldDefinition< TTypeScriptType = TType['valueType'], > extends FieldDefinition< void, - TTypeScriptType, - never + TTypeScriptType > { public readonly type: TType; diff --git a/packages/struct/src/types/variable-length-array-buffer.ts b/packages/struct/src/types/variable-length-array-buffer.ts index 112394aa..e4031ff2 100644 --- a/packages/struct/src/types/variable-length-array-buffer.ts +++ b/packages/struct/src/types/variable-length-array-buffer.ts @@ -3,8 +3,8 @@ import { ArrayBufferLikeFieldDefinition, ArrayBufferLikeFieldRuntimeValue, Array import { KeysOfType } from './utils'; export interface VariableLengthArrayBufferLikeFieldOptions< - TInit = object, - TLengthField extends KeysOfType = any, + TFields = object, + TLengthField extends KeysOfType = any, > { lengthField: TLengthField; }