diff --git a/examples/markdown/docs/custom-objects/Event__c.md b/examples/markdown/docs/custom-objects/Event__c.md index 023f2a04..4ab294bc 100644 --- a/examples/markdown/docs/custom-objects/Event__c.md +++ b/examples/markdown/docs/custom-objects/Event__c.md @@ -40,6 +40,25 @@ Represents an event that people can register for. *Location* +--- +### Social Security Number + +Used to store the U.S. social security number in 9 digit format. + +**Compliance Category** +PII + +**Security Classification** +Internal + +**API Name** + +`ns__Social_Security_Number__c` + +**Type** + +*Text* + --- ### Start Date **Required** diff --git a/examples/markdown/force-app/objects/Event__c/fields/Social_Security_Number__c.field-meta.xml b/examples/markdown/force-app/objects/Event__c/fields/Social_Security_Number__c.field-meta.xml new file mode 100644 index 00000000..6cd99937 --- /dev/null +++ b/examples/markdown/force-app/objects/Event__c/fields/Social_Security_Number__c.field-meta.xml @@ -0,0 +1,12 @@ + + + Social_Security_Number__c + false + + Used to store the U.S. social security number in 9 digit format. + 9 + false + Text + PII + Internal + diff --git a/src/cli/commands/markdown.ts b/src/cli/commands/markdown.ts index 5666d5d6..d92cefff 100644 --- a/src/cli/commands/markdown.ts +++ b/src/cli/commands/markdown.ts @@ -72,4 +72,9 @@ export const markdownOptions: Recordfalse Url A Photo URL field + Internal + PII `; describe('when parsing custom field metadata', () => { @@ -107,6 +109,34 @@ describe('when parsing custom field metadata', () => { assertEither(result, (data) => expect(data[0].type.description).toBe('A Photo URL field')); }); + test('the resulting type contains the correct security classification', async () => { + const unparsed: UnparsedCustomFieldBundle = { + type: 'customfield', + name: 'PhotoUrl__c', + parentName: 'MyFirstObject__c', + filePath: 'src/field/PhotoUrl__c.field-meta.xml', + content: customFieldContent, + }; + + const result = await reflectCustomFieldSources([unparsed])(); + + assertEither(result, (data) => expect(data[0].type.securityClassification).toBe('Internal')); + }); + + test('the resulting type contains the correct compliance category', async () => { + const unparsed: UnparsedCustomFieldBundle = { + type: 'customfield', + name: 'PhotoUrl__c', + parentName: 'MyFirstObject__c', + filePath: 'src/field/PhotoUrl__c.field-meta.xml', + content: customFieldContent, + }; + + const result = await reflectCustomFieldSources([unparsed])(); + + assertEither(result, (data) => expect(data[0].type.complianceCategory).toBe('PII')); + }); + test('can parse picklist values when there are multiple picklist values available', 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 698864aa..c16c9296 100644 --- a/src/core/reflection/sobject/reflect-custom-field-source.ts +++ b/src/core/reflection/sobject/reflect-custom-field-source.ts @@ -18,6 +18,8 @@ export type CustomFieldMetadata = { parentName: string; pickListValues?: string[]; required: boolean; + securityClassification: string | null; + complianceCategory: string | null; }; export function reflectCustomFieldSources( @@ -66,6 +68,8 @@ function toCustomFieldMetadata(parserResult: { CustomField: unknown }): CustomFi const defaultValues = { description: null, required: false, + securityClassification: null, + complianceCategory: null, }; return { diff --git a/src/core/reflection/sobject/reflect-custom-object-sources.ts b/src/core/reflection/sobject/reflect-custom-object-sources.ts index aea2eb53..7f274651 100644 --- a/src/core/reflection/sobject/reflect-custom-object-sources.ts +++ b/src/core/reflection/sobject/reflect-custom-object-sources.ts @@ -109,6 +109,8 @@ function convertInlineFieldsToCustomFieldMetadata( const label = inlineField.label ? (inlineField.label as string) : name; const type = inlineField.type ? (inlineField.type as string) : null; const required = inlineField.required ? (inlineField.required as boolean) : false; + const securityClassification = inlineField.securityClassification ? (inlineField.securityClassification as string) : null; + const complianceCategory = inlineField.complianceCategory ? (inlineField.complianceCategory as string) : null; return { type_name: 'customfield', @@ -118,6 +120,8 @@ function convertInlineFieldsToCustomFieldMetadata( parentName, type, required, + securityClassification, + complianceCategory, pickListValues: getPickListValues(inlineField), }; } diff --git a/src/core/renderables/types.d.ts b/src/core/renderables/types.d.ts index c56a10d9..9067c9c0 100644 --- a/src/core/renderables/types.d.ts +++ b/src/core/renderables/types.d.ts @@ -202,6 +202,8 @@ export type RenderableCustomField = { type: 'field'; fieldType?: string | null; required: boolean; + complianceCategory: string | null; + securityClassification: string | null; }; export type RenderableCustomMetadata = { diff --git a/src/core/shared/types.d.ts b/src/core/shared/types.d.ts index c4fd9bab..5df8281e 100644 --- a/src/core/shared/types.d.ts +++ b/src/core/shared/types.d.ts @@ -38,6 +38,7 @@ export type CliConfigurableMarkdownConfig = { includeMetadata: boolean; linkingStrategy: LinkingStrategy; referenceGuideTitle: string; + includeFieldSecurityMetadata: boolean; }; export type UserDefinedMarkdownConfig = { diff --git a/src/defaults.ts b/src/defaults.ts index f30c2e0d..780991c9 100644 --- a/src/defaults.ts +++ b/src/defaults.ts @@ -19,6 +19,7 @@ export const markdownDefaults = { linkingStrategy: 'relative' as const, referenceGuideTitle: 'Reference Guide', excludeTags: [], + includeFieldSecurityMetadata: false, }; export const openApiDefaults = {