Skip to content

Commit

Permalink
handle actions edits in transitions
Browse files Browse the repository at this point in the history
  • Loading branch information
Andarist committed Mar 11, 2024
1 parent 914b920 commit 1596fb5
Show file tree
Hide file tree
Showing 2 changed files with 269 additions and 95 deletions.
322 changes: 227 additions & 95 deletions new-packages/ts-project/__tests__/source-edits/edit-action.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,115 +305,247 @@ test('should be possible to update object exit action name in an array', async (
`);
});

test.todo(
'should be possible to update a single transition action name',
async () => {
const tmpPath = await testdir({
'tsconfig.json': JSON.stringify({}),
'index.ts': ts`
import { createMachine } from "xstate";
createMachine({
on: {
CALL_HIM_MAYBE: {
actions: "callDavid",
},
test('should be possible to update a single transition action name', async () => {
const tmpPath = await testdir({
'tsconfig.json': JSON.stringify({}),
'index.ts': ts`
import { createMachine } from "xstate";
createMachine({
on: {
CALL_HIM_MAYBE: {
actions: "callDavid",
},
});
`,
});
},
});
`,
});

const project = await createTestProject(tmpPath);
const project = await createTestProject(tmpPath);

const textEdits = project.editDigraph(
{
fileName: 'index.ts',
machineIndex: 0,
const textEdits = project.editDigraph(
{
fileName: 'index.ts',
machineIndex: 0,
},
{
type: 'edit_action',
path: [],
actionPath: ['on', 'CALL_HIM_MAYBE', 0, 0],
name: 'getRaise',
},
);
expect(await project.applyTextEdits(textEdits)).toMatchInlineSnapshot(`
{
"index.ts": "import { createMachine } from "xstate";
createMachine({
on: {
CALL_HIM_MAYBE: {
actions: "getRaise",
},
},
{
type: 'edit_action',
path: [],
actionPath: ['on', 'CALL_HIM_MAYBE', 0, 0],
name: 'getRaise',
});",
}
`);
});

test('should be possible to update a single transition object action name', async () => {
const tmpPath = await testdir({
'tsconfig.json': JSON.stringify({}),
'index.ts': ts`
import { createMachine } from "xstate";
createMachine({
on: {
CALL_HIM_MAYBE: {
actions: { type: "callDavid" },
},
},
});
`,
});

const project = await createTestProject(tmpPath);

const textEdits = project.editDigraph(
{
fileName: 'index.ts',
machineIndex: 0,
},
{
type: 'edit_action',
path: [],
actionPath: ['on', 'CALL_HIM_MAYBE', 0, 0],
name: 'getRaise',
},
);
expect(await project.applyTextEdits(textEdits)).toMatchInlineSnapshot(`
{
"index.ts": "import { createMachine } from "xstate";
createMachine({
on: {
CALL_HIM_MAYBE: {
actions: { type: "getRaise" },
},
},
);
expect(await project.applyTextEdits(textEdits)).toMatchInlineSnapshot();
},
);

test.todo(
'should be possible to update a single transition object action name',
async () => {
const tmpPath = await testdir({
'tsconfig.json': JSON.stringify({}),
'index.ts': ts`
import { createMachine } from "xstate";
createMachine({
on: {
CALL_HIM_MAYBE: {
actions: { type: "callDavid" },
});",
}
`);
});

test('should be possible to update an action name within the nth guarded transition', async () => {
const tmpPath = await testdir({
'tsconfig.json': JSON.stringify({}),
'index.ts': ts`
import { createMachine } from "xstate";
createMachine({
on: {
CALL_HIM_MAYBE: [
{
guard: "isItTooLate",
},
},
});
`,
});
{
actions: "callDavid",
},
],
},
});
`,
});

const project = await createTestProject(tmpPath);
const project = await createTestProject(tmpPath);

const textEdits = project.editDigraph(
{
fileName: 'index.ts',
machineIndex: 0,
},
{
type: 'edit_action',
path: [],
actionPath: ['on', 'CALL_HIM_MAYBE', 1, 0],
name: 'getRaise',
},
);
expect(await project.applyTextEdits(textEdits)).toMatchInlineSnapshot(`
{
"index.ts": "import { createMachine } from "xstate";
const textEdits = project.editDigraph(
{
fileName: 'index.ts',
machineIndex: 0,
createMachine({
on: {
CALL_HIM_MAYBE: [
{
guard: "isItTooLate",
},
{
actions: "getRaise",
},
],
},
{
type: 'edit_action',
path: [],
actionPath: ['on', 'CALL_HIM_MAYBE', 0, 0],
name: 'getRaise',
});",
}
`);
});

test('should be possible to update a transition action name in an array', async () => {
const tmpPath = await testdir({
'tsconfig.json': JSON.stringify({}),
'index.ts': ts`
import { createMachine } from "xstate";
createMachine({
on: {
CALL_HIM_MAYBE: {
actions: ["callDavid", "keepTheJob"],
},
},
});
`,
});

const project = await createTestProject(tmpPath);

const textEdits = project.editDigraph(
{
fileName: 'index.ts',
machineIndex: 0,
},
{
type: 'edit_action',
path: [],
actionPath: ['on', 'CALL_HIM_MAYBE', 0, 1],
name: 'getRaise',
},
);
expect(await project.applyTextEdits(textEdits)).toMatchInlineSnapshot(`
{
"index.ts": "import { createMachine } from "xstate";
createMachine({
on: {
CALL_HIM_MAYBE: {
actions: ["callDavid", "getRaise"],
},
},
);
expect(await project.applyTextEdits(textEdits)).toMatchInlineSnapshot();
},
);

test.todo(
'should be possible to update an action name within the nth guarded transition',
async () => {
const tmpPath = await testdir({
'tsconfig.json': JSON.stringify({}),
'index.ts': ts`
import { createMachine } from "xstate";
createMachine({
on: {
CALL_HIM_MAYBE: [
{
guard: "isItTooLate",
},
});",
}
`);
});

test('should be possible to update an object transition action name in an array', async () => {
const tmpPath = await testdir({
'tsconfig.json': JSON.stringify({}),
'index.ts': ts`
import { createMachine } from "xstate";
createMachine({
on: {
CALL_HIM_MAYBE: {
actions: [
"callDavid",
{
actions: "callDavid",
type: "keepTheJob",
},
],
},
});
`,
});
},
});
`,
});

const project = await createTestProject(tmpPath);
const project = await createTestProject(tmpPath);

const textEdits = project.editDigraph(
{
fileName: 'index.ts',
machineIndex: 0,
},
{
type: 'edit_action',
path: [],
actionPath: ['on', 'CALL_HIM_MAYBE', 1, 0],
name: 'getRaise',
const textEdits = project.editDigraph(
{
fileName: 'index.ts',
machineIndex: 0,
},
{
type: 'edit_action',
path: [],
actionPath: ['on', 'CALL_HIM_MAYBE', 0, 1],
name: 'getRaise',
},
);
expect(await project.applyTextEdits(textEdits)).toMatchInlineSnapshot(`
{
"index.ts": "import { createMachine } from "xstate";
createMachine({
on: {
CALL_HIM_MAYBE: {
actions: [
"callDavid",
{
type: "getRaise",
},
],
},
},
);
expect(await project.applyTextEdits(textEdits)).toMatchInlineSnapshot();
},
);
});",
}
`);
});
42 changes: 42 additions & 0 deletions new-packages/ts-project/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -833,6 +833,48 @@ function createProjectMachine({
// there is no way to know where to look for this parent
// so if it wasn't a node we try to find it in the edges
const edge = currentState.digraph!.edges[block.parentId];
const transitionNode = findNodeByAstPath(
host.ts,
createMachineCall,
currentState.astPaths.edges[edge.uniqueId],
);
assert(host.ts.isObjectLiteralExpression(transitionNode));

const actionIndex = edge.data.actions.indexOf(blockId);

const actionsProperty = findProperty(
undefined,
host.ts,
transitionNode,
'actions',
);
assert(!!actionsProperty);

if (
host.ts.isArrayLiteralExpression(
actionsProperty.initializer,
)
) {
const element =
actionsProperty.initializer.elements[actionIndex];
assert(!!element);

updateParameterizedObjectLocation(
host.ts,
codeChanges,
element,
block.sourceId,
);
break;
}
assert(actionIndex === 0);

updateParameterizedObjectLocation(
host.ts,
codeChanges,
actionsProperty.initializer,
block.sourceId,
);
break;
}
const stateNode = findNodeByAstPath(
Expand Down

0 comments on commit 1596fb5

Please sign in to comment.