Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vscode extension sometimes adds multiple annotations to machine #274

Open
viglucci opened this issue Dec 12, 2022 · 11 comments
Open

vscode extension sometimes adds multiple annotations to machine #274

viglucci opened this issue Dec 12, 2022 · 11 comments

Comments

@viglucci
Copy link

viglucci commented Dec 12, 2022

Description

The VSCode extension sometimes adds multiple annotations to a machine definition. I'm not entirely sure what behavior or steps I am taking that might be causing this to happen.

Each added annotation has different data and is a different length.

image

Environment

XState VSCode version: v1.11.0

@JoepKockelkorn
Copy link

I have this same issue, also not sure what causes this.

@Andarist
Copy link
Member

If you could come up with repro steps - that would be immensely helpful in fixing this.

@davidkpiano
Copy link
Member

I have a hunch that it has to do with the indentation of the first /** @xstate-layout which makes the extension fail to recognize that there is already a layout string? Wild guess though

@Andarist
Copy link
Member

I think that it's likely that you had some other error before this happened, something failed to sync properly and impacted future sync - causing the duplicate layout strings to be inserted.

@Andarist
Copy link
Member

@viglucci @JoepKockelkorn could you try the newest version of the VS Code extension? Does the problem persist?

@JoepKockelkorn
Copy link

I just tried on version v1.11.2 (xstate version 4.33.6) but eventually it still failed. What I did was the following:

  • click 'Open Visual Inspector'
  • the metadata comment was generated
  • drag some box a little
  • the metadata got updated successfully (🎉)
  • closed the visual inspector
  • reopened the visual inspector
  • added some new state somewhere
  • the metadata got updated, but the new state was not to be found in the state machine code (it should right?)
  • closed the inspector again
  • opened it again
  • removed the new state
  • a new metadata comment got created:

image

So there are actually two bugs happening at the same time:

  • new metadata comments get created somehow
  • the state machine doesn't get updated somehow

I see these errors coming by in the Extension Host logs:

2022-12-16 10:16:03.710 [error] Error: Request applyMachineEdits failed with message: Unexpected token, expected "," (35:6)
	at handleResponse (/Users/joepkockelkorn/.vscode/extensions/statelyai.stately-vscode-1.11.2/dist/index.js:329487:40)
	at processMessageQueue (/Users/joepkockelkorn/.vscode/extensions/statelyai.stately-vscode-1.11.2/dist/index.js:329325:13)
	at Immediate.<anonymous> (/Users/joepkockelkorn/.vscode/extensions/statelyai.stately-vscode-1.11.2/dist/index.js:329311:11)
	at process.processImmediate (node:internal/timers:466:21)
2022-12-16 10:16:06.592 [error] Error: Request applyMachineEdits failed with message: Could not find state
	at handleResponse (/Users/joepkockelkorn/.vscode/extensions/statelyai.stately-vscode-1.11.2/dist/index.js:329487:40)
	at processMessageQueue (/Users/joepkockelkorn/.vscode/extensions/statelyai.stately-vscode-1.11.2/dist/index.js:329325:13)
	at Immediate.<anonymous> (/Users/joepkockelkorn/.vscode/extensions/statelyai.stately-vscode-1.11.2/dist/index.js:329311:11)
	at process.processImmediate (node:internal/timers:466:21)
2022-12-16 10:16:21.168 [error] Error: Request applyMachineEdits failed with message: Unterminated string constant. (32:11)
	at handleResponse (/Users/joepkockelkorn/.vscode/extensions/statelyai.stately-vscode-1.11.2/dist/index.js:329487:40)
	at processMessageQueue (/Users/joepkockelkorn/.vscode/extensions/statelyai.stately-vscode-1.11.2/dist/index.js:329325:13)
	at Immediate.<anonymous> (/Users/joepkockelkorn/.vscode/extensions/statelyai.stately-vscode-1.11.2/dist/index.js:329311:11)
	at process.processImmediate (node:internal/timers:466:21)
2022-12-16 10:16:43.921 [error] Error: Request applyMachineEdits failed with message: Unexpected token, expected "," (35:6)
	at handleResponse (/Users/joepkockelkorn/.vscode/extensions/statelyai.stately-vscode-1.11.2/dist/index.js:329487:40)
	at processMessageQueue (/Users/joepkockelkorn/.vscode/extensions/statelyai.stately-vscode-1.11.2/dist/index.js:329325:13)
	at Immediate.<anonymous> (/Users/joepkockelkorn/.vscode/extensions/statelyai.stately-vscode-1.11.2/dist/index.js:329311:11)
	at process.processImmediate (node:internal/timers:466:21)

Here is my machine code (imports + typings omitted):

export const signUpMachine = createMachine({
	id: 'SignUp',
	tsTypes: {} as import('./sign-up.machine.typegen').Typegen0,
	initial: 'selectPriceplan',
	states: {
		registered: {
			entry: 'cleanLocalStorage',
			type: 'final',
			meta: { step: 4 },
		},
		checkingPaymentStatus: {
			after: {
				'60000': {
					target: 'checkPaymentFailed',
					actions: [],
					internal: false,
				},
			},
			initial: 'loading',
			states: {
				loading: {
					invoke: {
						src: 'checkStatus',
						onDone: [
							{
								target: '#SignUp.checkingRegistrationStatus',
								cond: 'paid',
								actions: ['saveStatus', 'resetRetryAttempts'],
							},
							{
								target: 'waiting',
								actions: 'incrementAttempts',
							},
						],
						onError: [
							{
								target: '#SignUp.workflowNotFound',
								cond: 'not found',
							},
							{
								target: '#SignUp.checkPaymentFailed',
							},
						],
					},
				},
				waiting: {
					after: {
						DELAY_WITH_BACKOFF: {
							target: '#SignUp.checkingPaymentStatus.loading',
							actions: [],
							internal: false,
						},
					},
				},
			},
			meta: { step: 4, loading: true },
		},
		checkPaymentFailed: {
			type: 'final',
			meta: { step: 4 },
		},
		loadingCheckoutUrl: {
			invoke: {
				src: 'loadCheckoutUrl',
				onDone: [
					{
						target: 'loadCheckoutUrlSuccess',
						actions: 'saveCheckoutUrl',
					},
				],
				onError: [
					{
						target: 'loadCheckoutUrlFailed',
					},
				],
			},
			meta: { step: 3, loading: true },
		},
		loadCheckoutUrlSuccess: {
			type: 'final',
			meta: { step: 3 },
		},
		loadCheckoutUrlFailed: {
			type: 'final',
			meta: { step: 3 },
		},
		enterUserRegistration: {
			description: "If existingUser then don't show password fields and terms.",
			always: {
				target: 'enterEmailCodes',
				cond: 'registrationRequested',
			},
			on: {
				'submit.userRegistration': {
					target: 'checkingUserRegistration',
					actions: 'storeEnteredPersonalDetails',
				},
			},
			meta: { step: 1 },
		},
		enterEmailCodes: {
			always: [
				{
					target: 'checkingRegistrationStatus',
					cond: 'emailAddressesVerified and (payment not required or paid)',
				},
				{
					target: 'checkingPaymentStatus',
					cond: 'emailAddressesVerified, paymentRequired and checkout done but not paid',
					actions: 'resetRetryAttempts',
				},
				{
					target: 'loadingCheckoutUrl',
					cond: 'emailAddressVerified, paymentRequired but not checkout done and not paid',
				},
			],
			on: {
				'submit.emailCodes': {
					target: 'checkingEmailCodes',
				},
			},
			meta: { step: 2 },
		},
		checkingEmailCodes: {
			invoke: {
				src: 'checkEmailCodes',
				onDone: [
					{
						target: 'enterEmailCodes',
						cond: 'codes invalid',
						actions: 'saveVerifyEmailCodeResponse',
					},
					{
						target: 'loadingCheckoutUrl',
						cond: 'payment required',
					},
					{
						target: 'checkingRegistrationStatus',
					},
				],
				onError: [
					{
						target: 'enterEmailCodes',
						actions: 'showErrorInDialog',
					},
				],
			},
			meta: { step: 2, loading: true },
		},
		checkingUserRegistration: {
			invoke: {
				src: 'checkUserRegistration',
				onDone: [
					{
						target: 'enterEmailCodes',
						actions: 'storeRegisterCustomerResponse',
					},
				],
				onError: [
					{
						target: 'enterUserRegistration',
						actions: 'showErrorInDialog',
					},
				],
			},
			meta: { step: 1, loading: true },
		},
		selectPriceplan: {
			always: [
				{
					target: 'enterUserRegistration',
					cond: 'priceplan selected',
				},
				{
					target: 'enterUserRegistration',
					cond: 'only one free priceplan available',
					actions: 'preselectPriceplan',
				},
			],
			on: {
				'select.pricePlan': {
					target: 'enterUserRegistration',
					actions: 'storePriceplan',
				},
			},
		},
		checkingRegistrationStatus: {
			after: {
				'60000': {
					target: 'checkRegistrationFailed',
					actions: [],
					internal: false,
				},
			},
			initial: 'loading',
			states: {
				loading: {
					invoke: {
						src: 'checkStatus',
						onDone: [
							{
								target: 'waiting',
								actions: ['saveStatus', 'incrementAttempts'],
							},
						],
						onError: [
							{
								target: '#SignUp.workflowNotFound',
								cond: 'not found',
							},
							{
								target: '#SignUp.checkRegistrationFailed',
							},
						],
					},
				},
				waiting: {
					after: {
						DELAY_WITH_BACKOFF: {
							target: '#SignUp.checkingRegistrationStatus.loading',
							actions: [],
							internal: false,
						},
					},
				},
			},
			meta: { step: 4, loading: true },
		},
		checkRegistrationFailed: {
			type: 'final',
			meta: { step: 4 },
		},
		workflowNotFound: {
			entry: ['cleanLocalStorage', 'redirectToSignUpOops'],
			type: 'final',
		},
	},
	always: [
		{
			target: 'registered',
			cond: 'registered',
		},
	],
	schema: {
		context: {} as SignUpContext,
		events: {} as
			| { type: 'startPayment' }
			| { type: 'submit.emailCodes'; request: VerifyEmailCodeRequest }
			| { type: 'submit.userRegistration'; request: RegisterCustomerRequest }
			| { type: 'select.pricePlan'; price: Price },
		services: {} as {
			checkStatus: { data: CheckStatusResponse };
			checkUserRegistration: { data: RegisterCustomerResponse };
			checkEmailCodes: { data: VerifyEmailCodeResponse };
			loadCheckoutUrl: { data: GetCheckoutUrlResponse };
		},
	},
	context: { checkoutComplete: false },
	predictableActionArguments: true,
	preserveActionOrder: true,
});

@Andarist
Copy link
Member

@JoepKockelkorn thank you for all of this detail! However, I fail to reproduce this with the given steps. The state is being added correctly - maybe it depends on where we add it (?). I'm also a little bit confused by one of the last steps in which you remove a new state. If you added a new state, it didn't pop up in the code, and then if you reopened the Visual Editor... there should be a new state there (since it didn't get synced to the code before).

@JoepKockelkorn
Copy link

Yes, indeed the new state was only in the visual, not in the code. So that's where I removed it. As soon as I removed it, the second metadata comment was created. The way I added the new state was double clicking anywhere in the machine. So there wasn't any way to get in that state, but it should have been created anyway, right?

But I think it doesn't matter what change I make to the machine, it fails in updating the machine right away. This is using the exact same machine code as above:

bug

@andrejpavlovic
Copy link

andrejpavlovic commented Jan 4, 2023

This happens pretty frequently for me. The larger and more complicated the state gets, the more likely that some change will cause a duplication of @xstate-layout issue. If I don't notice it right away, any changes I make to the layout will essentially not be saved. I've started using the VS Code extension a few days ago, and I'd say I encounter this issue constantly - every 10-15 minutes, across various statecharts while working on them.

Some error messages I've seen outputted from the extension that cause this issue:

2023-01-04 15:21:28.077 [error] Error: Request applyMachineEdits failed with message: Array element was not an object expression
	at handleResponse (c:\Users\Andrej\.vscode\extensions\statelyai.stately-vscode-1.11.3\dist\index.js:329487:40)
	at processMessageQueue (c:\Users\Andrej\.vscode\extensions\statelyai.stately-vscode-1.11.3\dist\index.js:329325:13)
	at Immediate.<anonymous> (c:\Users\Andrej\.vscode\extensions\statelyai.stately-vscode-1.11.3\dist\index.js:329311:11)
	at process.processImmediate (node:internal/timers:466:21)
2023-01-04 15:23:19.401 [error] Error: Request applyMachineEdits failed with message: Unexpected token, expected "," (37:1)
	at handleResponse (c:\Users\Andrej\.vscode\extensions\statelyai.stately-vscode-1.11.3\dist\index.js:329487:40)
	at processMessageQueue (c:\Users\Andrej\.vscode\extensions\statelyai.stately-vscode-1.11.3\dist\index.js:329325:13)
	at Immediate.<anonymous> (c:\Users\Andrej\.vscode\extensions\statelyai.stately-vscode-1.11.3\dist\index.js:329311:11)
	at process.processImmediate (node:internal/timers:466:21)
2023-01-04 15:23:19.449 [error] Error: Request applyMachineEdits failed with message: Changing transition path requires the transitionPath ([on, asd, 0]) to exist on the source state ([s2])
	at handleResponse (c:\Users\Andrej\.vscode\extensions\statelyai.stately-vscode-1.11.3\dist\index.js:329487:40)
	at processMessageQueue (c:\Users\Andrej\.vscode\extensions\statelyai.stately-vscode-1.11.3\dist\index.js:329325:13)
	at Immediate.<anonymous> (c:\Users\Andrej\.vscode\extensions\statelyai.stately-vscode-1.11.3\dist\index.js:329311:11)
	at process.processImmediate (node:internal/timers:466:21)

@rjchow
Copy link

rjchow commented Jan 9, 2023

Similarly I have issues with the editor syncing, to the point where it makes it untenable for me to introduce xstate to my team.

If there's an error with syncing, the editor should fail fast and obvious so the user does not continue inputting work that cannot be recovered.

@davidkpiano
Copy link
Member

Similarly I have issues with the editor syncing, to the point where it makes it untenable for me to introduce xstate to my team.

If there's an error with syncing, the editor should fail fast and obvious so the user does not continue inputting work that cannot be recovered.

Thanks for the feedback, I agree. We're prioritizing the syncing issues with the extension (not the easiest problem to solve 😅)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants