From 41f50b1ca06441acf703b8abcf283dd7c1ca3442 Mon Sep 17 00:00:00 2001 From: Matt Carroll Date: Mon, 26 Aug 2024 16:27:33 +1000 Subject: [PATCH 1/5] ON-43061 # Added processInjectableResource to submissionService --- CHANGELOG.md | 4 + src/replaceCustomValues.ts | 174 +++++++++++++++++++++++++++++++++++++ 2 files changed, 178 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13725bf..69036c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +### Added + +- `submissionService.processInjectableResource()` + ## [7.0.0] - 2024-08-13 ### Removed diff --git a/src/replaceCustomValues.ts b/src/replaceCustomValues.ts index 8baa4b5..2735873 100644 --- a/src/replaceCustomValues.ts +++ b/src/replaceCustomValues.ts @@ -694,3 +694,177 @@ export function replaceInjectablesWithSubmissionValues( hadAllInjectablesReplaced, } } + +/** + * Process a resource with injectable element values to turn a single resource + * (could be a single) into multiple resources. e.g. `"{ELEMENT:Parent_Name}: + * {ELEMENT:Children|Child_Name}"` with the following submission data: + * + * ```json + * { + * "Parent_Name": "John", + * "Children": [ + * { + * "Child_Name": "Jane" + * }, + * { + * "Child_Name": "Tom" + * } + * ] + * } + * ``` + * + * Would result in the following resources: + * + * - `"John: Jane"` + * - `"John: Tom"` + * + * #### Example + * + * ```js + * const emailAddresses = processInjectableResource( + * '{ELEMENT:People|Email_Address}', + * { + * People: [ + * { + * Email_Address: 'user@oneblink.io', + * }, + * { + * Email_Address: 'admin@oneblink.io', + * }, + * ], + * }, + * [ + * { + * id: '18dcd3e0-6e2f-462e-803b-e24562d9fa6d', + * type: 'repeatableSet', + * name: 'People', + * label: 'People', + * elements: [ + * { + * id: 'd0902113-3f77-4070-adbd-ca3ae95ce091', + * type: 'email', + * name: 'Email_Address', + * label: 'Email_Address', + * }, + * ], + * }, + * ], + * (resource, submission, formElements) => { + * const { text } = replaceInjectablesWithElementValues(resource, { + * submission, + * formElements, + * // other options + * }) + * return text + * }, + * ) + * // emailAddresses === ["user@oneblink.io", "admin@oneblink.io"] + * ``` + * + * @param resource The resource that contains properties that support injection + * or a string + * @param submission The form submission data to process + * @param formElements The form elements to process + * @param injector A function to inject values, this allows custom formatters to + * be used. Return `undefined` to prevent the injection from recursively + * continuing. + * @param replacer An optional function to replace nested injectables when + * creating multiple resources from repeatable sets. Only required if the + * `resource` param is not a `string`. + * @returns + */ +export function processInjectableResource( + resource: T, + submission: SubmissionTypes.S3SubmissionData['submission'], + formElements: FormTypes.FormElement[], + injector: ( + resource: T, + submission: SubmissionTypes.S3SubmissionData['submission'], + formElements: FormTypes.FormElement[], + ) => + | [injectedText: string, resourceKey: string, newResource: T] + | string + | undefined, + replacer: (resource: T, replaceAll: (resourceText: string) => string) => T = ( + resource, + replaceAll, + ) => replaceAll(String(resource)) as T, +): Map { + const newResources: Map = new Map() + + const injectorResult = injector(resource, submission, formElements) + if (!injectorResult) { + return newResources + } + + const [text, resourceKey, newResource] = + typeof injectorResult === 'string' + ? [injectorResult, injectorResult, injectorResult as T] + : injectorResult + + // Find nested form elements + const matches: Map = new Map() + matchElementsTagRegex( + { + text, + excludeNestedElements: false, + }, + ({ elementName }) => { + const [repeatableSetElementName, ...elementNames] = elementName.split('|') + matches.set(repeatableSetElementName, !!elementNames.length) + }, + ) + + if (matches.size) { + matches.forEach((hasNestedFormElements, repeatableSetElementName) => { + if (hasNestedFormElements) { + // Attempt to create a new resource for each entry in the repeatable set. + const entries = submission?.[repeatableSetElementName] + if (Array.isArray(entries)) { + const repeatableSetElement = findFormElement( + formElements, + (formElement) => { + return ( + 'name' in formElement && + formElement.name === repeatableSetElementName + ) + }, + ) + if ( + repeatableSetElement && + 'elements' in repeatableSetElement && + Array.isArray(repeatableSetElement.elements) + ) { + for (const entry of entries) { + const replacedResource = replacer(newResource, (resourceText) => { + return resourceText.replaceAll( + `{ELEMENT:${repeatableSetElementName}|`, + '{ELEMENT:', + ) + }) + const nestedResources = processInjectableResource( + replacedResource, + entry, + repeatableSetElement.elements, + injector, + replacer, + ) + if (nestedResources.size) { + nestedResources.forEach((nestedResource, nestedResourceKey) => { + if (!newResources.has(nestedResourceKey)) { + newResources.set(nestedResourceKey, nestedResource) + } + }) + } + } + } + } + } + }) + } else { + newResources.set(resourceKey, newResource) + } + + return newResources +} From aacbbe821d9b7d9e17fa238468bf7ee7555e254b Mon Sep 17 00:00:00 2001 From: Matt Carroll Date: Tue, 27 Aug 2024 10:26:44 +1000 Subject: [PATCH 2/5] ON-43061 # Added unit tests for processInjectableResource --- src/replaceCustomValues.ts | 15 +- .../submissionService.test.ts.snap | 80 +++++ tests/submissionService.test.ts | 338 +++++++++++++++++- 3 files changed, 425 insertions(+), 8 deletions(-) create mode 100644 tests/__snapshots__/submissionService.test.ts.snap diff --git a/src/replaceCustomValues.ts b/src/replaceCustomValues.ts index 2735873..5c0910d 100644 --- a/src/replaceCustomValues.ts +++ b/src/replaceCustomValues.ts @@ -697,18 +697,19 @@ export function replaceInjectablesWithSubmissionValues( /** * Process a resource with injectable element values to turn a single resource - * (could be a single) into multiple resources. e.g. `"{ELEMENT:Parent_Name}: - * {ELEMENT:Children|Child_Name}"` with the following submission data: + * (could be a single) into multiple resources. e.g. + * `"{ELEMENT:Children|Child_Name} {ELEMENT:Family_Name}"` with the following + * submission data: * * ```json * { - * "Parent_Name": "John", + * "Family_Name": "Smith", * "Children": [ * { - * "Child_Name": "Jane" + * "Child_Name": "John" * }, * { - * "Child_Name": "Tom" + * "Child_Name": "Jane" * } * ] * } @@ -716,8 +717,8 @@ export function replaceInjectablesWithSubmissionValues( * * Would result in the following resources: * - * - `"John: Jane"` - * - `"John: Tom"` + * - `"John Smith"` + * - `"Jane Smith"` * * #### Example * diff --git a/tests/__snapshots__/submissionService.test.ts.snap b/tests/__snapshots__/submissionService.test.ts.snap new file mode 100644 index 0000000..6f99d83 --- /dev/null +++ b/tests/__snapshots__/submissionService.test.ts.snap @@ -0,0 +1,80 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`processInjectableResource should correctly replace nested injectables 1`] = ` +Map { + "John is part of the Smith family" => "John is part of the Smith family", + "Jane is part of the Smith family" => "Jane is part of the Smith family", +} +`; + +exports[`processInjectableResource should handle missing element values gracefully 1`] = `Map {}`; + +exports[`processInjectableResource should handle multiple replacements correctly 1`] = ` +Map { + "Smith Smith" => "Smith Smith", +} +`; + +exports[`processInjectableResource should handle single element without iteration 1`] = ` +Map { + "Smith" => "Smith", +} +`; + +exports[`processInjectableResource should replace injectable values correctly 1`] = ` +Map { + "John Smith" => "John Smith", + "Jane Smith" => "Jane Smith", +} +`; + +exports[`processInjectableResource should replace injectable values correctly when resource is not a string 1`] = ` +[ + { + "book_title": "The Adventures of Superman", + "favorite_sentence": "It was a bright cold day in April, and the clocks were striking thirteen.", + }, + { + "book_title": "The Adventures of Wonder Woman", + "favorite_sentence": "It was a bright cold day in April, and the clocks were striking thirteen.", + }, + { + "book_title": "The Mysterious Case of Sherlock Holmes", + "favorite_sentence": "Elementary, my dear Watson.", + }, + { + "book_title": "The Mysterious Case of Hercule Poirot", + "favorite_sentence": "Elementary, my dear Watson.", + }, + { + "book_title": "Strange Times in Gotham", + "favorite_sentence": "It was the best of times, it was the worst of times.", + }, + { + "book_title": "Strange Times in Metropolis", + "favorite_sentence": "It was the best of times, it was the worst of times.", + }, + { + "book_title": "The Journey of Superman", + "favorite_sentence": "Not all those who wander are lost.", + }, + { + "book_title": "The Journey of Wonder Woman", + "favorite_sentence": "Not all those who wander are lost.", + }, + { + "book_title": "Brave Nights", + "favorite_sentence": "To be, or not to be, that is the question.", + }, + { + "book_title": "Mysterious Nights", + "favorite_sentence": "To be, or not to be, that is the question.", + }, +] +`; + +exports[`processInjectableResource should return an empty array if no injectables are present 1`] = ` +Map { + "No injectables here" => "No injectables here", +} +`; diff --git a/tests/submissionService.test.ts b/tests/submissionService.test.ts index 289e118..5618b82 100644 --- a/tests/submissionService.test.ts +++ b/tests/submissionService.test.ts @@ -1,8 +1,13 @@ -import { FormTypes, ScheduledTasksTypes } from '@oneblink/types' +import { + FormTypes, + ScheduledTasksTypes, + SubmissionTypes, +} from '@oneblink/types' import { replaceInjectablesWithElementValues, replaceInjectablesWithSubmissionValues, getElementSubmissionValue, + processInjectableResource, } from '../src/submissionService' describe('replaceInjectablesWithSubmissionValues()', () => { @@ -585,3 +590,334 @@ describe('replaceInjectablesWithSubmissionValues()', () => { }) }) }) + +describe('processInjectableResource', () => { + const formElements: FormTypes.FormElement[] = [ + { + id: 'element1', + name: 'Family_Name', + type: 'text', + label: 'Family Name', + readOnly: false, + required: false, + conditionallyShow: false, + requiresAllConditionallyShowPredicates: false, + isElementLookup: false, + isDataLookup: false, + }, + { + id: 'element2', + type: 'repeatableSet', + name: 'Children', + label: 'Children', + conditionallyShow: false, + elements: [ + { + id: 'element3', + name: 'Child_Name', + type: 'text', + label: 'Child Name', + readOnly: false, + required: false, + conditionallyShow: false, + requiresAllConditionallyShowPredicates: false, + isElementLookup: false, + isDataLookup: false, + }, + ], + }, + ] + + const submission: SubmissionTypes.S3SubmissionData['submission'] = { + Family_Name: 'Smith', + Children: [ + { + Child_Name: 'John', + }, + { + Child_Name: 'Jane', + }, + ], + } + + const injector = ( + text: string, + entry: SubmissionTypes.S3SubmissionData['submission'], + elements: FormTypes.FormElement[], + ) => { + return replaceInjectablesWithElementValues(text, { + userProfile: undefined, + task: undefined, + taskGroup: undefined, + taskGroupInstance: undefined, + formatDateTime: (value) => new Date(value).toString(), + formatDate: (value) => new Date(value).toDateString(), + formatTime: (value) => new Date(value).toTimeString(), + formatNumber: (value) => value.toString(), + formatCurrency: (value) => value.toFixed(2), + submission: entry, + formElements: elements, + excludeNestedElements: true, + }).text + } + + it('should replace injectable values correctly', () => { + const resource = '{ELEMENT:Children|Child_Name} {ELEMENT:Family_Name}' + const result = processInjectableResource( + resource, + submission, + formElements, + injector, + ) + + expect(result).toMatchSnapshot() + }) + + it('should handle single element without iteration', () => { + const resource = '{ELEMENT:Family_Name}' + const result = processInjectableResource( + resource, + submission, + formElements, + injector, + ) + + expect(result).toMatchSnapshot() + }) + + it('should handle missing element values gracefully', () => { + const resource = '{ELEMENT:Non_Existing_Element}' + const result = processInjectableResource( + resource, + submission, + formElements, + injector, + ) + + expect(result).toMatchSnapshot() + }) + + it('should correctly replace nested injectables', () => { + const resource = + '{ELEMENT:Children|Child_Name} is part of the {ELEMENT:Family_Name} family' + const result = processInjectableResource( + resource, + submission, + formElements, + injector, + ) + + expect(result).toMatchSnapshot() + }) + + it('should return an empty array if no injectables are present', () => { + const resource = 'No injectables here' + const result = processInjectableResource( + resource, + submission, + formElements, + injector, + ) + + expect(result).toMatchSnapshot() + }) + + it('should handle multiple replacements correctly', () => { + const resource = '{ELEMENT:Family_Name} {ELEMENT:Family_Name}' + const result = processInjectableResource( + resource, + submission, + formElements, + injector, + ) + + expect(result).toMatchSnapshot() + }) + + it('should replace injectable values correctly when resource is not a string', () => { + type Book = { + book_title: string + favorite_sentence: string + } + const books: Book[] = [ + { + book_title: 'The Adventures of {ELEMENT:heros|name}', + favorite_sentence: + 'It was a bright cold day in April, and the clocks were striking thirteen.', + }, + { + book_title: 'The Mysterious Case of {ELEMENT:detectives|name}', + favorite_sentence: 'Elementary, my dear Watson.', + }, + { + book_title: 'Strange Times in {ELEMENT:cities|name}', + favorite_sentence: + 'It was the best of times, it was the worst of times.', + }, + { + book_title: 'The Journey of {ELEMENT:heros|name}', + favorite_sentence: 'Not all those who wander are lost.', + }, + { + book_title: '{ELEMENT:adjectives|name} Nights', + favorite_sentence: 'To be, or not to be, that is the question.', + }, + ] + + const result = books.reduce((memo, book) => { + const map = processInjectableResource( + book, + { + heros: [{ name: 'Superman' }, { name: 'Wonder Woman' }], + detectives: [{ name: 'Sherlock Holmes' }, { name: 'Hercule Poirot' }], + cities: [{ name: 'Gotham' }, { name: 'Metropolis' }], + adjectives: [{ name: 'Brave' }, { name: 'Mysterious' }], + }, + [ + { + id: 'element1', + type: 'repeatableSet', + name: 'heros', + label: 'Heros', + conditionallyShow: false, + elements: [ + { + id: 'element2', + name: 'name', + type: 'text', + label: 'Name', + readOnly: false, + required: false, + conditionallyShow: false, + requiresAllConditionallyShowPredicates: false, + isElementLookup: false, + isDataLookup: false, + }, + ], + }, + { + id: 'element3', + type: 'repeatableSet', + name: 'detectives', + label: 'Detectives', + conditionallyShow: false, + elements: [ + { + id: 'element4', + name: 'name', + type: 'text', + label: 'Name', + readOnly: false, + required: false, + conditionallyShow: false, + requiresAllConditionallyShowPredicates: false, + isElementLookup: false, + isDataLookup: false, + }, + ], + }, + { + id: 'element3', + type: 'repeatableSet', + name: 'detectives', + label: 'Detectives', + conditionallyShow: false, + elements: [ + { + id: 'element4', + name: 'name', + type: 'text', + label: 'Name', + readOnly: false, + required: false, + conditionallyShow: false, + requiresAllConditionallyShowPredicates: false, + isElementLookup: false, + isDataLookup: false, + }, + ], + }, + { + id: 'element5', + type: 'repeatableSet', + name: 'cities', + label: 'Cities', + conditionallyShow: false, + elements: [ + { + id: 'element6', + name: 'name', + type: 'text', + label: 'Name', + readOnly: false, + required: false, + conditionallyShow: false, + requiresAllConditionallyShowPredicates: false, + isElementLookup: false, + isDataLookup: false, + }, + ], + }, + { + id: 'element7', + type: 'repeatableSet', + name: 'adjectives', + label: 'Adjectives', + conditionallyShow: false, + elements: [ + { + id: 'element8', + name: 'name', + type: 'text', + label: 'Name', + readOnly: false, + required: false, + conditionallyShow: false, + requiresAllConditionallyShowPredicates: false, + isElementLookup: false, + isDataLookup: false, + }, + ], + }, + ], + (book, entry, elements) => { + const book_title = replaceInjectablesWithElementValues( + book.book_title, + { + userProfile: undefined, + task: undefined, + taskGroup: undefined, + taskGroupInstance: undefined, + formatDateTime: (value) => new Date(value).toString(), + formatDate: (value) => new Date(value).toDateString(), + formatTime: (value) => new Date(value).toTimeString(), + formatNumber: (value) => value.toString(), + formatCurrency: (value) => value.toFixed(2), + submission: entry, + formElements: elements, + excludeNestedElements: true, + }, + ).text + return [ + book_title, + book_title, + { + ...book, + book_title, + } as Book, + ] + }, + (book, replaceAll) => { + return { + ...book, + book_title: replaceAll(book.book_title), + } + }, + ) + + return [...memo, ...map.values()] + }, []) + + expect(result).toMatchSnapshot() + }) +}) From 52d94997401c2b5d6ec789286b006594cb0e3930 Mon Sep 17 00:00:00 2001 From: Matt Carroll Date: Wed, 28 Aug 2024 10:24:42 +1000 Subject: [PATCH 3/5] Update tests/submissionService.test.ts Co-authored-by: jdawg093 <49189518+jdawg093@users.noreply.github.com> --- tests/submissionService.test.ts | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/tests/submissionService.test.ts b/tests/submissionService.test.ts index 5618b82..0ab3583 100644 --- a/tests/submissionService.test.ts +++ b/tests/submissionService.test.ts @@ -816,27 +816,6 @@ describe('processInjectableResource', () => { }, ], }, - { - id: 'element3', - type: 'repeatableSet', - name: 'detectives', - label: 'Detectives', - conditionallyShow: false, - elements: [ - { - id: 'element4', - name: 'name', - type: 'text', - label: 'Name', - readOnly: false, - required: false, - conditionallyShow: false, - requiresAllConditionallyShowPredicates: false, - isElementLookup: false, - isDataLookup: false, - }, - ], - }, { id: 'element5', type: 'repeatableSet', From 490f0c8cf840e1d648b7eab8e6999405ec811681 Mon Sep 17 00:00:00 2001 From: Matt Carroll Date: Wed, 28 Aug 2024 12:03:45 +1000 Subject: [PATCH 4/5] ON-43061 # Changed parameter names for processInjectablesInCustomResource --- CHANGELOG.md | 2 +- src/replaceCustomValues.ts | 111 +++++++++++------- .../submissionService.test.ts.snap | 14 +-- tests/submissionService.test.ts | 58 ++++----- 4 files changed, 108 insertions(+), 77 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 69036c1..21c871d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Added -- `submissionService.processInjectableResource()` +- `submissionService.processInjectablesInCustomResource()` ## [7.0.0] - 2024-08-13 diff --git a/src/replaceCustomValues.ts b/src/replaceCustomValues.ts index 5c0910d..0d5b447 100644 --- a/src/replaceCustomValues.ts +++ b/src/replaceCustomValues.ts @@ -723,9 +723,9 @@ export function replaceInjectablesWithSubmissionValues( * #### Example * * ```js - * const emailAddresses = processInjectableResource( - * '{ELEMENT:People|Email_Address}', - * { + * const emailAddresses = processInjectablesInCustomResource({ + * resource: '{ELEMENT:People|Email_Address}', + * submission: { * People: [ * { * Email_Address: 'user@oneblink.io', @@ -735,7 +735,7 @@ export function replaceInjectablesWithSubmissionValues( * }, * ], * }, - * [ + * formElements: [ * { * id: '18dcd3e0-6e2f-462e-803b-e24562d9fa6d', * type: 'repeatableSet', @@ -751,50 +751,78 @@ export function replaceInjectablesWithSubmissionValues( * ], * }, * ], - * (resource, submission, formElements) => { + * replaceRootInjectables: (resource, submission, formElements) => { * const { text } = replaceInjectablesWithElementValues(resource, { * submission, * formElements, + * excludeNestedElements: true, * // other options * }) * return text * }, - * ) + * }) * // emailAddresses === ["user@oneblink.io", "admin@oneblink.io"] * ``` * - * @param resource The resource that contains properties that support injection - * or a string - * @param submission The form submission data to process - * @param formElements The form elements to process - * @param injector A function to inject values, this allows custom formatters to - * be used. Return `undefined` to prevent the injection from recursively - * continuing. - * @param replacer An optional function to replace nested injectables when - * creating multiple resources from repeatable sets. Only required if the - * `resource` param is not a `string`. + * @param options * @returns */ -export function processInjectableResource( - resource: T, - submission: SubmissionTypes.S3SubmissionData['submission'], - formElements: FormTypes.FormElement[], - injector: ( +export function processInjectablesInCustomResource({ + resource, + submission, + formElements, + replaceRootInjectables, + prepareNestedInjectables = (resource, preparer) => + preparer(String(resource)) as T, +}: { + /** The resource that contains properties that support injection or a string */ + resource: T + /** The form submission data to process */ + submission: SubmissionTypes.S3SubmissionData['submission'] + /** The form elements to process */ + formElements: FormTypes.FormElement[] + /** + * A function to inject values, this allows custom formatters to be used. + * Return `undefined` to prevent the injection from recursively continuing. + * + * @param resource The current resource that contains properties that support + * injection or a string + * @param submission The current form submission data to process (may be an + * entry in a repeatable set) + * @param formElements The current form elements to process (may be the + * elements from a repeatable set) + * @returns + */ + replaceRootInjectables: ( resource: T, submission: SubmissionTypes.S3SubmissionData['submission'], formElements: FormTypes.FormElement[], ) => | [injectedText: string, resourceKey: string, newResource: T] | string - | undefined, - replacer: (resource: T, replaceAll: (resourceText: string) => string) => T = ( - resource, - replaceAll, - ) => replaceAll(String(resource)) as T, -): Map { + | undefined + /** + * An optional function to replace nested injectables when creating multiple + * resources from repeatable sets. Only required if the `resource` param is + * not a `string`. + * + * @param resource The current resource that contains properties that support + * injection or a string + * @param preparer A function to prepare + * @returns + */ + prepareNestedInjectables?: ( + resource: T, + preparer: (resourceText: string) => string, + ) => T +}): Map { const newResources: Map = new Map() - const injectorResult = injector(resource, submission, formElements) + const injectorResult = replaceRootInjectables( + resource, + submission, + formElements, + ) if (!injectorResult) { return newResources } @@ -838,19 +866,22 @@ export function processInjectableResource( Array.isArray(repeatableSetElement.elements) ) { for (const entry of entries) { - const replacedResource = replacer(newResource, (resourceText) => { - return resourceText.replaceAll( - `{ELEMENT:${repeatableSetElementName}|`, - '{ELEMENT:', - ) - }) - const nestedResources = processInjectableResource( - replacedResource, - entry, - repeatableSetElement.elements, - injector, - replacer, + const replacedResource = prepareNestedInjectables( + newResource, + (resourceText) => { + return resourceText.replaceAll( + `{ELEMENT:${repeatableSetElementName}|`, + '{ELEMENT:', + ) + }, ) + const nestedResources = processInjectablesInCustomResource({ + resource: replacedResource, + submission: entry, + formElements: repeatableSetElement.elements, + replaceRootInjectables, + prepareNestedInjectables, + }) if (nestedResources.size) { nestedResources.forEach((nestedResource, nestedResourceKey) => { if (!newResources.has(nestedResourceKey)) { diff --git a/tests/__snapshots__/submissionService.test.ts.snap b/tests/__snapshots__/submissionService.test.ts.snap index 6f99d83..4ca5ab4 100644 --- a/tests/__snapshots__/submissionService.test.ts.snap +++ b/tests/__snapshots__/submissionService.test.ts.snap @@ -1,34 +1,34 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`processInjectableResource should correctly replace nested injectables 1`] = ` +exports[`processInjectablesInCustomResource should correctly replace nested injectables 1`] = ` Map { "John is part of the Smith family" => "John is part of the Smith family", "Jane is part of the Smith family" => "Jane is part of the Smith family", } `; -exports[`processInjectableResource should handle missing element values gracefully 1`] = `Map {}`; +exports[`processInjectablesInCustomResource should handle missing element values gracefully 1`] = `Map {}`; -exports[`processInjectableResource should handle multiple replacements correctly 1`] = ` +exports[`processInjectablesInCustomResource should handle multiple replacements correctly 1`] = ` Map { "Smith Smith" => "Smith Smith", } `; -exports[`processInjectableResource should handle single element without iteration 1`] = ` +exports[`processInjectablesInCustomResource should handle single element without iteration 1`] = ` Map { "Smith" => "Smith", } `; -exports[`processInjectableResource should replace injectable values correctly 1`] = ` +exports[`processInjectablesInCustomResource should replace injectable values correctly 1`] = ` Map { "John Smith" => "John Smith", "Jane Smith" => "Jane Smith", } `; -exports[`processInjectableResource should replace injectable values correctly when resource is not a string 1`] = ` +exports[`processInjectablesInCustomResource should replace injectable values correctly when resource is not a string 1`] = ` [ { "book_title": "The Adventures of Superman", @@ -73,7 +73,7 @@ exports[`processInjectableResource should replace injectable values correctly wh ] `; -exports[`processInjectableResource should return an empty array if no injectables are present 1`] = ` +exports[`processInjectablesInCustomResource should return an empty array if no injectables are present 1`] = ` Map { "No injectables here" => "No injectables here", } diff --git a/tests/submissionService.test.ts b/tests/submissionService.test.ts index 0ab3583..8f3d2ff 100644 --- a/tests/submissionService.test.ts +++ b/tests/submissionService.test.ts @@ -7,7 +7,7 @@ import { replaceInjectablesWithElementValues, replaceInjectablesWithSubmissionValues, getElementSubmissionValue, - processInjectableResource, + processInjectablesInCustomResource, } from '../src/submissionService' describe('replaceInjectablesWithSubmissionValues()', () => { @@ -591,7 +591,7 @@ describe('replaceInjectablesWithSubmissionValues()', () => { }) }) -describe('processInjectableResource', () => { +describe('processInjectablesInCustomResource', () => { const formElements: FormTypes.FormElement[] = [ { id: 'element1', @@ -640,7 +640,7 @@ describe('processInjectableResource', () => { ], } - const injector = ( + const replaceRootInjectables = ( text: string, entry: SubmissionTypes.S3SubmissionData['submission'], elements: FormTypes.FormElement[], @@ -663,36 +663,36 @@ describe('processInjectableResource', () => { it('should replace injectable values correctly', () => { const resource = '{ELEMENT:Children|Child_Name} {ELEMENT:Family_Name}' - const result = processInjectableResource( + const result = processInjectablesInCustomResource({ resource, submission, formElements, - injector, - ) + replaceRootInjectables, + }) expect(result).toMatchSnapshot() }) it('should handle single element without iteration', () => { const resource = '{ELEMENT:Family_Name}' - const result = processInjectableResource( + const result = processInjectablesInCustomResource({ resource, submission, formElements, - injector, - ) + replaceRootInjectables, + }) expect(result).toMatchSnapshot() }) it('should handle missing element values gracefully', () => { const resource = '{ELEMENT:Non_Existing_Element}' - const result = processInjectableResource( + const result = processInjectablesInCustomResource({ resource, submission, formElements, - injector, - ) + replaceRootInjectables, + }) expect(result).toMatchSnapshot() }) @@ -700,36 +700,36 @@ describe('processInjectableResource', () => { it('should correctly replace nested injectables', () => { const resource = '{ELEMENT:Children|Child_Name} is part of the {ELEMENT:Family_Name} family' - const result = processInjectableResource( + const result = processInjectablesInCustomResource({ resource, submission, formElements, - injector, - ) + replaceRootInjectables, + }) expect(result).toMatchSnapshot() }) it('should return an empty array if no injectables are present', () => { const resource = 'No injectables here' - const result = processInjectableResource( + const result = processInjectablesInCustomResource({ resource, submission, formElements, - injector, - ) + replaceRootInjectables, + }) expect(result).toMatchSnapshot() }) it('should handle multiple replacements correctly', () => { const resource = '{ELEMENT:Family_Name} {ELEMENT:Family_Name}' - const result = processInjectableResource( + const result = processInjectablesInCustomResource({ resource, submission, formElements, - injector, - ) + replaceRootInjectables, + }) expect(result).toMatchSnapshot() }) @@ -765,15 +765,15 @@ describe('processInjectableResource', () => { ] const result = books.reduce((memo, book) => { - const map = processInjectableResource( - book, - { + const map = processInjectablesInCustomResource({ + resource: book, + submission: { heros: [{ name: 'Superman' }, { name: 'Wonder Woman' }], detectives: [{ name: 'Sherlock Holmes' }, { name: 'Hercule Poirot' }], cities: [{ name: 'Gotham' }, { name: 'Metropolis' }], adjectives: [{ name: 'Brave' }, { name: 'Mysterious' }], }, - [ + formElements: [ { id: 'element1', type: 'repeatableSet', @@ -859,7 +859,7 @@ describe('processInjectableResource', () => { ], }, ], - (book, entry, elements) => { + replaceRootInjectables: (book, entry, elements) => { const book_title = replaceInjectablesWithElementValues( book.book_title, { @@ -886,13 +886,13 @@ describe('processInjectableResource', () => { } as Book, ] }, - (book, replaceAll) => { + prepareNestedInjectables: (book, preparer) => { return { ...book, - book_title: replaceAll(book.book_title), + book_title: preparer(book.book_title), } }, - ) + }) return [...memo, ...map.values()] }, []) From 57a1dcc35ba87bdb22219932838c4a287dbbbfa0 Mon Sep 17 00:00:00 2001 From: Matt Carroll Date: Wed, 28 Aug 2024 12:43:04 +1000 Subject: [PATCH 5/5] ON-43061 # Changed preparer to prepare --- src/replaceCustomValues.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/replaceCustomValues.ts b/src/replaceCustomValues.ts index 0d5b447..14142ff 100644 --- a/src/replaceCustomValues.ts +++ b/src/replaceCustomValues.ts @@ -772,8 +772,8 @@ export function processInjectablesInCustomResource({ submission, formElements, replaceRootInjectables, - prepareNestedInjectables = (resource, preparer) => - preparer(String(resource)) as T, + prepareNestedInjectables = (resource, prepare) => + prepare(String(resource)) as T, }: { /** The resource that contains properties that support injection or a string */ resource: T @@ -808,7 +808,8 @@ export function processInjectablesInCustomResource({ * * @param resource The current resource that contains properties that support * injection or a string - * @param preparer A function to prepare + * @param prepare A function to prepare the resource string(s) for another + * iteration * @returns */ prepareNestedInjectables?: (