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

chore: Move stringUtils to @studio/pure-functions #13918

Merged
merged 1 commit into from
Oct 25, 2024
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
5 changes: 2 additions & 3 deletions frontend/app-development/utils/metadataUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import type {
DataModelMetadataJson,
DataModelMetadataXsd,
} from 'app-shared/types/DataModelMetadata';
import { replaceEnd } from 'app-shared/utils/stringUtils';
import { ArrayUtils } from '@studio/pure-functions';
import { ArrayUtils, StringUtils } from '@studio/pure-functions';
import type { MetadataOption } from '../types/MetadataOption';
import type { MetadataOptionsGroup } from '../types/MetadataOptionsGroup';
import { removeSchemaExtension } from 'app-shared/utils/filenameUtils';
Expand All @@ -23,7 +22,7 @@ export const filterOutXsdDataIfJsonDataExist = (
({ fileName }) =>
!jsonData.find(
({ fileName: jsonFileName }) =>
jsonFileName === replaceEnd(fileName, '.xsd', '.schema.json'),
jsonFileName === StringUtils.replaceEnd(fileName, '.xsd', '.schema.json'),
),
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,56 @@ describe('StringUtils', () => {
expect(input).toBe('abc/def/ghi');
});
});

describe('replaceEnd', () => {
it('Replaces the given substring with the given replacement at the end of the string', () => {
expect(StringUtils.replaceEnd('abc/def/ghi', 'ghi', 'xyz')).toBe('abc/def/xyz');
});

it('Does not replace the given substring other places than at the end', () => {
expect(StringUtils.replaceEnd('abcdefghi', 'abc', 'xyz')).toBe('abcdefghi');
expect(StringUtils.replaceEnd('abcdefghi', 'def', 'xyz')).toBe('abcdefghi');
expect(StringUtils.replaceEnd('abcdefghidef', 'def', 'xyz')).toBe('abcdefghixyz');
});
});

describe('replaceStart', () => {
it('Replaces the given substring with the given replacement at the start of the string', () => {
expect(StringUtils.replaceStart('abc/def/ghi', 'abc', 'xyz')).toBe('xyz/def/ghi');
});

it('Does not replace the given substring other places than at the start', () => {
expect(StringUtils.replaceStart('abcdefghi', 'ghi', 'xyz')).toBe('abcdefghi');
expect(StringUtils.replaceStart('abcdefghi', 'def', 'xyz')).toBe('abcdefghi');
expect(StringUtils.replaceStart('defabcdefghi', 'def', 'xyz')).toBe('xyzabcdefghi');
});
});

describe('substringBeforeLast', () => {
it('Returns substring before last occurrence of separator', () => {
expect(StringUtils.substringBeforeLast('abc/def/ghi', '/')).toBe('abc/def');
});

it('Returns whole string if separator is not found', () => {
expect(StringUtils.substringBeforeLast('abc', '/')).toBe('abc');
});

it('Returns whole string if there are no characters before the last separator', () => {
expect(StringUtils.substringBeforeLast('/abc', '/')).toBe('');
});
});

describe('substringAfterLast', () => {
it('Returns substring after last occurrence of separator', () => {
expect(StringUtils.substringAfterLast('abc/def/ghi', '/')).toBe('ghi');
});

it('Returns whole string if separator is not found', () => {
expect(StringUtils.substringAfterLast('abc', '/')).toBe('abc');
});

it('Returns empty string if there are no characters after the last separator', () => {
expect(StringUtils.substringAfterLast('abc/def/', '/')).toBe('');
});
});
});
46 changes: 46 additions & 0 deletions frontend/libs/studio-pure-functions/src/StringUtils/StringUtils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { ArrayUtils } from '../ArrayUtils';

export class StringUtils {
/**
* Removes any of the given substrings from the start of the string.
Expand Down Expand Up @@ -32,4 +34,48 @@ export class StringUtils {
}
return str;
};

/**
* Replaces the given substring with the given replacement at the end of the string.
* If the substring does not appear at the end of the string, the string is returned unchanged.
* @param str The string to search in.
* @param substring The substring to search for.
* @param replacement The replacement to replace the substring with.
* @returns The string with the substring replaced at the end.
*/
static replaceEnd = (str: string, substring: string, replacement: string): string =>
str.replace(new RegExp(substring + '$'), replacement);

/**
* Replaces the given substring with the given replacement at the start of the string.
* If the substring does not appear at the start of the string, the string is returned unchanged.
* @param str The string to search in.
* @param substring The substring to search for.
* @param replacement The replacement to replace the substring with.
* @returns The string with the substring replaced at the start.
*/
static replaceStart = (str: string, substring: string, replacement: string): string => {
if (str.startsWith(substring)) {
return replacement + str.slice(substring.length);
}
return str;
};

/**
* Returns substring before last occurrence of separator.
* @param str The string to search in.
* @param separator The separator to search for.
* @returns The substring before the last occurrence of the given separator.
*/
static substringBeforeLast = (str: string, separator: string): string =>
str.includes(separator) ? str.substring(0, str.lastIndexOf(separator)) : str;

/**
* Returns substring after last occurrence of separator.
* @param str The string to search in.
* @param separator The separator to search for.
* @returns The substring after the last occurrence of the given separator.
*/
static substringAfterLast = (str: string, separator: string): string =>
ArrayUtils.last(str.split(separator)) || '';
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import {
import { ROOT_POINTER, UNIQUE_POINTER_PREFIX } from '../constants';
import type { ReferenceNode } from '../../types/ReferenceNode';
import { ObjectUtils, ArrayUtils, StringUtils } from '@studio/pure-functions';
import { replaceStart } from 'app-shared/utils/stringUtils';
import {
createDefinitionPointer,
createPropertyPointer,
Expand Down Expand Up @@ -375,7 +374,7 @@ export class SchemaModel extends SchemaModelBase {
const node = this.getNodeBySchemaPointer(newPointer); // Expects the node map to be updated
if (isFieldOrCombination(node) && node.children) {
const makeNewPointer = (schemaPointer: string) =>
replaceStart(schemaPointer, oldPointer, newPointer);
StringUtils.replaceStart(schemaPointer, oldPointer, newPointer);
node.children.forEach((childPointer) => {
const newPointer = makeNewPointer(childPointer);
this.changePointer(childPointer, newPointer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ import { expect } from '@jest/globals';
import { CombinationKind, FieldType, Keyword, ObjectKind, StrRestrictionKey } from '../../types';
import { ROOT_POINTER } from '../constants';
import { getPointers } from '../mappers/getPointers';
import { substringAfterLast, substringBeforeLast } from 'app-shared/utils/stringUtils';
import type { KeyValuePairs } from 'app-shared/types/KeyValuePairs';
import { validateTestUiSchema } from '../../../test/validateTestUiSchema';
import { SchemaModel } from '../SchemaModel';
import type { FieldNode } from '../../types/FieldNode';
import type { ReferenceNode } from '../../types/ReferenceNode';
import type { CombinationNode } from '../../types/CombinationNode';
import { StringUtils } from '@studio/pure-functions';

describe('ui-schema-reducers', () => {
let result: SchemaModel;
Expand All @@ -73,7 +73,7 @@ describe('ui-schema-reducers', () => {
it('Converts a property to a root level definition', () => {
const { schemaPointer } = stringNodeMock;
result = promoteProperty(createNewModelMock(), schemaPointer);
const expectedPointer = `${ROOT_POINTER}/$defs/${substringAfterLast(schemaPointer, '/')}`;
const expectedPointer = `${ROOT_POINTER}/$defs/${StringUtils.substringAfterLast(schemaPointer, '/')}`;
expect(getPointers(result.asArray())).toContain(expectedPointer);
expect(result.getNodeBySchemaPointer(expectedPointer)).toMatchObject({
fieldType: stringNodeMock.fieldType,
Expand Down Expand Up @@ -223,7 +223,7 @@ describe('ui-schema-reducers', () => {
const name = 'new name';
const callback = jest.fn();
const args: SetPropertyNameArgs = { path: schemaPointer, name, callback };
const expectedPointer = substringBeforeLast(schemaPointer, '/') + '/' + name;
const expectedPointer = StringUtils.substringBeforeLast(schemaPointer, '/') + '/' + name;

it('Sets the name of the given property', () => {
result = setPropertyName(createNewModelMock(), args);
Expand Down
60 changes: 0 additions & 60 deletions frontend/packages/shared/src/utils/stringUtils.test.ts

This file was deleted.

45 changes: 0 additions & 45 deletions frontend/packages/shared/src/utils/stringUtils.ts

This file was deleted.

Loading