Skip to content

Commit

Permalink
feat: Make replaceTagsWithValues exported as point-free, and with typing
Browse files Browse the repository at this point in the history
Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>
  • Loading branch information
Iku-turso and jansav committed Feb 12, 2024
1 parent b6fd8b3 commit 3ff26b1
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 70 deletions.
5 changes: 5 additions & 0 deletions packages/fp/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,8 @@ export {
pipelineBreak,
} from './src/pipeline/unsafePipeline/pipeline';
export { safePipeline } from './src/pipeline/safePipeline/safePipeline';

export {
replaceTagsWithValues,
replaceTagsWithValuesUnsafe,
} from './src/replaceTagsWithValues/replaceTagsWithValues';
2 changes: 2 additions & 0 deletions packages/fp/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import getSafeFrom from './src/getSafeFrom/getSafeFrom';
import getFrom from './src/getFrom/getFrom';
import firstMatchValue from './src/firstMatchValue/firstMatchValue';
import { DeepMap } from './src/deepMap/deepMap';
import replaceTagsWithValues from './src/replaceTagsWithValues/replaceTagsWithValues';

export {
awaitAll,
Expand All @@ -23,4 +24,5 @@ export {
getSafeFrom,
firstMatchValue,
DeepMap,
replaceTagsWithValues,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export function replaceTagsWithValues(
stringWithTags: string,
): (valuesForTags: object) => string;

export function replaceTagsWithValuesUnsafe(
stringWithTags: string,
): (valuesForTags: object) => string;
35 changes: 14 additions & 21 deletions packages/fp/src/replaceTagsWithValues/replaceTagsWithValues.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,9 @@
import {
get,
identity,
isArray,
isObject,
map,
reduce,
tap,
isString,
curry,
} from 'lodash/fp';
import { get, isArray, isObject, isString, map, reduce, tap } from 'lodash/fp';

import matchAll from '../matchAll/matchAll';
import { pipeline } from '../pipeline/unsafePipeline/pipeline';

const replaceTagsWithValues = curry((valuesForTags, oldStringWithTags) => {
const replaceTagsWithValuesInternal = valuesForTags => oldStringWithTags => {
const newStringWithTags = pipeline(
matchAll(oldStringWithTags, /{(.*?)}/),
map(toResolvedValuesForTagsFor(valuesForTags)),
Expand All @@ -24,19 +14,22 @@ const replaceTagsWithValues = curry((valuesForTags, oldStringWithTags) => {
return newStringWithTags;
}

return replaceTagsWithValues(valuesForTags, newStringWithTags);
});
return replaceTagsWithValuesInternal(valuesForTags)(newStringWithTags);
};

export const replaceTagsWithValues = stringWithTags => valuesForTags =>
pipeline(
stringWithTags,
tap(protectAgainstNonStringInput),
replaceTagsWithValuesInternal(valuesForTags),
tap(protectAgainstMissingValues),
);

export default (
stringWithTags,
valuesForTags,
{ throwOnMissingTagValues = true } = {},
) =>
export const replaceTagsWithValuesUnsafe = stringWithTags => valuesForTags =>
pipeline(
stringWithTags,
tap(protectAgainstNonStringInput),
replaceTagsWithValues(valuesForTags),
throwOnMissingTagValues ? tap(protectAgainstMissingValues) : identity,
replaceTagsWithValuesInternal(valuesForTags),
);

const replaceTagWithValue = (stringWithTags, { tag, value }) => {
Expand Down
90 changes: 41 additions & 49 deletions packages/fp/src/replaceTagsWithValues/replaceTagsWithValues.test.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import replaceTagsWithValues from './replaceTagsWithValues';
import {
replaceTagsWithValues,
replaceTagsWithValuesUnsafe,
} from './replaceTagsWithValues';

describe('replaceTagsWithValues', () => {
it('replaces one tag in string', () => {
const actual = replaceTagsWithValues(
'some string "{someTag}" some more string',
{ someTag: 'some tag value' },
);
)({ someTag: 'some tag value' });

expect(actual).toBe('some string "some tag value" some more string');
});

it('replaces multiple tags in string', () => {
const actual = replaceTagsWithValues(
'some string "{someTag}" some more string "{someTag}" again',
{ someTag: 'some tag value' },
);
)({ someTag: 'some tag value' });

expect(actual).toBe(
'some string "some tag value" some more string "some tag value" again',
Expand All @@ -24,24 +25,23 @@ describe('replaceTagsWithValues', () => {
it('replaces multiple different tags in string', () => {
const actual = replaceTagsWithValues(
'some string "{someTag}" some more string "{someOtherTag}"',
{ someTag: 'some tag value', someOtherTag: 'some other tag value' },
);
)({ someTag: 'some tag value', someOtherTag: 'some other tag value' });

expect(actual).toBe(
'some string "some tag value" some more string "some other tag value"',
);
});

it('replaces nested tags in string', () => {
const actual = replaceTagsWithValues('some string "{some.nested.value}"', {
const actual = replaceTagsWithValues('some string "{some.nested.value}"')({
some: { nested: { value: 'some nested tag value' } },
});

expect(actual).toBe('some string "some nested tag value"');
});

it('given tagged value is object, replaces with stringified object', () => {
const actual = replaceTagsWithValues('some string "{some}"', {
const actual = replaceTagsWithValues('some string "{some}"')({
some: { nested: { value: 'some nested tag value' } },
});

Expand All @@ -51,7 +51,7 @@ describe('replaceTagsWithValues', () => {
});

it('given tagged value is array, replaces with stringified array', () => {
const actual = replaceTagsWithValues('some string "{some}"', {
const actual = replaceTagsWithValues('some string "{some}"')({
some: ['array-value', 'other-array-value'],
});

Expand All @@ -60,18 +60,17 @@ describe('replaceTagsWithValues', () => {

it('given non-string input, throws', () => {
expect(() => {
replaceTagsWithValues({ not: 'string' }, {});
replaceTagsWithValues({ not: 'string' })({});
}).toThrow('Non-string input encountered.');
});

it('given not enough values for tags, throws', () => {
expect(() => {
replaceTagsWithValues(
'some string "{someTag}" some more string "{someTagWithoutValue}" "{someOtherTagWithoutValue}"',
{
someTag: 'some tag value',
},
);
)({
someTag: 'some tag value',
});
}).toThrow(
'Missing value for "{someTagWithoutValue}", "{someOtherTagWithoutValue}".',
);
Expand All @@ -81,27 +80,24 @@ describe('replaceTagsWithValues', () => {
expect(() => {
replaceTagsWithValues(
'some string "{someTag}" some more string "{someTagWithUndefinedValue}" "{someOtherTagWithUndefinedValue}"',
{
someTag: 'some tag value',
someTagWithUndefinedValue: undefined,
someOtherTagWithUndefinedValue: undefined,
},
);
)({
someTag: 'some tag value',
someTagWithUndefinedValue: undefined,
someOtherTagWithUndefinedValue: undefined,
});
}).toThrow(
'Missing value for "{someTagWithUndefinedValue}", "{someOtherTagWithUndefinedValue}".',
);
});

it('given undefined values for tags but throwing on missing values is omitted, does not alter tags with missing values', () => {
const actual = replaceTagsWithValues(
const actual = replaceTagsWithValuesUnsafe(
'some string "{someTag}" some more string "{someTagWithUndefinedValue}" "{someOtherTagWithUndefinedValue}"',
{
someTag: 'some tag value',
someTagWithUndefinedValue: undefined,
someOtherTagWithUndefinedValue: undefined,
},
{ throwOnMissingTagValues: false },
);
)({
someTag: 'some tag value',
someTagWithUndefinedValue: undefined,
someOtherTagWithUndefinedValue: undefined,
});

expect(actual).toEqual(
'some string "some tag value" some more string "{someTagWithUndefinedValue}" "{someOtherTagWithUndefinedValue}"',
Expand All @@ -111,33 +107,30 @@ describe('replaceTagsWithValues', () => {
it('given null values for tags, replaces to empty string', () => {
const actual = replaceTagsWithValues(
'some string "{someTagWithNullValue}"',
{
someTagWithNullValue: null,
},
);
)({
someTagWithNullValue: null,
});

expect(actual).toBe('some string ""');
});

it('given empty string values for tags, replaces to empty string', () => {
const actual = replaceTagsWithValues(
'some string "{someTagWithEmptyStringValue}"',
{
someTagWithEmptyStringValue: '',
},
);
)({
someTagWithEmptyStringValue: '',
});

expect(actual).toBe('some string ""');
});

it('given value containing another tag, replaces recursively until tag has value', () => {
const actual = replaceTagsWithValues(
'some string "{someTagContainingAnotherTagAsValue}"',
{
someTagContainingAnotherTagAsValue: '{otherTag}',
otherTag: 'some-value',
},
);
)({
someTagContainingAnotherTagAsValue: '{otherTag}',
otherTag: 'some-value',
});

expect(actual).toBe('some string "some-value"');
});
Expand All @@ -146,13 +139,12 @@ describe('replaceTagsWithValues', () => {
const actual = () =>
replaceTagsWithValues(
'some string "{someTagContainingAnotherTagAsValue}"',
{
someTagContainingAnotherTagAsValue:
'{otherTagContainingOriginalTagAsValue}',
otherTagContainingOriginalTagAsValue:
'{someTagContainingAnotherTagAsValue}',
},
);
)({
someTagContainingAnotherTagAsValue:
'{otherTagContainingOriginalTagAsValue}',
otherTagContainingOriginalTagAsValue:
'{someTagContainingAnotherTagAsValue}',
});

expect(actual).toThrow();
});
Expand Down

0 comments on commit 3ff26b1

Please sign in to comment.