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/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/__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..638e9375 100644 --- a/src/core/markdown/adapters/type-to-renderable.ts +++ b/src/core/markdown/adapters/type-to-renderable.ts @@ -281,6 +281,11 @@ function fieldMetadataToRenderable( description: field.description ? [field.description] : [], apiName: getApiName(field.name, config), fieldType: field.type, + pickListValues: field.pickListValues ? { + headingLevel: headingLevel + 1, + heading: 'Possible values are', + 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 bedc7f41..b182c4cb 100644 --- a/src/core/markdown/templates/custom-object-template.ts +++ b/src/core/markdown/templates/custom-object-template.ts @@ -23,6 +23,13 @@ export const customObjectTemplate = ` **Type** *{{fieldType}}* + +{{#if pickListValues}} +{{ heading pickListValues.headingLevel pickListValues.heading }} +{{#each pickListValues.value}} +* {{{this}}} +{{/each}} +{{/if}} {{/if}} {{#unless @last}}---{{/unless}} 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..4d03b3e6 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 hasType(customField: object): customField is CustomFieldMetadata { + 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 cfdc58a8..3b646264 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?: RenderableSection type: 'field'; fieldType?: string | null; };