From 4de1d2f004390395412b3372f0decf677ca6931e Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Lievremont Date: Fri, 20 Sep 2024 15:17:50 +0200 Subject: [PATCH 1/3] SLLS-263 Adopt INFO and BLOCKER impact severity levels --- pom.xml | 2 +- .../ls/clientapi/SonarLintVSCodeClient.java | 5 +- .../sonarlint/ls/util/EnumLabelsMapper.java | 2 + .../clientapi/SonarLintVSCodeClientTests.java | 3 +- .../ls/util/EnumLabelsMapperTests.java | 114 ++++++++++-------- 5 files changed, 75 insertions(+), 51 deletions(-) diff --git a/pom.xml b/pom.xml index 446ff2266..717205ece 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ 17 - 10.5.0.78949 + 10.6.0.79033 1.6.10 diff --git a/src/main/java/org/sonarsource/sonarlint/ls/clientapi/SonarLintVSCodeClient.java b/src/main/java/org/sonarsource/sonarlint/ls/clientapi/SonarLintVSCodeClient.java index eab50366b..9a34cfb5b 100644 --- a/src/main/java/org/sonarsource/sonarlint/ls/clientapi/SonarLintVSCodeClient.java +++ b/src/main/java/org/sonarsource/sonarlint/ls/clientapi/SonarLintVSCodeClient.java @@ -64,6 +64,7 @@ import org.sonarsource.sonarlint.core.rpc.protocol.backend.tracking.TaintVulnerabilityDto; import org.sonarsource.sonarlint.core.rpc.protocol.client.binding.AssistBindingParams; import org.sonarsource.sonarlint.core.rpc.protocol.client.binding.AssistBindingResponse; +import org.sonarsource.sonarlint.core.rpc.protocol.client.binding.NoBindingSuggestionFoundParams; import org.sonarsource.sonarlint.core.rpc.protocol.client.binding.SuggestBindingParams; import org.sonarsource.sonarlint.core.rpc.protocol.client.connection.AssistCreatingConnectionParams; import org.sonarsource.sonarlint.core.rpc.protocol.client.connection.AssistCreatingConnectionResponse; @@ -311,9 +312,9 @@ public AssistBindingResponse assistBinding(AssistBindingParams params, SonarLint } @Override - public void noBindingSuggestionFound(String projectKey) { + public void noBindingSuggestionFound(NoBindingSuggestionFoundParams params) { var messageRequestParams = new ShowMessageRequestParams(); - messageRequestParams.setMessage("SonarLint couldn't match the server project '" + projectKey + "' to any of the currently " + + messageRequestParams.setMessage("SonarLint couldn't match the server project '" + params.getProjectKey() + "' to any of the currently " + "open workspace folders. Please make sure the project is open in the workspace, or try configuring the binding manually."); messageRequestParams.setType(MessageType.Error); var learnMoreAction = new MessageActionItem("Learn more"); diff --git a/src/main/java/org/sonarsource/sonarlint/ls/util/EnumLabelsMapper.java b/src/main/java/org/sonarsource/sonarlint/ls/util/EnumLabelsMapper.java index a7eaa4c2f..928a2f73c 100644 --- a/src/main/java/org/sonarsource/sonarlint/ls/util/EnumLabelsMapper.java +++ b/src/main/java/org/sonarsource/sonarlint/ls/util/EnumLabelsMapper.java @@ -91,9 +91,11 @@ public static String softwareQualityToLabel(SoftwareQuality softwareQuality) { public static String impactSeverityToLabel(ImpactSeverity softwareQuality) { return switch (softwareQuality) { + case INFO -> "Info"; case LOW -> "Low"; case MEDIUM -> "Medium"; case HIGH -> "High"; + case BLOCKER -> "Blocker"; }; } diff --git a/src/test/java/org/sonarsource/sonarlint/ls/clientapi/SonarLintVSCodeClientTests.java b/src/test/java/org/sonarsource/sonarlint/ls/clientapi/SonarLintVSCodeClientTests.java index 898baebef..f59faf886 100644 --- a/src/test/java/org/sonarsource/sonarlint/ls/clientapi/SonarLintVSCodeClientTests.java +++ b/src/test/java/org/sonarsource/sonarlint/ls/clientapi/SonarLintVSCodeClientTests.java @@ -67,6 +67,7 @@ import org.sonarsource.sonarlint.core.rpc.protocol.backend.tracking.TextRangeWithHashDto; import org.sonarsource.sonarlint.core.rpc.protocol.client.OpenUrlInBrowserParams; import org.sonarsource.sonarlint.core.rpc.protocol.client.binding.AssistBindingParams; +import org.sonarsource.sonarlint.core.rpc.protocol.client.binding.NoBindingSuggestionFoundParams; import org.sonarsource.sonarlint.core.rpc.protocol.client.binding.SuggestBindingParams; import org.sonarsource.sonarlint.core.rpc.protocol.client.connection.AssistCreatingConnectionParams; import org.sonarsource.sonarlint.core.rpc.protocol.client.connection.ConnectionSuggestionDto; @@ -533,7 +534,7 @@ void testNoBindingSuggestionFound() { var learnMoreAction = new MessageActionItem("Learn more"); messageRequestParams.setActions(List.of(learnMoreAction)); - underTest.noBindingSuggestionFound(projectKey); + underTest.noBindingSuggestionFound(new NoBindingSuggestionFoundParams(projectKey, false)); verify(client).showMessageRequest(messageRequestParams); verify(client).browseTo("https://docs.sonarsource.com/sonarlint/vs-code/troubleshooting/#troubleshooting-connected-mode-setup"); } diff --git a/src/test/java/org/sonarsource/sonarlint/ls/util/EnumLabelsMapperTests.java b/src/test/java/org/sonarsource/sonarlint/ls/util/EnumLabelsMapperTests.java index 976f2fe15..60292b803 100644 --- a/src/test/java/org/sonarsource/sonarlint/ls/util/EnumLabelsMapperTests.java +++ b/src/test/java/org/sonarsource/sonarlint/ls/util/EnumLabelsMapperTests.java @@ -19,72 +19,92 @@ */ package org.sonarsource.sonarlint.ls.util; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; import org.sonarsource.sonarlint.core.rpc.protocol.backend.issue.ResolutionStatus; import org.sonarsource.sonarlint.core.rpc.protocol.common.CleanCodeAttribute; import org.sonarsource.sonarlint.core.rpc.protocol.common.CleanCodeAttributeCategory; import org.sonarsource.sonarlint.core.rpc.protocol.common.ImpactSeverity; import org.sonarsource.sonarlint.core.rpc.protocol.common.SoftwareQuality; -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; class EnumLabelsMapperTests { - @Test - void resolutionStatusToLabel() { - assertThat(EnumLabelsMapper.resolutionStatusToLabel(ResolutionStatus.ACCEPT)).isEqualTo("Accepted"); - assertThat(EnumLabelsMapper.resolutionStatusToLabel(ResolutionStatus.FALSE_POSITIVE)).isEqualTo("False positive"); - assertThat(EnumLabelsMapper.resolutionStatusToLabel(ResolutionStatus.WONT_FIX)).isEqualTo("Won't fix"); + @ParameterizedTest(name = "ResolutionStatus.{0} is mapped to `{1}`") + @CsvSource({ + "ACCEPT , Accepted", + "FALSE_POSITIVE, False positive", + "WONT_FIX , Won't fix", + }) + void resolutionStatusToLabel(String enumName, String expectedLabel) { + assertThat(EnumLabelsMapper.resolutionStatusToLabel(ResolutionStatus.valueOf(enumName))).isEqualTo(expectedLabel); } - @Test - void resolutionStatusFromLabel() { - assertThat(EnumLabelsMapper.resolutionStatusFromLabel("Accepted")).isEqualTo(ResolutionStatus.ACCEPT); - assertThat(EnumLabelsMapper.resolutionStatusFromLabel("False positive")).isEqualTo(ResolutionStatus.FALSE_POSITIVE); - assertThat(EnumLabelsMapper.resolutionStatusFromLabel("Won't fix")).isEqualTo(ResolutionStatus.WONT_FIX); - assertThrows(IllegalArgumentException.class, () -> EnumLabelsMapper.resolutionStatusFromLabel("Unknown")); + @ParameterizedTest(name = "Label `{0}` is mapped to ResolutionStatus.{1}") + @CsvSource({ + "Accepted , ACCEPT", + "False positive, FALSE_POSITIVE", + "Won't fix , WONT_FIX", + }) + void resolutionStatusFromLabel(String label, String expectedEnumValue) { + assertThat(EnumLabelsMapper.resolutionStatusFromLabel(label)).isEqualTo(ResolutionStatus.valueOf(expectedEnumValue)); + assertThatThrownBy(() -> EnumLabelsMapper.resolutionStatusFromLabel("Unknown")).isInstanceOf(IllegalArgumentException.class); } - @Test - void cleanCodeAttributeToLabel() { - assertEquals("Not conventional", EnumLabelsMapper.cleanCodeAttributeToLabel(CleanCodeAttribute.CONVENTIONAL)); - assertEquals("Not formatted", EnumLabelsMapper.cleanCodeAttributeToLabel(CleanCodeAttribute.FORMATTED)); - assertEquals("Not identifiable", EnumLabelsMapper.cleanCodeAttributeToLabel(CleanCodeAttribute.IDENTIFIABLE)); - assertEquals("Not clear", EnumLabelsMapper.cleanCodeAttributeToLabel(CleanCodeAttribute.CLEAR)); - assertEquals("Not complete", EnumLabelsMapper.cleanCodeAttributeToLabel(CleanCodeAttribute.COMPLETE)); - assertEquals("Not efficient", EnumLabelsMapper.cleanCodeAttributeToLabel(CleanCodeAttribute.EFFICIENT)); - assertEquals("Not logical", EnumLabelsMapper.cleanCodeAttributeToLabel(CleanCodeAttribute.LOGICAL)); - assertEquals("Not distinct", EnumLabelsMapper.cleanCodeAttributeToLabel(CleanCodeAttribute.DISTINCT)); - assertEquals("Not focused", EnumLabelsMapper.cleanCodeAttributeToLabel(CleanCodeAttribute.FOCUSED)); - assertEquals("Not modular", EnumLabelsMapper.cleanCodeAttributeToLabel(CleanCodeAttribute.MODULAR)); - assertEquals("Not tested", EnumLabelsMapper.cleanCodeAttributeToLabel(CleanCodeAttribute.TESTED)); - assertEquals("Not lawful", EnumLabelsMapper.cleanCodeAttributeToLabel(CleanCodeAttribute.LAWFUL)); - assertEquals("Not respectful", EnumLabelsMapper.cleanCodeAttributeToLabel(CleanCodeAttribute.RESPECTFUL)); - assertEquals("Not trustworthy", EnumLabelsMapper.cleanCodeAttributeToLabel(CleanCodeAttribute.TRUSTWORTHY)); + @ParameterizedTest(name = "CleanCodeAttribute.{0} is mapped to `{1}`") + @CsvSource({ + "CONVENTIONAL, Not conventional", + "FORMATTED , Not formatted", + "IDENTIFIABLE, Not identifiable", + "CLEAR , Not clear", + "COMPLETE , Not complete", + "EFFICIENT , Not efficient", + "LOGICAL , Not logical", + "DISTINCT , Not distinct", + "FOCUSED , Not focused", + "MODULAR , Not modular", + "TESTED , Not tested", + "LAWFUL , Not lawful", + "RESPECTFUL , Not respectful", + "TRUSTWORTHY , Not trustworthy" + }) + void cleanCodeAttributeToLabel(String enumName, String expectedLabel) { + assertThat(EnumLabelsMapper.cleanCodeAttributeToLabel(CleanCodeAttribute.valueOf(enumName))).isEqualTo(expectedLabel); } - @Test - void testCleanCodeAttributeCategoryToLabel() { - assertEquals("Adaptability", EnumLabelsMapper.cleanCodeAttributeCategoryToLabel(CleanCodeAttributeCategory.ADAPTABLE)); - assertEquals("Consistency", EnumLabelsMapper.cleanCodeAttributeCategoryToLabel(CleanCodeAttributeCategory.CONSISTENT)); - assertEquals("Intentionality", EnumLabelsMapper.cleanCodeAttributeCategoryToLabel(CleanCodeAttributeCategory.INTENTIONAL)); - assertEquals("Responsibility", EnumLabelsMapper.cleanCodeAttributeCategoryToLabel(CleanCodeAttributeCategory.RESPONSIBLE)); + @ParameterizedTest(name = "CleanCodeAttributeCategory.{0} is mapped to `{1}`") + @CsvSource({ + "ADAPTABLE , Adaptability", + "CONSISTENT , Consistency", + "INTENTIONAL, Intentionality", + "RESPONSIBLE, Responsibility" + }) + void testCleanCodeAttributeCategoryToLabel(String enumName, String expectedLabel) { + assertThat(EnumLabelsMapper.cleanCodeAttributeCategoryToLabel(CleanCodeAttributeCategory.valueOf(enumName))).isEqualTo(expectedLabel); } - @Test - void testSoftwareQualityToLabel() { - assertEquals("Maintainability", EnumLabelsMapper.softwareQualityToLabel(SoftwareQuality.MAINTAINABILITY)); - assertEquals("Reliability", EnumLabelsMapper.softwareQualityToLabel(SoftwareQuality.RELIABILITY)); - assertEquals("Security", EnumLabelsMapper.softwareQualityToLabel(SoftwareQuality.SECURITY)); + @ParameterizedTest(name = "SoftwareQuality.{0} is mapped to `{1}`") + @CsvSource({ + "MAINTAINABILITY, Maintainability", + "RELIABILITY , Reliability", + "SECURITY , Security" + }) + void testSoftwareQualityToLabel(String enumName, String expectedLabel) { + assertThat(EnumLabelsMapper.softwareQualityToLabel(SoftwareQuality.valueOf(enumName))).isEqualTo(expectedLabel); } - @Test - void testImpactSeverityToLabel() { - assertEquals("Low", EnumLabelsMapper.impactSeverityToLabel(ImpactSeverity.LOW)); - assertEquals("Medium", EnumLabelsMapper.impactSeverityToLabel(ImpactSeverity.MEDIUM)); - assertEquals("High", EnumLabelsMapper.impactSeverityToLabel(ImpactSeverity.HIGH)); + @ParameterizedTest(name = "ImpactSeverity.{0} is mapped to `{1}`") + @CsvSource({ + "INFO , Info", + "LOW , Low", + "MEDIUM , Medium", + "HIGH , High", + "BLOCKER, Blocker", + }) + void testImpactSeverityToLabel(String enumName, String expectedLabel) { + assertThat(EnumLabelsMapper.impactSeverityToLabel(ImpactSeverity.valueOf(enumName))).isEqualTo(expectedLabel); } } From 1419811d137ca9d955e9fb9bf9e495ad8ba750c1 Mon Sep 17 00:00:00 2001 From: Sophio Japharidze Date: Thu, 19 Sep 2024 16:15:48 +0200 Subject: [PATCH 2/3] SLLS-265 fix Jupyter document line indexing --- .../sonarlint/ls/AnalysisHelper.java | 8 +++- .../ls/notebooks/VersionedOpenNotebook.java | 4 -- .../notebooks/VersionedOpenNotebookTests.java | 38 +++++++++++++++++++ 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/sonarsource/sonarlint/ls/AnalysisHelper.java b/src/main/java/org/sonarsource/sonarlint/ls/AnalysisHelper.java index 2ad91601b..9de3954de 100644 --- a/src/main/java/org/sonarsource/sonarlint/ls/AnalysisHelper.java +++ b/src/main/java/org/sonarsource/sonarlint/ls/AnalysisHelper.java @@ -102,8 +102,12 @@ public void handleIssues(Map> issuesByFileUri) { issuesCache.reportIssues(issuesByFileUri); issuesByFileUri.forEach((uri, issues) -> { diagnosticPublisher.publishDiagnostics(uri, true); - notebookDiagnosticPublisher.cleanupDiagnosticsForCellsWithoutIssues(uri); - openNotebooksCache.getFile(uri).ifPresent(notebook -> notebookDiagnosticPublisher.publishNotebookDiagnostics(uri, notebook)); + openNotebooksCache.getFile(uri).ifPresent(notebook -> { + // clean up old diagnostics + notebookDiagnosticPublisher.cleanupCellsList(uri); + notebookDiagnosticPublisher.cleanupDiagnosticsForCellsWithoutIssues(uri); + notebookDiagnosticPublisher.publishNotebookDiagnostics(uri, notebook); + }); }); } diff --git a/src/main/java/org/sonarsource/sonarlint/ls/notebooks/VersionedOpenNotebook.java b/src/main/java/org/sonarsource/sonarlint/ls/notebooks/VersionedOpenNotebook.java index 5b297214e..ad9a48ac9 100644 --- a/src/main/java/org/sonarsource/sonarlint/ls/notebooks/VersionedOpenNotebook.java +++ b/src/main/java/org/sonarsource/sonarlint/ls/notebooks/VersionedOpenNotebook.java @@ -69,9 +69,6 @@ private VersionedOpenNotebook(URI uri, int version, List cells } private void indexCellsByLineNumber() { - if (notebookVersion.equals(indexedNotebookVersion)) { - return; - } var lineCount = 1; var cellCount = 1; for (var cell : orderedCells) { @@ -117,7 +114,6 @@ public Set getCellUris() { } public Optional getCellUri(int lineNumber) { - indexCellsByLineNumber(); return Optional.ofNullable(fileLineToCell.get(lineNumber)) .map(TextDocumentItem::getUri) .map(URI::create); diff --git a/src/test/java/org/sonarsource/sonarlint/ls/notebooks/VersionedOpenNotebookTests.java b/src/test/java/org/sonarsource/sonarlint/ls/notebooks/VersionedOpenNotebookTests.java index ec1283d87..4db035205 100644 --- a/src/test/java/org/sonarsource/sonarlint/ls/notebooks/VersionedOpenNotebookTests.java +++ b/src/test/java/org/sonarsource/sonarlint/ls/notebooks/VersionedOpenNotebookTests.java @@ -20,8 +20,10 @@ package org.sonarsource.sonarlint.ls.notebooks; import java.net.URI; +import java.time.Instant; import java.util.Collections; import java.util.List; +import java.util.UUID; import javax.annotation.Nullable; import org.eclipse.lsp4j.NotebookCellArrayChange; import org.eclipse.lsp4j.NotebookDocumentChangeEvent; @@ -40,10 +42,14 @@ import org.sonarsource.sonarlint.core.rpc.protocol.client.issue.IssueFlowDto; import org.sonarsource.sonarlint.core.rpc.protocol.client.issue.QuickFixDto; import org.sonarsource.sonarlint.core.rpc.protocol.client.issue.RaisedFindingDto; +import org.sonarsource.sonarlint.core.rpc.protocol.client.issue.RaisedIssueDto; import org.sonarsource.sonarlint.core.rpc.protocol.client.issue.TextEditDto; +import org.sonarsource.sonarlint.core.rpc.protocol.common.CleanCodeAttribute; import org.sonarsource.sonarlint.core.rpc.protocol.common.IssueSeverity; +import org.sonarsource.sonarlint.core.rpc.protocol.common.RuleType; import org.sonarsource.sonarlint.core.rpc.protocol.common.TextRangeDto; import org.sonarsource.sonarlint.ls.connected.DelegatingFinding; +import org.sonarsource.sonarlint.ls.connected.DelegatingIssue; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -110,6 +116,8 @@ void shouldCorrectlyMapFileLineToCellLine() { var tmpUri = URI.create("file:///some/notebook.ipynb"); var underTest = createTestNotebookWithThreeCells(tmpUri); + manuallyReindexCellLines(underTest); + assertThat(underTest.getCellUri(1)).contains(URI.create(tmpUri + "#cell1")); assertThat(underTest.getCellUri(2)).contains(URI.create(tmpUri + "#cell1")); assertThat(underTest.getCellUri(3)).contains(URI.create(tmpUri + "#cell1")); @@ -173,6 +181,8 @@ void shouldConvertQuickFixWithSingleFileEdit() { var fakeNotebook = createTestNotebookWithThreeCells(tmpUri); var quickFixTextRange = new TextRangeDto(9, 0, 9, 2); + manuallyReindexCellLines(fakeNotebook); + var textEdit = mock(TextEditDto.class); when(textEdit.newText()).thenReturn(""); when(textEdit.range()).thenReturn(quickFixTextRange); @@ -211,6 +221,8 @@ void shouldConvertQuickFixWithMultipleFileEdits() { var quickFixTextRange1 = new TextRangeDto(9, 0, 9, 2); var quickFixTextRange2 = new TextRangeDto(5, 0, 6, 2); + manuallyReindexCellLines(fakeNotebook); + var textEdit1 = mock(org.sonarsource.sonarlint.core.rpc.protocol.client.issue.TextEditDto.class); when(textEdit1.newText()).thenReturn(""); when(textEdit1.range()).thenReturn(quickFixTextRange1); @@ -308,6 +320,8 @@ void shouldHandleCellCreation() { underTest.didChange(2, changeEvent); + manuallyReindexCellLines(underTest); + assertThat(underTest.getNotebookVersion()).isEqualTo(2); assertThat(underTest.getCellUris()).hasSize(4); assertThat(underTest.getContent()).isEqualTo("" + @@ -350,6 +364,8 @@ void shouldHandleCellDeletion() { underTest.didChange(2, changeEvent); + manuallyReindexCellLines(underTest); + assertThat(underTest.getNotebookVersion()).isEqualTo(2); assertThat(underTest.getCellUris()).hasSize(2); assertThat(underTest.getContent()).isEqualTo("" + @@ -382,6 +398,7 @@ void shouldNotFailWhenRemovingNonexistentCell() { changeEvent.setCells(changeEventCells); underTest.didChange(2, changeEvent); + manuallyReindexCellLines(underTest); assertThat(underTest.getNotebookVersion()).isEqualTo(2); assertThat(underTest.getCellUris()).hasSize(3); @@ -494,4 +511,25 @@ public static VersionedOpenNotebook createTestNotebookWithThreeCells(URI tmpUri) return VersionedOpenNotebook.create(tmpUri, 1, List.of(cell1, cell2, cell3), mock(NotebookDiagnosticPublisher.class)); } + private void manuallyReindexCellLines(VersionedOpenNotebook underTest) { + var fakeFindingDto = new RaisedIssueDto( + UUID.randomUUID(), + null, + "ruleKey", + "message", + IssueSeverity.BLOCKER, + RuleType.BUG, + CleanCodeAttribute.TRUSTWORTHY, + List.of(), + Instant.now(), + true, + false, + new TextRangeDto(1, 0, 1, 0), + List.of(), + List.of(), + null + ); + underTest.toCellIssue(new DelegatingIssue(fakeFindingDto, URI.create(""))); + } + } From b97371202a8bf368a978f5ef18fb33c8939705f2 Mon Sep 17 00:00:00 2001 From: Sophio Japharidze Date: Mon, 23 Sep 2024 11:36:54 +0200 Subject: [PATCH 3/3] SLLS-265 fix QG --- .../sonarlint/ls/notebooks/VersionedOpenNotebook.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/org/sonarsource/sonarlint/ls/notebooks/VersionedOpenNotebook.java b/src/main/java/org/sonarsource/sonarlint/ls/notebooks/VersionedOpenNotebook.java index ad9a48ac9..211b41337 100644 --- a/src/main/java/org/sonarsource/sonarlint/ls/notebooks/VersionedOpenNotebook.java +++ b/src/main/java/org/sonarsource/sonarlint/ls/notebooks/VersionedOpenNotebook.java @@ -51,7 +51,6 @@ public class VersionedOpenNotebook { private final URI uri; private Integer notebookVersion; - private Integer indexedNotebookVersion; private final LinkedHashMap cells = new LinkedHashMap<>(); private final List orderedCells = new ArrayList<>(); private final Map fileLineToCell = new HashMap<>(); @@ -85,7 +84,6 @@ private void indexCellsByLineNumber() { } cellCount++; } - indexedNotebookVersion = notebookVersion; } public static VersionedOpenNotebook create(URI baseUri, int version, List cells, NotebookDiagnosticPublisher notebookDiagnosticPublisher) {