Repository: mermaid-js/mermaid
File: packages/mermaid/src/diagrams/git/gitGraphAst.js (JavaScript)

Code before:
      'Incorrect usage of "cherryPick". Source commit id should exist and provided'
    );
    error.hash = {
      text: 'cherryPick ' + sourceId + ' ' + targetId,
      token: 'cherryPick ' + sourceId + ' ' + targetId,
      line: '1',
      loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
      expected: ['cherry-pick abc'],
    };
    throw error;
  }
  let sourceCommit = commits[sourceId];
  let sourceCommitBranch = sourceCommit.branch;
  if (sourceCommit.type === commitType.MERGE) {
    if (!parentCommitId) {
      let error = new Error(
        'Incorrect usage of cherry-pick: If the source commit is a merge commit, an immediate parent commit must be specified.'
      );
      throw error;
    }
    if (!(Array.isArray(sourceCommit.parents) && sourceCommit.parents.includes(parentCommitId))) {
      let error = new Error(
        'Invalid operation: The specified parent commit is not an immediate parent of the cherry-picked commit.'
      );
      throw error;
    }
  }
  if (!targetId || commits[targetId] === undefined) {
    // cherry-pick source commit to current branch

    if (sourceCommitBranch === curBranch) {
      let error = new Error(
        'Incorrect usage of "cherryPick". Source commit is already on current branch'
      );
      error.hash = {
        text: 'cherryPick ' + sourceId + ' ' + targetId,
        token: 'cherryPick ' + sourceId + ' ' + targetId,
        line: '1',
        loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
        expected: ['cherry-pick abc'],
      };
      throw error;
    }
    const currentCommit = commits[branches[curBranch]];
    if (currentCommit === undefined || !currentCommit) {
      let error = new Error(
        'Incorrect usage of "cherry-pick". Current branch (' + curBranch + ')has no commits'
      );
      error.hash = {
        text: 'cherryPick ' + sourceId + ' ' + targetId,
        token: 'cherryPick ' + sourceId + ' ' + targetId,

Review comment (refactor):
One potential change (although we could do this in another PR, since I know this PR has been open for a while). Should we move this check outside of the `if (sourceCommit.type === commitType.MERGE) {` condition?

```suggestion
  }
  if (parentCommitId && !(Array.isArray(sourceCommit.parents) && sourceCommit.parents.includes(parentCommitId))) {
    let error = new Error(
      'Invalid operation: The specified parent commit is not an immediate parent of the cherry-picked commit.'
    );
    throw error;
```

Currently, if we use a bad `parent: "xxx"` field for a cherry-pick that **doesn't target a MERGE**, there's no error, e.g. the following diagram renders correctly without any errors:

````markdown
```mermaid
gitGraph
    commit id: "ZERO"
    branch feature
    branch release
    checkout feature
    commit id: "A"
    commit id: "Not a merge commit"
    checkout main
    merge feature id: "M"
    checkout release
    cherry-pick id: "Not a merge commit" parent: "this-parent-does-not-exist"
```
````



Code after:
      'Incorrect usage of "cherryPick". Source commit id should exist and provided'
    );
    error.hash = {
      text: 'cherryPick ' + sourceId + ' ' + targetId,
      token: 'cherryPick ' + sourceId + ' ' + targetId,
      line: '1',
      loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
      expected: ['cherry-pick abc'],
    };
    throw error;
  }
  let sourceCommit = commits[sourceId];
  let sourceCommitBranch = sourceCommit.branch;
  if (
    parentCommitId &&
    !(Array.isArray(sourceCommit.parents) && sourceCommit.parents.includes(parentCommitId))
  ) {
    let error = new Error(
      'Invalid operation: The specified parent commit is not an immediate parent of the cherry-picked commit.'
    );
    throw error;
  }
  if (sourceCommit.type === commitType.MERGE && !parentCommitId) {
    let error = new Error(
      'Incorrect usage of cherry-pick: If the source commit is a merge commit, an immediate parent commit must be specified.'
    );
    throw error;
  }
  if (!targetId || commits[targetId] === undefined) {
    // cherry-pick source commit to current branch

    if (sourceCommitBranch === curBranch) {
      let error = new Error(
        'Incorrect usage of "cherryPick". Source commit is already on current branch'
      );
      error.hash = {
        text: 'cherryPick ' + sourceId + ' ' + targetId,
        token: 'cherryPick ' + sourceId + ' ' + targetId,
        line: '1',
        loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
        expected: ['cherry-pick abc'],
      };
      throw error;
    }
    const currentCommit = commits[branches[curBranch]];
    if (currentCommit === undefined || !currentCommit) {
      let error = new Error(
        'Incorrect usage of "cherry-pick". Current branch (' + curBranch + ')has no commits'
      );
      error.hash = {
        text: 'cherryPick ' + sourceId + ' ' + targetId,