Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(shared-object-base): Improve typing in legacy+alpha API surface #23238

Merged
merged 11 commits into from
Jan 9, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ export class SharedPropertyTree extends SharedObject {
const handleTableChunk = await storage.readBlob("properties");
const utf8 = bufferToString(handleTableChunk, "utf8");

const snapshot: ISnapshot = this.serializer.parse(utf8);
const snapshot: ISnapshot = this.serializer.parse(utf8) as ISnapshot;
this.useMH = snapshot.useMH;

try {
Expand Down
2 changes: 1 addition & 1 deletion experimental/dds/ot/ot/src/ot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export abstract class SharedOT<TState, TOp> extends SharedObject {
protected async loadCore(storage: IChannelStorageService): Promise<void> {
const blob = await storage.readBlob("header");
const rawContent = bufferToString(blob, "utf8");
this.global = this.local = this.serializer.parse(rawContent);
this.global = this.local = this.serializer.parse(rawContent) as TState;
}

protected onDisconnect() {}
Expand Down
2 changes: 1 addition & 1 deletion experimental/dds/tree/src/SummaryBackCompatibility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {
export function deserialize(jsonSummary: string, serializer: IFluidSerializer): SharedTreeSummaryBase {
let summary: Partial<SharedTreeSummaryBase>;
try {
summary = serializer.parse(jsonSummary);
summary = serializer.parse(jsonSummary) as Partial<SharedTreeSummaryBase>;
} catch {
fail('Json syntax error in Summary');
}
Expand Down
3 changes: 1 addition & 2 deletions packages/dds/cell/src/cell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,7 @@ export class SharedCell<T = any>
protected async loadCore(storage: IChannelStorageService): Promise<void> {
const content = await readAndParse<ICellValue>(storage, snapshotFileName);

// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
this.data = this.serializer.decode(content.value);
this.data = this.serializer.decode(content.value) as Serializable<T>;
this.attribution = content.attribution;
}

Expand Down
4 changes: 2 additions & 2 deletions packages/dds/map/src/directory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -784,8 +784,8 @@ export class SharedDirectory
const localValue = this.makeLocal(
key,
currentSubDir.absolutePath,
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
parseHandles(serializable, this.serializer),
// eslint-disable-next-line import/no-deprecated
parseHandles(serializable, this.serializer) as ISerializableValue,
);
currentSubDir.populateStorage(key, localValue);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@

// @alpha (undocumented)
export interface IFluidSerializer {
decode(input: any): any;
encode(value: any, bind: IFluidHandle): any;
parse(value: string): any;
stringify(value: any, bind: IFluidHandle): string;
decode(input: unknown): unknown;
encode(value: unknown, bind: IFluidHandle): unknown;
parse(value: string): unknown;
stringify(value: unknown, bind: IFluidHandle): string;
}

// @alpha
Expand All @@ -33,10 +33,10 @@ export interface ISharedObjectKind<TSharedObject> {
}

// @alpha
export function makeHandlesSerializable(value: unknown, serializer: IFluidSerializer, bind: IFluidHandle): any;
export function makeHandlesSerializable(value: unknown, serializer: IFluidSerializer, bind: IFluidHandle): unknown;

// @alpha
export function parseHandles(value: unknown, serializer: IFluidSerializer): any;
export function parseHandles(value: unknown, serializer: IFluidSerializer): unknown;

// @alpha
export abstract class SharedObject<TEvent extends ISharedObjectEvents = ISharedObjectEvents> extends SharedObjectCore<TEvent> {
Expand All @@ -53,7 +53,7 @@ export abstract class SharedObject<TEvent extends ISharedObjectEvents = ISharedO
// @alpha
export abstract class SharedObjectCore<TEvent extends ISharedObjectEvents = ISharedObjectEvents> extends EventEmitterWithErrorHandling<TEvent> implements ISharedObject<TEvent> {
constructor(id: string, runtime: IFluidDataStoreRuntime, attributes: IChannelAttributes);
protected abstract applyStashedOp(content: any): void;
protected abstract applyStashedOp(content: unknown): void;
// (undocumented)
readonly attributes: IChannelAttributes;
bindToContext(): void;
Expand All @@ -76,16 +76,16 @@ export abstract class SharedObjectCore<TEvent extends ISharedObjectEvents = ISha
load(services: IChannelServices): Promise<void>;
protected abstract loadCore(services: IChannelStorageService): Promise<void>;
protected readonly logger: ITelemetryLoggerExt;
protected newAckBasedPromise<T>(executor: (resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): Promise<T>;
protected newAckBasedPromise<T>(executor: (resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: unknown) => void) => void): Promise<T>;
protected onConnect(): void;
protected abstract onDisconnect(): any;
protected abstract processCore(message: ISequencedDocumentMessage, local: boolean, localOpMetadata: unknown): any;
protected reSubmitCore(content: any, localOpMetadata: unknown): void;
protected rollback(content: any, localOpMetadata: unknown): void;
protected abstract onDisconnect(): void;
protected abstract processCore(message: ISequencedDocumentMessage, local: boolean, localOpMetadata: unknown): void;
protected reSubmitCore(content: unknown, localOpMetadata: unknown): void;
protected rollback(content: unknown, localOpMetadata: unknown): void;
// (undocumented)
protected runtime: IFluidDataStoreRuntime;
protected abstract get serializer(): IFluidSerializer;
protected submitLocalMessage(content: any, localOpMetadata?: unknown): void;
protected submitLocalMessage(content: unknown, localOpMetadata?: unknown): void;
abstract summarize(fullTree?: boolean, trackState?: boolean, telemetryContext?: ITelemetryContext): Promise<ISummaryTreeWithStats>;
}

Expand Down
21 changes: 7 additions & 14 deletions packages/dds/shared-object-base/src/serializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ export interface IFluidSerializer {
* The original `input` object is not mutated. This method will shallowly clones all objects in the path from
* the root to any replaced handles. (If no handles are found, returns the original object.)
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO: AB#26129 use unknown instead of any (legacy breaking)
encode(value: any, bind: IFluidHandle): any;
encode(value: unknown, bind: IFluidHandle): unknown;

/**
* Given a fully-jsonable object tree that may have encoded handle objects embedded within, will return an
Expand All @@ -43,21 +42,18 @@ export interface IFluidSerializer {
*
* The decoded handles are implicitly bound to the handle context of this serializer.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO: AB#26129 use unknown instead of any (legacy breaking)
decode(input: any): any;
decode(input: unknown): unknown;

/**
* Stringifies a given value. Converts any IFluidHandle to its stringified equivalent.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO: AB#26129 use unknown instead of any (legacy breaking)
stringify(value: any, bind: IFluidHandle): string;
stringify(value: unknown, bind: IFluidHandle): string;

/**
* Parses the given JSON input string and returns the JavaScript object defined by it. Any Fluid
* handles will be realized as part of the parse
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO: AB#26129 use unknown instead of any (legacy breaking)
parse(value: string): any;
parse(value: string): unknown;
}

/**
Expand Down Expand Up @@ -87,14 +83,12 @@ export class FluidSerializer implements IFluidSerializer {
*
* Any unbound handles encountered are bound to the provided IFluidHandle.
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- TODO: AB#26129 ddsFuzzHarness breaks when we update any->unknown
public encode(input: any, bind: IFluidHandleInternal): any {
public encode(input: unknown, bind: IFluidHandleInternal): unknown {
// If the given 'input' cannot contain handles, return it immediately. Otherwise,
// return the result of 'recursivelyReplace()'.
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
return !!input && typeof input === "object"
? // eslint-disable-next-line @typescript-eslint/no-unsafe-argument -- TODO: AB#26129 ddsFuzzHarness breaks when we update any->unknown
this.recursivelyReplace(input, this.encodeValue, bind)
? this.recursivelyReplace(input, this.encodeValue, bind)
: input;
}

Expand All @@ -107,8 +101,7 @@ export class FluidSerializer implements IFluidSerializer {
*
* The decoded handles are implicitly bound to the handle context of this serializer.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO: AB#26129 ddsFuzzHarness breaks when we update any->unknown
public decode(input: unknown): any {
public decode(input: unknown): unknown {
// If the given 'input' cannot contain handles, return it immediately. Otherwise,
// return the result of 'recursivelyReplace()'.
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
Expand Down
21 changes: 7 additions & 14 deletions packages/dds/shared-object-base/src/sharedObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -389,15 +389,13 @@ export abstract class SharedObjectCore<
message: ISequencedDocumentMessage,
local: boolean,
localOpMetadata: unknown,
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO: AB#26129 use void instead of any (legacy breaking)
): any;
): void;

/**
* Called when the object has disconnected from the delta stream.
*/

// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO: AB#26129 change return type to void (legacy breaking)
protected abstract onDisconnect(): any;
protected abstract onDisconnect(): void;

/**
* The serializer to serialize / parse handles.
Expand All @@ -412,8 +410,7 @@ export abstract class SharedObjectCore<
* and not sent to the server. This will be sent back when this message is received back from the server. This is
* also sent if we are asked to resubmit the message.
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- TODO: AB#26129 use unknown instead of any (legacy breaking)
protected submitLocalMessage(content: any, localOpMetadata: unknown = undefined): void {
protected submitLocalMessage(content: unknown, localOpMetadata: unknown = undefined): void {
this.verifyNotClosed();
if (this.isAttached()) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
Expand Down Expand Up @@ -451,8 +448,7 @@ export abstract class SharedObjectCore<
* @param content - The content of the original message.
* @param localOpMetadata - The local metadata associated with the original message.
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- TODO: AB#26129 use unknown instead of any (legacy breaking)
protected reSubmitCore(content: any, localOpMetadata: unknown): void {
protected reSubmitCore(content: unknown, localOpMetadata: unknown): void {
this.submitLocalMessage(content, localOpMetadata);
}

Expand All @@ -465,8 +461,7 @@ export abstract class SharedObjectCore<
protected async newAckBasedPromise<T>(
executor: (
resolve: (value: T | PromiseLike<T>) => void,
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO: AB#26129 use unknown instead of any (legacy breaking)
reject: (reason?: any) => void,
reject: (reason?: unknown) => void,
) => void,
): Promise<T> {
let rejectBecauseDispose: () => void;
Expand Down Expand Up @@ -619,8 +614,7 @@ export abstract class SharedObjectCore<
/**
* Revert an op
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- TODO: AB#26129 use unknown instead of any (legacy breaking)
protected rollback(content: any, localOpMetadata: unknown): void {
protected rollback(content: unknown, localOpMetadata: unknown): void {
throw new Error("rollback not supported");
}

Expand All @@ -641,8 +635,7 @@ export abstract class SharedObjectCore<
*
* @param content - Contents of a stashed op.
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- TODO: AB#26129 use unknown instead of any (legacy breaking)
protected abstract applyStashedOp(content: any): void;
protected abstract applyStashedOp(content: unknown): void;

/**
* Emit an event. This function is only intended for use by DDS classes that extend SharedObject/SharedObjectCore,
Expand Down
6 changes: 2 additions & 4 deletions packages/dds/shared-object-base/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ export function makeHandlesSerializable(
value: unknown,
serializer: IFluidSerializer,
bind: IFluidHandle,
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO: AB#26129 use unknown instead of any (legacy breaking)
): any {
): unknown {
return serializer.encode(value, bind);
}

Expand All @@ -61,8 +60,7 @@ export function makeHandlesSerializable(
* @legacy
* @alpha
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO: AB#26129 use unknown instead of any (legacy breaking)
export function parseHandles(value: unknown, serializer: IFluidSerializer): any {
export function parseHandles(value: unknown, serializer: IFluidSerializer): unknown {
return serializer.decode(value);
}

Expand Down
7 changes: 2 additions & 5 deletions packages/dds/test-dds-utils/src/ddsFuzzHarness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1460,14 +1460,11 @@ export async function runTestForSeed<
let operationCount = 0;
const generator = model.generatorFactory();
const finalState = await performFuzzActionsAsync(
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
async (state) => serializer.encode(await generator(state), bind),
async (state) => serializer.encode(await generator(state), bind) as TOperation,
async (state, operation) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const decodedHandles = serializer.decode(operation);
const decodedHandles = serializer.decode(operation) as TOperation;
options.emitter.emit("operation", decodedHandles);
operationCount++;
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
return model.reducer(state, decodedHandles);
},
initialState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ export function manufactureHandle<T>(
const handle: IFluidHandleInternal<T> = parseHandles(
{ type: "__fluid_handle__", url },
serializer,
);
) as IFluidHandleInternal<T>;
return handle;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,7 @@ describeCompat("GC data store tombstone tests", "NoCompat", (getTestObjectProvid
const handle: IFluidHandle = parseHandles(
{ type: "__fluid_handle__", url: unreferencedId },
serializer,
);
) as IFluidHandle;

// This fails because the DataStore is tombstoned
let tombstoneError: ExpectedTombstoneError | undefined;
Expand Down
Loading