diff --git a/docs/contributing/test-case-recorder.md b/docs/contributing/test-case-recorder.md index 282f29f728..5641f23a74 100644 --- a/docs/contributing/test-case-recorder.md +++ b/docs/contributing/test-case-recorder.md @@ -78,11 +78,11 @@ and can be run in vscode or via yarn in terminal. ### Autoformatting -To clean up the formatting of all of the yaml test cases, run `yarn run compile && node ./out/scripts/transformRecordedTests/index.js` +To clean up the formatting of all of the yaml test cases, run `yarn compile && yarn transform-recorded-tests` ### Upgrading fixtures -To upgrade all the test fixtures to the latest command version, run the command `yarn run compile && node ./out/scripts/transformRecordedTests/index.js upgrade`. This command should be idempotent. +To upgrade all the test fixtures to the latest command version, run the command `yarn compile && yarn transform-recorded-tests upgrade`. This command should be idempotent. ### Custom transformation @@ -90,7 +90,7 @@ To upgrade all the test fixtures to the latest command version, run the command 1. Change the value at the `custom` key in `AVAILABLE_TRANSFORMATIONS` at the top of [`transformRecordedTests/index.ts`](../../src/scripts/transformRecordedTests/index.ts) to point to your new transformation -1. Run `yarn run compile && node ./out/scripts/transformRecordedTests/index.js custom` +1. Run `yarn compile && yarn transform-recorded-tests custom` Example of a custom transformation diff --git a/package.json b/package.json index cb235e4da3..6771ecbaaf 100644 --- a/package.json +++ b/package.json @@ -732,7 +732,8 @@ "test": "env CURSORLESS_TEST=true node ./out/test/scripts/runTestsCI.js", "unused-exports": "ts-unused-exports tsconfig.json --showLineNumber", "init-launch-sandbox": "node ./out/scripts/initLaunchSandbox.js", - "prepare-for-extension-publish": "node ./out/scripts/prepareForExtensionPublish.js" + "prepare-for-extension-publish": "node ./out/scripts/prepareForExtensionPublish.js", + "transform-recorded-tests": "node ./out/scripts/transformRecordedTests/index.js" }, "devDependencies": { "@types/chai": "^4.3.3", diff --git a/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts index bca747a9e3..e5d7ad82be 100644 --- a/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts +++ b/src/core/commandVersionUpgrades/canonicalizeAndValidateCommand.ts @@ -1,5 +1,6 @@ import { ActionType } from "../../actions/actions.types"; import { OutdatedExtensionError } from "../../errors"; +import { EnforceUndefined } from "../../libs/common/util/typeUtils"; import ide from "../../libs/cursorless-engine/singletons/ide.singleton"; import { Modifier, @@ -29,14 +30,13 @@ import { upgradeV2ToV3 } from "./upgradeV2ToV3"; */ export function canonicalizeAndValidateCommand( command: Command, -): CommandComplete { +): EnforceUndefined { const commandUpgraded = upgradeCommand(command); const { action, targets: inputPartialTargets, usePrePhraseSnapshot = false, - version, - ...rest + spokenForm, } = commandUpgraded; const actionName = canonicalizeActionName(action.name); @@ -45,8 +45,8 @@ export function canonicalizeAndValidateCommand( validateCommand(actionName, partialTargets); return { - ...rest, version: LATEST_VERSION, + spokenForm, action: { name: actionName, args: action.args ?? [], diff --git a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts index 9430205f90..cece3773bd 100644 --- a/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts +++ b/src/core/commandVersionUpgrades/upgradeV1ToV2/upgradeV1ToV2.ts @@ -150,10 +150,10 @@ function upgradePrimitiveTarget( return { type, isImplicit, - // Cursor token is just cursor position but treated as a token. This is done in the pipeline for normal cursor now - mark: mark?.type === "cursorToken" ? undefined : mark, // Empty array of modifiers is not allowed modifiers: modifiers.length > 0 ? modifiers : undefined, + // Cursor token is just cursor position but treated as a token. This is done in the pipeline for normal cursor now + mark: mark?.type === "cursorToken" ? undefined : mark, }; } diff --git a/src/libs/common/util/typeUtils.ts b/src/libs/common/util/typeUtils.ts new file mode 100644 index 0000000000..c2ea20cd12 --- /dev/null +++ b/src/libs/common/util/typeUtils.ts @@ -0,0 +1,19 @@ +type GetOptional = { + [K in keyof T as Pick extends Required> ? never : K]: T[K]; +}; + +type GetRequired = { + [K in keyof T as Pick extends Required> ? K : never]: T[K]; +}; + +type UnionUndefined = { + [K in keyof T]: T[K] | undefined; +}; + +/** + * Use this type to convert all optional keys in an interface to required undefined unions. + * Useful for passthrough objects that need manual extending + * { opt?: boolean; } => { opt: boolean | undefined; } + */ +export type EnforceUndefined = GetRequired & + UnionUndefined>>; diff --git a/src/scripts/transformRecordedTests/index.ts b/src/scripts/transformRecordedTests/index.ts index ee2823f4d0..fcf5aa186d 100644 --- a/src/scripts/transformRecordedTests/index.ts +++ b/src/scripts/transformRecordedTests/index.ts @@ -1,3 +1,6 @@ +// Ensures that the aliases such as @cursorless/common that we define in +// package.json are active +import "module-alias/register"; import { getRecordedTestPaths } from "../../apps/cursorless-vscode-e2e/getFixturePaths"; import { identity } from "./transformations/identity"; import { upgrade } from "./transformations/upgrade"; diff --git a/src/scripts/transformRecordedTests/transformations/reorderFields.ts b/src/scripts/transformRecordedTests/transformations/reorderFields.ts index 4c6555b362..abd546b5e2 100644 --- a/src/scripts/transformRecordedTests/transformations/reorderFields.ts +++ b/src/scripts/transformRecordedTests/transformations/reorderFields.ts @@ -1,13 +1,21 @@ +import { EnforceUndefined } from "../../../libs/common/util/typeUtils"; import { TestCaseFixture } from "../../../testUtil/TestCaseFixture"; -export function reorderFields(fixture: TestCaseFixture) { +export function reorderFields( + fixture: TestCaseFixture, +): EnforceUndefined { return { languageId: fixture.languageId, command: fixture.command, marksToCheck: fixture.marksToCheck, initialState: fixture.initialState, finalState: fixture.finalState, + decorations: fixture.decorations, returnValue: fixture.returnValue, + thrownError: fixture.thrownError, + ide: fixture.ide, + postEditorOpenSleepTimeMs: fixture.postEditorOpenSleepTimeMs, + postCommandSleepTimeMs: fixture.postCommandSleepTimeMs, fullTargets: fixture.fullTargets, }; } diff --git a/src/testUtil/TestCase.ts b/src/testUtil/TestCase.ts index b15477b63a..5ceb1d371b 100644 --- a/src/testUtil/TestCase.ts +++ b/src/testUtil/TestCase.ts @@ -163,9 +163,9 @@ export class TestCase { finalState: this.finalState, decorations: this.decorations, returnValue: this.returnValue, - fullTargets: this.fullTargets, thrownError: this.thrownError, ide: this.spyIdeValues, + fullTargets: this.fullTargets, }; return serialize(fixture); } diff --git a/src/testUtil/cleanUpTestCaseCommand.ts b/src/testUtil/cleanUpTestCaseCommand.ts index 61b7ff5b10..babab7d364 100644 --- a/src/testUtil/cleanUpTestCaseCommand.ts +++ b/src/testUtil/cleanUpTestCaseCommand.ts @@ -1,16 +1,13 @@ import { TestCaseCommand } from "./TestCaseFixture"; +import { merge } from "lodash"; export function cleanUpTestCaseCommand( command: TestCaseCommand, ): TestCaseCommand { - const { action, ...rest } = command; - const { args } = action; - - return { - ...rest, - action: { - ...action, - args: args == null ? undefined : args.length === 0 ? undefined : args, - }, - }; + const { args } = command.action; + const result = merge({}, command); + if (args == null || args.length === 0) { + result.action.args = undefined; + } + return result; }