Skip to content

Commit fadda9a

Browse files
authored
Merge pull request #247 from williamsalexisSFDC/master
Add compliance category and security classification to Custom Field
2 parents 0faec6b + 03278bf commit fadda9a

File tree

14 files changed

+102
-0
lines changed

14 files changed

+102
-0
lines changed

examples/markdown/docs/custom-objects/Event__c.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,25 @@ Represents an event that people can register for.
4040

4141
*Location*
4242

43+
---
44+
### Social Security Number
45+
46+
Used to store the U.S. social security number in 9 digit format.
47+
48+
**Compliance Category**
49+
PII
50+
51+
**Security Classification**
52+
Internal
53+
54+
**API Name**
55+
56+
`ns__Social_Security_Number__c`
57+
58+
**Type**
59+
60+
*Text*
61+
4362
---
4463
### Start Date
4564
**Required**
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
3+
<fullName>Social_Security_Number__c</fullName>
4+
<externalId>false</externalId>
5+
<label>Social Security Number</label>
6+
<description>Used to store the U.S. social security number in 9 digit format.</description>
7+
<length>9</length>
8+
<trackTrending>false</trackTrending>
9+
<type>Text</type>
10+
<complianceCategory>PII</complianceCategory>
11+
<securityClassification>Internal</securityClassification>
12+
</CustomField>

src/cli/commands/markdown.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,9 @@ export const markdownOptions: Record<keyof CliConfigurableMarkdownConfig, Option
7272
describe: 'The title of the reference guide.',
7373
default: markdownDefaults.referenceGuideTitle,
7474
},
75+
includeFieldSecurityMetadata: {
76+
type: 'boolean',
77+
describe: 'Whether to include the compliance category and security classification for fields in the generated files.',
78+
default: markdownDefaults.includeFieldSecurityMetadata,
79+
}
7580
};

src/core/changelog/__test__/helpers/custom-field-metadata-builder.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ export default class CustomFieldMetadataBuilder {
2323
description: this.description,
2424
parentName: 'MyObject',
2525
required: false,
26+
securityClassification: 'Internal',
27+
complianceCategory: 'PII',
2628
};
2729
}
2830
}

src/core/markdown/__test__/test-helpers.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export function generateDocs(bundles: UnparsedSourceBundle[], config?: Partial<M
5656
linkingStrategy: 'relative',
5757
excludeTags: [],
5858
referenceGuideTitle: 'Apex Reference Guide',
59+
includeFieldSecurityMetadata: true,
5960
exclude: [],
6061
...config,
6162
});

src/core/markdown/adapters/__tests__/interface-adapter.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const defaultMarkdownGeneratorConfig: MarkdownGeneratorConfig = {
2020
sortAlphabetically: false,
2121
linkingStrategy: 'relative',
2222
referenceGuideTitle: 'Apex Reference Guide',
23+
includeFieldSecurityMetadata: true,
2324
exclude: [],
2425
excludeTags: [],
2526
};

src/core/markdown/adapters/type-to-renderable.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,8 @@ function fieldMetadataToRenderable(
357357
apiName: getApiName(field.name, config),
358358
fieldType: field.type,
359359
required: field.required,
360+
complianceCategory: renderComplianceCategory(field.complianceCategory, config),
361+
securityClassification: renderComplianceCategory(field.securityClassification, config),
360362
pickListValues: field.pickListValues
361363
? {
362364
headingLevel: headingLevel + 1,
@@ -391,3 +393,11 @@ function getApiName(currentName: string, config: MarkdownGeneratorConfig) {
391393
}
392394
return currentName;
393395
}
396+
397+
function renderComplianceCategory(complianceCategory: string | null, config: MarkdownGeneratorConfig) {
398+
if(config.includeFieldSecurityMetadata) {
399+
return complianceCategory;
400+
} else {
401+
return null;
402+
}
403+
}

src/core/markdown/templates/custom-object-template.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@ export const customObjectTemplate = `
2424
{{{renderContent description}}}
2525
{{/if}}
2626
27+
{{#if complianceCategory}}
28+
**Compliance Category**
29+
{{complianceCategory}}
30+
{{/if}}
31+
32+
{{#if securityClassification}}
33+
**Security Classification**
34+
{{securityClassification}}
35+
{{/if}}
36+
2737
**API Name**
2838
2939
\`{{{apiName}}}\`

src/core/reflection/sobject/__test__/reflect-custom-field-sources.spec.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ const customFieldContent = `
1414
<trackFeedHistory>false</trackFeedHistory>
1515
<type>Url</type>
1616
<description>A Photo URL field</description>
17+
<securityClassification>Internal</securityClassification>
18+
<complianceCategory>PII</complianceCategory>
1719
</CustomField>`;
1820

1921
describe('when parsing custom field metadata', () => {
@@ -107,6 +109,34 @@ describe('when parsing custom field metadata', () => {
107109
assertEither(result, (data) => expect(data[0].type.description).toBe('A Photo URL field'));
108110
});
109111

112+
test('the resulting type contains the correct security classification', async () => {
113+
const unparsed: UnparsedCustomFieldBundle = {
114+
type: 'customfield',
115+
name: 'PhotoUrl__c',
116+
parentName: 'MyFirstObject__c',
117+
filePath: 'src/field/PhotoUrl__c.field-meta.xml',
118+
content: customFieldContent,
119+
};
120+
121+
const result = await reflectCustomFieldSources([unparsed])();
122+
123+
assertEither(result, (data) => expect(data[0].type.securityClassification).toBe('Internal'));
124+
});
125+
126+
test('the resulting type contains the correct compliance category', async () => {
127+
const unparsed: UnparsedCustomFieldBundle = {
128+
type: 'customfield',
129+
name: 'PhotoUrl__c',
130+
parentName: 'MyFirstObject__c',
131+
filePath: 'src/field/PhotoUrl__c.field-meta.xml',
132+
content: customFieldContent,
133+
};
134+
135+
const result = await reflectCustomFieldSources([unparsed])();
136+
137+
assertEither(result, (data) => expect(data[0].type.complianceCategory).toBe('PII'));
138+
});
139+
110140
test('can parse picklist values when there are multiple picklist values available', async () => {
111141
const unparsed: UnparsedCustomFieldBundle = {
112142
type: 'customfield',

src/core/reflection/sobject/reflect-custom-field-source.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ export type CustomFieldMetadata = {
1818
parentName: string;
1919
pickListValues?: string[];
2020
required: boolean;
21+
securityClassification: string | null;
22+
complianceCategory: string | null;
2123
};
2224

2325
export function reflectCustomFieldSources(
@@ -66,6 +68,8 @@ function toCustomFieldMetadata(parserResult: { CustomField: unknown }): CustomFi
6668
const defaultValues = {
6769
description: null,
6870
required: false,
71+
securityClassification: null,
72+
complianceCategory: null,
6973
};
7074

7175
return {

0 commit comments

Comments
 (0)