@neo4j-cypher/react-codemirror
Advanced tools
Comparing version 2.0.0-canary-dcbe67d to 2.0.0-canary-dd41bf6
# @neo4j-cypher/react-codemirror | ||
## 2.0.0-next.14 | ||
### Patch Changes | ||
- d85c1e0: Fixes bug with auto-completions | ||
- Updated dependencies [bccf518] | ||
- @neo4j-cypher/language-support@2.0.0-next.11 | ||
## 2.0.0-next.13 | ||
### Patch Changes | ||
- Updated dependencies [8760c02] | ||
- @neo4j-cypher/language-support@2.0.0-next.10 | ||
## 2.0.0-next.12 | ||
### Patch Changes | ||
- dcbe67d: Expose moveFocusOnTab property on the CypherEditor component to conditionally disable tab keymappings | ||
- e9621c8: Re-export language support from react codemirror | ||
- Updated dependencies [2e72ac8] | ||
- @neo4j-cypher/language-support@2.0.0-next.9 | ||
## 2.0.0-next.11 | ||
@@ -4,0 +28,0 @@ |
import { jsx as _jsx } from "react/jsx-runtime"; | ||
/* eslint-disable @typescript-eslint/unbound-method */ | ||
import { testData } from '@neo4j-cypher/language-support'; | ||
@@ -69,2 +70,14 @@ import { expect, test } from '@playwright/experimental-ct-react'; | ||
}); | ||
test('can complete properties with backticks', async ({ mount, page }) => { | ||
const component = await mount(_jsx(CypherEditor, { schema: { | ||
propertyKeys: ['foo bar'], | ||
} })); | ||
const textField = page.getByRole('textbox'); | ||
await textField.fill('MATCH (n) RETURN n.foo'); | ||
await textField.press('Escape'); | ||
await textField.press('Control+ '); | ||
await page.locator('.cm-tooltip-autocomplete').getByText('foo bar').click(); | ||
await expect(page.locator('.cm-tooltip-autocomplete')).not.toBeVisible(); | ||
await expect(component).toContainText('MATCH (n) RETURN n.`foo bar`'); | ||
}); | ||
test('can update dbschema', async ({ mount, page }) => { | ||
@@ -216,9 +229,2 @@ const component = await mount(_jsx(CypherEditor, { schema: { | ||
}); | ||
test('does not signature help information on auto-completion if flag not enabled explicitly', async ({ page, mount, }) => { | ||
await mount(_jsx(CypherEditor, { schema: testData.mockSchema })); | ||
const textField = page.getByRole('textbox'); | ||
await textField.fill('CALL apoc.periodic.'); | ||
await expect(page.locator('.cm-tooltip-autocomplete')).toBeVisible(); | ||
await expect(page.locator('.cm-completionInfo')).not.toBeVisible(); | ||
}); | ||
test('does not signature help information on auto-completion if docs and signature are empty', async ({ page, mount, }) => { | ||
@@ -225,0 +231,0 @@ await mount(_jsx(CypherEditor, { schema: testData.mockSchema, featureFlags: { |
import { jsx as _jsx } from "react/jsx-runtime"; | ||
/* eslint-disable @typescript-eslint/unbound-method */ | ||
import { testData } from '@neo4j-cypher/language-support'; | ||
@@ -6,2 +7,3 @@ import { expect, test } from '@playwright/experimental-ct-react'; | ||
test.use({ viewport: { width: 1000, height: 500 } }); | ||
const importCsvProc = testData.mockSchema.procedures['apoc.import.csv']; | ||
function testTooltip(tooltip, expectations) { | ||
@@ -42,4 +44,5 @@ const includes = expectations.includes ?? []; | ||
includes: [ | ||
'nodes :: LIST<MAP>', | ||
'Imports `NODE` and `RELATIONSHIP` values with the given labels and types from the provided CSV file', | ||
testData.mockSchema.procedures['apoc.import.csv'].argumentDescription[0] | ||
.description, | ||
testData.mockSchema.procedures['apoc.import.csv'].description, | ||
], | ||
@@ -54,4 +57,4 @@ }); | ||
includes: [ | ||
'nodes :: LIST<MAP>', | ||
'Imports `NODE` and `RELATIONSHIP` values with the given labels and types from the provided CSV file', | ||
importCsvProc.argumentDescription[0].description, | ||
importCsvProc.description, | ||
], | ||
@@ -66,4 +69,4 @@ }); | ||
includes: [ | ||
'rels :: LIST<MAP>', | ||
'Imports `NODE` and `RELATIONSHIP` values with the given labels and types from the provided CSV file', | ||
importCsvProc.argumentDescription[1].description, | ||
importCsvProc.description, | ||
], | ||
@@ -78,4 +81,4 @@ }); | ||
includes: [ | ||
'rels :: LIST<MAP>', | ||
'Imports `NODE` and `RELATIONSHIP` values with the given labels and types from the provided CSV file', | ||
importCsvProc.argumentDescription[1].description, | ||
importCsvProc.description, | ||
], | ||
@@ -82,0 +85,0 @@ }); |
@@ -57,59 +57,43 @@ import { snippet, } from '@codemirror/autocomplete'; | ||
} | ||
const options = autocomplete(documentText, config.schema ?? {}, context.pos, context.explicit); | ||
if (config.featureFlags?.signatureInfoOnAutoCompletions) { | ||
return { | ||
from: context.matchBefore(/(\w|\$)*$/).from, | ||
options: options.map((o) => { | ||
let maybeInfo = {}; | ||
let emptyInfo = true; | ||
const newDiv = document.createElement('div'); | ||
if (o.signature) { | ||
const header = document.createElement('p'); | ||
header.setAttribute('class', 'cm-completionInfo-signature'); | ||
header.textContent = o.signature; | ||
if (header.textContent.length > 0) { | ||
emptyInfo = false; | ||
newDiv.appendChild(header); | ||
} | ||
const options = autocomplete( | ||
// TODO This is a temporary hack because completions are not working well | ||
documentText.slice(0, context.pos), config.schema ?? {}, context.pos, context.explicit); | ||
return { | ||
from: context.matchBefore(/(\w|\$)*$/).from, | ||
options: options.map((o) => { | ||
let maybeInfo = {}; | ||
let emptyInfo = true; | ||
const newDiv = document.createElement('div'); | ||
if (o.signature) { | ||
const header = document.createElement('p'); | ||
header.setAttribute('class', 'cm-completionInfo-signature'); | ||
header.textContent = o.signature; | ||
if (header.textContent.length > 0) { | ||
emptyInfo = false; | ||
newDiv.appendChild(header); | ||
} | ||
if (o.documentation) { | ||
const paragraph = document.createElement('p'); | ||
paragraph.textContent = getDocString(o.documentation); | ||
if (paragraph.textContent.length > 0) { | ||
emptyInfo = false; | ||
newDiv.appendChild(paragraph); | ||
} | ||
} | ||
if (o.documentation) { | ||
const paragraph = document.createElement('p'); | ||
paragraph.textContent = getDocString(o.documentation); | ||
if (paragraph.textContent.length > 0) { | ||
emptyInfo = false; | ||
newDiv.appendChild(paragraph); | ||
} | ||
if (!emptyInfo) { | ||
maybeInfo = { | ||
info: () => Promise.resolve(newDiv), | ||
}; | ||
} | ||
const deprecated = o.tags?.find((tag) => tag === CompletionItemTag.Deprecated) ?? | ||
false; | ||
// The negative boost moves the deprecation down the list | ||
// so we offer the user the completions that are | ||
// deprecated the last | ||
const maybeDeprecated = deprecated | ||
? { boost: -99, deprecated: true } | ||
: {}; | ||
return { | ||
label: o.label, | ||
type: completionKindToCodemirrorIcon(o.kind), | ||
apply: o.kind === CompletionItemKind.Snippet | ||
? // codemirror requires an empty snippet space to be able to tab out of the completion | ||
snippet((o.insertText ?? o.label) + '${}') | ||
: undefined, | ||
detail: o.detail, | ||
...maybeDeprecated, | ||
...maybeInfo, | ||
} | ||
if (!emptyInfo) { | ||
maybeInfo = { | ||
info: () => Promise.resolve(newDiv), | ||
}; | ||
}), | ||
}; | ||
} | ||
else { | ||
return { | ||
from: context.matchBefore(/(\w|\$)*$/).from, | ||
options: options.map((o) => ({ | ||
label: o.label, | ||
} | ||
const deprecated = o.tags?.find((tag) => tag === CompletionItemTag.Deprecated) ?? false; | ||
// The negative boost moves the deprecation down the list | ||
// so we offer the user the completions that are | ||
// deprecated the last | ||
const maybeDeprecated = deprecated | ||
? { boost: -99, deprecated: true } | ||
: {}; | ||
return { | ||
label: o.insertText ? o.insertText : o.label, | ||
displayLabel: o.label, | ||
type: completionKindToCodemirrorIcon(o.kind), | ||
@@ -121,6 +105,8 @@ apply: o.kind === CompletionItemKind.Snippet | ||
detail: o.detail, | ||
})), | ||
}; | ||
} | ||
...maybeDeprecated, | ||
...maybeInfo, | ||
}; | ||
}), | ||
}; | ||
}; | ||
//# sourceMappingURL=autocomplete.js.map |
@@ -79,2 +79,5 @@ import { HighlightStyle, syntaxHighlighting, } from '@codemirror/language'; | ||
}, | ||
'& .cm-signature-help-panel-arg-description': { | ||
padding: '5px', | ||
}, | ||
'& .cm-signature-help-panel-description': { | ||
@@ -81,0 +84,0 @@ padding: '5px', |
@@ -7,3 +7,2 @@ import { LanguageSupport } from '@codemirror/language'; | ||
featureFlags?: { | ||
signatureInfoOnAutoCompletions?: boolean; | ||
consoleCommands?: boolean; | ||
@@ -10,0 +9,0 @@ }; |
import { StateField } from '@codemirror/state'; | ||
import { showTooltip } from '@codemirror/view'; | ||
import { signatureHelp } from '@neo4j-cypher/language-support'; | ||
import { MarkupContent, } from 'vscode-languageserver-types'; | ||
import { getDocString } from './utils'; | ||
@@ -25,7 +26,10 @@ function getTriggerCharacter(query, caretPosition) { | ||
signatureLabel.className = 'cm-signature-help-panel-name'; | ||
signatureLabel.appendChild(document.createTextNode(`${signature.label}(`)); | ||
const methodName = signature.label.slice(0, signature.label.indexOf('(')); | ||
const returnType = signature.label.slice(signature.label.indexOf(')') + 1); | ||
signatureLabel.appendChild(document.createTextNode(`${methodName}(`)); | ||
let currentParamDescription = undefined; | ||
parameters.forEach((param, index) => { | ||
if (typeof param.documentation === 'string') { | ||
if (typeof param.label === 'string') { | ||
const span = document.createElement('span'); | ||
span.appendChild(document.createTextNode(param.documentation)); | ||
span.appendChild(document.createTextNode(param.label)); | ||
if (index !== parameters.length - 1) { | ||
@@ -36,2 +40,6 @@ span.appendChild(document.createTextNode(', ')); | ||
span.className = 'cm-signature-help-panel-current-argument'; | ||
const paramDoc = param.documentation; | ||
currentParamDescription = MarkupContent.is(paramDoc) | ||
? paramDoc.value | ||
: paramDoc; | ||
} | ||
@@ -42,2 +50,3 @@ signatureLabel.appendChild(span); | ||
signatureLabel.appendChild(document.createTextNode(')')); | ||
signatureLabel.appendChild(document.createTextNode(returnType)); | ||
contents.appendChild(signatureLabel); | ||
@@ -47,6 +56,12 @@ const separator = document.createElement('div'); | ||
contents.appendChild(separator); | ||
const description = document.createElement('div'); | ||
description.className = 'cm-signature-help-panel-description'; | ||
description.appendChild(document.createTextNode(doc)); | ||
contents.appendChild(description); | ||
if (currentParamDescription !== undefined) { | ||
const argDescription = document.createElement('div'); | ||
argDescription.className = 'cm-signature-help-panel-arg-description'; | ||
argDescription.appendChild(document.createTextNode(currentParamDescription)); | ||
contents.appendChild(argDescription); | ||
} | ||
const methodDescription = document.createElement('div'); | ||
methodDescription.className = 'cm-signature-help-panel-description'; | ||
methodDescription.appendChild(document.createTextNode(doc)); | ||
contents.appendChild(methodDescription); | ||
return { dom }; | ||
@@ -53,0 +68,0 @@ }; |
@@ -20,3 +20,3 @@ { | ||
], | ||
"version": "2.0.0-canary-dcbe67d", | ||
"version": "2.0.0-canary-dd41bf6", | ||
"main": "./dist/index.js", | ||
@@ -55,3 +55,3 @@ "types": "./dist/index.d.ts", | ||
"@lezer/highlight": "^1.1.3", | ||
"@neo4j-cypher/language-support": "2.0.0-canary-dcbe67d", | ||
"@neo4j-cypher/language-support": "2.0.0-canary-dd41bf6", | ||
"@types/prismjs": "^1.26.3", | ||
@@ -58,0 +58,0 @@ "@types/workerpool": "^6.4.7", |
@@ -80,3 +80,4 @@ import { | ||
const options = autocomplete( | ||
documentText, | ||
// TODO This is a temporary hack because completions are not working well | ||
documentText.slice(0, context.pos), | ||
config.schema ?? {}, | ||
@@ -87,63 +88,45 @@ context.pos, | ||
if (config.featureFlags?.signatureInfoOnAutoCompletions) { | ||
return { | ||
from: context.matchBefore(/(\w|\$)*$/).from, | ||
options: options.map((o) => { | ||
let maybeInfo = {}; | ||
let emptyInfo = true; | ||
const newDiv = document.createElement('div'); | ||
return { | ||
from: context.matchBefore(/(\w|\$)*$/).from, | ||
options: options.map((o) => { | ||
let maybeInfo = {}; | ||
let emptyInfo = true; | ||
const newDiv = document.createElement('div'); | ||
if (o.signature) { | ||
const header = document.createElement('p'); | ||
header.setAttribute('class', 'cm-completionInfo-signature'); | ||
header.textContent = o.signature; | ||
if (header.textContent.length > 0) { | ||
emptyInfo = false; | ||
newDiv.appendChild(header); | ||
} | ||
if (o.signature) { | ||
const header = document.createElement('p'); | ||
header.setAttribute('class', 'cm-completionInfo-signature'); | ||
header.textContent = o.signature; | ||
if (header.textContent.length > 0) { | ||
emptyInfo = false; | ||
newDiv.appendChild(header); | ||
} | ||
} | ||
if (o.documentation) { | ||
const paragraph = document.createElement('p'); | ||
paragraph.textContent = getDocString(o.documentation); | ||
if (paragraph.textContent.length > 0) { | ||
emptyInfo = false; | ||
newDiv.appendChild(paragraph); | ||
} | ||
if (o.documentation) { | ||
const paragraph = document.createElement('p'); | ||
paragraph.textContent = getDocString(o.documentation); | ||
if (paragraph.textContent.length > 0) { | ||
emptyInfo = false; | ||
newDiv.appendChild(paragraph); | ||
} | ||
} | ||
if (!emptyInfo) { | ||
maybeInfo = { | ||
info: () => Promise.resolve(newDiv), | ||
}; | ||
} | ||
const deprecated = | ||
o.tags?.find((tag) => tag === CompletionItemTag.Deprecated) ?? | ||
false; | ||
// The negative boost moves the deprecation down the list | ||
// so we offer the user the completions that are | ||
// deprecated the last | ||
const maybeDeprecated = deprecated | ||
? { boost: -99, deprecated: true } | ||
: {}; | ||
if (!emptyInfo) { | ||
maybeInfo = { | ||
info: () => Promise.resolve(newDiv), | ||
}; | ||
} | ||
const deprecated = | ||
o.tags?.find((tag) => tag === CompletionItemTag.Deprecated) ?? false; | ||
// The negative boost moves the deprecation down the list | ||
// so we offer the user the completions that are | ||
// deprecated the last | ||
const maybeDeprecated = deprecated | ||
? { boost: -99, deprecated: true } | ||
: {}; | ||
return { | ||
label: o.label, | ||
type: completionKindToCodemirrorIcon(o.kind), | ||
apply: | ||
o.kind === CompletionItemKind.Snippet | ||
? // codemirror requires an empty snippet space to be able to tab out of the completion | ||
snippet((o.insertText ?? o.label) + '${}') | ||
: undefined, | ||
detail: o.detail, | ||
...maybeDeprecated, | ||
...maybeInfo, | ||
}; | ||
}), | ||
}; | ||
} else { | ||
return { | ||
from: context.matchBefore(/(\w|\$)*$/).from, | ||
options: options.map((o) => ({ | ||
label: o.label, | ||
return { | ||
label: o.insertText ? o.insertText : o.label, | ||
displayLabel: o.label, | ||
type: completionKindToCodemirrorIcon(o.kind), | ||
@@ -156,5 +139,7 @@ apply: | ||
detail: o.detail, | ||
})), | ||
}; | ||
} | ||
...maybeDeprecated, | ||
...maybeInfo, | ||
}; | ||
}), | ||
}; | ||
}; |
@@ -124,2 +124,5 @@ import { | ||
}, | ||
'& .cm-signature-help-panel-arg-description': { | ||
padding: '5px', | ||
}, | ||
'& .cm-signature-help-panel-description': { | ||
@@ -126,0 +129,0 @@ padding: '5px', |
@@ -25,3 +25,2 @@ import { autocompletion } from '@codemirror/autocomplete'; | ||
featureFlags?: { | ||
signatureInfoOnAutoCompletions?: boolean; | ||
consoleCommands?: boolean; | ||
@@ -28,0 +27,0 @@ }; |
import { EditorState, StateField } from '@codemirror/state'; | ||
import { showTooltip, Tooltip } from '@codemirror/view'; | ||
import { signatureHelp } from '@neo4j-cypher/language-support'; | ||
import { SignatureInformation } from 'vscode-languageserver-types'; | ||
import { | ||
MarkupContent, | ||
SignatureInformation, | ||
} from 'vscode-languageserver-types'; | ||
import { CypherConfig } from './langCypher'; | ||
@@ -41,8 +44,11 @@ import { getDocString } from './utils'; | ||
signatureLabel.className = 'cm-signature-help-panel-name'; | ||
signatureLabel.appendChild(document.createTextNode(`${signature.label}(`)); | ||
const methodName = signature.label.slice(0, signature.label.indexOf('(')); | ||
const returnType = signature.label.slice(signature.label.indexOf(')') + 1); | ||
signatureLabel.appendChild(document.createTextNode(`${methodName}(`)); | ||
let currentParamDescription: string | undefined = undefined; | ||
parameters.forEach((param, index) => { | ||
if (typeof param.documentation === 'string') { | ||
if (typeof param.label === 'string') { | ||
const span = document.createElement('span'); | ||
span.appendChild(document.createTextNode(param.documentation)); | ||
span.appendChild(document.createTextNode(param.label)); | ||
if (index !== parameters.length - 1) { | ||
@@ -54,2 +60,6 @@ span.appendChild(document.createTextNode(', ')); | ||
span.className = 'cm-signature-help-panel-current-argument'; | ||
const paramDoc = param.documentation; | ||
currentParamDescription = MarkupContent.is(paramDoc) | ||
? paramDoc.value | ||
: paramDoc; | ||
} | ||
@@ -61,2 +71,3 @@ signatureLabel.appendChild(span); | ||
signatureLabel.appendChild(document.createTextNode(')')); | ||
signatureLabel.appendChild(document.createTextNode(returnType)); | ||
@@ -70,8 +81,15 @@ contents.appendChild(signatureLabel); | ||
const description = document.createElement('div'); | ||
description.className = 'cm-signature-help-panel-description'; | ||
description.appendChild(document.createTextNode(doc)); | ||
if (currentParamDescription !== undefined) { | ||
const argDescription = document.createElement('div'); | ||
argDescription.className = 'cm-signature-help-panel-arg-description'; | ||
argDescription.appendChild( | ||
document.createTextNode(currentParamDescription), | ||
); | ||
contents.appendChild(argDescription); | ||
} | ||
const methodDescription = document.createElement('div'); | ||
methodDescription.className = 'cm-signature-help-panel-description'; | ||
methodDescription.appendChild(document.createTextNode(doc)); | ||
contents.appendChild(methodDescription); | ||
contents.appendChild(description); | ||
return { dom }; | ||
@@ -78,0 +96,0 @@ }; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
674155
8992
+ Added@neo4j-cypher/language-support@2.0.0-canary-dd41bf6(transitive)
- Removed@neo4j-cypher/language-support@2.0.0-canary-dcbe67d(transitive)