-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add
extras.maxLength
options to configure the maximum extras …
…lengths To achieve this nicely in the code, intorduce a separate `Extras` formatter. This formatter is solely focussed on formatting the extras and is used by `Formatter`.
- Loading branch information
Showing
7 changed files
with
258 additions
and
60 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
import { ParsedOptions } from '../options'; | ||
|
||
class Extras { | ||
readonly options = { | ||
keyValueSeparator: '=', | ||
separator: ', ', | ||
start: '(', | ||
end: ')', | ||
} as const; | ||
|
||
private readonly _maxLength: ParsedOptions['extras']['maxLength']; | ||
private _extras: string[]; | ||
private _length: number; | ||
|
||
constructor(maxLength: ParsedOptions['extras']['maxLength']) { | ||
this._maxLength = maxLength; | ||
this._length = 0; | ||
this._extras = []; | ||
} | ||
|
||
get length() { | ||
return this._length; | ||
} | ||
|
||
get extras() { | ||
return this._extras; | ||
} | ||
|
||
/** | ||
* Parse a key-value pair and add to the extras if it is a valid extra. | ||
* | ||
* @param key | ||
* @param value | ||
* @returns `true` if the key-value was valid and is added, false otherwise. | ||
*/ | ||
parseAndAdd(key: string, value: unknown): boolean { | ||
if (typeof value === 'object' || typeof value === 'function') { | ||
return false; | ||
} | ||
|
||
const extra = this.formatExtra(key, value); | ||
if ( | ||
extra.key.length > this._maxLength.key || | ||
extra.value.length > this._maxLength.value || | ||
this.lengthAfterAdding(extra.formatted) > this._maxLength.total | ||
) { | ||
return false; | ||
} | ||
|
||
this.add(extra.formatted); | ||
return true; | ||
} | ||
|
||
format(): string { | ||
if (this._extras.length === 0) { | ||
return ''; | ||
} | ||
|
||
return [ | ||
this.options.start, | ||
this._extras.join(this.options.separator), | ||
this.options.end, | ||
].join(''); | ||
} | ||
|
||
formatExtra( | ||
key: string, | ||
value: unknown, | ||
): { formatted: string; key: string; value: string } { | ||
const stringifiedKey = this.stringify(key); | ||
const stringifiedValue = this.stringify(value); | ||
const formatted = [ | ||
stringifiedKey, | ||
this.options.keyValueSeparator, | ||
stringifiedValue, | ||
].join(''); | ||
|
||
return { | ||
formatted, | ||
key: stringifiedKey, | ||
value: stringifiedValue, | ||
}; | ||
} | ||
|
||
private lengthAfterAdding(formattedExtra: string): number { | ||
let length = this._length + formattedExtra.length; | ||
if (this._length === 0) { | ||
length += this.options.start.length + this.options.end.length; | ||
} else if (this._extras.length >= 1) { | ||
length += this.options.separator.length; | ||
} | ||
|
||
return length; | ||
} | ||
|
||
private add(formattedExtra: string): void { | ||
this._extras.push(formattedExtra); | ||
this._length = this.lengthAfterAdding(formattedExtra); | ||
} | ||
|
||
private stringify(value: unknown): string { | ||
if ( | ||
typeof value === 'string' && | ||
value.length > 0 && | ||
!this.containsWhitespace(value) && | ||
!value.includes(this.options.keyValueSeparator) | ||
) { | ||
return value; | ||
} | ||
|
||
return JSON.stringify(value); | ||
} | ||
|
||
private containsWhitespace(value: string): boolean { | ||
return /\s/.test(value); | ||
} | ||
} | ||
|
||
export { Extras }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import { beforeEach, describe, expect, it } from '@jest/globals'; | ||
import { Extras } from './extras'; | ||
|
||
describe('Extras', () => { | ||
let extras: Extras; | ||
beforeEach(() => { | ||
const options = { key: 10, value: 20, total: 50 } as const; | ||
extras = new Extras(options); | ||
}); | ||
|
||
it('formats an extra key with spaces in quotations', () => { | ||
const extra = extras.formatExtra('some key', 'value'); | ||
expect(extra.key).toBe('"some key"'); | ||
}); | ||
|
||
it('formats an extra value with spaces in quotations', () => { | ||
const extra = extras.formatExtra('key', 'some value'); | ||
expect(extra.value).toBe('"some value"'); | ||
}); | ||
|
||
it('formats an extra key and value with spaces in quotations', () => { | ||
const extra = extras.formatExtra('some key', 'some value'); | ||
expect(extra.key).toBe('"some key"'); | ||
expect(extra.value).toBe('"some value"'); | ||
}); | ||
|
||
it('formats an extra with a key-value separator', () => { | ||
const extra = extras.formatExtra('key', 'value'); | ||
expect(extra.formatted).toMatch(/^key.+value$/); | ||
}); | ||
|
||
describe('length', () => { | ||
it('is "0" for no extras', () => { | ||
expect(extras).toHaveLength(0); | ||
}); | ||
|
||
it('is the correct length for a single extra', () => { | ||
const key = 'myKey'; | ||
const value = 'myValue'; | ||
|
||
extras.parseAndAdd(key, value); | ||
expect(extras).toHaveLength( | ||
extras.options.start.length + | ||
key.length + | ||
extras.options.keyValueSeparator.length + | ||
value.length + | ||
extras.options.end.length, | ||
); | ||
}); | ||
|
||
it('is the correct length for a multiple extras', () => { | ||
const key = 'myKey'; | ||
const value = 'myValue'; | ||
extras.parseAndAdd(`${key}1`, value); | ||
extras.parseAndAdd(`${key}2`, value); | ||
expect(extras).toHaveLength( | ||
extras.options.start.length + | ||
(key.length + | ||
1 + | ||
extras.options.keyValueSeparator.length + | ||
value.length) * | ||
2 + | ||
extras.options.separator.length + | ||
extras.options.end.length, | ||
); | ||
}); | ||
|
||
it('is the correct length for non-included extras', () => { | ||
const key = 'myKey'; | ||
const value = 'myValue'; | ||
extras.parseAndAdd(key, value); | ||
extras.parseAndAdd('my very long key that cannot be added', value); | ||
expect(extras).toHaveLength( | ||
extras.options.start.length + | ||
key.length + | ||
extras.options.keyValueSeparator.length + | ||
value.length + | ||
extras.options.end.length, | ||
); | ||
}); | ||
}); | ||
|
||
describe('parseAndAdd', () => { | ||
it('returns "true" if the extra was added', () => { | ||
expect(extras.parseAndAdd('myKey', 'myValue')).toBe(true); | ||
}); | ||
|
||
it('returns "false" if the extra was not added', () => { | ||
expect( | ||
extras.parseAndAdd('my very long key that cannot be added', 'myValue'), | ||
).toBe(false); | ||
}); | ||
|
||
it('adds the extra if it can', () => { | ||
expect(extras.extras).toHaveLength(0); | ||
extras.parseAndAdd('myKey', 'myValue'); | ||
expect(extras.extras).toHaveLength(1); | ||
}); | ||
|
||
it('does not add the extra if it is invalid', () => { | ||
expect(extras.extras).toHaveLength(0); | ||
extras.parseAndAdd('my very long key that cannot be added', 'myValue'); | ||
expect(extras.extras).toHaveLength(0); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import { Formatter } from './formatter'; | ||
|
||
export { Formatter }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters