diff --git a/.changeset/blue-glasses-love.md b/.changeset/blue-glasses-love.md new file mode 100644 index 00000000..2c2afe30 --- /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 de9e3fce..075af835 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 6d2bad22..18732096 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 c5e418af..ca7467a0 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 d859e07b..cef31d06 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 a4b855b4..6b6df54d 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 eaeaec3e..9321cf95 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 f2a8b47f..72c583a3 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 b9287e8a..0407ae04 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 ec00902c..6ecdcb4f 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 b14925a4..3a12e899 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 4e72a957..5befac6d 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 f1673dbe..0c672ebb 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 db99d107..ded732d6 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 3a6fd784..50423843 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 f1673dbe..0c672ebb 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 7766a5f3..a0deb51b 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 7abf8de5..d2632ccb 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 abb33a7c..4b2addcf 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 279f3dd9..4fbe4ac5 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 e97ab79e..63aac4d2 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