diff --git a/.changeset/blue-glasses-love.md b/.changeset/blue-glasses-love.md new file mode 100644 index 00000000000..2c2afe30a88 --- /dev/null +++ b/.changeset/blue-glasses-love.md @@ -0,0 +1,5 @@ +--- +"fast-check": major +--- + +🔧 Toggle on `isolatedDeclarations` flag on the project diff --git a/packages/fast-check/src/arbitrary/_internals/helpers/FloatHelpers.ts b/packages/fast-check/src/arbitrary/_internals/helpers/FloatHelpers.ts index de9e3fceea3..075af835c6e 100644 --- a/packages/fast-check/src/arbitrary/_internals/helpers/FloatHelpers.ts +++ b/packages/fast-check/src/arbitrary/_internals/helpers/FloatHelpers.ts @@ -2,11 +2,11 @@ const safeNegativeInfinity = Number.NEGATIVE_INFINITY; const safePositiveInfinity = Number.POSITIVE_INFINITY; /** @internal */ -export const MIN_VALUE_32 = 2 ** -126 * 2 ** -23; +export const MIN_VALUE_32: number = 2 ** -126 * 2 ** -23; /** @internal */ -export const MAX_VALUE_32 = 2 ** 127 * (1 + (2 ** 23 - 1) / 2 ** 23); +export const MAX_VALUE_32: number = 2 ** 127 * (1 + (2 ** 23 - 1) / 2 ** 23); /** @internal */ -export const EPSILON_32 = 2 ** -23; +export const EPSILON_32: number = 2 ** -23; /** @internal */ const INDEX_POSITIVE_INFINITY = 2139095040; // floatToIndex(MAX_VALUE_32) + 1; diff --git a/packages/fast-check/src/arbitrary/_internals/helpers/NoUndefinedAsContext.ts b/packages/fast-check/src/arbitrary/_internals/helpers/NoUndefinedAsContext.ts index 6d2bad22901..187320964d6 100644 --- a/packages/fast-check/src/arbitrary/_internals/helpers/NoUndefinedAsContext.ts +++ b/packages/fast-check/src/arbitrary/_internals/helpers/NoUndefinedAsContext.ts @@ -1,7 +1,7 @@ import { Value } from '../../../check/arbitrary/definition/Value'; /** @internal */ -export const UndefinedContextPlaceholder = Symbol('UndefinedContextPlaceholder'); +export const UndefinedContextPlaceholder: unique symbol = Symbol('UndefinedContextPlaceholder'); /** @internal */ export function noUndefinedAsContext(value: Value): Value { diff --git a/packages/fast-check/src/arbitrary/_internals/implementations/SchedulerImplem.ts b/packages/fast-check/src/arbitrary/_internals/implementations/SchedulerImplem.ts index c5e418afe2b..ca7467a02e2 100644 --- a/packages/fast-check/src/arbitrary/_internals/implementations/SchedulerImplem.ts +++ b/packages/fast-check/src/arbitrary/_internals/implementations/SchedulerImplem.ts @@ -1,5 +1,6 @@ import { escapeForTemplateString } from '../helpers/TextEscaper'; import { cloneMethod } from '../../../check/symbols'; +import type { WithCloneMethod } from '../../../check/symbols'; import { stringify } from '../../../utils/stringify'; import type { Scheduler, SchedulerAct, SchedulerReportItem, SchedulerSequenceItem } from '../interfaces/Scheduler'; @@ -49,6 +50,11 @@ export class SchedulerImplem implements Scheduler { this.scheduledTasks = []; this.triggeredTasks = []; this.scheduledWatchers = []; + (this as unknown as WithCloneMethod)[cloneMethod] = function ( + this: SchedulerImplem, + ): Scheduler { + return new SchedulerImplem(this.act, this.sourceTaskSelector); + }; } private static buildLog(reportItem: SchedulerReportItem) { @@ -323,8 +329,4 @@ export class SchedulerImplem implements Scheduler { '`' ); } - - [cloneMethod](): Scheduler { - return new SchedulerImplem(this.act, this.sourceTaskSelector); - } } diff --git a/packages/fast-check/src/check/model/commands/CommandWrapper.ts b/packages/fast-check/src/check/model/commands/CommandWrapper.ts index d859e07b6a0..cef31d06a85 100644 --- a/packages/fast-check/src/check/model/commands/CommandWrapper.ts +++ b/packages/fast-check/src/check/model/commands/CommandWrapper.ts @@ -4,6 +4,7 @@ import { hasToStringMethod, toStringMethod, } from '../../../utils/stringify'; +import type { WithToStringMethod, WithAsyncToStringMethod } from '../../../utils/stringify'; import { cloneMethod, hasCloneMethod } from '../../symbols'; import type { ICommand } from '../command/ICommand'; @@ -14,22 +15,20 @@ import type { ICommand } from '../command/ICommand'; export class CommandWrapper implements ICommand { - [toStringMethod]?: () => string; - [asyncToStringMethod]?: () => Promise; - hasRan = false; constructor(readonly cmd: ICommand) { if (hasToStringMethod(cmd)) { const method = cmd[toStringMethod]; - this[toStringMethod] = function toStringMethod(): string { + (this as unknown as WithToStringMethod)[toStringMethod] = function toStringMethod(): string { return method.call(cmd); }; } if (hasAsyncToStringMethod(cmd)) { const method = cmd[asyncToStringMethod]; - this[asyncToStringMethod] = function asyncToStringMethod(): Promise { - return method.call(cmd); - }; + (this as unknown as WithAsyncToStringMethod)[asyncToStringMethod] = + function asyncToStringMethod(): Promise { + return method.call(cmd); + }; } } check(m: Readonly): CheckAsync extends false ? boolean : Promise { diff --git a/packages/fast-check/src/check/model/commands/CommandsIterable.ts b/packages/fast-check/src/check/model/commands/CommandsIterable.ts index a4b855b4107..6b6df54d7e7 100644 --- a/packages/fast-check/src/check/model/commands/CommandsIterable.ts +++ b/packages/fast-check/src/check/model/commands/CommandsIterable.ts @@ -1,4 +1,5 @@ import { cloneMethod } from '../../symbols'; +import type { WithCloneMethod } from '../../symbols'; import type { CommandWrapper } from './CommandWrapper'; /** @@ -10,16 +11,19 @@ export class CommandsIterable[], readonly metadataForReplay: () => string, - ) {} + ) { + (this as unknown as WithCloneMethod)[cloneMethod] = function ( + this: CommandsIterable, + ): CommandsIterable { + return new CommandsIterable( + this.commands.map((c) => c.clone()), + this.metadataForReplay, + ); + }; + } [Symbol.iterator](): Iterator> { return this.commands[Symbol.iterator](); } - [cloneMethod](): CommandsIterable { - return new CommandsIterable( - this.commands.map((c) => c.clone()), - this.metadataForReplay, - ); - } toString(): string { const serializedCommands = this.commands .filter((c) => c.hasRan) diff --git a/packages/fast-check/src/utils/globals.ts b/packages/fast-check/src/utils/globals.ts index eaeaec3eea3..9321cf95df1 100644 --- a/packages/fast-check/src/utils/globals.ts +++ b/packages/fast-check/src/utils/globals.ts @@ -42,9 +42,9 @@ const SUint32Array: typeof Uint32Array = Uint32Array; export { SUint32Array as Uint32Array }; const SencodeURIComponent: typeof encodeURIComponent = encodeURIComponent; export { SencodeURIComponent as encodeURIComponent }; -const SMap = Map; +const SMap: MapConstructor = Map; export { SMap as Map }; -const SSymbol = Symbol; +const SSymbol: SymbolConstructor = Symbol; export { SSymbol as Symbol }; // Various remarks concerning this part of the file: diff --git a/packages/fast-check/test/e2e/seed.ts b/packages/fast-check/test/e2e/seed.ts index f2a8b47f36d..72c583a3728 100644 --- a/packages/fast-check/test/e2e/seed.ts +++ b/packages/fast-check/test/e2e/seed.ts @@ -7,4 +7,4 @@ const globalSeed = globalConfig.seed; if (process.env.CI && globalSeed === undefined) { throw new Error('seed must be defined globally in CI'); } -export const seed = globalSeed !== undefined ? globalSeed : Date.now(); +export const seed: number = globalSeed !== undefined ? globalSeed : Date.now(); diff --git a/packages/fast-check/test/unit/arbitrary/__test-helpers__/FloatingPointHelpers.ts b/packages/fast-check/test/unit/arbitrary/__test-helpers__/FloatingPointHelpers.ts index b9287e8a4c2..0407ae040e8 100644 --- a/packages/fast-check/test/unit/arbitrary/__test-helpers__/FloatingPointHelpers.ts +++ b/packages/fast-check/test/unit/arbitrary/__test-helpers__/FloatingPointHelpers.ts @@ -17,7 +17,15 @@ export function float64raw(): fc.Arbitrary { .map(([na32, nb32]) => new Float64Array(new Int32Array([na32, nb32]).buffer)[0]); } -export const defaultFloatRecordConstraints = { +export const defaultFloatRecordConstraints: { + min: fc.Arbitrary; + max: fc.Arbitrary; + noDefaultInfinity: fc.Arbitrary; + noNaN: fc.Arbitrary; + noInteger: fc.Arbitrary; + minExcluded: fc.Arbitrary; + maxExcluded: fc.Arbitrary; +} = { min: float32raw(), max: float32raw(), noDefaultInfinity: fc.boolean(), @@ -27,7 +35,15 @@ export const defaultFloatRecordConstraints = { maxExcluded: fc.boolean(), }; -export const defaultDoubleRecordConstraints = { +export const defaultDoubleRecordConstraints: { + min: fc.Arbitrary; + max: fc.Arbitrary; + noDefaultInfinity: fc.Arbitrary; + noNaN: fc.Arbitrary; + noInteger: fc.Arbitrary; + minExcluded: fc.Arbitrary; + maxExcluded: fc.Arbitrary; +} = { min: float64raw(), max: float64raw(), noDefaultInfinity: fc.boolean(), diff --git a/packages/fast-check/test/unit/arbitrary/__test-helpers__/SizeHelpers.ts b/packages/fast-check/test/unit/arbitrary/__test-helpers__/SizeHelpers.ts index ec00902c1f2..6ecdcb4f894 100644 --- a/packages/fast-check/test/unit/arbitrary/__test-helpers__/SizeHelpers.ts +++ b/packages/fast-check/test/unit/arbitrary/__test-helpers__/SizeHelpers.ts @@ -7,20 +7,21 @@ import type { } from '../../../../src/arbitrary/_internals/helpers/MaxLengthFromMinLength'; const allSizeOrdered = ['xsmall', 'small', 'medium', 'large', 'xlarge'] as const; -export const sizeArb = fc.constantFrom(...allSizeOrdered); +export const sizeArb: fc.Arbitrary = fc.constantFrom(...allSizeOrdered); export const isSmallerSize = (sa: Size, sb: Size): boolean => allSizeOrdered.indexOf(sa) < allSizeOrdered.indexOf(sb); const allRelativeSize = ['-4', '-3', '-2', '-1', '=', '+1', '+2', '+3', '+4'] as const; -export const relativeSizeArb = fc.constantFrom(...allRelativeSize); +export const relativeSizeArb: fc.Arbitrary = fc.constantFrom(...allRelativeSize); const allSizeForArbitrary = [...allSizeOrdered, ...allRelativeSize, 'max'] as const; // WARNING: it does not include undefined -export const sizeForArbitraryArb = fc.constantFrom(...allSizeForArbitrary); - -export const sizeRelatedGlobalConfigArb = fc.record( - { baseSize: sizeArb, defaultSizeToMaxWhenMaxSpecified: fc.boolean() }, - { requiredKeys: [] }, +export const sizeForArbitraryArb: fc.Arbitrary = fc.constantFrom( + ...allSizeForArbitrary, ); +export const sizeRelatedGlobalConfigArb: fc.Arbitrary< + Partial<{ baseSize: Size; defaultSizeToMaxWhenMaxSpecified: boolean }> +> = fc.record({ baseSize: sizeArb, defaultSizeToMaxWhenMaxSpecified: fc.boolean() }, { requiredKeys: [] }); + // Type check that helpers are covering all the possibilities const failIfMissingSize: Size extends (typeof allSizeOrdered)[number] ? true : never = true; diff --git a/packages/fast-check/test/unit/check/model/commands/CommandsIterable.spec.ts b/packages/fast-check/test/unit/check/model/commands/CommandsIterable.spec.ts index b14925a47b3..3a12e8998ec 100644 --- a/packages/fast-check/test/unit/check/model/commands/CommandsIterable.spec.ts +++ b/packages/fast-check/test/unit/check/model/commands/CommandsIterable.spec.ts @@ -4,7 +4,7 @@ import * as fc from 'fast-check'; import { CommandWrapper } from '../../../../../src/check/model/commands/CommandWrapper'; import { CommandsIterable } from '../../../../../src/check/model/commands/CommandsIterable'; import type { Command } from '../../../../../src/check/model/command/Command'; -import { cloneMethod } from '../../../../../src/check/symbols'; +import { cloneMethod, hasCloneMethod } from '../../../../../src/check/symbols'; type Model = Record; type Real = unknown; @@ -38,6 +38,9 @@ describe('CommandsIterable', () => { fc.assert( fc.property(fc.array(fc.boolean()), (runFlags) => { const originalIterable = new CommandsIterable(buildAlreadyRanCommands(runFlags), () => ''); + if (!hasCloneMethod(originalIterable)) { + throw new Error(`Not cloaneable`); + } originalIterable[cloneMethod](); const commands = [...originalIterable]; for (let idx = 0; idx !== runFlags.length; ++idx) { @@ -48,7 +51,11 @@ describe('CommandsIterable', () => { it('Should reset hasRun flag for the clone on clone', () => fc.assert( fc.property(fc.array(fc.boolean()), (runFlags) => { - const commands = [...new CommandsIterable(buildAlreadyRanCommands(runFlags), () => '')[cloneMethod]()]; + const commandsIterable = new CommandsIterable(buildAlreadyRanCommands(runFlags), () => ''); + if (!hasCloneMethod(commandsIterable)) { + throw new Error(`Not cloaneable`); + } + const commands = [...commandsIterable[cloneMethod]()]; for (let idx = 0; idx !== runFlags.length; ++idx) { expect(commands[idx].hasRan).toBe(false); } diff --git a/packages/jest/package.json b/packages/jest/package.json index 4e72a95721c..5befac6d058 100644 --- a/packages/jest/package.json +++ b/packages/jest/package.json @@ -81,6 +81,7 @@ "jest": "^29.7.0", "jest-jasmine2": "^29.7.0", "typescript": "~5.7.3", + "vite": "^6.1.0", "vitest": "^2.1.9" }, "keywords": [ diff --git a/packages/jest/vitest.config.ts b/packages/jest/vitest.config.ts index f1673dbe922..0c672ebb0e0 100644 --- a/packages/jest/vitest.config.ts +++ b/packages/jest/vitest.config.ts @@ -1,11 +1,14 @@ +import type { UserConfig } from 'vite'; import { defineConfig } from 'vitest/config'; const major = Number(process.versions.node.split('.')[0]); -export default defineConfig({ +// @ts-expect-error - We will fix that one by bumping Vitest to v3 +const config: UserConfig = defineConfig({ test: { testTimeout: 60000, // 60s include: ['**/test/*.{test,spec}.?(c|m)[jt]s?(x)'], retry: major === 23 ? 5 : undefined, }, }); +export default config; diff --git a/packages/packaged/package.json b/packages/packaged/package.json index db99d107c59..ded732d6848 100644 --- a/packages/packaged/package.json +++ b/packages/packaged/package.json @@ -41,6 +41,7 @@ "@types/npm-packlist": "^7.0.3", "@types/npmcli__arborist": "^6.3.0", "typescript": "~5.7.3", + "vite": "^6.1.0", "vitest": "^2.1.9" }, "keywords": [], diff --git a/packages/packaged/vitest.config.ts b/packages/packaged/vitest.config.ts index 3a6fd784c78..504238436b1 100644 --- a/packages/packaged/vitest.config.ts +++ b/packages/packaged/vitest.config.ts @@ -1,7 +1,10 @@ +import type { UserConfig } from 'vite'; import { defineConfig } from 'vitest/config'; -export default defineConfig({ +// @ts-expect-error - We will fix that one by bumping Vitest to v3 +const config: UserConfig = defineConfig({ test: { include: ['**/test/*.{test,spec}.?(c|m)[jt]s?(x)'], }, }); +export default config; diff --git a/packages/vitest/vitest.config.ts b/packages/vitest/vitest.config.ts index f1673dbe922..0c672ebb0e0 100644 --- a/packages/vitest/vitest.config.ts +++ b/packages/vitest/vitest.config.ts @@ -1,11 +1,14 @@ +import type { UserConfig } from 'vite'; import { defineConfig } from 'vitest/config'; const major = Number(process.versions.node.split('.')[0]); -export default defineConfig({ +// @ts-expect-error - We will fix that one by bumping Vitest to v3 +const config: UserConfig = defineConfig({ test: { testTimeout: 60000, // 60s include: ['**/test/*.{test,spec}.?(c|m)[jt]s?(x)'], retry: major === 23 ? 5 : undefined, }, }); +export default config; diff --git a/tsconfig.common.json b/tsconfig.common.json index 7766a5f34e5..a0deb51b2f6 100644 --- a/tsconfig.common.json +++ b/tsconfig.common.json @@ -1,7 +1,8 @@ { "compilerOptions": { "noEmit": true, - "declaration": false, + "declaration": true, + "isolatedDeclarations": true, "incremental": false, "sourceMap": true, "target": "es2017", diff --git a/tsconfig.publish.json b/tsconfig.publish.json index 7abf8de509d..d2632ccb79d 100644 --- a/tsconfig.publish.json +++ b/tsconfig.publish.json @@ -3,6 +3,7 @@ "compilerOptions": { "noEmit": false, "declaration": false, + "isolatedDeclarations": false, "removeComments": true, "sourceMap": false } diff --git a/tsconfig.publish.types.json b/tsconfig.publish.types.json index abb33a7c0f6..4b2addcf4cd 100644 --- a/tsconfig.publish.types.json +++ b/tsconfig.publish.types.json @@ -4,6 +4,7 @@ "noEmit": false, "declaration": true, "emitDeclarationOnly": true, + "isolatedDeclarations": true, "removeComments": false, "sourceMap": false, "stripInternal": true diff --git a/website/docs/migration/from-3.x-to-4.x.md b/website/docs/migration/from-3.x-to-4.x.md index 279f3dd9b3b..4fbe4ac59af 100644 --- a/website/docs/migration/from-3.x-to-4.x.md +++ b/website/docs/migration/from-3.x-to-4.x.md @@ -449,3 +449,40 @@ stringify(Object.assign(Object.create(null), { a: 1 })); // '{__proto__:null,"a" This change is unlikely to impact most users. However, we are highlighting it for advanced users who might rely on custom reporting capabilities or stringifier behavior to meet specific needs. Related pull requests: [#5603](https://github.com/dubzzz/fast-check/pull/5603) + +### Remove certain Symbol-based typings for commands + +In previous versions, the typings for `CommandWrapper` included methods on the symbols `toStringMethod` and `asyncToStringMethod`. While these methods will still exist in JavaScript in v4, they will no longer be exposed in the TypeScript typings. As a result, the declared type will change as follows: + +```diff +export declare class CommandWrapper + implements ICommand +{ + readonly cmd: ICommand; +- [toStringMethod]?: () => string; +- [asyncToStringMethod]?: () => Promise; + hasRan: boolean; + constructor(cmd: ICommand); + check(m: Readonly): CheckAsync extends false ? boolean : Promise; + run(m: Model, r: Real): RunResult; + clone(): CommandWrapper; + toString(): string; +} +``` + +A similar change affects `CommandsIterable`, where the `cloneMethod` symbol will no longer be included in the typings: + +```diff +export declare class CommandsIterable + implements Iterable> +{ + readonly commands: CommandWrapper[]; + readonly metadataForReplay: () => string; + constructor(commands: CommandWrapper[], metadataForReplay: () => string); + [Symbol.iterator](): Iterator>; +- [cloneMethod](): CommandsIterable; + toString(): string; +} +``` + +Related pull requests: [#5136](https://github.com/dubzzz/fast-check/pull/5136) diff --git a/yarn.lock b/yarn.lock index e97ab79e5ec..63aac4d2388 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3670,6 +3670,7 @@ __metadata: jest: "npm:^29.7.0" jest-jasmine2: "npm:^29.7.0" typescript: "npm:~5.7.3" + vite: "npm:^6.1.0" vitest: "npm:^2.1.9" peerDependencies: "@fast-check/worker": ">=0.0.7 <0.5.0" @@ -3712,6 +3713,7 @@ __metadata: "@types/npmcli__arborist": "npm:^6.3.0" npm-packlist: "npm:^10.0.0" typescript: "npm:~5.7.3" + vite: "npm:^6.1.0" vitest: "npm:^2.1.9" bin: packaged: ./bin/packaged.js