Repository: storybookjs/storybook
File: code/core/src/preview-api/modules/preview-web/render/mount-utils.test.ts (TypeScript)

Code before:
const TranspiledDefinition = {
  play: async (context: any) => {
    const {
      mount,
      veryLongTranspiledDefinitionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn,
      over,
      multiple,
      lines,
    } = context;
    await mount();
  },
};

const LateDestructuring = {
  play: async (a: any) => {
    console.log(a);
    const {
      mount,
      veryLongTranspiledDefinitionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn,
      over,
      multiple,
      lines,
    } = a;
    await mount();
  },
};

test('Detect basic destructuring', () => {
  expect(getUsedProps(StoryWithContext.play)).toMatchInlineSnapshot(`[]`);
  expect(getUsedProps(StoryWitCanvasElement.play)).toMatchInlineSnapshot(`
    [
      "canvasElement",
    ]
  `);
  expect(getUsedProps(MountStory.play)).toMatchInlineSnapshot(`
    [
      "mount",
    ]
  `);
});

test('Detect multiline destructuring', () => {
  expect(getUsedProps(LongDefinition.play)).toMatchInlineSnapshot(`
    [
      "mount",
      "veryLongDefinitionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn",
      "over",
      "multiple",
      "lines",
    ]
  `);

Review comment (bug):
Hopefully I'm understanding the code correctly, if not my comment might not make sense:

You're testing a 2 happy paths of your code:
- the old methodology, where de-structure happens in the function arguments
- the new, where de-structuring happens on the first line, I suppose this is what SWC outputs when the `bugfixes` is turned off?

Then you test a single "non-happy" path, by adding a `console.log`-call above the de-structure, and your test correctly shows, it's not detected.

There are cases possible where the code can get "confused", and get triggered in an happy path incorrectly, or potentially crash?

Here are some scenarios, that would be worth having a test for:
```
// I'd expect this to return ['mount']
play: async (context: any) => {
  const {
    mount, // a comment
  } = context;
  await mount();
},

// No trailing comma! I'd expect this to still return ['mount']
play: async (context: any) => {
  const {
    mount // a comment
  } = context;
  await mount();
},

// I'd expect this to return ['mount']
play: async (context: any) => {
  const {
    // a comment
    mount,
  } = context;
  await mount();
},

// I'd expect this to return [], even though "mount" is destructured, it's not from the context
play: async (context: any) => {
  const { mount } = await import('unrelated-module');
  const {
    mount: sbMount,
  } = context;
  await sbMount();
},

// I'm unsure what to expect, but the preferred return is ['mount']
play: async (context: any) => {
  const {
    mount: sbMount,
  } = context;
  await sbMount();
},
```

I don't know if these would work correctly with the implementation, 
I understand that there's only so much we can do with a stringified fn and regexp.

Perhaps we should add a bit more resilience to more failure cases, and I suggest adding a try-catch block around `getUsedProps`. That is unless any thrown errors would already be handled further up the code chain, which I'm not too familiar with. 

Code after:
const TranspiledDefinition = {
  play: async (context: any) => {
    const {
      mount,
      veryLongTranspiledDefinitionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn,
      over,
      multiple,
      lines,
    } = context;
    await mount();
  },
};

const LateDestructuring = {
  play: async (a: any) => {
    console.log(a);
    const {
      mount,
      veryLongTranspiledDefinitionnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn,
      over,
      multiple,
      lines,
    } = a;
    await mount();
  },
};

const WithComment = {
  play: async (context: any) => {
    const {
      // a comment
      mount,
    } = context;
    await mount();
  },
};

const WithTrailingComment = {
  play: async (context: any) => {
    const {
      mount, // a comment
    } = context;
    await mount();
  },
};

const WithMultipleComments = {
  play: async (context: any) => {
    const {
      mount, // a comment
      // another comment