Skip to content

Commit

Permalink
Implement basic invoke editing
Browse files Browse the repository at this point in the history
  • Loading branch information
Andarist committed Mar 11, 2024
1 parent b3318cd commit 4a0969e
Show file tree
Hide file tree
Showing 4 changed files with 446 additions and 36 deletions.
308 changes: 308 additions & 0 deletions new-packages/ts-project/__tests__/source-edits/edit-invoke.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,308 @@
import { expect, test } from 'vitest';
import { createTestProject, testdir, ts } from '../utils';

test(`should be possible to update invoke's source`, 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: 'edit_invoke',
path: [],
invokeIndex: 0,
source: 'callAn(d)e(r)s',
},
);
expect(await project.applyTextEdits(textEdits)).toMatchInlineSnapshot(`
{
"index.ts": "import { createMachine } from "xstate";
createMachine({
invoke: {
src: "callAn(d)e(r)s",
},
});",
}
`);
});

test(`should be possible to add an ID to the existing invoke`, 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: 'edit_invoke',
path: [],
invokeIndex: 0,
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 update invoke's ID`, async () => {
const tmpPath = await testdir({
'tsconfig.json': JSON.stringify({}),
'index.ts': ts`
import { createMachine } from "xstate";
createMachine({
invoke: {
src: "callDavid",
id: "importantCall",
},
});
`,
});

const project = await createTestProject(tmpPath);

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

test(`should be possible to update invoke's source and ID at the same time`, async () => {
const tmpPath = await testdir({
'tsconfig.json': JSON.stringify({}),
'index.ts': ts`
import { createMachine } from "xstate";
createMachine({
invoke: {
src: "callDavid",
id: "importantCall",
},
});
`,
});

const project = await createTestProject(tmpPath);

const textEdits = project.editDigraph(
{
fileName: 'index.ts',
machineIndex: 0,
},
{
type: 'edit_invoke',
path: [],
invokeIndex: 0,
source: 'callAn(d)e(r)s',
id: 'veryImportantCall',
},
);
expect(await project.applyTextEdits(textEdits)).toMatchInlineSnapshot(`
{
"index.ts": "import { createMachine } from "xstate";
createMachine({
invoke: {
src: "callAn(d)e(r)s",
id: "veryImportantCall",
},
});",
}
`);
});

test(`should be possible to remove invoke's ID`, async () => {
const tmpPath = await testdir({
'tsconfig.json': JSON.stringify({}),
'index.ts': ts`
import { createMachine } from "xstate";
createMachine({
invoke: {
src: "callDavid",
id: "importantCall",
},
});
`,
});

const project = await createTestProject(tmpPath);

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

test(`should remove all \`id\` props when removing invoke's ID`, async () => {
const tmpPath = await testdir({
'tsconfig.json': JSON.stringify({}),
'index.ts': ts`
import { createMachine } from "xstate";
createMachine({
invoke: {
src: "callDavid",
id: "importantCall",
id: "veryImportantCall",
},
});
`,
});

const project = await createTestProject(tmpPath);

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

test(`should be possible to update nth invoke's source`, async () => {
const tmpPath = await testdir({
'tsconfig.json': JSON.stringify({}),
'index.ts': ts`
import { createMachine } from "xstate";
createMachine({
invoke: [
{
src: "callDavid",
},
{
src: "callAnders",
},
],
});
`,
});

const project = await createTestProject(tmpPath);

const textEdits = project.editDigraph(
{
fileName: 'index.ts',
machineIndex: 0,
},
{
type: 'edit_invoke',
path: [],
invokeIndex: 1,
source: 'callAn(d)e(r)s',
},
);
expect(await project.applyTextEdits(textEdits)).toMatchInlineSnapshot(`
{
"index.ts": "import { createMachine } from "xstate";
createMachine({
invoke: [
{
src: "callDavid",
},
{
src: "callAn(d)e(r)s",
},
],
});",
}
`);
});
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 @@ -592,8 +592,25 @@ function produceNewDigraphUsingEdit(
break;
}
case 'remove_invoke':
case 'edit_invoke':
throw new Error(`Not implemented: ${edit.type}`);
case 'edit_invoke': {
const node = findNodeByStatePath(digraphDraft, edit.path);
const blockId = node.data.invoke[edit.invokeIndex];
const block = digraphDraft.blocks[blockId];
if (edit.source) {
block.sourceId = edit.source;
digraphDraft.implementations.actors[edit.source] ??= {
type: 'actor',
id: edit.source,
name: edit.source,
};
}
if ('id' in edit) {
assert(block.blockType === 'actor');
block.properties.id = edit.id ?? '';
}
break;
}
case 'set_description': {
const node = findNodeByStatePath(digraphDraft, edit.statePath);
if (edit.transitionPath) {
Expand Down
29 changes: 19 additions & 10 deletions new-packages/ts-project/src/codeChanges.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
findLast,
findProperty,
first,
getPropertyKey,
last,
} from './utils';

Expand Down Expand Up @@ -407,16 +408,24 @@ export function createCodeChanges(ts: typeof import('typescript')) {
priority,
});
},
removeProperty: (property: PropertyAssignment) => {
changes.push({
type: 'remove_property',
sourceFile: property.getSourceFile(),
range: {
start: property.getStart(),
end: property.getEnd(),
},
property,
});
removeObjectProperty: (object: ObjectLiteralExpression, name: string) => {
for (const property of object.properties) {
if (
!ts.isPropertyAssignment(property) ||
getPropertyKey(undefined, ts, property) !== name
) {
continue;
}
changes.push({
type: 'remove_property',
sourceFile: property.getSourceFile(),
range: {
start: property.getStart(),
end: property.getEnd(),
},
property,
});
}
},
replacePropertyName: (property: PropertyAssignment, name: string) => {
changes.push({
Expand Down
Loading

0 comments on commit 4a0969e

Please sign in to comment.