Skip to content

Commit

Permalink
Merge pull request #1651 from eijawerner/fix-set-params-multiline
Browse files Browse the repository at this point in the history
Fixed so possible to set params using multiline
  • Loading branch information
eijawerner committed Jan 25, 2022
2 parents 711adbf + dabaeb1 commit e63ee65
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 41 deletions.
34 changes: 30 additions & 4 deletions e2e_tests/integration/params.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,8 @@
/* global Cypress, cy, before */

describe(':param in Browser', () => {
before(function() {
cy.visit(Cypress.config('url'))
.title()
.should('include', 'Neo4j Browser')
before(function () {
cy.visit(Cypress.config('url')).title().should('include', 'Neo4j Browser')
cy.wait(3000)
})
it('handles :param without web worker', () => {
Expand Down Expand Up @@ -121,4 +119,32 @@ function runTests() {
cy.resultContains('point({srid:4326, x:12.9082, y:57.7346})')
}
// })

// :params
// it('can set :params with multiple lines syntax', () => {
cy.executeCommand(':clear')
setParamQ = `:params {{} x: 1,{shift}{enter}stringWithSpace:'with space',{shift}{enter}stringWithTab: 'with\ttab'{}}`
cy.executeCommand(setParamQ)
cy.get('[data-testid="rawParamData"]', { timeout: 20000 })
.first()
.should(
'contain',
'{\n "x": 1.0,\n "stringWithSpace": "with space",\n "stringWithTab": "\'with\ttab\'"\n}'
)
getParamQ = 'RETURN $stringWithSpace'
cy.executeCommand(getParamQ)
cy.waitForCommandResult()
cy.resultContains('"with space"')
// })
// it('can set :params where a new line is before the {', () => {
cy.executeCommand(':clear')
setParamQ = `:params{shift}{enter}{{} x: 1,{shift}{enter}stringWithSpace:'with space',{shift}{enter}stringWithTab: 'with\ttab'{}}`
cy.executeCommand(setParamQ)
cy.get('[data-testid="rawParamData"]', { timeout: 20000 })
.first()
.should(
'contain',
'{\n "x": 1.0,\n "stringWithSpace": "with space",\n "stringWithTab": "\'with\ttab\'"\n}'
)
// })
}
6 changes: 3 additions & 3 deletions src/shared/modules/commands/helpers/params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { splitStringOnFirst } from 'services/commandUtils'
import { SYSTEM_DB } from 'shared/modules/dbMeta/constants'
import { replace, update } from 'shared/modules/params/paramsDuck'

export const extractParams = (param: any) => {
export const extractParams = (param: string) => {
// early bail, now handled by parser
if (param.includes('=>')) {
return {
Expand Down Expand Up @@ -83,11 +83,11 @@ export const handleParamsCommand = (action: any, put: any, targetDb?: any) => {
)
}
const strippedCmd = action.cmd.substr(1)
const parts = splitStringOnFirst(strippedCmd, ' ')
const parts = splitStringOnFirst(strippedCmd, /\s/)
const param = parts[1].trim()

return Promise.resolve().then(() => {
if (/^"?\{.*\}"?$/.test(param)) {
if (/^"?\{[\s\S]*\}"?$/.test(param)) {
// JSON object string {"x": 2, "y":"string"}
try {
const res = jsonic(param.replace(/^"/, '').replace(/"$/, '')) // Remove any surrounding quotes
Expand Down
35 changes: 35 additions & 0 deletions src/shared/services/commandUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,21 @@ RETURN 2
str: 'test:"hello :space"',
delimiter: ':',
expect: ['test', '"hello :space"']
},
{
str: 'test:"hello :space"',
delimiter: /\s/,
expect: ['test:"hello', ':space"']
},
{
str: ' :config test:"hello :space"',
delimiter: /\s/,
expect: ['', ':config test:"hello :space"']
},
{
str: ':config',
delimiter: /\s/,
expect: [':config', '']
}
]
testStrs.forEach(obj => {
Expand All @@ -94,6 +109,26 @@ RETURN 2
str: 'test:"hello :space"',
delimiter: ':',
expect: ['test:"hello ', 'space"']
},
{
str: ' test:hello',
delimiter: ' ',
expect: ['', 'test:hello']
},
{
str: 'test:hello ',
delimiter: ' ',
expect: ['test:hello', '']
},
{
str: 'test:hello',
delimiter: ' ',
expect: ['', 'test:hello']
},
{
str: 'test:"hello :space"',
delimiter: /\s/,
expect: ['test:"hello', ':space"']
}
]
testStrs.forEach(obj => {
Expand Down
77 changes: 43 additions & 34 deletions src/shared/services/commandUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,38 +19,44 @@
*/
import { extractStatements } from 'cypher-editor-support'

export function cleanCommand(cmd: any) {
export function cleanCommand(cmd: string): string {
const noComments = stripCommandComments(cmd)
const noEmptyLines = stripEmptyCommandLines(noComments)
return noEmptyLines
return stripEmptyCommandLines(noComments)
}

export function stripEmptyCommandLines(str: any) {
const skipEmptyLines = (e: any) => !/^\s*$/.test(e)
export function stripEmptyCommandLines(str: string): string {
const skipEmptyLines = (e: string) => !/^\s*$/.test(e)
return str.split('\n').filter(skipEmptyLines).join('\n')
}

export function stripCommandComments(str: any) {
export function stripCommandComments(str: string): string {
return str
.split('\n')
.filter((line: any) => !line.trim().startsWith('//'))
.filter((line: string) => !line.trim().startsWith('//'))
.join('\n')
}

export function splitStringOnFirst(str: any, delimiter: any) {
export function splitStringOnFirst(
str: string,
delimiter: string | RegExp
): string[] {
const parts = str.split(delimiter)
return ([] as any[]).concat(parts[0], parts.slice(1).join(delimiter))
const strWithoutFirst = str.slice(parts[0].length + 1)
return ([] as string[]).concat(parts[0], strWithoutFirst)
}

export function splitStringOnLast(str: any, delimiter: any) {
export function splitStringOnLast(
str: string,
delimiter: string | RegExp
): string[] {
const parts = str.split(delimiter)
return [].concat(
parts.slice(0, parts.length - 1).join(delimiter),
parts[parts.length - 1]
)
const lastPart = parts[parts.length - 1]
const stringWithoutLast =
parts.length > 1 ? str.slice(0, str.length - lastPart.length - 1) : ''
return ([] as string[]).concat(stringWithoutLast, lastPart)
}

export const isCypherCommand = (cmd: any) => {
export const isCypherCommand = (cmd: string): boolean => {
const cleanCmd = cleanCommand(cmd)
return cleanCmd[0] !== ':'
}
Expand All @@ -60,38 +66,41 @@ export const buildCommandObject = (action: any, interpret: any) => {
return { action, interpreted, useDb: action.useDb }
}

export const getInterpreter = (interpret: any, cmd: any, ignore = false) => {
export const getInterpreter = (interpret: any, cmd: string, ignore = false) => {
if (ignore) return interpret('noop')
if (isCypherCommand(cmd)) return interpret('cypher')
return interpret(cleanCommand(cmd).substr(1))
}

export const extractPostConnectCommandsFromServerConfig = (str: any) => {
export const extractPostConnectCommandsFromServerConfig = (
str: string
): string[] | undefined => {
const substituteStr = '@@semicolon@@'
const substituteRe = new RegExp(substituteStr, 'g')
const replaceFn = (m: any) => m.replace(/;/g, substituteStr)
const replaceFn = (m: string) => m.replace(/;/g, substituteStr)
const qs = [/(`[^`]*?`)/g, /("[^"]*?")/g, /('[^']*?')/g]
qs.forEach(q => (str = str.replace(q, replaceFn)))
const splitted = str
.split(';')
.map((item: any) => item.trim())
.map((item: any) => item.replace(substituteRe, ';'))
.filter((item: any) => item && item.length)
.map((item: string) => item.trim())
.map((item: string) => item.replace(substituteRe, ';'))
.filter((item: string) => item && item.length)
return splitted && splitted.length ? splitted : undefined
}

const getHelpTopic = (str: any) => splitStringOnFirst(str, ' ')[1] || 'help' // Map empty input to :help help
const stripPound = (str: any) => splitStringOnFirst(str, '#')[0]
const lowerCase = (str: any) => str.toLowerCase()
const trim = (str: any) => str.trim()
const replaceSpaceWithDash = (str: any) => str.replace(/\s/g, '-')
const snakeToCamel = (str: any) =>
str.replace(/(-\w)/g, (match: any) => match[1].toUpperCase())
const camelToSnake = (name: any, separator: any) => {
const getHelpTopic = (str: string) => splitStringOnFirst(str, ' ')[1] || 'help' // Map empty input to :help help
const stripPound = (str: string) => splitStringOnFirst(str, '#')[0]
const lowerCase = (str: string) => str.toLowerCase()
const trim = (str: string) => str.trim()
const replaceSpaceWithDash = (str: string) => str.replace(/\s/g, '-')
const snakeToCamel = (str: string) =>
str.replace(/(-\w)/g, (match: string) => match[1].toUpperCase())
const camelToSnake = (name: string, separator: string) => {
return name
.replace(
/([a-z]|(?:[A-Z0-9]+))([A-Z0-9]|$)/g,
(_: any, $1: any, $2: any) => $1 + ($2 && (separator || '_') + $2)
(_: string, $1: string, $2: string) =>
$1 + ($2 && (separator || '_') + $2)
)
.toLowerCase()
}
Expand All @@ -105,7 +114,7 @@ export const transformCommandToHelpTopic = (inputStr?: string): string =>
.map(replaceSpaceWithDash)
.map(snakeToCamel)[0]

export const transformHelpTopicToCommand = (inputStr: any) => {
export const transformHelpTopicToCommand = (inputStr: string): string => {
if (inputStr.indexOf('-') > -1) {
return inputStr
}
Expand All @@ -115,7 +124,7 @@ export const transformHelpTopicToCommand = (inputStr: any) => {
const quotedRegex = /^"(.*)"|'(.*)'/
const arrowFunctionRegex = /^.*=>\s*([^$]*)$/

export const mapParamToCypherStatement = (key: any, param: any) => {
export const mapParamToCypherStatement = (key: any, param: any): string => {
const quotedKey = key.match(quotedRegex)
const cleanKey = quotedKey
? `\`${quotedKey[1]}\``
Expand All @@ -131,7 +140,7 @@ export const mapParamToCypherStatement = (key: any, param: any) => {
return returnAs(param)
}

export const extractStatementsFromString = (str: any) => {
export const extractStatementsFromString = (str: string) => {
const cleanCmd = cleanCommand(str)
const parsed = extractStatements(cleanCmd)
const { statements } = parsed.referencesListener
Expand All @@ -141,7 +150,7 @@ export const extractStatementsFromString = (str: any) => {
.filter((_: any) => _)
}

export const getCommandAndParam = (str: any) => {
export const getCommandAndParam = (str: string): string[] => {
const [serverCmd, props] = splitStringOnFirst(
splitStringOnFirst(str, ' ')[1],
' '
Expand Down

0 comments on commit e63ee65

Please sign in to comment.