Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix format option splitter problems #2315

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
Please see [CONTRIBUTING.md](./CONTRIBUTING.md) on how to contribute to Cucumber.

## [Unreleased]
### Fixed
- Improve handling of formatter paths ([#2315](https://github.com/cucumber/cucumber-js/pull/2315))

## [9.5.1] - 2023-09-06
### Fixed
Expand Down
64 changes: 48 additions & 16 deletions src/configuration/option_splitter.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,57 @@
export const OptionSplitter = {
split(option: string): string[] {
option = option.replace(/"/g, '')
let result: string[]
let match1, match2

const parts = option.split(/((?:file){0}):(?!\\|\/\/)/)

const result = parts.reduce((memo: string[], part: string, i: number) => {
if (partNeedsRecombined(i)) {
memo.push(parts.slice(i, i + 2).join(''))
// "foo":"bar" or "foo":bar
if ((match1 = option.match(/^"([^"]*)":(.*)$/)) !== null) {
// "foo":"bar"
if ((match2 = match1[2].match(/^"([^"]*)"$/)) !== null) {
result = [match1[1], match2[1]]
}

return memo
}, [])

if (result.length === 1) {
result.push('')
// "foo":bar
else {
result = [match1[1], match1[2]]
}
}
// foo:"bar"
else if ((match1 = option.match(/^(.*):"([^"]*)"$/)) !== null) {
result = [match1[1], match1[2]]
}
// "foo"
else if ((match1 = option.match(/^"([^"]*)"$/)) !== null) {
result = [match1[1], '']
}
// file://foo or file:///foo or file://C:/foo or file://C:\foo or file:///C:/foo or file:///C:\foo
else if (
(match1 = option.match(/^(file:\/{2,3}(?:[a-zA-Z]:[/\\])?)(.*)$/)) !==
null
) {
// file://foo:bar
if ((match2 = match1[2].match(/^([^:]*):(.*)$/)) !== null) {
result = [match1[1] + match2[1], match2[2]]
} else {
result = [option, '']
}
}
// C:\foo or C:/foo
else if ((match1 = option.match(/^([a-zA-Z]:[/\\])(.*)$/)) !== null) {
// C:\foo:bar or C:/foo:bar
if ((match2 = match1[2].match(/^([^:]*):(.*)$/)) !== null) {
result = [match1[1] + match2[1], match2[2]]
} else {
result = [option, '']
}
}
// foo:bar
else if ((match1 = option.match(/^([^:]*):(.*)$/)) !== null) {
result = [match1[1], match1[2]]
}
// foo
else {
result = [option, '']
}

return result
},
}

function partNeedsRecombined(i: number): boolean {
return i % 2 === 0
}
152 changes: 146 additions & 6 deletions src/configuration/option_splitter_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,26 @@ describe('OptionSplitter', () => {
output: ['../custom/formatter', '../formatter/output.txt'],
},
{
description: 'splits absolute unix paths',
description: 'splits relative windows paths',
input: '..\\custom\\formatter:..\\formatter\\output.txt',
output: ['..\\custom\\formatter', '..\\formatter\\output.txt'],
},
{
description: 'splits file URLs for absolute unix path',
input: 'file:///custom/formatter:file:///formatter/output.txt',
output: ['file:///custom/formatter', 'file:///formatter/output.txt'],
},
{
description: 'splits paths with quotes around them',
input: '/custom/formatter:"/formatter directory/output.txt"',
output: ['/custom/formatter', '/formatter directory/output.txt'],
description: 'splits file URLs for UNC path',
input:
'file://hostname/custom/formatter:file://hostname/formatter/output.txt',
output: [
'file://hostname/custom/formatter',
'file://hostname/formatter/output.txt',
],
},
{
description: 'splits absolute windows paths',
description: 'splits file URLs for absolute windows path',
input: 'file://C:\\custom\\formatter:file://C:\\formatter\\output.txt',
output: [
'file://C:\\custom\\formatter',
Expand All @@ -34,10 +43,141 @@ describe('OptionSplitter', () => {
},
{
description:
'does not split a single absolute windows paths, adds empty string',
'splits file URLs for absolute windows path with "/" as directory separator',
input: 'file:///C:/custom/formatter:file:///C:/formatter/output.txt',
output: [
'file:///C:/custom/formatter',
'file:///C:/formatter/output.txt',
],
},
{
description: 'splits valid file URLs for absolute windows path',
input: 'file:///C:\\custom\\formatter:file:///C:\\formatter\\output.txt',
output: [
'file:///C:\\custom\\formatter',
'file:///C:\\formatter\\output.txt',
],
},
{
description:
'splits valid file URLs for absolute windows path with "/" as directory separator',
input: 'file:///C:/custom/formatter:file:///C:/formatter/output.txt',
output: [
'file:///C:/custom/formatter',
'file:///C:/formatter/output.txt',
],
},
{
description: 'splits absolute unix paths',
input: '/custom/formatter:/formatter/output.txt',
output: ['/custom/formatter', '/formatter/output.txt'],
},
{
description: 'splits absolute windows paths',
input: 'C:\\custom\\formatter:C:\\formatter\\output.txt',
output: ['C:\\custom\\formatter', 'C:\\formatter\\output.txt'],
},
{
description:
'splits absolute windows paths with "/" as directory separator',
input: 'C:/custom/formatter:C:/formatter/output.txt',
output: ['C:/custom/formatter', 'C:/formatter/output.txt'],
},
{
description: 'splits UNC paths',
input:
'\\\\hostname\\custom\\formatter:\\\\hostname\\formatter\\output.txt',
output: [
'\\\\hostname\\custom\\formatter',
'\\\\hostname\\formatter\\output.txt',
],
},
{
description: 'splits UNC paths with "/" as directory separator',
input: '//hostname/custom/formatter://hostname/formatter/output.txt',
output: [
'//hostname/custom/formatter',
'//hostname/formatter/output.txt',
],
},
{
description: 'splits paths with quotes around them',
input: '/custom/formatter:"/formatter directory/output.txt"',
output: ['/custom/formatter', '/formatter directory/output.txt'],
},
{
description:
'does not split a single file URL for absolute unix path, adds empty string',
input: 'file:///custom/formatter',
output: ['file:///custom/formatter', ''],
},
{
description:
'does not split a single file URL for UNC path, adds empty string',
input: 'file://hostname/custom/formatter',
output: ['file://hostname/custom/formatter', ''],
},
{
description:
'does not split a single file URL for absolute windows path, adds empty string',
input: 'file://C:\\custom\\formatter',
output: ['file://C:\\custom\\formatter', ''],
},
{
description:
'does not split a single file URL for absolute windows path with "/" as directory separator, adds empty string',
input: 'file://C:/custom/formatter',
output: ['file://C:/custom/formatter', ''],
},
{
description:
'does not split a valid single file URL for absolute windows path, adds empty string',
input: 'file:///C:\\custom\\formatter',
output: ['file:///C:\\custom\\formatter', ''],
},
{
description:
'does not split a valid single file URL for absolute windows path with "/" as directory separator, adds empty string',
input: 'file:///C:/custom/formatter',
output: ['file:///C:/custom/formatter', ''],
},
{
description:
'does not split a single absolute windows path, adds empty string',
input: 'C:\\custom\\formatter',
output: ['C:\\custom\\formatter', ''],
},
{
description:
'does not split a single absolute windows path with "/" as directory separator, adds empty string',
input: 'C:/custom/formatter',
output: ['C:/custom/formatter', ''],
},
{
description: 'does not split quoted values: case 1',
input: '"foo:bar":"baz:qux"',
output: ['foo:bar', 'baz:qux'],
},
{
description: 'does not split quoted values: case 2',
input: '"foo:bar":baz:qux',
output: ['foo:bar', 'baz:qux'],
},
{
description: 'does not split quoted values: case 3',
input: 'foo:bar:"baz:qux"',
output: ['foo:bar', 'baz:qux'],
},
{
description: 'does not split quoted values: case 4',
input: '"foo:bar:baz:qux"',
output: ['foo:bar:baz:qux', ''],
},
{
description: 'splits string contains multiple ":"',
input: 'foo:bar:baz:qux',
output: ['foo', 'bar:baz:qux'],
},
]

examples.forEach(({ description, input, output }) => {
Expand Down