diff --git a/common/build/build-common/tsc-multi.test.json b/common/build/build-common/tsc-multi.test.json index f59909ee4f30..8cfaf1c4286c 100644 --- a/common/build/build-common/tsc-multi.test.json +++ b/common/build/build-common/tsc-multi.test.json @@ -1,4 +1,4 @@ { - "targets": [{ "extname": ".cjs", "module": "CommonJS", "moduleResolution": "Node10" }], + "targets": [{ "extname": ".cjs", "module": "CommonJS", "moduleResolution": "Node16" }], "projects": ["./tsconfig.json", "./src/test/tsconfig.json"] } diff --git a/fluidBuild.config.cjs b/fluidBuild.config.cjs index 8499652a48d6..8c0b22cf4ed2 100644 --- a/fluidBuild.config.cjs +++ b/fluidBuild.config.cjs @@ -3,7 +3,7 @@ * Licensed under the MIT License. */ -const tscDependsOn = ["^tsc", "^api", "build:genver"]; +const tscDependsOn = ["^tsc", "^api", "^build:rename-types", "build:genver"]; /** * The settings in this file configure the Fluid build tools, such as fluid-build and flub. Some settings apply to the * whole repo, while others apply only to the client release group. @@ -23,7 +23,13 @@ module.exports = { script: false, }, "compile": { - dependsOn: ["commonjs", "build:esnext", "build:test", "build:copy"], + dependsOn: [ + "commonjs", + "build:esnext", + "build:test", + "build:copy", + "build:rename-types", + ], script: false, }, "commonjs": { @@ -58,10 +64,11 @@ module.exports = { dependsOn: ["api-extractor:commonjs", "api-extractor:esnext"], script: false, }, - "api-extractor:commonjs": [...tscDependsOn, "tsc"], - "api-extractor:esnext": [...tscDependsOn, "api-extractor:commonjs", "build:esnext"], - "build:docs": [...tscDependsOn, "tsc"], - "ci:build:docs": [...tscDependsOn, "tsc"], + "api-extractor:commonjs": ["tsc"], + "api-extractor:esnext": ["api-extractor:commonjs", "build:esnext"], + "build:rename-types": ["build:esnext", "api-extractor:esnext"], + "build:docs": ["tsc"], + "ci:build:docs": ["tsc"], "build:readme": { dependsOn: ["build:manifest"], script: true, @@ -159,9 +166,17 @@ module.exports = { // Can be removed once the policy handler is updated to support tsc-multi as equivalent to tsc. "^azure/packages/azure-client/package.json", "^azure/packages/azure-service-utils/package.json", + "^experimental/dds/tree2/package.json", + "^experimental/dds/sequence-deprecated/package.json", + "^experimental/framework/tree-react-api/package.json", + "^packages/common/.*/package.json", "^packages/dds/.*/package.json", "^packages/drivers/.*/package.json", "^packages/framework/.*/package.json", + "^packages/loader/.*/package.json", + "^packages/runtime/.*/package.json", + "^packages/service-clients/.*/package.json", + "^packages/utils/.*/package.json", "^packages/loader/container-loader/package.json", ], "html-copyright-file-header": [ @@ -217,9 +232,10 @@ module.exports = { "^tools/getkeys", ], "npm-package-json-esm": [ - // This is an ESM-only package, and uses tsc to build the ESM output. The policy handler doesn't understand this + // These are ESM-only packages and use tsc to build the ESM output. The policy handler doesn't understand this // case. "packages/dds/migration-shim/package.json", + "packages/test/functional-tests/package.json", ], // This handler will be rolled out slowly, so excluding most packages here while we roll it out. "npm-package-exports-field": [ @@ -315,6 +331,9 @@ module.exports = { ["depcruise", "dependency-cruiser"], ["copyfiles", "copyfiles"], ["oclif", "oclif"], + ["renamer", "renamer"], + ["tsc-multi", "tsc-multi"], + ["attw", "@arethetypeswrong/cli"], ], }, // These packages are independently versioned and released, but we use pnpm workspaces in single packages to work diff --git a/packages/common/client-utils/jest.config.js b/packages/common/client-utils/jest.config.js index 8341b38a5c84..012abaedc52e 100644 --- a/packages/common/client-utils/jest.config.js +++ b/packages/common/client-utils/jest.config.js @@ -15,6 +15,6 @@ module.exports = { }, ], ], - testMatch: ["**/dist/test/jest/?(*.)+(spec|test).js"], + testMatch: ["**/dist/test/jest/?(*.)+(spec|test).?js"], testPathIgnorePatterns: ["/node_modules/"], }; diff --git a/packages/common/client-utils/package.json b/packages/common/client-utils/package.json index 286c15c92a69..259f90c6252d 100644 --- a/packages/common/client-utils/package.json +++ b/packages/common/client-utils/package.json @@ -11,11 +11,11 @@ "license": "MIT", "author": "Microsoft and contributors", "sideEffects": false, - "main": "dist/index.js", - "module": "lib/index.js", + "main": "dist/index.cjs", + "module": "lib/index.mjs", "browser": { - "./dist/indexNode.js": "./dist/indexBrowser.js", - "./lib/indexNode.js": "./lib/indexBrowser.js" + "./dist/indexNode.cjs": "./dist/indexBrowser.cjs", + "./lib/indexNode.mjs": "./lib/indexBrowser.mjs" }, "types": "dist/index.d.ts", "scripts": { @@ -26,11 +26,9 @@ "build:commonjs": "fluid-build . --task commonjs", "build:compile": "fluid-build . --task compile", "build:docs": "fluid-build . --task api", - "build:esnext": "tsc --project ./tsconfig.esnext.json", - "build:test": "concurrently npm:build:test:mocha npm:build:test:jest npm:build:test:types", - "build:test:jest": "tsc --project ./src/test/jest/tsconfig.json", - "build:test:mocha": "tsc --project ./src/test/mocha/tsconfig.json", - "build:test:types": "tsc --project ./src/test/types/tsconfig.json", + "build:esnext": "tsc-multi --config ../../../common/build/build-common/tsc-multi.esm.json", + "build:rename-types": "renamer \"lib/**\" -f .d.ts -r .d.mts --force", + "build:test": "tsc-multi --config ./tsc-multi.test.json", "check:are-the-types-wrong": "attw --pack", "check:release-tags": "api-extractor run --local --config ./api-extractor-lint.json", "ci:build:docs": "api-extractor run", @@ -45,8 +43,8 @@ "test": "npm run test:mocha && npm run test:jest", "test:coverage": "c8 npm test", "test:jest": "jest", - "test:mocha": "mocha --recursive \"dist/test/mocha/**/*.spec.js\" --exit --project test/tsconfig.json", - "tsc": "tsc", + "test:mocha": "mocha --recursive \"dist/test/mocha/**/*.spec.?js\" --exit --project test/tsconfig.json", + "tsc": "tsc-multi --config ../../../common/build/build-common/tsc-multi.cjs.json", "typetests:gen": "fluid-type-test-generator", "typetests:prepare": "flub typetests --dir . --reset --previous --normalize" }, @@ -82,6 +80,7 @@ }, "devDependencies": { "@arethetypeswrong/cli": "^0.13.3", + "@fluid-internal/client-utils-previous": "npm:@fluid-internal/client-utils@2.0.0-internal.7.3.0", "@fluid-tools/build-cli": "^0.28.0", "@fluidframework/build-common": "^2.0.3", "@fluidframework/build-tools": "^0.28.0", @@ -112,21 +111,17 @@ "moment": "^2.21.0", "prettier": "~3.0.3", "puppeteer": "^17.1.3", + "renamer": "^4.0.0", "rewire": "^5.0.0", "rimraf": "^4.4.0", "sinon": "^7.4.2", "ts-jest": "^29.1.1", "ts-node": "^10.9.1", + "tsc-multi": "^1.1.0", "typescript": "~5.1.6" }, "fluidBuild": { "tasks": { - "eslint": [ - "tsc", - "build:test:mocha", - "build:test:jest", - "build:test:types" - ], "build:docs": { "dependsOn": [ "...", @@ -134,20 +129,10 @@ "api-extractor:esnext" ], "script": false - }, - "build:test:jest": [ - "tsc" - ], - "build:test:mocha": [ - "tsc" - ], - "build:test:types": [ - "tsc" - ] + } } }, "typeValidation": { - "disabled": true, "broken": {} } } diff --git a/packages/common/client-utils/src/test/jest/gitHash.spec.ts b/packages/common/client-utils/src/test/jest/gitHash.spec.ts index e9b4677ee195..76c503dcdcfc 100644 --- a/packages/common/client-utils/src/test/jest/gitHash.spec.ts +++ b/packages/common/client-utils/src/test/jest/gitHash.spec.ts @@ -15,7 +15,7 @@ import rewire from "rewire"; import * as HashNode from "../../hashFileNode"; // Use rewire to access private functions -const HashBrowser = rewire("../../hashFileBrowser"); +const HashBrowser = rewire("../../hashFileBrowser.cjs"); async function getFileContents(p: string): Promise { return new Promise((resolve, reject) => { diff --git a/packages/common/client-utils/src/test/mocha/eventForwarder.spec.ts b/packages/common/client-utils/src/test/mocha/eventForwarder.spec.ts index 7169842446ee..0f24df851175 100644 --- a/packages/common/client-utils/src/test/mocha/eventForwarder.spec.ts +++ b/packages/common/client-utils/src/test/mocha/eventForwarder.spec.ts @@ -6,7 +6,7 @@ import { strict as assert } from "node:assert"; import { EventEmitter } from "node:events"; import { IErrorEvent } from "@fluidframework/core-interfaces"; -import { EventForwarder } from "../.."; +import { EventForwarder } from "../../eventForwarder"; interface ITestEvents extends IErrorEvent { (event: "testEvent", listener: (name: string, count: number) => void); diff --git a/packages/common/client-utils/src/test/mocha/typedEventEmitter.spec.ts b/packages/common/client-utils/src/test/mocha/typedEventEmitter.spec.ts index 1a5ec561d98b..e4f2dbf08093 100644 --- a/packages/common/client-utils/src/test/mocha/typedEventEmitter.spec.ts +++ b/packages/common/client-utils/src/test/mocha/typedEventEmitter.spec.ts @@ -4,7 +4,7 @@ */ import { strict as assert } from "node:assert"; import { IErrorEvent } from "@fluidframework/core-interfaces"; -import { TypedEventEmitter } from "../.."; +import { TypedEventEmitter } from "../../typedEventEmitter"; describe("TypedEventEmitter", () => { it("Validate Function proxies", () => { diff --git a/packages/common/client-utils/src/test/types/validateClientUtilsPrevious.generated.ts b/packages/common/client-utils/src/test/types/validateClientUtilsPrevious.generated.ts new file mode 100644 index 000000000000..cc3d71be71df --- /dev/null +++ b/packages/common/client-utils/src/test/types/validateClientUtilsPrevious.generated.ts @@ -0,0 +1,502 @@ +/*! + * Copyright (c) Microsoft Corporation and contributors. All rights reserved. + * Licensed under the MIT License. + */ +/* + * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. + * Generated by fluid-type-test-generator in @fluidframework/build-tools. + */ +import type * as old from "@fluid-internal/client-utils-previous"; +import type * as current from "../../index"; + + +// See 'build-tools/src/type-test-generator/compatibility.ts' for more information. +type TypeOnly = T extends number + ? number + : T extends string + ? string + : T extends boolean | bigint | symbol + ? T + : { + [P in keyof T]: TypeOnly; + }; + +/* +* Validate forward compat by using old type in place of current type +* If breaking change required, add in package.json under typeValidation.broken: +* "ClassDeclaration_Buffer": {"forwardCompat": false} +*/ +declare function get_old_ClassDeclaration_Buffer(): + TypeOnly; +declare function use_current_ClassDeclaration_Buffer( + use: TypeOnly): void; +use_current_ClassDeclaration_Buffer( + get_old_ClassDeclaration_Buffer()); + +/* +* Validate back compat by using current type in place of old type +* If breaking change required, add in package.json under typeValidation.broken: +* "ClassDeclaration_Buffer": {"backCompat": false} +*/ +declare function get_current_ClassDeclaration_Buffer(): + TypeOnly; +declare function use_old_ClassDeclaration_Buffer( + use: TypeOnly): void; +use_old_ClassDeclaration_Buffer( + get_current_ClassDeclaration_Buffer()); + +/* +* Validate forward compat by using old type in place of current type +* If breaking change required, add in package.json under typeValidation.broken: +* "TypeAliasDeclaration_EventEmitterEventType": {"forwardCompat": false} +*/ +declare function get_old_TypeAliasDeclaration_EventEmitterEventType(): + TypeOnly; +declare function use_current_TypeAliasDeclaration_EventEmitterEventType( + use: TypeOnly): void; +use_current_TypeAliasDeclaration_EventEmitterEventType( + get_old_TypeAliasDeclaration_EventEmitterEventType()); + +/* +* Validate back compat by using current type in place of old type +* If breaking change required, add in package.json under typeValidation.broken: +* "TypeAliasDeclaration_EventEmitterEventType": {"backCompat": false} +*/ +declare function get_current_TypeAliasDeclaration_EventEmitterEventType(): + TypeOnly; +declare function use_old_TypeAliasDeclaration_EventEmitterEventType( + use: TypeOnly): void; +use_old_TypeAliasDeclaration_EventEmitterEventType( + get_current_TypeAliasDeclaration_EventEmitterEventType()); + +/* +* Validate forward compat by using old type in place of current type +* If breaking change required, add in package.json under typeValidation.broken: +* "ClassDeclaration_EventForwarder": {"forwardCompat": false} +*/ +declare function get_old_ClassDeclaration_EventForwarder(): + TypeOnly; +declare function use_current_ClassDeclaration_EventForwarder( + use: TypeOnly): void; +use_current_ClassDeclaration_EventForwarder( + get_old_ClassDeclaration_EventForwarder()); + +/* +* Validate back compat by using current type in place of old type +* If breaking change required, add in package.json under typeValidation.broken: +* "ClassDeclaration_EventForwarder": {"backCompat": false} +*/ +declare function get_current_ClassDeclaration_EventForwarder(): + TypeOnly; +declare function use_old_ClassDeclaration_EventForwarder( + use: TypeOnly): void; +use_old_ClassDeclaration_EventForwarder( + get_current_ClassDeclaration_EventForwarder()); + +/* +* Validate forward compat by using old type in place of current type +* If breaking change required, add in package.json under typeValidation.broken: +* "InterfaceDeclaration_ITraceEvent": {"forwardCompat": false} +*/ +declare function get_old_InterfaceDeclaration_ITraceEvent(): + TypeOnly; +declare function use_current_InterfaceDeclaration_ITraceEvent( + use: TypeOnly): void; +use_current_InterfaceDeclaration_ITraceEvent( + get_old_InterfaceDeclaration_ITraceEvent()); + +/* +* Validate back compat by using current type in place of old type +* If breaking change required, add in package.json under typeValidation.broken: +* "InterfaceDeclaration_ITraceEvent": {"backCompat": false} +*/ +declare function get_current_InterfaceDeclaration_ITraceEvent(): + TypeOnly; +declare function use_old_InterfaceDeclaration_ITraceEvent( + use: TypeOnly): void; +use_old_InterfaceDeclaration_ITraceEvent( + get_current_InterfaceDeclaration_ITraceEvent()); + +/* +* Validate forward compat by using old type in place of current type +* If breaking change required, add in package.json under typeValidation.broken: +* "VariableDeclaration_IsoBuffer": {"forwardCompat": false} +*/ +declare function get_old_VariableDeclaration_IsoBuffer(): + TypeOnly; +declare function use_current_VariableDeclaration_IsoBuffer( + use: TypeOnly): void; +use_current_VariableDeclaration_IsoBuffer( + get_old_VariableDeclaration_IsoBuffer()); + +/* +* Validate back compat by using current type in place of old type +* If breaking change required, add in package.json under typeValidation.broken: +* "VariableDeclaration_IsoBuffer": {"backCompat": false} +*/ +declare function get_current_VariableDeclaration_IsoBuffer(): + TypeOnly; +declare function use_old_VariableDeclaration_IsoBuffer( + use: TypeOnly): void; +use_old_VariableDeclaration_IsoBuffer( + get_current_VariableDeclaration_IsoBuffer()); + +/* +* Validate forward compat by using old type in place of current type +* If breaking change required, add in package.json under typeValidation.broken: +* "TypeAliasDeclaration_IsoBuffer": {"forwardCompat": false} +*/ +declare function get_old_TypeAliasDeclaration_IsoBuffer(): + TypeOnly; +declare function use_current_TypeAliasDeclaration_IsoBuffer( + use: TypeOnly): void; +use_current_TypeAliasDeclaration_IsoBuffer( + get_old_TypeAliasDeclaration_IsoBuffer()); + +/* +* Validate back compat by using current type in place of old type +* If breaking change required, add in package.json under typeValidation.broken: +* "TypeAliasDeclaration_IsoBuffer": {"backCompat": false} +*/ +declare function get_current_TypeAliasDeclaration_IsoBuffer(): + TypeOnly; +declare function use_old_TypeAliasDeclaration_IsoBuffer( + use: TypeOnly): void; +use_old_TypeAliasDeclaration_IsoBuffer( + get_current_TypeAliasDeclaration_IsoBuffer()); + +/* +* Validate forward compat by using old type in place of current type +* If breaking change required, add in package.json under typeValidation.broken: +* "TypeAliasDeclaration_IsomorphicPerformance": {"forwardCompat": false} +*/ +declare function get_old_TypeAliasDeclaration_IsomorphicPerformance(): + TypeOnly; +declare function use_current_TypeAliasDeclaration_IsomorphicPerformance( + use: TypeOnly): void; +use_current_TypeAliasDeclaration_IsomorphicPerformance( + get_old_TypeAliasDeclaration_IsomorphicPerformance()); + +/* +* Validate back compat by using current type in place of old type +* If breaking change required, add in package.json under typeValidation.broken: +* "TypeAliasDeclaration_IsomorphicPerformance": {"backCompat": false} +*/ +declare function get_current_TypeAliasDeclaration_IsomorphicPerformance(): + TypeOnly; +declare function use_old_TypeAliasDeclaration_IsomorphicPerformance( + use: TypeOnly): void; +use_old_TypeAliasDeclaration_IsomorphicPerformance( + get_current_TypeAliasDeclaration_IsomorphicPerformance()); + +/* +* Validate forward compat by using old type in place of current type +* If breaking change required, add in package.json under typeValidation.broken: +* "ClassDeclaration_Trace": {"forwardCompat": false} +*/ +declare function get_old_ClassDeclaration_Trace(): + TypeOnly; +declare function use_current_ClassDeclaration_Trace( + use: TypeOnly): void; +use_current_ClassDeclaration_Trace( + get_old_ClassDeclaration_Trace()); + +/* +* Validate back compat by using current type in place of old type +* If breaking change required, add in package.json under typeValidation.broken: +* "ClassDeclaration_Trace": {"backCompat": false} +*/ +declare function get_current_ClassDeclaration_Trace(): + TypeOnly; +declare function use_old_ClassDeclaration_Trace( + use: TypeOnly): void; +use_old_ClassDeclaration_Trace( + get_current_ClassDeclaration_Trace()); + +/* +* Validate forward compat by using old type in place of current type +* If breaking change required, add in package.json under typeValidation.broken: +* "ClassDeclaration_TypedEventEmitter": {"forwardCompat": false} +*/ +declare function get_old_ClassDeclaration_TypedEventEmitter(): + TypeOnly>; +declare function use_current_ClassDeclaration_TypedEventEmitter( + use: TypeOnly>): void; +use_current_ClassDeclaration_TypedEventEmitter( + get_old_ClassDeclaration_TypedEventEmitter()); + +/* +* Validate back compat by using current type in place of old type +* If breaking change required, add in package.json under typeValidation.broken: +* "ClassDeclaration_TypedEventEmitter": {"backCompat": false} +*/ +declare function get_current_ClassDeclaration_TypedEventEmitter(): + TypeOnly>; +declare function use_old_ClassDeclaration_TypedEventEmitter( + use: TypeOnly>): void; +use_old_ClassDeclaration_TypedEventEmitter( + get_current_ClassDeclaration_TypedEventEmitter()); + +/* +* Validate forward compat by using old type in place of current type +* If breaking change required, add in package.json under typeValidation.broken: +* "TypeAliasDeclaration_TypedEventTransform": {"forwardCompat": false} +*/ +declare function get_old_TypeAliasDeclaration_TypedEventTransform(): + TypeOnly>; +declare function use_current_TypeAliasDeclaration_TypedEventTransform( + use: TypeOnly>): void; +use_current_TypeAliasDeclaration_TypedEventTransform( + get_old_TypeAliasDeclaration_TypedEventTransform()); + +/* +* Validate back compat by using current type in place of old type +* If breaking change required, add in package.json under typeValidation.broken: +* "TypeAliasDeclaration_TypedEventTransform": {"backCompat": false} +*/ +declare function get_current_TypeAliasDeclaration_TypedEventTransform(): + TypeOnly>; +declare function use_old_TypeAliasDeclaration_TypedEventTransform( + use: TypeOnly>): void; +use_old_TypeAliasDeclaration_TypedEventTransform( + get_current_TypeAliasDeclaration_TypedEventTransform()); + +/* +* Validate forward compat by using old type in place of current type +* If breaking change required, add in package.json under typeValidation.broken: +* "FunctionDeclaration_Uint8ArrayToArrayBuffer": {"forwardCompat": false} +*/ +declare function get_old_FunctionDeclaration_Uint8ArrayToArrayBuffer(): + TypeOnly; +declare function use_current_FunctionDeclaration_Uint8ArrayToArrayBuffer( + use: TypeOnly): void; +use_current_FunctionDeclaration_Uint8ArrayToArrayBuffer( + get_old_FunctionDeclaration_Uint8ArrayToArrayBuffer()); + +/* +* Validate back compat by using current type in place of old type +* If breaking change required, add in package.json under typeValidation.broken: +* "FunctionDeclaration_Uint8ArrayToArrayBuffer": {"backCompat": false} +*/ +declare function get_current_FunctionDeclaration_Uint8ArrayToArrayBuffer(): + TypeOnly; +declare function use_old_FunctionDeclaration_Uint8ArrayToArrayBuffer( + use: TypeOnly): void; +use_old_FunctionDeclaration_Uint8ArrayToArrayBuffer( + get_current_FunctionDeclaration_Uint8ArrayToArrayBuffer()); + +/* +* Validate forward compat by using old type in place of current type +* If breaking change required, add in package.json under typeValidation.broken: +* "FunctionDeclaration_Uint8ArrayToString": {"forwardCompat": false} +*/ +declare function get_old_FunctionDeclaration_Uint8ArrayToString(): + TypeOnly; +declare function use_current_FunctionDeclaration_Uint8ArrayToString( + use: TypeOnly): void; +use_current_FunctionDeclaration_Uint8ArrayToString( + get_old_FunctionDeclaration_Uint8ArrayToString()); + +/* +* Validate back compat by using current type in place of old type +* If breaking change required, add in package.json under typeValidation.broken: +* "FunctionDeclaration_Uint8ArrayToString": {"backCompat": false} +*/ +declare function get_current_FunctionDeclaration_Uint8ArrayToString(): + TypeOnly; +declare function use_old_FunctionDeclaration_Uint8ArrayToString( + use: TypeOnly): void; +use_old_FunctionDeclaration_Uint8ArrayToString( + get_current_FunctionDeclaration_Uint8ArrayToString()); + +/* +* Validate forward compat by using old type in place of current type +* If breaking change required, add in package.json under typeValidation.broken: +* "VariableDeclaration_bufferToString": {"forwardCompat": false} +*/ +declare function get_old_VariableDeclaration_bufferToString(): + TypeOnly; +declare function use_current_VariableDeclaration_bufferToString( + use: TypeOnly): void; +use_current_VariableDeclaration_bufferToString( + get_old_VariableDeclaration_bufferToString()); + +/* +* Validate back compat by using current type in place of old type +* If breaking change required, add in package.json under typeValidation.broken: +* "VariableDeclaration_bufferToString": {"backCompat": false} +*/ +declare function get_current_VariableDeclaration_bufferToString(): + TypeOnly; +declare function use_old_VariableDeclaration_bufferToString( + use: TypeOnly): void; +use_old_VariableDeclaration_bufferToString( + get_current_VariableDeclaration_bufferToString()); + +/* +* Validate forward compat by using old type in place of current type +* If breaking change required, add in package.json under typeValidation.broken: +* "VariableDeclaration_fromBase64ToUtf8": {"forwardCompat": false} +*/ +declare function get_old_VariableDeclaration_fromBase64ToUtf8(): + TypeOnly; +declare function use_current_VariableDeclaration_fromBase64ToUtf8( + use: TypeOnly): void; +use_current_VariableDeclaration_fromBase64ToUtf8( + get_old_VariableDeclaration_fromBase64ToUtf8()); + +/* +* Validate back compat by using current type in place of old type +* If breaking change required, add in package.json under typeValidation.broken: +* "VariableDeclaration_fromBase64ToUtf8": {"backCompat": false} +*/ +declare function get_current_VariableDeclaration_fromBase64ToUtf8(): + TypeOnly; +declare function use_old_VariableDeclaration_fromBase64ToUtf8( + use: TypeOnly): void; +use_old_VariableDeclaration_fromBase64ToUtf8( + get_current_VariableDeclaration_fromBase64ToUtf8()); + +/* +* Validate forward compat by using old type in place of current type +* If breaking change required, add in package.json under typeValidation.broken: +* "VariableDeclaration_fromUtf8ToBase64": {"forwardCompat": false} +*/ +declare function get_old_VariableDeclaration_fromUtf8ToBase64(): + TypeOnly; +declare function use_current_VariableDeclaration_fromUtf8ToBase64( + use: TypeOnly): void; +use_current_VariableDeclaration_fromUtf8ToBase64( + get_old_VariableDeclaration_fromUtf8ToBase64()); + +/* +* Validate back compat by using current type in place of old type +* If breaking change required, add in package.json under typeValidation.broken: +* "VariableDeclaration_fromUtf8ToBase64": {"backCompat": false} +*/ +declare function get_current_VariableDeclaration_fromUtf8ToBase64(): + TypeOnly; +declare function use_old_VariableDeclaration_fromUtf8ToBase64( + use: TypeOnly): void; +use_old_VariableDeclaration_fromUtf8ToBase64( + get_current_VariableDeclaration_fromUtf8ToBase64()); + +/* +* Validate forward compat by using old type in place of current type +* If breaking change required, add in package.json under typeValidation.broken: +* "FunctionDeclaration_gitHashFile": {"forwardCompat": false} +*/ +declare function get_old_FunctionDeclaration_gitHashFile(): + TypeOnly; +declare function use_current_FunctionDeclaration_gitHashFile( + use: TypeOnly): void; +use_current_FunctionDeclaration_gitHashFile( + get_old_FunctionDeclaration_gitHashFile()); + +/* +* Validate back compat by using current type in place of old type +* If breaking change required, add in package.json under typeValidation.broken: +* "FunctionDeclaration_gitHashFile": {"backCompat": false} +*/ +declare function get_current_FunctionDeclaration_gitHashFile(): + TypeOnly; +declare function use_old_FunctionDeclaration_gitHashFile( + use: TypeOnly): void; +use_old_FunctionDeclaration_gitHashFile( + get_current_FunctionDeclaration_gitHashFile()); + +/* +* Validate forward compat by using old type in place of current type +* If breaking change required, add in package.json under typeValidation.broken: +* "FunctionDeclaration_hashFile": {"forwardCompat": false} +*/ +declare function get_old_FunctionDeclaration_hashFile(): + TypeOnly; +declare function use_current_FunctionDeclaration_hashFile( + use: TypeOnly): void; +use_current_FunctionDeclaration_hashFile( + get_old_FunctionDeclaration_hashFile()); + +/* +* Validate back compat by using current type in place of old type +* If breaking change required, add in package.json under typeValidation.broken: +* "FunctionDeclaration_hashFile": {"backCompat": false} +*/ +declare function get_current_FunctionDeclaration_hashFile(): + TypeOnly; +declare function use_old_FunctionDeclaration_hashFile( + use: TypeOnly): void; +use_old_FunctionDeclaration_hashFile( + get_current_FunctionDeclaration_hashFile()); + +/* +* Validate forward compat by using old type in place of current type +* If breaking change required, add in package.json under typeValidation.broken: +* "VariableDeclaration_performance": {"forwardCompat": false} +*/ +declare function get_old_VariableDeclaration_performance(): + TypeOnly; +declare function use_current_VariableDeclaration_performance( + use: TypeOnly): void; +use_current_VariableDeclaration_performance( + get_old_VariableDeclaration_performance()); + +/* +* Validate back compat by using current type in place of old type +* If breaking change required, add in package.json under typeValidation.broken: +* "VariableDeclaration_performance": {"backCompat": false} +*/ +declare function get_current_VariableDeclaration_performance(): + TypeOnly; +declare function use_old_VariableDeclaration_performance( + use: TypeOnly): void; +use_old_VariableDeclaration_performance( + get_current_VariableDeclaration_performance()); + +/* +* Validate forward compat by using old type in place of current type +* If breaking change required, add in package.json under typeValidation.broken: +* "FunctionDeclaration_stringToBuffer": {"forwardCompat": false} +*/ +declare function get_old_FunctionDeclaration_stringToBuffer(): + TypeOnly; +declare function use_current_FunctionDeclaration_stringToBuffer( + use: TypeOnly): void; +use_current_FunctionDeclaration_stringToBuffer( + get_old_FunctionDeclaration_stringToBuffer()); + +/* +* Validate back compat by using current type in place of old type +* If breaking change required, add in package.json under typeValidation.broken: +* "FunctionDeclaration_stringToBuffer": {"backCompat": false} +*/ +declare function get_current_FunctionDeclaration_stringToBuffer(): + TypeOnly; +declare function use_old_FunctionDeclaration_stringToBuffer( + use: TypeOnly): void; +use_old_FunctionDeclaration_stringToBuffer( + get_current_FunctionDeclaration_stringToBuffer()); + +/* +* Validate forward compat by using old type in place of current type +* If breaking change required, add in package.json under typeValidation.broken: +* "VariableDeclaration_toUtf8": {"forwardCompat": false} +*/ +declare function get_old_VariableDeclaration_toUtf8(): + TypeOnly; +declare function use_current_VariableDeclaration_toUtf8( + use: TypeOnly): void; +use_current_VariableDeclaration_toUtf8( + get_old_VariableDeclaration_toUtf8()); + +/* +* Validate back compat by using current type in place of old type +* If breaking change required, add in package.json under typeValidation.broken: +* "VariableDeclaration_toUtf8": {"backCompat": false} +*/ +declare function get_current_VariableDeclaration_toUtf8(): + TypeOnly; +declare function use_old_VariableDeclaration_toUtf8( + use: TypeOnly): void; +use_old_VariableDeclaration_toUtf8( + get_current_VariableDeclaration_toUtf8()); diff --git a/packages/common/client-utils/tsc-multi.test.json b/packages/common/client-utils/tsc-multi.test.json new file mode 100644 index 000000000000..ea43dadf7600 --- /dev/null +++ b/packages/common/client-utils/tsc-multi.test.json @@ -0,0 +1,4 @@ +{ + "targets": [{ "extname": ".cjs", "module": "CommonJS", "moduleResolution": "Node16" }], + "projects": ["./tsconfig.json", "./src/test/jest/tsconfig.json", "./src/test/mocha/tsconfig.json"] +} diff --git a/packages/common/client-utils/tsconfig.esnext.json b/packages/common/client-utils/tsconfig.esnext.json deleted file mode 100644 index 3c2dddb86236..000000000000 --- a/packages/common/client-utils/tsconfig.esnext.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": ["./tsconfig.json", "../../../common/build/build-common/tsconfig.esm.json"], - "compilerOptions": { - "outDir": "./lib", - }, -} diff --git a/packages/dds/merge-tree/.npmignore b/packages/dds/merge-tree/.npmignore index 38855da2b48a..d7a2581775be 100644 --- a/packages/dds/merge-tree/.npmignore +++ b/packages/dds/merge-tree/.npmignore @@ -2,8 +2,12 @@ nyc *.log **/*.tsbuildinfo src/test -dist/test **/_api-extractor-temp/** docs/ .vscode/ + +# We technically don't need to distribute the compiled test code, but because it's imported in the sequence package, +# including it in the package makes it a lot easier to test using standardized tools. If we don't include the test code, +# then the ./test export is invalid, so it will fail to import anywhere outside the repo. +# dist/test diff --git a/packages/dds/merge-tree/package.json b/packages/dds/merge-tree/package.json index 8a0303cb8954..c3b8beefbb94 100644 --- a/packages/dds/merge-tree/package.json +++ b/packages/dds/merge-tree/package.json @@ -11,8 +11,30 @@ "license": "MIT", "author": "Microsoft and contributors", "sideEffects": false, - "main": "dist/index.js", - "module": "lib/index.js", + "exports": { + ".": { + "import": { + "types": "./lib/index.d.mts", + "default": "./lib/index.mjs" + }, + "require": { + "types": "./dist/index.d.ts", + "default": "./dist/index.cjs" + } + }, + "./dist/test": { + "import": { + "types": "./dist/test/index.d.ts", + "default": "./dist/test/index.cjs" + }, + "require": { + "types": "./dist/test/index.d.ts", + "default": "./dist/test/index.cjs" + } + } + }, + "main": "dist/index.cjs", + "module": "lib/index.mjs", "types": "dist/index.d.ts", "scripts": { "api": "fluid-build . --task api", @@ -22,8 +44,9 @@ "build:commonjs": "fluid-build . --task commonjs", "build:compile": "fluid-build . --task compile", "build:docs": "fluid-build . --task api", - "build:esnext": "tsc --project ./tsconfig.esnext.json", - "build:test": "tsc --project ./src/test/tsconfig.json", + "build:esnext": "tsc-multi --config ../../../common/build/build-common/tsc-multi.esm.json", + "build:rename-types": "renamer \"lib/**\" -f .d.ts -r .d.mts --force", + "build:test": "tsc-multi --config ./tsc-multi.test.json", "check:are-the-types-wrong": "attw --pack", "check:release-tags": "api-extractor run --local --config ./api-extractor-lint.json", "ci:build:docs": "api-extractor run", @@ -45,7 +68,7 @@ "test:mocha": "mocha --ignore \"dist/test/types/*\" --recursive dist/test", "test:mocha:verbose": "cross-env FLUID_TEST_VERBOSE=1 npm run test:mocha", "test:stress": "cross-env FUZZ_STRESS_RUN=1 FUZZ_TEST_COUNT=1 npm run test:mocha", - "tsc": "tsc", + "tsc": "tsc-multi --config ../../../common/build/build-common/tsc-multi.cjs.json", "typetests:gen": "fluid-type-test-generator", "typetests:prepare": "flub typetests --dir . --reset --previous --normalize" }, @@ -107,7 +130,10 @@ "mocha-multi-reporters": "^1.5.1", "moment": "^2.21.0", "prettier": "~3.0.3", + "renamer": "^4.0.0", + "replace-in-file": "^6.3.5", "rimraf": "^4.4.0", + "tsc-multi": "^1.1.0", "typescript": "~5.1.6" }, "fluidBuild": { diff --git a/packages/dds/merge-tree/src/test/index.ts b/packages/dds/merge-tree/src/test/index.ts index 0ee7d38bb3c2..f7707a90777f 100644 --- a/packages/dds/merge-tree/src/test/index.ts +++ b/packages/dds/merge-tree/src/test/index.ts @@ -158,4 +158,4 @@ export { TreeMaintenanceSequenceNumber, UnassignedSequenceNumber, UniversalSequenceNumber, -} from ".."; +} from "../index"; diff --git a/packages/dds/merge-tree/src/test/snapshot.utils.ts b/packages/dds/merge-tree/src/test/snapshot.utils.ts index f5e3f4bc9809..61227bd19bcf 100644 --- a/packages/dds/merge-tree/src/test/snapshot.utils.ts +++ b/packages/dds/merge-tree/src/test/snapshot.utils.ts @@ -12,9 +12,11 @@ import { MockStorage } from "@fluidframework/test-runtime-utils"; import { IMergeTreeOp, ReferenceType } from "../ops"; import { SnapshotV1 } from "../snapshotV1"; import { IMergeTreeOptions } from "../mergeTree"; +import { PropertySet } from "../properties"; +import { ISegment } from "../mergeTreeNodes"; import { createClientsAtInitialState } from "./testClientLogger"; import { TestSerializer } from "./testSerializer"; -import { ISegment, PropertySet, TestClient } from "."; +import { TestClient } from "./testClient"; // Reconstitutes a MergeTree client from a summary export async function loadSnapshot(summary: ISummaryTree, options?: IMergeTreeOptions) { diff --git a/packages/dds/merge-tree/src/test/snapshotlegacy.spec.ts b/packages/dds/merge-tree/src/test/snapshotlegacy.spec.ts index 14307bd2a627..0842e4ecafe4 100644 --- a/packages/dds/merge-tree/src/test/snapshotlegacy.spec.ts +++ b/packages/dds/merge-tree/src/test/snapshotlegacy.spec.ts @@ -15,7 +15,7 @@ import { } from "../attributionPolicy"; import { TestSerializer } from "./testSerializer"; import { createClientsAtInitialState } from "./testClientLogger"; -import { TestClient } from "."; +import { TestClient } from "./testClient"; describe("snapshot", () => { it("header only", async () => { diff --git a/packages/dds/merge-tree/tsc-multi.test.json b/packages/dds/merge-tree/tsc-multi.test.json new file mode 100644 index 000000000000..eca0e81a8b78 --- /dev/null +++ b/packages/dds/merge-tree/tsc-multi.test.json @@ -0,0 +1,10 @@ +{ + "targets": [ + { + "extname": ".cjs", + "module": "Node16", + "moduleResolution": "Node16" + } + ], + "projects": ["./tsconfig.json", "./src/test/tsconfig.json"] +} diff --git a/packages/dds/merge-tree/tsconfig.esnext.json b/packages/dds/merge-tree/tsconfig.esnext.json deleted file mode 100644 index 3c2dddb86236..000000000000 --- a/packages/dds/merge-tree/tsconfig.esnext.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": ["./tsconfig.json", "../../../common/build/build-common/tsconfig.esm.json"], - "compilerOptions": { - "outDir": "./lib", - }, -} diff --git a/packages/dds/sequence/package.json b/packages/dds/sequence/package.json index dc1898b47c1f..1e58715d3f1a 100644 --- a/packages/dds/sequence/package.json +++ b/packages/dds/sequence/package.json @@ -11,8 +11,20 @@ "license": "MIT", "author": "Microsoft and contributors", "sideEffects": false, - "main": "dist/index.js", - "module": "lib/index.js", + "exports": { + ".": { + "import": { + "types": "./lib/index.d.mts", + "default": "./lib/index.mjs" + }, + "require": { + "types": "./dist/index.d.ts", + "default": "./dist/index.cjs" + } + } + }, + "main": "dist/index.cjs", + "module": "lib/index.mjs", "types": "dist/index.d.ts", "scripts": { "api": "fluid-build . --task api", @@ -22,9 +34,10 @@ "build:commonjs": "fluid-build . --task commonjs", "build:compile": "fluid-build . --task compile", "build:docs": "fluid-build . --task api", - "build:esnext": "tsc --project ./tsconfig.esnext.json", + "build:esnext": "tsc-multi --config ../../../common/build/build-common/tsc-multi.esm.json", "build:genver": "gen-version", - "build:test": "tsc --project ./src/test/tsconfig.json", + "build:rename-types": "renamer \"lib/**\" -f .d.ts -r .d.mts --force", + "build:test": "tsc-multi --config ./tsc-multi.test.json", "check:are-the-types-wrong": "attw --pack", "check:release-tags": "api-extractor run --local --config ./api-extractor-lint.json", "ci:build:docs": "api-extractor run", @@ -44,12 +57,11 @@ "test:coverage": "c8 npm test", "test:memory": "mocha --config src/test/memory/.mocharc.js", "test:memory-profiling:report": "mocha --config src/test/memory/.mocharc.js", - "test:mocha": "mocha --ignore \"dist/test/memory/**/*\" --recursive \"dist/test/**/*.spec.js\" -r node_modules/@fluidframework/mocha-test-setup", + "test:mocha": "mocha --ignore \"dist/test/memory/**/*\" --recursive \"dist/test/**/*.spec.?js\" -r node_modules/@fluidframework/mocha-test-setup", "test:mocha:verbose": "cross-env FLUID_TEST_VERBOSE=1 npm run test:mocha", "test:newsnapfiles": "node dist/test/createSnapshotFiles.js", "test:stress": "cross-env FUZZ_TEST_COUNT=100 FUZZ_STRESS_RUN=true mocha --ignore \"dist/test/memory/**/*\" --recursive \"dist/test/**/*.fuzz.spec.js\" -r @fluidframework/mocha-test-setup", - "testfarm": "node dist/test/testFarm.js", - "tsc": "tsc", + "tsc": "tsc-multi --config ../../../common/build/build-common/tsc-multi.cjs.json", "typetests:gen": "fluid-type-test-generator", "typetests:prepare": "flub typetests --dir . --reset --previous --normalize" }, @@ -58,12 +70,12 @@ "cache-dir": "nyc/.cache", "exclude": [ "src/test/**/*.ts", - "dist/test/**/*.js" + "dist/test/**/*.?js" ], "exclude-after-remap": false, "include": [ "src/**/*.ts", - "dist/**/*.js" + "dist/**/*.?js" ], "report-dir": "nyc/report", "reporter": [ @@ -113,7 +125,10 @@ "moment": "^2.21.0", "prettier": "~3.0.3", "random-js": "^2.1.0", + "renamer": "^4.0.0", + "replace-in-file": "^6.3.5", "rimraf": "^4.4.0", + "tsc-multi": "^1.1.0", "typescript": "~5.1.6" }, "fluidBuild": { diff --git a/packages/dds/sequence/src/test/partialLoad.spec.ts b/packages/dds/sequence/src/test/partialLoad.spec.ts index 7c4058cc60ef..f660b0e455e7 100644 --- a/packages/dds/sequence/src/test/partialLoad.spec.ts +++ b/packages/dds/sequence/src/test/partialLoad.spec.ts @@ -12,7 +12,7 @@ import { import { ReferenceType } from "@fluidframework/merge-tree"; import { IChannelServices } from "@fluidframework/datastore-definitions"; import { ISummaryTree } from "@fluidframework/protocol-definitions"; -import { SharedStringFactory, SharedString } from ".."; +import { SharedStringFactory, SharedString } from "../index"; function applyOperations( sharedString: SharedString, diff --git a/packages/dds/sequence/src/test/sequenceDeltaEvent.spec.ts b/packages/dds/sequence/src/test/sequenceDeltaEvent.spec.ts index 0a35e9d250e3..cc0f265cc165 100644 --- a/packages/dds/sequence/src/test/sequenceDeltaEvent.spec.ts +++ b/packages/dds/sequence/src/test/sequenceDeltaEvent.spec.ts @@ -14,7 +14,7 @@ import { TextSegment, } from "@fluidframework/merge-tree"; // eslint-disable-next-line import/no-internal-modules -import { TestClient } from "@fluidframework/merge-tree/dist/test/"; +import { TestClient } from "@fluidframework/merge-tree/dist/test"; import { SequenceDeltaEvent } from "../sequenceDeltaEvent"; interface IExpectedSegmentInfo { diff --git a/packages/dds/sequence/src/test/subSequence.spec.ts b/packages/dds/sequence/src/test/subSequence.spec.ts index a6158d12e25b..cfc33e5c50cb 100644 --- a/packages/dds/sequence/src/test/subSequence.spec.ts +++ b/packages/dds/sequence/src/test/subSequence.spec.ts @@ -13,7 +13,7 @@ import { PropertySet, } from "@fluidframework/merge-tree"; // eslint-disable-next-line import/no-internal-modules -import { TestClient } from "@fluidframework/merge-tree/dist/test/testClient"; +import { TestClient } from "@fluidframework/merge-tree/dist/test"; import { SubSequence } from "../sharedSequence"; const clientNames = ["Ed", "Ted", "Ned", "Harv", "Marv", "Glenda", "Susan"]; diff --git a/packages/dds/sequence/src/test/testFarm.ts b/packages/dds/sequence/src/test/testFarm.ts deleted file mode 100644 index 7a05da7df792..000000000000 --- a/packages/dds/sequence/src/test/testFarm.ts +++ /dev/null @@ -1,1826 +0,0 @@ -/*! - * Copyright (c) Microsoft Corporation and contributors. All rights reserved. - * Licensed under the MIT License. - */ - -// TODO: Some of these should be fixed -/* eslint-disable no-bitwise */ -/* eslint-disable no-restricted-syntax */ -/* eslint-disable guard-for-in */ -/* eslint-disable @typescript-eslint/no-base-to-string */ -/* eslint-disable @typescript-eslint/no-for-in-array */ -/* eslint-disable @typescript-eslint/consistent-type-assertions */ - -import path from "path"; -import { Trace } from "@fluid-internal/client-utils"; -import { assert } from "@fluidframework/core-utils"; -// eslint-disable-next-line import/no-internal-modules -import * as MergeTree from "@fluidframework/merge-tree/dist/test/"; -import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions"; -import JsDiff from "diff"; -import { MersenneTwister19937, integer } from "random-js"; -import { createIntervalIndex } from "../intervalCollection"; -import { IntervalTree } from "../intervalTree"; -import { SequenceInterval, IntervalType, Interval } from "../intervals"; - -const clock = () => Trace.start(); - -const elapsedMicroseconds = (trace: Trace) => { - return trace.trace().duration * 1000; -}; - -// Enum AsyncRoundState { -// Insert, -// Remove, -// Tail -// } - -// interface AsyncRoundInfo { -// clientIndex: number; -// state: AsyncRoundState; -// insertSegmentCount?: number; -// removeSegmentCount?: number; -// iterIndex: number; -// } - -export function propertyCopy() { - const propCount = 2000; - const iterCount = 10000; - const a = []; - const v = []; - for (let i = 0; i < propCount; i++) { - a[i] = `prop${i}`; - v[i] = i; - } - let clockStart = clock(); - let obj: MergeTree.MapLike = MergeTree.createMap(); - for (let j = 0; j < iterCount; j++) { - obj = MergeTree.createMap(); - for (let i = 0; i < propCount; i++) { - obj[a[i]] = v[i]; - } - } - let et = elapsedMicroseconds(clockStart); - let perIter = (et / iterCount).toFixed(3); - let perProp = (et / (iterCount * propCount)).toFixed(3); - console.log(`arr prop init time ${perIter} per init; ${perProp} per property`); - clockStart = clock(); - for (let j = 0; j < iterCount; j++) { - const bObj = MergeTree.createMap(); - for (const key in obj) { - bObj[key] = obj[key]; - } - } - et = elapsedMicroseconds(clockStart); - perIter = (et / iterCount).toFixed(3); - perProp = (et / (iterCount * propCount)).toFixed(3); - console.log(`obj prop init time ${perIter} per init; ${perProp} per property`); -} - -function makeBookmarks(client: MergeTree.TestClient, bookmarkCount: number) { - const mt = MersenneTwister19937.seedWithArray([0xdeadbeef, 0xfeedbed]); - const bookmarks = []; - const len = client.mergeTree.getLength( - MergeTree.UniversalSequenceNumber, - MergeTree.NonCollabClient, - ); - const maxRangeLen = Math.min(Math.floor(len / 100), 30); - for (let i = 0; i < bookmarkCount; i++) { - let pos1 = integer(0, len - 1)(mt); - const rangeLen = integer(0, maxRangeLen)(mt); - let pos2 = pos1 + rangeLen; - if (pos2 >= len) { - pos2 = len - 2; - } - if (pos1 > pos2) { - const temp = pos1; - pos1 = pos2; - pos2 = temp; - } - const segoff1 = client.getContainingSegment(pos1); - const segoff2 = client.getContainingSegment(pos2); - - if (segoff1?.segment && segoff2?.segment) { - const baseSegment1 = segoff1.segment; - const baseSegment2 = segoff2.segment; - const lref1 = client.createLocalReferencePosition( - baseSegment1, - segoff1.offset, - MergeTree.ReferenceType.RangeBegin, - undefined, - ); - const lref2 = client.createLocalReferencePosition( - baseSegment2, - segoff2.offset, - MergeTree.ReferenceType.RangeEnd, - undefined, - ); - lref1.addProperties({ [MergeTree.reservedRangeLabelsKey]: ["bookmark"] }); - lref2.addProperties({ [MergeTree.reservedRangeLabelsKey]: ["bookmark"] }); - bookmarks.push(new SequenceInterval(client, lref1, lref2, IntervalType.Simple)); - } else { - i--; - } - } - return bookmarks; -} - -function makeReferences(client: MergeTree.TestClient, referenceCount: number) { - const mt = MersenneTwister19937.seedWithArray([0xdeadbeef, 0xfeedbed]); - const refs = []; - const len = client.mergeTree.getLength( - MergeTree.UniversalSequenceNumber, - MergeTree.NonCollabClient, - ); - for (let i = 0; i < referenceCount; i++) { - const pos = integer(0, len - 1)(mt); - const segoff = client.getContainingSegment(pos); - if (segoff?.segment) { - const baseSegment = segoff.segment; - const lref = client.createLocalReferencePosition( - baseSegment, - segoff.offset, - MergeTree.ReferenceType.Simple, - undefined, - ); - if (i & 1) { - lref.refType = MergeTree.ReferenceType.SlideOnRemove; - } - refs.push(lref); - } else { - i--; - } - } - return refs; -} - -export function TestPack(verbose = true) { - const mt = MersenneTwister19937.seedWithArray([0xdeadbeef, 0xfeedbed]); - const smallSegmentCountDistribution = integer(1, 4); - const randSmallSegmentCount = () => smallSegmentCountDistribution(mt); - const textLengthDistribution = integer(1, 5); - const randTextLength = () => textLengthDistribution(mt); - const zedCode = 48; - function randomString(len: number, c: string) { - let str = ""; - for (let i = 0; i < len; i++) { - str += c; - } - return str; - } - - const checkIncr = false; - - // Let incrGetTextTime = 0; - // let incrGetTextCalls = 0; - // let catchUpTime = 0; - // let catchUps = 0; - - function reportTiming(client: MergeTree.TestClient) { - if (!verbose) { - return; - } - const aveTime = (client.accumTime / client.accumOps).toFixed(1); - const stats = MergeTree.getStats(client.mergeTree); - const packTime = stats.packTime; - const ordTime = stats.ordTime; - const aveOrdTime = ((ordTime ?? 0) / client.accumOps).toFixed(1); - const avePackTime = ((packTime ?? 0) / client.accumOps).toFixed(1); - const aveExtraWindowTime = (client.accumWindowTime / client.accumOps).toFixed(1); - const aveWindow = (client.accumWindow / client.accumOps).toFixed(1); - - console.log(`ord time average: ${aveOrdTime}us max ${stats.maxOrdTime}us`); - console.log( - `${client.longClientId} accum time ${client.accumTime} us ops: ${client.accumOps} ave time ${aveTime} - pack ${avePackTime} ave window ${aveWindow}`, - ); - console.log( - `${client.longClientId} accum window time ${client.accumWindowTime} us ave window time not in ops ${aveExtraWindowTime}; max ${client.maxWindowTime}`, - ); - } - - function manyMergeTrees() { - const mergeTreeCount = 2000000; - const a = Array(mergeTreeCount); - for (let i = 0; i < mergeTreeCount; i++) { - a[i] = new MergeTree.MergeTree(); - } - for (;;) {} - } - - function clientServer(startFile?: string, initRounds = 1000) { - const clientCount = 5; - const fileSegCount = 0; - const initString = "don't ask for whom the bell tolls; it tolls for thee"; - let snapInProgress = false; - const asyncExec = false; - const addSnapClient = false; - const extractSnap = false; - const includeMarkers = false; - const measureBookmarks = true; - let bookmarks: SequenceInterval[]; - const bookmarkRangeTree = new IntervalTree(); - const testOrdinals = true; - let ordErrors = 0; - let ordSuccess = 0; - const measureRanges = true; - const referenceCount = 2000; - const bookmarkCount = 5000; - let references: MergeTree.LocalReferencePosition[]; - let refReads = 0; - let refReadTime = 0; - let posContextChecks = 0; - let posContextTime = 0; - let posContextResults = 0; - let rangeOverlapTime = 0; - let rangeOverlapChecks = 0; - let overlapIntervalResults = 0; - const testSyncload = false; - let snapClient: MergeTree.TestClient; - const useGroupOperationsForMoveWord = false; - let annotateProps: MergeTree.PropertySet | undefined; - const insertAsRefPos = false; - - const testServer = new MergeTree.TestServer({}); - testServer.measureOps = true; - if (startFile) { - MergeTree.loadTextFromFile(startFile, testServer.mergeTree, fileSegCount); - } else { - testServer.insertTextLocal(0, initString); - } - - const clients = new Array(clientCount); - for (let i = 0; i < clientCount; i++) { - clients[i] = new MergeTree.TestClient(); - clients[i].measureOps = true; - if (startFile) { - MergeTree.loadTextFromFile(startFile, clients[i].mergeTree, fileSegCount); - } else { - clients[i].insertTextLocal(0, initString); - } - if (annotateProps) { - clients[i].annotateRangeLocal(0, clients[i].getLength(), annotateProps, undefined); - } - clients[i].startOrUpdateCollaboration(`Fred${i}`); - } - testServer.startOrUpdateCollaboration("theServer"); - testServer.addClients(clients); - if (measureBookmarks) { - references = makeReferences(testServer, referenceCount); - if (measureRanges) { - bookmarks = makeBookmarks(testServer, bookmarkCount); - for (const bookmark of bookmarks) { - bookmarkRangeTree.put(bookmark); - } - } - } - if (testSyncload) { - const clockStart = clock(); - // Let segs = Paparazzo.Snapshot.loadSync("snap-initial"); - console.log(`sync load time ${elapsedMicroseconds(clockStart)}`); - const fromLoad = new MergeTree.MergeTree(); - // FromLoad.reloadFromSegments(segs); - const fromLoadText = new MergeTree.MergeTreeTextHelper(fromLoad).getText( - MergeTree.UniversalSequenceNumber, - MergeTree.NonCollabClient, - ); - const serverText = testServer.getText(); - if (fromLoadText !== serverText) { - console.log("snap file vs. text file mismatch"); - } - } - if (addSnapClient) { - snapClient = new MergeTree.TestClient(); - if (startFile) { - MergeTree.loadTextFromFile(startFile, snapClient.mergeTree, fileSegCount); - } else { - snapClient.insertTextLocal(0, initString); - } - snapClient.startOrUpdateCollaboration("snapshot"); - testServer.addListeners([snapClient]); - } - - function checkTextMatch() { - // Console.log(`checking text match @${server.getCurrentSeq()}`); - const serverText = testServer.getText(); - if (checkIncr) { - const serverIncrText = testServer.incrementalGetText(); - // IncrGetTextTime += elapsedMicroseconds(clockStart); - // incrGetTextCalls++; - if (serverIncrText !== serverText) { - console.log("incr get text mismatch"); - } - } - for (const client of clients) { - const cliText = client.getText(); - if (cliText !== serverText) { - console.log( - `mismatch @${testServer.getCurrentSeq()} client @${client.getCurrentSeq()} id: ${client.getClientId()}`, - ); - // Console.log(serverText); - // console.log(cliText); - const diffParts = JsDiff.diffChars(serverText, cliText); - for (const diffPart of diffParts) { - let annotes = ""; - if (diffPart.added) { - annotes += "added "; - } else if (diffPart.removed) { - annotes += "removed "; - } - if (diffPart.count) { - annotes += `count: ${diffPart.count}`; - } - console.log(`text: ${diffPart.value} ${annotes}`); - } - console.log(testServer.mergeTree.toString()); - console.log(client.mergeTree.toString()); - return true; - } - } - return false; - } - - const rounds = initRounds; - - function clientProcessSome(client: MergeTree.TestClient, all = false) { - const cliMsgCount = client.getMessageCount(); - const countToApply: number = all - ? cliMsgCount - : integer(Math.floor((2 * cliMsgCount) / 3), cliMsgCount)(mt); - client.applyMessages(countToApply); - } - - function serverProcessSome(server: MergeTree.TestClient, all = false) { - const svrMsgCount = server.getMessageCount(); - const countToApply: number = all - ? svrMsgCount - : integer(Math.floor((2 * svrMsgCount) / 3), svrMsgCount)(mt); - return server.applyMessages(countToApply); - } - - function randomSpateOfInserts(client: MergeTree.TestClient, charIndex: number) { - const textLen = randTextLength(); - const text = randomString( - textLen, - String.fromCharCode(zedCode + ((client.getCurrentSeq() + charIndex) % 50)), - ); - const preLen = client.getLength(); - const pos = integer(0, preLen)(mt); - if (includeMarkers) { - const markerOp = client.insertMarkerLocal(pos, MergeTree.ReferenceType.Tile, { - [MergeTree.reservedTileLabelsKey]: "test", - }); - testServer.enqueueMsg( - client.makeOpMessage(markerOp, MergeTree.UnassignedSequenceNumber), - ); - } - const textOp = client.insertTextLocal(pos, text); - testServer.enqueueMsg(client.makeOpMessage(textOp, MergeTree.UnassignedSequenceNumber)); - if (MergeTree.TestClient.useCheckQ) { - client.enqueueTestString(); - } - } - - function randomSpateOfRemoves(client: MergeTree.TestClient) { - const dlen = randTextLength(); - const preLen = client.getLength(); - const pos = integer(0, preLen)(mt); - const op = client.removeRangeLocal(pos, pos + dlen); - testServer.enqueueMsg(client.makeOpMessage(op)); - if (MergeTree.TestClient.useCheckQ) { - client.enqueueTestString(); - } - } - - function randomWordMove(client: MergeTree.TestClient) { - const word1 = client.findRandomWord(); - if (word1) { - const removeStart = word1.pos; - const removeEnd = removeStart + word1.text.length; - const ops: MergeTree.IMergeTreeDeltaOp[] = []; - const removeOp = client.removeRangeLocal(removeStart, removeEnd); - if (!useGroupOperationsForMoveWord) { - testServer.enqueueMsg(client.makeOpMessage(removeOp)); - if (MergeTree.TestClient.useCheckQ) { - client.enqueueTestString(); - } - } else if (removeOp) { - ops.push(removeOp); - } - - let word2 = client.findRandomWord(); - while (!word2) { - word2 = client.findRandomWord(); - } - const pos = word2.pos + word2.text.length; - - const segOff = client.getContainingSegment(pos); - const insertOp = - !insertAsRefPos && segOff.segment - ? client.insertAtReferencePositionLocal( - client.createLocalReferencePosition( - segOff.segment, - segOff.offset, - MergeTree.ReferenceType.Transient, - undefined, - ), - MergeTree.TextSegment.make(word1.text), - ) - : client.insertTextLocal(pos, word1.text); - - if (!useGroupOperationsForMoveWord) { - testServer.enqueueMsg(client.makeOpMessage(insertOp)); - if (MergeTree.TestClient.useCheckQ) { - client.enqueueTestString(); - } - } else if (insertOp) { - ops.push(insertOp); - } - - if (annotateProps) { - const annotateOp = client.annotateRangeLocal( - pos, - pos + word1.text.length, - annotateProps, - undefined, - ); - if (!useGroupOperationsForMoveWord) { - testServer.enqueueMsg(client.makeOpMessage(annotateOp)); - } else if (annotateOp) { - ops.push(annotateOp); - } - } - - if (useGroupOperationsForMoveWord) { - testServer.enqueueMsg(client.makeOpMessage(MergeTree.createGroupOp(...ops))); - if (MergeTree.TestClient.useCheckQ) { - client.enqueueTestString(); - } - } - } - } - - let errorCount = 0; - - // Function asyncRoundStep(asyncInfo: AsyncRoundInfo, roundCount: number) { - // if (asyncInfo.state == AsyncRoundState.Insert) { - // if (!asyncInfo.insertSegmentCount) { - // asyncInfo.insertSegmentCount = randSmallSegmentCount(); - // } - // if (asyncInfo.clientIndex == clients.length) { - // asyncInfo.state = AsyncRoundState.Remove; - // asyncInfo.iterIndex = 0; - // } - // else { - // let client = clients[asyncInfo.clientIndex]; - // if (startFile) { - // randomWordMove(client); - // } - // else { - // randomSpateOfInserts(client, asyncInfo.iterIndex); - // } - // asyncInfo.iterIndex++; - // if (asyncInfo.iterIndex == asyncInfo.insertSegmentCount) { - // asyncInfo.clientIndex++; - // asyncInfo.insertSegmentCount = undefined; - // asyncInfo.iterIndex = 0; - // } - // } - // } - // if (asyncInfo.state == AsyncRoundState.Remove) { - // if (!asyncInfo.removeSegmentCount) { - // asyncInfo.removeSegmentCount = Math.floor(3 * asyncInfo.insertSegmentCount / 4); - // if (asyncInfo.removeSegmentCount < 1) { - // asyncInfo.removeSegmentCount = 1; - // } - // } - // if (asyncInfo.clientIndex == clients.length) { - // asyncInfo.state = AsyncRoundState.Tail; - // } - // else { - // let client = clients[asyncInfo.clientIndex]; - // if (startFile) { - // randomWordMove(client); - // } - // else { - // randomSpateOfInserts(client, asyncInfo.iterIndex); - // } - // asyncInfo.iterIndex++; - // if (asyncInfo.iterIndex == asyncInfo.removeSegmentCount) { - // asyncInfo.clientIndex++; - // asyncInfo.removeSegmentCount = undefined; - // asyncInfo.iterIndex = 0; - // } - // } - // } - // if (asyncInfo.state == AsyncRoundState.Tail) { - // finishRound(roundCount); - // } - // else { - // setImmediate(asyncRoundStep, asyncInfo, roundCount); - // } - // } - - // function asyncRound(roundCount: number) { - // let asyncInfo = { - // clientIndex: 0, - // iterIndex: 0, - // state: AsyncRoundState.Insert - // } - // setImmediate(asyncRoundStep, asyncInfo, roundCount); - // } - - let extractSnapTime = 0; - let extractSnapOps = 0; - function finishRound(roundCount: number) { - // Process remaining messages - if (serverProcessSome(testServer, true)) { - return; - } - for (const client of clients) { - clientProcessSome(client, true); - } - - if (measureBookmarks) { - const refReadsPerRound = 200; - const posChecksPerRound = 200; - const rangeChecksPerRound = 200; - let clockStart = clock(); - for (let i = 0; i < refReadsPerRound; i++) { - testServer.localReferencePositionToPosition(references[i]); - refReads++; - } - refReadTime += elapsedMicroseconds(clockStart); - if (testOrdinals) { - const mt2 = MersenneTwister19937.seedWithArray([0xdeadbeef, 0xfeedbed]); - const checkRange = []; - const len = testServer.mergeTree.getLength( - MergeTree.UniversalSequenceNumber, - testServer.getClientId(), - ); - for (let i = 0; i < rangeChecksPerRound; i++) { - const e = integer(0, len - 2)(mt2); - const rangeSize = integer(1, Math.min(1000, len - 2))(mt2); - let b = e - rangeSize; - if (b < 0) { - b = 0; - } - checkRange[i] = [b, b + rangeSize]; - const segoff1 = testServer.getContainingSegment(checkRange[i][0]); - const segoff2 = testServer.getContainingSegment(checkRange[i][1]); - if (segoff1 && segoff2 && segoff1.segment && segoff2.segment) { - // Console.log(`[${checkRange[i][0]},${checkRange[i][1]})`); - if (segoff1.segment === segoff2.segment) { - // Console.log("same segment"); - } else if (segoff1.segment.ordinal > segoff2.segment.ordinal) { - ordErrors++; - console.log( - `reverse ordinals ${ordinalToArray( - segoff1.segment.ordinal, - )} > ${ordinalToArray(segoff2.segment.ordinal)}`, - ); - console.log( - `segments ${segoff1.segment.toString()} ${segoff2.segment.toString()}`, - ); - console.log(testServer.mergeTree.toString()); - break; - } else { - ordSuccess++; - // Console.log(`happy ordinals ${MergeTree.ordinalToArray(segoff1.segment.ordinal)} < ${MergeTree.ordinalToArray(segoff2.segment.ordinal)}`); - } - } else { - // Console.log(`no seg for [${b},${e}) with len ${len}`); - } - } - } - if (measureRanges) { - const mt2 = MersenneTwister19937.seedWithArray([0xdeadbeef, 0xfeedbed]); - const len = testServer.mergeTree.getLength( - MergeTree.UniversalSequenceNumber, - testServer.getClientId(), - ); - const checkPos = []; - const checkRange = []; - const checkPosRanges = []; - const checkRangeRanges = []; - for (let i = 0; i < posChecksPerRound; i++) { - checkPos[i] = integer(0, len - 2)(mt2); - const segoff1 = testServer.getContainingSegment(checkPos[i]); - const segoff2 = testServer.getContainingSegment(checkPos[i] + 1); - if (segoff1?.segment && segoff2?.segment) { - const lrefPos1 = testServer.createLocalReferencePosition( - segoff1.segment, - segoff1.offset, - MergeTree.ReferenceType.Simple, - undefined, - ); - const lrefPos2 = testServer.createLocalReferencePosition( - segoff2.segment, - segoff2.offset, - MergeTree.ReferenceType.Simple, - undefined, - ); - checkPosRanges[i] = new SequenceInterval( - testServer, - lrefPos1, - lrefPos2, - IntervalType.Simple, - ); - } else { - i--; - } - } - for (let i = 0; i < rangeChecksPerRound; i++) { - const e = integer(0, len - 2)(mt2); - const rangeSize = integer(1, Math.min(1000, len - 2))(mt2); - let b = e - rangeSize; - if (b < 0) { - b = 0; - } - checkRange[i] = [b, b + rangeSize]; - const segoff1 = testServer.getContainingSegment(checkRange[i][0]); - const segoff2 = testServer.getContainingSegment(checkRange[i][1]); - if (segoff1?.segment && segoff2?.segment) { - const lrefPos1 = testServer.createLocalReferencePosition( - segoff1.segment, - segoff1.offset, - MergeTree.ReferenceType.Simple, - undefined, - ); - const lrefPos2 = testServer.createLocalReferencePosition( - segoff2.segment, - segoff2.offset, - MergeTree.ReferenceType.Simple, - undefined, - ); - checkRangeRanges[i] = new SequenceInterval( - testServer, - lrefPos1, - lrefPos2, - IntervalType.Simple, - ); - } else { - i--; - } - } - const showResults = false; - clockStart = clock(); - - for (let i = 0; i < posChecksPerRound; i++) { - const ivals = bookmarkRangeTree.match(checkPosRanges[i]); - if (showResults) { - console.log(`results for point [${checkPos[i]},${checkPos[i] + 1})`); - for (const ival of ivals) { - const pos1 = testServer.mergeTree.referencePositionToLocalPosition( - ival.key.start, - ); - const pos2 = testServer.mergeTree.referencePositionToLocalPosition( - ival.key.end, - ); - console.log(`[${pos1},${pos2})`); - } - } - posContextResults += ivals.length; - } - posContextTime += elapsedMicroseconds(clockStart); - posContextChecks += posChecksPerRound; - - clockStart = clock(); - for (let i = 0; i < rangeChecksPerRound; i++) { - const ivals = bookmarkRangeTree.match(checkRangeRanges[i]); - if (showResults) { - console.log(`results for [${checkRange[i][0]},${checkRange[i][1]})`); - for (const ival of ivals) { - const pos1 = testServer.mergeTree.referencePositionToLocalPosition( - ival.key.start, - ); - const pos2 = testServer.mergeTree.referencePositionToLocalPosition( - ival.key.end, - ); - console.log(`[${pos1},${pos2})`); - } - } - overlapIntervalResults += ivals.length; - } - rangeOverlapTime += elapsedMicroseconds(clockStart); - rangeOverlapChecks += rangeChecksPerRound; - } - } - - if (extractSnap) { - const clockStart = clock(); - // Let snapshot = new Paparazzo.Snapshot(snapClient.mergeTree); - // snapshot.extractSync(); - extractSnapTime += elapsedMicroseconds(clockStart); - extractSnapOps++; - } - /* - If (checkTextMatch()) { - console.log(`round: ${i}`); - break; - } - */ - // console.log(server.getText()); - // console.log(server.mergeTree.toString()); - // console.log(MergeTree.getStats(server.mergeTree)); - if (0 === roundCount % 100) { - const clockStart = clock(); - if (checkTextMatch()) { - console.log(`round: ${roundCount} BREAK`); - errorCount++; - return errorCount; - } - checkTime += elapsedMicroseconds(clockStart); - if (verbose) { - console.log(`wall clock is ${((Date.now() - startTime) / 1000.0).toFixed(1)}`); - } - const stats = MergeTree.getStats(testServer.mergeTree); - const liveAve = (stats.liveCount / stats.nodeCount).toFixed(1); - const posLeaves = stats.leafCount - stats.removedLeafCount; - let aveExtractSnapTime = "off"; - if (extractSnapOps > 0) { - aveExtractSnapTime = (extractSnapTime / extractSnapOps).toFixed(1); - } - console.log( - `round: ${roundCount} seq ${ - testServer.seq - } char count ${testServer.getLength()} height ${stats.maxHeight} lv ${ - stats.leafCount - } rml ${stats.removedLeafCount} p ${posLeaves} nodes ${ - stats.nodeCount - } pop ${liveAve} histo ${stats.histo}`, - ); - if (extractSnapOps > 0) { - aveExtractSnapTime = (extractSnapTime / extractSnapOps).toFixed(1); - console.log(`ave extract snap time ${aveExtractSnapTime}`); - } - reportTiming(testServer); - if (measureBookmarks) { - const timePerRead = (refReadTime / refReads).toFixed(2); - const bookmarksPerSeg = (bookmarkCount / stats.leafCount).toFixed(2); - if (ordErrors > 0) { - console.log(`ord errors: ${ordErrors}`); - } - if (ordSuccess > 0) { - console.log(`total ord range tests ${ordSuccess}`); - } - console.log( - `bookmark count ${bookmarkCount} ave. per seg ${bookmarksPerSeg} time/read ${timePerRead}`, - ); - if (measureRanges) { - const timePerContextCheck = (posContextTime / posContextChecks).toFixed(2); - const results = (posContextResults / posContextChecks).toFixed(2); - console.log( - `ave. per bookmark context check ${timePerContextCheck} ave results per check ${results}`, - ); - const timePerRangeCheck = (rangeOverlapTime / rangeOverlapChecks).toFixed( - 2, - ); - const resultsRange = (overlapIntervalResults / rangeOverlapChecks).toFixed( - 2, - ); - console.log( - `ave. per bookmark range check ${timePerRangeCheck} ave results per check ${resultsRange}`, - ); - } - } - reportTiming(clients[2]); - let totalTime = testServer.accumTime + testServer.accumWindowTime; - for (const client of clients) { - totalTime += client.accumTime + client.accumWindowTime; - } - if (verbose) { - console.log( - `total time ${(totalTime / 1000000.0).toFixed(1)} check time ${( - checkTime / 1000000.0 - ).toFixed(1)}`, - ); - } - // Console.log(server.getText()); - // console.log(server.mergeTree.toString()); - } - return errorCount; - } - - function round(roundCount: number) { - for (const client of clients) { - const insertSegmentCount = randSmallSegmentCount(); - for (let j = 0; j < insertSegmentCount; j++) { - if (startFile) { - randomWordMove(client); - } else { - randomSpateOfInserts(client, j); - } - } - if (serverProcessSome(testServer)) { - return; - } - clientProcessSome(client); - - let removeSegmentCount = Math.floor((3 * insertSegmentCount) / 4); - if (removeSegmentCount < 1) { - removeSegmentCount = 1; - } - for (let j = 0; j < removeSegmentCount; j++) { - if (startFile) { - randomWordMove(client); - } else { - randomSpateOfRemoves(client); - if (includeMarkers) { - if (client.getLength() > 200) { - randomSpateOfRemoves(client); - } - } - } - } - if (serverProcessSome(testServer)) { - return; - } - clientProcessSome(client); - } - finishRound(roundCount); - } - - const startTime = Date.now(); - let checkTime = 0; - let asyncRoundCount = 0; - let lastSnap = 0; - // Let checkSnapText = true; - - // function snapFinished() { - // snapInProgress = false; - // let curmin = snapClient.mergeTree.getCollabWindow().minSeq; - // console.log(`snap finished round ${asyncRoundCount} server seq ${server.getCurrentSeq()} seq ${snapClient.getCurrentSeq()} minseq ${curmin}`); - // let clockStart = clock(); - // //snapClient.verboseOps = true; - // clientProcessSome(snapClient, true); - // catchUpTime += elapsedMicroseconds(clockStart); - // catchUps++; - // if (checkSnapText) { - // let serverText = server.getText(); - // let snapText = snapClient.getText(); - // if (serverText != snapText) { - // console.log(`mismatch @${server.getCurrentSeq()} client @${snapClient.getCurrentSeq()} id: ${snapClient.getClientId()}`); - // } - // } - // } - - function ohSnap(filename: string) { - snapInProgress = true; - const curmin = snapClient.getCollabWindow().minSeq; - lastSnap = curmin; - console.log(`snap started seq ${snapClient.getCurrentSeq()} minseq ${curmin}`); - // Let snapshot = new Paparazzo.Snapshot(snapClient.mergeTree, filename, snapFinished); - // snapshot.start(); - } - - function asyncStep() { - round(asyncRoundCount); - const curmin = testServer.getCollabWindow().minSeq; - if (!snapInProgress && lastSnap < curmin) { - ohSnap("snapit"); - } - asyncRoundCount++; - if (asyncRoundCount < rounds) { - setImmediate(asyncStep); - } - } - - if (asyncExec) { - ohSnap("snap-initial"); - setImmediate(asyncStep); - } else { - for (let i = 0; i < rounds; i++) { - round(i); - if (errorCount > 0) { - break; - } - } - tail(); - } - function tail() { - reportTiming(testServer); - reportTiming(clients[2]); - // Console.log(server.getText()); - // console.log(server.mergeTree.toString()); - } - return errorCount; - } - - const clientNames = ["Ed", "Ted", "Ned", "Harv", "Marv", "Glenda", "Susan"]; - - function firstTest() { - let cli = new MergeTree.TestClient(); - cli.insertTextLocal(0, "on the mat."); - cli.startOrUpdateCollaboration("Fred1"); - for (const cname of clientNames) { - cli.addLongClientId(cname); - } - cli.insertTextRemote(0, "that ", undefined, 1, 0, "1"); - if (verbose) { - console.log(cli.mergeTree.toString()); - } - cli.insertTextRemote(0, "fat ", undefined, 2, 0, "2"); - if (verbose) { - console.log(cli.mergeTree.toString()); - } - cli.insertTextLocal(5, "cat "); - if (verbose) { - console.log(cli.mergeTree.toString()); - } - if (verbose) { - for (let i = 0; i < 4; i++) { - for (let j = 0; j < 3; j++) { - console.log(cli.relText(i, j)); - } - } - } - cli.mergeTree.ackPendingSegment({ - op: { type: MergeTree.MergeTreeDeltaType.INSERT }, - sequencedMessage: { - sequenceNumber: 3, - } as ISequencedDocumentMessage, - }); - if (verbose) { - console.log(cli.mergeTree.toString()); - for (let clientId = 0; clientId < 4; clientId++) { - for (let refSeq = 0; refSeq < 4; refSeq++) { - console.log(cli.relText(clientId, refSeq)); - } - } - } - cli.insertTextRemote(6, "very ", undefined, 4, 2, "2"); - cli.insertMarkerRemote( - 0, - { refType: MergeTree.ReferenceType.Tile }, - { [MergeTree.reservedTileLabelsKey]: ["peach"] }, - 5, - 0, - "2", - ); - if (verbose) { - console.log(cli.mergeTree.toString()); - for (let clientId = 0; clientId < 4; clientId++) { - for (let refSeq = 0; refSeq < 5; refSeq++) { - console.log(cli.relText(clientId, refSeq)); - } - } - } - - cli = new MergeTree.TestClient(); - cli.insertTextLocal(0, " old sock!"); - cli.startOrUpdateCollaboration("Fred2"); - for (const cname of clientNames) { - cli.addLongClientId(cname); - } - cli.insertTextRemote(0, "abcde", undefined, 1, 0, "2"); - const segoff = cli.getContainingSegment(0); - const lref1 = cli.createLocalReferencePosition( - segoff.segment, - segoff.offset, - MergeTree.ReferenceType.Simple, - undefined, - ); - cli.insertTextRemote(0, "yyy", undefined, 2, 0, "1"); - cli.insertTextRemote(2, "zzz", undefined, 3, 1, "3"); - cli.insertTextRemote(1, "EAGLE", undefined, 4, 1, "4"); - cli.insertTextRemote(4, "HAS", undefined, 5, 1, "5"); - cli.insertTextLocal(19, " LANDED"); - cli.insertTextRemote(0, "yowza: ", undefined, 6, 4, "2"); - const lref1pos = cli.mergeTree.referencePositionToLocalPosition(lref1); - console.log(`lref pos: ${lref1pos}`); - cli.mergeTree.ackPendingSegment({ - op: { type: MergeTree.MergeTreeDeltaType.INSERT }, - sequencedMessage: { - sequenceNumber: 7, - } as ISequencedDocumentMessage, - }); - if (verbose) { - console.log(cli.mergeTree.toString()); - for (let clientId = 0; clientId < 6; clientId++) { - for (let refSeq = 0; refSeq < 8; refSeq++) { - console.log(cli.relText(clientId, refSeq)); - } - } - } - cli.applyMsg(cli.makeOpMessage(MergeTree.createRemoveRangeOp(3, 5), 8, 6, "1")); - if (verbose) { - console.log(cli.mergeTree.toString()); - for (let clientId = 0; clientId < 6; clientId++) { - for (let refSeq = 0; refSeq < 9; refSeq++) { - console.log(cli.relText(clientId, refSeq)); - } - } - } - cli = new MergeTree.TestClient(); - cli.insertTextLocal(0, "abcdefgh"); - cli.startOrUpdateCollaboration("Fred3"); - for (const cname of clientNames) { - cli.addLongClientId(cname); - } - cli.applyMsg(cli.makeOpMessage(MergeTree.createRemoveRangeOp(1, 3), 1, 0, "3")); - if (verbose) { - console.log(cli.mergeTree.toString()); - } - cli.insertTextRemote(2, "zzz", undefined, 2, 0, "2"); - if (verbose) { - console.log(cli.mergeTree.toString()); - } - cli.insertTextRemote(9, " chaser", undefined, 3, 2, "3"); - cli.removeRangeLocal(12, 14); - cli.mergeTree.ackPendingSegment({ - op: { type: MergeTree.MergeTreeDeltaType.REMOVE }, - sequencedMessage: { - sequenceNumber: 4, - } as ISequencedDocumentMessage, - }); - if (verbose) { - console.log(cli.mergeTree.toString()); - for (let clientId = 0; clientId < 4; clientId++) { - for (let refSeq = 0; refSeq < 5; refSeq++) { - console.log(cli.relText(clientId, refSeq)); - } - } - } - cli.insertTextLocal(14, "*yolumba*"); - cli.insertTextLocal(17, "-zanzibar-"); - cli.mergeTree.ackPendingSegment({ - op: { type: MergeTree.MergeTreeDeltaType.INSERT }, - sequencedMessage: { - sequenceNumber: 5, - } as ISequencedDocumentMessage, - }); - cli.insertTextRemote(2, "(aaa)", undefined, 6, 4, "2"); - cli.mergeTree.ackPendingSegment({ - op: { type: MergeTree.MergeTreeDeltaType.INSERT }, - sequencedMessage: { - sequenceNumber: 7, - } as ISequencedDocumentMessage, - }); - if (verbose) { - console.log(cli.mergeTree.toString()); - for (let clientId = 0; clientId < 4; clientId++) { - for (let refSeq = 0; refSeq < 8; refSeq++) { - console.log(cli.relText(clientId, refSeq)); - } - } - } - /* - Cli.removeRangeLocal(3,8); - cli.removeRangeLocal(5,7); - cli.ackPendingSegment(8); - cli.ackPendingSegment(9); - */ - cli.applyMsg(cli.makeOpMessage(MergeTree.createRemoveRangeOp(3, 8), 8, 7, "2")); - cli.applyMsg(cli.makeOpMessage(MergeTree.createRemoveRangeOp(5, 7), 9, 7, "2")); - if (verbose) { - console.log(cli.mergeTree.toString()); - for (let clientId = 0; clientId < 4; clientId++) { - for (let refSeq = 0; refSeq < 10; refSeq++) { - console.log(cli.relText(clientId, refSeq)); - } - } - } - const localRemoveOp = cli.removeRangeLocal(3, 5); - cli.applyMsg(cli.makeOpMessage(MergeTree.createRemoveRangeOp(3, 6), 10, 9, "2")); - cli.applyMsg(cli.makeOpMessage(localRemoveOp, 11)); - if (verbose) { - console.log(cli.mergeTree.toString()); - for (let clientId = 0; clientId < 4; clientId++) { - for (let refSeq = 0; refSeq < 12; refSeq++) { - console.log(cli.relText(clientId, refSeq)); - } - } - } - } - - return { - firstTest, - clientServer, - manyMergeTrees, - }; -} - -const editFlat = (source: string, s: number, dl: number, nt = "") => - source.substring(0, s) + nt + source.substring(s + dl, source.length); - -let accumTime = 0; - -function checkInsertMergeTree( - mergeTree: MergeTree.MergeTree, - pos: number, - textSegment: MergeTree.TextSegment, - verbose = false, -) { - const helper = new MergeTree.MergeTreeTextHelper(mergeTree); - let checkText = helper.getText(MergeTree.UniversalSequenceNumber, MergeTree.LocalClientId); - checkText = editFlat(checkText, pos, 0, textSegment.text); - const clockStart = clock(); - mergeTree.insertSegments( - pos, - [new MergeTree.TextSegment(textSegment.text)], - MergeTree.UniversalSequenceNumber, - MergeTree.LocalClientId, - MergeTree.UniversalSequenceNumber, - undefined, - ); - accumTime += elapsedMicroseconds(clockStart); - const updatedText = helper.getText(MergeTree.UniversalSequenceNumber, MergeTree.LocalClientId); - const result = checkText === updatedText; - if (!result && verbose) { - console.log(`mismatch(o): ${checkText}`); - console.log(`mismatch(u): ${updatedText}`); - } - return result; -} - -function checkMarkRemoveMergeTree( - mergeTree: MergeTree.MergeTree, - start: number, - end: number, - verbose = false, -) { - const helper = new MergeTree.MergeTreeTextHelper(mergeTree); - const origText = helper.getText(MergeTree.UniversalSequenceNumber, MergeTree.LocalClientId); - const checkText = editFlat(origText, start, end - start); - const clockStart = clock(); - mergeTree.markRangeRemoved( - start, - end, - MergeTree.UniversalSequenceNumber, - MergeTree.LocalClientId, - MergeTree.UniversalSequenceNumber, - false, - // `opArgs` being `undefined` is special-cased specifically for internal - // test code - undefined as any, - ); - accumTime += elapsedMicroseconds(clockStart); - const updatedText = helper.getText(MergeTree.UniversalSequenceNumber, MergeTree.LocalClientId); - const result = checkText === updatedText; - if (!result && verbose) { - console.log(`mismatch(o): ${origText}`); - console.log(`mismatch(c): ${checkText}`); - console.log(`mismatch(u): ${updatedText}`); - } - return result; -} - -const makeCollabTextSegment = (text: string) => new MergeTree.TextSegment(text); - -export function mergeTreeCheckedTest() { - const mergeTree = new MergeTree.MergeTree(); - mergeTree.insertSegments( - 0, - [MergeTree.TextSegment.make("the cat is on the mat")], - MergeTree.UniversalSequenceNumber, - MergeTree.LocalClientId, - MergeTree.UniversalSequenceNumber, - undefined, - ); - const insertCount = 2000; - const removeCount = 1400; - const largeRemoveCount = 20; - const mt = MersenneTwister19937.seedWithArray([0xdeadbeef, 0xfeedbed]); - const imin = 1; - const imax = 9; - const distribution = integer(imin, imax); - const largeDistribution = integer(10, 1000); - const randInt = () => distribution(mt); - const randLargeInt = () => largeDistribution(mt); - function randomString(len: number, c: string) { - let str = ""; - for (let i = 0; i < len; i++) { - str += c; - } - return str; - } - accumTime = 0; - let accumTreeSize = 0; - let treeCount = 0; - let errorCount = 0; - for (let i = 0; i < insertCount; i++) { - const slen = randInt(); - const s = randomString(slen, String.fromCharCode(48 + slen)); - const preLen = mergeTree.getLength( - MergeTree.UniversalSequenceNumber, - MergeTree.LocalClientId, - ); - const pos = integer(0, preLen)(mt); - if (!checkInsertMergeTree(mergeTree, pos, makeCollabTextSegment(s), true)) { - console.log( - `i: ${i} preLen ${preLen} pos: ${pos} slen: ${slen} s: ${s} itree len: ${mergeTree.getLength( - MergeTree.UniversalSequenceNumber, - MergeTree.LocalClientId, - )}`, - ); - console.log(mergeTree.toString()); - errorCount++; - break; - } - if (i > 0 && 0 === i % 1000) { - const perIter = (accumTime / (i + 1)).toFixed(3); - treeCount++; - accumTreeSize += mergeTree.getLength( - MergeTree.UniversalSequenceNumber, - MergeTree.LocalClientId, - ); - const averageTreeSize = (accumTreeSize / treeCount).toFixed(3); - console.log( - `i: ${i} time: ${accumTime}us which is average ${perIter} per insert with average tree size ${averageTreeSize}`, - ); - } - } - accumTime = 0; - accumTreeSize = 0; - treeCount = 0; - for (let i = 0; i < largeRemoveCount; i++) { - const dlen = randLargeInt(); - const preLen = mergeTree.getLength( - MergeTree.UniversalSequenceNumber, - MergeTree.LocalClientId, - ); - const pos = integer(0, preLen)(mt); - // Console.log(itree.toString()); - if (!checkMarkRemoveMergeTree(mergeTree, pos, pos + dlen, true)) { - console.log( - `i: ${i} preLen ${preLen} pos: ${pos} dlen: ${dlen} itree len: ${mergeTree.getLength( - MergeTree.UniversalSequenceNumber, - MergeTree.LocalClientId, - )}`, - ); - console.log(mergeTree.toString()); - break; - } - if (i > 0 && 0 === i % 10) { - const perIter = (accumTime / (i + 1)).toFixed(3); - treeCount++; - accumTreeSize += mergeTree.getLength( - MergeTree.UniversalSequenceNumber, - MergeTree.LocalClientId, - ); - const averageTreeSize = (accumTreeSize / treeCount).toFixed(3); - console.log( - `i: ${i} time: ${accumTime}us which is average ${perIter} per large del with average tree size ${averageTreeSize}`, - ); - } - } - accumTime = 0; - accumTreeSize = 0; - treeCount = 0; - for (let i = 0; i < removeCount; i++) { - const dlen = randInt(); - const preLen = mergeTree.getLength( - MergeTree.UniversalSequenceNumber, - MergeTree.LocalClientId, - ); - const pos = integer(0, preLen)(mt); - // Console.log(itree.toString()); - if (i & 1) { - if (!checkMarkRemoveMergeTree(mergeTree, pos, pos + dlen, true)) { - console.log( - `mr i: ${i} preLen ${preLen} pos: ${pos} dlen: ${dlen} itree len: ${mergeTree.getLength( - MergeTree.UniversalSequenceNumber, - MergeTree.LocalClientId, - )}`, - ); - console.log(mergeTree.toString()); - errorCount++; - break; - } - } else { - if (!checkMarkRemoveMergeTree(mergeTree, pos, pos + dlen, true)) { - console.log( - `i: ${i} preLen ${preLen} pos: ${pos} dlen: ${dlen} itree len: ${mergeTree.getLength( - MergeTree.UniversalSequenceNumber, - MergeTree.LocalClientId, - )}`, - ); - console.log(mergeTree.toString()); - errorCount++; - break; - } - } - if (i > 0 && 0 === i % 1000) { - const perIter = (accumTime / (i + 1)).toFixed(3); - treeCount++; - accumTreeSize += mergeTree.getLength( - MergeTree.UniversalSequenceNumber, - MergeTree.LocalClientId, - ); - const averageTreeSize = (accumTreeSize / treeCount).toFixed(3); - console.log( - `i: ${i} time: ${accumTime}us which is average ${perIter} per del with average tree size ${averageTreeSize}`, - ); - } - } - accumTime = 0; - accumTreeSize = 0; - treeCount = 0; - for (let i = 0; i < insertCount; i++) { - const slen = randInt(); - const s = randomString(slen, String.fromCharCode(48 + slen)); - const preLen = mergeTree.getLength( - MergeTree.UniversalSequenceNumber, - MergeTree.LocalClientId, - ); - const pos = integer(0, preLen)(mt); - if (!checkInsertMergeTree(mergeTree, pos, makeCollabTextSegment(s), true)) { - console.log( - `i: ${i} preLen ${preLen} pos: ${pos} slen: ${slen} s: ${s} itree len: ${mergeTree.getLength( - MergeTree.UniversalSequenceNumber, - MergeTree.LocalClientId, - )}`, - ); - console.log(mergeTree.toString()); - errorCount++; - break; - } - if (i > 0 && 0 === i % 1000) { - const perIter = (accumTime / (i + 1)).toFixed(3); - treeCount++; - accumTreeSize += mergeTree.getLength( - MergeTree.UniversalSequenceNumber, - MergeTree.LocalClientId, - ); - const averageTreeSize = (accumTreeSize / treeCount).toFixed(3); - console.log( - `i: ${i} time: ${accumTime}us which is average ${perIter} per insert with average tree size ${averageTreeSize}`, - ); - } - } - accumTime = 0; - accumTreeSize = 0; - treeCount = 0; - for (let i = 0; i < removeCount; i++) { - const dlen = randInt(); - const preLen = mergeTree.getLength( - MergeTree.UniversalSequenceNumber, - MergeTree.LocalClientId, - ); - const pos = integer(0, preLen)(mt); - // Console.log(itree.toString()); - if (i & 1) { - if (!checkMarkRemoveMergeTree(mergeTree, pos, pos + dlen, true)) { - console.log( - `i: ${i} preLen ${preLen} pos: ${pos} dlen: ${dlen} itree len: ${mergeTree.getLength( - MergeTree.UniversalSequenceNumber, - MergeTree.LocalClientId, - )}`, - ); - console.log(mergeTree.toString()); - errorCount++; - break; - } - } else { - if (!checkMarkRemoveMergeTree(mergeTree, pos, pos + dlen, true)) { - console.log( - `i: ${i} preLen ${preLen} pos: ${pos} dlen: ${dlen} itree len: ${mergeTree.getLength( - MergeTree.UniversalSequenceNumber, - MergeTree.LocalClientId, - )}`, - ); - console.log(mergeTree.toString()); - errorCount++; - break; - } - } - if (i > 0 && 0 === i % 1000) { - const perIter = (accumTime / (i + 1)).toFixed(3); - treeCount++; - accumTreeSize += mergeTree.getLength( - MergeTree.UniversalSequenceNumber, - MergeTree.LocalClientId, - ); - const averageTreeSize = (accumTreeSize / treeCount).toFixed(3); - console.log( - `i: ${i} time: ${accumTime}us which is average ${perIter} per del with average tree size ${averageTreeSize}`, - ); - } - } - return errorCount; -} - -export class RandomPack { - mt: MersenneTwister19937; - constructor() { - this.mt = MersenneTwister19937.seedWithArray([0xdeadbeef, 0xfeedbed]); - } - - randInteger(min: number, max: number) { - return integer(min, max)(this.mt); - } - - randString(wordCount: number) { - const exampleWords = [ - "giraffe", - "hut", - "aardvark", - "gold", - "hover", - "yurt", - "hot", - "antelope", - "gift", - "banana", - "book", - "airplane", - "kitten", - "moniker", - "lemma", - "doughnut", - "orange", - "tangerine", - ]; - let buf = ""; - for (let i = 0; i < wordCount; i++) { - const exampleWord = exampleWords[this.randInteger(0, exampleWords.length - 1)]; - if (i > 0) { - buf += " "; - } - buf += exampleWord; - } - return buf; - } -} - -function docNodeToString(docNode: DocumentNode) { - return typeof docNode === "string" ? docNode : docNode.name; -} - -export type DocumentNode = string | DocumentTree; -/** - * Generate and model documents from the following tree grammar: - * Row -\> row[Box*]; - * Box -\> box[Content]; - * Content -\> (Row|Paragraph)*; - * Paragraph -\> pgtile text; - * Document-\> Content - */ -export class DocumentTree { - pos = 0; - ids = { box: 0, row: 0 }; - id: string | undefined; - static randPack = new RandomPack(); - - constructor( - public name: string, - public children: DocumentNode[], - ) {} - - addToMergeTree(client: MergeTree.TestClient, docNode: DocumentNode) { - if (typeof docNode === "string") { - const text = docNode; - client.insertTextLocal(this.pos, text); - this.pos += text.length; - } else { - let id: number | undefined; - if (docNode.name === "pg") { - client.insertMarkerLocal(this.pos, MergeTree.ReferenceType.Tile, { - [MergeTree.reservedTileLabelsKey]: [docNode.name], - }); - this.pos++; - } else { - // eslint-disable-next-line @typescript-eslint/restrict-plus-operands - const trid = docNode.name + this.ids[docNode.name].toString(); - docNode.id = trid; - id = this.ids[docNode.name]++; - const props = { - [MergeTree.reservedMarkerIdKey]: trid, - [MergeTree.reservedRangeLabelsKey]: [docNode.name], - }; - let behaviors = MergeTree.ReferenceType.NestBegin; - if (docNode.name === "row") { - props[MergeTree.reservedTileLabelsKey] = ["pg"]; - behaviors |= MergeTree.ReferenceType.Tile; - } - - client.insertMarkerLocal(this.pos, behaviors, props); - this.pos++; - } - for (const child of docNode.children) { - this.addToMergeTree(client, child); - } - if (docNode.name !== "pg") { - assert(id !== undefined, "expected `id` to be defined"); - const etrid = `end-${docNode.name}${id.toString()}`; - client.insertMarkerLocal(this.pos, MergeTree.ReferenceType.NestEnd, { - [MergeTree.reservedMarkerIdKey]: etrid, - [MergeTree.reservedRangeLabelsKey]: [docNode.name], - }); - this.pos++; - } - } - } - - checkStacksAllPositions(client: MergeTree.TestClient) { - let errorCount = 0; - let pos = 0; - const verbose = false; - const stacks = { - box: new MergeTree.Stack(), - row: new MergeTree.Stack(), - }; - - function printStack(stack: MergeTree.Stack) { - for (const item in stack.items) { - console.log(item); - } - } - - function printStacks() { - for (const name of ["box", "row"]) { - console.log(`${name}:`); - printStack(stacks[name]); - } - } - - function checkTreeStackEmpty(treeStack: MergeTree.Stack) { - if (!treeStack.empty()) { - errorCount++; - console.log("mismatch: client stack empty; tree stack not"); - } - } - - const checkNodeStacks = (docNode: DocumentNode) => { - if (typeof docNode === "string") { - const text = docNode; - const epos = pos + text.length; - if (verbose) { - console.log(`stacks for [${pos}, ${epos}): ${text}`); - printStacks(); - } - const cliStacks = client.getStackContext(pos, ["box", "row"]); - for (const name of ["box", "row"]) { - const cliStack = cliStacks[name]; - const treeStack = >stacks[name]; - if (cliStack) { - const len = cliStack.items.length; - if (len > 0) { - if (len !== treeStack.items.length) { - console.log( - `stack length mismatch cli ${len} tree ${treeStack.items.length}`, - ); - errorCount++; - } - for (let i = 0; i < len; i++) { - const cliMarkerId = (cliStack.items[i] as MergeTree.Marker).getId(); - const treeMarkerId = treeStack.items[i]; - if (cliMarkerId !== treeMarkerId) { - errorCount++; - console.log( - `mismatch index ${i}: ${cliMarkerId} !== ${treeMarkerId} pos ${pos} text ${text}`, - ); - printStack(treeStack); - console.log(client.mergeTree.toString()); - } - } - } else { - checkTreeStackEmpty(treeStack); - } - } else { - checkTreeStackEmpty(treeStack); - } - } - pos = epos; - } else { - pos++; - if (docNode.name === "pg") { - checkNodeStacks(docNode.children[0]); - } else { - stacks[docNode.name].push(docNode.id); - for (const child of docNode.children) { - checkNodeStacks(child); - } - stacks[docNode.name].pop(); - pos++; - } - } - }; - - let prevPos = -1; - let prevChild: DocumentNode | undefined; - - // Console.log(client.mergeTree.toString()); - for (const rootChild of this.children) { - if (prevPos >= 0) { - if (typeof prevChild !== "string" && prevChild?.name === "row") { - const id = prevChild.id; - const endId = `end-${id}`; - const endRowMarker = client.getMarkerFromId(endId); - const endRowPos = client.getPosition(endRowMarker); - prevPos = endRowPos; - } - const tilePos = client.findTile(prevPos, "pg", false); - if (tilePos) { - if (tilePos.pos !== pos) { - errorCount++; - console.log( - `next tile ${tilePos.tile} found from pos ${prevPos} at ${tilePos.pos} compare to ${pos}`, - ); - } - } - } - if (verbose) { - console.log(`next child ${pos} with name ${docNodeToString(rootChild)}`); - } - prevPos = pos; - prevChild = rootChild; - // PrintStacks(); - checkNodeStacks(rootChild); - } - return errorCount; - } - - private generateClient() { - const client = new MergeTree.TestClient(); - client.startOrUpdateCollaboration("Fred"); - for (const child of this.children) { - this.addToMergeTree(client, child); - } - return client; - } - - static test1() { - const doc = DocumentTree.generateDocument(); - const client = doc.generateClient(); - return doc.checkStacksAllPositions(client); - } - - static generateDocument() { - const tree = new DocumentTree("Document", DocumentTree.generateContent(0.6)); - return tree; - } - - static generateContent(initialRowProbability: number) { - let rowProbability = initialRowProbability; - const items = []; - const docLen = DocumentTree.randPack.randInteger(7, 25); - for (let i = 0; i < docLen; i++) { - const rowThreshold = rowProbability * 1000; - const selector = DocumentTree.randPack.randInteger(1, 1000); - if (selector >= rowThreshold) { - const pg = DocumentTree.generateParagraph(); - items.push(pg); - } else { - rowProbability /= 2; - if (rowProbability < 0.08) { - rowProbability = 0; - } - const row = DocumentTree.generateRow(rowProbability); - items.push(row); - } - } - return items; - } - - // Model pg tile as tree with single child - static generateParagraph() { - const wordCount = DocumentTree.randPack.randInteger(1, 6); - const text = DocumentTree.randPack.randString(wordCount); - const pgTree = new DocumentTree("pg", [text]); - return pgTree; - } - - static generateRow(rowProbability: number) { - const items = []; - const rowLen = DocumentTree.randPack.randInteger(1, 5); - for (let i = 0; i < rowLen; i++) { - const item = DocumentTree.generateBox(rowProbability); - items.push(item); - } - return new DocumentTree("row", items); - } - - static generateBox(rowProbability: number) { - return new DocumentTree("box", DocumentTree.generateContent(rowProbability)); - } -} - -export function intervalTest() { - const mt = MersenneTwister19937.seedWithArray([0xdeadbeef, 0xfeedbed]); - const imin = 0; - const imax = 10000000; - const intCount = 50000; - const arr = [] as Interval[]; - const distribution = integer(imin, imax); - const randInt = () => distribution(mt); - const intervalIndex = createIntervalIndex(); - - for (let i = 0; i < intCount; i++) { - let a = randInt(); - let b = randInt(); - while (a === b) { - b = randInt(); - } - if (a > b) { - const temp = a; - a = b; - b = temp; - } - arr.push(intervalIndex.addInterval(a, b, IntervalType.Simple, { id: i })); - } - let dup = 0; - for (let i = 0; i < intCount; i++) { - if (arr[i].getAdditionalPropertySets()) { - dup++; - } - } - console.log(`dup: ${dup}`); -} - -export interface ICmd { - description?: string; - iconURL?: string; - exec?: () => void; -} -export function tstSimpleCmd() { - const tst = new MergeTree.TST(); - tst.put("zest", { description: "zesty" }); - tst.put("nest", { description: "nesty" }); - tst.put("newt", { description: "newty" }); - tst.put("neither", { description: "neithery" }); - tst.put("restitution", { description: "restitutiony" }); - tst.put("restful", { description: "restfuly" }); - tst.put("fish", { description: "fishy" }); - tst.put("nurf", { description: "nurfy" }); - tst.put("reify", { description: "reifyy" }); - tst.put("pert", { description: "perty" }); - tst.put("jest", { description: "jesty" }); - tst.put("jestcuz", { description: "jestcuzy" }); - let res = tst.pairsWithPrefix("je"); - console.log("trying je"); - for (const pair of res) { - console.log(`key: ${pair.key} val: ${pair.val.description}`); - } - res = tst.pairsWithPrefix("n"); - console.log("trying n"); - for (const pair of res) { - console.log(`key: ${pair.key} val: ${pair.val.description}`); - } - res = tst.pairsWithPrefix("ne"); - console.log("trying ne"); - for (const pair of res) { - console.log(`key: ${pair.key} val: ${pair.val.description}`); - } - res = []; - tst.map((key, val) => res.push({ key, val })); - console.log("trying map"); - for (const pair of res) { - console.log(`key: ${pair.key} val: ${pair.val.description}`); - } -} - -const testPropCopy = false; -const docTree = false; -const chktst = false; -const clientServerTest = true; -const tstTest = false; -const doFirstTest = false; -const ivalTest = false; - -if (doFirstTest) { - const testPack = TestPack(true); - testPack.firstTest(); -} - -if (ivalTest) { - intervalTest(); -} - -if (tstTest) { - tstSimpleCmd(); -} - -if (chktst) { - mergeTreeCheckedTest(); -} - -if (testPropCopy) { - propertyCopy(); -} - -if (docTree) { - DocumentTree.test1(); -} - -if (clientServerTest) { - const ppTest = true; - const testPack = TestPack(); - const baseDir = "../../../merge-tree/src/test/literature"; - const filename = path.join(__dirname, baseDir, "pp.txt"); - if (ppTest) { - testPack.clientServer(filename, 100000); - } else { - testPack.clientServer(undefined, 100000); - } -} - -function ordinalToArray(ord: string) { - const a: number[] = []; - if (ord) { - for (let i = 0, len = ord.length; i < len; i++) { - a.push(ord.charCodeAt(i)); - } - } - return a; -} diff --git a/packages/dds/sequence/src/test/tsconfig.json b/packages/dds/sequence/src/test/tsconfig.json index e4c50048cad9..b6874d728e97 100644 --- a/packages/dds/sequence/src/test/tsconfig.json +++ b/packages/dds/sequence/src/test/tsconfig.json @@ -13,6 +13,9 @@ "rootDir": "./", "outDir": "../../dist/test", "types": ["mocha"], + "noImplicitAny": false, "noUnusedLocals": false, // Need it so memory tests can declare local variables just for the sake of keeping things in memory, + "module": "Node16", + "moduleResolution": "Node16", }, } diff --git a/packages/dds/sequence/tsc-multi.test.json b/packages/dds/sequence/tsc-multi.test.json new file mode 100644 index 000000000000..eca0e81a8b78 --- /dev/null +++ b/packages/dds/sequence/tsc-multi.test.json @@ -0,0 +1,10 @@ +{ + "targets": [ + { + "extname": ".cjs", + "module": "Node16", + "moduleResolution": "Node16" + } + ], + "projects": ["./tsconfig.json", "./src/test/tsconfig.json"] +} diff --git a/packages/dds/sequence/tsconfig.esnext.json b/packages/dds/sequence/tsconfig.esnext.json deleted file mode 100644 index 3c2dddb86236..000000000000 --- a/packages/dds/sequence/tsconfig.esnext.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": ["./tsconfig.json", "../../../common/build/build-common/tsconfig.esm.json"], - "compilerOptions": { - "outDir": "./lib", - }, -} diff --git a/packages/runtime/id-compressor/package.json b/packages/runtime/id-compressor/package.json index 35d193da3845..b543469c43a9 100644 --- a/packages/runtime/id-compressor/package.json +++ b/packages/runtime/id-compressor/package.json @@ -73,6 +73,7 @@ "uuid": "^9.0.0" }, "devDependencies": { + "@arethetypeswrong/cli": "^0.13.3", "@fluid-private/stochastic-test-utils": "workspace:~", "@fluid-tools/benchmark": "^0.48.0", "@fluid-tools/build-cli": "^0.28.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6d3f30369538..40b19104f198 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -328,7 +328,7 @@ importers: rimraf: 4.4.1 start-server-and-test: 1.15.5 tinylicious: 2.0.2 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju tsc-multi: 1.1.0_44oayjl3iesbankmh6w6z32iii_typescript@5.1.6 typescript: 5.1.6 @@ -568,7 +568,7 @@ importers: process: 0.11.10 puppeteer: 17.1.3 rimraf: 4.4.1 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -659,7 +659,7 @@ importers: process: 0.11.10 puppeteer: 17.1.3 rimraf: 4.4.1 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -742,7 +742,7 @@ importers: process: 0.11.10 puppeteer: 17.1.3 rimraf: 4.4.1 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -950,7 +950,7 @@ importers: prettier: 3.0.3 puppeteer: 17.1.3 rimraf: 4.4.1 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -1035,7 +1035,7 @@ importers: process: 0.11.10 puppeteer: 17.1.3 rimraf: 4.4.1 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -1148,7 +1148,7 @@ importers: puppeteer: 17.1.3 rimraf: 4.4.1 style-loader: 1.3.0_webpack@5.89.0 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -1223,7 +1223,7 @@ importers: prettier: 3.0.3 puppeteer: 17.1.3 rimraf: 4.4.1 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -1370,7 +1370,7 @@ importers: prettier: 3.0.3 puppeteer: 17.1.3 rimraf: 4.4.1 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 typescript-formatter: 7.2.2_typescript@5.1.6 @@ -1450,7 +1450,7 @@ importers: prettier: 3.0.3 puppeteer: 17.1.3 rimraf: 4.4.1 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -1527,7 +1527,7 @@ importers: prettier: 3.0.3 puppeteer: 17.1.3 rimraf: 4.4.1 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -1694,7 +1694,7 @@ importers: rimraf: 4.4.1 start-server-and-test: 1.15.5 tinylicious: 2.0.2 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju tslib: 1.14.1 typescript: 5.1.6 @@ -1847,7 +1847,7 @@ importers: prettier: 3.0.3 puppeteer: 17.1.3 rimraf: 4.4.1 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -1997,7 +1997,7 @@ importers: prettier: 3.0.3 puppeteer: 17.1.3 rimraf: 4.4.1 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -2068,7 +2068,7 @@ importers: prettier: 3.0.3 puppeteer: 17.1.3 rimraf: 4.4.1 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -2202,7 +2202,7 @@ importers: prettier: 3.0.3 puppeteer: 17.1.3 rimraf: 4.4.1 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -2273,7 +2273,7 @@ importers: puppeteer: 17.1.3 rimraf: 4.4.1 style-loader: 1.3.0_webpack@5.89.0 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -2370,7 +2370,7 @@ importers: puppeteer: 17.1.3 rimraf: 4.4.1 style-loader: 1.3.0_webpack@5.89.0 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -2431,7 +2431,7 @@ importers: prettier: 3.0.3 puppeteer: 17.1.3 rimraf: 4.4.1 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -2542,7 +2542,7 @@ importers: puppeteer: 17.1.3 rimraf: 4.4.1 style-loader: 1.3.0_webpack@5.89.0 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -2611,7 +2611,7 @@ importers: puppeteer: 17.1.3 rimraf: 4.4.1 style-loader: 1.3.0_webpack@5.89.0 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -2680,7 +2680,7 @@ importers: puppeteer: 17.1.3 rimraf: 4.4.1 style-loader: 1.3.0_webpack@5.89.0 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -3478,7 +3478,7 @@ importers: stream-http: 3.2.0 supertest: 3.4.2 tinylicious: 2.0.2 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -3784,7 +3784,7 @@ importers: process: 0.11.10 puppeteer: 17.1.3 rimraf: 4.4.1 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -3905,7 +3905,7 @@ importers: puppeteer: 17.1.3 rimraf: 4.4.1 style-loader: 1.3.0_webpack@5.89.0 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -4026,7 +4026,7 @@ importers: puppeteer: 17.1.3 rimraf: 4.4.1 style-loader: 1.3.0_webpack@5.89.0 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -4143,7 +4143,7 @@ importers: start-server-and-test: 1.15.5 style-loader: 1.3.0_webpack@5.89.0 tinylicious: 2.0.2 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -4230,7 +4230,7 @@ importers: prettier: 3.0.3 puppeteer: 17.1.3 rimraf: 4.4.1 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -4305,7 +4305,7 @@ importers: process: 0.11.10 puppeteer: 17.1.3 rimraf: 4.4.1 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -4390,7 +4390,7 @@ importers: process: 0.11.10 puppeteer: 17.1.3 rimraf: 4.4.1 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -5345,7 +5345,7 @@ importers: jest-junit: 10.0.0 prettier: 3.0.3 rimraf: 4.4.1 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm typescript: 5.1.6 experimental/PropertyDDS/services/property-query-service: @@ -6120,6 +6120,7 @@ importers: packages/common/client-utils: specifiers: '@arethetypeswrong/cli': ^0.13.3 + '@fluid-internal/client-utils-previous': npm:@fluid-internal/client-utils@2.0.0-internal.7.3.0 '@fluid-tools/build-cli': ^0.28.0 '@fluidframework/build-common': ^2.0.3 '@fluidframework/build-tools': ^0.28.0 @@ -6157,12 +6158,14 @@ importers: moment: ^2.21.0 prettier: ~3.0.3 puppeteer: ^17.1.3 + renamer: ^4.0.0 rewire: ^5.0.0 rimraf: ^4.4.0 sha.js: ^2.4.11 sinon: ^7.4.2 ts-jest: ^29.1.1 ts-node: ^10.9.1 + tsc-multi: ^1.1.0 typescript: ~5.1.6 dependencies: '@fluidframework/core-interfaces': link:../core-interfaces @@ -6175,6 +6178,7 @@ importers: sha.js: 2.4.11 devDependencies: '@arethetypeswrong/cli': 0.13.3 + '@fluid-internal/client-utils-previous': /@fluid-internal/client-utils/2.0.0-internal.7.3.0 '@fluid-tools/build-cli': 0.28.0_mhw3tufvtaceew37hrkkevjcli '@fluidframework/build-common': 2.0.3 '@fluidframework/build-tools': 0.28.0_@types+node@18.19.1 @@ -6205,11 +6209,13 @@ importers: moment: 2.29.4 prettier: 3.0.3 puppeteer: 17.1.3 + renamer: 4.0.0 rewire: 5.0.0 rimraf: 4.4.1 sinon: 7.5.0 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-node: 10.9.1_ggysxzqxruqvydtrq6zb2nxvwm + tsc-multi: 1.1.0_44oayjl3iesbankmh6w6z32iii_typescript@5.1.6 typescript: 5.1.6 packages/common/container-definitions: @@ -6776,7 +6782,10 @@ importers: mocha-multi-reporters: ^1.5.1 moment: ^2.21.0 prettier: ~3.0.3 + renamer: ^4.0.0 + replace-in-file: ^6.3.5 rimraf: ^4.4.0 + tsc-multi: ^1.1.0 typescript: ~5.1.6 dependencies: '@fluid-internal/client-utils': link:../../common/client-utils @@ -6815,7 +6824,10 @@ importers: mocha-multi-reporters: 1.5.1_mocha@10.2.0 moment: 2.29.4 prettier: 3.0.3 + renamer: 4.0.0 + replace-in-file: 6.3.5 rimraf: 4.4.1 + tsc-multi: 1.1.0_44oayjl3iesbankmh6w6z32iii_typescript@5.1.6 typescript: 5.1.6 packages/dds/ordered-collection: @@ -7063,7 +7075,10 @@ importers: moment: ^2.21.0 prettier: ~3.0.3 random-js: ^2.1.0 + renamer: ^4.0.0 + replace-in-file: ^6.3.5 rimraf: ^4.4.0 + tsc-multi: ^1.1.0 typescript: ~5.1.6 uuid: ^9.0.0 dependencies: @@ -7105,7 +7120,10 @@ importers: moment: 2.29.4 prettier: 3.0.3 random-js: 2.1.0 + renamer: 4.0.0 + replace-in-file: 6.3.5 rimraf: 4.4.1 + tsc-multi: 1.1.0_44oayjl3iesbankmh6w6z32iii_typescript@5.1.6 typescript: 5.1.6 packages/dds/shared-object-base: @@ -9598,6 +9616,7 @@ importers: packages/runtime/id-compressor: specifiers: + '@arethetypeswrong/cli': ^0.13.3 '@fluid-internal/client-utils': workspace:~ '@fluid-private/stochastic-test-utils': workspace:~ '@fluid-tools/benchmark': ^0.48.0 @@ -9633,6 +9652,7 @@ importers: sorted-btree: 1.8.1 uuid: 9.0.1 devDependencies: + '@arethetypeswrong/cli': 0.13.3 '@fluid-private/stochastic-test-utils': link:../../test/stochastic-test-utils '@fluid-tools/benchmark': 0.48.0 '@fluid-tools/build-cli': 0.28.0_loebgezstcsvd2poh2d55fifke @@ -11176,7 +11196,7 @@ importers: sinon: 7.5.0 sinon-chrome: 3.0.1 start-server-and-test: 1.15.5 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -11398,7 +11418,7 @@ importers: prettier: 3.0.3 puppeteer: 17.1.3 rimraf: 4.4.1 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm ts-loader: 9.5.1_535b6rdv6xzubhvm4whegmtnju typescript: 5.1.6 webpack: 5.89.0_webpack-cli@4.10.0 @@ -11539,7 +11559,7 @@ importers: prop-types: 15.8.1 rimraf: 4.4.1 simple-git: 3.21.0 - ts-jest: 29.1.1_gvmt7aj7nai5bnvsxmiksfugce + ts-jest: 29.1.1_7c6s2cwl7nw46fjeerv4uupgbm typescript: 5.1.6 vite: 4.5.0_@types+node@18.19.1 @@ -15823,6 +15843,19 @@ packages: sha.js: 2.4.11 dev: true + /@fluid-internal/client-utils/2.0.0-internal.7.3.0: + resolution: {integrity: sha512-q+lf7BTbBYvtLfg0AJXvnn4+pdtYt/R44fkD+Srs9s2PenieOM5LEAeIABS0xG99d6ys8K54P4xvqpkctupYqg==} + dependencies: + '@fluidframework/core-interfaces': 2.0.0-internal.7.3.0 + '@fluidframework/core-utils': 2.0.0-internal.7.3.0 + '@types/events': 3.0.3 + base64-js: 1.5.1 + buffer: 6.0.3 + events: 3.3.0 + lodash: 4.17.21 + sha.js: 2.4.11 + dev: true + /@fluid-tools/benchmark/0.47.0: resolution: {integrity: sha512-lQ2ijhUJ68aOHqH1UxOBmAsSWfx2dIuI4vAlQ4e/ueh0a8KUZ8D8AUpJPu1k1pwuTlOuvb629BY9Q4HC6H/KBQ==} dependencies: @@ -16704,10 +16737,18 @@ packages: resolution: {integrity: sha512-RaI37klIYxUpCH5PHeIzkUjxXbA0Omytb22bzc6zoosXzwCDQ4EikFQ02qKqVZpl4wIC6Fw+B6uKIgaR7xNdCg==} dev: true + /@fluidframework/core-interfaces/2.0.0-internal.7.3.0: + resolution: {integrity: sha512-pPDhVlcr4Wm340TCgIkGV+QduKRcrYU44mdaEhBaRaubYrf742kjrpaqrT7JvQCP1KVSH9whRo4/WexANuu3BQ==} + dev: true + /@fluidframework/core-utils/2.0.0-internal.7.2.2: resolution: {integrity: sha512-UYRRyFDmq1KZXoeSxYIu5ra82XoeLT9S0Y/1HzLu9UnVz813TzgI2gvW+BG7yXC+E9lNIy7CWoSrD7itjjNAWQ==} dev: true + /@fluidframework/core-utils/2.0.0-internal.7.3.0: + resolution: {integrity: sha512-5yrf+YIWHMzyeZL4UI4w6j4Xrju3QKzbiIWj6H3+QsckrrRQdVzP7reSnj6sp3F59KmClajcJi4CAp4lU5Kx+g==} + dev: true + /@fluidframework/counter/2.0.0-internal.7.2.0: resolution: {integrity: sha512-QFjtHBAdwPR2eHRVoo7X8nncHdq4y6ZIX0LlEnvtA8WCoGDOALoK5KF40+B3fZ84q8NyDWtcXoU6SJSh/Q/ztA==} dependencies: @@ -17008,7 +17049,7 @@ packages: eslint-config-prettier: 9.0.0_eslint@8.50.0 eslint-import-resolver-typescript: 3.6.1_ptoqaxx4zydtl73iuefwc5ceta eslint-plugin-eslint-comments: 3.2.0_eslint@8.50.0 - eslint-plugin-import: /eslint-plugin-i/2.29.0_qkgnnbjqevbkx5nf2343uj5ca4 + eslint-plugin-import: /eslint-plugin-i/2.29.0_vbz3upjaqqip6sbto2camnstqu eslint-plugin-jsdoc: 46.8.2_eslint@8.50.0 eslint-plugin-promise: 6.1.1_eslint@8.50.0 eslint-plugin-react: 7.33.2_eslint@8.50.0 @@ -24203,6 +24244,21 @@ packages: typical: 2.6.1 dev: true + /array-back/3.1.0: + resolution: {integrity: sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==} + engines: {node: '>=6'} + dev: true + + /array-back/4.0.2: + resolution: {integrity: sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==} + engines: {node: '>=8'} + dev: true + + /array-back/6.2.2: + resolution: {integrity: sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==} + engines: {node: '>=12.17'} + dev: true + /array-buffer-byte-length/1.0.0: resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} dependencies: @@ -26479,6 +26535,26 @@ packages: typical: 2.6.1 dev: true + /command-line-args/5.2.1: + resolution: {integrity: sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==} + engines: {node: '>=4.0.0'} + dependencies: + array-back: 3.1.0 + find-replace: 3.0.0 + lodash.camelcase: 4.3.0 + typical: 4.0.0 + dev: true + + /command-line-usage/6.1.3: + resolution: {integrity: sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==} + engines: {node: '>=8.0.0'} + dependencies: + array-back: 4.0.2 + chalk: 2.4.2 + table-layout: 1.0.2 + typical: 5.2.0 + dev: true + /commander/10.0.1: resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} engines: {node: '>=14'} @@ -27289,6 +27365,11 @@ packages: stream-transform: 2.1.3 dev: true + /current-module-paths/1.1.1: + resolution: {integrity: sha512-8Ga5T8oMXBaSsHq9Gj+bddX7kHSaJKsl2vaAd3ep51eQLkr4W18eFEmEZM5bLo1zrz8tt3jE1U8QK9QGhaLR4g==} + engines: {node: '>=12.17'} + dev: true + /currently-unhandled/0.4.1: resolution: {integrity: sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==} engines: {node: '>=0.10.0'} @@ -28784,7 +28865,7 @@ packages: enhanced-resolve: 5.15.0 eslint: 8.50.0 eslint-module-utils: 2.8.0_qkgnnbjqevbkx5nf2343uj5ca4 - eslint-plugin-import: /eslint-plugin-i/2.29.0_qkgnnbjqevbkx5nf2343uj5ca4 + eslint-plugin-import: /eslint-plugin-i/2.29.0_vbz3upjaqqip6sbto2camnstqu fast-glob: 3.3.2 get-tsconfig: 4.7.2 is-core-module: 2.13.1 @@ -28796,7 +28877,7 @@ packages: - supports-color dev: true - /eslint-module-utils/2.8.0_2fdjpxztni4ct7ibb6nnscsdt4: + /eslint-module-utils/2.8.0_62axpgaukyzoyqg7a4wuabw3mq: resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} peerDependencies: @@ -28821,7 +28902,6 @@ packages: debug: 3.2.7 eslint: 8.50.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1_ptoqaxx4zydtl73iuefwc5ceta transitivePeerDependencies: - supports-color dev: true @@ -28913,7 +28993,7 @@ packages: lodash.upperfirst: 4.3.1 dev: true - /eslint-plugin-i/2.29.0_qkgnnbjqevbkx5nf2343uj5ca4: + /eslint-plugin-i/2.29.0_vbz3upjaqqip6sbto2camnstqu: resolution: {integrity: sha512-slGeTS3GQzx9267wLJnNYNO8X9EHGsc75AKIAFvnvMYEcTJKotPKL1Ru5PIGVHIVet+2DsugePWp8Oxpx8G22w==} engines: {node: '>=12'} peerDependencies: @@ -28923,7 +29003,7 @@ packages: doctrine: 2.1.0 eslint: 8.50.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0_2fdjpxztni4ct7ibb6nnscsdt4 + eslint-module-utils: 2.8.0_62axpgaukyzoyqg7a4wuabw3mq get-tsconfig: 4.7.2 is-glob: 4.0.3 minimatch: 3.1.2 @@ -29907,6 +29987,14 @@ packages: webpack: 4.47.0_webpack-cli@4.10.0 dev: true + /file-set/5.1.3: + resolution: {integrity: sha512-mQ6dqz+z59on3B50IGF3ujNGbZmY1TAeLHpNfhLEeNM6Lky31w3RUlbCyqZWQs0DuZJQU4R2qDuVd9ojyzadcg==} + engines: {node: '>=12.17'} + dependencies: + array-back: 6.2.2 + glob: 7.2.3 + dev: true + /file-system-cache/1.1.0: resolution: {integrity: sha512-IzF5MBq+5CR0jXx5RxPe4BICl/oEhBSXKaL9fLhAXrIfIUS77Hr4vzrYyqYMHN6uTt+BOqi3fDCTjjEBCjERKw==} dependencies: @@ -30028,6 +30116,13 @@ packages: test-value: 2.1.0 dev: true + /find-replace/3.0.0: + resolution: {integrity: sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==} + engines: {node: '>=4.0.0'} + dependencies: + array-back: 3.1.0 + dev: true + /find-root/1.1.0: resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} @@ -34822,6 +34917,13 @@ packages: strip-bom: 3.0.0 type-fest: 0.3.1 + /load-module/4.2.1: + resolution: {integrity: sha512-Sbfg6R4LjvyThJpqUoADHMjyoI2+cL4msbCQeZ9kkY/CqP/TT2938eftKm7x4I2gd4/A+DEe6nePkbfWYbXwSw==} + engines: {node: '>=12.17'} + dependencies: + array-back: 6.2.2 + dev: true + /load-yaml-file/0.2.0: resolution: {integrity: sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==} engines: {node: '>=6'} @@ -38621,6 +38723,12 @@ packages: engines: {node: '>=0.8'} hasBin: true + /printj/1.3.1: + resolution: {integrity: sha512-GA3TdL8szPK4AQ2YnOe/b+Y1jUFwmmGMMK/qbY7VcE3Z7FU8JstbKiKRzO6CIiAKPhTO8m01NoQ0V5f3jc4OGg==} + engines: {node: '>=0.8'} + hasBin: true + dev: true + /proc-log/1.0.0: resolution: {integrity: sha512-aCk8AO51s+4JyuYGg3Q/a6gnrlDO09NpVWePtjp7xwphcoQ04x5WAfCyugcsbLooWcMJ87CLkD4+604IckEdhg==} dev: true @@ -39829,6 +39937,11 @@ packages: dependencies: redis-errors: 1.2.0 + /reduce-flatten/2.0.0: + resolution: {integrity: sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==} + engines: {node: '>=6'} + dev: true + /reduce-to-639-1/1.1.0: resolution: {integrity: sha512-9yy/xgTE8qPlZKQrQmyCU1Y1ZSnnOCP4K0Oe1YrBtteUmVXk0AgyINp0NS5kHGzZfpvjgHr6ygFZc9fpqf7moQ==} dev: true @@ -40083,6 +40196,25 @@ packages: resolution: {integrity: sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==} dev: true + /renamer/4.0.0: + resolution: {integrity: sha512-yurufcXxbJfFBVAUoByNyDVH811zTZ/MrKo6gUH8pHGeAmdK7J5egj2lSNe57HuVIvnVzSalzeVGu8pi8UHGxg==} + engines: {node: '>=12.17'} + hasBin: true + dependencies: + array-back: 6.2.2 + chalk: 4.1.2 + command-line-args: 5.2.1 + command-line-usage: 6.1.3 + current-module-paths: 1.1.1 + fast-diff: 1.2.0 + file-set: 5.1.3 + global-dirs: 3.0.1 + load-module: 4.2.1 + printj: 1.3.1 + stream-read-all: 3.0.1 + typical: 7.1.1 + dev: true + /renderkid/2.0.7: resolution: {integrity: sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ==} dependencies: @@ -41699,6 +41831,11 @@ packages: xtend: 4.0.2 dev: true + /stream-read-all/3.0.1: + resolution: {integrity: sha512-EWZT9XOceBPlVJRrYcykW8jyRSZYbkb/0ZK36uLEmoWVO5gxBOnntNTseNzfREsqxqdfEGQrD8SXQ3QWbBmq8A==} + engines: {node: '>=10'} + dev: true + /stream-shift/1.0.1: resolution: {integrity: sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==} dev: true @@ -42249,6 +42386,16 @@ packages: zod: 3.21.4 dev: true + /table-layout/1.0.2: + resolution: {integrity: sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==} + engines: {node: '>=8.0.0'} + dependencies: + array-back: 4.0.2 + deep-extend: 0.6.0 + typical: 5.2.0 + wordwrapjs: 4.0.1 + dev: true + /table-parser/0.1.3: resolution: {integrity: sha512-LCYeuvqqoPII3lzzYaXKbC3Forb+d2u4bNwhk/9FlivuGRxPE28YEWAYcujeSlLLDlMfvy29+WPybFJZFiKMYg==} dependencies: @@ -42876,39 +43023,6 @@ packages: yargs-parser: 21.1.1 dev: true - /ts-jest/29.1.1_gvmt7aj7nai5bnvsxmiksfugce: - resolution: {integrity: sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - peerDependencies: - '@babel/core': '>=7.0.0-beta.0 <8' - '@jest/types': ^29.0.0 - babel-jest: ^29.0.0 - esbuild: '*' - jest: ^29.0.0 - typescript: '>=4.3 <6' - peerDependenciesMeta: - '@babel/core': - optional: true - '@jest/types': - optional: true - babel-jest: - optional: true - esbuild: - optional: true - dependencies: - bs-logger: 0.2.6 - fast-json-stable-stringify: 2.1.0 - jest: 29.7.0_@types+node@18.19.1 - jest-util: 29.7.0 - json5: 2.2.3 - lodash.memoize: 4.1.2 - make-error: 1.3.6 - semver: 7.5.4 - typescript: 5.1.6 - yargs-parser: 21.1.1 - dev: true - /ts-loader/9.5.1_535b6rdv6xzubhvm4whegmtnju: resolution: {integrity: sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==} engines: {node: '>=12.0.0'} @@ -43374,6 +43488,21 @@ packages: resolution: {integrity: sha512-ofhi8kjIje6npGozTip9Fr8iecmYfEbS06i0JnIg+rh51KakryWF4+jX8lLKZVhy6N+ID45WYSFCxPOdTWCzNg==} dev: true + /typical/4.0.0: + resolution: {integrity: sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==} + engines: {node: '>=8'} + dev: true + + /typical/5.2.0: + resolution: {integrity: sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==} + engines: {node: '>=8'} + dev: true + + /typical/7.1.1: + resolution: {integrity: sha512-T+tKVNs6Wu7IWiAce5BgMd7OZfNYUndHwc5MknN+UHOudi7sGZzuHdCadllRuqJ3fPtgFtIH9+lt9qRv6lmpfA==} + engines: {node: '>=12.17'} + dev: true + /typo-js/1.2.3: resolution: {integrity: sha512-67Hyl94beZX8gmTap7IDPrG5hy2cHftgsCAcGvE1tzuxGT+kRB+zSBin0wIMwysYw8RUCBCvv9UfQl8TNM75dA==} dev: false @@ -45117,6 +45246,14 @@ packages: /wordwrap/1.0.0: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} + /wordwrapjs/4.0.1: + resolution: {integrity: sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==} + engines: {node: '>=8.0.0'} + dependencies: + reduce-flatten: 2.0.0 + typical: 5.2.0 + dev: true + /worker-farm/1.7.0: resolution: {integrity: sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==} dependencies: diff --git a/tools/pipelines/build-client.yml b/tools/pipelines/build-client.yml index 276755b04073..cc11752a9b7b 100644 --- a/tools/pipelines/build-client.yml +++ b/tools/pipelines/build-client.yml @@ -136,6 +136,10 @@ extends: # one. And since we don't batch commits for CI pipeline runs, the only reason we see for automated runs is IndividualCI. telemetry: ${{ eq(variables['Build.Reason'], 'IndividualCI') }} taskTest: + # This check must be run after the build, since it relies on built files being present. Eventually it might be moved + # to the "pack" stage since it can use the already-packed packages in that case. As it is the pipeline packs some + # packages twice. + - check:are-the-types-wrong - webpack - ci:test:mocha - ci:test:jest @@ -147,10 +151,6 @@ extends: - ci:test:realsvc:tinylicious:full - ci:test:stress:tinylicious - test:copyresults - # This check must be run after the build, since it relies on built files being present. Eventually it might be moved - # to the "pack" stage since it can use the already-packed packages in that case. As it is the pipeline packs some - # packages twice. - - check:are-the-types-wrong testResultDirs: - nyc/azure - nyc/examples