From cb2dccb87dab757bc65a3069324bbc6a874b57f8 Mon Sep 17 00:00:00 2001 From: Ravi Varanasi Date: Sun, 3 Nov 2024 17:33:18 -0600 Subject: [PATCH 1/4] feat: add support to parse picklist values --- .../reflect-custom-field-sources.spec.ts | 46 +++++++++++++++++++ .../sobject/reflect-custom-field-source.ts | 27 ++++++++++- 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/src/core/reflection/sobject/__test__/reflect-custom-field-sources.spec.ts b/src/core/reflection/sobject/__test__/reflect-custom-field-sources.spec.ts index 0a621483..02e75eef 100644 --- a/src/core/reflection/sobject/__test__/reflect-custom-field-sources.spec.ts +++ b/src/core/reflection/sobject/__test__/reflect-custom-field-sources.spec.ts @@ -100,6 +100,52 @@ describe('when parsing custom field metadata', () => { assertEither(result, (data) => expect(data[0].type.description).toBe('A Photo URL field')); }); + test('can parse picklist values', async() => { + const unparsed: UnparsedCustomFieldBundle = { + type: 'customfield', + name: 'Status__c', + parentName: 'MyFirstObject__c', + filePath: 'src/field/Status__c.field-meta.xml', + content: ` + + + Status__c + false + + true + false + Status + Picklist + + true + + false + + Staging + false + + + + Active + false + + + + Inactive + false + + + + + `, + }; + + const result = await reflectCustomFieldSources([unparsed])(); + + assertEither(result, (data) => expect(data[0].type.description).toBe('Status')); + assertEither(result, (data) => expect(data[0].type.pickListValues).toEqual(['Staging', 'Active', 'Inactive'])); + }); + test('An error is returned when the XML is in an invalid format', async () => { const unparsed: UnparsedCustomFieldBundle = { type: 'customfield', diff --git a/src/core/reflection/sobject/reflect-custom-field-source.ts b/src/core/reflection/sobject/reflect-custom-field-source.ts index c42f78fc..afbf9e3f 100644 --- a/src/core/reflection/sobject/reflect-custom-field-source.ts +++ b/src/core/reflection/sobject/reflect-custom-field-source.ts @@ -15,6 +15,7 @@ export type CustomFieldMetadata = { label?: string | null; type?: string | null; parentName: string; + pickListValues: string[]; }; export function reflectCustomFieldSources( @@ -58,12 +59,34 @@ function validate(parsedResult: unknown): E.Either 'fullName' in each).map((each) => each.fullName as string); + } + } + } + + return []; +} + +function isCustomField(customField: object): customField is CustomFieldMetadata { + return (customField as CustomFieldMetadata).type != undefined; } function addName(metadata: CustomFieldMetadata, name: string): CustomFieldMetadata { From 19701456f3af2808052d02fa95bb61e99690f08f Mon Sep 17 00:00:00 2001 From: Ravi Varanasi Date: Sun, 3 Nov 2024 20:26:53 -0600 Subject: [PATCH 2/4] feat: render picklist values in doc template --- .../generating-custom-object-docs.spec.ts | 22 ++++++++++++- src/core/markdown/__test__/test-helpers.ts | 33 +++++++++++++++++++ .../markdown/adapters/type-to-renderable.ts | 1 + .../templates/custom-object-template.ts | 3 ++ .../sobject/reflect-custom-field-source.ts | 4 +-- src/core/renderables/types.d.ts | 1 + 6 files changed, 61 insertions(+), 3 deletions(-) diff --git a/src/core/markdown/__test__/generating-custom-object-docs.spec.ts b/src/core/markdown/__test__/generating-custom-object-docs.spec.ts index f08d0499..e1af6d39 100644 --- a/src/core/markdown/__test__/generating-custom-object-docs.spec.ts +++ b/src/core/markdown/__test__/generating-custom-object-docs.spec.ts @@ -1,6 +1,7 @@ import { extendExpect } from './expect-extensions'; import { customField, + customFieldPickListValues, customObjectGenerator, generateDocs, unparsedFieldBundleFromRawString, @@ -46,7 +47,7 @@ describe('Generates Custom Object documentation', () => { expect(result).documentationBundleHasLength(1); assertEither(result, (data) => expect(data).firstDocContains('`TestObject__c`')); }); - + it('displays the Fields heading if fields are present', async () => { const customObjectBundle = unparsedObjectBundleFromRawString({ rawContent: customObjectGenerator(), @@ -64,6 +65,25 @@ describe('Generates Custom Object documentation', () => { assertEither(result, (data) => expect(data).firstDocContains('## Fields')); }); + it('displays the pick list values name', async () => { + const customObjectBundle = unparsedObjectBundleFromRawString({ + rawContent: customObjectGenerator(), + filePath: 'src/object/TestObject__c.object-meta.xml', + }); + + const customFieldBundle = unparsedFieldBundleFromRawString({ + rawContent: customFieldPickListValues, + filePath: 'src/object/TestField__c.field-meta.xml', + parentName: 'TestObject__c', + }); + + const result = await generateDocs([customObjectBundle, customFieldBundle])(); + expect(result).documentationBundleHasLength(1); + assertEither(result, (data) => expect(data).firstDocContains('* Staging')); + assertEither(result, (data) => expect(data).firstDocContains('* Active')); + assertEither(result, (data) => expect(data).firstDocContains('* Inactive')); + }); + it('does not display the Fields heading if no fields are present', async () => { const input = unparsedObjectBundleFromRawString({ rawContent: customObjectGenerator(), diff --git a/src/core/markdown/__test__/test-helpers.ts b/src/core/markdown/__test__/test-helpers.ts index d884958f..c711414d 100644 --- a/src/core/markdown/__test__/test-helpers.ts +++ b/src/core/markdown/__test__/test-helpers.ts @@ -84,3 +84,36 @@ export const customField = ` Url A URL that points to a photo `; + +export const customFieldPickListValues = ` + + + Status__c + false + + true + false + Status + Picklist + + true + + false + + Staging + false + + + + Active + false + + + + Inactive + false + + + + +`; diff --git a/src/core/markdown/adapters/type-to-renderable.ts b/src/core/markdown/adapters/type-to-renderable.ts index 286a09b9..64f4dd09 100644 --- a/src/core/markdown/adapters/type-to-renderable.ts +++ b/src/core/markdown/adapters/type-to-renderable.ts @@ -281,6 +281,7 @@ function fieldMetadataToRenderable( description: field.description ? [field.description] : [], apiName: getApiName(field.name, config), fieldType: field.type, + pickListValues: field.pickListValues }; } diff --git a/src/core/markdown/templates/custom-object-template.ts b/src/core/markdown/templates/custom-object-template.ts index bedc7f41..d1af3bca 100644 --- a/src/core/markdown/templates/custom-object-template.ts +++ b/src/core/markdown/templates/custom-object-template.ts @@ -23,6 +23,9 @@ export const customObjectTemplate = ` **Type** *{{fieldType}}* +{{#each pickListValues}} +* {{this}} +{{/each}} {{/if}} {{#unless @last}}---{{/unless}} diff --git a/src/core/reflection/sobject/reflect-custom-field-source.ts b/src/core/reflection/sobject/reflect-custom-field-source.ts index afbf9e3f..91c38c87 100644 --- a/src/core/reflection/sobject/reflect-custom-field-source.ts +++ b/src/core/reflection/sobject/reflect-custom-field-source.ts @@ -66,7 +66,7 @@ function toCustomFieldMetadata(parserResult: { CustomField: unknown }): CustomFi }; const pickListValues = - isCustomField(customField) && customField.type === 'Picklist' ? toPickListValues(customField) : []; + hasType(customField) && customField.type?.toLowerCase() === 'picklist' ? toPickListValues(customField) : []; return { ...defaultValues, ...customField, type_name: 'customfield', pickListValues } as CustomFieldMetadata; } @@ -85,7 +85,7 @@ function toPickListValues(customField: object): string[] { return []; } -function isCustomField(customField: object): customField is CustomFieldMetadata { +function hasType(customField: object): customField is CustomFieldMetadata { return (customField as CustomFieldMetadata).type != undefined; } diff --git a/src/core/renderables/types.d.ts b/src/core/renderables/types.d.ts index cfdc58a8..aa3fc9ce 100644 --- a/src/core/renderables/types.d.ts +++ b/src/core/renderables/types.d.ts @@ -189,6 +189,7 @@ export type RenderableCustomField = { heading: string; apiName: string; description: RenderableContent[]; + pickListValues: string[]; type: 'field'; fieldType?: string | null; }; From f8f9bab155a9233e1211e1cfe5fbe459dd7e89a1 Mon Sep 17 00:00:00 2001 From: Ravi Varanasi Date: Mon, 4 Nov 2024 23:00:15 -0600 Subject: [PATCH 3/4] feat: render section as opposed to string[] --- .gitignore | 1 + src/core/markdown/adapters/type-to-renderable.ts | 8 +++++++- src/core/markdown/templates/custom-object-template.ts | 10 +++++++--- src/core/renderables/types.d.ts | 3 ++- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 5e8c19d7..4c28f20d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ npm-debug.log /.idea/ /dist/ /lib/ +.sfdx/ diff --git a/src/core/markdown/adapters/type-to-renderable.ts b/src/core/markdown/adapters/type-to-renderable.ts index 64f4dd09..050645bb 100644 --- a/src/core/markdown/adapters/type-to-renderable.ts +++ b/src/core/markdown/adapters/type-to-renderable.ts @@ -281,7 +281,13 @@ function fieldMetadataToRenderable( description: field.description ? [field.description] : [], apiName: getApiName(field.name, config), fieldType: field.type, - pickListValues: field.pickListValues + isPicklist: field.pickListValues.length > 0, + pickListValues: { + headingLevel: headingLevel + 1, + heading: 'Possible values are', + value: field.pickListValues + + } }; } diff --git a/src/core/markdown/templates/custom-object-template.ts b/src/core/markdown/templates/custom-object-template.ts index d1af3bca..18242a0b 100644 --- a/src/core/markdown/templates/custom-object-template.ts +++ b/src/core/markdown/templates/custom-object-template.ts @@ -23,9 +23,13 @@ export const customObjectTemplate = ` **Type** *{{fieldType}}* -{{#each pickListValues}} -* {{this}} -{{/each}} + +{{#if isPicklist}} + {{ heading headingLevel heading }} + {{#each pickListValues.value}} + * {{{this}}} + {{/each}} +{{/if}} {{/if}} {{#unless @last}}---{{/unless}} diff --git a/src/core/renderables/types.d.ts b/src/core/renderables/types.d.ts index aa3fc9ce..0b2ecec1 100644 --- a/src/core/renderables/types.d.ts +++ b/src/core/renderables/types.d.ts @@ -189,7 +189,8 @@ export type RenderableCustomField = { heading: string; apiName: string; description: RenderableContent[]; - pickListValues: string[]; + isPicklist: boolean; + pickListValues?: RenderableSection type: 'field'; fieldType?: string | null; }; From 2e58a937e825930be3957183b22ba153c3a06fd4 Mon Sep 17 00:00:00 2001 From: cesarParra Date: Tue, 5 Nov 2024 07:40:44 -0400 Subject: [PATCH 4/4] CR updates --- .../docs/custom-objects/Price_Component__c.md | 7 ++++++- .../docs/custom-objects/Sales_Order_Line__c.md | 6 +++++- src/core/markdown/adapters/type-to-renderable.ts | 8 +++----- src/core/markdown/templates/custom-object-template.ts | 10 +++++----- .../reflection/sobject/reflect-custom-field-source.ts | 6 +++--- src/core/renderables/types.d.ts | 1 - 6 files changed, 22 insertions(+), 16 deletions(-) diff --git a/examples/vitepress/docs/custom-objects/Price_Component__c.md b/examples/vitepress/docs/custom-objects/Price_Component__c.md index 053ccb3c..fa4be586 100644 --- a/examples/vitepress/docs/custom-objects/Price_Component__c.md +++ b/examples/vitepress/docs/custom-objects/Price_Component__c.md @@ -66,4 +66,9 @@ Use this when the Price Component represents a Flat Price. To represent a Percen **Type** -*Picklist* \ No newline at end of file +*Picklist* + +#### Possible values are +* List Price +* Surcharge +* Discount \ No newline at end of file diff --git a/examples/vitepress/docs/custom-objects/Sales_Order_Line__c.md b/examples/vitepress/docs/custom-objects/Sales_Order_Line__c.md index 041e94ce..bc1ac4f7 100644 --- a/examples/vitepress/docs/custom-objects/Sales_Order_Line__c.md +++ b/examples/vitepress/docs/custom-objects/Sales_Order_Line__c.md @@ -62,4 +62,8 @@ Represents a line item on a sales order. **Type** -*Picklist* \ No newline at end of file +*Picklist* + +#### Possible values are +* Charge +* Discount \ No newline at end of file diff --git a/src/core/markdown/adapters/type-to-renderable.ts b/src/core/markdown/adapters/type-to-renderable.ts index 050645bb..638e9375 100644 --- a/src/core/markdown/adapters/type-to-renderable.ts +++ b/src/core/markdown/adapters/type-to-renderable.ts @@ -281,13 +281,11 @@ function fieldMetadataToRenderable( description: field.description ? [field.description] : [], apiName: getApiName(field.name, config), fieldType: field.type, - isPicklist: field.pickListValues.length > 0, - pickListValues: { + pickListValues: field.pickListValues ? { headingLevel: headingLevel + 1, heading: 'Possible values are', - value: field.pickListValues - - } + value: field.pickListValues, + } : undefined, }; } diff --git a/src/core/markdown/templates/custom-object-template.ts b/src/core/markdown/templates/custom-object-template.ts index 18242a0b..b182c4cb 100644 --- a/src/core/markdown/templates/custom-object-template.ts +++ b/src/core/markdown/templates/custom-object-template.ts @@ -24,11 +24,11 @@ export const customObjectTemplate = ` *{{fieldType}}* -{{#if isPicklist}} - {{ heading headingLevel heading }} - {{#each pickListValues.value}} - * {{{this}}} - {{/each}} +{{#if pickListValues}} +{{ heading pickListValues.headingLevel pickListValues.heading }} +{{#each pickListValues.value}} +* {{{this}}} +{{/each}} {{/if}} {{/if}} diff --git a/src/core/reflection/sobject/reflect-custom-field-source.ts b/src/core/reflection/sobject/reflect-custom-field-source.ts index 91c38c87..4d03b3e6 100644 --- a/src/core/reflection/sobject/reflect-custom-field-source.ts +++ b/src/core/reflection/sobject/reflect-custom-field-source.ts @@ -15,7 +15,7 @@ export type CustomFieldMetadata = { label?: string | null; type?: string | null; parentName: string; - pickListValues: string[]; + pickListValues?: string[]; }; export function reflectCustomFieldSources( @@ -66,7 +66,7 @@ function toCustomFieldMetadata(parserResult: { CustomField: unknown }): CustomFi }; const pickListValues = - hasType(customField) && customField.type?.toLowerCase() === 'picklist' ? toPickListValues(customField) : []; + hasType(customField) && customField.type?.toLowerCase() === 'picklist' ? toPickListValues(customField) : undefined; return { ...defaultValues, ...customField, type_name: 'customfield', pickListValues } as CustomFieldMetadata; } @@ -86,7 +86,7 @@ function toPickListValues(customField: object): string[] { } function hasType(customField: object): customField is CustomFieldMetadata { - return (customField as CustomFieldMetadata).type != undefined; + return !!(customField as CustomFieldMetadata).type; } function addName(metadata: CustomFieldMetadata, name: string): CustomFieldMetadata { diff --git a/src/core/renderables/types.d.ts b/src/core/renderables/types.d.ts index 0b2ecec1..3b646264 100644 --- a/src/core/renderables/types.d.ts +++ b/src/core/renderables/types.d.ts @@ -189,7 +189,6 @@ export type RenderableCustomField = { heading: string; apiName: string; description: RenderableContent[]; - isPicklist: boolean; pickListValues?: RenderableSection type: 'field'; fieldType?: string | null;