Skip to content

Commit

Permalink
Implement invoke insertions (#483)
Browse files Browse the repository at this point in the history
  • Loading branch information
Andarist authored Mar 11, 2024
1 parent 90c2218 commit a4c5608
Show file tree
Hide file tree
Showing 4 changed files with 448 additions and 16 deletions.
336 changes: 336 additions & 0 deletions new-packages/ts-project/__tests__/source-edits/add-invoke.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,336 @@
import { expect, test } from 'vitest';
import { createTestProject, testdir, ts } from '../utils';

test('should be possible to add an invoke to the root', async () => {
const tmpPath = await testdir({
'tsconfig.json': JSON.stringify({}),
'index.ts': ts`
import { createMachine } from "xstate";
createMachine({});
`,
});

const project = await createTestProject(tmpPath);

const textEdits = project.editDigraph(
{
fileName: 'index.ts',
machineIndex: 0,
},
{
type: 'add_invoke',
path: [],
invokeIndex: 0,
source: 'callDavid',
},
);
expect(await project.applyTextEdits(textEdits)).toMatchInlineSnapshot(`
{
"index.ts": "import { createMachine } from "xstate";
createMachine({
invoke: {
src: "callDavid"
}
});",
}
`);
});

test('should be possible to add an invoke to a nested state', async () => {
const tmpPath = await testdir({
'tsconfig.json': JSON.stringify({}),
'index.ts': ts`
import { createMachine } from "xstate";
createMachine({
on: {
FOO: "a",
},
states: {
a: {},
},
});
`,
});

const project = await createTestProject(tmpPath);

const textEdits = project.editDigraph(
{
fileName: 'index.ts',
machineIndex: 0,
},
{
type: 'add_invoke',
path: ['a'],
invokeIndex: 0,
source: 'callDavid',
},
);
expect(await project.applyTextEdits(textEdits)).toMatchInlineSnapshot(`
{
"index.ts": "import { createMachine } from "xstate";
createMachine({
on: {
FOO: "a",
},
states: {
a: {
invoke: {
src: "callDavid"
}
},
},
});",
}
`);
});

test('should be possible to add an invoke with an ID', async () => {
const tmpPath = await testdir({
'tsconfig.json': JSON.stringify({}),
'index.ts': ts`
import { createMachine } from "xstate";
createMachine({});
`,
});

const project = await createTestProject(tmpPath);

const textEdits = project.editDigraph(
{
fileName: 'index.ts',
machineIndex: 0,
},
{
type: 'add_invoke',
path: [],
invokeIndex: 0,
source: 'callDavid',
id: 'importantCall',
},
);
expect(await project.applyTextEdits(textEdits)).toMatchInlineSnapshot(`
{
"index.ts": "import { createMachine } from "xstate";
createMachine({
invoke: {
src: "callDavid",
id: "importantCall"
}
});",
}
`);
});

test('should be possible to add a new invoke to an existing invoke property', async () => {
const tmpPath = await testdir({
'tsconfig.json': JSON.stringify({}),
'index.ts': ts`
import { createMachine } from "xstate";
createMachine({
invoke: {
src: "callDavid",
},
});
`,
});

const project = await createTestProject(tmpPath);

const textEdits = project.editDigraph(
{
fileName: 'index.ts',
machineIndex: 0,
},
{
type: 'add_invoke',
path: [],
invokeIndex: 1,
source: 'getRaise',
},
);
expect(await project.applyTextEdits(textEdits)).toMatchInlineSnapshot(`
{
"index.ts": "import { createMachine } from "xstate";
createMachine({
invoke: [ {
src: "callDavid",
},
{
src: "getRaise"
}
],
});",
}
`);
});

test('should be possible to add a new invoke at the start of the existing invoke list', async () => {
const tmpPath = await testdir({
'tsconfig.json': JSON.stringify({}),
'index.ts': ts`
import { createMachine } from "xstate";
createMachine({
invoke: [
{
src: "miny",
},
{
src: "moe",
},
],
});
`,
});

const project = await createTestProject(tmpPath);

const textEdits = project.editDigraph(
{
fileName: 'index.ts',
machineIndex: 0,
},
{
type: 'add_invoke',
path: [],
invokeIndex: 0,
source: 'eeny',
},
);
expect(await project.applyTextEdits(textEdits)).toMatchInlineSnapshot(`
{
"index.ts": "import { createMachine } from "xstate";
createMachine({
invoke: [
{
src: "eeny"
},
{
src: "miny",
},
{
src: "moe",
},
],
});",
}
`);
});

test('should be possible to add a new invoke in the middle of the existing invoke list', async () => {
const tmpPath = await testdir({
'tsconfig.json': JSON.stringify({}),
'index.ts': ts`
import { createMachine } from "xstate";
createMachine({
invoke: [
{
src: "eeny",
},
{
src: "moe",
},
],
});
`,
});

const project = await createTestProject(tmpPath);

const textEdits = project.editDigraph(
{
fileName: 'index.ts',
machineIndex: 0,
},
{
type: 'add_invoke',
path: [],
invokeIndex: 1,
source: 'miny',
},
);
expect(await project.applyTextEdits(textEdits)).toMatchInlineSnapshot(`
{
"index.ts": "import { createMachine } from "xstate";
createMachine({
invoke: [
{
src: "eeny",
},
{
src: "miny"
},
{
src: "moe",
},
],
});",
}
`);
});

test('should be possible to add a new invoke at the end of the existing invoke list', async () => {
const tmpPath = await testdir({
'tsconfig.json': JSON.stringify({}),
'index.ts': ts`
import { createMachine } from "xstate";
createMachine({
invoke: [
{
src: "eeny",
},
{
src: "miny",
},
],
});
`,
});

const project = await createTestProject(tmpPath);

const textEdits = project.editDigraph(
{
fileName: 'index.ts',
machineIndex: 0,
},
{
type: 'add_invoke',
path: [],
invokeIndex: 2,
source: 'moe',
},
);
expect(await project.applyTextEdits(textEdits)).toMatchInlineSnapshot(`
{
"index.ts": "import { createMachine } from "xstate";
createMachine({
invoke: [
{
src: "eeny",
},
{
src: "miny",
},
{
src: "moe"
},
],
});",
}
`);
});
19 changes: 18 additions & 1 deletion new-packages/ts-project/__tests__/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ import {
} from '../src/index';
import {
createActionBlock,
createActorBlock,
createGuardBlock,
registerActionBlocks,
registerActorBlocks,
registerGuardBlock,
} from '../src/state';
import {
Expand Down Expand Up @@ -520,7 +522,22 @@ function produceNewDigraphUsingEdit(
}
case 'remove_guard':
case 'edit_guard':
case 'add_invoke':
throw new Error(`Not implemented: ${edit.type}`);
case 'add_invoke': {
const node = findNodeByStatePath(digraphDraft, edit.path);
const block = createActorBlock({
sourceId: edit.source,
parentId: node.uniqueId,
actorId: edit.id ?? `inline:${uniqueId()}:invocation`,
});
registerActorBlocks(
digraphDraft,
[block],
node.data.invoke,
edit.invokeIndex,
);
break;
}
case 'remove_invoke':
case 'edit_invoke':
throw new Error(`Not implemented: ${edit.type}`);
Expand Down
Loading

0 comments on commit a4c5608

Please sign in to comment.