Integrate main to next (#10011)
This commit is contained in:
Родитель
a5e03298e6
Коммит
215ec2086e
|
@ -32,6 +32,7 @@ services:
|
|||
environment:
|
||||
- DEBUG=fluid:*
|
||||
- NODE_ENV=development
|
||||
- IS_FLUID_SERVER=true
|
||||
- login__microsoft__clientId
|
||||
- login__microsoft__secret
|
||||
- login__accounts
|
||||
|
@ -44,6 +45,7 @@ services:
|
|||
environment:
|
||||
- DEBUG=fluid:*
|
||||
- NODE_ENV=development
|
||||
- IS_FLUID_SERVER=true
|
||||
restart: always
|
||||
deli:
|
||||
image: prague.azurecr.io/prague:12579
|
||||
|
@ -51,6 +53,7 @@ services:
|
|||
environment:
|
||||
- DEBUG=fluid:*
|
||||
- NODE_ENV=development
|
||||
- IS_FLUID_SERVER=true
|
||||
restart: always
|
||||
scriptorium:
|
||||
image: prague.azurecr.io/prague:12579
|
||||
|
@ -58,6 +61,7 @@ services:
|
|||
environment:
|
||||
- DEBUG=fluid:*
|
||||
- NODE_ENV=development
|
||||
- IS_FLUID_SERVER=true
|
||||
restart: always
|
||||
broadcaster:
|
||||
image: prague.azurecr.io/prague:12579
|
||||
|
@ -65,6 +69,7 @@ services:
|
|||
environment:
|
||||
- DEBUG=fluid:*
|
||||
- NODE_ENV=development
|
||||
- IS_FLUID_SERVER=true
|
||||
restart: always
|
||||
scribe:
|
||||
image: prague.azurecr.io/prague:12579
|
||||
|
@ -72,6 +77,7 @@ services:
|
|||
environment:
|
||||
- DEBUG=fluid:*
|
||||
- NODE_ENV=development
|
||||
- IS_FLUID_SERVER=true
|
||||
restart: always
|
||||
riddler:
|
||||
image: prague.azurecr.io/prague:12579
|
||||
|
@ -81,6 +87,7 @@ services:
|
|||
environment:
|
||||
- DEBUG=fluid:*
|
||||
- NODE_ENV=development
|
||||
- IS_FLUID_SERVER=true
|
||||
restart: always
|
||||
historian:
|
||||
image: prague.azurecr.io/historian:5109
|
||||
|
@ -89,12 +96,14 @@ services:
|
|||
environment:
|
||||
- DEBUG=fluid:*
|
||||
- NODE_ENV=development
|
||||
- IS_FLUID_SERVER=true
|
||||
restart: always
|
||||
gitrest:
|
||||
image: prague.azurecr.io/gitrest:4048
|
||||
environment:
|
||||
- DEBUG=fluid:*
|
||||
- NODE_ENV=development
|
||||
- IS_FLUID_SERVER=true
|
||||
volumes:
|
||||
- git:/home/node/documents
|
||||
restart: always
|
||||
|
|
|
@ -45,10 +45,14 @@ In order to use `IContainer.closeAndGetPendingLocalState`, pass a set of options
|
|||
|
||||
## 0.59 Upcoming changes
|
||||
- [Remove ICodeLoader interface](#Remove-ICodeLoader-interface)
|
||||
- [IFluidContainer.connect() and IFluidContainer.disconnect() will be made mandatory in future major release](#ifluidcontainer-connect-and-ifluidcontainer-disconnect-will-be-made-mandatory-in-future-major-release)
|
||||
|
||||
### Remove ICodeLoader interface
|
||||
ICodeLoader interface was deprecated a while ago and will be removed in the next release. Please refer to [replace ICodeLoader with ICodeDetailsLoader interface](#Replace-ICodeLoader-with-ICodeDetailsLoader-interface) for more details.
|
||||
|
||||
### IFluidContainer.connect() and IFluidContainer.disconnect() will be made mandatory in future major release
|
||||
In major release 1.0, the optional functions `IFluidContainer.connect()` and `IFluidContainer.disconnect()` will be made mandatory functions.
|
||||
|
||||
## 0.59 Breaking changes
|
||||
- [Removing Commit from TreeEntry and commits from SnapShotTree](#Removing-Commit-from-TreeEntry-and-commits-from-SnapShotTree)
|
||||
- [raiseContainerWarning removed from IContainerContext](#raiseContainerWarning-removed-from-IContainerContext)
|
||||
|
|
|
@ -498,6 +498,8 @@ export const ISummarizer: keyof IProvideSummarizer;
|
|||
|
||||
// @public (undocumented)
|
||||
export interface ISummarizer extends IEventProvider<ISummarizerEvents>, IFluidLoadable, Partial<IProvideSummarizer> {
|
||||
// (undocumented)
|
||||
close(): void;
|
||||
enqueueSummarize(options: IEnqueueSummarizeOptions): EnqueueSummarizeResult;
|
||||
// (undocumented)
|
||||
run(onBehalfOf: string, options?: Readonly<Partial<ISummarizerOptions>>): Promise<SummarizerStopReason>;
|
||||
|
@ -670,6 +672,8 @@ export class Summarizer extends EventEmitter implements ISummarizer {
|
|||
constructor(url: string,
|
||||
runtime: ISummarizerRuntime, configurationGetter: () => ISummaryConfiguration,
|
||||
internalsProvider: ISummarizerInternalsProvider, handleContext: IFluidHandleContext, summaryCollection: SummaryCollection, runCoordinatorCreateFn: (runtime: IConnectableRuntime) => Promise<ICancellableSummarizerController>);
|
||||
// (undocumented)
|
||||
close(): void;
|
||||
static create(loader: ILoader, url: string): Promise<ISummarizer>;
|
||||
dispose(): void;
|
||||
// (undocumented)
|
||||
|
|
|
@ -80,7 +80,6 @@ export interface IDeltaConnection {
|
|||
|
||||
// @public
|
||||
export interface IDeltaHandler {
|
||||
// (undocumented)
|
||||
applyStashedOp(message: any): unknown;
|
||||
process: (message: ISequencedDocumentMessage, local: boolean, localOpMetadata: unknown) => void;
|
||||
reSubmit(message: any, localOpMetadata: unknown): void;
|
||||
|
@ -140,5 +139,4 @@ export type Jsonable<T = any, TReplaced = void> = T extends undefined | null | b
|
|||
// @public
|
||||
export type Serializable<T = any> = Jsonable<T, IFluidHandle>;
|
||||
|
||||
|
||||
```
|
||||
|
|
|
@ -516,6 +516,12 @@ export interface InsertInternal_0_0_2 {
|
|||
readonly type: typeof ChangeTypeInternal.Insert;
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface InternalizedChange {
|
||||
// (undocumented)
|
||||
InternalChangeBrand: '2cae1045-61cf-4ef7-a6a3-8ad920cb7ab3';
|
||||
}
|
||||
|
||||
// @public
|
||||
export type InternedStringId = number & {
|
||||
readonly InternedStringId: 'e221abc9-9d17-4493-8db0-70c871a1c27c';
|
||||
|
@ -819,9 +825,9 @@ export class SharedTree extends SharedObject<ISharedTreeEvents> implements NodeI
|
|||
constructor(runtime: IFluidDataStoreRuntime, id: string, writeFormat: WriteFormat, summarizeHistory?: false | {
|
||||
uploadEditChunks: boolean;
|
||||
}, expensiveValidation?: boolean);
|
||||
applyEdit(...changes: Change[]): Edit<unknown>;
|
||||
applyEdit(...changes: Change[]): Edit<InternalizedChange>;
|
||||
// (undocumented)
|
||||
applyEdit(changes: Change[]): Edit<unknown>;
|
||||
applyEdit(changes: Change[]): Edit<InternalizedChange>;
|
||||
// @internal
|
||||
applyEditInternal(editOrChanges: Edit<ChangeInternal> | readonly ChangeInternal[]): Edit<ChangeInternal>;
|
||||
protected applyStashedOp(op: unknown): void;
|
||||
|
@ -831,9 +837,7 @@ export class SharedTree extends SharedObject<ISharedTreeEvents> implements NodeI
|
|||
// (undocumented)
|
||||
get currentView(): RevisionView;
|
||||
// (undocumented)
|
||||
get edits(): OrderedEditSet;
|
||||
// @internal (undocumented)
|
||||
get editsInternal(): OrderedEditSet<ChangeInternal>;
|
||||
get edits(): OrderedEditSet<InternalizedChange>;
|
||||
// @internal
|
||||
equals(sharedTree: SharedTree): boolean;
|
||||
generateNodeId(override?: string): NodeId;
|
||||
|
@ -855,6 +859,7 @@ export class SharedTree extends SharedObject<ISharedTreeEvents> implements NodeI
|
|||
// (undocumented)
|
||||
protected readonly logger: ITelemetryLogger;
|
||||
get logViewer(): LogViewer;
|
||||
mergeEditsFrom(other: SharedTree, edits: Iterable<Edit<InternalizedChange>>, stableIdRemapper?: (id: StableNodeId) => StableNodeId): EditId[];
|
||||
// (undocumented)
|
||||
protected onDisconnect(): void;
|
||||
// (undocumented)
|
||||
|
@ -863,7 +868,7 @@ export class SharedTree extends SharedObject<ISharedTreeEvents> implements NodeI
|
|||
protected registerCore(): void;
|
||||
revert(editId: EditId): EditId | undefined;
|
||||
// @internal
|
||||
revertChanges(changes: readonly ChangeInternal[], before: RevisionView): ChangeInternal[] | undefined;
|
||||
revertChanges(changes: readonly InternalizedChange[], before: RevisionView): ChangeInternal[] | undefined;
|
||||
// @internal
|
||||
saveSerializedSummary(options?: {
|
||||
serializer?: IFluidSerializer;
|
||||
|
|
|
@ -42,9 +42,11 @@ export class FluidContainer extends TypedEventEmitter<IFluidContainerEvents> imp
|
|||
constructor(container: IContainer, rootDataObject: RootDataObject);
|
||||
attach(): Promise<string>;
|
||||
get attachState(): AttachState;
|
||||
connect(): Promise<void>;
|
||||
get connected(): boolean;
|
||||
get connectionState(): ConnectionState;
|
||||
create<T extends IFluidLoadable>(objectClass: LoadableObjectClass<T>): Promise<T>;
|
||||
disconnect(): Promise<void>;
|
||||
dispose(): void;
|
||||
get disposed(): boolean;
|
||||
get initialObjects(): Record<string, IFluidLoadable>;
|
||||
|
@ -61,10 +63,12 @@ export interface IConnection {
|
|||
export interface IFluidContainer extends IEventProvider<IFluidContainerEvents> {
|
||||
attach(): Promise<string>;
|
||||
readonly attachState: AttachState;
|
||||
connect?(): void;
|
||||
// @deprecated
|
||||
readonly connected: boolean;
|
||||
readonly connectionState: ConnectionState;
|
||||
create<T extends IFluidLoadable>(objectClass: LoadableObjectClass<T>): Promise<T>;
|
||||
disconnect?(): void;
|
||||
dispose(): void;
|
||||
readonly disposed: boolean;
|
||||
readonly initialObjects: LoadableObjectRecord;
|
||||
|
|
|
@ -43,7 +43,7 @@ export type MatrixItem<T> = Serializable<Exclude<T, null>> | undefined;
|
|||
export class SharedMatrix<T = any> extends SharedObject implements IMatrixProducer<MatrixItem<T>>, IMatrixReader<MatrixItem<T>>, IMatrixWriter<MatrixItem<T>> {
|
||||
constructor(runtime: IFluidDataStoreRuntime, id: string, attributes: IChannelAttributes);
|
||||
// (undocumented)
|
||||
protected applyStashedOp(): void;
|
||||
protected applyStashedOp(content: any): unknown;
|
||||
// (undocumented)
|
||||
closeMatrix(consumer: IMatrixConsumer<MatrixItem<T>>): void;
|
||||
// (undocumented)
|
||||
|
@ -116,7 +116,6 @@ export class SharedMatrixFactory implements IChannelFactory {
|
|||
get type(): string;
|
||||
}
|
||||
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
|
||||
```
|
||||
|
|
|
@ -104,7 +104,13 @@ export class Client {
|
|||
annotateMarkerNotifyConsensus(marker: Marker, props: PropertySet, consensusCallback: (m: Marker) => void): IMergeTreeAnnotateMsg | undefined;
|
||||
annotateRangeLocal(start: number, end: number, props: PropertySet, combiningOp: ICombiningOp | undefined): IMergeTreeAnnotateMsg | undefined;
|
||||
// (undocumented)
|
||||
applyMsg(msg: ISequencedDocumentMessage): void;
|
||||
applyMsg(msg: ISequencedDocumentMessage, local?: boolean): void;
|
||||
// (undocumented)
|
||||
applyStashedOp(op: IMergeTreeDeltaOp): SegmentGroup;
|
||||
// (undocumented)
|
||||
applyStashedOp(op: IMergeTreeGroupMsg): SegmentGroup[];
|
||||
// (undocumented)
|
||||
applyStashedOp(op: IMergeTreeOp): SegmentGroup | SegmentGroup[];
|
||||
// (undocumented)
|
||||
cloneFromSegments(): Client;
|
||||
// (undocumented)
|
||||
|
@ -825,7 +831,7 @@ export class LocalReference implements ReferencePosition {
|
|||
toPosition(): number;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export class LocalReferenceCollection {
|
||||
// (undocumented)
|
||||
[Symbol.iterator](): {
|
||||
|
@ -833,7 +839,8 @@ export class LocalReferenceCollection {
|
|||
[Symbol.iterator](): any;
|
||||
};
|
||||
// Warning: (ae-forgotten-export) The symbol "IRefsAtOffset" needs to be exported by the entry point index.d.ts
|
||||
constructor(segment: ISegment, initialRefsByfOffset?: (IRefsAtOffset | undefined)[]);
|
||||
constructor(
|
||||
segment: ISegment, initialRefsByfOffset?: (IRefsAtOffset | undefined)[]);
|
||||
// (undocumented)
|
||||
addAfterTombstones(...refs: Iterable<LocalReference>[]): void;
|
||||
// (undocumented)
|
||||
|
@ -851,7 +858,6 @@ export class LocalReferenceCollection {
|
|||
hierRefCount: number;
|
||||
// (undocumented)
|
||||
removeLocalRef(lref: LocalReference): LocalReference | undefined;
|
||||
// (undocumented)
|
||||
split(offset: number, splitSeg: ISegment): void;
|
||||
}
|
||||
|
||||
|
@ -1044,7 +1050,7 @@ export class MergeTree {
|
|||
startCollaboration(localClientId: number, minSeq: number, currentSeq: number): void;
|
||||
// (undocumented)
|
||||
walkAllSegments<TClientData>(block: IMergeBlock, action: (segment: ISegment, accum?: TClientData) => boolean, accum?: TClientData): boolean;
|
||||
}
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export type MergeTreeDeltaCallback = (opArgs: IMergeTreeDeltaOpArgs, deltaArgs: IMergeTreeDeltaCallbackArgs) => void;
|
||||
|
@ -1114,7 +1120,7 @@ export class MergeTreeTextHelper {
|
|||
parallelText: string[];
|
||||
parallelMarkers: Marker[];
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface MinListener {
|
||||
|
@ -1147,7 +1153,7 @@ export class PropertiesManager {
|
|||
copyTo(oldProps: PropertySet, newProps: PropertySet | undefined, newManager: PropertiesManager): PropertySet | undefined;
|
||||
// (undocumented)
|
||||
hasPendingProperties(): boolean;
|
||||
}
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface Property<TKey, TData> {
|
||||
|
@ -1566,7 +1572,6 @@ export const UnassignedSequenceNumber = -1;
|
|||
// @public
|
||||
export const UniversalSequenceNumber = 0;
|
||||
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
|
||||
```
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
## API Report File for "@fluid-internal/quorum"
|
||||
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
|
||||
import { IChannelAttributes } from '@fluidframework/datastore-definitions';
|
||||
import { IChannelFactory } from '@fluidframework/datastore-definitions';
|
||||
import { IChannelStorageService } from '@fluidframework/datastore-definitions';
|
||||
import { IFluidDataStoreRuntime } from '@fluidframework/datastore-definitions';
|
||||
import { IFluidSerializer } from '@fluidframework/shared-object-base';
|
||||
import { ISequencedDocumentMessage } from '@fluidframework/protocol-definitions';
|
||||
import { ISharedObject } from '@fluidframework/shared-object-base';
|
||||
import { ISharedObjectEvents } from '@fluidframework/shared-object-base';
|
||||
import { ISummaryTreeWithStats } from '@fluidframework/runtime-definitions';
|
||||
import { SharedObject } from '@fluidframework/shared-object-base';
|
||||
|
||||
// @public
|
||||
export interface IQuorum extends ISharedObject<IQuorumEvents> {
|
||||
delete(key: string): void;
|
||||
get(key: string): any;
|
||||
getPending(key: string): any;
|
||||
has(key: string): boolean;
|
||||
set(key: string, value: any): void;
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface IQuorumEvents extends ISharedObjectEvents {
|
||||
(event: "pending" | "accepted", listener: (key: string) => void): any;
|
||||
}
|
||||
|
||||
// @public
|
||||
export class Quorum extends SharedObject<IQuorumEvents> implements IQuorum {
|
||||
constructor(id: string, runtime: IFluidDataStoreRuntime, attributes: IChannelAttributes);
|
||||
// (undocumented)
|
||||
applyStashedOp(): void;
|
||||
static create(runtime: IFluidDataStoreRuntime, id?: string): Quorum;
|
||||
delete(key: string): void;
|
||||
get(key: string): any;
|
||||
static getFactory(): IChannelFactory;
|
||||
getPending(key: string): any;
|
||||
has(key: string): boolean;
|
||||
// @internal (undocumented)
|
||||
protected initializeLocalCore(): void;
|
||||
// @internal (undocumented)
|
||||
protected loadCore(storage: IChannelStorageService): Promise<void>;
|
||||
// @internal (undocumented)
|
||||
protected onDisconnect(): void;
|
||||
// @internal
|
||||
protected processCore(message: ISequencedDocumentMessage, local: boolean, localOpMetadata: unknown): void;
|
||||
set(key: string, value: any): void;
|
||||
// @internal
|
||||
protected summarizeCore(serializer: IFluidSerializer): ISummaryTreeWithStats;
|
||||
}
|
||||
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
|
||||
```
|
|
@ -76,7 +76,7 @@ export class DocumentService implements api.IDocumentService {
|
|||
|
||||
// @public (undocumented)
|
||||
export class DocumentStorageService extends DocumentStorageServiceProxy {
|
||||
constructor(id: string, manager: GitManager, logger: ITelemetryLogger, policies?: IDocumentStorageServicePolicies, driverPolicies?: IRouterliciousDriverPolicies, blobCache?: ICache<ArrayBufferLike>, snapshotTreeCache?: ICache<ISnapshotTreeVersion>);
|
||||
constructor(id: string, manager: GitManager, logger: ITelemetryLogger, policies?: IDocumentStorageServicePolicies, driverPolicies?: IRouterliciousDriverPolicies, blobCache?: ICache<ArrayBufferLike>, snapshotTreeCache?: ICache<ISnapshotTreeVersion>, noCacheGitManager?: GitManager | undefined);
|
||||
// (undocumented)
|
||||
getSnapshotTree(version?: IVersion): Promise<ISnapshotTree | null>;
|
||||
// (undocumented)
|
||||
|
@ -85,11 +85,14 @@ export class DocumentStorageService extends DocumentStorageServiceProxy {
|
|||
get logTailSha(): string | undefined;
|
||||
// (undocumented)
|
||||
manager: GitManager;
|
||||
// (undocumented)
|
||||
noCacheGitManager?: GitManager | undefined;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface IRouterliciousDriverPolicies {
|
||||
aggregateBlobsSmallerThanBytes: number | undefined;
|
||||
enableDiscovery?: boolean;
|
||||
enablePrefetch: boolean;
|
||||
enableRestLess: boolean;
|
||||
enableWholeSummaryUpload: boolean;
|
||||
|
@ -141,7 +144,7 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
|
|||
constructor(tokenProvider: ITokenProvider, driverPolicies?: Partial<IRouterliciousDriverPolicies>);
|
||||
// (undocumented)
|
||||
createContainer(createNewSummary: ISummaryTree | undefined, resolvedUrl: IResolvedUrl, logger?: ITelemetryBaseLogger, clientIsSummarizer?: boolean): Promise<IDocumentService>;
|
||||
createDocumentService(resolvedUrl: IResolvedUrl, logger?: ITelemetryBaseLogger, clientIsSummarizer?: boolean): Promise<IDocumentService>;
|
||||
createDocumentService(resolvedUrl: IResolvedUrl, logger?: ITelemetryBaseLogger, clientIsSummarizer?: boolean, isCreateContainer?: boolean): Promise<IDocumentService>;
|
||||
// (undocumented)
|
||||
readonly protocolName = "fluid:";
|
||||
}
|
||||
|
|
|
@ -176,7 +176,7 @@ export class IntervalCollectionIterator<TInterval extends ISerializableInterval>
|
|||
value: TInterval;
|
||||
done: boolean;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export enum IntervalType {
|
||||
|
@ -359,12 +359,12 @@ export abstract class SequenceEvent<TOperation extends MergeTreeDeltaOperationTy
|
|||
readonly deltaArgs: IMergeTreeDeltaCallbackArgs<TOperation>;
|
||||
// (undocumented)
|
||||
readonly deltaOperation: TOperation;
|
||||
get first(): Readonly<ISequenceDeltaRange<TOperation>> | undefined;
|
||||
// (undocumented)
|
||||
get first(): Readonly<ISequenceDeltaRange<TOperation>>;
|
||||
// @deprecated (undocumented)
|
||||
readonly isEmpty: boolean;
|
||||
get last(): Readonly<ISequenceDeltaRange<TOperation>> | undefined;
|
||||
get last(): Readonly<ISequenceDeltaRange<TOperation>>;
|
||||
get ranges(): readonly Readonly<ISequenceDeltaRange<TOperation>>[];
|
||||
}
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export class SequenceInterval implements ISerializableInterval {
|
||||
|
@ -523,7 +523,7 @@ export abstract class SharedSegmentSequence<T extends ISegment> extends SharedOb
|
|||
addLocalReference(lref: LocalReference): void;
|
||||
annotateRange(start: number, end: number, props: PropertySet, combiningOp?: ICombiningOp): void;
|
||||
// (undocumented)
|
||||
protected applyStashedOp(): void;
|
||||
protected applyStashedOp(content: any): unknown;
|
||||
// (undocumented)
|
||||
protected client: Client;
|
||||
// (undocumented)
|
||||
|
@ -747,7 +747,6 @@ export class SubSequence<T> extends BaseSegment {
|
|||
static readonly typeString: string;
|
||||
}
|
||||
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
|
||||
```
|
||||
|
|
|
@ -100,7 +100,6 @@ export abstract class SharedObject<TEvent extends ISharedObjectEvents = ISharedO
|
|||
// @public
|
||||
export abstract class SharedObjectCore<TEvent extends ISharedObjectEvents = ISharedObjectEvents> extends EventEmitterWithErrorHandling<TEvent> implements ISharedObject<TEvent> {
|
||||
constructor(id: string, runtime: IFluidDataStoreRuntime, attributes: IChannelAttributes);
|
||||
// (undocumented)
|
||||
protected abstract applyStashedOp(content: any): unknown;
|
||||
// (undocumented)
|
||||
readonly attributes: IChannelAttributes;
|
||||
|
@ -132,7 +131,7 @@ export abstract class SharedObjectCore<TEvent extends ISharedObjectEvents = ISha
|
|||
protected runtime: IFluidDataStoreRuntime;
|
||||
protected submitLocalMessage(content: any, localOpMetadata?: unknown): void;
|
||||
abstract summarize(fullTree?: boolean, trackState?: boolean): Promise<ISummaryTreeWithStats>;
|
||||
}
|
||||
}
|
||||
|
||||
// @public
|
||||
export class SummarySerializer extends FluidSerializer {
|
||||
|
@ -152,7 +151,6 @@ export enum ValueType {
|
|||
Shared = 0
|
||||
}
|
||||
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
|
||||
```
|
||||
|
|
|
@ -32,8 +32,6 @@ a diff to review as part of a PR -- just like we do with API reports for code ch
|
|||
<!-- AUTO-GENERATED-CONTENT:START (SCRIPTS) -->
|
||||
| Script | Description |
|
||||
|--------|-------------|
|
||||
| `build` | Build the package. |
|
||||
| `build:ci` | Build the package -- called as part of CI. |
|
||||
| `cleanup-printed-configs` | Clean up the printed configs. Removes the `parser` property and sorts the JSON. |
|
||||
| `print-config` | Print all the eslint configs. |
|
||||
| `print-config:default` | Print the eslint config for regular TypeScript files (`eslint --config index.js --print-config src/file.ts`). |
|
||||
|
|
|
@ -3660,9 +3660,9 @@
|
|||
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA=="
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.5.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.3.tgz",
|
||||
"integrity": "sha512-eVYaEHALSt+s9LbvgEv4Ef+Tdq7hBiIZgii12xXJnukryt3pMgJf6aKhoCZ3FWQsu6sydEnkg11fYXLzhLBjeQ==",
|
||||
"version": "4.5.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz",
|
||||
"integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==",
|
||||
"dev": true
|
||||
},
|
||||
"unbox-primitive": {
|
||||
|
|
|
@ -36,6 +36,6 @@
|
|||
"eslint": "~8.6.0",
|
||||
"node-jq": "^2.3.3",
|
||||
"sort-json": "^2.0.1",
|
||||
"typescript": "^4.5.3"
|
||||
"typescript": "~4.5.5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1275,6 +1275,63 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/utils": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.20.0.tgz",
|
||||
"integrity": "sha512-lHONGJL1LIO12Ujyx8L8xKbwWSkoUKFSO+0wDAqGXiudWB2EO7WEUT+YZLtVbmOmSllAjLb9tpoIPwpRe5Tn6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@typescript-eslint/scope-manager": "5.20.0",
|
||||
"@typescript-eslint/types": "5.20.0",
|
||||
"@typescript-eslint/typescript-estree": "5.20.0",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.20.0.tgz",
|
||||
"integrity": "sha512-h9KtuPZ4D/JuX7rpp1iKg3zOH0WNEa+ZIXwpW/KWmEFDxlA/HSfCMhiyF1HS/drTICjIbpA6OqkAhrP/zkCStg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.20.0",
|
||||
"@typescript-eslint/visitor-keys": "5.20.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.20.0.tgz",
|
||||
"integrity": "sha512-+d8wprF9GyvPwtoB4CxBAR/s0rpP25XKgnOvMf/gMXYDvlUC3rPFHupdTQ/ow9vn7UDe5rX02ovGYQbv/IUCbg==",
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.20.0.tgz",
|
||||
"integrity": "sha512-36xLjP/+bXusLMrT9fMMYy1KJAGgHhlER2TqpUVDYUQg4w0q/NW/sg4UGAgVwAqb8V4zYg43KMUpM8vV2lve6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.20.0",
|
||||
"@typescript-eslint/visitor-keys": "5.20.0",
|
||||
"debug": "^4.3.2",
|
||||
"globby": "^11.0.4",
|
||||
"is-glob": "^4.0.3",
|
||||
"semver": "^7.3.5",
|
||||
"tsutils": "^3.21.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.20.0.tgz",
|
||||
"integrity": "sha512-1flRpNF+0CAQkMNlTJ6L/Z5jiODG/e5+7mk6XwtPOUS3UrTz3UOiAg9jG2VtKsWI6rZQfy4C6a232QNRZTRGlg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.20.0",
|
||||
"eslint-visitor-keys": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "5.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.9.0.tgz",
|
||||
|
@ -2530,11 +2587,24 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"eslint-plugin-no-null": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-no-null/-/eslint-plugin-no-null-1.0.2.tgz",
|
||||
"integrity": "sha1-EjaoEjkTkKGHetQAfCbnRTQclR8=",
|
||||
"dev": true
|
||||
"eslint-plugin-jest": {
|
||||
"version": "26.1.4",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-26.1.4.tgz",
|
||||
"integrity": "sha512-wgqxujmqc2qpvZqMFWCh6Cniqc8lWpapvXt9j/19DmBDqeDaYhJrSRezYR1SKyemvjx+9e9kny/dgRahraHImA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/utils": "^5.10.0"
|
||||
}
|
||||
},
|
||||
"eslint-plugin-mocha": {
|
||||
"version": "10.0.4",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-10.0.4.tgz",
|
||||
"integrity": "sha512-8wzAeepVY027oBHz/TmBmUr7vhVqoC1KTFeDybFLhbaWKx+aQ7fJJVuUsqcUy+L+G+XvgQBJY+cbAf7hl5DF7Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"eslint-utils": "^3.0.0",
|
||||
"ramda": "^0.28.0"
|
||||
}
|
||||
},
|
||||
"eslint-plugin-promise": {
|
||||
"version": "6.0.0",
|
||||
|
@ -4790,6 +4860,12 @@
|
|||
"integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==",
|
||||
"dev": true
|
||||
},
|
||||
"ramda": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.28.0.tgz",
|
||||
"integrity": "sha512-9QnLuG/kPVgWvMQ4aODhsBUFKOUmnbUnsSXACv+NCQZcHbeb+v8Lodp8OVxtRULN1/xOyYLLaL6npE6dMq5QTA==",
|
||||
"dev": true
|
||||
},
|
||||
"react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
|
@ -5651,9 +5727,9 @@
|
|||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz",
|
||||
"integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==",
|
||||
"version": "4.5.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz",
|
||||
"integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==",
|
||||
"dev": true
|
||||
},
|
||||
"typescript-formatter": {
|
||||
|
|
|
@ -55,11 +55,14 @@
|
|||
"eslint-plugin-editorconfig": "~3.2.0",
|
||||
"eslint-plugin-eslint-comments": "~3.2.0",
|
||||
"eslint-plugin-import": "~2.25.4",
|
||||
"eslint-plugin-no-null": "~1.0.2",
|
||||
"eslint-plugin-jest": "~26.1.3",
|
||||
"eslint-plugin-mocha": "~10.0.3",
|
||||
"eslint-plugin-promise": "~6.0.0",
|
||||
"eslint-plugin-react": "~7.28.0",
|
||||
"eslint-plugin-tsdoc": "~0.2.14",
|
||||
"eslint-plugin-unicorn": "~40.0.0",
|
||||
"rimraf": "^2.6.2",
|
||||
"typescript": "~4.1.3",
|
||||
"typescript": "~4.5.5",
|
||||
"typescript-formatter": "7.1.0"
|
||||
},
|
||||
"typeValidation": {
|
||||
|
|
|
@ -2367,9 +2367,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"@types/mocha": {
|
||||
"version": "8.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.2.tgz",
|
||||
"integrity": "sha512-Lwh0lzzqT5Pqh6z61P3c3P5nm6fzQK/MMHl9UKeneAeInVflBSz1O2EkX6gM6xfJd7FBXBY5purtLx7fUiZ7Hw==",
|
||||
"version": "8.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.3.tgz",
|
||||
"integrity": "sha512-ekGvFhFgrc2zYQoX4JeZPmVzZxw6Dtllga7iGHzfbYIYkAMUx/sAFP2GdFpLff+vdHXu5fl7WX9AT+TtqYcsyw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/node": {
|
||||
|
@ -2753,6 +2753,87 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/utils": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.20.0.tgz",
|
||||
"integrity": "sha512-lHONGJL1LIO12Ujyx8L8xKbwWSkoUKFSO+0wDAqGXiudWB2EO7WEUT+YZLtVbmOmSllAjLb9tpoIPwpRe5Tn6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@typescript-eslint/scope-manager": "5.20.0",
|
||||
"@typescript-eslint/types": "5.20.0",
|
||||
"@typescript-eslint/typescript-estree": "5.20.0",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.20.0.tgz",
|
||||
"integrity": "sha512-h9KtuPZ4D/JuX7rpp1iKg3zOH0WNEa+ZIXwpW/KWmEFDxlA/HSfCMhiyF1HS/drTICjIbpA6OqkAhrP/zkCStg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.20.0",
|
||||
"@typescript-eslint/visitor-keys": "5.20.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.20.0.tgz",
|
||||
"integrity": "sha512-+d8wprF9GyvPwtoB4CxBAR/s0rpP25XKgnOvMf/gMXYDvlUC3rPFHupdTQ/ow9vn7UDe5rX02ovGYQbv/IUCbg==",
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.20.0.tgz",
|
||||
"integrity": "sha512-36xLjP/+bXusLMrT9fMMYy1KJAGgHhlER2TqpUVDYUQg4w0q/NW/sg4UGAgVwAqb8V4zYg43KMUpM8vV2lve6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.20.0",
|
||||
"@typescript-eslint/visitor-keys": "5.20.0",
|
||||
"debug": "^4.3.2",
|
||||
"globby": "^11.0.4",
|
||||
"is-glob": "^4.0.3",
|
||||
"semver": "^7.3.5",
|
||||
"tsutils": "^3.21.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.20.0.tgz",
|
||||
"integrity": "sha512-1flRpNF+0CAQkMNlTJ6L/Z5jiODG/e5+7mk6XwtPOUS3UrTz3UOiAg9jG2VtKsWI6rZQfy4C6a232QNRZTRGlg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.20.0",
|
||||
"eslint-visitor-keys": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "5.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.9.0.tgz",
|
||||
|
@ -5054,11 +5135,24 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"eslint-plugin-no-null": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-no-null/-/eslint-plugin-no-null-1.0.2.tgz",
|
||||
"integrity": "sha1-EjaoEjkTkKGHetQAfCbnRTQclR8=",
|
||||
"dev": true
|
||||
"eslint-plugin-jest": {
|
||||
"version": "26.1.4",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-26.1.4.tgz",
|
||||
"integrity": "sha512-wgqxujmqc2qpvZqMFWCh6Cniqc8lWpapvXt9j/19DmBDqeDaYhJrSRezYR1SKyemvjx+9e9kny/dgRahraHImA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/utils": "^5.10.0"
|
||||
}
|
||||
},
|
||||
"eslint-plugin-mocha": {
|
||||
"version": "10.0.4",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-10.0.4.tgz",
|
||||
"integrity": "sha512-8wzAeepVY027oBHz/TmBmUr7vhVqoC1KTFeDybFLhbaWKx+aQ7fJJVuUsqcUy+L+G+XvgQBJY+cbAf7hl5DF7Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"eslint-utils": "^3.0.0",
|
||||
"ramda": "^0.28.0"
|
||||
}
|
||||
},
|
||||
"eslint-plugin-promise": {
|
||||
"version": "6.0.0",
|
||||
|
@ -11342,6 +11436,12 @@
|
|||
"integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==",
|
||||
"dev": true
|
||||
},
|
||||
"ramda": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.28.0.tgz",
|
||||
"integrity": "sha512-9QnLuG/kPVgWvMQ4aODhsBUFKOUmnbUnsSXACv+NCQZcHbeb+v8Lodp8OVxtRULN1/xOyYLLaL6npE6dMq5QTA==",
|
||||
"dev": true
|
||||
},
|
||||
"randombytes": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||
|
@ -13419,9 +13519,9 @@
|
|||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz",
|
||||
"integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==",
|
||||
"version": "4.5.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz",
|
||||
"integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==",
|
||||
"dev": true
|
||||
},
|
||||
"typescript-formatter": {
|
||||
|
|
|
@ -106,8 +106,11 @@
|
|||
"eslint-plugin-editorconfig": "~3.2.0",
|
||||
"eslint-plugin-eslint-comments": "~3.2.0",
|
||||
"eslint-plugin-import": "~2.25.4",
|
||||
"eslint-plugin-no-null": "~1.0.2",
|
||||
"eslint-plugin-jest": "~26.1.3",
|
||||
"eslint-plugin-mocha": "~10.0.3",
|
||||
"eslint-plugin-promise": "~6.0.0",
|
||||
"eslint-plugin-react": "~7.28.0",
|
||||
"eslint-plugin-tsdoc": "~0.2.14",
|
||||
"eslint-plugin-unicorn": "~40.0.0",
|
||||
"jest": "^26.6.3",
|
||||
"jest-junit": "^10.0.0",
|
||||
|
@ -120,7 +123,7 @@
|
|||
"sinon": "^7.4.2",
|
||||
"ts-jest": "^26.4.4",
|
||||
"ts-node": "^7.0.1",
|
||||
"typescript": "~4.1.3",
|
||||
"typescript": "~4.5.5",
|
||||
"typescript-formatter": "7.1.0"
|
||||
},
|
||||
"jest-junit": {
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
* impact on bundle sizes.
|
||||
* @param condition - The condition that should be true, if the condition is false an error will be thrown.
|
||||
* @param message - The message to include in the error when the condition does not hold.
|
||||
* A number should not be specificed manually. Run policy-check to get shortcode number assigned.
|
||||
* A number should not be specificed manually: use a string.
|
||||
* Before a release, policy-check should be run, which will convert any asserts still using strings to
|
||||
* use numbered error codes instead.
|
||||
*/
|
||||
export function assert(condition: boolean, message: string | number): asserts condition {
|
||||
if (!condition) {
|
||||
|
|
|
@ -12,7 +12,7 @@ describe("Assert", () => {
|
|||
for (const shortCode of ["0x000", "0x03a", "0x200", "0x4321"]) {
|
||||
try {
|
||||
assert(false, Number.parseInt(shortCode, 16));
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
strict(e instanceof Error, "not an error");
|
||||
strict.strictEqual(
|
||||
e.message,
|
||||
|
|
|
@ -1350,6 +1350,63 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/utils": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.20.0.tgz",
|
||||
"integrity": "sha512-lHONGJL1LIO12Ujyx8L8xKbwWSkoUKFSO+0wDAqGXiudWB2EO7WEUT+YZLtVbmOmSllAjLb9tpoIPwpRe5Tn6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@typescript-eslint/scope-manager": "5.20.0",
|
||||
"@typescript-eslint/types": "5.20.0",
|
||||
"@typescript-eslint/typescript-estree": "5.20.0",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.20.0.tgz",
|
||||
"integrity": "sha512-h9KtuPZ4D/JuX7rpp1iKg3zOH0WNEa+ZIXwpW/KWmEFDxlA/HSfCMhiyF1HS/drTICjIbpA6OqkAhrP/zkCStg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.20.0",
|
||||
"@typescript-eslint/visitor-keys": "5.20.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.20.0.tgz",
|
||||
"integrity": "sha512-+d8wprF9GyvPwtoB4CxBAR/s0rpP25XKgnOvMf/gMXYDvlUC3rPFHupdTQ/ow9vn7UDe5rX02ovGYQbv/IUCbg==",
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.20.0.tgz",
|
||||
"integrity": "sha512-36xLjP/+bXusLMrT9fMMYy1KJAGgHhlER2TqpUVDYUQg4w0q/NW/sg4UGAgVwAqb8V4zYg43KMUpM8vV2lve6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.20.0",
|
||||
"@typescript-eslint/visitor-keys": "5.20.0",
|
||||
"debug": "^4.3.2",
|
||||
"globby": "^11.0.4",
|
||||
"is-glob": "^4.0.3",
|
||||
"semver": "^7.3.5",
|
||||
"tsutils": "^3.21.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.20.0.tgz",
|
||||
"integrity": "sha512-1flRpNF+0CAQkMNlTJ6L/Z5jiODG/e5+7mk6XwtPOUS3UrTz3UOiAg9jG2VtKsWI6rZQfy4C6a232QNRZTRGlg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.20.0",
|
||||
"eslint-visitor-keys": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "5.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.9.0.tgz",
|
||||
|
@ -2567,11 +2624,24 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"eslint-plugin-no-null": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-no-null/-/eslint-plugin-no-null-1.0.2.tgz",
|
||||
"integrity": "sha1-EjaoEjkTkKGHetQAfCbnRTQclR8=",
|
||||
"dev": true
|
||||
"eslint-plugin-jest": {
|
||||
"version": "26.1.4",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-26.1.4.tgz",
|
||||
"integrity": "sha512-wgqxujmqc2qpvZqMFWCh6Cniqc8lWpapvXt9j/19DmBDqeDaYhJrSRezYR1SKyemvjx+9e9kny/dgRahraHImA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/utils": "^5.10.0"
|
||||
}
|
||||
},
|
||||
"eslint-plugin-mocha": {
|
||||
"version": "10.0.4",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-10.0.4.tgz",
|
||||
"integrity": "sha512-8wzAeepVY027oBHz/TmBmUr7vhVqoC1KTFeDybFLhbaWKx+aQ7fJJVuUsqcUy+L+G+XvgQBJY+cbAf7hl5DF7Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"eslint-utils": "^3.0.0",
|
||||
"ramda": "^0.28.0"
|
||||
}
|
||||
},
|
||||
"eslint-plugin-promise": {
|
||||
"version": "6.0.0",
|
||||
|
@ -4791,6 +4861,12 @@
|
|||
"integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==",
|
||||
"dev": true
|
||||
},
|
||||
"ramda": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.28.0.tgz",
|
||||
"integrity": "sha512-9QnLuG/kPVgWvMQ4aODhsBUFKOUmnbUnsSXACv+NCQZcHbeb+v8Lodp8OVxtRULN1/xOyYLLaL6npE6dMq5QTA==",
|
||||
"dev": true
|
||||
},
|
||||
"react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
|
@ -5581,9 +5657,9 @@
|
|||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.5.tgz",
|
||||
"integrity": "sha512-6OSu9PTIzmn9TCDiovULTnET6BgXtDYL4Gg4szY+cGsc3JP1dQL8qvE8kShTRx1NIw4Q9IBHlwODjkjWEtMUyA==",
|
||||
"version": "4.5.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz",
|
||||
"integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==",
|
||||
"dev": true
|
||||
},
|
||||
"typescript-formatter": {
|
||||
|
|
|
@ -62,11 +62,14 @@
|
|||
"eslint-plugin-editorconfig": "~3.2.0",
|
||||
"eslint-plugin-eslint-comments": "~3.2.0",
|
||||
"eslint-plugin-import": "~2.25.4",
|
||||
"eslint-plugin-no-null": "~1.0.2",
|
||||
"eslint-plugin-jest": "~26.1.3",
|
||||
"eslint-plugin-mocha": "~10.0.3",
|
||||
"eslint-plugin-promise": "~6.0.0",
|
||||
"eslint-plugin-react": "~7.28.0",
|
||||
"eslint-plugin-tsdoc": "~0.2.14",
|
||||
"eslint-plugin-unicorn": "~40.0.0",
|
||||
"rimraf": "^2.6.2",
|
||||
"typescript": "~4.1.3",
|
||||
"typescript": "~4.5.5",
|
||||
"typescript-formatter": "7.1.0"
|
||||
},
|
||||
"typeValidation": {
|
||||
|
|
|
@ -1297,6 +1297,63 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/utils": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.20.0.tgz",
|
||||
"integrity": "sha512-lHONGJL1LIO12Ujyx8L8xKbwWSkoUKFSO+0wDAqGXiudWB2EO7WEUT+YZLtVbmOmSllAjLb9tpoIPwpRe5Tn6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@typescript-eslint/scope-manager": "5.20.0",
|
||||
"@typescript-eslint/types": "5.20.0",
|
||||
"@typescript-eslint/typescript-estree": "5.20.0",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.20.0.tgz",
|
||||
"integrity": "sha512-h9KtuPZ4D/JuX7rpp1iKg3zOH0WNEa+ZIXwpW/KWmEFDxlA/HSfCMhiyF1HS/drTICjIbpA6OqkAhrP/zkCStg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.20.0",
|
||||
"@typescript-eslint/visitor-keys": "5.20.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.20.0.tgz",
|
||||
"integrity": "sha512-+d8wprF9GyvPwtoB4CxBAR/s0rpP25XKgnOvMf/gMXYDvlUC3rPFHupdTQ/ow9vn7UDe5rX02ovGYQbv/IUCbg==",
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.20.0.tgz",
|
||||
"integrity": "sha512-36xLjP/+bXusLMrT9fMMYy1KJAGgHhlER2TqpUVDYUQg4w0q/NW/sg4UGAgVwAqb8V4zYg43KMUpM8vV2lve6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.20.0",
|
||||
"@typescript-eslint/visitor-keys": "5.20.0",
|
||||
"debug": "^4.3.2",
|
||||
"globby": "^11.0.4",
|
||||
"is-glob": "^4.0.3",
|
||||
"semver": "^7.3.5",
|
||||
"tsutils": "^3.21.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.20.0.tgz",
|
||||
"integrity": "sha512-1flRpNF+0CAQkMNlTJ6L/Z5jiODG/e5+7mk6XwtPOUS3UrTz3UOiAg9jG2VtKsWI6rZQfy4C6a232QNRZTRGlg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.20.0",
|
||||
"eslint-visitor-keys": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "5.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.9.0.tgz",
|
||||
|
@ -2514,11 +2571,24 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"eslint-plugin-no-null": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-no-null/-/eslint-plugin-no-null-1.0.2.tgz",
|
||||
"integrity": "sha1-EjaoEjkTkKGHetQAfCbnRTQclR8=",
|
||||
"dev": true
|
||||
"eslint-plugin-jest": {
|
||||
"version": "26.1.4",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-26.1.4.tgz",
|
||||
"integrity": "sha512-wgqxujmqc2qpvZqMFWCh6Cniqc8lWpapvXt9j/19DmBDqeDaYhJrSRezYR1SKyemvjx+9e9kny/dgRahraHImA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/utils": "^5.10.0"
|
||||
}
|
||||
},
|
||||
"eslint-plugin-mocha": {
|
||||
"version": "10.0.4",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-10.0.4.tgz",
|
||||
"integrity": "sha512-8wzAeepVY027oBHz/TmBmUr7vhVqoC1KTFeDybFLhbaWKx+aQ7fJJVuUsqcUy+L+G+XvgQBJY+cbAf7hl5DF7Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"eslint-utils": "^3.0.0",
|
||||
"ramda": "^0.28.0"
|
||||
}
|
||||
},
|
||||
"eslint-plugin-promise": {
|
||||
"version": "6.0.0",
|
||||
|
@ -4738,6 +4808,12 @@
|
|||
"integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==",
|
||||
"dev": true
|
||||
},
|
||||
"ramda": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.28.0.tgz",
|
||||
"integrity": "sha512-9QnLuG/kPVgWvMQ4aODhsBUFKOUmnbUnsSXACv+NCQZcHbeb+v8Lodp8OVxtRULN1/xOyYLLaL6npE6dMq5QTA==",
|
||||
"dev": true
|
||||
},
|
||||
"react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
|
@ -5528,9 +5604,9 @@
|
|||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.5.tgz",
|
||||
"integrity": "sha512-6OSu9PTIzmn9TCDiovULTnET6BgXtDYL4Gg4szY+cGsc3JP1dQL8qvE8kShTRx1NIw4Q9IBHlwODjkjWEtMUyA==",
|
||||
"version": "4.5.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz",
|
||||
"integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==",
|
||||
"dev": true
|
||||
},
|
||||
"typescript-formatter": {
|
||||
|
|
|
@ -54,11 +54,14 @@
|
|||
"eslint-plugin-editorconfig": "~3.2.0",
|
||||
"eslint-plugin-eslint-comments": "~3.2.0",
|
||||
"eslint-plugin-import": "~2.25.4",
|
||||
"eslint-plugin-no-null": "~1.0.2",
|
||||
"eslint-plugin-jest": "~26.1.3",
|
||||
"eslint-plugin-mocha": "~10.0.3",
|
||||
"eslint-plugin-promise": "~6.0.0",
|
||||
"eslint-plugin-react": "~7.28.0",
|
||||
"eslint-plugin-tsdoc": "~0.2.14",
|
||||
"eslint-plugin-unicorn": "~40.0.0",
|
||||
"rimraf": "^2.6.2",
|
||||
"typescript": "~4.1.3",
|
||||
"typescript": "~4.5.5",
|
||||
"typescript-formatter": "7.1.0"
|
||||
},
|
||||
"typeValidation": {
|
||||
|
|
|
@ -1320,6 +1320,63 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/utils": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.20.0.tgz",
|
||||
"integrity": "sha512-lHONGJL1LIO12Ujyx8L8xKbwWSkoUKFSO+0wDAqGXiudWB2EO7WEUT+YZLtVbmOmSllAjLb9tpoIPwpRe5Tn6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@typescript-eslint/scope-manager": "5.20.0",
|
||||
"@typescript-eslint/types": "5.20.0",
|
||||
"@typescript-eslint/typescript-estree": "5.20.0",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.20.0.tgz",
|
||||
"integrity": "sha512-h9KtuPZ4D/JuX7rpp1iKg3zOH0WNEa+ZIXwpW/KWmEFDxlA/HSfCMhiyF1HS/drTICjIbpA6OqkAhrP/zkCStg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.20.0",
|
||||
"@typescript-eslint/visitor-keys": "5.20.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.20.0.tgz",
|
||||
"integrity": "sha512-+d8wprF9GyvPwtoB4CxBAR/s0rpP25XKgnOvMf/gMXYDvlUC3rPFHupdTQ/ow9vn7UDe5rX02ovGYQbv/IUCbg==",
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.20.0.tgz",
|
||||
"integrity": "sha512-36xLjP/+bXusLMrT9fMMYy1KJAGgHhlER2TqpUVDYUQg4w0q/NW/sg4UGAgVwAqb8V4zYg43KMUpM8vV2lve6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.20.0",
|
||||
"@typescript-eslint/visitor-keys": "5.20.0",
|
||||
"debug": "^4.3.2",
|
||||
"globby": "^11.0.4",
|
||||
"is-glob": "^4.0.3",
|
||||
"semver": "^7.3.5",
|
||||
"tsutils": "^3.21.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.20.0.tgz",
|
||||
"integrity": "sha512-1flRpNF+0CAQkMNlTJ6L/Z5jiODG/e5+7mk6XwtPOUS3UrTz3UOiAg9jG2VtKsWI6rZQfy4C6a232QNRZTRGlg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.20.0",
|
||||
"eslint-visitor-keys": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "5.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.9.0.tgz",
|
||||
|
@ -2537,11 +2594,24 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"eslint-plugin-no-null": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-no-null/-/eslint-plugin-no-null-1.0.2.tgz",
|
||||
"integrity": "sha1-EjaoEjkTkKGHetQAfCbnRTQclR8=",
|
||||
"dev": true
|
||||
"eslint-plugin-jest": {
|
||||
"version": "26.1.4",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-26.1.4.tgz",
|
||||
"integrity": "sha512-wgqxujmqc2qpvZqMFWCh6Cniqc8lWpapvXt9j/19DmBDqeDaYhJrSRezYR1SKyemvjx+9e9kny/dgRahraHImA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/utils": "^5.10.0"
|
||||
}
|
||||
},
|
||||
"eslint-plugin-mocha": {
|
||||
"version": "10.0.4",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-10.0.4.tgz",
|
||||
"integrity": "sha512-8wzAeepVY027oBHz/TmBmUr7vhVqoC1KTFeDybFLhbaWKx+aQ7fJJVuUsqcUy+L+G+XvgQBJY+cbAf7hl5DF7Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"eslint-utils": "^3.0.0",
|
||||
"ramda": "^0.28.0"
|
||||
}
|
||||
},
|
||||
"eslint-plugin-promise": {
|
||||
"version": "6.0.0",
|
||||
|
@ -4761,6 +4831,12 @@
|
|||
"integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==",
|
||||
"dev": true
|
||||
},
|
||||
"ramda": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.28.0.tgz",
|
||||
"integrity": "sha512-9QnLuG/kPVgWvMQ4aODhsBUFKOUmnbUnsSXACv+NCQZcHbeb+v8Lodp8OVxtRULN1/xOyYLLaL6npE6dMq5QTA==",
|
||||
"dev": true
|
||||
},
|
||||
"react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
|
@ -5551,9 +5627,9 @@
|
|||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.5.tgz",
|
||||
"integrity": "sha512-6OSu9PTIzmn9TCDiovULTnET6BgXtDYL4Gg4szY+cGsc3JP1dQL8qvE8kShTRx1NIw4Q9IBHlwODjkjWEtMUyA==",
|
||||
"version": "4.5.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz",
|
||||
"integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==",
|
||||
"dev": true
|
||||
},
|
||||
"typescript-formatter": {
|
||||
|
|
|
@ -57,11 +57,14 @@
|
|||
"eslint-plugin-editorconfig": "~3.2.0",
|
||||
"eslint-plugin-eslint-comments": "~3.2.0",
|
||||
"eslint-plugin-import": "~2.25.4",
|
||||
"eslint-plugin-no-null": "~1.0.2",
|
||||
"eslint-plugin-jest": "~26.1.3",
|
||||
"eslint-plugin-mocha": "~10.0.3",
|
||||
"eslint-plugin-promise": "~6.0.0",
|
||||
"eslint-plugin-react": "~7.28.0",
|
||||
"eslint-plugin-tsdoc": "~0.2.14",
|
||||
"eslint-plugin-unicorn": "~40.0.0",
|
||||
"rimraf": "^2.6.2",
|
||||
"typescript": "~4.1.3",
|
||||
"typescript": "~4.5.5",
|
||||
"typescript-formatter": "7.1.0"
|
||||
},
|
||||
"typeValidation": {
|
||||
|
|
|
@ -1305,6 +1305,63 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/utils": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.20.0.tgz",
|
||||
"integrity": "sha512-lHONGJL1LIO12Ujyx8L8xKbwWSkoUKFSO+0wDAqGXiudWB2EO7WEUT+YZLtVbmOmSllAjLb9tpoIPwpRe5Tn6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
"@typescript-eslint/scope-manager": "5.20.0",
|
||||
"@typescript-eslint/types": "5.20.0",
|
||||
"@typescript-eslint/typescript-estree": "5.20.0",
|
||||
"eslint-scope": "^5.1.1",
|
||||
"eslint-utils": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.20.0.tgz",
|
||||
"integrity": "sha512-h9KtuPZ4D/JuX7rpp1iKg3zOH0WNEa+ZIXwpW/KWmEFDxlA/HSfCMhiyF1HS/drTICjIbpA6OqkAhrP/zkCStg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.20.0",
|
||||
"@typescript-eslint/visitor-keys": "5.20.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.20.0.tgz",
|
||||
"integrity": "sha512-+d8wprF9GyvPwtoB4CxBAR/s0rpP25XKgnOvMf/gMXYDvlUC3rPFHupdTQ/ow9vn7UDe5rX02ovGYQbv/IUCbg==",
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.20.0.tgz",
|
||||
"integrity": "sha512-36xLjP/+bXusLMrT9fMMYy1KJAGgHhlER2TqpUVDYUQg4w0q/NW/sg4UGAgVwAqb8V4zYg43KMUpM8vV2lve6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.20.0",
|
||||
"@typescript-eslint/visitor-keys": "5.20.0",
|
||||
"debug": "^4.3.2",
|
||||
"globby": "^11.0.4",
|
||||
"is-glob": "^4.0.3",
|
||||
"semver": "^7.3.5",
|
||||
"tsutils": "^3.21.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "5.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.20.0.tgz",
|
||||
"integrity": "sha512-1flRpNF+0CAQkMNlTJ6L/Z5jiODG/e5+7mk6XwtPOUS3UrTz3UOiAg9jG2VtKsWI6rZQfy4C6a232QNRZTRGlg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "5.20.0",
|
||||
"eslint-visitor-keys": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "5.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.9.0.tgz",
|
||||
|
@ -2522,11 +2579,24 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"eslint-plugin-no-null": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-no-null/-/eslint-plugin-no-null-1.0.2.tgz",
|
||||
"integrity": "sha1-EjaoEjkTkKGHetQAfCbnRTQclR8=",
|
||||
"dev": true
|
||||
"eslint-plugin-jest": {
|
||||
"version": "26.1.4",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-26.1.4.tgz",
|
||||
"integrity": "sha512-wgqxujmqc2qpvZqMFWCh6Cniqc8lWpapvXt9j/19DmBDqeDaYhJrSRezYR1SKyemvjx+9e9kny/dgRahraHImA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/utils": "^5.10.0"
|
||||
}
|
||||
},
|
||||
"eslint-plugin-mocha": {
|
||||
"version": "10.0.4",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-10.0.4.tgz",
|
||||
"integrity": "sha512-8wzAeepVY027oBHz/TmBmUr7vhVqoC1KTFeDybFLhbaWKx+aQ7fJJVuUsqcUy+L+G+XvgQBJY+cbAf7hl5DF7Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"eslint-utils": "^3.0.0",
|
||||
"ramda": "^0.28.0"
|
||||
}
|
||||
},
|
||||
"eslint-plugin-promise": {
|
||||
"version": "6.0.0",
|
||||
|
@ -4746,6 +4816,12 @@
|
|||
"integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==",
|
||||
"dev": true
|
||||
},
|
||||
"ramda": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.28.0.tgz",
|
||||
"integrity": "sha512-9QnLuG/kPVgWvMQ4aODhsBUFKOUmnbUnsSXACv+NCQZcHbeb+v8Lodp8OVxtRULN1/xOyYLLaL6npE6dMq5QTA==",
|
||||
"dev": true
|
||||
},
|
||||
"react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
|
@ -5536,9 +5612,9 @@
|
|||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.5.tgz",
|
||||
"integrity": "sha512-6OSu9PTIzmn9TCDiovULTnET6BgXtDYL4Gg4szY+cGsc3JP1dQL8qvE8kShTRx1NIw4Q9IBHlwODjkjWEtMUyA==",
|
||||
"version": "4.5.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz",
|
||||
"integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==",
|
||||
"dev": true
|
||||
},
|
||||
"typescript-formatter": {
|
||||
|
|
|
@ -55,11 +55,14 @@
|
|||
"eslint-plugin-editorconfig": "~3.2.0",
|
||||
"eslint-plugin-eslint-comments": "~3.2.0",
|
||||
"eslint-plugin-import": "~2.25.4",
|
||||
"eslint-plugin-no-null": "~1.0.2",
|
||||
"eslint-plugin-jest": "~26.1.3",
|
||||
"eslint-plugin-mocha": "~10.0.3",
|
||||
"eslint-plugin-promise": "~6.0.0",
|
||||
"eslint-plugin-react": "~7.28.0",
|
||||
"eslint-plugin-tsdoc": "~0.2.14",
|
||||
"eslint-plugin-unicorn": "~40.0.0",
|
||||
"rimraf": "^2.6.2",
|
||||
"typescript": "~4.1.3",
|
||||
"typescript": "~4.5.5",
|
||||
"typescript-formatter": "7.1.0"
|
||||
},
|
||||
"typeValidation": {
|
||||
|
|
|
@ -11,13 +11,13 @@ aliases:
|
|||
|
||||
<!-- AUTO-GENERATED-CONTENT:START (INCLUDE:path=packages/dds/sequence/README.md&start=2&end=252) -->
|
||||
The **@fluidframework/sequence** packages supports distributed data structures which are list-like. It includes
|
||||
SharedString for storing storing and simultaneously editing a sequence of text. Note that SharedString is a sequence
|
||||
SharedString for storing and simultaneously editing a sequence of text. Note that SharedString is a sequence
|
||||
DDS but it has additional specialized features and behaviors for working with text.
|
||||
|
||||
Sequence DDSes share a common base class, SharedSegmentSequence. For the remainder of this document, the term
|
||||
*sequence* refers to this base class.
|
||||
|
||||
*Item*s are the individual units that are stored within the sequence (i.e. in a SharedString the items are characters),
|
||||
*Item*s are the individual units that are stored within the sequence (e.g. in a SharedString the items are characters),
|
||||
but regardless of the type of data stored in the sequence, every item in a sequence is at a specific *position* starting
|
||||
at 0, similar to an array. However, sequences differ from arrays in that the positions can move as local and remote
|
||||
editors make modifications to the sequence.
|
||||
|
@ -64,7 +64,7 @@ sequence, to insert at the end.
|
|||
// content:
|
||||
// positions:
|
||||
|
||||
// insert text at positions 0
|
||||
// insert text at position 0
|
||||
sharedString.insertText(0, "hi");
|
||||
// content: hi
|
||||
// positions: 01
|
||||
|
|
|
@ -28,26 +28,26 @@
|
|||
}
|
||||
},
|
||||
"@microsoft/api-extractor-model": {
|
||||
"version": "7.15.3",
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.15.3.tgz",
|
||||
"integrity": "sha512-NkSjolmSI7NGvbdz0Y7kjQfdpD+j9E5CwXTxEyjDqxd10MI7GXV8DnAsQ57GFJcgHKgTjf2aUnYfMJ9w3aMicw==",
|
||||
"version": "7.17.2",
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.17.2.tgz",
|
||||
"integrity": "sha512-fYfCeBeLm7jnZligC64qHiH4/vzswFLDfyPpX+uKO36OI2kIeMHrYG0zaezmuinKvE4vg1dAz38zZeDbPvBKGg==",
|
||||
"requires": {
|
||||
"@microsoft/tsdoc": "0.13.2",
|
||||
"@microsoft/tsdoc-config": "~0.15.2",
|
||||
"@rushstack/node-core-library": "3.45.0"
|
||||
"@microsoft/tsdoc": "0.14.1",
|
||||
"@microsoft/tsdoc-config": "~0.16.1",
|
||||
"@rushstack/node-core-library": "3.45.4"
|
||||
}
|
||||
},
|
||||
"@microsoft/tsdoc": {
|
||||
"version": "0.13.2",
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.13.2.tgz",
|
||||
"integrity": "sha512-WrHvO8PDL8wd8T2+zBGKrMwVL5IyzR3ryWUsl0PXgEV0QHup4mTLi0QcATefGI6Gx9Anu7vthPyyyLpY0EpiQg=="
|
||||
"version": "0.14.1",
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.1.tgz",
|
||||
"integrity": "sha512-6Wci+Tp3CgPt/B9B0a3J4s3yMgLNSku6w5TV6mN+61C71UqsRBv2FUibBf3tPGlNxebgPHMEUzKpb1ggE8KCKw=="
|
||||
},
|
||||
"@microsoft/tsdoc-config": {
|
||||
"version": "0.15.2",
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.15.2.tgz",
|
||||
"integrity": "sha512-mK19b2wJHSdNf8znXSMYVShAHktVr/ib0Ck2FA3lsVBSEhSI/TfXT7DJQkAYgcztTuwazGcg58ZjYdk0hTCVrA==",
|
||||
"version": "0.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.16.1.tgz",
|
||||
"integrity": "sha512-2RqkwiD4uN6MLnHFljqBlZIXlt/SaUT6cuogU1w2ARw4nKuuppSmR0+s+NC+7kXBQykd9zzu0P4HtBpZT5zBpQ==",
|
||||
"requires": {
|
||||
"@microsoft/tsdoc": "0.13.2",
|
||||
"@microsoft/tsdoc": "0.14.1",
|
||||
"ajv": "~6.12.6",
|
||||
"jju": "~1.4.0",
|
||||
"resolve": "~1.19.0"
|
||||
|
@ -97,9 +97,9 @@
|
|||
}
|
||||
},
|
||||
"@rushstack/node-core-library": {
|
||||
"version": "3.45.0",
|
||||
"resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.45.0.tgz",
|
||||
"integrity": "sha512-YMuIJl19vQT1+g/OU9mLY6T5ZBT9uDlmeXExDQACpGuxTJW+LHNbk/lRX+eCApQI2eLBlaL4U68r3kZlqwbdmw==",
|
||||
"version": "3.45.4",
|
||||
"resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.45.4.tgz",
|
||||
"integrity": "sha512-FMoEQWjK7nWAO2uFgV1eVpVhY9ZDGOdIIomi9zTej64cKJ+8/Nvu+ny0xKaUDEjw/ALftN2D2ml7L0RDpW/Z9g==",
|
||||
"requires": {
|
||||
"@types/node": "12.20.24",
|
||||
"colors": "~1.2.1",
|
||||
|
@ -117,11 +117,6 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.24.tgz",
|
||||
"integrity": "sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ=="
|
||||
},
|
||||
"colors": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/colors/-/colors-1.2.5.tgz",
|
||||
"integrity": "sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg=="
|
||||
},
|
||||
"fs-extra": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
|
||||
|
@ -135,21 +130,14 @@
|
|||
}
|
||||
},
|
||||
"@rushstack/ts-command-line": {
|
||||
"version": "4.10.6",
|
||||
"resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.10.6.tgz",
|
||||
"integrity": "sha512-Y3GkUag39sTIlukDg9mUp8MCHrrlJ27POrBNRQGc/uF+VVgX8M7zMzHch5zP6O1QVquWgD7Engdpn2piPYaS/g==",
|
||||
"version": "4.10.10",
|
||||
"resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.10.10.tgz",
|
||||
"integrity": "sha512-F+MH7InPDXqX40qvvcEsnvPpmg566SBpfFqj2fcCh8RjM6AyOoWlXc8zx7giBD3ZN85NVAEjZAgrcLU0z+R2yg==",
|
||||
"requires": {
|
||||
"@types/argparse": "1.0.38",
|
||||
"argparse": "~1.0.9",
|
||||
"colors": "~1.2.1",
|
||||
"string-argv": "~0.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"colors": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/colors/-/colors-1.2.5.tgz",
|
||||
"integrity": "sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@szmarczak/http-timer": {
|
||||
|
@ -207,29 +195,17 @@
|
|||
}
|
||||
},
|
||||
"@tylerbu/custom-api-documenter": {
|
||||
"version": "0.3.3-tylerbu-6-prerelease",
|
||||
"resolved": "https://registry.npmjs.org/@tylerbu/custom-api-documenter/-/custom-api-documenter-0.3.3-tylerbu-6-prerelease.tgz",
|
||||
"integrity": "sha512-IZ6Q0U3hUg2B3WERCU8tMYnQqZxRkO15O76+HqAHjy598E7CY4lEIvrceuozjqAwXsF2StW2YaadaaHRw8c++Q==",
|
||||
"version": "0.3.4-1",
|
||||
"resolved": "https://registry.npmjs.org/@tylerbu/custom-api-documenter/-/custom-api-documenter-0.3.4-1.tgz",
|
||||
"integrity": "sha512-bGiiuKEUDQ20Ttxm8GT928Jb1DRbOseCZbrDUzQrGQSd6IOxEIscpkTVJoccVkcF36LcColQLw+UEoGwZOeN6w==",
|
||||
"requires": {
|
||||
"@microsoft/api-extractor-model": "^7.15.3",
|
||||
"@microsoft/tsdoc": "0.13.2",
|
||||
"@rushstack/node-core-library": "^3.45.0",
|
||||
"@rushstack/ts-command-line": "^4.10.6",
|
||||
"colors": "~1.4.0",
|
||||
"js-yaml": "~4.1.0",
|
||||
"resolve": "~1.21.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"resolve": {
|
||||
"version": "1.21.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.21.1.tgz",
|
||||
"integrity": "sha512-lfEImVbnolPuaSZuLQ52cAxPBHeI77sPwCOWRdy12UG/CNa8an7oBHH1R+Fp1/mUqSJi4c8TIP6FOIPSZAUrEQ==",
|
||||
"requires": {
|
||||
"is-core-module": "^2.8.0",
|
||||
"path-parse": "^1.0.7",
|
||||
"supports-preserve-symlinks-flag": "^1.0.0"
|
||||
}
|
||||
}
|
||||
"@microsoft/api-extractor-model": "~7.17.2",
|
||||
"@microsoft/tsdoc": "0.14.1",
|
||||
"@rushstack/node-core-library": "^3.45.4",
|
||||
"@rushstack/ts-command-line": "^4.5.0",
|
||||
"colors": "~1.2.1",
|
||||
"js-yaml": "~3.13.1",
|
||||
"resolve": "~1.17.0"
|
||||
}
|
||||
},
|
||||
"@tylerbu/dl-cli": {
|
||||
|
@ -1430,9 +1406,9 @@
|
|||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"colors": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
|
||||
"integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA=="
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/colors/-/colors-1.2.5.tgz",
|
||||
"integrity": "sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg=="
|
||||
},
|
||||
"combined-stream": {
|
||||
"version": "1.0.8",
|
||||
|
@ -2299,6 +2275,11 @@
|
|||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
||||
},
|
||||
"esprima": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
|
||||
},
|
||||
"execa": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
|
||||
|
@ -3592,18 +3573,12 @@
|
|||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
||||
"version": "3.13.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
|
||||
"integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
|
||||
"requires": {
|
||||
"argparse": "^2.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
|
||||
}
|
||||
"argparse": "^1.0.7",
|
||||
"esprima": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"json-parse-even-better-errors": {
|
||||
|
@ -5779,11 +5754,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"supports-preserve-symlinks-flag": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
||||
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="
|
||||
},
|
||||
"sync-request": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz",
|
||||
|
@ -6512,11 +6482,11 @@
|
|||
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="
|
||||
},
|
||||
"z-schema": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.2.tgz",
|
||||
"integrity": "sha512-40TH47ukMHq5HrzkeVE40Ad7eIDKaRV2b+Qpi2prLc9X9eFJFzV7tMe5aH12e6avaSS/u5l653EQOv+J9PirPw==",
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.3.tgz",
|
||||
"integrity": "sha512-sGvEcBOTNum68x9jCpCVGPFJ6mWnkD0YxOcddDlJHRx3tKdB2q8pCHExMVZo/AV/6geuVJXG7hljDaWG8+5GDw==",
|
||||
"requires": {
|
||||
"commander": "^2.7.1",
|
||||
"commander": "^2.20.3",
|
||||
"lodash.get": "^4.4.2",
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"validator": "^13.7.0"
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
"start": "npm run build:md-magic && hugo server"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tylerbu/custom-api-documenter": "0.3.3-tylerbu-6-prerelease",
|
||||
"@tylerbu/custom-api-documenter": "~0.3.4-1",
|
||||
"@tylerbu/dl-cli": "1.1.2-tylerbu-0",
|
||||
"@tylerbu/markdown-magic": "^2.4.0-tylerbu-1",
|
||||
"@vscode/codicons": "0.0.28",
|
||||
|
|
|
@ -30,11 +30,13 @@ module.exports = env => {
|
|||
}],
|
||||
exclude: /node_modules/
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
use: [require.resolve("source-map-loader")],
|
||||
enforce: "pre"
|
||||
},
|
||||
// This example currently has missing sourcemap issues.
|
||||
// Disabling source mapping allows it to be runnable with these issues.
|
||||
// {
|
||||
// test: /\.js$/,
|
||||
// use: [require.resolve("source-map-loader")],
|
||||
// enforce: "pre"
|
||||
// },
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
|
@ -83,8 +85,6 @@ module.exports = env => {
|
|||
},
|
||||
devServer: {
|
||||
host: "0.0.0.0",
|
||||
onBeforeSetupMiddleware: (devServer) => fluidRoute.before(devServer.app, devServer, env),
|
||||
onAfterSetupMiddleware: (devServer) => fluidRoute.after(devServer.app, devServer, __dirname, env),
|
||||
},
|
||||
// This impacts which files are watched by the dev server (and likely by webpack if watch is true).
|
||||
// This should be configurable under devServer.static.watch
|
||||
|
|
|
@ -197,7 +197,7 @@ describeLoaderCompat("Table Document with Interception", (getTestObjectProvider)
|
|||
let asserted: boolean = false;
|
||||
try {
|
||||
tableDocumentWithInterception.setCellValue(cell.row, cell.col, cell.value);
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
assert.strictEqual(error.message,
|
||||
"Interception wrapper method called recursively from the interception callback",
|
||||
"We should have caught an assert in setCellValue because it detects an infinite recursion");
|
||||
|
|
|
@ -81,13 +81,14 @@ module.exports = env => {
|
|||
libraryTarget: "umd",
|
||||
globalObject: 'self',
|
||||
},
|
||||
devServer: {
|
||||
onBeforeSetupMiddleware: (devServer) => fluidRoute.before(devServer.app, devServer, env),
|
||||
onAfterSetupMiddleware: (devServer) => fluidRoute.after(devServer.app, devServer, __dirname, env),
|
||||
watchOptions: {
|
||||
ignored: "**/node_modules/**",
|
||||
}
|
||||
},
|
||||
// This impacts which files are watched by the dev server (and likely by webpack if watch is true).
|
||||
// This should be configurable under devServer.static.watch
|
||||
// (see https://github.com/webpack/webpack-dev-server/blob/master/migration-v4.md) but that does not seem to work.
|
||||
// The CLI options for disabling watching don't seem to work either, so this may be a symptom of using webpack4 with the newer webpack-cli and webpack-dev-server.
|
||||
watchOptions: {
|
||||
ignored: "**/node_modules/**",
|
||||
}
|
||||
},
|
||||
isProduction ? require("./webpack.prod") : require("./webpack.dev"));
|
||||
isProduction ? require("./webpack.prod") : require("./webpack.dev"),
|
||||
fluidRoute.devServerConfig(__dirname, env));
|
||||
};
|
||||
|
|
|
@ -30,7 +30,6 @@ import {
|
|||
SequenceDeltaEvent,
|
||||
} from "@fluidframework/sequence";
|
||||
import { ISharedDirectory, SharedDirectory } from "@fluidframework/map";
|
||||
import { IFluidHTMLOptions } from "@fluidframework/view-interfaces";
|
||||
import { IEvent } from "@fluidframework/common-definitions";
|
||||
import { clamp, emptyArray, randomId, TagName, TokenList } from "../util";
|
||||
import { IHTMLAttributes } from "../util/attr";
|
||||
|
@ -43,14 +42,13 @@ export const enum DocSegmentKind {
|
|||
paragraph = "<p>",
|
||||
lineBreak = "<br>",
|
||||
beginTags = "<t>",
|
||||
inclusion = "<?>",
|
||||
endTags = "</>",
|
||||
|
||||
// Special case for LocalReference to end of document. (See comments on 'endOfTextSegment').
|
||||
endOfText = "eot",
|
||||
}
|
||||
|
||||
const tilesAndRanges = new Set([DocSegmentKind.paragraph, DocSegmentKind.lineBreak, DocSegmentKind.beginTags, DocSegmentKind.inclusion]);
|
||||
const tilesAndRanges = new Set([DocSegmentKind.paragraph, DocSegmentKind.lineBreak, DocSegmentKind.beginTags]);
|
||||
|
||||
const enum Workaround { checkpoint = "*" }
|
||||
|
||||
|
@ -95,9 +93,6 @@ const empty = Object.freeze({});
|
|||
|
||||
export const getCss = (segment: ISegment): Readonly<{ style?: string, classList?: string }> => segment.properties || empty;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
export const getComponentOptions = (segment: ISegment): IFluidHTMLOptions | undefined => (segment.properties && segment.properties.componentOptions) || empty;
|
||||
|
||||
type LeafAction = (position: number, segment: ISegment, startOffset: number, endOffset: number) => boolean;
|
||||
|
||||
/**
|
||||
|
@ -153,9 +148,8 @@ export class FlowDocument extends LazyLoadedDataObject<ISharedDirectory, IFlowDo
|
|||
|
||||
private static readonly paragraphProperties = Object.freeze({ [reservedTileLabelsKey]: [DocSegmentKind.paragraph, DocTile.checkpoint], tag: TagName.p });
|
||||
private static readonly lineBreakProperties = Object.freeze({ [reservedTileLabelsKey]: [DocSegmentKind.lineBreak, DocTile.checkpoint] });
|
||||
private static readonly inclusionProperties = Object.freeze({ [reservedTileLabelsKey]: [DocSegmentKind.inclusion, DocTile.checkpoint] });
|
||||
private static readonly tagsProperties = Object.freeze({
|
||||
[reservedTileLabelsKey]: [DocSegmentKind.inclusion, DocTile.checkpoint],
|
||||
[reservedTileLabelsKey]: [DocTile.checkpoint],
|
||||
[reservedRangeLabelsKey]: [DocSegmentKind.beginTags],
|
||||
});
|
||||
|
||||
|
@ -318,14 +312,6 @@ export class FlowDocument extends LazyLoadedDataObject<ISharedDirectory, IFlowDo
|
|||
this.sharedString.insertMarker(position, ReferenceType.Tile, FlowDocument.lineBreakProperties);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
public insertComponent(position: number, handle: IFluidHandle, view: string, componentOptions: object, style?: string, classList?: string[]) {
|
||||
this.sharedString.insertMarker(position, ReferenceType.Tile, Object.freeze({
|
||||
...FlowDocument.inclusionProperties,
|
||||
componentOptions, handle, style, classList: classList && classList.join(" "), view,
|
||||
}));
|
||||
}
|
||||
|
||||
public setFormat(position: number, tag: TagName) {
|
||||
const { start } = this.findParagraph(position);
|
||||
|
||||
|
|
|
@ -4,10 +4,9 @@
|
|||
*/
|
||||
|
||||
import { FluidObject } from "@fluidframework/core-interfaces";
|
||||
import { IFluidHTMLView } from "@fluidframework/view-interfaces";
|
||||
import { paste } from "../clipboard/paste";
|
||||
import { DocSegmentKind, FlowDocument, getDocSegmentKind } from "../document";
|
||||
import { caretEnter, Direction, getDeltaX, getDeltaY, KeyCode } from "../util";
|
||||
import { FlowDocument } from "../document";
|
||||
import { Direction, getDeltaX, KeyCode } from "../util";
|
||||
import { ownsNode } from "../util/event";
|
||||
import { IFormatterState, RootFormatter } from "../view/formatter";
|
||||
import { Layout } from "../view/layout";
|
||||
|
@ -15,22 +14,14 @@ import { Caret } from "./caret";
|
|||
import { debug } from "./debug";
|
||||
import * as styles from "./index.css";
|
||||
|
||||
/**
|
||||
* The Host provides the Editor with a registry of view factories which will be used to render components that have
|
||||
* been inserted into the document.
|
||||
*/
|
||||
export interface IFluidHTMLViewFactory {
|
||||
createView(model: FluidObject, scope?: FluidObject): IFluidHTMLView;
|
||||
}
|
||||
|
||||
export class Editor {
|
||||
private readonly layout: Layout;
|
||||
private readonly caret: Caret;
|
||||
private readonly caretSync: () => void;
|
||||
private get doc() { return this.layout.doc; }
|
||||
|
||||
constructor(doc: FlowDocument, private readonly root: HTMLElement, formatter: Readonly<RootFormatter<IFormatterState>>, viewFactoryRegistry?: Map<string, IFluidHTMLViewFactory>, scope?: FluidObject) {
|
||||
this.layout = new Layout(doc, root, formatter, viewFactoryRegistry, scope);
|
||||
constructor(doc: FlowDocument, private readonly root: HTMLElement, formatter: Readonly<RootFormatter<IFormatterState>>, scope?: FluidObject) {
|
||||
this.layout = new Layout(doc, root, formatter);
|
||||
this.caret = new Caret(this.layout);
|
||||
|
||||
let scheduled = false;
|
||||
|
@ -122,14 +113,6 @@ export class Editor {
|
|||
break;
|
||||
}
|
||||
|
||||
case KeyCode.arrowLeft:
|
||||
this.enterIfInclusion(e, this.caret.position - 1, Direction.left);
|
||||
break;
|
||||
|
||||
case KeyCode.arrowRight:
|
||||
this.enterIfInclusion(e, this.caret.position, Direction.right);
|
||||
break;
|
||||
|
||||
// Note: Chrome 69 delivers backspace on 'keydown' only (i.e., 'keypress' is not fired.)
|
||||
case KeyCode.backspace: {
|
||||
this.delete(e, Direction.left);
|
||||
|
@ -190,17 +173,4 @@ export class Editor {
|
|||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
private enterIfInclusion(e: Event, position: number, direction: Direction) {
|
||||
const { segment } = this.doc.getSegmentAndOffset(position);
|
||||
const kind = getDocSegmentKind(segment);
|
||||
if (kind === DocSegmentKind.inclusion) {
|
||||
const { node } = this.layout.segmentAndOffsetToNodeAndOffset(segment, 0);
|
||||
const bounds = this.caret.bounds;
|
||||
debug("Entering inclusion: (dx=%d,dy=%d,bounds=%o)", getDeltaX(direction), getDeltaY(direction), bounds);
|
||||
if (caretEnter(node as Element, direction, bounds)) {
|
||||
this.consume(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
export { Editor, IFluidHTMLViewFactory } from "./editor";
|
||||
export { Editor } from "./editor";
|
||||
|
|
|
@ -4,12 +4,9 @@
|
|||
*/
|
||||
|
||||
import { assert } from "@fluidframework/common-utils";
|
||||
import { FluidObject } from "@fluidframework/core-interfaces";
|
||||
import { Marker, TextSegment } from "@fluidframework/merge-tree";
|
||||
import { IFluidHTMLView } from "@fluidframework/view-interfaces";
|
||||
import { DocSegmentKind, getComponentOptions, getCss, getDocSegmentKind } from "../document";
|
||||
import * as styles from "../editor/index.css";
|
||||
import { caretEnter, Direction, emptyObject, Rect, TagName } from "../util";
|
||||
import { DocSegmentKind, getCss, getDocSegmentKind } from "../document";
|
||||
import { emptyObject, TagName } from "../util";
|
||||
import { getAttrs, syncAttrs } from "../util/attr";
|
||||
|
||||
import { Formatter, IFormatterState, RootFormatter } from "../view/formatter";
|
||||
|
@ -42,11 +39,6 @@ class HtmlFormatter extends RootFormatter<IFormatterState> {
|
|||
return { state, consumed: true };
|
||||
}
|
||||
|
||||
case DocSegmentKind.inclusion: {
|
||||
layout.pushFormat(inclusionFormatter, emptyObject);
|
||||
return { state, consumed: false };
|
||||
}
|
||||
|
||||
case DocSegmentKind.beginTags: {
|
||||
layout.pushFormat(tagsFormatter, emptyObject);
|
||||
return { state, consumed: true };
|
||||
|
@ -67,59 +59,6 @@ class HtmlFormatter extends RootFormatter<IFormatterState> {
|
|||
public onChange() { }
|
||||
}
|
||||
|
||||
interface IInclusionState {
|
||||
root?: HTMLElement;
|
||||
slot?: HTMLElement;
|
||||
view?: Promise<IFluidHTMLView>;
|
||||
}
|
||||
|
||||
export class InclusionFormatter extends Formatter<IInclusionState> {
|
||||
public begin(layout: Layout, init: Readonly<Partial<IInclusionState>>, prevState?: Readonly<IInclusionState>) {
|
||||
const segment = layout.segment;
|
||||
|
||||
const state: IInclusionState = prevState || {};
|
||||
|
||||
if (!state.root) {
|
||||
const marker = segment as Marker;
|
||||
|
||||
state.root = document.createElement(TagName.span);
|
||||
state.root.contentEditable = "false";
|
||||
|
||||
state.slot = document.createElement(
|
||||
getComponentOptions(segment).display === "block"
|
||||
? TagName.div
|
||||
: TagName.span);
|
||||
|
||||
const viewFactory = layout.viewFactoryRegistry.get(marker.properties.view);
|
||||
state.view = layout.doc.getComponentFromMarker(marker).then((component: FluidObject) => {
|
||||
if (viewFactory) {
|
||||
// We found a view class registered for this marker's view type
|
||||
const view = viewFactory.createView(component, layout.scope);
|
||||
view.render(state.slot);
|
||||
caretEnter(state.slot, Direction.right, Rect.empty);
|
||||
state.slot.focus();
|
||||
return view;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
syncCss(state.root, getCss(segment), styles.inclusion);
|
||||
layout.pushNode(state.root);
|
||||
layout.emitNode(state.slot);
|
||||
return state;
|
||||
}
|
||||
|
||||
public visit(layout: Layout, state: Readonly<IInclusionState>) {
|
||||
assert(getDocSegmentKind(layout.segment) === DocSegmentKind.inclusion, "Layout segment has unexpected kind!");
|
||||
layout.popFormat();
|
||||
return { state, consumed: true };
|
||||
}
|
||||
|
||||
public end(layout: Layout) {
|
||||
layout.popNode();
|
||||
}
|
||||
}
|
||||
|
||||
interface ITagsState extends IFormatterState { root?: HTMLElement; pTag: TagName; popCount: number; }
|
||||
interface ITagsProps { tags?: TagName[]; }
|
||||
|
||||
|
@ -163,11 +102,6 @@ class TagsFormatter extends Formatter<ITagsState> {
|
|||
return { state, consumed: true };
|
||||
}
|
||||
|
||||
case DocSegmentKind.inclusion: {
|
||||
layout.pushFormat(inclusionFormatter, emptyObject);
|
||||
return { state, consumed: false };
|
||||
}
|
||||
|
||||
case DocSegmentKind.beginTags: {
|
||||
layout.pushFormat(tagsFormatter, emptyObject);
|
||||
return { state, consumed: true };
|
||||
|
@ -231,16 +165,6 @@ class ParagraphFormatter extends Formatter<IParagraphState> {
|
|||
return { state, consumed: true };
|
||||
}
|
||||
|
||||
case DocSegmentKind.inclusion: {
|
||||
// If the inclusion is a block, it implicitly terminates the current paragraph.
|
||||
if (getComponentOptions(segment).display === "block") {
|
||||
layout.popFormat();
|
||||
}
|
||||
|
||||
layout.pushFormat(inclusionFormatter, emptyObject);
|
||||
return { state, consumed: false };
|
||||
}
|
||||
|
||||
default:
|
||||
debug("%s@%d: Unhanded DocSegmentKind '%s'.", this, layout.position, kind);
|
||||
layout.popFormat();
|
||||
|
@ -294,7 +218,6 @@ class TextFormatter extends Formatter<ITextState> {
|
|||
}
|
||||
|
||||
export const htmlFormatter = Object.freeze(new HtmlFormatter());
|
||||
const inclusionFormatter = Object.freeze(new InclusionFormatter());
|
||||
const paragraphFormatter = Object.freeze(new ParagraphFormatter(TagName.p));
|
||||
const tagsFormatter = Object.freeze(new TagsFormatter());
|
||||
const textFormatter = Object.freeze(new TextFormatter());
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
import { ContainerViewRuntimeFactory } from "@fluid-example/example-utils";
|
||||
|
||||
export { FlowDocument } from "./document";
|
||||
export { Editor, IFluidHTMLViewFactory } from "./editor";
|
||||
export { Editor } from "./editor";
|
||||
import { WebFlow, WebflowView } from "./host";
|
||||
export { htmlFormatter } from "./html/formatters";
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports
|
||||
require("jsdom-global")("", { url: "http://localhost" });
|
||||
window.performance.mark = window.performance.mark || (() => { });
|
||||
window.performance.measure = window.performance.measure || (() => { });
|
||||
window.performance.mark ??= (() => undefined as PerformanceMark);
|
||||
window.performance.measure ??= (() => undefined as PerformanceMeasure);
|
||||
|
||||
import { strict as assert } from "assert";
|
||||
import { requestFluidObject } from "@fluidframework/runtime-utils";
|
||||
|
|
|
@ -5,11 +5,9 @@
|
|||
|
||||
import assert from "assert";
|
||||
import { EventEmitter } from "events";
|
||||
import { FluidObject } from "@fluidframework/core-interfaces";
|
||||
import { ISegment, LocalReference, MergeTreeMaintenanceType } from "@fluidframework/merge-tree";
|
||||
import { SequenceEvent } from "@fluidframework/sequence";
|
||||
import { FlowDocument } from "../document";
|
||||
import { IFluidHTMLViewFactory } from "../editor";
|
||||
import { clamp, Dom, done, emptyObject, getSegmentRange, hasTagName, isTextNode, TagName } from "../util";
|
||||
import { extractRef, updateRef } from "../util/localref";
|
||||
import { debug } from "./debug";
|
||||
|
@ -92,7 +90,7 @@ export class Layout extends EventEmitter {
|
|||
private renderPromise = done;
|
||||
private renderResolver: () => void;
|
||||
|
||||
constructor(public readonly doc: FlowDocument, public readonly root: Element, formatter: Readonly<RootFormatter<IFormatterState>>, public readonly viewFactoryRegistry: Map<string, IFluidHTMLViewFactory> = new Map(), public readonly scope?: FluidObject) {
|
||||
constructor(public readonly doc: FlowDocument, public readonly root: Element, formatter: Readonly<RootFormatter<IFormatterState>>) {
|
||||
super();
|
||||
|
||||
let scheduled = false;
|
||||
|
|
|
@ -81,13 +81,14 @@ module.exports = env => {
|
|||
libraryTarget: "umd",
|
||||
globalObject: 'self',
|
||||
},
|
||||
devServer: {
|
||||
onBeforeSetupMiddleware: (devServer) => fluidRoute.before(devServer.app, devServer, env),
|
||||
onAfterSetupMiddleware: (devServer) => fluidRoute.after(devServer.app, devServer, __dirname, env),
|
||||
watchOptions: {
|
||||
ignored: "**/node_modules/**",
|
||||
}
|
||||
},
|
||||
// This impacts which files are watched by the dev server (and likely by webpack if watch is true).
|
||||
// This should be configurable under devServer.static.watch
|
||||
// (see https://github.com/webpack/webpack-dev-server/blob/master/migration-v4.md) but that does not seem to work.
|
||||
// The CLI options for disabling watching don't seem to work either, so this may be a symptom of using webpack4 with the newer webpack-cli and webpack-dev-server.
|
||||
watchOptions: {
|
||||
ignored: "**/node_modules/**",
|
||||
}
|
||||
},
|
||||
isProduction ? require("./webpack.prod") : require("./webpack.dev"));
|
||||
isProduction ? require("./webpack.prod") : require("./webpack.dev"),
|
||||
fluidRoute.devServerConfig(__dirname, env));
|
||||
};
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
"@fluidframework/container-runtime-definitions": "^0.60.1000",
|
||||
"@fluidframework/core-interfaces": "^0.43.1000",
|
||||
"@fluidframework/driver-definitions": "^0.47.1000-0",
|
||||
"@fluidframework/driver-utils": "^0.60.1000",
|
||||
"@fluidframework/register-collection": "^0.60.1000",
|
||||
"@fluidframework/request-handler": "^0.60.1000",
|
||||
"@fluidframework/routerlicious-driver": "^0.60.1000",
|
||||
|
|
|
@ -5,32 +5,19 @@
|
|||
|
||||
import { IContainer, IFluidModuleWithDetails } from "@fluidframework/container-definitions";
|
||||
import { Loader } from "@fluidframework/container-loader";
|
||||
import { ensureFluidResolvedUrl } from "@fluidframework/driver-utils";
|
||||
import { requestFluidObject } from "@fluidframework/runtime-utils";
|
||||
import { createTinyliciousCreateNewRequest } from "@fluidframework/tinylicious-driver";
|
||||
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
import { TinyliciousService } from "./tinyliciousService";
|
||||
import { AppView } from "./appView";
|
||||
import { containerKillBitId, InventoryListContainerRuntimeFactory } from "./containerCode";
|
||||
import { IContainerKillBit } from "./containerKillBit";
|
||||
import { extractStringData, fetchData, applyStringData, writeData } from "./dataHelpers";
|
||||
import { IInventoryList } from "./inventoryList";
|
||||
|
||||
// In interacting with the service, we need to be explicit about whether we're creating a new document vs. loading
|
||||
// an existing one. We also need to provide the unique ID for the document we are creating or loading from.
|
||||
|
||||
// In this app, we'll choose to create a new document when navigating directly to http://localhost:8080. For the ID,
|
||||
// we'll choose to use the current timestamp. We'll also choose to interpret the URL hash as an existing document's
|
||||
// ID to load from, so the URL for a document load will look something like http://localhost:8080/#1596520748752.
|
||||
// These policy choices are arbitrary for demo purposes, and can be changed however you'd like.
|
||||
let createNew = false;
|
||||
if (location.hash.length === 0) {
|
||||
createNew = true;
|
||||
location.hash = Date.now().toString();
|
||||
}
|
||||
const documentId = location.hash.substring(1);
|
||||
document.title = documentId;
|
||||
import { TinyliciousService } from "./tinyliciousService";
|
||||
|
||||
async function getInventoryListFromContainer(container: IContainer): Promise<IInventoryList> {
|
||||
// Since we're using a ContainerRuntimeFactoryWithDefaultDataStore, our inventory list is available at the URL "/".
|
||||
|
@ -61,21 +48,42 @@ async function start(): Promise<void> {
|
|||
|
||||
let fetchedData: string | undefined;
|
||||
let container: IContainer;
|
||||
let containerId: string;
|
||||
let inventoryList: IInventoryList;
|
||||
let containerKillBit: IContainerKillBit;
|
||||
|
||||
if (createNew) {
|
||||
// In interacting with the service, we need to be explicit about whether we're creating a new container vs.
|
||||
// loading an existing one. If loading, we also need to provide the unique ID for the container we are
|
||||
// loading from.
|
||||
|
||||
// In this app, we'll choose to create a new container when navigating directly to http://localhost:8080.
|
||||
// A newly created container will generate its own ID, which we'll place in the URL hash.
|
||||
// If navigating to http://localhost:8080#containerId, we'll load from the ID in the hash.
|
||||
|
||||
// These policy choices are arbitrary for demo purposes, and can be changed however you'd like.
|
||||
if (location.hash.length === 0) {
|
||||
fetchedData = await fetchData();
|
||||
container = await loader.createDetachedContainer({ package: "no-dynamic-package", config: {} });
|
||||
inventoryList = await getInventoryListFromContainer(container);
|
||||
containerKillBit = await getContainerKillBitFromContainer(container);
|
||||
await applyStringData(inventoryList, fetchedData);
|
||||
await container.attach({ url: documentId });
|
||||
await container.attach(createTinyliciousCreateNewRequest());
|
||||
|
||||
// Discover the container ID after attaching
|
||||
const resolved = container.resolvedUrl;
|
||||
ensureFluidResolvedUrl(resolved);
|
||||
containerId = resolved.id;
|
||||
|
||||
// Update the URL with the actual container ID
|
||||
location.hash = containerId;
|
||||
} else {
|
||||
container = await loader.resolve({ url: documentId });
|
||||
containerId = location.hash.substring(1);
|
||||
container = await loader.resolve({ url: containerId });
|
||||
containerKillBit = await getContainerKillBitFromContainer(container);
|
||||
inventoryList = await getInventoryListFromContainer(container);
|
||||
}
|
||||
// Put the container ID in the tab title
|
||||
document.title = containerId;
|
||||
|
||||
const writeToExternalStorage = async () => {
|
||||
// CONSIDER: it's perhaps more-correct to spawn a new client to extract with (to avoid local changes).
|
||||
|
|
|
@ -23,7 +23,7 @@ module.exports = env => {
|
|||
]
|
||||
},
|
||||
output: {
|
||||
filename: "[name].[contenthash].js",
|
||||
filename: "[name].[hash].js",
|
||||
},
|
||||
plugins: [
|
||||
new HtmlWebpackPlugin({
|
||||
|
|
|
@ -14,6 +14,13 @@ module.exports = env => {
|
|||
devServer: {
|
||||
port: 9000
|
||||
},
|
||||
// This impacts which files are watched by the dev server (and likely by webpack if watch is true).
|
||||
// This should be configurable under devServer.static.watch
|
||||
// (see https://github.com/webpack/webpack-dev-server/blob/master/migration-v4.md) but that does not seem to work.
|
||||
// The CLI options for disabling watching don't seem to work either, so this may be a symptom of using webpack4 with the newer webpack-cli and webpack-dev-server.
|
||||
watchOptions: {
|
||||
ignored: "**/node_modules/**",
|
||||
},
|
||||
module: {
|
||||
rules: [{
|
||||
test: /\.s?css$/,
|
||||
|
@ -30,7 +37,7 @@ module.exports = env => {
|
|||
]
|
||||
},
|
||||
output: {
|
||||
filename: "[name].[contenthash].js",
|
||||
filename: "[name].[hash].js",
|
||||
},
|
||||
plugins: [
|
||||
new HtmlWebpackPlugin({
|
||||
|
|
|
@ -59,7 +59,7 @@
|
|||
"@fluidframework/local-driver": "^0.60.1000",
|
||||
"@fluidframework/mocha-test-setup": "^0.60.1000",
|
||||
"@fluidframework/sequence": "^0.60.1000",
|
||||
"@fluidframework/server-local-server": "^0.1036.1000",
|
||||
"@fluidframework/server-local-server": "^0.1036.2000-0",
|
||||
"@fluidframework/test-runtime-utils": "^0.60.1000",
|
||||
"@fluidframework/test-utils": "^0.60.1000",
|
||||
"@microsoft/api-extractor": "^7.22.2",
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
"test:coverage": "jest --coverage --ci --reporters=default --reporters=jest-junit",
|
||||
"test:jest": "jest",
|
||||
"tsc": "tsc",
|
||||
"webpack": "webpack --config webpack.prod.js --env production"
|
||||
"webpack": "webpack --config webpack.prod.js --env production --color --no-stats"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hig/fonts": "^1.0.2",
|
||||
|
@ -104,8 +104,6 @@
|
|||
"webpack": "^4.46.0",
|
||||
"webpack-cli": "^4.9.2",
|
||||
"webpack-dev-server": "4.0.0",
|
||||
"webpack-karma-die-hard": "^1.0.4",
|
||||
"webpack-license-plugin": "^4.2.2",
|
||||
"webpack-merge": "^5.8.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
|
|
@ -67,7 +67,6 @@ interface IEditReferencePathProps {
|
|||
}
|
||||
|
||||
export const EditReferencePath: React.FunctionComponent<IEditReferencePathProps
|
||||
// eslint-disable-next-line react/prop-types
|
||||
& React.HTMLAttributes<HTMLDivElement>> = ({onCancel, onEdit, name, path, className, ...restProps}) => {
|
||||
const classes = useStyles();
|
||||
const [newPath, setNewPath] = React.useState(path);
|
||||
|
|
|
@ -54,7 +54,7 @@ export async function ErrorPopup<
|
|||
} else {
|
||||
return Promise.resolve(result);
|
||||
}
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
processError(err);
|
||||
if (catchErr) {
|
||||
return Promise.resolve();
|
||||
|
|
|
@ -240,7 +240,7 @@ export class HashCalculator {
|
|||
|
||||
// Compute the hash for the remaining bytes in the buffer
|
||||
const buffer = this.hashBuffer.Uint8HashArray;
|
||||
/* eslint-disable no-fallthrough, no-multi-spaces */ // Allows cases to fallthrough without complaints.
|
||||
/* eslint-disable no-multi-spaces */
|
||||
switch (this.hashBuffer.pos) {
|
||||
case 15: k4 = (k4 ^ (buffer[14] << 16)) >>> 0;
|
||||
case 14: k4 = (k4 ^ (buffer[13] << 8)) >>> 0;
|
||||
|
@ -284,7 +284,7 @@ export class HashCalculator {
|
|||
default:
|
||||
throw new Error("_finalizeHash: We should never get into the default case.");
|
||||
}
|
||||
/* eslint-enable no-fallthrough, no-multi-spaces */
|
||||
/* eslint-enable no-multi-spaces */
|
||||
|
||||
// Perform the finalization
|
||||
const len = this.length + this.hashBuffer.pos;
|
||||
|
|
|
@ -349,7 +349,6 @@ class InspectorTable extends React.Component<WithStyles<typeof styles> & IInspec
|
|||
// We need to update the table rows directly, because they might be used in the search call below.
|
||||
// Treating table rows as a mutable state property is fine, since it is purely derived from props anyway, and
|
||||
// we also update it directly in other places already.
|
||||
// eslint-disable-next-line react/no-direct-mutation-state
|
||||
this.state.tableRows = updatedTableRows;
|
||||
// We still need to add it to the new state to trigger a re-render of the table.
|
||||
newState.tableRows = updatedTableRows;
|
||||
|
@ -646,7 +645,7 @@ class InspectorTable extends React.Component<WithStyles<typeof styles> & IInspec
|
|||
parentProp.setValues({[rowData.name]: newPath});
|
||||
try {
|
||||
(parentProp as unknown as ReferenceMapProperty).isReferenceValid(rowData.name);
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
// if maximum call stack size is exceeded, user probably created cyclic reference
|
||||
// we can't delete cyclic references so we need set reference path to some other value
|
||||
if (e.message.includes("Maximum call stack size exceeded")) {
|
||||
|
@ -660,7 +659,7 @@ class InspectorTable extends React.Component<WithStyles<typeof styles> & IInspec
|
|||
unresolvedProperty.setValue(newPath);
|
||||
try {
|
||||
unresolvedProperty.isReferenceValid();
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
if (e.message.includes("Maximum call stack size exceeded")) {
|
||||
unresolvedProperty.setValue("Could not resolve the reference");
|
||||
}
|
||||
|
|
|
@ -2244,7 +2244,7 @@ declare module "@fluid-experimental/property-properties" {
|
|||
/**
|
||||
* Returns the full property type identifier for the ChangeSet including the enum type id
|
||||
* @param in_hideCollection if true the collection type (if applicable) will be omitted
|
||||
* since that is not aplicable here, this param is ignored. Default to false
|
||||
* since that is not applicable here, this param is ignored. Default to false
|
||||
* @return The typeid
|
||||
*/
|
||||
getFullTypeid(in_hideCollection?: boolean): string;
|
||||
|
@ -2267,7 +2267,7 @@ declare module "@fluid-experimental/property-properties" {
|
|||
*/
|
||||
getParent(): BaseProperty | undefined;
|
||||
/**
|
||||
* checks whether the property is dynamic (only properties inherting from NodeProperty are)
|
||||
* checks whether the property is dynamic (only properties inheriting from NodeProperty are)
|
||||
*/
|
||||
isDynamic(): boolean;
|
||||
/**
|
||||
|
@ -2547,7 +2547,7 @@ declare module "@fluid-experimental/property-properties" {
|
|||
/**
|
||||
* Returns the full property type identifier for the ChangeSet including the enum type id
|
||||
* @param in_hideCollection - if true the collection type (if applicable) will be omitted
|
||||
* since that is not aplicable here, this param is ignored. Default to false
|
||||
* since that is not applicable here, this param is ignored. Default to false
|
||||
* @return The typeid
|
||||
*/
|
||||
getFullTypeid(in_hideCollection: boolean): string;
|
||||
|
|
|
@ -136,7 +136,7 @@ export class AbstractStaticCollectionProperty extends BaseProperty {
|
|||
/**
|
||||
* returns the value of a sub-property
|
||||
* This is a shortcut for .get(in_ids, in_options).getValue()
|
||||
* @param {string|number|array<string|number>} in_ids the ID or IDs of the property or an array of IDs
|
||||
* @param {string|number|Array<string|number>} in_ids the ID or IDs of the property or an array of IDs
|
||||
* if an array is passed, the .get function will be performed on each id in sequence
|
||||
* for example .getValue(['position','x']) is equivalent to .get('position').get('x').getValue().
|
||||
* If at any point .get resolves to a ReferenceProperty, it will, by default, return the property that the
|
||||
|
@ -326,8 +326,8 @@ export class AbstractStaticCollectionProperty extends BaseProperty {
|
|||
* found in that object.
|
||||
* @see {setValues}
|
||||
* @param {object} in_values The object containing the nested values to assign
|
||||
* @param {Bool} in_typed Whether the values are typed/polymorphic.
|
||||
* @param {Bool} in_initial - Whether we are setting default/initial values
|
||||
* @param {boolean} in_typed Whether the values are typed/polymorphic.
|
||||
* @param {boolean} in_initial - Whether we are setting default/initial values
|
||||
or if the function is called directly with the values to set.
|
||||
*/
|
||||
_setValues(in_values, in_typed, in_initial) {
|
||||
|
|
|
@ -147,7 +147,7 @@ export class Integer64Property extends ValueProperty {
|
|||
/**
|
||||
* @param {number} in_high set the higher 32 bit integer part
|
||||
* @throws if in_high is not a number
|
||||
* @return {boolen} true if the value was actually changed
|
||||
* @return {boolean} true if the value was actually changed
|
||||
*/
|
||||
setValueHigh(in_high) {
|
||||
ConsoleUtils.assert(_.isNumber(in_high), MSG.IN_HIGH_MUST_BE_NUMBER + in_high);
|
||||
|
@ -164,7 +164,7 @@ export class Integer64Property extends ValueProperty {
|
|||
/**
|
||||
* @param {number} in_low set the lower 32 bit integer part
|
||||
* @throws if in_low is not a number
|
||||
* @return {boolen} true if the value was actually changed
|
||||
* @return {boolean} true if the value was actually changed
|
||||
*/
|
||||
setValueLow(in_low) {
|
||||
ConsoleUtils.assert(_.isNumber(in_low), MSG.IN_LOW_MUST_BE_NUMBER + in_low);
|
||||
|
|
|
@ -8,7 +8,7 @@ export class PropertyUtils {
|
|||
* Gather all properties that pass an arbitrary predicate function
|
||||
* @param {property-properties.NodeProperty} in_rootProperty The root property to traverse from
|
||||
* @param {function} in_predicate The predicate function
|
||||
* @return {Array.<property-properties.BasePropertyy>} The list of properties that passed the predicate
|
||||
* @return {Array.<property-properties.BaseProperty>} The list of properties that passed the predicate
|
||||
* function
|
||||
*/
|
||||
static gatherProperties = function(in_rootProperty, in_predicate) {
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
"strict": false,
|
||||
"allowJs": true,
|
||||
"checkJs": false,
|
||||
|
||||
"declarationDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"outDir": "./dist",
|
||||
"composite": true
|
||||
|
|
|
@ -14,5 +14,5 @@ module.exports = {
|
|||
tsconfig: 'src/test/tsconfig.json'
|
||||
}
|
||||
},
|
||||
testPathIgnorePatterns: ['/node_modules/']
|
||||
testPathIgnorePatterns: ['/node_modules/', 'dist'],
|
||||
};
|
||||
|
|
|
@ -68,7 +68,7 @@ const setTrapSpecialCases = getTrapSpecialCases.concat(["fill", "sort"]);
|
|||
* must be used in conjunction with this class.
|
||||
* @hidden
|
||||
*/
|
||||
export const arrayProxyHandler = {
|
||||
export const arrayProxyHandler: ProxyHandler<ComponentArray> = {
|
||||
/**
|
||||
* The get trap that handles access to properties and functions.
|
||||
* @param target The {@link ComponentArray} the Proxy handles.
|
||||
|
@ -150,14 +150,28 @@ export const arrayProxyHandler = {
|
|||
|
||||
/**
|
||||
* The trap for the in operator.
|
||||
* Forwards the query to the has() method of the {@link external:ArrayProperty ArrayProperty}.
|
||||
* @param target The {@link ComponentArray} the Proxy handles.
|
||||
* @param key The name of the property/function that is to be accessed.
|
||||
* @return if the key is part of the {@link external:ArrayProperty ArrayProperty}, otherwise false.
|
||||
*/
|
||||
has: (target: ComponentArray, key: string | number | typeof proxySymbol) =>
|
||||
key === "swap" || key in [] || key === proxySymbol ||
|
||||
(key >= 0 && key < target.getProperty().getLength()),
|
||||
has: (target: ComponentArray, key: string | symbol) => {
|
||||
switch (typeof key) {
|
||||
case "string":
|
||||
{
|
||||
if (key === "swap" || key in []) {
|
||||
return true;
|
||||
}
|
||||
// Act like an array.
|
||||
// This means that "0" can be present, but not "0.0", "0.1", "-0", " 0" etc.
|
||||
// Simplest way to check for this is to round trip:
|
||||
const numeric = Number(key);
|
||||
return String(Number(key)) === key &&
|
||||
Number.isInteger(numeric) && numeric >= 0 && numeric < target.getProperty().getLength();
|
||||
}
|
||||
default:
|
||||
return key === proxySymbol;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Trap for the Object.keys().
|
||||
|
@ -168,70 +182,78 @@ export const arrayProxyHandler = {
|
|||
ownKeys: (target: ComponentArray) => Reflect.ownKeys(Array.from(target.getProperty().getIds())),
|
||||
|
||||
/**
|
||||
* The set trap handles setting of properties. If key is a number >= 0 it sets the
|
||||
* property at that index in the {@link external:ArrayProperty ArrayProperty}.
|
||||
* The set trap handles setting of properties.
|
||||
*
|
||||
* If key is a numeric string it sets the property at that index in the
|
||||
* {@link external:ArrayProperty ArrayProperty}.
|
||||
* In this case the key must be a normalized positive integer.
|
||||
*
|
||||
* If the key is 'length' it sets a new length for the {@link external:ArrayProperty ArrayProperty}.
|
||||
*
|
||||
* Otherwise, it just sets it on the associated {@link ComponentArray}.
|
||||
*
|
||||
* @param target The {@link ComponentArray} the Proxy handles.
|
||||
* @param key The name of the property/function that is to be accessed.
|
||||
* @param value The value to be set.
|
||||
* @return Returns a boolean.
|
||||
*/
|
||||
set(target: ComponentArray, key: string | number, value: any) {
|
||||
set(target: ComponentArray, key: string | symbol, value: any) {
|
||||
// process key for cases like "*1" 1 "string_key", "*string_key"
|
||||
let processed_key = key;
|
||||
let processed_key: string | symbol = key;
|
||||
const asteriskFound = Utilities.containsAsterisk(processed_key);
|
||||
if (asteriskFound) {
|
||||
// if we found an * we can safely treat it as string
|
||||
processed_key = (processed_key as string).slice(0, -1);
|
||||
}
|
||||
// convert strings of numbers to numbers
|
||||
processed_key = isNaN(Number(processed_key)) ? processed_key : Number(processed_key);
|
||||
// handle special cases for strigns and numbers
|
||||
if (typeof processed_key === "string") {
|
||||
const numeric_key = Number(processed_key);
|
||||
// handle special cases for strings and numbers
|
||||
if (isNaN(numeric_key)) {
|
||||
if (processed_key === "length") {
|
||||
return setLength(target, Number(value));
|
||||
}
|
||||
// If we land here there was no special case: simply assign.
|
||||
target[processed_key] = value;
|
||||
return true;
|
||||
} else {
|
||||
if (!isNaN(processed_key) && processed_key >= 0) {
|
||||
const property = target.getProperty();
|
||||
const isReferenceArray = PropertyFactory.instanceOf(property, "Reference", "array");
|
||||
|
||||
let insert = false;
|
||||
if (processed_key >= property.getLength()) {
|
||||
setLength(target, processed_key + 1);
|
||||
// Trying to set something that was currently not in the array,
|
||||
// means a new reference path is inserted
|
||||
insert = true;
|
||||
}
|
||||
const specialCases = setTrapSpecialCases.includes(target.lastCalledMethod);
|
||||
|
||||
if (isReferenceArray && forceType<ReferenceArrayProperty>(property)
|
||||
&& !specialCases && !asteriskFound && !insert) {
|
||||
Utilities.setValueOfReferencedProperty(property, processed_key, value);
|
||||
} else {
|
||||
if (asteriskFound && !isReferenceArray) {
|
||||
throw new Error(PropertyProxyErrors.NON_REFERENCE_ASSIGN);
|
||||
}
|
||||
if (property.isPrimitiveType() || property.get(processed_key)!.getContext() === "single") {
|
||||
Utilities.throwOnIterableForSingleProperty(value);
|
||||
property.set(processed_key,
|
||||
Utilities.prepareElementForInsertion(property, value, target.lastCalledMethod));
|
||||
} else {
|
||||
const child = property.get(processed_key);
|
||||
if (child) {
|
||||
Utilities.assign(child, value);
|
||||
} else {
|
||||
throw new Error(PropertyProxyErrors.INVALID_PROPERTY);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
// Validate numeric property: must be a normalized numeric string for an non-negative integer.
|
||||
if (numeric_key < 0 || !Number.isInteger(numeric_key) || String(numeric_key) !== processed_key) {
|
||||
throw new Error(PropertyProxyErrors.INVALID_PROPERTY);
|
||||
}
|
||||
|
||||
const property = target.getProperty();
|
||||
const isReferenceArray = PropertyFactory.instanceOf(property, "Reference", "array");
|
||||
|
||||
let insert = false;
|
||||
if (numeric_key >= property.getLength()) {
|
||||
setLength(target, numeric_key + 1);
|
||||
// Trying to set something that was currently not in the array,
|
||||
// means a new reference path is inserted
|
||||
insert = true;
|
||||
}
|
||||
const specialCases = setTrapSpecialCases.includes(target.lastCalledMethod);
|
||||
|
||||
if (isReferenceArray && forceType<ReferenceArrayProperty>(property)
|
||||
&& !specialCases && !asteriskFound && !insert) {
|
||||
Utilities.setValueOfReferencedProperty(property, numeric_key, value);
|
||||
} else {
|
||||
if (asteriskFound && !isReferenceArray) {
|
||||
throw new Error(PropertyProxyErrors.NON_REFERENCE_ASSIGN);
|
||||
}
|
||||
if (property.isPrimitiveType() || property.get(numeric_key)!.getContext() === "single") {
|
||||
Utilities.throwOnIterableForSingleProperty(value);
|
||||
property.set(numeric_key,
|
||||
Utilities.prepareElementForInsertion(property, value, target.lastCalledMethod));
|
||||
} else {
|
||||
const child = property.get(numeric_key);
|
||||
if (child) {
|
||||
Utilities.assign(child, value);
|
||||
} else {
|
||||
throw new Error(PropertyProxyErrors.INVALID_PROPERTY);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// if we land here there was no special case
|
||||
// simply assign simply assign
|
||||
target[processed_key] = value;
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
|
|
@ -74,7 +74,7 @@
|
|||
"@fluidframework/local-driver": "^0.60.1000",
|
||||
"@fluidframework/mocha-test-setup": "^0.60.1000",
|
||||
"@fluidframework/runtime-utils": "^0.60.1000",
|
||||
"@fluidframework/server-local-server": "^0.1036.1000",
|
||||
"@fluidframework/server-local-server": "^0.1036.2000-0",
|
||||
"@fluidframework/test-utils": "^0.60.1000",
|
||||
"@rushstack/eslint-config": "^2.5.1",
|
||||
"aws-sdk": "2.547.0",
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
"module": "lib/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "concurrently npm:build:compile npm:lint",
|
||||
"build": "concurrently npm:build:compile npm:lint && npm run build:docs",
|
||||
"build:compile": "concurrently npm:tsc npm:build:esnext",
|
||||
"build:docs": "api-extractor run --local --typescript-compiler-folder ../../../node_modules/typescript && copyfiles -u 1 ./_api-extractor-temp/doc-models/* ../../../_api-extractor-temp/",
|
||||
"build:esnext": "tsc --project ./tsconfig.esnext.json",
|
||||
|
|
|
@ -323,7 +323,7 @@ export abstract class Checkout extends EventEmitterWithErrorHandling<ICheckoutEv
|
|||
public revert(editId: EditId): void {
|
||||
assert(this.currentEdit !== undefined);
|
||||
const index = this.tree.edits.getIndexOfId(editId);
|
||||
const edit = this.tree.editsInternal.getEditInSessionAtIndex(index);
|
||||
const edit = this.tree.edits.getEditInSessionAtIndex(index);
|
||||
const before = this.tree.logViewer.getRevisionViewInSession(index);
|
||||
const changes = this.tree.revertChanges(edit.changes, before);
|
||||
if (changes !== undefined) {
|
||||
|
|
|
@ -66,6 +66,7 @@ import {
|
|||
ghostSessionId,
|
||||
WriteFormat,
|
||||
TreeNodeSequence,
|
||||
InternalizedChange,
|
||||
} from './persisted-types';
|
||||
import { serialize, SummaryContents } from './Summary';
|
||||
import {
|
||||
|
@ -558,16 +559,8 @@ export class SharedTree extends SharedObject<ISharedTreeEvents> implements NodeI
|
|||
* @returns the edit history of the tree.
|
||||
* @public
|
||||
*/
|
||||
public get edits(): OrderedEditSet {
|
||||
return this.editLog;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the edit history of the tree. The format of the contents of edits are subject to change and should not be relied upon.
|
||||
* @internal
|
||||
*/
|
||||
public get editsInternal(): OrderedEditSet<ChangeInternal> {
|
||||
return this.editLog;
|
||||
public get edits(): OrderedEditSet<InternalizedChange> {
|
||||
return this.editLog as unknown as OrderedEditSet<InternalizedChange>;
|
||||
}
|
||||
|
||||
private deserializeHandle(serializedHandle: string): IFluidHandle<ArrayBufferLike> {
|
||||
|
@ -1133,7 +1126,7 @@ export class SharedTree extends SharedObject<ISharedTreeEvents> implements NodeI
|
|||
|
||||
const unifyHistoricalIds = (context: NodeIdContext): void => {
|
||||
for (let i = 0; i < this.editLog.numberOfSequencedEdits; i++) {
|
||||
const edit = this.editsInternal.getEditInSessionAtIndex(i);
|
||||
const edit = this.editLog.getEditInSessionAtIndex(i);
|
||||
convertEditIds(edit, (id) => context.generateNodeId(this.convertToStableNodeId(id)));
|
||||
}
|
||||
};
|
||||
|
@ -1146,7 +1139,7 @@ export class SharedTree extends SharedObject<ISharedTreeEvents> implements NodeI
|
|||
unifyHistoricalIds(ghostContext);
|
||||
// The same logic applies to string interning, so intern all the strings in the history (superset of those in the current view)
|
||||
for (let i = 0; i < this.editLog.numberOfSequencedEdits; i++) {
|
||||
this.internStringsFromEdit(this.editsInternal.getEditInSessionAtIndex(i));
|
||||
this.internStringsFromEdit(this.editLog.getEditInSessionAtIndex(i));
|
||||
}
|
||||
} else {
|
||||
// Clients do not have the full history, but all share the same current view (sequenced). They can all finalize the same final
|
||||
|
@ -1174,9 +1167,9 @@ export class SharedTree extends SharedObject<ISharedTreeEvents> implements NodeI
|
|||
* should be used instead.
|
||||
* @public
|
||||
*/
|
||||
public applyEdit(...changes: Change[]): Edit<unknown>;
|
||||
public applyEdit(changes: Change[]): Edit<unknown>;
|
||||
public applyEdit(headOrChanges: Change | Change[], ...tail: Change[]): Edit<unknown> {
|
||||
public applyEdit(...changes: Change[]): Edit<InternalizedChange>;
|
||||
public applyEdit(changes: Change[]): Edit<InternalizedChange>;
|
||||
public applyEdit(headOrChanges: Change | Change[], ...tail: Change[]): Edit<InternalizedChange> {
|
||||
const changes = Array.isArray(headOrChanges) ? headOrChanges : [headOrChanges, ...tail];
|
||||
const id = newEditId();
|
||||
const internalEdit: Edit<ChangeInternal> = {
|
||||
|
@ -1185,7 +1178,34 @@ export class SharedTree extends SharedObject<ISharedTreeEvents> implements NodeI
|
|||
};
|
||||
this.submitEditOp(internalEdit);
|
||||
this.applyEditLocally(internalEdit, undefined);
|
||||
return internalEdit;
|
||||
return internalEdit as unknown as Edit<InternalizedChange>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges `edits` from `other` into this SharedTree.
|
||||
* @param other - Tree containing the edits that should be applied to this one.
|
||||
* @param edits - Iterable of edits from `other` to apply.
|
||||
* @param stableIdRemapper - Optional remapper to translate stable identities from `other` into stable identities on this tree.
|
||||
* Any references that `other` contains to a stable id `foo` will be replaced with references to the id `stableIdRemapper(foo)`.
|
||||
*
|
||||
* Payloads on the edits are left intact.
|
||||
* @returns a list containing `EditId`s for all applied edits.
|
||||
*/
|
||||
public mergeEditsFrom(
|
||||
other: SharedTree,
|
||||
edits: Iterable<Edit<InternalizedChange>>,
|
||||
stableIdRemapper?: (id: StableNodeId) => StableNodeId
|
||||
): EditId[] {
|
||||
const idConverter = (id: NodeId) => {
|
||||
const stableId = other.convertToStableNodeId(id);
|
||||
const convertedStableId = stableIdRemapper?.(stableId) ?? stableId;
|
||||
return this.generateNodeId(convertedStableId);
|
||||
};
|
||||
|
||||
return Array.from(
|
||||
edits as unknown as Iterable<Edit<ChangeInternal>>,
|
||||
(edit) => this.applyEditInternal(convertEditIds(edit, (id) => idConverter(id))).id
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1305,7 +1325,7 @@ export class SharedTree extends SharedObject<ISharedTreeEvents> implements NodeI
|
|||
*/
|
||||
public revert(editId: EditId): EditId | undefined {
|
||||
const index = this.edits.getIndexOfId(editId);
|
||||
const edit = this.editLog.getEditInSessionAtIndex(index);
|
||||
const edit = this.edits.getEditInSessionAtIndex(index);
|
||||
const before = this.logViewer.getRevisionViewInSession(index);
|
||||
const changes = this.revertChanges(edit.changes, before);
|
||||
if (changes === undefined) {
|
||||
|
@ -1322,8 +1342,8 @@ export class SharedTree extends SharedObject<ISharedTreeEvents> implements NodeI
|
|||
* @returns the inverse of `changes` or undefined if the changes could not be inverted for the given tree state.
|
||||
* @internal
|
||||
*/
|
||||
public revertChanges(changes: readonly ChangeInternal[], before: RevisionView): ChangeInternal[] | undefined {
|
||||
return revert(changes, before);
|
||||
public revertChanges(changes: readonly InternalizedChange[], before: RevisionView): ChangeInternal[] | undefined {
|
||||
return revert(changes as unknown as readonly ChangeInternal[], before);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -29,7 +29,7 @@ export interface UploadedEditChunkContents {
|
|||
*/
|
||||
export async function getUploadedEditChunkContents(sharedTree: SharedTree): Promise<UploadedEditChunkContents[]> {
|
||||
const editChunks: UploadedEditChunkContents[] = [];
|
||||
const { editChunks: editsOrHandles } = (sharedTree.edits as EditLog<ChangeInternal>).getEditLogSummary();
|
||||
const { editChunks: editsOrHandles } = (sharedTree.edits as unknown as EditLog<ChangeInternal>).getEditLogSummary();
|
||||
for (const { chunk } of editsOrHandles) {
|
||||
if (!Array.isArray(chunk)) {
|
||||
const handle = chunk as FluidEditHandle;
|
||||
|
|
|
@ -111,8 +111,8 @@ export class Transaction extends TypedEventEmitter<TransactionEvents> {
|
|||
if (this.transaction.changes.length > 0) {
|
||||
const result = this.transaction.close();
|
||||
const edit: Edit<ChangeInternal> = { id: newEditId(), changes: result.changes };
|
||||
if (this.tree.editsInternal instanceof CachingLogViewer) {
|
||||
this.tree.editsInternal.setKnownEditingResult(edit, result);
|
||||
if (this.tree.edits instanceof CachingLogViewer) {
|
||||
this.tree.edits.setKnownEditingResult(edit, result);
|
||||
}
|
||||
this.tree.applyEditInternal(edit);
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@ export {
|
|||
ConstraintEffect,
|
||||
Edit,
|
||||
ChangeInternal,
|
||||
InternalizedChange,
|
||||
ChangeNode,
|
||||
ChangeNode_0_0_2,
|
||||
EditLogSummary,
|
||||
|
|
|
@ -204,6 +204,17 @@ export interface CompressedBuildInternal<TId extends OpSpaceNodeId> {
|
|||
*/
|
||||
export type CompressedBuildNode<TId extends OpSpaceNodeId> = CompressedPlaceholderTree<TId, DetachedSequenceId>;
|
||||
|
||||
// TODO: `ChangeInternal`s should be assignable to this type without casting; this will require some test refactoring.
|
||||
/**
|
||||
* This type should be used as an opaque handle in the public API for `ChangeInternal` objects.
|
||||
* This is useful for supporting public APIs which involve working with a tree's edit history,
|
||||
* which will involve changes that have already been internalized.
|
||||
* @public
|
||||
*/
|
||||
export interface InternalizedChange {
|
||||
InternalChangeBrand: '2cae1045-61cf-4ef7-a6a3-8ad920cb7ab3';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc (Change:type)}
|
||||
* @public
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import { benchmark, BenchmarkType } from '@fluid-tools/benchmark';
|
||||
import { benchmark, BenchmarkType, isInPerformanceTestingMode } from '@fluid-tools/benchmark';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { assert } from '../Common';
|
||||
|
@ -17,8 +17,10 @@ import { refreshTestTree } from './utilities/TestUtilities';
|
|||
|
||||
describe('Forest Perf', () => {
|
||||
const testTree = refreshTestTree();
|
||||
// Larger sizes can slow down correctness test runs, or even time out, so only run smaller sizes as correctness tests.
|
||||
const sizes = isInPerformanceTestingMode ? [100, 1_000, 10_000, 100_000] : [100, 1_000];
|
||||
|
||||
for (const count of [100, 1_000, 10_000, 100_000]) {
|
||||
for (const count of sizes) {
|
||||
// Pick a single representative size for the 'Measurement' suite to keep it small.
|
||||
const type = count === 10_000 ? BenchmarkType.Measurement : BenchmarkType.Perspective;
|
||||
|
||||
|
@ -71,7 +73,7 @@ describe('Forest Perf', () => {
|
|||
});
|
||||
|
||||
let otherForest: Forest | undefined;
|
||||
for (const otherCount of [100, 1_000, 10_000, 100_000]) {
|
||||
for (const otherCount of sizes) {
|
||||
benchmark({
|
||||
type,
|
||||
title: `invoke delta on Forest with ${count} nodes against Forest with ${otherCount} nodes`,
|
||||
|
|
|
@ -1325,7 +1325,7 @@ function createNetworkTestFunction(validateAfter: boolean): NetworkTestFunction
|
|||
network.deliverOperations(DestinationClient.All);
|
||||
network.assertNetworkState();
|
||||
}
|
||||
});
|
||||
}).timeout(10000);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ import { sequencedIdNormalizer } from '../NodeIdUtilities';
|
|||
import { expectDefined } from './utilities/TestCommon';
|
||||
import { TestFluidSerializer } from './utilities/TestSerializer';
|
||||
import {
|
||||
getEditLogInternal,
|
||||
getIdNormalizerFromSharedTree,
|
||||
makeNodeIdContext,
|
||||
setUpLocalServerTestSharedTree,
|
||||
|
@ -421,12 +422,12 @@ async function expectSharedTreesEqual(
|
|||
const roundTrip = <T>(obj: T): T => JSON.parse(JSON.stringify(obj)) as T;
|
||||
|
||||
const editA = roundTrip(
|
||||
convertEditIds(await sharedTreeA.editsInternal.getEditAtIndex(i), (id) =>
|
||||
convertEditIds(await getEditLogInternal(sharedTreeA).getEditAtIndex(i), (id) =>
|
||||
sharedTreeA.convertToStableNodeId(id)
|
||||
)
|
||||
);
|
||||
const editB = roundTrip(
|
||||
convertEditIds(await sharedTreeB.editsInternal.getEditAtIndex(i), (id) =>
|
||||
convertEditIds(await getEditLogInternal(sharedTreeB).getEditAtIndex(i), (id) =>
|
||||
sharedTreeB.convertToStableNodeId(id)
|
||||
)
|
||||
);
|
||||
|
|
|
@ -109,8 +109,8 @@ export async function performFuzzActions(
|
|||
const first = trees[0].tree;
|
||||
for (let i = 1; i < trees.length; i++) {
|
||||
const tree = trees[i].tree;
|
||||
const editLogA = first.editsInternal as EditLog<ChangeInternal>;
|
||||
const editLogB = tree.editsInternal as EditLog<ChangeInternal>;
|
||||
const editLogA = first.edits;
|
||||
const editLogB = tree.edits;
|
||||
const minEdits = Math.min(editLogA.length, editLogB.length);
|
||||
for (let j = 0; j < minEdits - 1; j++) {
|
||||
const editA = await editLogA.getEditAtIndex(editLogA.length - j - 1);
|
||||
|
|
|
@ -13,6 +13,7 @@ import type { EditLog } from '../../EditLog';
|
|||
import { SharedTree } from '../../SharedTree';
|
||||
import { Change, StablePlace } from '../../ChangeTypes';
|
||||
import {
|
||||
getEditLogInternal,
|
||||
LocalServerSharedTreeTestingComponents,
|
||||
LocalServerSharedTreeTestingOptions,
|
||||
setUpTestTree,
|
||||
|
@ -67,9 +68,7 @@ export function runPendingLocalStateTests(
|
|||
testObjectProvider,
|
||||
container,
|
||||
() =>
|
||||
tree.applyEdit(
|
||||
...Change.insertTree(testTree.buildLeaf(), StablePlace.after(testTree.left))
|
||||
) as Edit<ChangeInternal>
|
||||
tree.applyEdit(...Change.insertTree(testTree.buildLeaf(), StablePlace.after(testTree.left)))
|
||||
);
|
||||
await testObjectProvider.ensureSynchronized();
|
||||
const leftTraitAfterOfflineClose = tree2.currentView.getTrait(
|
||||
|
@ -82,7 +81,7 @@ export function runPendingLocalStateTests(
|
|||
const container3 = await loader.resolve({ url }, pendingLocalState);
|
||||
const dataObject3 = await requestFluidObject<ITestFluidObject>(container3, '/');
|
||||
const tree3 = await dataObject3.getSharedObject<SharedTree>(documentId);
|
||||
expect((tree3.editsInternal as EditLog<ChangeInternal>).isLocalEdit(edit.id)).to.be.true; // Kludge
|
||||
expect((tree3.edits as unknown as EditLog<ChangeInternal>).isLocalEdit(edit.id)).to.be.true; // Kludge
|
||||
|
||||
await testObjectProvider.ensureSynchronized();
|
||||
|
||||
|
@ -99,12 +98,12 @@ export function runPendingLocalStateTests(
|
|||
'Tree collaborating with a client that applies stashed pending edits should see them.'
|
||||
);
|
||||
|
||||
const stableEdit = stabilizeEdit(tree, edit);
|
||||
const stableEdit = stabilizeEdit(tree, edit as unknown as Edit<ChangeInternal>);
|
||||
expect(
|
||||
stabilizeEdit(tree2, (await tree2.editsInternal.tryGetEdit(edit.id)) ?? fail())
|
||||
stabilizeEdit(tree2, (await getEditLogInternal(tree2).tryGetEdit(edit.id)) ?? fail())
|
||||
).to.deep.equal(stableEdit);
|
||||
expect(
|
||||
stabilizeEdit(tree3, (await tree3.editsInternal.tryGetEdit(edit.id)) ?? fail())
|
||||
stabilizeEdit(tree3, (await getEditLogInternal(tree3).tryGetEdit(edit.id)) ?? fail())
|
||||
).to.deep.equal(stableEdit);
|
||||
expect(tree2.edits.length).to.equal(initialEditLogLength + 1);
|
||||
expect(tree3.edits.length).to.equal(initialEditLogLength + 1);
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
MockFluidDataStoreRuntime,
|
||||
} from '@fluidframework/test-runtime-utils';
|
||||
import { assertArrayOfOne, assertNotUndefined, fail, isSharedTreeEvent } from '../../Common';
|
||||
import { EditId, OpSpaceNodeId, TraitLabel } from '../../Identifiers';
|
||||
import { EditId, NodeId, OpSpaceNodeId, TraitLabel } from '../../Identifiers';
|
||||
import { CachingLogViewer } from '../../LogViewer';
|
||||
import { EditLog, OrderedEditSet } from '../../EditLog';
|
||||
import { initialTree } from '../../InitialTree';
|
||||
|
@ -69,6 +69,7 @@ import {
|
|||
applyNoop,
|
||||
getIdNormalizerFromSharedTree,
|
||||
waitForSummary,
|
||||
getEditLogInternal,
|
||||
} from './TestUtilities';
|
||||
|
||||
function revertEditInTree(tree: SharedTree, edit: EditId): EditId | undefined {
|
||||
|
@ -1294,7 +1295,7 @@ export function runSharedTreeOperationsTests(
|
|||
});
|
||||
|
||||
// Verify we loaded a no-history summary.
|
||||
expect(tree3.editsInternal.length).to.equal(1);
|
||||
expect(tree3.edits.length).to.equal(1);
|
||||
|
||||
let unexpectedHistoryChunkCount = 0;
|
||||
tree3.on(SharedTreeDiagnosticEvent.UnexpectedHistoryChunk, () => unexpectedHistoryChunkCount++);
|
||||
|
@ -1361,10 +1362,12 @@ export function runSharedTreeOperationsTests(
|
|||
containerRuntimeFactory.processAllMessages();
|
||||
const { internedStrings } = tree.saveSummary() as SharedTreeSummary;
|
||||
|
||||
const insertEdit = normalizeEdit(tree, tree.editsInternal.getEditInSessionAtIndex(1));
|
||||
const moveEdit = normalizeEdit(tree, tree.editsInternal.getEditInSessionAtIndex(2));
|
||||
const insertEdit2 = normalizeEdit(secondTree, secondTree.editsInternal.getEditInSessionAtIndex(1));
|
||||
const moveEdit2 = normalizeEdit(secondTree, secondTree.editsInternal.getEditInSessionAtIndex(2));
|
||||
const log = getEditLogInternal(tree);
|
||||
const log2 = getEditLogInternal(secondTree);
|
||||
const insertEdit = normalizeEdit(tree, log.getEditInSessionAtIndex(1));
|
||||
const moveEdit = normalizeEdit(tree, log.getEditInSessionAtIndex(2));
|
||||
const insertEdit2 = normalizeEdit(secondTree, log2.getEditInSessionAtIndex(1));
|
||||
const moveEdit2 = normalizeEdit(secondTree, log2.getEditInSessionAtIndex(2));
|
||||
expect(insertEdit).to.deep.equal(insertEdit2);
|
||||
expect(moveEdit).to.deep.equal(moveEdit2);
|
||||
expect(tree.equals(secondTree)).to.be.true;
|
||||
|
@ -1413,7 +1416,7 @@ export function runSharedTreeOperationsTests(
|
|||
|
||||
const uncompressedEdits: EditWithoutId<ChangeInternal>[] = [
|
||||
{
|
||||
changes: tree.edits.getEditInSessionAtIndex(0).changes as ChangeInternal[],
|
||||
changes: getEditLogInternal(tree).getEditInSessionAtIndex(0).changes,
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -1466,5 +1469,67 @@ export function runSharedTreeOperationsTests(
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe('mergeEditsFrom', () => {
|
||||
const getTestTreeRootHandle = (tree: SharedTree, testTree: TestTree): TreeNodeHandle => {
|
||||
const view = tree.currentView;
|
||||
const handle = new TreeNodeHandle(view, view.root);
|
||||
return handle.traits[testTree.traitLabel][0];
|
||||
};
|
||||
|
||||
it('can be used with simple edits', () => {
|
||||
const { sharedTree, testTree } = createSimpleTestTree();
|
||||
const { sharedTree: sharedTree2, testTree: testTree2 } = createSimpleTestTree();
|
||||
sharedTree.applyEdit(...Change.insertTree(testTree.buildLeaf(), StablePlace.after(testTree.left)));
|
||||
sharedTree.applyEdit(
|
||||
Change.delete(StableRange.all({ parent: testTree.identifier, label: testTree.right.traitLabel }))
|
||||
);
|
||||
const preEditRootHandle = getTestTreeRootHandle(sharedTree2, testTree2);
|
||||
const edits = [0, 1, 2].map((i) => sharedTree.edits.getEditInSessionAtIndex(i));
|
||||
// Since the TestTree setup edit is a `setTrait`, this should wipe `testTree2` state.
|
||||
sharedTree2.mergeEditsFrom(sharedTree, edits);
|
||||
expect(sharedTree2.edits.length).to.equal(4);
|
||||
const rootHandle = getTestTreeRootHandle(sharedTree2, testTree2);
|
||||
expect(preEditRootHandle.identifier).to.not.equal(rootHandle.identifier);
|
||||
expect(rootHandle.traits[testTree2.left.traitLabel].length).to.equal(2);
|
||||
});
|
||||
|
||||
it('can be used with a translation map', () => {
|
||||
const { sharedTree, testTree } = createSimpleTestTree();
|
||||
const { sharedTree: sharedTree2, testTree: testTree2 } = createSimpleTestTree();
|
||||
// For each of the identities in the simple test tree...
|
||||
const nodeIdGetters: ((tree: TestTree) => NodeId)[] = [
|
||||
(tree) => tree.identifier,
|
||||
(tree) => tree.left.identifier,
|
||||
(tree) => tree.right.identifier,
|
||||
];
|
||||
// Make a map translating that identifier from `testTree` to `testTree2`
|
||||
const translationMap = new Map(
|
||||
nodeIdGetters.map((getter) => [
|
||||
sharedTree.convertToStableNodeId(getter(testTree)),
|
||||
sharedTree2.convertToStableNodeId(getter(testTree2)),
|
||||
])
|
||||
);
|
||||
sharedTree.applyEdit(...Change.insertTree(testTree.buildLeaf(), StablePlace.after(testTree.left)));
|
||||
sharedTree.applyEdit(
|
||||
Change.delete(StableRange.all({ parent: testTree.identifier, label: testTree.right.traitLabel }))
|
||||
);
|
||||
const edits = [1, 2].map((i) => sharedTree.edits.getEditInSessionAtIndex(i));
|
||||
sharedTree2.mergeEditsFrom(sharedTree, edits, (id) => translationMap.get(id) ?? id);
|
||||
|
||||
const root = getTestTreeRootHandle(sharedTree, testTree);
|
||||
const root2 = getTestTreeRootHandle(sharedTree2, testTree2);
|
||||
|
||||
const leftTrait = root.traits[testTree.left.traitLabel];
|
||||
const leftTrait2 = root2.traits[testTree2.left.traitLabel];
|
||||
|
||||
// Inserted leaves should be equivalent.
|
||||
expect(leftTrait2.length).to.equal(2);
|
||||
expect(leftTrait2[1]).to.deep.equal(leftTrait[1]);
|
||||
// Right subtree should have been deleted.
|
||||
expect(Object.entries(root2.traits).length).to.equal(1);
|
||||
expect(root2.traits[testTree2.right.traitLabel]).to.equal(undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -507,7 +507,7 @@ export function runSharedTreeVersioningTests(
|
|||
version: newVersion,
|
||||
};
|
||||
containerRuntimeFactory.pushMessage({ contents: op });
|
||||
(tree.editsInternal as EditLog).getLocalEdits = () => {
|
||||
(tree.edits as EditLog).getLocalEdits = () => {
|
||||
throw new Error('Simulated issue in update');
|
||||
};
|
||||
const matchesFailedVersionUpdate = (event: ITelemetryBaseEvent) =>
|
||||
|
|
|
@ -142,7 +142,7 @@ export function runSummarySizeTests(
|
|||
if (revertEdits) {
|
||||
for (let i = changes.length - 1; i >= 0; i--) {
|
||||
const editIndex = tree.edits.getIndexOfId(edits[i].id);
|
||||
const edit = tree.edits.getEditInSessionAtIndex(editIndex) as Edit<ChangeInternal>;
|
||||
const edit = tree.edits.getEditInSessionAtIndex(editIndex) as unknown as Edit<ChangeInternal>;
|
||||
const reverted = revert(edit.changes, tree.logViewer.getRevisionViewInSession(editIndex));
|
||||
if (reverted !== undefined) {
|
||||
tree.applyEditInternal(reverted);
|
||||
|
|
|
@ -53,6 +53,7 @@ import { newEdit, setTrait } from '../../EditUtilities';
|
|||
import { SharedTree } from '../../SharedTree';
|
||||
import { BuildNode, Change, StablePlace } from '../../ChangeTypes';
|
||||
import { convertEditIds } from '../../IdConversion';
|
||||
import { OrderedEditSet } from '../../EditLog';
|
||||
import { buildLeaf, RefreshingTestTree, SimpleTestTree, TestTree } from './TestNode';
|
||||
|
||||
/** Objects returned by setUpTestSharedTree */
|
||||
|
@ -283,8 +284,13 @@ export async function setUpLocalServerTestSharedTree(
|
|||
TestDataStoreType,
|
||||
new TestFluidObjectFactory(registry),
|
||||
{
|
||||
summaryOptions: { initialSummarizerDelayMs: 0 },
|
||||
enableOfflineLoad: true,
|
||||
summaryOptions: {
|
||||
summaryConfigOverrides: {
|
||||
idleTime: 1000, // Current default idleTime is 15000 which will cause some SharedTree tests to timeout.
|
||||
},
|
||||
initialSummarizerDelayMs: 0,
|
||||
},
|
||||
},
|
||||
[innerRequestHandler]
|
||||
);
|
||||
|
@ -586,6 +592,10 @@ export function stabilizeEdit(
|
|||
return convertEditIds(edit, (id) => tree.convertToStableNodeId(id));
|
||||
}
|
||||
|
||||
export function getEditLogInternal(tree: SharedTree): OrderedEditSet<ChangeInternal> {
|
||||
return tree.edits as unknown as OrderedEditSet<ChangeInternal>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Spies on all future ops submitted to `containerRuntimeFactory`. When ops are submitted, they will be `push`ed into the
|
||||
* returned array.
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
"@fluidframework/common-utils": "^0.32.1",
|
||||
"@fluidframework/core-interfaces": "^0.43.1000",
|
||||
"@fluidframework/datastore-definitions": "^0.60.1000",
|
||||
"@fluidframework/protocol-base": "^0.1036.1000",
|
||||
"@fluidframework/protocol-base": "^0.1036.2000-0",
|
||||
"@fluidframework/protocol-definitions": "^0.1028.1000",
|
||||
"@fluidframework/runtime-definitions": "^0.60.1000",
|
||||
"@fluidframework/runtime-utils": "^0.60.1000",
|
||||
|
|
|
@ -55,33 +55,36 @@ const createObjectProxy = (
|
|||
consumer: Consumer,
|
||||
parent?: IProxy,
|
||||
parentKey?: json1.Key,
|
||||
) => new Proxy(subject, {
|
||||
get: (target, key, receiver) => {
|
||||
if (key === contextSym) {
|
||||
return { parent, parentKey };
|
||||
}
|
||||
) => {
|
||||
const handler: ProxyHandler<IProxy> = {
|
||||
get: (target, key, receiver) => {
|
||||
if (key === contextSym) {
|
||||
return { parent, parentKey };
|
||||
}
|
||||
|
||||
const value = target[key];
|
||||
const value = target[key];
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
return value !== null && typeof value === "object"
|
||||
? getProxy(/* target: */ value, consumer, /* parent: */ receiver, key as string)
|
||||
: value;
|
||||
/* eslint-enable @typescript-eslint/no-unsafe-return */
|
||||
},
|
||||
set: (target, key, value, receiver) => {
|
||||
const path = getPath(receiver, key as json1.Key);
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
return value !== null && typeof value === "object"
|
||||
? getProxy(/* target: */ value, consumer, /* parent: */ receiver, key as string)
|
||||
: value;
|
||||
/* eslint-enable @typescript-eslint/no-unsafe-return */
|
||||
},
|
||||
set: (target, key, value, receiver) => {
|
||||
const path = getPath(receiver, key as json1.Key);
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(target, key)) {
|
||||
consumer(json1.replaceOp(path, /* oldVal: */ target[key], /* newVal: */ value));
|
||||
} else {
|
||||
consumer(json1.insertOp(path, value));
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(target, key)) {
|
||||
consumer(json1.replaceOp(path, /* oldVal: */ target[key], /* newVal: */ value));
|
||||
} else {
|
||||
consumer(json1.insertOp(path, value));
|
||||
}
|
||||
|
||||
target[key] = value;
|
||||
return true;
|
||||
},
|
||||
});
|
||||
target[key] = value;
|
||||
return true;
|
||||
},
|
||||
};
|
||||
return new Proxy(subject, handler);
|
||||
};
|
||||
|
||||
// If given key is a string containing an integer then convert it to an integer,
|
||||
// otherwise return the key unmodified.
|
||||
|
|
|
@ -72,13 +72,13 @@ export const TreeObjectProxy = <T extends Object>(
|
|||
// },
|
||||
});
|
||||
|
||||
export class TreeArrayProxy<T> implements IArrayish<T> {
|
||||
export class TreeArrayProxy<T> implements IArrayish<Serializable<T>> {
|
||||
constructor(
|
||||
private readonly tree: SharedTree,
|
||||
private readonly nodeId: NodeId,
|
||||
private readonly update: (...change: Change[]) => void,
|
||||
) {
|
||||
return new Proxy(this, {
|
||||
const handler: ProxyHandler<TreeArrayProxy<T>> = {
|
||||
get(target, key) {
|
||||
if (typeof key !== "symbol" && !isNaN(key as unknown as number)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
||||
|
@ -107,10 +107,11 @@ export class TreeArrayProxy<T> implements IArrayish<T> {
|
|||
|
||||
return false;
|
||||
},
|
||||
});
|
||||
};
|
||||
return new Proxy(this, handler);
|
||||
}
|
||||
|
||||
[n: number]: T;
|
||||
[n: number]: Serializable<T>;
|
||||
|
||||
private get itemIds(): readonly NodeId[] {
|
||||
const view = this.tree.currentView;
|
||||
|
@ -118,13 +119,13 @@ export class TreeArrayProxy<T> implements IArrayish<T> {
|
|||
}
|
||||
|
||||
private idsToItems(itemIds: readonly NodeId[]) {
|
||||
return itemIds.map((itemId) => getChild(this.tree, itemId, this.update)) as T[];
|
||||
return itemIds.map((itemId) => getChild(this.tree, itemId, this.update)) as Serializable<T>[];
|
||||
}
|
||||
|
||||
private get items(): T[] { return this.idsToItems(this.itemIds); }
|
||||
private get items(): Serializable<T>[] { return this.idsToItems(this.itemIds); }
|
||||
get length(): number { return this.items.length; }
|
||||
|
||||
[Symbol.iterator](): IterableIterator<T> { return this.items[Symbol.iterator](); }
|
||||
[Symbol.iterator](): IterableIterator<Serializable<T>> { return this.items[Symbol.iterator](); }
|
||||
|
||||
toString(): string { return this.items.toString(); }
|
||||
toLocaleString(): string { return this.items.toLocaleString(); }
|
||||
|
@ -159,7 +160,7 @@ export class TreeArrayProxy<T> implements IArrayish<T> {
|
|||
label: "items" as TraitLabel })));
|
||||
}
|
||||
|
||||
map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[] {
|
||||
map<U>(callbackfn: (value: Serializable<T>, index: number, array: Serializable<T>[]) => U, thisArg?: any): U[] {
|
||||
return this.items.map<U>(callbackfn, thisArg);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
"@fluidframework/local-driver": "^0.60.1000",
|
||||
"@fluidframework/protocol-definitions": "^0.1028.1000",
|
||||
"@fluidframework/routerlicious-driver": "^0.60.1000",
|
||||
"@fluidframework/server-local-server": "^0.1036.1000",
|
||||
"@fluidframework/server-local-server": "^0.1036.2000-0",
|
||||
"@fluidframework/test-runtime-utils": "^0.60.1000",
|
||||
"@fluidframework/tinylicious-driver": "^0.60.1000",
|
||||
"jsonwebtoken": "^8.4.0"
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -349,6 +349,7 @@ export class SharedMap extends SharedObject<ISharedMapEvents> implements IShared
|
|||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.applyStashedOp}
|
||||
* @internal
|
||||
*/
|
||||
protected applyStashedOp(content: any): unknown {
|
||||
|
|
|
@ -179,7 +179,7 @@ describe("Directory", () => {
|
|||
try {
|
||||
subDirectory.set("throw", "error");
|
||||
assert.fail("Should throw usage error");
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
assert.strictEqual(error.errorType, "usageError", "Should throw usage error");
|
||||
}
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
"@fluidframework/core-interfaces": "^0.43.1000",
|
||||
"@fluidframework/datastore-definitions": "^0.60.1000",
|
||||
"@fluidframework/merge-tree": "^0.60.1000",
|
||||
"@fluidframework/protocol-base": "^0.1036.1000",
|
||||
"@fluidframework/protocol-base": "^0.1036.2000-0",
|
||||
"@fluidframework/protocol-definitions": "^0.1028.1000",
|
||||
"@fluidframework/runtime-definitions": "^0.60.1000",
|
||||
"@fluidframework/runtime-utils": "^0.60.1000",
|
||||
|
|
|
@ -507,7 +507,7 @@ export class SharedMatrix<T = any>
|
|||
default: {
|
||||
assert(content.type === MatrixOp.set, 0x020 /* "Unknown SharedMatrix 'op' type." */);
|
||||
|
||||
const setOp = content as ISetOp<Serializable<T>>;
|
||||
const setOp = content as ISetOp<T>;
|
||||
const { rowHandle, colHandle, localSeq } = localOpMetadata as ISetOpMetadata;
|
||||
|
||||
// If there are more pending local writes to the same row/col handle, it is important
|
||||
|
@ -564,10 +564,10 @@ export class SharedMatrix<T = any>
|
|||
|
||||
switch (contents.target) {
|
||||
case SnapshotPath.cols:
|
||||
this.cols.applyMsg(msg);
|
||||
this.cols.applyMsg(msg, local);
|
||||
break;
|
||||
case SnapshotPath.rows:
|
||||
this.rows.applyMsg(msg);
|
||||
this.rows.applyMsg(msg, local);
|
||||
break;
|
||||
default: {
|
||||
assert(contents.type === MatrixOp.set,
|
||||
|
@ -687,7 +687,52 @@ export class SharedMatrix<T = any>
|
|||
return `${s}\n`;
|
||||
}
|
||||
|
||||
protected applyStashedOp() {
|
||||
throw new Error("not implemented");
|
||||
/**
|
||||
* {@inheritDoc @fluidframework/shared-object-base#SharedObjectCore.applyStashedOp}
|
||||
*/
|
||||
protected applyStashedOp(content: any): unknown {
|
||||
if (content.target === SnapshotPath.cols || content.target === SnapshotPath.rows) {
|
||||
const op = content as IMergeTreeOp;
|
||||
const currentVector = content.target === SnapshotPath.cols ? this.cols : this.rows;
|
||||
const oppositeVector = content.target === SnapshotPath.cols ? this.rows : this.cols;
|
||||
const metadata = currentVector.applyStashedOp(op);
|
||||
const localSeq = currentVector.getCollabWindow().localSeq;
|
||||
const oppositeWindow = oppositeVector.getCollabWindow();
|
||||
|
||||
assert(localSeq > oppositeWindow.localSeq,
|
||||
"The 'localSeq' of the vector applying stashed op must > the 'localSeq' of the other vector.");
|
||||
|
||||
oppositeWindow.localSeq = localSeq;
|
||||
|
||||
return metadata;
|
||||
} else {
|
||||
assert(content.type === MatrixOp.set, "Unknown SharedMatrix 'op' type.");
|
||||
|
||||
const setOp = content as ISetOp<T>;
|
||||
const rowHandle = this.rows.getAllocatedHandle(setOp.row);
|
||||
const colHandle = this.cols.getAllocatedHandle(setOp.col);
|
||||
if (this.undo !== undefined) {
|
||||
let oldValue = this.cells.getCell(rowHandle, colHandle);
|
||||
if (oldValue === null) {
|
||||
oldValue = undefined;
|
||||
}
|
||||
|
||||
this.undo.cellSet(
|
||||
rowHandle,
|
||||
colHandle,
|
||||
oldValue);
|
||||
}
|
||||
|
||||
this.cells.setCell(rowHandle, colHandle, setOp.value);
|
||||
const localSeq = this.nextLocalSeq();
|
||||
const metadata: ISetOpMetadata = {
|
||||
rowHandle,
|
||||
colHandle,
|
||||
localSeq,
|
||||
};
|
||||
|
||||
this.pending.setCell(rowHandle, colHandle, localSeq);
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import { ISequencedDocumentMessage, MessageType } from "@fluidframework/protocol
|
|||
import { IFluidDataStoreRuntime, IChannelStorageService } from "@fluidframework/datastore-definitions";
|
||||
import { ISummaryTreeWithStats } from "@fluidframework/runtime-definitions";
|
||||
import { ITelemetryLogger } from "@fluidframework/common-definitions";
|
||||
import { assert, Trace } from "@fluidframework/common-utils";
|
||||
import { assert, Trace, unreachableCase } from "@fluidframework/common-utils";
|
||||
import { LoggingError } from "@fluidframework/telemetry-utils";
|
||||
import { IIntegerRange } from "./base";
|
||||
import { RedBlackTree } from "./collections";
|
||||
|
@ -778,7 +778,34 @@ export class Client {
|
|||
}
|
||||
}
|
||||
|
||||
public applyMsg(msg: ISequencedDocumentMessage) {
|
||||
public applyStashedOp(op: IMergeTreeDeltaOp): SegmentGroup;
|
||||
public applyStashedOp(op: IMergeTreeGroupMsg): SegmentGroup[];
|
||||
public applyStashedOp(op: IMergeTreeOp): SegmentGroup | SegmentGroup[];
|
||||
public applyStashedOp(op: IMergeTreeOp): SegmentGroup | SegmentGroup[] {
|
||||
let metadata: SegmentGroup | SegmentGroup[] | undefined;
|
||||
switch (op.type) {
|
||||
case MergeTreeDeltaType.INSERT:
|
||||
this.applyInsertOp({ op });
|
||||
metadata = this.peekPendingSegmentGroups();
|
||||
break;
|
||||
case MergeTreeDeltaType.REMOVE:
|
||||
this.applyRemoveRangeOp({ op });
|
||||
metadata = this.peekPendingSegmentGroups();
|
||||
break;
|
||||
case MergeTreeDeltaType.ANNOTATE:
|
||||
this.applyAnnotateRangeOp({ op });
|
||||
metadata = this.peekPendingSegmentGroups();
|
||||
break;
|
||||
case MergeTreeDeltaType.GROUP:
|
||||
return op.ops.map((o) => this.applyStashedOp(o));
|
||||
default:
|
||||
unreachableCase(op, "unrecognized op type");
|
||||
}
|
||||
assert(!!metadata, "Applying op must generate a pending segment");
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public applyMsg(msg: ISequencedDocumentMessage, local: boolean = false) {
|
||||
// Ensure client ID is registered
|
||||
this.getOrAddShortClientId(msg.clientId);
|
||||
// Apply if an operation message
|
||||
|
@ -787,7 +814,7 @@ export class Client {
|
|||
op: msg.contents as IMergeTreeOp,
|
||||
sequencedMessage: msg,
|
||||
};
|
||||
if (opArgs.sequencedMessage?.clientId === this.longClientId) {
|
||||
if (opArgs.sequencedMessage?.clientId === this.longClientId || local) {
|
||||
this.ackPendingSegment(opArgs);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -128,6 +128,9 @@ interface IRefsAtOffset {
|
|||
after?: LocalReference[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a collection of {@link LocalReference}s associated with one segment in a merge-tree.
|
||||
*/
|
||||
export class LocalReferenceCollection {
|
||||
public static append(seg1: ISegment, seg2: ISegment) {
|
||||
if (seg2.localRefs && !seg2.localRefs.empty) {
|
||||
|
@ -150,6 +153,7 @@ export class LocalReferenceCollection {
|
|||
private refCount: number = 0;
|
||||
|
||||
constructor(
|
||||
/** Segment this `LocalReferenceCollection` is associated to. */
|
||||
private readonly segment: ISegment,
|
||||
initialRefsByfOffset = new Array<IRefsAtOffset | undefined>(segment.cachedLength)) {
|
||||
// Since javascript arrays are sparse the above won't populate any of the
|
||||
|
@ -296,6 +300,15 @@ export class LocalReferenceCollection {
|
|||
this.refsByOffset.push(...other.refsByOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits this `LocalReferenceCollection` into the intervals [0, offset) and [offset, originalLength).
|
||||
* Local references in the former half of this split will remain associated with the segment used on construction.
|
||||
* Local references in the latter half of this split will be transferred to `splitSeg`,
|
||||
* and its `localRefs` field will be set.
|
||||
* @param offset - Offset into the original segment at which the collection should be split
|
||||
* @param splitSeg - Split segment which originally corresponded to the indices [offset, originalLength)
|
||||
* before splitting.
|
||||
*/
|
||||
public split(offset: number, splitSeg: ISegment) {
|
||||
if (!this.empty) {
|
||||
const localRefs =
|
||||
|
@ -314,6 +327,9 @@ export class LocalReferenceCollection {
|
|||
this.refCount--;
|
||||
localRefs.refCount++;
|
||||
}
|
||||
} else {
|
||||
// shrink the offset array when empty and splitting
|
||||
this.refsByOffset.length = offset;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2331,7 +2331,7 @@ export class MergeTree {
|
|||
this.mapRange({ leaf: annotateSegment }, refSeq, clientId, undefined, start, end);
|
||||
|
||||
// OpArgs == undefined => test code
|
||||
if (this.mergeTreeDeltaCallback) {
|
||||
if (this.mergeTreeDeltaCallback && deltaSegments.length > 0) {
|
||||
this.mergeTreeDeltaCallback(
|
||||
opArgs,
|
||||
{
|
||||
|
@ -2445,7 +2445,7 @@ export class MergeTree {
|
|||
}
|
||||
|
||||
// opArgs == undefined => test code
|
||||
if (this.mergeTreeDeltaCallback) {
|
||||
if (this.mergeTreeDeltaCallback && removedSegments.length > 0) {
|
||||
this.mergeTreeDeltaCallback(
|
||||
opArgs,
|
||||
{
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
/*!
|
||||
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
import random from "random-js";
|
||||
import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
|
||||
import { IMergeTreeOp } from "../ops";
|
||||
import { SegmentGroup } from "../mergeTree";
|
||||
import {
|
||||
generateClientNames,
|
||||
doOverRange,
|
||||
runMergeTreeOperationRunner,
|
||||
annotateRange,
|
||||
removeRange,
|
||||
IMergeTreeOperationRunnerConfig,
|
||||
IConfigRange,
|
||||
} from "./mergeTreeOperationRunner";
|
||||
import { TestClient } from "./testClient";
|
||||
import { TestClientLogger } from "./testClientLogger";
|
||||
|
||||
function applyMessagesWithReconnect(
|
||||
startingSeq: number,
|
||||
messageDatas: [ISequencedDocumentMessage, SegmentGroup | SegmentGroup[]][],
|
||||
clients: readonly TestClient[],
|
||||
stashClients: readonly TestClient[],
|
||||
) {
|
||||
let seq = startingSeq;
|
||||
const reconnectClientMsgs: [IMergeTreeOp, SegmentGroup | SegmentGroup[]][] = [];
|
||||
let minSeq = 0;
|
||||
|
||||
// apply ops as stashed ops except for client #1
|
||||
const stashedOps: [IMergeTreeOp, SegmentGroup | SegmentGroup[], number][] = [];
|
||||
for (const messageData of messageDatas) {
|
||||
if (messageData[0].clientId !== clients[1].longClientId) {
|
||||
const index = clients.map((c) => c.longClientId).indexOf(messageData[0].clientId);
|
||||
const localMetadata = stashClients[index].applyStashedOp(messageData[0].contents);
|
||||
stashedOps.push([messageData[0].contents, localMetadata, index]);
|
||||
}
|
||||
}
|
||||
// this should put all stash clients (except #1) in the same state as the
|
||||
// respective normal clients, having local changes only.
|
||||
for (let i = 0; i < clients.length; ++i) {
|
||||
if (i !== 1) {
|
||||
TestClientLogger.validate([clients[i], stashClients[i]]);
|
||||
}
|
||||
}
|
||||
TestClientLogger.validate([clients[0], stashClients[1]]);
|
||||
|
||||
// apply the ops to the normal clients. they will all be the same now,
|
||||
// except #1 which has local changes other clients haven't seen yet
|
||||
for (const [message, sg] of messageDatas) {
|
||||
if (message.clientId === clients[1].longClientId) {
|
||||
reconnectClientMsgs.push([message.contents as IMergeTreeOp, sg]);
|
||||
} else {
|
||||
message.sequenceNumber = ++seq;
|
||||
clients.forEach((c) => c.applyMsg(message));
|
||||
minSeq = message.minimumSequenceNumber;
|
||||
}
|
||||
}
|
||||
|
||||
// regenerate the ops that were applied as stashed ops. this simulates resubmit()
|
||||
const regeneratedStashedOps = stashedOps.map((op) =>
|
||||
stashClients[op[2]].makeOpMessage(
|
||||
stashClients[op[2]].regeneratePendingOp(
|
||||
op[0],
|
||||
op[1],
|
||||
)));
|
||||
|
||||
// apply the regenerated stashed ops
|
||||
let stashedOpSeq = startingSeq;
|
||||
for (const msg of regeneratedStashedOps) {
|
||||
msg.sequenceNumber = ++stashedOpSeq;
|
||||
stashClients.forEach((c) => c.applyMsg(msg));
|
||||
}
|
||||
// all stash and normal clients should now be in the same state,
|
||||
// except #1 (normal) which still has local changes
|
||||
TestClientLogger.validate([...clients.filter((_, i) => i !== 1), ...stashClients]);
|
||||
|
||||
// regenerate ops for client #1
|
||||
const reconnectMsgs: ISequencedDocumentMessage[] = [];
|
||||
reconnectClientMsgs.forEach((opData) => {
|
||||
const newMsg = clients[1].makeOpMessage(
|
||||
clients[1].regeneratePendingOp(
|
||||
opData[0],
|
||||
opData[1],
|
||||
));
|
||||
newMsg.minimumSequenceNumber = minSeq;
|
||||
reconnectMsgs.push(newMsg);
|
||||
});
|
||||
|
||||
// apply regenerated ops as stashed ops for client #1
|
||||
const stashedRegeneratedOps: [IMergeTreeOp, SegmentGroup | SegmentGroup[]][] = reconnectMsgs.map((message) => {
|
||||
const localMetadata = stashClients[1].applyStashedOp(message.contents);
|
||||
return [message.contents, localMetadata];
|
||||
});
|
||||
// now both clients at index 1 should be the same
|
||||
TestClientLogger.validate([clients[1], stashClients[1]]);
|
||||
|
||||
// apply the regenerated ops from client #1
|
||||
for (const message of reconnectMsgs) {
|
||||
message.sequenceNumber = ++seq;
|
||||
clients.forEach((c) => c.applyMsg(message));
|
||||
}
|
||||
|
||||
// resubmit regenerated stashed ops
|
||||
const reRegeneratedStashedMessages = stashedRegeneratedOps.map((stashedOp) =>
|
||||
stashClients[1].makeOpMessage(
|
||||
stashClients[1].regeneratePendingOp(
|
||||
stashedOp[0],
|
||||
stashedOp[1]),
|
||||
));
|
||||
|
||||
for (const reRegeneratedStashedOp of reRegeneratedStashedMessages) {
|
||||
reRegeneratedStashedOp.sequenceNumber = ++stashedOpSeq;
|
||||
stashClients.forEach((c) => c.applyMsg(reRegeneratedStashedOp));
|
||||
}
|
||||
|
||||
// all clients should now be the same
|
||||
TestClientLogger.validate([...clients, ...stashClients]);
|
||||
|
||||
return seq;
|
||||
}
|
||||
|
||||
export const defaultOptions: IMergeTreeOperationRunnerConfig & { minLength: number, clients: IConfigRange } = {
|
||||
minLength: 16,
|
||||
clients: { min: 3, max: 12 },
|
||||
opsPerRoundRange: { min: 40, max: 120 },
|
||||
rounds: 3,
|
||||
operations: [annotateRange, removeRange],
|
||||
growthFunc: (input: number) => input * 2,
|
||||
};
|
||||
|
||||
describe("MergeTree.Client", () => {
|
||||
const opts = defaultOptions;
|
||||
|
||||
// Generate a list of single character client names, support up to 69 clients
|
||||
const clientNames = generateClientNames();
|
||||
|
||||
doOverRange(opts.clients, opts.growthFunc.bind(opts), (clientCount) => {
|
||||
it(`applyStashedOpFarm_${clientCount}`, async () => {
|
||||
const mt = random.engines.mt19937();
|
||||
mt.seedWithArray([0xDEADBEEF, 0xFEEDBED, clientCount]);
|
||||
|
||||
const clients: TestClient[] = [new TestClient()];
|
||||
// This test is based on reconnectFarm, but we keep a second set of clients. For
|
||||
// these clients, we apply the generated ops as stashed ops, then regenerate
|
||||
// them to simulate resubmit(), then apply them. In the end, they should arrive
|
||||
// at the same state as the "normal" set of clients
|
||||
let stashClients: TestClient[] = [];
|
||||
|
||||
clients.forEach(
|
||||
(c, i) => c.startOrUpdateCollaboration(clientNames[i]));
|
||||
stashClients = [new TestClient()];
|
||||
stashClients.forEach(
|
||||
(c, i) => c.startOrUpdateCollaboration(clientNames[i]));
|
||||
|
||||
let seq = 0;
|
||||
clients.forEach((c) => c.updateMinSeq(seq));
|
||||
stashClients.forEach((c) => c.updateMinSeq(seq));
|
||||
|
||||
// Add double the number of clients each iteration
|
||||
const targetClients = Math.max(opts.clients.min, clientCount);
|
||||
for (let cc = clients.length; cc < targetClients; cc++) {
|
||||
const newClient = await TestClient.createFromClientSnapshot(clients[0], clientNames[cc]);
|
||||
clients.push(newClient);
|
||||
// add 1 stash client per normal client
|
||||
const anotherNewClient = await TestClient.createFromClientSnapshot(clients[0], clientNames[cc]);
|
||||
stashClients.push(anotherNewClient);
|
||||
}
|
||||
|
||||
seq = runMergeTreeOperationRunner(
|
||||
mt,
|
||||
seq,
|
||||
clients,
|
||||
opts.minLength,
|
||||
opts,
|
||||
(s, m, c) => applyMessagesWithReconnect(s, m, c, stashClients));
|
||||
})
|
||||
.timeout(30 * 1000);
|
||||
});
|
||||
});
|
|
@ -5,8 +5,11 @@
|
|||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
|
||||
import { strict as assert } from "assert";
|
||||
import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
|
||||
import { LocalReference } from "../localReference";
|
||||
import { ReferenceType } from "../ops";
|
||||
import { TextSegment } from "../textSegment";
|
||||
import { createClientsAtInitialState } from "./testClientLogger";
|
||||
import { TestClient } from "./";
|
||||
|
||||
describe("MergeTree.Client", () => {
|
||||
|
@ -171,4 +174,44 @@ describe("MergeTree.Client", () => {
|
|||
|
||||
assert.equal(c1LocalRef.toPosition(), -1);
|
||||
});
|
||||
|
||||
it("Split segment with no references and append to segment with references", () => {
|
||||
const clients = createClientsAtInitialState("","A", "B");
|
||||
|
||||
const messages: ISequencedDocumentMessage[] = [];
|
||||
let seq = 0;
|
||||
messages.push(clients.A.makeOpMessage(clients.A.insertTextLocal(0, "0123456789"),++seq));
|
||||
// initialize the local reference collection on the segment, but keep it empty
|
||||
{
|
||||
const segInfo = clients.A.getContainingSegment(9);
|
||||
const segment = segInfo.segment;
|
||||
assert(TextSegment.is(segment!));
|
||||
assert.strictEqual(segment.text[segInfo.offset!], "9");
|
||||
const localRef =
|
||||
new LocalReference(clients.A, segment, segInfo.offset, ReferenceType.Simple);
|
||||
clients.A.addLocalReference(localRef);
|
||||
clients.A.removeLocalReference(localRef);
|
||||
}
|
||||
// split the segment
|
||||
messages.push(clients.A.makeOpMessage(clients.A.insertTextLocal(5, "ABCD"),++seq));
|
||||
|
||||
// add a local reference to the newly inserted segment that caused the split
|
||||
{
|
||||
const segInfo = clients.A.getContainingSegment(6);
|
||||
const segment = segInfo.segment;
|
||||
assert(TextSegment.is(segment!));
|
||||
assert.strictEqual(segment.text[segInfo.offset!], "B");
|
||||
const localRef =
|
||||
new LocalReference(clients.A, segment, segInfo.offset, ReferenceType.SlideOnRemove);
|
||||
clients.A.addLocalReference(localRef);
|
||||
}
|
||||
// apply all the ops
|
||||
while (messages.length > 0) {
|
||||
const msg = messages.shift()!;
|
||||
clients.all.forEach((c)=>c.applyMsg(msg));
|
||||
}
|
||||
|
||||
// regression: would fire 0x2be on zamboni during segment append
|
||||
clients.all.forEach((c)=>c.updateMinSeq(seq));
|
||||
});
|
||||
});
|
||||
|
|
|
@ -54,12 +54,31 @@ describe("MergeTree", () => {
|
|||
});
|
||||
});
|
||||
|
||||
it("No event on annotation of empty range", () => {
|
||||
const count = countOperations(mergeTree);
|
||||
mergeTree.annotateRange(
|
||||
3,
|
||||
3,
|
||||
{
|
||||
foo: "bar",
|
||||
},
|
||||
undefined,
|
||||
currentSequenceNumber,
|
||||
localClientId,
|
||||
++currentSequenceNumber,
|
||||
undefined as any);
|
||||
|
||||
assert.deepStrictEqual(count, {
|
||||
[MergeTreeMaintenanceType.SPLIT]: 1,
|
||||
});
|
||||
});
|
||||
|
||||
it("Annotate over local insertion", () => {
|
||||
insertText(
|
||||
mergeTree,
|
||||
4,
|
||||
localClientId,
|
||||
currentSequenceNumber,
|
||||
localClientId,
|
||||
UnassignedSequenceNumber,
|
||||
"a",
|
||||
undefined,
|
||||
|
@ -92,8 +111,8 @@ describe("MergeTree", () => {
|
|||
insertText(
|
||||
mergeTree,
|
||||
4,
|
||||
remoteClientId,
|
||||
remoteSequenceNumber,
|
||||
remoteClientId,
|
||||
++remoteSequenceNumber,
|
||||
"a",
|
||||
undefined,
|
||||
|
@ -126,8 +145,8 @@ describe("MergeTree", () => {
|
|||
mergeTree.markRangeRemoved(
|
||||
4,
|
||||
6,
|
||||
remoteClientId,
|
||||
remoteSequenceNumber,
|
||||
remoteClientId,
|
||||
++remoteSequenceNumber,
|
||||
false,
|
||||
undefined as any);
|
||||
|
@ -151,5 +170,38 @@ describe("MergeTree", () => {
|
|||
[MergeTreeMaintenanceType.SPLIT]: 2,
|
||||
});
|
||||
});
|
||||
|
||||
it("Remote annotate within local deletion", () => {
|
||||
const remoteClientId: number = 35;
|
||||
let remoteSequenceNumber = currentSequenceNumber;
|
||||
|
||||
mergeTree.markRangeRemoved(
|
||||
3,
|
||||
8,
|
||||
currentSequenceNumber,
|
||||
localClientId,
|
||||
UnassignedSequenceNumber,
|
||||
false,
|
||||
undefined as any);
|
||||
|
||||
const count = countOperations(mergeTree);
|
||||
|
||||
mergeTree.annotateRange(
|
||||
4,
|
||||
6,
|
||||
{
|
||||
foo: "bar",
|
||||
},
|
||||
undefined,
|
||||
remoteSequenceNumber,
|
||||
remoteClientId,
|
||||
++remoteSequenceNumber,
|
||||
undefined as any);
|
||||
|
||||
assert.deepStrictEqual(count, {
|
||||
[MergeTreeDeltaType.ANNOTATE]: 1,
|
||||
[MergeTreeMaintenanceType.SPLIT]: 2,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -152,5 +152,35 @@ describe("MergeTree", () => {
|
|||
[MergeTreeMaintenanceType.SPLIT]: 2,
|
||||
});
|
||||
});
|
||||
|
||||
it("Local delete shadows remote", () => {
|
||||
const remoteClientId: number = 35;
|
||||
let remoteSequenceNumber = currentSequenceNumber;
|
||||
|
||||
mergeTree.markRangeRemoved(
|
||||
3,
|
||||
6,
|
||||
currentSequenceNumber,
|
||||
localClientId,
|
||||
UnassignedSequenceNumber,
|
||||
false,
|
||||
undefined as any);
|
||||
|
||||
const count = countOperations(mergeTree);
|
||||
|
||||
mergeTree.markRangeRemoved(
|
||||
4,
|
||||
5,
|
||||
remoteSequenceNumber,
|
||||
remoteClientId,
|
||||
++remoteSequenceNumber,
|
||||
false,
|
||||
undefined as any);
|
||||
|
||||
assert.deepStrictEqual(count, {
|
||||
/* MergeTreeDeltaType.REMOVE is absent as it should not be fired. */
|
||||
[MergeTreeMaintenanceType.SPLIT]: 2,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,7 +10,7 @@ import * as fs from "fs";
|
|||
import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
|
||||
import random from "random-js";
|
||||
import { LocalReference } from "../localReference";
|
||||
import { IMergeTreeOp, MergeTreeDeltaType } from "../ops";
|
||||
import { IMergeTreeOp, MergeTreeDeltaType, ReferenceType } from "../ops";
|
||||
import { TextSegment } from "../textSegment";
|
||||
import { ISegment, SegmentGroup } from "../mergeTree";
|
||||
import { TestClient } from "./testClient";
|
||||
|
@ -44,9 +44,13 @@ export const insertAtRefPos: TestOperation =
|
|||
if(segs.length > 0) {
|
||||
const text = client.longClientId!.repeat(random.integer(1, 3)(mt));
|
||||
const seg = random.pick(mt,segs);
|
||||
return client.insertAtReferencePositionLocal(
|
||||
new LocalReference(client, seg, random.integer(0, seg.cachedLength - 1)(mt)),
|
||||
TextSegment.make(text));
|
||||
const lref = new LocalReference(
|
||||
client, seg, random.integer(0, seg.cachedLength - 1)(mt),
|
||||
random.pick(mt,[ReferenceType.Simple, ReferenceType.SlideOnRemove, ReferenceType.Transient]));
|
||||
if(lref.refType !== ReferenceType.Transient) {
|
||||
client.addLocalReference(lref);
|
||||
}
|
||||
return client.insertAtReferencePositionLocal(lref,TextSegment.make(text));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -168,6 +168,10 @@ export class TestClientLogger {
|
|||
return baseText;
|
||||
}
|
||||
|
||||
static validate(clients: readonly TestClient[], title?: string) {
|
||||
return new TestClientLogger(clients, title).validate();
|
||||
}
|
||||
|
||||
public toString(excludeHeader: boolean = false) {
|
||||
let str = "";
|
||||
if(!excludeHeader) {
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
/*!
|
||||
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
||||
* Licensed under the MIT License.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"@fluidframework/eslint-config-fluid/strict"
|
||||
],
|
||||
"parserOptions": {
|
||||
"project": ["./tsconfig.json", "./src/test/tsconfig.json"]
|
||||
},
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
# Compiled TypeScript and CSS
|
||||
dist
|
||||
lib
|
||||
|
||||
# Babel
|
||||
public/scripts/es5
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
.cache-loader
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directory
|
||||
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
|
||||
node_modules
|
||||
|
||||
# Typings
|
||||
typings
|
||||
|
||||
# Debug log from npm
|
||||
npm-debug.log
|
||||
|
||||
# Code coverage
|
||||
nyc
|
||||
.nyc_output/
|
||||
|
||||
# Chart dependencies
|
||||
**/charts/*.tgz
|
||||
|
||||
# Generated modules
|
||||
intel_modules/
|
||||
temp_modules/
|
|
@ -0,0 +1,6 @@
|
|||
nyc
|
||||
*.log
|
||||
**/*.tsbuildinfo
|
||||
src/test
|
||||
dist/test
|
||||
**/_api-extractor-temp/**
|
|
@ -0,0 +1,21 @@
|
|||
Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
||||
|
||||
MIT License
|
||||
|
||||
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.
|
|
@ -0,0 +1,15 @@
|
|||
# @fluid-internal/quorum
|
||||
|
||||
<!-- AUTO-GENERATED-CONTENT:START (TEMPLATE:src=readme-simple.md) -->
|
||||
<!-- This section is automatically generated. To update it, edit docs/md-magic.config.js then run
|
||||
'npm run build:md-magic' in the docs folder. -->
|
||||
|
||||
Documentation available at <https://fluidframework.com/docs/apis/quorum>.
|
||||
|
||||
## Trademark
|
||||
|
||||
This project may contain Microsoft trademarks or logos for Microsoft projects, products, or services. Use of these trademarks
|
||||
or logos must follow Microsoft's [Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general).
|
||||
Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship.
|
||||
|
||||
<!-- AUTO-GENERATED-CONTENT:END -->
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче