diff --git a/examples/markdown/docs/custom-objects/Account.md b/examples/markdown/docs/custom-objects/Account.md new file mode 100644 index 00000000..af6d2715 --- /dev/null +++ b/examples/markdown/docs/custom-objects/Account.md @@ -0,0 +1,4 @@ +# Account + +## API Name +`ns__Account` \ No newline at end of file diff --git a/examples/markdown/docs/custom-objects/Contact.md b/examples/markdown/docs/custom-objects/Contact.md new file mode 100644 index 00000000..27086047 --- /dev/null +++ b/examples/markdown/docs/custom-objects/Contact.md @@ -0,0 +1,15 @@ +# Contact + +## API Name +`ns__Contact` + +## Fields +### PhotoUrl + +**API Name** + +`ns__PhotoUrl__c` + +**Type** + +*Url* \ No newline at end of file diff --git a/examples/markdown/docs/index.md b/examples/markdown/docs/index.md index bc012275..fb757332 100644 --- a/examples/markdown/docs/index.md +++ b/examples/markdown/docs/index.md @@ -2,6 +2,10 @@ ## Custom Objects +### [Account](custom-objects/Account.md) + +### [Contact](custom-objects/Contact.md) + ### [Event__c](custom-objects/Event__c.md) Represents an event that people can register for. diff --git a/examples/markdown/force-app/objects/Account/Account.object-meta.xml b/examples/markdown/force-app/objects/Account/Account.object-meta.xml new file mode 100644 index 00000000..5f969ba5 --- /dev/null +++ b/examples/markdown/force-app/objects/Account/Account.object-meta.xml @@ -0,0 +1,90 @@ + + + + CallHighlightAction + Default + + + CancelEdit + Default + + + Delete + Default + + + Edit + Default + + + EmailHighlightAction + Default + + + EnableCustomerPortalUser + Default + + + List + Default + + + ListClean + Default + + + New + Default + + + RequestUpdate + Default + + + SaveEdit + Default + + + SmsHighlightAction + Default + + + Tab + Default + + + View + Account_Record_Page + Large + false + Flexipage + + + ViewCustomerPortalUser + Default + + + WebsiteHighlightAction + Default + + Account_Compact_Layout + true + true + false + + ACCOUNT.NAME + ACCOUNT.ADDRESS1_CITY + ACCOUNT.PHONE1 + ACCOUNT.NAME + CORE.USERS.ALIAS + ACCOUNT.TYPE + ACCOUNT.NAME + CORE.USERS.ALIAS + ACCOUNT.TYPE + ACCOUNT.PHONE1 + ACCOUNT.NAME + ACCOUNT.PHONE1 + CORE.USERS.ALIAS + + ReadWrite + diff --git a/examples/markdown/force-app/objects/Contact/Contact.object-meta.xml b/examples/markdown/force-app/objects/Contact/Contact.object-meta.xml new file mode 100644 index 00000000..0d11ee1b --- /dev/null +++ b/examples/markdown/force-app/objects/Contact/Contact.object-meta.xml @@ -0,0 +1,3 @@ + + + diff --git a/package.json b/package.json index 43b8a745..2c269126 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cparra/apexdocs", - "version": "3.4.1", + "version": "3.4.2", "description": "Library with CLI capabilities to generate documentation for Salesforce Apex classes.", "keywords": [ "apex", diff --git a/src/application/source-code-file-reader.ts b/src/application/source-code-file-reader.ts index 7d9b5da3..2a4e6071 100644 --- a/src/application/source-code-file-reader.ts +++ b/src/application/source-code-file-reader.ts @@ -155,7 +155,16 @@ export function processFiles(fileSystem: FileSystem) { return (rootPath: string, exclude: string[]) => { return pipe( fileSystem.getComponents(rootPath), - (components) => components.filter((component) => !isExcluded(component.content!, exclude)), + (components) => { + return components.map((component) => { + const pathLocation = component.type.name === 'ApexClass' ? component.content : component.xml; + return { + ...component, + filePath: pathLocation!, + }; + }); + }, + (components) => components.filter((component) => !isExcluded(component.filePath, exclude)), (components) => convertersToUse.map((converter) => converter(components)), (bundles) => bundles.flat(), ); diff --git a/src/core/markdown/adapters/type-to-renderable.ts b/src/core/markdown/adapters/type-to-renderable.ts index cd66d8ec..286a09b9 100644 --- a/src/core/markdown/adapters/type-to-renderable.ts +++ b/src/core/markdown/adapters/type-to-renderable.ts @@ -254,7 +254,7 @@ function objectMetadataToRenderable( type: 'customobject', headingLevel: 1, apiName: getApiName(objectMetadata.name, config), - heading: objectMetadata.label, + heading: objectMetadata.label ?? objectMetadata.name, name: objectMetadata.name, doc: { description: objectMetadata.description ? [objectMetadata.description] : [], @@ -277,7 +277,7 @@ function fieldMetadataToRenderable( return { type: 'field', headingLevel: headingLevel, - heading: field.label, + heading: field.label ?? field.name, description: field.description ? [field.description] : [], apiName: getApiName(field.name, config), fieldType: field.type, diff --git a/src/core/markdown/templates/custom-object-template.ts b/src/core/markdown/templates/custom-object-template.ts index ff0af90b..bedc7f41 100644 --- a/src/core/markdown/templates/custom-object-template.ts +++ b/src/core/markdown/templates/custom-object-template.ts @@ -19,9 +19,11 @@ export const customObjectTemplate = ` \`{{{apiName}}}\` +{{#if fieldType}} **Type** *{{fieldType}}* +{{/if}} {{#unless @last}}---{{/unless}} {{/each}} 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 0eba7e3c..0a621483 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 @@ -137,66 +137,4 @@ describe('when parsing custom field metadata', () => { expect(E.isLeft(result)).toBe(true); }); - - test('An error is returned when the CustomField key is not an object', async () => { - const unparsed: UnparsedCustomFieldBundle = { - type: 'customfield', - name: 'PhotoUrl__c', - parentName: 'MyFirstObject__c', - filePath: 'src/field/PhotoUrl__c.field-meta.xml', - content: ` - - invalid`, - }; - - const result = await reflectCustomFieldSources([unparsed])(); - - expect(E.isLeft(result)).toBe(true); - }); - - test('An error is returned when the CustomKey object does not contain the label key', async () => { - const unparsed: UnparsedCustomFieldBundle = { - type: 'customfield', - name: 'PhotoUrl__c', - parentName: 'MyFirstObject__c', - filePath: 'src/field/PhotoUrl__c.field-meta.xml', - content: ` - - - PhotoUrl__c - false - false - false - Url - A Photo URL field - `, - }; - - const result = await reflectCustomFieldSources([unparsed])(); - - expect(E.isLeft(result)).toBe(true); - }); - - test('An error is returned when the CustomKey object does not contain the type key', async () => { - const unparsed: UnparsedCustomFieldBundle = { - type: 'customfield', - name: 'PhotoUrl__c', - parentName: 'MyFirstObject__c', - filePath: 'src/field/PhotoUrl__c.field-meta.xml', - content: ` - - - PhotoUrl__c - false - - false - false - A Photo URL field - `, - }; - - const result = await reflectCustomFieldSources([unparsed])(); - - expect(E.isLeft(result)).toBe(true); - }); }); diff --git a/src/core/reflection/sobject/__test__/reflect-custom-object-sources.spec.ts b/src/core/reflection/sobject/__test__/reflect-custom-object-sources.spec.ts index f923feee..b02f10bc 100644 --- a/src/core/reflection/sobject/__test__/reflect-custom-object-sources.spec.ts +++ b/src/core/reflection/sobject/__test__/reflect-custom-object-sources.spec.ts @@ -156,26 +156,4 @@ describe('when parsing SObject metadata', () => { expect(E.isLeft(result)).toBe(true); }); - - test('an error is thrown when the label is missing', async () => { - const sObjectContent = ` - - - Deployed - test object for testing - MyFirstObjects - Public - `; - - const unparsed: UnparsedCustomObjectBundle = { - type: 'customobject', - name: 'MyFirstObject__c', - filePath: 'src/object/MyFirstObject__c.object-meta.xml', - content: sObjectContent, - }; - - const result = await reflectCustomObjectSources([unparsed])(); - - expect(E.isLeft(result)).toBe(true); - }); }); diff --git a/src/core/reflection/sobject/reflect-custom-field-source.ts b/src/core/reflection/sobject/reflect-custom-field-source.ts index a0affa80..c42f78fc 100644 --- a/src/core/reflection/sobject/reflect-custom-field-source.ts +++ b/src/core/reflection/sobject/reflect-custom-field-source.ts @@ -12,8 +12,8 @@ export type CustomFieldMetadata = { type_name: 'customfield'; description: string | null; name: string; - label: string; - type: string; + label?: string | null; + type?: string | null; parentName: string; }; @@ -43,7 +43,7 @@ function reflectCustomFieldSource( ); } -function validate(parsedResult: unknown): E.Either { +function validate(parsedResult: unknown): E.Either { const err = E.left(new Error('Invalid custom field metadata')); function isObject(value: unknown) { @@ -54,34 +54,16 @@ function validate(parsedResult: unknown): E.Either) { - return typeof value.CustomField === 'object' ? E.right(value as Record<'CustomField', object>) : err; - } - - function theCustomFieldObjectContainsTheLabelKey(value: Record<'CustomField', object>) { - return 'label' in value.CustomField ? E.right(value) : err; - } - - function theCustomFieldObjectContainsTheTypeKey(value: Record<'CustomField', object>) { - return 'type' in value.CustomField ? E.right(value) : err; - } - - return pipe( - parsedResult, - isObject, - E.chain(hasTheCustomFieldKey), - E.chain(theCustomFieldKeyIsAnObject), - E.chain(theCustomFieldObjectContainsTheLabelKey), - E.chain(theCustomFieldObjectContainsTheTypeKey), - ); + return pipe(parsedResult, isObject, E.chain(hasTheCustomFieldKey)); } -function toCustomFieldMetadata(parserResult: { CustomField: object }): CustomFieldMetadata { +function toCustomFieldMetadata(parserResult: { CustomField: unknown }): CustomFieldMetadata { + const customField = typeof parserResult.CustomField === 'object' ? parserResult.CustomField : {}; const defaultValues = { description: null, }; - return { ...defaultValues, ...parserResult.CustomField, type_name: 'customfield' } as CustomFieldMetadata; + return { ...defaultValues, ...customField, type_name: 'customfield' } as CustomFieldMetadata; } function addName(metadata: CustomFieldMetadata, name: string): CustomFieldMetadata { diff --git a/src/core/reflection/sobject/reflect-custom-object-sources.ts b/src/core/reflection/sobject/reflect-custom-object-sources.ts index e301c4c1..8ddfe459 100644 --- a/src/core/reflection/sobject/reflect-custom-object-sources.ts +++ b/src/core/reflection/sobject/reflect-custom-object-sources.ts @@ -13,7 +13,7 @@ export type ObjectMetadata = { type_name: 'customobject'; deploymentStatus: string; visibility: string; - label: string; + label?: string | null; name: string; description: string | null; fields: ParsedFile[]; @@ -45,7 +45,7 @@ function reflectCustomObjectSource( ); } -function validate(parseResult: unknown): E.Either { +function validate(parseResult: unknown): E.Either { const err = E.left(new Error('Invalid SObject metadata')); function isObject(value: unknown) { @@ -56,31 +56,19 @@ function validate(parseResult: unknown): E.Either) { - return typeof value.CustomObject === 'object' ? E.right(value as Record<'CustomObject', object>) : err; - } - - function theCustomObjectContainsTheLabelKey(value: Record<'CustomObject', object>) { - return 'label' in value.CustomObject ? E.right(value) : err; - } - - return pipe( - parseResult, - isObject, - E.chain(hasTheCustomObjectKey), - E.chain(theCustomObjectKeyIsAnObject), - E.chain(theCustomObjectContainsTheLabelKey), - ); + return pipe(parseResult, isObject, E.chain(hasTheCustomObjectKey)); } -function toObjectMetadata(parserResult: { CustomObject: object }): ObjectMetadata { +function toObjectMetadata(parserResult: { CustomObject: unknown }): ObjectMetadata { + const customObject = typeof parserResult.CustomObject === 'object' ? parserResult.CustomObject : {}; + const defaultValues = { deploymentStatus: 'Deployed', visibility: 'Public', description: null, fields: [] as ParsedFile[], }; - return { ...defaultValues, ...parserResult.CustomObject } as ObjectMetadata; + return { ...defaultValues, ...customObject } as ObjectMetadata; } function addName(objectMetadata: ObjectMetadata, name: string): ObjectMetadata { diff --git a/src/core/renderables/types.d.ts b/src/core/renderables/types.d.ts index ddf50728..cfdc58a8 100644 --- a/src/core/renderables/types.d.ts +++ b/src/core/renderables/types.d.ts @@ -190,7 +190,7 @@ export type RenderableCustomField = { apiName: string; description: RenderableContent[]; type: 'field'; - fieldType: string; + fieldType?: string | null; }; export type Renderable = (RenderableClass | RenderableInterface | RenderableEnum | RenderableCustomObject) & {