diff --git a/examples/vitepress/apexdocs.config.ts b/examples/vitepress/apexdocs.config.ts
index 4a76b64f..15db7a60 100644
--- a/examples/vitepress/apexdocs.config.ts
+++ b/examples/vitepress/apexdocs.config.ts
@@ -33,6 +33,7 @@ export default {
}),
markdown: defineMarkdownConfig({
sourceDir: 'force-app',
+ includeMetadata: false,
scope: ['global', 'public', 'protected', 'private', 'namespaceaccessible'],
sortAlphabetically: true,
namespace: 'apexdocs',
@@ -50,36 +51,21 @@ export default {
},
excludeTags: ['internal'],
transformDocs: async (docs) => {
+ const apexOnlyDocs = docs.filter((doc) => doc.type !== 'customobject');
+ const objectOnlyDocs = docs.filter((doc) => doc.type === 'customobject');
+
// Update sidebar
const sidebar = [
{
text: 'API Reference',
- items: [
- {
- text: 'Grouped By Type',
- items: [
- {
- text: 'Classes',
- items: docs.filter((doc) => doc.source.type === 'class').map(toSidebarLink),
- },
- {
- text: 'Interfaces',
- items: docs.filter((doc) => doc.source.type === 'interface').map(toSidebarLink),
- },
- {
- text: 'Enums',
- items: docs.filter((doc) => doc.source.type === 'enum').map(toSidebarLink),
- },
- ],
- },
- {
- text: 'Grouped by Group',
- items: Array.from(extractGroups(docs)).map(([groupName, groupDocs]) => ({
- text: groupName,
- items: groupDocs.map(toSidebarLink),
- })),
- },
- ],
+ items: Array.from(extractGroups(apexOnlyDocs)).map(([groupName, groupDocs]) => ({
+ text: groupName,
+ items: groupDocs.map(toSidebarLink),
+ })),
+ },
+ {
+ text: 'Object Reference',
+ items: objectOnlyDocs.map(toSidebarLink),
},
];
await writeFileAsync('./docs/.vitepress/sidebar.json', JSON.stringify(sidebar, null, 2));
diff --git a/examples/vitepress/docs/.vitepress/sidebar.json b/examples/vitepress/docs/.vitepress/sidebar.json
index a4e2b837..dd5afb72 100644
--- a/examples/vitepress/docs/.vitepress/sidebar.json
+++ b/examples/vitepress/docs/.vitepress/sidebar.json
@@ -3,117 +3,89 @@
"text": "API Reference",
"items": [
{
- "text": "Grouped By Type",
+ "text": "Miscellaneous",
"items": [
{
- "text": "Classes",
- "items": [
- {
- "text": "BaseClass",
- "link": "miscellaneous/BaseClass.md"
- },
- {
- "text": "MultiInheritanceClass",
- "link": "miscellaneous/MultiInheritanceClass.md"
- },
- {
- "text": "SampleClass",
- "link": "samplegroup/SampleClass.md"
- },
- {
- "text": "SampleException",
- "link": "miscellaneous/SampleException.md"
- },
- {
- "text": "Url",
- "link": "miscellaneous/Url.md"
- }
- ]
+ "text": "BaseClass",
+ "link": "miscellaneous/BaseClass.md"
},
{
- "text": "Interfaces",
- "items": [
- {
- "text": "ParentInterface",
- "link": "miscellaneous/ParentInterface.md"
- },
- {
- "text": "SampleInterface",
- "link": "miscellaneous/SampleInterface.md"
- }
- ]
+ "text": "MultiInheritanceClass",
+ "link": "miscellaneous/MultiInheritanceClass.md"
},
{
- "text": "Enums",
- "items": [
- {
- "text": "ReferencedEnum",
- "link": "miscellaneous/ReferencedEnum.md"
- },
- {
- "text": "SampleEnum",
- "link": "sample-enums/SampleEnum.md"
- }
- ]
+ "text": "ParentInterface",
+ "link": "miscellaneous/ParentInterface.md"
+ },
+ {
+ "text": "ReferencedEnum",
+ "link": "miscellaneous/ReferencedEnum.md"
+ },
+ {
+ "text": "SampleException",
+ "link": "miscellaneous/SampleException.md"
+ },
+ {
+ "text": "SampleInterface",
+ "link": "miscellaneous/SampleInterface.md"
+ },
+ {
+ "text": "Url",
+ "link": "miscellaneous/Url.md"
}
]
},
{
- "text": "Grouped by Group",
+ "text": "SampleGroup",
"items": [
{
- "text": "Miscellaneous",
- "items": [
- {
- "text": "BaseClass",
- "link": "miscellaneous/BaseClass.md"
- },
- {
- "text": "MultiInheritanceClass",
- "link": "miscellaneous/MultiInheritanceClass.md"
- },
- {
- "text": "ParentInterface",
- "link": "miscellaneous/ParentInterface.md"
- },
- {
- "text": "ReferencedEnum",
- "link": "miscellaneous/ReferencedEnum.md"
- },
- {
- "text": "SampleException",
- "link": "miscellaneous/SampleException.md"
- },
- {
- "text": "SampleInterface",
- "link": "miscellaneous/SampleInterface.md"
- },
- {
- "text": "Url",
- "link": "miscellaneous/Url.md"
- }
- ]
- },
- {
- "text": "SampleGroup",
- "items": [
- {
- "text": "SampleClass",
- "link": "samplegroup/SampleClass.md"
- }
- ]
- },
+ "text": "SampleClass",
+ "link": "samplegroup/SampleClass.md"
+ }
+ ]
+ },
+ {
+ "text": "Sample Enums",
+ "items": [
{
- "text": "Sample Enums",
- "items": [
- {
- "text": "SampleEnum",
- "link": "sample-enums/SampleEnum.md"
- }
- ]
+ "text": "SampleEnum",
+ "link": "sample-enums/SampleEnum.md"
}
]
}
]
+ },
+ {
+ "text": "Object Reference",
+ "items": [
+ {
+ "text": "Event__c",
+ "link": "custom-objects/Event__c.md"
+ },
+ {
+ "text": "Price_Component__c",
+ "link": "custom-objects/Price_Component__c.md"
+ },
+ {
+ "text": "Product__c",
+ "link": "custom-objects/Product__c.md"
+ },
+ {
+ "text": "Product_Price_Component__c",
+ "link": "custom-objects/Product_Price_Component__c.md"
+ },
+ {
+ "text": "Sales_Order__c",
+ "link": "custom-objects/Sales_Order__c.md"
+ },
+ {
+ "text": "Sales_Order_Line__c",
+ "link": "custom-objects/Sales_Order_Line__c.md"
+ },
+ {
+ "text": "Speaker__c",
+ "link": "custom-objects/Speaker__c.md"
+ }
+ ]
}
]
\ No newline at end of file
diff --git a/examples/vitepress/docs/custom-objects/Event__c.md b/examples/vitepress/docs/custom-objects/Event__c.md
new file mode 100644
index 00000000..892379a4
--- /dev/null
+++ b/examples/vitepress/docs/custom-objects/Event__c.md
@@ -0,0 +1,65 @@
+---
+title: Event__c
+---
+
+# Event
+
+Represents an event that people can register for.
+
+## API Name
+`apexdocs__Event__c`
+
+## Fields
+### Description
+
+**API Name**
+
+`apexdocs__Description__c`
+
+**Type**
+
+*LongTextArea*
+
+---
+### End Date
+
+**API Name**
+
+`apexdocs__End_Date__c`
+
+**Type**
+
+*Date*
+
+---
+### Location
+
+**API Name**
+
+`apexdocs__Location__c`
+
+**Type**
+
+*Location*
+
+---
+### Start Date
+
+**API Name**
+
+`apexdocs__Start_Date__c`
+
+**Type**
+
+*Date*
+
+---
+### Tag Line
+
+**API Name**
+
+`apexdocs__Tag_Line__c`
+
+**Type**
+
+*Text*
\ No newline at end of file
diff --git a/examples/vitepress/docs/custom-objects/Price_Component__c.md b/examples/vitepress/docs/custom-objects/Price_Component__c.md
new file mode 100644
index 00000000..053ccb3c
--- /dev/null
+++ b/examples/vitepress/docs/custom-objects/Price_Component__c.md
@@ -0,0 +1,69 @@
+---
+title: Price_Component__c
+---
+
+# Price Component
+
+## API Name
+`apexdocs__Price_Component__c`
+
+## Fields
+### Description
+
+**API Name**
+
+`apexdocs__Description__c`
+
+**Type**
+
+*Text*
+
+---
+### Expression
+
+The Expression that determines if this price should take effect or not.
+
+**API Name**
+
+`apexdocs__Expression__c`
+
+**Type**
+
+*LongTextArea*
+
+---
+### Percent
+
+Use this field to calculate the price based on the list price's percentage instead of providing a flat price.
+
+**API Name**
+
+`apexdocs__Percent__c`
+
+**Type**
+
+*Percent*
+
+---
+### Price
+
+Use this when the Price Component represents a Flat Price. To represent a Percentage use the Percent field.
+
+**API Name**
+
+`apexdocs__Price__c`
+
+**Type**
+
+*Currency*
+
+---
+### Type
+
+**API Name**
+
+`apexdocs__Type__c`
+
+**Type**
+
+*Picklist*
\ No newline at end of file
diff --git a/examples/vitepress/docs/custom-objects/Product_Price_Component__c.md b/examples/vitepress/docs/custom-objects/Product_Price_Component__c.md
new file mode 100644
index 00000000..cfe9dffa
--- /dev/null
+++ b/examples/vitepress/docs/custom-objects/Product_Price_Component__c.md
@@ -0,0 +1,30 @@
+---
+title: Product_Price_Component__c
+---
+
+# Product Price Component
+
+## API Name
+`apexdocs__Product_Price_Component__c`
+
+## Fields
+### Price Component
+
+**API Name**
+
+`apexdocs__Price_Component__c`
+
+**Type**
+
+*MasterDetail*
+
+---
+### Product
+
+**API Name**
+
+`apexdocs__Product__c`
+
+**Type**
+
+*MasterDetail*
\ No newline at end of file
diff --git a/examples/vitepress/docs/custom-objects/Product__c.md b/examples/vitepress/docs/custom-objects/Product__c.md
new file mode 100644
index 00000000..ba3e70d6
--- /dev/null
+++ b/examples/vitepress/docs/custom-objects/Product__c.md
@@ -0,0 +1,43 @@
+---
+title: Product__c
+---
+
+# Product (Custom)
+
+Product that is sold or available for sale.
+
+## API Name
+`apexdocs__Product__c`
+
+## Fields
+### Description
+
+**API Name**
+
+`apexdocs__Description__c`
+
+**Type**
+
+*Text*
+
+---
+### Event
+
+**API Name**
+
+`apexdocs__Event__c`
+
+**Type**
+
+*Lookup*
+
+---
+### Features
+
+**API Name**
+
+`apexdocs__Features__c`
+
+**Type**
+
+*LongTextArea*
\ 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
new file mode 100644
index 00000000..041e94ce
--- /dev/null
+++ b/examples/vitepress/docs/custom-objects/Sales_Order_Line__c.md
@@ -0,0 +1,65 @@
+---
+title: Sales_Order_Line__c
+---
+
+# Sales Order Line
+
+Represents a line item on a sales order.
+
+## API Name
+`apexdocs__Sales_Order_Line__c`
+
+## Fields
+### Amount
+
+**API Name**
+
+`apexdocs__Amount__c`
+
+**Type**
+
+*Currency*
+
+---
+### Product
+
+**API Name**
+
+`apexdocs__Product__c`
+
+**Type**
+
+*Lookup*
+
+---
+### Sales Order
+
+**API Name**
+
+`apexdocs__Sales_Order__c`
+
+**Type**
+
+*MasterDetail*
+
+---
+### Source Price Component
+
+**API Name**
+
+`apexdocs__Source_Price_Component__c`
+
+**Type**
+
+*Lookup*
+
+---
+### Type
+
+**API Name**
+
+`apexdocs__Type__c`
+
+**Type**
+
+*Picklist*
\ No newline at end of file
diff --git a/examples/vitepress/docs/custom-objects/Sales_Order__c.md b/examples/vitepress/docs/custom-objects/Sales_Order__c.md
new file mode 100644
index 00000000..220efa21
--- /dev/null
+++ b/examples/vitepress/docs/custom-objects/Sales_Order__c.md
@@ -0,0 +1,10 @@
+---
+title: Sales_Order__c
+---
+
+# Sales Order
+
+Custom object for tracking sales orders.
+
+## API Name
+`apexdocs__Sales_Order__c`
\ No newline at end of file
diff --git a/examples/vitepress/docs/custom-objects/Speaker__c.md b/examples/vitepress/docs/custom-objects/Speaker__c.md
new file mode 100644
index 00000000..093efbf4
--- /dev/null
+++ b/examples/vitepress/docs/custom-objects/Speaker__c.md
@@ -0,0 +1,43 @@
+---
+title: Speaker__c
+---
+
+# Speaker
+
+Represents a speaker at an event.
+
+## API Name
+`apexdocs__Speaker__c`
+
+## Fields
+### About
+
+**API Name**
+
+`apexdocs__About__c`
+
+**Type**
+
+*LongTextArea*
+
+---
+### Event
+
+**API Name**
+
+`apexdocs__Event__c`
+
+**Type**
+
+*MasterDetail*
+
+---
+### Person
+
+**API Name**
+
+`apexdocs__Person__c`
+
+**Type**
+
+*MasterDetail*
\ No newline at end of file
diff --git a/examples/vitepress/docs/index.md b/examples/vitepress/docs/index.md
index cdb614cd..e8629caa 100644
--- a/examples/vitepress/docs/index.md
+++ b/examples/vitepress/docs/index.md
@@ -15,7 +15,33 @@ hero:
link: /api-examples
---
-# Apex Reference Guide
+# Reference Guide
+
+## Custom Objects
+
+### [Event__c](custom-objects/Event__c)
+
+Represents an event that people can register for.
+
+### [Price_Component__c](custom-objects/Price_Component__c)
+
+### [Product__c](custom-objects/Product__c)
+
+Product that is sold or available for sale.
+
+### [Product_Price_Component__c](custom-objects/Product_Price_Component__c)
+
+### [Sales_Order__c](custom-objects/Sales_Order__c)
+
+Custom object for tracking sales orders.
+
+### [Sales_Order_Line__c](custom-objects/Sales_Order_Line__c)
+
+Represents a line item on a sales order.
+
+### [Speaker__c](custom-objects/Speaker__c)
+
+Represents a speaker at an event.
## Miscellaneous
diff --git a/examples/vitepress/force-app/main/default/classes/BaseClass.cls-meta.xml b/examples/vitepress/force-app/main/default/classes/BaseClass.cls-meta.xml
new file mode 100644
index 00000000..998805a8
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/classes/BaseClass.cls-meta.xml
@@ -0,0 +1,5 @@
+
+
+ 62.0
+ Active
+
diff --git a/examples/vitepress/force-app/main/default/classes/MultiInheritanceClass.cls-meta.xml b/examples/vitepress/force-app/main/default/classes/MultiInheritanceClass.cls-meta.xml
new file mode 100644
index 00000000..998805a8
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/classes/MultiInheritanceClass.cls-meta.xml
@@ -0,0 +1,5 @@
+
+
+ 62.0
+ Active
+
diff --git a/examples/vitepress/force-app/main/default/classes/ParentInterface.cls-meta.xml b/examples/vitepress/force-app/main/default/classes/ParentInterface.cls-meta.xml
new file mode 100644
index 00000000..998805a8
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/classes/ParentInterface.cls-meta.xml
@@ -0,0 +1,5 @@
+
+
+ 62.0
+ Active
+
diff --git a/examples/vitepress/force-app/main/default/classes/ReferencedEnum.cls-meta.xml b/examples/vitepress/force-app/main/default/classes/ReferencedEnum.cls-meta.xml
new file mode 100644
index 00000000..998805a8
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/classes/ReferencedEnum.cls-meta.xml
@@ -0,0 +1,5 @@
+
+
+ 62.0
+ Active
+
diff --git a/examples/vitepress/force-app/main/default/classes/Url.cls-meta.xml b/examples/vitepress/force-app/main/default/classes/Url.cls-meta.xml
new file mode 100644
index 00000000..998805a8
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/classes/Url.cls-meta.xml
@@ -0,0 +1,5 @@
+
+
+ 62.0
+ Active
+
diff --git a/examples/vitepress/force-app/main/default/classes/feature-a/SampleClass.cls-meta.xml b/examples/vitepress/force-app/main/default/classes/feature-a/SampleClass.cls-meta.xml
new file mode 100644
index 00000000..998805a8
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/classes/feature-a/SampleClass.cls-meta.xml
@@ -0,0 +1,5 @@
+
+
+ 62.0
+ Active
+
diff --git a/examples/vitepress/force-app/main/default/classes/feature-a/SampleEnum.cls-meta.xml b/examples/vitepress/force-app/main/default/classes/feature-a/SampleEnum.cls-meta.xml
new file mode 100644
index 00000000..998805a8
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/classes/feature-a/SampleEnum.cls-meta.xml
@@ -0,0 +1,5 @@
+
+
+ 62.0
+ Active
+
diff --git a/examples/vitepress/force-app/main/default/classes/feature-a/SampleException.cls-meta.xml b/examples/vitepress/force-app/main/default/classes/feature-a/SampleException.cls-meta.xml
new file mode 100644
index 00000000..998805a8
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/classes/feature-a/SampleException.cls-meta.xml
@@ -0,0 +1,5 @@
+
+
+ 62.0
+ Active
+
diff --git a/examples/vitepress/force-app/main/default/classes/feature-a/SampleInterface.cls-meta.xml b/examples/vitepress/force-app/main/default/classes/feature-a/SampleInterface.cls-meta.xml
new file mode 100644
index 00000000..998805a8
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/classes/feature-a/SampleInterface.cls-meta.xml
@@ -0,0 +1,5 @@
+
+
+ 62.0
+ Active
+
diff --git a/examples/vitepress/force-app/main/default/objects/Contact/fields/PhotoUrl__c.field-meta.xml b/examples/vitepress/force-app/main/default/objects/Contact/fields/PhotoUrl__c.field-meta.xml
new file mode 100644
index 00000000..a9117781
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Contact/fields/PhotoUrl__c.field-meta.xml
@@ -0,0 +1,9 @@
+
+
+ PhotoUrl__c
+ false
+
+ false
+ false
+ Url
+
diff --git a/examples/vitepress/force-app/main/default/objects/Event__c/Event__c.object-meta.xml b/examples/vitepress/force-app/main/default/objects/Event__c/Event__c.object-meta.xml
new file mode 100644
index 00000000..d30dde5c
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Event__c/Event__c.object-meta.xml
@@ -0,0 +1,167 @@
+
+
+
+ Accept
+ Default
+
+
+ Accept
+ Large
+ Default
+
+
+ Accept
+ Small
+ Default
+
+
+ CancelEdit
+ Default
+
+
+ CancelEdit
+ Large
+ Default
+
+
+ CancelEdit
+ Small
+ Default
+
+
+ Clone
+ Default
+
+
+ Clone
+ Large
+ Default
+
+
+ Clone
+ Small
+ Default
+
+
+ Delete
+ Default
+
+
+ Delete
+ Large
+ Default
+
+
+ Delete
+ Small
+ Default
+
+
+ Edit
+ Default
+
+
+ Edit
+ Large
+ Default
+
+
+ Edit
+ Small
+ Default
+
+
+ List
+ Default
+
+
+ List
+ Large
+ Default
+
+
+ List
+ Small
+ Default
+
+
+ New
+ Default
+
+
+ New
+ Large
+ Default
+
+
+ New
+ Small
+ Default
+
+
+ SaveEdit
+ Default
+
+
+ SaveEdit
+ Large
+ Default
+
+
+ SaveEdit
+ Small
+ Default
+
+
+ Tab
+ Default
+
+
+ Tab
+ Large
+ Default
+
+
+ Tab
+ Small
+ Default
+
+
+ View
+ Default
+
+
+ View
+ Large
+ Default
+
+
+ View
+ Small
+ Default
+
+ false
+ SYSTEM
+ Deployed
+ false
+ true
+ false
+ false
+ false
+ false
+ false
+ true
+ true
+ Private
+
+
+
+ Text
+
+ Events
+ Represents an event that people can register for.
+
+ ReadWrite
+ Vowel
+ Public
+
diff --git a/examples/vitepress/force-app/main/default/objects/Event__c/fields/Description__c.field-meta.xml b/examples/vitepress/force-app/main/default/objects/Event__c/fields/Description__c.field-meta.xml
new file mode 100644
index 00000000..c1b682a4
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Event__c/fields/Description__c.field-meta.xml
@@ -0,0 +1,10 @@
+
+
+ Description__c
+ false
+
+ 32768
+ false
+ LongTextArea
+ 10
+
diff --git a/examples/vitepress/force-app/main/default/objects/Event__c/fields/End_Date__c.field-meta.xml b/examples/vitepress/force-app/main/default/objects/Event__c/fields/End_Date__c.field-meta.xml
new file mode 100644
index 00000000..422a0003
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Event__c/fields/End_Date__c.field-meta.xml
@@ -0,0 +1,9 @@
+
+
+ End_Date__c
+ false
+
+ true
+ false
+ Date
+
diff --git a/examples/vitepress/force-app/main/default/objects/Event__c/fields/Location__c.field-meta.xml b/examples/vitepress/force-app/main/default/objects/Event__c/fields/Location__c.field-meta.xml
new file mode 100644
index 00000000..b8f32121
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Event__c/fields/Location__c.field-meta.xml
@@ -0,0 +1,11 @@
+
+
+ Location__c
+ false
+ false
+
+ true
+ 3
+ false
+ Location
+
diff --git a/examples/vitepress/force-app/main/default/objects/Event__c/fields/Start_Date__c.field-meta.xml b/examples/vitepress/force-app/main/default/objects/Event__c/fields/Start_Date__c.field-meta.xml
new file mode 100644
index 00000000..81fb3f6d
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Event__c/fields/Start_Date__c.field-meta.xml
@@ -0,0 +1,9 @@
+
+
+ Start_Date__c
+ false
+
+ true
+ false
+ Date
+
diff --git a/examples/vitepress/force-app/main/default/objects/Event__c/fields/Tag_Line__c.field-meta.xml b/examples/vitepress/force-app/main/default/objects/Event__c/fields/Tag_Line__c.field-meta.xml
new file mode 100644
index 00000000..652ee2e0
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Event__c/fields/Tag_Line__c.field-meta.xml
@@ -0,0 +1,11 @@
+
+
+ Tag_Line__c
+ false
+
+ 255
+ false
+ false
+ Text
+ false
+
diff --git a/examples/vitepress/force-app/main/default/objects/Price_Component__c/Price_Component__c.object-meta.xml b/examples/vitepress/force-app/main/default/objects/Price_Component__c/Price_Component__c.object-meta.xml
new file mode 100644
index 00000000..ae72fd0c
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Price_Component__c/Price_Component__c.object-meta.xml
@@ -0,0 +1,169 @@
+
+
+
+ Accept
+ Default
+
+
+ Accept
+ Large
+ Default
+
+
+ Accept
+ Small
+ Default
+
+
+ CancelEdit
+ Default
+
+
+ CancelEdit
+ Large
+ Default
+
+
+ CancelEdit
+ Small
+ Default
+
+
+ Clone
+ Default
+
+
+ Clone
+ Large
+ Default
+
+
+ Clone
+ Small
+ Default
+
+
+ Delete
+ Default
+
+
+ Delete
+ Large
+ Default
+
+
+ Delete
+ Small
+ Default
+
+
+ Edit
+ Default
+
+
+ Edit
+ Large
+ Default
+
+
+ Edit
+ Small
+ Default
+
+
+ List
+ Default
+
+
+ List
+ Large
+ Default
+
+
+ List
+ Small
+ Default
+
+
+ New
+ Default
+
+
+ New
+ Large
+ Default
+
+
+ New
+ Small
+ Default
+
+
+ SaveEdit
+ Default
+
+
+ SaveEdit
+ Large
+ Default
+
+
+ SaveEdit
+ Small
+ Default
+
+
+ Tab
+ Default
+
+
+ Tab
+ Large
+ Default
+
+
+ Tab
+ Small
+ Default
+
+
+ View
+ Action override created by Lightning App Builder during activation.
+ Price_Component_Record_Page
+ Large
+ false
+ Flexipage
+
+
+ View
+ Default
+
+
+ View
+ Small
+ Default
+
+ false
+ SYSTEM
+ Deployed
+ false
+ true
+ false
+ false
+ false
+ false
+ false
+ true
+ true
+ Private
+
+
+ PC-{0000}
+
+ AutoNumber
+
+ Price Components
+
+ ReadWrite
+ Public
+
diff --git a/examples/vitepress/force-app/main/default/objects/Price_Component__c/fields/Description__c.field-meta.xml b/examples/vitepress/force-app/main/default/objects/Price_Component__c/fields/Description__c.field-meta.xml
new file mode 100644
index 00000000..69050ca6
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Price_Component__c/fields/Description__c.field-meta.xml
@@ -0,0 +1,11 @@
+
+
+ Description__c
+ false
+
+ 255
+ false
+ false
+ Text
+ false
+
diff --git a/examples/vitepress/force-app/main/default/objects/Price_Component__c/fields/Expression__c.field-meta.xml b/examples/vitepress/force-app/main/default/objects/Price_Component__c/fields/Expression__c.field-meta.xml
new file mode 100644
index 00000000..c0bf4e45
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Price_Component__c/fields/Expression__c.field-meta.xml
@@ -0,0 +1,12 @@
+
+
+ Expression__c
+ The Expression that determines if this price should take effect or not.
+ false
+ The Expression that determines if this price should take effect or not.
+
+ 131072
+ false
+ LongTextArea
+ 20
+
diff --git a/examples/vitepress/force-app/main/default/objects/Price_Component__c/fields/Percent__c.field-meta.xml b/examples/vitepress/force-app/main/default/objects/Price_Component__c/fields/Percent__c.field-meta.xml
new file mode 100644
index 00000000..9c303bc4
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Price_Component__c/fields/Percent__c.field-meta.xml
@@ -0,0 +1,13 @@
+
+
+ Percent__c
+ Use this field to calculate the price based on the list price's percentage instead of providing a flat price.
+ false
+ Use this field to calculate the price based on the list price's percentage instead of providing a flat price.
+
+ 18
+ false
+ 0
+ false
+ Percent
+
diff --git a/examples/vitepress/force-app/main/default/objects/Price_Component__c/fields/Price__c.field-meta.xml b/examples/vitepress/force-app/main/default/objects/Price_Component__c/fields/Price__c.field-meta.xml
new file mode 100644
index 00000000..84136dec
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Price_Component__c/fields/Price__c.field-meta.xml
@@ -0,0 +1,13 @@
+
+
+ Price__c
+ Use this when the Price Component represents a Flat Price. To represent a Percentage use the Percent field.
+ false
+ Use this when the Price Component represents a Flat Price. To represent a Percentage use the Percent field.
+
+ 18
+ false
+ 2
+ false
+ Currency
+
diff --git a/examples/vitepress/force-app/main/default/objects/Price_Component__c/fields/Type__c.field-meta.xml b/examples/vitepress/force-app/main/default/objects/Price_Component__c/fields/Type__c.field-meta.xml
new file mode 100644
index 00000000..c430b305
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Price_Component__c/fields/Type__c.field-meta.xml
@@ -0,0 +1,30 @@
+
+
+ Type__c
+ false
+
+ true
+ false
+ Picklist
+
+ true
+
+ false
+
+ List Price
+ false
+
+
+
+ Surcharge
+ false
+
+
+
+ Discount
+ false
+
+
+
+
+
diff --git a/examples/vitepress/force-app/main/default/objects/Product_Price_Component__c/Product_Price_Component__c.object-meta.xml b/examples/vitepress/force-app/main/default/objects/Product_Price_Component__c/Product_Price_Component__c.object-meta.xml
new file mode 100644
index 00000000..8a9a6348
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Product_Price_Component__c/Product_Price_Component__c.object-meta.xml
@@ -0,0 +1,166 @@
+
+
+
+ Accept
+ Default
+
+
+ Accept
+ Large
+ Default
+
+
+ Accept
+ Small
+ Default
+
+
+ CancelEdit
+ Default
+
+
+ CancelEdit
+ Large
+ Default
+
+
+ CancelEdit
+ Small
+ Default
+
+
+ Clone
+ Default
+
+
+ Clone
+ Large
+ Default
+
+
+ Clone
+ Small
+ Default
+
+
+ Delete
+ Default
+
+
+ Delete
+ Large
+ Default
+
+
+ Delete
+ Small
+ Default
+
+
+ Edit
+ Default
+
+
+ Edit
+ Large
+ Default
+
+
+ Edit
+ Small
+ Default
+
+
+ List
+ Default
+
+
+ List
+ Large
+ Default
+
+
+ List
+ Small
+ Default
+
+
+ New
+ Default
+
+
+ New
+ Large
+ Default
+
+
+ New
+ Small
+ Default
+
+
+ SaveEdit
+ Default
+
+
+ SaveEdit
+ Large
+ Default
+
+
+ SaveEdit
+ Small
+ Default
+
+
+ Tab
+ Default
+
+
+ Tab
+ Large
+ Default
+
+
+ Tab
+ Small
+ Default
+
+
+ View
+ Default
+
+
+ View
+ Large
+ Default
+
+
+ View
+ Small
+ Default
+
+ false
+ SYSTEM
+ Deployed
+ false
+ true
+ false
+ false
+ false
+ false
+ false
+ true
+ true
+ ControlledByParent
+
+
+ PPC-{0000}
+
+ AutoNumber
+
+ Product Price Components
+
+ ControlledByParent
+ Public
+
diff --git a/examples/vitepress/force-app/main/default/objects/Product_Price_Component__c/fields/Price_Component__c.field-meta.xml b/examples/vitepress/force-app/main/default/objects/Product_Price_Component__c/fields/Price_Component__c.field-meta.xml
new file mode 100644
index 00000000..f152ecb6
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Product_Price_Component__c/fields/Price_Component__c.field-meta.xml
@@ -0,0 +1,14 @@
+
+
+ Price_Component__c
+ false
+
+ Price_Component__c
+ Product Price Components
+ Product_Price_Components
+ 1
+ false
+ false
+ MasterDetail
+ false
+
diff --git a/examples/vitepress/force-app/main/default/objects/Product_Price_Component__c/fields/Product__c.field-meta.xml b/examples/vitepress/force-app/main/default/objects/Product_Price_Component__c/fields/Product__c.field-meta.xml
new file mode 100644
index 00000000..16ec5b33
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Product_Price_Component__c/fields/Product__c.field-meta.xml
@@ -0,0 +1,14 @@
+
+
+ Product__c
+ false
+
+ Product__c
+ Product Price Components
+ Product_Price_Components
+ 0
+ false
+ false
+ MasterDetail
+ false
+
diff --git a/examples/vitepress/force-app/main/default/objects/Product__c/Product__c.object-meta.xml b/examples/vitepress/force-app/main/default/objects/Product__c/Product__c.object-meta.xml
new file mode 100644
index 00000000..cdeb52a9
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Product__c/Product__c.object-meta.xml
@@ -0,0 +1,169 @@
+
+
+
+ Accept
+ Default
+
+
+ Accept
+ Large
+ Default
+
+
+ Accept
+ Small
+ Default
+
+
+ CancelEdit
+ Default
+
+
+ CancelEdit
+ Large
+ Default
+
+
+ CancelEdit
+ Small
+ Default
+
+
+ Clone
+ Default
+
+
+ Clone
+ Large
+ Default
+
+
+ Clone
+ Small
+ Default
+
+
+ Delete
+ Default
+
+
+ Delete
+ Large
+ Default
+
+
+ Delete
+ Small
+ Default
+
+
+ Edit
+ Default
+
+
+ Edit
+ Large
+ Default
+
+
+ Edit
+ Small
+ Default
+
+
+ List
+ Default
+
+
+ List
+ Large
+ Default
+
+
+ List
+ Small
+ Default
+
+
+ New
+ Default
+
+
+ New
+ Large
+ Default
+
+
+ New
+ Small
+ Default
+
+
+ SaveEdit
+ Default
+
+
+ SaveEdit
+ Large
+ Default
+
+
+ SaveEdit
+ Small
+ Default
+
+
+ Tab
+ Default
+
+
+ Tab
+ Large
+ Default
+
+
+ Tab
+ Small
+ Default
+
+
+ View
+ Action override created by Lightning App Builder during activation.
+ Product_Record_Page
+ Large
+ false
+ Flexipage
+
+
+ View
+ Default
+
+
+ View
+ Small
+ Default
+
+ false
+ SYSTEM
+ Deployed
+ false
+ true
+ false
+ false
+ false
+ false
+ false
+ true
+ true
+ Private
+
+ Product that is sold or available for sale.
+
+
+ Text
+
+ Products
+
+ ReadWrite
+ Public
+
diff --git a/examples/vitepress/force-app/main/default/objects/Product__c/fields/Description__c.field-meta.xml b/examples/vitepress/force-app/main/default/objects/Product__c/fields/Description__c.field-meta.xml
new file mode 100644
index 00000000..69050ca6
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Product__c/fields/Description__c.field-meta.xml
@@ -0,0 +1,11 @@
+
+
+ Description__c
+ false
+
+ 255
+ false
+ false
+ Text
+ false
+
diff --git a/examples/vitepress/force-app/main/default/objects/Product__c/fields/Event__c.field-meta.xml b/examples/vitepress/force-app/main/default/objects/Product__c/fields/Event__c.field-meta.xml
new file mode 100644
index 00000000..82947d0b
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Product__c/fields/Event__c.field-meta.xml
@@ -0,0 +1,12 @@
+
+
+ Event__c
+ Restrict
+ false
+
+ Event__c
+ Products
+ true
+ false
+ Lookup
+
diff --git a/examples/vitepress/force-app/main/default/objects/Product__c/fields/Features__c.field-meta.xml b/examples/vitepress/force-app/main/default/objects/Product__c/fields/Features__c.field-meta.xml
new file mode 100644
index 00000000..6b67a859
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Product__c/fields/Features__c.field-meta.xml
@@ -0,0 +1,10 @@
+
+
+ Features__c
+ false
+
+ 32768
+ false
+ LongTextArea
+ 10
+
diff --git a/examples/vitepress/force-app/main/default/objects/Sales_Order_Line__c/Sales_Order_Line__c.object-meta.xml b/examples/vitepress/force-app/main/default/objects/Sales_Order_Line__c/Sales_Order_Line__c.object-meta.xml
new file mode 100644
index 00000000..36e9348d
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Sales_Order_Line__c/Sales_Order_Line__c.object-meta.xml
@@ -0,0 +1,167 @@
+
+
+
+ Accept
+ Default
+
+
+ Accept
+ Large
+ Default
+
+
+ Accept
+ Small
+ Default
+
+
+ CancelEdit
+ Default
+
+
+ CancelEdit
+ Large
+ Default
+
+
+ CancelEdit
+ Small
+ Default
+
+
+ Clone
+ Default
+
+
+ Clone
+ Large
+ Default
+
+
+ Clone
+ Small
+ Default
+
+
+ Delete
+ Default
+
+
+ Delete
+ Large
+ Default
+
+
+ Delete
+ Small
+ Default
+
+
+ Edit
+ Default
+
+
+ Edit
+ Large
+ Default
+
+
+ Edit
+ Small
+ Default
+
+
+ List
+ Default
+
+
+ List
+ Large
+ Default
+
+
+ List
+ Small
+ Default
+
+
+ New
+ Default
+
+
+ New
+ Large
+ Default
+
+
+ New
+ Small
+ Default
+
+
+ SaveEdit
+ Default
+
+
+ SaveEdit
+ Large
+ Default
+
+
+ SaveEdit
+ Small
+ Default
+
+
+ Tab
+ Default
+
+
+ Tab
+ Large
+ Default
+
+
+ Tab
+ Small
+ Default
+
+
+ View
+ Default
+
+
+ View
+ Large
+ Default
+
+
+ View
+ Small
+ Default
+
+ false
+ SYSTEM
+ Deployed
+ false
+ true
+ false
+ false
+ false
+ false
+ false
+ true
+ true
+ ControlledByParent
+
+ Represents a line item on a sales order.
+
+ SOL-{0000}
+
+ AutoNumber
+
+ Sales Order Lines
+
+ ControlledByParent
+ Public
+
diff --git a/examples/vitepress/force-app/main/default/objects/Sales_Order_Line__c/fields/Amount__c.field-meta.xml b/examples/vitepress/force-app/main/default/objects/Sales_Order_Line__c/fields/Amount__c.field-meta.xml
new file mode 100644
index 00000000..3a464e2d
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Sales_Order_Line__c/fields/Amount__c.field-meta.xml
@@ -0,0 +1,11 @@
+
+
+ Amount__c
+ false
+
+ 18
+ true
+ 2
+ false
+ Currency
+
diff --git a/examples/vitepress/force-app/main/default/objects/Sales_Order_Line__c/fields/Product__c.field-meta.xml b/examples/vitepress/force-app/main/default/objects/Sales_Order_Line__c/fields/Product__c.field-meta.xml
new file mode 100644
index 00000000..b6b5369f
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Sales_Order_Line__c/fields/Product__c.field-meta.xml
@@ -0,0 +1,13 @@
+
+
+ Product__c
+ Restrict
+ false
+
+ Product__c
+ Sales Order Lines
+ Sales_Order_Lines
+ true
+ false
+ Lookup
+
diff --git a/examples/vitepress/force-app/main/default/objects/Sales_Order_Line__c/fields/Sales_Order__c.field-meta.xml b/examples/vitepress/force-app/main/default/objects/Sales_Order_Line__c/fields/Sales_Order__c.field-meta.xml
new file mode 100644
index 00000000..c1d881c8
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Sales_Order_Line__c/fields/Sales_Order__c.field-meta.xml
@@ -0,0 +1,14 @@
+
+
+ Sales_Order__c
+ false
+
+ Sales_Order__c
+ Sales Order Lines
+ Sales_Order_Lines
+ 0
+ false
+ false
+ MasterDetail
+ false
+
diff --git a/examples/vitepress/force-app/main/default/objects/Sales_Order_Line__c/fields/Source_Price_Component__c.field-meta.xml b/examples/vitepress/force-app/main/default/objects/Sales_Order_Line__c/fields/Source_Price_Component__c.field-meta.xml
new file mode 100644
index 00000000..69817d96
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Sales_Order_Line__c/fields/Source_Price_Component__c.field-meta.xml
@@ -0,0 +1,13 @@
+
+
+ Source_Price_Component__c
+ SetNull
+ false
+
+ Price_Component__c
+ Sales Order Lines
+ Sales_Order_Lines
+ false
+ false
+ Lookup
+
diff --git a/examples/vitepress/force-app/main/default/objects/Sales_Order_Line__c/fields/Type__c.field-meta.xml b/examples/vitepress/force-app/main/default/objects/Sales_Order_Line__c/fields/Type__c.field-meta.xml
new file mode 100644
index 00000000..328b5529
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Sales_Order_Line__c/fields/Type__c.field-meta.xml
@@ -0,0 +1,26 @@
+
+
+ Type__c
+ "Charge"
+ false
+
+ true
+ false
+ Picklist
+
+ true
+
+ false
+
+ Charge
+ false
+
+
+
+ Discount
+ false
+
+
+
+
+
diff --git a/examples/vitepress/force-app/main/default/objects/Sales_Order__c/Sales_Order__c.object-meta.xml b/examples/vitepress/force-app/main/default/objects/Sales_Order__c/Sales_Order__c.object-meta.xml
new file mode 100644
index 00000000..2225e4f9
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Sales_Order__c/Sales_Order__c.object-meta.xml
@@ -0,0 +1,170 @@
+
+
+
+ Accept
+ Default
+
+
+ Accept
+ Large
+ Default
+
+
+ Accept
+ Small
+ Default
+
+
+ CancelEdit
+ Default
+
+
+ CancelEdit
+ Large
+ Default
+
+
+ CancelEdit
+ Small
+ Default
+
+
+ Clone
+ Default
+
+
+ Clone
+ Large
+ Default
+
+
+ Clone
+ Small
+ Default
+
+
+ Delete
+ Default
+
+
+ Delete
+ Large
+ Default
+
+
+ Delete
+ Small
+ Default
+
+
+ Edit
+ Default
+
+
+ Edit
+ Large
+ Default
+
+
+ Edit
+ Small
+ Default
+
+
+ List
+ Default
+
+
+ List
+ Large
+ Default
+
+
+ List
+ Small
+ Default
+
+
+ New
+ Default
+
+
+ New
+ Large
+ Default
+
+
+ New
+ Small
+ Default
+
+
+ SaveEdit
+ Default
+
+
+ SaveEdit
+ Large
+ Default
+
+
+ SaveEdit
+ Small
+ Default
+
+
+ Tab
+ Default
+
+
+ Tab
+ Large
+ Default
+
+
+ Tab
+ Small
+ Default
+
+
+ View
+ Action override created by Lightning App Builder during activation.
+ Sales_Order_Record_Page
+ Large
+ false
+ Flexipage
+
+
+ View
+ Default
+
+
+ View
+ Small
+ Default
+
+ false
+ SYSTEM
+ Deployed
+ false
+ true
+ false
+ false
+ false
+ false
+ false
+ true
+ true
+ Private
+
+ Custom object for tracking sales orders.
+
+ SO-{0000}
+
+ AutoNumber
+
+ Sales Orders
+
+ ReadWrite
+ Public
+
diff --git a/examples/vitepress/force-app/main/default/objects/Speaker__c/Speaker__c.object-meta.xml b/examples/vitepress/force-app/main/default/objects/Speaker__c/Speaker__c.object-meta.xml
new file mode 100644
index 00000000..6bdf2199
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Speaker__c/Speaker__c.object-meta.xml
@@ -0,0 +1,167 @@
+
+
+
+ Accept
+ Default
+
+
+ Accept
+ Large
+ Default
+
+
+ Accept
+ Small
+ Default
+
+
+ CancelEdit
+ Default
+
+
+ CancelEdit
+ Large
+ Default
+
+
+ CancelEdit
+ Small
+ Default
+
+
+ Clone
+ Default
+
+
+ Clone
+ Large
+ Default
+
+
+ Clone
+ Small
+ Default
+
+
+ Delete
+ Default
+
+
+ Delete
+ Large
+ Default
+
+
+ Delete
+ Small
+ Default
+
+
+ Edit
+ Default
+
+
+ Edit
+ Large
+ Default
+
+
+ Edit
+ Small
+ Default
+
+
+ List
+ Default
+
+
+ List
+ Large
+ Default
+
+
+ List
+ Small
+ Default
+
+
+ New
+ Default
+
+
+ New
+ Large
+ Default
+
+
+ New
+ Small
+ Default
+
+
+ SaveEdit
+ Default
+
+
+ SaveEdit
+ Large
+ Default
+
+
+ SaveEdit
+ Small
+ Default
+
+
+ Tab
+ Default
+
+
+ Tab
+ Large
+ Default
+
+
+ Tab
+ Small
+ Default
+
+
+ View
+ Default
+
+
+ View
+ Large
+ Default
+
+
+ View
+ Small
+ Default
+
+ false
+ SYSTEM
+ Deployed
+ false
+ true
+ false
+ false
+ false
+ false
+ false
+ true
+ true
+ ControlledByParent
+
+ Represents a speaker at an event.
+
+ SPEAK-{0000}
+
+ AutoNumber
+
+ Speakers
+
+ ControlledByParent
+ Public
+
diff --git a/examples/vitepress/force-app/main/default/objects/Speaker__c/fields/About__c.field-meta.xml b/examples/vitepress/force-app/main/default/objects/Speaker__c/fields/About__c.field-meta.xml
new file mode 100644
index 00000000..2fc71d94
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Speaker__c/fields/About__c.field-meta.xml
@@ -0,0 +1,10 @@
+
+
+ About__c
+ false
+
+ 32768
+ false
+ LongTextArea
+ 3
+
diff --git a/examples/vitepress/force-app/main/default/objects/Speaker__c/fields/Event__c.field-meta.xml b/examples/vitepress/force-app/main/default/objects/Speaker__c/fields/Event__c.field-meta.xml
new file mode 100644
index 00000000..cf6bfc63
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Speaker__c/fields/Event__c.field-meta.xml
@@ -0,0 +1,14 @@
+
+
+ Event__c
+ false
+
+ Event__c
+ Speakers
+ Speakers
+ 0
+ false
+ false
+ MasterDetail
+ false
+
diff --git a/examples/vitepress/force-app/main/default/objects/Speaker__c/fields/Person__c.field-meta.xml b/examples/vitepress/force-app/main/default/objects/Speaker__c/fields/Person__c.field-meta.xml
new file mode 100644
index 00000000..b7ac07b1
--- /dev/null
+++ b/examples/vitepress/force-app/main/default/objects/Speaker__c/fields/Person__c.field-meta.xml
@@ -0,0 +1,14 @@
+
+
+ Person__c
+ false
+
+ Contact
+ Speakers
+ Speakers
+ 1
+ false
+ false
+ MasterDetail
+ false
+
diff --git a/package-lock.json b/package-lock.json
index 6c811b16..4cb39f91 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,15 +1,16 @@
{
"name": "@cparra/apexdocs",
- "version": "3.2.2",
+ "version": "3.3.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@cparra/apexdocs",
- "version": "3.2.2",
+ "version": "3.3.1",
"license": "MIT",
"dependencies": {
"@cparra/apex-reflection": "2.15.0",
+ "@salesforce/source-deploy-retrieve": "^12.8.1",
"@types/js-yaml": "^4.0.9",
"@types/yargs": "^17.0.32",
"chalk": "^4.1.2",
@@ -1950,6 +1951,28 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@jsforce/jsforce-node": {
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/@jsforce/jsforce-node/-/jsforce-node-3.5.2.tgz",
+ "integrity": "sha512-WZZo7HVFQsTeHRfykMJBrEK3ACr9sQnWSm3EVLasAnAUxjh+hjU4SfJ7HB1UaPRliHjLVZcSCUwF+OoJqjbfoA==",
+ "license": "MIT",
+ "dependencies": {
+ "@sindresorhus/is": "^4",
+ "base64url": "^3.0.1",
+ "csv-parse": "^5.5.2",
+ "csv-stringify": "^6.4.4",
+ "faye": "^1.4.0",
+ "form-data": "^4.0.0",
+ "https-proxy-agent": "^5.0.0",
+ "multistream": "^3.1.0",
+ "node-fetch": "^2.6.1",
+ "strip-ansi": "^6.0.0",
+ "xml2js": "^0.6.2"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -2449,12 +2472,168 @@
"win32"
]
},
+ "node_modules/@salesforce/core": {
+ "version": "8.6.2",
+ "resolved": "https://registry.npmjs.org/@salesforce/core/-/core-8.6.2.tgz",
+ "integrity": "sha512-LFzTLnavDeWsZBB7b2iuVz0F6yeuTcJzQxCy5n+rACY2/Lbw6UJDK/bOSt4wlss6fKrkyU1FTHNlUK5ZoBEveg==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@jsforce/jsforce-node": "^3.4.1",
+ "@salesforce/kit": "^3.2.2",
+ "@salesforce/schemas": "^1.9.0",
+ "@salesforce/ts-types": "^2.0.10",
+ "ajv": "^8.17.1",
+ "change-case": "^4.1.2",
+ "fast-levenshtein": "^3.0.0",
+ "faye": "^1.4.0",
+ "form-data": "^4.0.0",
+ "js2xmlparser": "^4.0.1",
+ "jsonwebtoken": "9.0.2",
+ "jszip": "3.10.1",
+ "pino": "^9.4.0",
+ "pino-abstract-transport": "^1.2.0",
+ "pino-pretty": "^11.2.2",
+ "proper-lockfile": "^4.1.2",
+ "semver": "^7.6.3",
+ "ts-retry-promise": "^0.8.1"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@salesforce/core/node_modules/ajv": {
+ "version": "8.17.1",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/@salesforce/core/node_modules/fast-levenshtein": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-3.0.0.tgz",
+ "integrity": "sha512-hKKNajm46uNmTlhHSyZkmToAc56uZJwYq7yrciZjqOxnlfQwERDQJmHPUp7m1m9wx8vgOe8IaCKZ5Kv2k1DdCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "fastest-levenshtein": "^1.0.7"
+ }
+ },
+ "node_modules/@salesforce/core/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "license": "MIT"
+ },
+ "node_modules/@salesforce/core/node_modules/semver": {
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@salesforce/kit": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/@salesforce/kit/-/kit-3.2.3.tgz",
+ "integrity": "sha512-X8rZouLt06dxRkn+uYTwywWDS/NqZ783AyomGqgtWdUxF61EOJvu0ehtcYeutx9Ng08uuZ+s6wNvWiDsdhUcPg==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@salesforce/ts-types": "^2.0.12"
+ }
+ },
+ "node_modules/@salesforce/schemas": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@salesforce/schemas/-/schemas-1.9.0.tgz",
+ "integrity": "sha512-LiN37zG5ODT6z70sL1fxF7BQwtCX9JOWofSU8iliSNIM+WDEeinnoFtVqPInRSNt8I0RiJxIKCrqstsmQRBNvA==",
+ "license": "ISC"
+ },
+ "node_modules/@salesforce/source-deploy-retrieve": {
+ "version": "12.8.1",
+ "resolved": "https://registry.npmjs.org/@salesforce/source-deploy-retrieve/-/source-deploy-retrieve-12.8.1.tgz",
+ "integrity": "sha512-1wTP6Qa9aWuToY5VMMO0Xg8ea5Vtnaf79ZYJry4BTK9y2XyzhrmwSHTvvO7UuhDb//zx2REfKT53JltCysEADA==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@salesforce/core": "^8.6.2",
+ "@salesforce/kit": "^3.2.2",
+ "@salesforce/ts-types": "^2.0.12",
+ "fast-levenshtein": "^3.0.0",
+ "fast-xml-parser": "^4.5.0",
+ "got": "^11.8.6",
+ "graceful-fs": "^4.2.11",
+ "ignore": "^5.3.2",
+ "isbinaryfile": "^5.0.2",
+ "jszip": "^3.10.1",
+ "mime": "2.6.0",
+ "minimatch": "^9.0.5",
+ "proxy-agent": "^6.4.0"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@salesforce/source-deploy-retrieve/node_modules/fast-levenshtein": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-3.0.0.tgz",
+ "integrity": "sha512-hKKNajm46uNmTlhHSyZkmToAc56uZJwYq7yrciZjqOxnlfQwERDQJmHPUp7m1m9wx8vgOe8IaCKZ5Kv2k1DdCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "fastest-levenshtein": "^1.0.7"
+ }
+ },
+ "node_modules/@salesforce/source-deploy-retrieve/node_modules/minimatch": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@salesforce/ts-types": {
+ "version": "2.0.12",
+ "resolved": "https://registry.npmjs.org/@salesforce/ts-types/-/ts-types-2.0.12.tgz",
+ "integrity": "sha512-BIJyduJC18Kc8z+arUm5AZ9VkPRyw1KKAm+Tk+9LT99eOzhNilyfKzhZ4t+tG2lIGgnJpmytZfVDZ0e2kFul8g==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
"node_modules/@sinclair/typebox": {
"version": "0.27.8",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
"integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==",
"dev": true
},
+ "node_modules/@sindresorhus/is": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
+ "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/is?sponsor=1"
+ }
+ },
"node_modules/@sinonjs/commons": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz",
@@ -2473,6 +2652,24 @@
"@sinonjs/commons": "^3.0.0"
}
},
+ "node_modules/@szmarczak/http-timer": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz",
+ "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==",
+ "license": "MIT",
+ "dependencies": {
+ "defer-to-connect": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@tootallnate/quickjs-emscripten": {
+ "version": "0.23.0",
+ "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz",
+ "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==",
+ "license": "MIT"
+ },
"node_modules/@types/babel__core": {
"version": "7.1.18",
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.18.tgz",
@@ -2514,6 +2711,18 @@
"@babel/types": "^7.3.0"
}
},
+ "node_modules/@types/cacheable-request": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz",
+ "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/http-cache-semantics": "*",
+ "@types/keyv": "^3.1.4",
+ "@types/node": "*",
+ "@types/responselike": "^1.0.0"
+ }
+ },
"node_modules/@types/eslint": {
"version": "8.56.10",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz",
@@ -2551,6 +2760,12 @@
"@types/node": "*"
}
},
+ "node_modules/@types/http-cache-semantics": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz",
+ "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==",
+ "license": "MIT"
+ },
"node_modules/@types/istanbul-lib-coverage": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz",
@@ -2597,6 +2812,15 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/keyv": {
+ "version": "3.1.4",
+ "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz",
+ "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
"node_modules/@types/node": {
"version": "20.14.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz",
@@ -2612,6 +2836,15 @@
"integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==",
"dev": true
},
+ "node_modules/@types/responselike": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz",
+ "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
"node_modules/@types/stack-utils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz",
@@ -2861,6 +3094,18 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/abort-controller": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
+ "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
+ "license": "MIT",
+ "dependencies": {
+ "event-target-shim": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=6.5"
+ }
+ },
"node_modules/acorn": {
"version": "8.12.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
@@ -2884,6 +3129,18 @@
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
+ "node_modules/agent-base": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+ "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6.0.0"
+ }
+ },
"node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -2976,6 +3233,39 @@
"node": ">=8"
}
},
+ "node_modules/asap": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
+ "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
+ "license": "MIT"
+ },
+ "node_modules/ast-types": {
+ "version": "0.13.4",
+ "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz",
+ "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+ "license": "MIT"
+ },
+ "node_modules/atomic-sleep": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
+ "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
"node_modules/babel-plugin-istanbul": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz",
@@ -3020,6 +3310,44 @@
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/base64url": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz",
+ "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/basic-ftp": {
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz",
+ "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
"node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
@@ -3093,6 +3421,36 @@
"node-int64": "^0.4.0"
}
},
+ "node_modules/buffer": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+ "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.2.1"
+ }
+ },
+ "node_modules/buffer-equal-constant-time": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+ "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
+ "license": "BSD-3-Clause"
+ },
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
@@ -3111,6 +3469,48 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/cacheable-lookup": {
+ "version": "5.0.4",
+ "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz",
+ "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.6.0"
+ }
+ },
+ "node_modules/cacheable-request": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz",
+ "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==",
+ "license": "MIT",
+ "dependencies": {
+ "clone-response": "^1.0.2",
+ "get-stream": "^5.1.0",
+ "http-cache-semantics": "^4.0.0",
+ "keyv": "^4.0.0",
+ "lowercase-keys": "^2.0.0",
+ "normalize-url": "^6.0.1",
+ "responselike": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cacheable-request/node_modules/get-stream": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+ "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+ "license": "MIT",
+ "dependencies": {
+ "pump": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/callsites": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
@@ -3119,6 +3519,16 @@
"node": ">=6"
}
},
+ "node_modules/camel-case": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz",
+ "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==",
+ "license": "MIT",
+ "dependencies": {
+ "pascal-case": "^3.1.2",
+ "tslib": "^2.0.3"
+ }
+ },
"node_modules/camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
@@ -3148,6 +3558,17 @@
}
]
},
+ "node_modules/capital-case": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz",
+ "integrity": "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==",
+ "license": "MIT",
+ "dependencies": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3",
+ "upper-case-first": "^2.0.2"
+ }
+ },
"node_modules/chalk": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -3218,6 +3639,26 @@
"node": ">=8"
}
},
+ "node_modules/change-case": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.2.tgz",
+ "integrity": "sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==",
+ "license": "MIT",
+ "dependencies": {
+ "camel-case": "^4.1.2",
+ "capital-case": "^1.0.4",
+ "constant-case": "^3.0.4",
+ "dot-case": "^3.0.4",
+ "header-case": "^2.0.4",
+ "no-case": "^3.0.4",
+ "param-case": "^3.0.4",
+ "pascal-case": "^3.1.2",
+ "path-case": "^3.0.4",
+ "sentence-case": "^3.0.4",
+ "snake-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
"node_modules/char-regex": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz",
@@ -3383,6 +3824,18 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
+ "node_modules/clone-response": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz",
+ "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==",
+ "license": "MIT",
+ "dependencies": {
+ "mimic-response": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
@@ -3416,9 +3869,20 @@
"version": "2.0.20",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
"integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
- "dev": true,
"license": "MIT"
},
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "license": "MIT",
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/commander": {
"version": "12.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz",
@@ -3442,6 +3906,23 @@
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"dev": true
},
+ "node_modules/constant-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz",
+ "integrity": "sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==",
+ "license": "MIT",
+ "dependencies": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3",
+ "upper-case": "^2.0.2"
+ }
+ },
+ "node_modules/core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+ "license": "MIT"
+ },
"node_modules/cosmiconfig": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz",
@@ -3519,12 +4000,53 @@
"node": ">= 8"
}
},
- "node_modules/debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
- "dev": true,
- "dependencies": {
+ "node_modules/csprng": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/csprng/-/csprng-0.1.2.tgz",
+ "integrity": "sha512-D3WAbvvgUVIqSxUfdvLeGjuotsB32bvfVPd+AaaTWMtyUeC9zgCnw5xs94no89yFLVsafvY9dMZEhTwsY/ZecA==",
+ "license": "MIT",
+ "dependencies": {
+ "sequin": "*"
+ },
+ "engines": {
+ "node": ">=0.6.0"
+ }
+ },
+ "node_modules/csv-parse": {
+ "version": "5.5.6",
+ "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-5.5.6.tgz",
+ "integrity": "sha512-uNpm30m/AGSkLxxy7d9yRXpJQFrZzVWLFBkS+6ngPcZkw/5k3L/jjFuj7tVnEpRn+QgmiXr21nDlhCiUK4ij2A==",
+ "license": "MIT"
+ },
+ "node_modules/csv-stringify": {
+ "version": "6.5.1",
+ "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-6.5.1.tgz",
+ "integrity": "sha512-+9lpZfwpLntpTIEpFbwQyWuW/hmI/eHuJZD1XzeZpfZTqkf1fyvBbBLXTJJMsBuuS11uTShMqPwzx4A6ffXgRQ==",
+ "license": "MIT"
+ },
+ "node_modules/data-uri-to-buffer": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz",
+ "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/dateformat": {
+ "version": "4.6.3",
+ "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz",
+ "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==",
+ "license": "MIT",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "dependencies": {
"ms": "2.1.2"
},
"engines": {
@@ -3536,6 +4058,33 @@
}
}
},
+ "node_modules/decompress-response": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
+ "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "mimic-response": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/decompress-response/node_modules/mimic-response": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
+ "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/dedent": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz",
@@ -3565,6 +4114,38 @@
"node": ">=0.10.0"
}
},
+ "node_modules/defer-to-connect": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
+ "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/degenerator": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz",
+ "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==",
+ "license": "MIT",
+ "dependencies": {
+ "ast-types": "^0.13.4",
+ "escodegen": "^2.1.0",
+ "esprima": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
"node_modules/detect-newline": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
@@ -3609,6 +4190,16 @@
"node": ">=6.0.0"
}
},
+ "node_modules/dot-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz",
+ "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==",
+ "license": "MIT",
+ "dependencies": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
"node_modules/eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
@@ -3616,6 +4207,15 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/ecdsa-sig-formatter": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
+ "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
"node_modules/electron-to-chromium": {
"version": "1.4.795",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.795.tgz",
@@ -3639,6 +4239,15 @@
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
+ "node_modules/end-of-stream": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+ "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+ "license": "MIT",
+ "dependencies": {
+ "once": "^1.4.0"
+ }
+ },
"node_modules/env-paths": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
@@ -3711,6 +4320,27 @@
"node": ">=0.8.0"
}
},
+ "node_modules/escodegen": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz",
+ "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "esprima": "^4.0.1",
+ "estraverse": "^5.2.0",
+ "esutils": "^2.0.2"
+ },
+ "bin": {
+ "escodegen": "bin/escodegen.js",
+ "esgenerate": "bin/esgenerate.js"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "optionalDependencies": {
+ "source-map": "~0.6.1"
+ }
+ },
"node_modules/eslint": {
"version": "8.57.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
@@ -3965,7 +4595,6 @@
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
- "dev": true,
"bin": {
"esparse": "bin/esparse.js",
"esvalidate": "bin/esvalidate.js"
@@ -4003,7 +4632,6 @@
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
- "dev": true,
"engines": {
"node": ">=4.0"
}
@@ -4018,12 +4646,20 @@
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
- "dev": true,
"license": "BSD-2-Clause",
"engines": {
"node": ">=0.10.0"
}
},
+ "node_modules/event-target-shim": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
+ "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/eventemitter3": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
@@ -4031,6 +4667,15 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/events": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.x"
+ }
+ },
"node_modules/execa": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
@@ -4079,11 +4724,16 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
+ "node_modules/fast-copy": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.2.tgz",
+ "integrity": "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==",
+ "license": "MIT"
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true,
"license": "MIT"
},
"node_modules/fast-glob": {
@@ -4128,10 +4778,31 @@
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
"dev": true
},
+ "node_modules/fast-redact": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz",
+ "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/fast-safe-stringify": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
+ "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==",
+ "license": "MIT"
+ },
+ "node_modules/fast-uri": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz",
+ "integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==",
+ "license": "BSD-3-Clause"
+ },
"node_modules/fast-xml-parser": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz",
- "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==",
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.0.tgz",
+ "integrity": "sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg==",
"funding": [
{
"type": "github",
@@ -4150,6 +4821,15 @@
"fxparser": "src/cli/cli.js"
}
},
+ "node_modules/fastest-levenshtein": {
+ "version": "1.0.16",
+ "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
+ "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4.9.1"
+ }
+ },
"node_modules/fastq": {
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
@@ -4159,6 +4839,35 @@
"reusify": "^1.0.4"
}
},
+ "node_modules/faye": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/faye/-/faye-1.4.0.tgz",
+ "integrity": "sha512-kRrIg4be8VNYhycS2PY//hpBJSzZPr/DBbcy9VWelhZMW3KhyLkQR0HL0k0MNpmVoNFF4EdfMFkNAWjTP65g6w==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "asap": "*",
+ "csprng": "*",
+ "faye-websocket": ">=0.9.1",
+ "safe-buffer": "*",
+ "tough-cookie": "*",
+ "tunnel-agent": "*"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/faye-websocket": {
+ "version": "0.11.4",
+ "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz",
+ "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "websocket-driver": ">=0.5.1"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
"node_modules/fb-watchman": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz",
@@ -4275,12 +4984,40 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/form-data": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz",
+ "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==",
+ "license": "MIT",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/fp-ts": {
"version": "2.16.8",
"resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.16.8.tgz",
"integrity": "sha512-nmDtNqmMZkOxu0M5hkrS9YA15/KPkYkILb6Axg9XBAoUoYEtzg+LFmVWqZrl9FNttsW0qIUpx9RCA9INbv+Bxw==",
"license": "MIT"
},
+ "node_modules/fs-extra": {
+ "version": "11.2.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz",
+ "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==",
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=14.14"
+ }
+ },
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -4361,6 +5098,21 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/get-uri": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz",
+ "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==",
+ "license": "MIT",
+ "dependencies": {
+ "basic-ftp": "^5.0.2",
+ "data-uri-to-buffer": "^6.0.2",
+ "debug": "^4.3.4",
+ "fs-extra": "^11.2.0"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
"node_modules/glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
@@ -4445,11 +5197,36 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/got": {
+ "version": "11.8.6",
+ "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz",
+ "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==",
+ "license": "MIT",
+ "dependencies": {
+ "@sindresorhus/is": "^4.0.0",
+ "@szmarczak/http-timer": "^4.0.5",
+ "@types/cacheable-request": "^6.0.1",
+ "@types/responselike": "^1.0.0",
+ "cacheable-lookup": "^5.0.3",
+ "cacheable-request": "^7.0.2",
+ "decompress-response": "^6.0.0",
+ "http2-wrapper": "^1.0.0-beta.5.2",
+ "lowercase-keys": "^2.0.0",
+ "p-cancelable": "^2.0.0",
+ "responselike": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10.19.0"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/got?sponsor=1"
+ }
+ },
"node_modules/graceful-fs": {
- "version": "4.2.9",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
- "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==",
- "dev": true
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "license": "ISC"
},
"node_modules/graphemer": {
"version": "1.4.0",
@@ -4497,12 +5274,91 @@
"node": ">= 0.4"
}
},
+ "node_modules/header-case": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/header-case/-/header-case-2.0.4.tgz",
+ "integrity": "sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==",
+ "license": "MIT",
+ "dependencies": {
+ "capital-case": "^1.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/help-me": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz",
+ "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==",
+ "license": "MIT"
+ },
"node_modules/html-escaper": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
"dev": true
},
+ "node_modules/http-cache-semantics": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
+ "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==",
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/http-parser-js": {
+ "version": "0.5.8",
+ "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz",
+ "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==",
+ "license": "MIT"
+ },
+ "node_modules/http-proxy-agent": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
+ "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "^7.1.0",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/http-proxy-agent/node_modules/agent-base": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
+ "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/http2-wrapper": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz",
+ "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==",
+ "license": "MIT",
+ "dependencies": {
+ "quick-lru": "^5.1.1",
+ "resolve-alpn": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=10.19.0"
+ }
+ },
+ "node_modules/https-proxy-agent": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
+ "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "6",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/human-signals": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
@@ -4528,15 +5384,41 @@
"url": "https://github.com/sponsors/typicode"
}
},
+ "node_modules/ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "BSD-3-Clause"
+ },
"node_modules/ignore": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
- "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==",
- "dev": true,
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+ "license": "MIT",
"engines": {
"node": ">= 4"
}
},
+ "node_modules/immediate": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
+ "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
+ "license": "MIT"
+ },
"node_modules/import-fresh": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -4593,8 +5475,26 @@
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
- "dev": true
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "node_modules/ip-address": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
+ "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==",
+ "license": "MIT",
+ "dependencies": {
+ "jsbn": "1.1.0",
+ "sprintf-js": "^1.1.3"
+ },
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/ip-address/node_modules/sprintf-js": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
+ "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
+ "license": "BSD-3-Clause"
},
"node_modules/is-arrayish": {
"version": "0.2.1",
@@ -4712,11 +5612,29 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/isexe": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
- "dev": true
+ "node_modules/isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+ "license": "MIT"
+ },
+ "node_modules/isbinaryfile": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-5.0.3.tgz",
+ "integrity": "sha512-VR4gNjFaDP8csJQvzInG20JvBj8MaHYLxNOMXysxRbGM7tcsHZwCjhch3FubFtZBkuDbN55i4dUukGeIrzF+6g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 18.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/gjtorikian/"
+ }
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+ "dev": true
},
"node_modules/istanbul-lib-coverage": {
"version": "3.2.0",
@@ -5987,6 +6905,15 @@
"jiti": "bin/jiti.js"
}
},
+ "node_modules/joycon": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz",
+ "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -6003,6 +6930,21 @@
"js-yaml": "bin/js-yaml.js"
}
},
+ "node_modules/js2xmlparser": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz",
+ "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "xmlcreate": "^2.0.4"
+ }
+ },
+ "node_modules/jsbn": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
+ "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==",
+ "license": "MIT"
+ },
"node_modules/jsesc": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
@@ -6019,7 +6961,6 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
- "dev": true,
"license": "MIT"
},
"node_modules/json-parse-even-better-errors": {
@@ -6052,11 +6993,89 @@
"node": ">=6"
}
},
+ "node_modules/jsonfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "license": "MIT",
+ "dependencies": {
+ "universalify": "^2.0.0"
+ },
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/jsonwebtoken": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
+ "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
+ "license": "MIT",
+ "dependencies": {
+ "jws": "^3.2.2",
+ "lodash.includes": "^4.3.0",
+ "lodash.isboolean": "^3.0.3",
+ "lodash.isinteger": "^4.0.4",
+ "lodash.isnumber": "^3.0.3",
+ "lodash.isplainobject": "^4.0.6",
+ "lodash.isstring": "^4.0.1",
+ "lodash.once": "^4.0.0",
+ "ms": "^2.1.1",
+ "semver": "^7.5.4"
+ },
+ "engines": {
+ "node": ">=12",
+ "npm": ">=6"
+ }
+ },
+ "node_modules/jsonwebtoken/node_modules/semver": {
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/jszip": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
+ "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
+ "license": "(MIT OR GPL-3.0-or-later)",
+ "dependencies": {
+ "lie": "~3.3.0",
+ "pako": "~1.0.2",
+ "readable-stream": "~2.3.6",
+ "setimmediate": "^1.0.5"
+ }
+ },
+ "node_modules/jwa": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
+ "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
+ "license": "MIT",
+ "dependencies": {
+ "buffer-equal-constant-time": "1.0.1",
+ "ecdsa-sig-formatter": "1.0.11",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/jws": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
+ "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
+ "license": "MIT",
+ "dependencies": {
+ "jwa": "^1.4.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
"node_modules/keyv": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
"integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
- "dev": true,
"license": "MIT",
"dependencies": {
"json-buffer": "3.0.1"
@@ -6093,6 +7112,15 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/lie": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
+ "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
+ "license": "MIT",
+ "dependencies": {
+ "immediate": "~3.0.5"
+ }
+ },
"node_modules/lilconfig": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz",
@@ -6467,6 +7495,42 @@
"node": ">=8"
}
},
+ "node_modules/lodash.includes": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
+ "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isboolean": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
+ "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isinteger": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
+ "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isnumber": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
+ "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isplainobject": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+ "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isstring": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
+ "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
+ "license": "MIT"
+ },
"node_modules/lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
@@ -6479,6 +7543,30 @@
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"dev": true
},
+ "node_modules/lodash.once": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+ "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
+ "license": "MIT"
+ },
+ "node_modules/lower-case": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
+ "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/lowercase-keys": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
+ "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/lru-cache": {
"version": "11.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.0.tgz",
@@ -6570,6 +7658,39 @@
"node": ">=8.6"
}
},
+ "node_modules/mime": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
+ "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==",
+ "license": "MIT",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
@@ -6579,6 +7700,15 @@
"node": ">=6"
}
},
+ "node_modules/mimic-response": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
+ "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/minimatch": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz",
@@ -6614,8 +7744,31 @@
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
+ "node_modules/multistream": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/multistream/-/multistream-3.1.0.tgz",
+ "integrity": "sha512-zBgD3kn8izQAN/TaL1PCMv15vYpf+Vcrsfub06njuYVYlzUldzpopTlrEZ53pZVEbfn3Shtv7vRFoOv6LOV87Q==",
+ "license": "MIT",
+ "dependencies": {
+ "inherits": "^2.0.1",
+ "readable-stream": "^3.4.0"
+ }
+ },
+ "node_modules/multistream/node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "license": "MIT",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
},
"node_modules/natural-compare": {
"version": "1.4.0",
@@ -6628,6 +7781,45 @@
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
},
+ "node_modules/netmask": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz",
+ "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/no-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
+ "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
+ "license": "MIT",
+ "dependencies": {
+ "lower-case": "^2.0.2",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/node-fetch": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
+ "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
+ "license": "MIT",
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ },
+ "peerDependencies": {
+ "encoding": "^0.1.0"
+ },
+ "peerDependenciesMeta": {
+ "encoding": {
+ "optional": true
+ }
+ }
+ },
"node_modules/node-int64": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
@@ -6649,6 +7841,18 @@
"node": ">=0.10.0"
}
},
+ "node_modules/normalize-url": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",
+ "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/npm-run-path": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
@@ -6661,11 +7865,19 @@
"node": ">=8"
}
},
+ "node_modules/on-exit-leak-free": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz",
+ "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
- "dev": true,
"dependencies": {
"wrappy": "1"
}
@@ -6702,6 +7914,15 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/p-cancelable": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz",
+ "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
@@ -6738,6 +7959,63 @@
"node": ">=6"
}
},
+ "node_modules/pac-proxy-agent": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz",
+ "integrity": "sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==",
+ "license": "MIT",
+ "dependencies": {
+ "@tootallnate/quickjs-emscripten": "^0.23.0",
+ "agent-base": "^7.0.2",
+ "debug": "^4.3.4",
+ "get-uri": "^6.0.1",
+ "http-proxy-agent": "^7.0.0",
+ "https-proxy-agent": "^7.0.5",
+ "pac-resolver": "^7.0.1",
+ "socks-proxy-agent": "^8.0.4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/pac-proxy-agent/node_modules/agent-base": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
+ "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/pac-proxy-agent/node_modules/https-proxy-agent": {
+ "version": "7.0.5",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz",
+ "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==",
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "^7.0.2",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/pac-resolver": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz",
+ "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==",
+ "license": "MIT",
+ "dependencies": {
+ "degenerator": "^5.0.0",
+ "netmask": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
"node_modules/package-json-from-dist": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz",
@@ -6745,6 +8023,22 @@
"dev": true,
"license": "BlueOak-1.0.0"
},
+ "node_modules/pako": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
+ "license": "(MIT AND Zlib)"
+ },
+ "node_modules/param-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz",
+ "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==",
+ "license": "MIT",
+ "dependencies": {
+ "dot-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
"node_modules/parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -6773,6 +8067,26 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/pascal-case": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz",
+ "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==",
+ "license": "MIT",
+ "dependencies": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/path-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/path-case/-/path-case-3.0.4.tgz",
+ "integrity": "sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==",
+ "license": "MIT",
+ "dependencies": {
+ "dot-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -6862,37 +8176,168 @@
"node": ">=0.10"
}
},
- "node_modules/pirates": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz",
- "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==",
- "dev": true,
- "engines": {
- "node": ">= 6"
+ "node_modules/pino": {
+ "version": "9.5.0",
+ "resolved": "https://registry.npmjs.org/pino/-/pino-9.5.0.tgz",
+ "integrity": "sha512-xSEmD4pLnV54t0NOUN16yCl7RIB1c5UUOse5HSyEXtBp+FgFQyPeDutc+Q2ZO7/22vImV7VfEjH/1zV2QuqvYw==",
+ "license": "MIT",
+ "dependencies": {
+ "atomic-sleep": "^1.0.0",
+ "fast-redact": "^3.1.1",
+ "on-exit-leak-free": "^2.1.0",
+ "pino-abstract-transport": "^2.0.0",
+ "pino-std-serializers": "^7.0.0",
+ "process-warning": "^4.0.0",
+ "quick-format-unescaped": "^4.0.3",
+ "real-require": "^0.2.0",
+ "safe-stable-stringify": "^2.3.1",
+ "sonic-boom": "^4.0.1",
+ "thread-stream": "^3.0.0"
+ },
+ "bin": {
+ "pino": "bin.js"
}
},
- "node_modules/pkg-dir": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
- "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
- "dev": true,
+ "node_modules/pino-abstract-transport": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.2.0.tgz",
+ "integrity": "sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==",
+ "license": "MIT",
"dependencies": {
- "find-up": "^4.0.0"
+ "readable-stream": "^4.0.0",
+ "split2": "^4.0.0"
+ }
+ },
+ "node_modules/pino-abstract-transport/node_modules/readable-stream": {
+ "version": "4.5.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz",
+ "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==",
+ "license": "MIT",
+ "dependencies": {
+ "abort-controller": "^3.0.0",
+ "buffer": "^6.0.3",
+ "events": "^3.3.0",
+ "process": "^0.11.10",
+ "string_decoder": "^1.3.0"
},
"engines": {
- "node": ">=8"
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
- "node_modules/pkgroll": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/pkgroll/-/pkgroll-2.4.2.tgz",
- "integrity": "sha512-9seL/4BNQsE+eL+kefjfh5jSLqQPSKXQE/adw1L76k49KFw/XnOnyU8dRwuWpVtvMyIVyecaSBIpvFYrmnZq6A==",
- "dev": true,
+ "node_modules/pino-abstract-transport/node_modules/string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"license": "MIT",
"dependencies": {
- "@rollup/plugin-alias": "^5.1.0",
- "@rollup/plugin-commonjs": "^26.0.1",
- "@rollup/plugin-inject": "^5.0.5",
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "node_modules/pino-pretty": {
+ "version": "11.3.0",
+ "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-11.3.0.tgz",
+ "integrity": "sha512-oXwn7ICywaZPHmu3epHGU2oJX4nPmKvHvB/bwrJHlGcbEWaVcotkpyVHMKLKmiVryWYByNp0jpgAcXpFJDXJzA==",
+ "license": "MIT",
+ "dependencies": {
+ "colorette": "^2.0.7",
+ "dateformat": "^4.6.3",
+ "fast-copy": "^3.0.2",
+ "fast-safe-stringify": "^2.1.1",
+ "help-me": "^5.0.0",
+ "joycon": "^3.1.1",
+ "minimist": "^1.2.6",
+ "on-exit-leak-free": "^2.1.0",
+ "pino-abstract-transport": "^2.0.0",
+ "pump": "^3.0.0",
+ "readable-stream": "^4.0.0",
+ "secure-json-parse": "^2.4.0",
+ "sonic-boom": "^4.0.1",
+ "strip-json-comments": "^3.1.1"
+ },
+ "bin": {
+ "pino-pretty": "bin.js"
+ }
+ },
+ "node_modules/pino-pretty/node_modules/pino-abstract-transport": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz",
+ "integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==",
+ "license": "MIT",
+ "dependencies": {
+ "split2": "^4.0.0"
+ }
+ },
+ "node_modules/pino-pretty/node_modules/readable-stream": {
+ "version": "4.5.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz",
+ "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==",
+ "license": "MIT",
+ "dependencies": {
+ "abort-controller": "^3.0.0",
+ "buffer": "^6.0.3",
+ "events": "^3.3.0",
+ "process": "^0.11.10",
+ "string_decoder": "^1.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/pino-pretty/node_modules/string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "node_modules/pino-std-serializers": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz",
+ "integrity": "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==",
+ "license": "MIT"
+ },
+ "node_modules/pino/node_modules/pino-abstract-transport": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz",
+ "integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==",
+ "license": "MIT",
+ "dependencies": {
+ "split2": "^4.0.0"
+ }
+ },
+ "node_modules/pirates": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz",
+ "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/pkg-dir": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+ "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+ "dev": true,
+ "dependencies": {
+ "find-up": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/pkgroll": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/pkgroll/-/pkgroll-2.4.2.tgz",
+ "integrity": "sha512-9seL/4BNQsE+eL+kefjfh5jSLqQPSKXQE/adw1L76k49KFw/XnOnyU8dRwuWpVtvMyIVyecaSBIpvFYrmnZq6A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@rollup/plugin-alias": "^5.1.0",
+ "@rollup/plugin-commonjs": "^26.0.1",
+ "@rollup/plugin-inject": "^5.0.5",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-replace": "^5.0.7",
@@ -6970,6 +8415,27 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
+ "node_modules/process": {
+ "version": "0.11.10",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6.0"
+ }
+ },
+ "node_modules/process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+ "license": "MIT"
+ },
+ "node_modules/process-warning": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-4.0.0.tgz",
+ "integrity": "sha512-/MyYDxttz7DfGMMHiysAsFE4qF+pQYAA8ziO/3NcRVrQ5fSk+Mns4QZA/oRPFzvcqNoVJXQNWNAsdwBXLUkQKw==",
+ "license": "MIT"
+ },
"node_modules/prompts": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
@@ -6983,6 +8449,86 @@
"node": ">= 6"
}
},
+ "node_modules/proper-lockfile": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz",
+ "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==",
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.4",
+ "retry": "^0.12.0",
+ "signal-exit": "^3.0.2"
+ }
+ },
+ "node_modules/proxy-agent": {
+ "version": "6.4.0",
+ "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz",
+ "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==",
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "^7.0.2",
+ "debug": "^4.3.4",
+ "http-proxy-agent": "^7.0.1",
+ "https-proxy-agent": "^7.0.3",
+ "lru-cache": "^7.14.1",
+ "pac-proxy-agent": "^7.0.1",
+ "proxy-from-env": "^1.1.0",
+ "socks-proxy-agent": "^8.0.2"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/proxy-agent/node_modules/agent-base": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
+ "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/proxy-agent/node_modules/https-proxy-agent": {
+ "version": "7.0.5",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz",
+ "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==",
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "^7.0.2",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/proxy-agent/node_modules/lru-cache": {
+ "version": "7.18.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
+ "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
+ "license": "MIT"
+ },
+ "node_modules/pump": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz",
+ "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==",
+ "license": "MIT",
+ "dependencies": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -7029,12 +8575,60 @@
}
]
},
+ "node_modules/quick-format-unescaped": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz",
+ "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==",
+ "license": "MIT"
+ },
+ "node_modules/quick-lru": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
+ "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/react-is": {
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
"dev": true
},
+ "node_modules/readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "license": "MIT",
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/readable-stream/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "license": "MIT"
+ },
+ "node_modules/real-require": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz",
+ "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 12.13.0"
+ }
+ },
"node_modules/require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@@ -7043,6 +8637,15 @@
"node": ">=0.10.0"
}
},
+ "node_modules/require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/resolve": {
"version": "1.22.8",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
@@ -7060,6 +8663,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/resolve-alpn": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
+ "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==",
+ "license": "MIT"
+ },
"node_modules/resolve-cwd": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz",
@@ -7098,6 +8707,27 @@
"node": ">=10"
}
},
+ "node_modules/responselike": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz",
+ "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==",
+ "license": "MIT",
+ "dependencies": {
+ "lowercase-keys": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/retry": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
+ "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
"node_modules/reusify": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
@@ -7217,6 +8847,47 @@
"queue-microtask": "^1.2.2"
}
},
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/safe-stable-stringify": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz",
+ "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/sax": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
+ "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",
+ "license": "ISC"
+ },
+ "node_modules/secure-json-parse": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz",
+ "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==",
+ "license": "BSD-3-Clause"
+ },
"node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
@@ -7226,6 +8897,32 @@
"semver": "bin/semver.js"
}
},
+ "node_modules/sentence-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.4.tgz",
+ "integrity": "sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==",
+ "license": "MIT",
+ "dependencies": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3",
+ "upper-case-first": "^2.0.2"
+ }
+ },
+ "node_modules/sequin": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/sequin/-/sequin-0.1.1.tgz",
+ "integrity": "sha512-hJWMZRwP75ocoBM+1/YaCsvS0j5MTPeBHJkS2/wruehl9xwtX30HlDF1Gt6UZ8HHHY8SJa2/IL+jo+JJCd59rA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/setimmediate": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+ "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
+ "license": "MIT"
+ },
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -7250,8 +8947,7 @@
"node_modules/signal-exit": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
- "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
- "dev": true
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
},
"node_modules/sisteransi": {
"version": "1.0.5",
@@ -7311,6 +9007,75 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/smart-buffer": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
+ "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6.0.0",
+ "npm": ">= 3.0.0"
+ }
+ },
+ "node_modules/snake-case": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz",
+ "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==",
+ "license": "MIT",
+ "dependencies": {
+ "dot-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/socks": {
+ "version": "2.8.3",
+ "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz",
+ "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==",
+ "license": "MIT",
+ "dependencies": {
+ "ip-address": "^9.0.5",
+ "smart-buffer": "^4.2.0"
+ },
+ "engines": {
+ "node": ">= 10.0.0",
+ "npm": ">= 3.0.0"
+ }
+ },
+ "node_modules/socks-proxy-agent": {
+ "version": "8.0.4",
+ "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz",
+ "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==",
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "^7.1.1",
+ "debug": "^4.3.4",
+ "socks": "^2.8.3"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/socks-proxy-agent/node_modules/agent-base": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
+ "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/sonic-boom": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.0.tgz",
+ "integrity": "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==",
+ "license": "MIT",
+ "dependencies": {
+ "atomic-sleep": "^1.0.0"
+ }
+ },
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -7329,6 +9094,15 @@
"source-map": "^0.6.0"
}
},
+ "node_modules/split2": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
+ "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">= 10.x"
+ }
+ },
"node_modules/sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
@@ -7356,6 +9130,21 @@
"node": ">=8"
}
},
+ "node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/string_decoder/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "license": "MIT"
+ },
"node_modules/string-argv": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz",
@@ -7455,7 +9244,6 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
- "dev": true,
"engines": {
"node": ">=8"
},
@@ -7533,6 +9321,33 @@
"integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
"dev": true
},
+ "node_modules/thread-stream": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.1.0.tgz",
+ "integrity": "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==",
+ "license": "MIT",
+ "dependencies": {
+ "real-require": "^0.2.0"
+ }
+ },
+ "node_modules/tldts": {
+ "version": "6.1.52",
+ "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.52.tgz",
+ "integrity": "sha512-fgrDJXDjbAverY6XnIt0lNfv8A0cf7maTEaZxNykLGsLG7XP+5xhjBTrt/ieAsFjAlZ+G5nmXomLcZDkxXnDzw==",
+ "license": "MIT",
+ "dependencies": {
+ "tldts-core": "^6.1.52"
+ },
+ "bin": {
+ "tldts": "bin/cli.js"
+ }
+ },
+ "node_modules/tldts-core": {
+ "version": "6.1.52",
+ "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.52.tgz",
+ "integrity": "sha512-j4OxQI5rc1Ve/4m/9o2WhWSC4jGc4uVbCINdOEJRAraCi0YqTqgMcxUx7DbmuP0G3PCixoof/RZB0Q5Kh9tagw==",
+ "license": "MIT"
+ },
"node_modules/tmpl": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
@@ -7560,6 +9375,24 @@
"node": ">=8.0"
}
},
+ "node_modules/tough-cookie": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.0.0.tgz",
+ "integrity": "sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "tldts": "^6.1.32"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
+ "license": "MIT"
+ },
"node_modules/ts-api-utils": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
@@ -7632,6 +9465,33 @@
"node": ">=10"
}
},
+ "node_modules/ts-retry-promise": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/ts-retry-promise/-/ts-retry-promise-0.8.1.tgz",
+ "integrity": "sha512-+AHPUmAhr5bSRRK5CurE9kNH8gZlEHnCgusZ0zy2bjfatUBDX0h6vGQjiT0YrGwSDwRZmU+bapeX6mj55FOPvg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
+ "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==",
+ "license": "0BSD"
+ },
+ "node_modules/tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -7710,6 +9570,15 @@
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
},
+ "node_modules/universalify": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
+ "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
"node_modules/update-browserslist-db": {
"version": "1.0.16",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz",
@@ -7740,6 +9609,24 @@
"browserslist": ">= 4.21.0"
}
},
+ "node_modules/upper-case": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-2.0.2.tgz",
+ "integrity": "sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/upper-case-first": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz",
+ "integrity": "sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.3"
+ }
+ },
"node_modules/uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@@ -7750,6 +9637,12 @@
"punycode": "^2.1.0"
}
},
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "license": "MIT"
+ },
"node_modules/v8-to-istanbul": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz",
@@ -7779,6 +9672,45 @@
"makeerror": "1.0.12"
}
},
+ "node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/websocket-driver": {
+ "version": "0.7.4",
+ "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
+ "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "http-parser-js": ">=0.5.1",
+ "safe-buffer": ">=5.1.0",
+ "websocket-extensions": ">=0.1.1"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/websocket-extensions": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
+ "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "license": "MIT",
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -7951,8 +9883,35 @@
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
- "dev": true
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+ },
+ "node_modules/xml2js": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz",
+ "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==",
+ "license": "MIT",
+ "dependencies": {
+ "sax": ">=0.6.0",
+ "xmlbuilder": "~11.0.0"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/xmlbuilder": {
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
+ "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/xmlcreate": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz",
+ "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==",
+ "license": "Apache-2.0"
},
"node_modules/y18n": {
"version": "5.0.8",
diff --git a/package.json b/package.json
index 2b7631ed..01e49836 100644
--- a/package.json
+++ b/package.json
@@ -62,6 +62,7 @@
},
"dependencies": {
"@cparra/apex-reflection": "2.15.0",
+ "@salesforce/source-deploy-retrieve": "^12.8.1",
"@types/js-yaml": "^4.0.9",
"@types/yargs": "^17.0.32",
"chalk": "^4.1.2",
diff --git a/src/application/Apexdocs.ts b/src/application/Apexdocs.ts
index 7ee33925..e153bc73 100644
--- a/src/application/Apexdocs.ts
+++ b/src/application/Apexdocs.ts
@@ -6,11 +6,11 @@ import markdown from './generators/markdown';
import openApi from './generators/openapi';
import changelog from './generators/changelog';
-import { processFiles } from './apex-file-reader';
+import { processFiles } from './source-code-file-reader';
import { DefaultFileSystem } from './file-system';
import { Logger } from '#utils/logger';
import {
- UnparsedSourceFile,
+ UnparsedApexBundle,
UserDefinedChangelogConfig,
UserDefinedConfig,
UserDefinedMarkdownConfig,
@@ -18,7 +18,6 @@ import {
} from '../core/shared/types';
import { ReflectionError, ReflectionErrors, HookError } from '../core/errors/errors';
import { FileReadingError, FileWritingError } from './errors';
-import { apply } from '#utils/fp';
/**
* Application entry-point to generate documentation out of Apex source files.
@@ -46,14 +45,19 @@ export class Apexdocs {
}
}
-const readFiles = apply(processFiles, new DefaultFileSystem());
+const readFiles = processFiles(new DefaultFileSystem());
async function processMarkdown(config: UserDefinedMarkdownConfig) {
return pipe(
- TE.tryCatch(
- () => readFiles(config.sourceDir, config.includeMetadata, config.exclude),
+ E.tryCatch(
+ () =>
+ readFiles(['ApexClass', 'CustomObject', 'CustomField'], { includeMetadata: config.includeMetadata })(
+ config.sourceDir,
+ config.exclude,
+ ),
(e) => new FileReadingError('An error occurred while reading files.', e),
),
+ TE.fromEither,
TE.flatMap((fileBodies) => markdown(fileBodies, config)),
TE.map(() => '✔️ Documentation generated successfully!'),
TE.mapLeft(toErrors),
@@ -61,20 +65,21 @@ async function processMarkdown(config: UserDefinedMarkdownConfig) {
}
async function processOpenApi(config: UserDefinedOpenApiConfig, logger: Logger) {
- const fileBodies = await readFiles(config.sourceDir, false, config.exclude);
+ const fileBodies = readFiles(['ApexClass'])(config.sourceDir, config.exclude) as UnparsedApexBundle[];
return openApi(logger, fileBodies, config);
}
async function processChangeLog(config: UserDefinedChangelogConfig) {
- async function loadFiles(): Promise<[UnparsedSourceFile[], UnparsedSourceFile[]]> {
+ function loadFiles(): [UnparsedApexBundle[], UnparsedApexBundle[]] {
return [
- await readFiles(config.previousVersionDir, false, config.exclude),
- await readFiles(config.currentVersionDir, false, config.exclude),
+ readFiles(['ApexClass'])(config.previousVersionDir, config.exclude) as UnparsedApexBundle[],
+ readFiles(['ApexClass'])(config.currentVersionDir, config.exclude) as UnparsedApexBundle[],
];
}
return pipe(
- TE.tryCatch(loadFiles, (e) => new FileReadingError('An error occurred while reading files.', e)),
+ E.tryCatch(loadFiles, (e) => new FileReadingError('An error occurred while reading files.', e)),
+ TE.fromEither,
TE.flatMap(([previous, current]) => changelog(previous, current, config)),
TE.mapLeft(toErrors),
);
diff --git a/src/application/__tests__/apex-file-reader.spec.ts b/src/application/__tests__/apex-file-reader.spec.ts
deleted file mode 100644
index 9b33fc5c..00000000
--- a/src/application/__tests__/apex-file-reader.spec.ts
+++ /dev/null
@@ -1,211 +0,0 @@
-import { FileSystem } from '../file-system';
-import { processFiles } from '../apex-file-reader';
-
-type File = {
- type: 'file';
- path: string;
- content: string;
-};
-
-type Directory = {
- type: 'directory';
- path: string;
- files: (File | Directory)[];
-};
-
-type Path = File | Directory;
-
-class TestFileSystem implements FileSystem {
- constructor(private readonly paths: Path[]) {}
-
- async isDirectory(path: string): Promise {
- const directory = this.findPath(path);
- return directory ? directory.type === 'directory' : false;
- }
-
- joinPath(...paths: string[]): string {
- return paths.join('/');
- }
-
- async readDirectory(sourceDirectory: string): Promise {
- const directory = this.findPath(sourceDirectory);
- if (!directory || directory.type !== 'directory') {
- throw new Error('Directory not found');
- }
- return directory.files.map((f) => f.path);
- }
-
- async readFile(path: string): Promise {
- const file = this.findPath(path);
- if (!file || file.type !== 'file') {
- throw new Error('File not found');
- }
- return file.content;
- }
-
- exists(path: string): boolean {
- return this.paths.some((p) => p.path === path);
- }
-
- findPath(path: string): Path | undefined {
- const splitPath = path.split('/');
- let currentPath = this.paths.find((p) => p.path === splitPath[0]);
- for (let i = 1; i < splitPath.length; i++) {
- if (!currentPath || currentPath.type !== 'directory') {
- return undefined;
- }
- currentPath = currentPath.files.find((f) => f.path === splitPath[i]);
- }
- return currentPath;
- }
-}
-
-describe('File Reader', () => {
- it('returns an empty list when there are no files in the directory', async () => {
- const fileSystem = new TestFileSystem([
- {
- type: 'directory',
- path: '',
- files: [],
- },
- ]);
-
- const result = await processFiles(fileSystem, '', false, []);
-
- expect(result.length).toBe(0);
- });
-
- it('returns an empty list when there are no Apex files in the directory', async () => {
- const fileSystem = new TestFileSystem([
- {
- type: 'directory',
- path: '',
- files: [
- {
- type: 'file',
- path: 'SomeFile.md',
- content: '## Some Markdown',
- },
- ],
- },
- ]);
-
- const result = await processFiles(fileSystem, '', false, []);
- expect(result.length).toBe(0);
- });
-
- it('returns the file contents for all Apex files', async () => {
- const fileSystem = new TestFileSystem([
- {
- type: 'directory',
- path: '',
- files: [
- {
- type: 'file',
- path: 'SomeFile.cls',
- content: 'public class MyClass{}',
- },
- {
- type: 'directory',
- path: 'subdir',
- files: [
- {
- type: 'file',
- path: 'AnotherFile.cls',
- content: 'public class AnotherClass{}',
- },
- ],
- },
- ],
- },
- ]);
-
- const result = await processFiles(fileSystem, '', false, []);
- expect(result.length).toBe(2);
- expect(result[0].content).toBe('public class MyClass{}');
- expect(result[1].content).toBe('public class AnotherClass{}');
- });
-
- it('skips files that match the excluded glob pattern', async () => {
- const fileSystem = new TestFileSystem([
- {
- type: 'directory',
- path: '',
- files: [
- {
- type: 'file',
- path: 'SomeFile.cls',
- content: 'public class MyClass{}',
- },
- {
- type: 'directory',
- path: 'subdir',
- files: [
- {
- type: 'file',
- path: 'AnotherFile.cls',
- content: 'public class AnotherClass{}',
- },
- ],
- },
- ],
- },
- ]);
-
- const result = await processFiles(fileSystem, '', false, ['**/AnotherFile.cls']);
- expect(result.length).toBe(1);
- expect(result[0].content).toBe('public class MyClass{}');
- });
-
- it('returns the file contents for all Apex when there are multiple directories', async () => {
- const fileSystem = new TestFileSystem([
- {
- type: 'directory',
- path: '',
- files: [
- {
- type: 'file',
- path: 'SomeFile.cls',
- content: 'public class MyClass{}',
- },
- {
- type: 'directory',
- path: 'subdir',
- files: [
- {
- type: 'file',
- path: 'AnotherFile.cls',
- content: 'public class AnotherClass{}',
- },
- ],
- },
- {
- type: 'directory',
- path: 'subdir2',
- files: [
- {
- type: 'file',
- path: 'SomeFile2.cls',
- content: 'public class MyClass{}',
- },
- {
- type: 'directory',
- path: 'subdir',
- files: [
- {
- type: 'file',
- path: 'AnotherFile2.cls',
- content: 'public class AnotherClass{}',
- },
- ],
- },
- ],
- },
- ],
- },
- ]);
-
- const result = await processFiles(fileSystem, '', false, []);
- expect(result.length).toBe(4);
- });
-});
diff --git a/src/application/__tests__/source-code-file-reader.spec.ts b/src/application/__tests__/source-code-file-reader.spec.ts
new file mode 100644
index 00000000..7a24e7f0
--- /dev/null
+++ b/src/application/__tests__/source-code-file-reader.spec.ts
@@ -0,0 +1,130 @@
+import { FileSystem } from '../file-system';
+import { processFiles, SourceComponentAdapter } from '../source-code-file-reader';
+
+class TestFileSystem implements FileSystem {
+ constructor(private readonly sourceComponents: SourceComponentAdapter[]) {}
+
+ getComponents(): SourceComponentAdapter[] {
+ return this.sourceComponents;
+ }
+
+ readFile(path: string): string {
+ switch (path) {
+ case 'Speaker.cls':
+ return 'public class Speaker{}';
+ case 'AnotherSpeaker.cls':
+ return 'public class AnotherSpeaker{}';
+ case 'SomeObject__c.object-meta.xml':
+ return `
+
+
+ Deployed
+ test object for testing
+
+ MyFirstObjects
+ `;
+ default:
+ return '';
+ }
+ }
+}
+
+describe('File Reader', () => {
+ it('returns an empty list when no source components are found', async () => {
+ const fileSystem = new TestFileSystem([]);
+
+ const result = processFiles(fileSystem)(['ApexClass'])('', []);
+
+ expect(result.length).toBe(0);
+ });
+
+ it('returns an empty list when reading Apex files and there are none', async () => {
+ const fileSystem = new TestFileSystem([
+ {
+ name: 'Speaker__c',
+ type: {
+ id: 'customobject',
+ name: 'CustomObject',
+ },
+ xml: 'force-app/main/default/objects/Speaker__c/Speaker__c.object-meta.xml',
+ content: 'force-app/main/default/objects/Speaker__c',
+ },
+ ]);
+
+ const result = processFiles(fileSystem)(['ApexClass'])('', []);
+ expect(result.length).toBe(0);
+ });
+
+ it('returns the file contents for all Apex files', async () => {
+ const fileSystem = new TestFileSystem([
+ {
+ name: 'Speaker',
+ type: {
+ id: 'apexclass',
+ name: 'ApexClass',
+ },
+ xml: 'Speaker.cls-meta.xml',
+ content: 'Speaker.cls',
+ },
+ {
+ name: 'AnotherSpeaker',
+ type: {
+ id: 'apexclass',
+ name: 'ApexClass',
+ },
+ xml: 'AnotherSpeaker.cls-meta.xml',
+ content: 'AnotherSpeaker.cls',
+ },
+ ]);
+
+ const result = processFiles(fileSystem)(['ApexClass'])('', []);
+ expect(result.length).toBe(2);
+ expect(result[0].content).toBe('public class Speaker{}');
+ expect(result[1].content).toBe('public class AnotherSpeaker{}');
+ });
+
+ it('returns the file contents of all Object files', async () => {
+ const fileSystem = new TestFileSystem([
+ {
+ name: 'SomeObject__c',
+ type: {
+ id: 'customobject',
+ name: 'CustomObject',
+ },
+ xml: 'SomeObject__c.object-meta.xml',
+ content: '',
+ },
+ ]);
+
+ const result = processFiles(fileSystem)(['CustomObject'])('', []);
+ expect(result.length).toBe(1);
+ expect(result[0].content).toContain('test object for testing');
+ });
+
+ it('skips files that match the excluded glob pattern', async () => {
+ const fileSystem = new TestFileSystem([
+ {
+ name: 'Speaker',
+ type: {
+ id: 'apexclass',
+ name: 'ApexClass',
+ },
+ xml: 'Speaker.cls-meta.xml',
+ content: 'Speaker.cls',
+ },
+ {
+ name: 'AnotherSpeaker',
+ type: {
+ id: 'apexclass',
+ name: 'ApexClass',
+ },
+ xml: 'AnotherSpeaker.cls-meta.xml',
+ content: 'AnotherSpeaker.cls',
+ },
+ ]);
+
+ const result = processFiles(fileSystem)(['ApexClass'])('', ['**/Speaker.cls']);
+ expect(result.length).toBe(1);
+ expect(result[0].content).toBe('public class AnotherSpeaker{}');
+ });
+});
diff --git a/src/application/apex-file-reader.ts b/src/application/apex-file-reader.ts
deleted file mode 100644
index 4ddd3697..00000000
--- a/src/application/apex-file-reader.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-import { FileSystem } from './file-system';
-import { UnparsedSourceFile } from '../core/shared/types';
-import { minimatch } from 'minimatch';
-import { pipe } from 'fp-ts/function';
-import { apply } from '#utils/fp';
-
-const APEX_FILE_EXTENSION = '.cls';
-
-/**
- * Reads from .cls files and returns their raw body.
- */
-export async function processFiles(
- fileSystem: FileSystem,
- rootPath: string,
- includeMetadata: boolean,
- exclude: string[],
-): Promise {
- const processSingleFile = apply(processFile, fileSystem, includeMetadata);
-
- return pipe(
- await getFilePaths(fileSystem, rootPath),
- (filePaths) => filePaths.filter((filePath) => !isExcluded(filePath, exclude)),
- (filePaths) => filePaths.filter(isApexFile),
- (filePaths) => Promise.all(filePaths.map(processSingleFile)),
- );
-}
-
-async function getFilePaths(fileSystem: FileSystem, rootPath: string): Promise {
- const directoryContents = await fileSystem.readDirectory(rootPath);
- const paths: string[] = [];
- for (const filePath of directoryContents) {
- const currentPath = fileSystem.joinPath(rootPath, filePath);
- if (await fileSystem.isDirectory(currentPath)) {
- paths.push(...(await getFilePaths(fileSystem, currentPath)));
- } else {
- paths.push(currentPath);
- }
- }
- return paths;
-}
-
-function isExcluded(filePath: string, exclude: string[]): boolean {
- return exclude.some((pattern) => minimatch(filePath, pattern));
-}
-
-async function processFile(
- fileSystem: FileSystem,
- includeMetadata: boolean,
- filePath: string,
-): Promise {
- const rawTypeContent = await fileSystem.readFile(filePath);
- const metadataPath = `${filePath}-meta.xml`;
- let rawMetadataContent = null;
- if (includeMetadata) {
- rawMetadataContent = fileSystem.exists(metadataPath) ? await fileSystem.readFile(metadataPath) : null;
- }
-
- return { filePath, content: rawTypeContent, metadataContent: rawMetadataContent };
-}
-
-function isApexFile(currentFile: string): boolean {
- return currentFile.endsWith(APEX_FILE_EXTENSION);
-}
diff --git a/src/application/file-system.ts b/src/application/file-system.ts
index 3626bf1d..e45b401c 100644
--- a/src/application/file-system.ts
+++ b/src/application/file-system.ts
@@ -1,69 +1,38 @@
import * as fs from 'fs';
-import * as path from 'path';
+import { MetadataResolver } from '@salesforce/source-deploy-retrieve';
+import { SourceComponentAdapter } from './source-code-file-reader';
+import { pipe } from 'fp-ts/function';
+import * as nodePath from 'path';
export interface FileSystem {
- isDirectory: (path: string) => Promise;
- readDirectory: (sourceDirectory: string) => Promise;
- readFile: (path: string) => Promise;
- joinPath: (...paths: string[]) => string;
- exists: (path: string) => boolean;
-}
-
-function stat(path: string): Promise {
- return new Promise((resolve, reject) => {
- fs.stat(path, (err, stats) => {
- if (err) {
- reject(err);
- } else {
- resolve(stats);
- }
- });
- });
-}
-
-function readdir(path: string): Promise {
- return new Promise((resolve, reject) => {
- fs.readdir(path, (err, files) => {
- if (err) {
- reject(err);
- } else {
- resolve(files);
- }
- });
- });
-}
-
-function readFile(path: string): Promise {
- return new Promise((resolve, reject) => {
- fs.readFile(path, (err, data) => {
- if (err) {
- reject(err);
- } else {
- resolve(data.toString());
- }
- });
- });
+ getComponents(path: string): SourceComponentAdapter[];
+ readFile: (path: string) => string;
}
export class DefaultFileSystem implements FileSystem {
- async isDirectory(pathToRead: string): Promise {
- const stats = await stat(pathToRead);
- return stats.isDirectory();
- }
-
- readDirectory(sourceDirectory: string): Promise {
- return readdir(sourceDirectory);
- }
-
- readFile(pathToRead: string): Promise {
- return readFile(pathToRead);
- }
-
- joinPath(...paths: string[]): string {
- return path.join(...paths);
+ getComponents(path: string): SourceComponentAdapter[] {
+ const components = new MetadataResolver().getComponentsFromPath(path);
+
+ const fieldComponents = pipe(
+ components,
+ (components) => components.filter((component) => component.type.name === 'CustomObject'),
+ (components) => components.map((component) => component.content),
+ (contents) => contents.filter((content) => content !== undefined),
+ (contents) => contents.map((content) => nodePath.join(content!, 'fields')),
+ (potentialFieldLocations) =>
+ potentialFieldLocations.filter((potentialFieldLocation) => fs.existsSync(potentialFieldLocation)),
+ (potentialFieldLocations) =>
+ potentialFieldLocations.map((potentialFieldLocation) =>
+ new MetadataResolver().getComponentsFromPath(potentialFieldLocation),
+ ),
+ (fieldComponents) => fieldComponents.flat(),
+ (fieldComponents) => fieldComponents.filter((fieldComponent) => fieldComponent.type.name === 'CustomField'),
+ );
+
+ return [...components, ...fieldComponents];
}
- exists(path: string): boolean {
- return fs.existsSync(path);
+ readFile(pathToRead: string): string {
+ return fs.readFileSync(pathToRead, 'utf8');
}
}
diff --git a/src/application/generators/changelog.ts b/src/application/generators/changelog.ts
index 8556deb2..d72dd1f9 100644
--- a/src/application/generators/changelog.ts
+++ b/src/application/generators/changelog.ts
@@ -1,5 +1,5 @@
import { pipe } from 'fp-ts/function';
-import { PageData, Skip, UnparsedSourceFile, UserDefinedChangelogConfig } from '../../core/shared/types';
+import { PageData, Skip, UnparsedApexBundle, UserDefinedChangelogConfig } from '../../core/shared/types';
import * as TE from 'fp-ts/TaskEither';
import { writeFiles } from '../file-writer';
import { ChangeLogPageData, generateChangeLog } from '../../core/changelog/generate-change-log';
@@ -7,8 +7,8 @@ import { FileWritingError } from '../errors';
import { isSkip } from '../../core/shared/utils';
export default function generate(
- oldBundles: UnparsedSourceFile[],
- newBundles: UnparsedSourceFile[],
+ oldBundles: UnparsedApexBundle[],
+ newBundles: UnparsedApexBundle[],
config: UserDefinedChangelogConfig,
) {
function handleFile(file: ChangeLogPageData | Skip) {
diff --git a/src/application/generators/markdown.ts b/src/application/generators/markdown.ts
index 50fa766a..56f2e9e1 100644
--- a/src/application/generators/markdown.ts
+++ b/src/application/generators/markdown.ts
@@ -3,7 +3,7 @@ import { pipe } from 'fp-ts/function';
import {
PageData,
PostHookDocumentationBundle,
- UnparsedSourceFile,
+ UnparsedSourceBundle,
UserDefinedMarkdownConfig,
} from '../../core/shared/types';
import { referenceGuideTemplate } from '../../core/markdown/templates/reference-guide';
@@ -12,14 +12,14 @@ import { isSkip } from '../../core/shared/utils';
import { writeFiles } from '../file-writer';
import { FileWritingError } from '../errors';
-export default function generate(bundles: UnparsedSourceFile[], config: UserDefinedMarkdownConfig) {
+export default function generate(bundles: UnparsedSourceBundle[], config: UserDefinedMarkdownConfig) {
return pipe(
generateDocumentationBundle(bundles, config),
TE.flatMap((files) => writeFilesToSystem(files, config.targetDir)),
);
}
-function generateDocumentationBundle(bundles: UnparsedSourceFile[], config: UserDefinedMarkdownConfig) {
+function generateDocumentationBundle(bundles: UnparsedSourceBundle[], config: UserDefinedMarkdownConfig) {
return generateDocs(bundles, {
...config,
referenceGuideTemplate: referenceGuideTemplate,
diff --git a/src/application/generators/openapi.ts b/src/application/generators/openapi.ts
index 8a15d2cd..79ecf7ad 100644
--- a/src/application/generators/openapi.ts
+++ b/src/application/generators/openapi.ts
@@ -6,17 +6,17 @@ import { Logger } from '#utils/logger';
import ErrorLogger from '#utils/error-logger';
import { reflect, ReflectionResult } from '@cparra/apex-reflection';
import Manifest from '../../core/manifest';
-import { PageData, UnparsedSourceFile, UserDefinedOpenApiConfig } from '../../core/shared/types';
+import { PageData, UnparsedApexBundle, UserDefinedOpenApiConfig } from '../../core/shared/types';
import { OpenApiDocsProcessor } from '../../core/openapi/open-api-docs-processor';
import { writeFiles } from '../file-writer';
import { pipe } from 'fp-ts/function';
import * as TE from 'fp-ts/TaskEither';
-import { OpenApiSettings } from '../../core/openApiSettings';
+import { OpenApiSettings } from '../../core/openapi/openApiSettings';
import { apply } from '#utils/fp';
export default async function openApi(
logger: Logger,
- fileBodies: UnparsedSourceFile[],
+ fileBodies: UnparsedApexBundle[],
config: UserDefinedOpenApiConfig,
) {
OpenApiSettings.build({
@@ -46,7 +46,7 @@ export default async function openApi(
ErrorLogger.logErrors(logger, filteredTypes);
}
-function reflectionWithLogger(logger: Logger, apexBundle: UnparsedSourceFile): ReflectionResult {
+function reflectionWithLogger(logger: Logger, apexBundle: UnparsedApexBundle): ReflectionResult {
const result = reflect(apexBundle.content);
if (result.error) {
logger.error(`${apexBundle.filePath} - Parsing error ${result.error?.message}`);
diff --git a/src/application/source-code-file-reader.ts b/src/application/source-code-file-reader.ts
new file mode 100644
index 00000000..7d9b5da3
--- /dev/null
+++ b/src/application/source-code-file-reader.ts
@@ -0,0 +1,168 @@
+import { FileSystem } from './file-system';
+import { UnparsedApexBundle, UnparsedCustomFieldBundle, UnparsedCustomObjectBundle } from '../core/shared/types';
+import { minimatch } from 'minimatch';
+import { flow, pipe } from 'fp-ts/function';
+import { apply } from '#utils/fp';
+
+type ComponentTypes = 'ApexClass' | 'CustomObject' | 'CustomField';
+
+/**
+ * Simplified representation of a source component, with only
+ * the required information we need.
+ */
+export type SourceComponentAdapter = {
+ name: string;
+ type: {
+ id: string;
+ name: string;
+ };
+ xml?: string;
+ content?: string;
+ parent?: {
+ name: string;
+ };
+};
+
+type ApexClassApexSourceComponent = {
+ type: 'ApexClass';
+ name: string;
+ xmlPath?: string;
+ contentPath: string;
+};
+
+type CustomObjectSourceComponent = {
+ type: 'CustomObject';
+ name: string;
+ contentPath: string;
+};
+
+type CustomFieldSourceComponent = {
+ type: 'CustomField';
+ name: string;
+ contentPath: string;
+ parentName: string;
+};
+
+function getApexSourceComponents(
+ includeMetadata: boolean,
+ sourceComponents: SourceComponentAdapter[],
+): ApexClassApexSourceComponent[] {
+ return sourceComponents
+ .filter((component) => component.type.name === 'ApexClass')
+ .map((component) => ({
+ type: 'ApexClass' as const,
+ name: component.name,
+ xmlPath: includeMetadata ? component.xml : undefined,
+ contentPath: component.content!,
+ }));
+}
+
+function toUnparsedApexBundle(
+ fileSystem: FileSystem,
+ apexSourceComponents: ApexClassApexSourceComponent[],
+): UnparsedApexBundle[] {
+ return apexSourceComponents.map((component) => {
+ const apexComponentTuple: [string, string | null] = [
+ fileSystem.readFile(component.contentPath),
+ component.xmlPath ? fileSystem.readFile(component.xmlPath) : null,
+ ];
+
+ return {
+ type: 'apex',
+ name: component.name,
+ filePath: component.contentPath,
+ content: apexComponentTuple[0],
+ metadataContent: apexComponentTuple[1],
+ };
+ });
+}
+
+function getCustomObjectSourceComponents(sourceComponents: SourceComponentAdapter[]): CustomObjectSourceComponent[] {
+ return sourceComponents
+ .filter((component) => component.type.name === 'CustomObject')
+ .map((component) => ({
+ name: component.name,
+ type: 'CustomObject' as const,
+ contentPath: component.xml!,
+ }));
+}
+
+function toUnparsedSObjectBundle(
+ fileSystem: FileSystem,
+ customObjectSourceComponents: CustomObjectSourceComponent[],
+): UnparsedCustomObjectBundle[] {
+ return customObjectSourceComponents.map((component) => {
+ return {
+ type: 'customobject',
+ name: component.name,
+ filePath: component.contentPath,
+ content: fileSystem.readFile(component.contentPath),
+ };
+ });
+}
+
+function getCustomFieldSourceComponents(sourceComponents: SourceComponentAdapter[]): CustomFieldSourceComponent[] {
+ return sourceComponents
+ .filter((component) => component.type.name === 'CustomField')
+ .map((component) => ({
+ name: component.name,
+ type: 'CustomField' as const,
+ contentPath: component.xml!,
+ parentName: component.parent!.name,
+ }));
+}
+
+function toUnparsedCustomFieldBundle(
+ fileSystem: FileSystem,
+ customFieldSourceComponents: CustomFieldSourceComponent[],
+): UnparsedCustomFieldBundle[] {
+ return customFieldSourceComponents.map((component) => ({
+ type: 'customfield',
+ name: component.name,
+ filePath: component.contentPath,
+ content: fileSystem.readFile(component.contentPath),
+ parentName: component.parentName,
+ }));
+}
+
+/**
+ * Reads from source code files and returns their raw body.
+ */
+export function processFiles(fileSystem: FileSystem) {
+ return (
+ componentTypesToRetrieve: T,
+ options: { includeMetadata: boolean } = { includeMetadata: false },
+ ) => {
+ const converters: Record<
+ ComponentTypes,
+ (
+ components: SourceComponentAdapter[],
+ ) => (UnparsedApexBundle | UnparsedCustomObjectBundle | UnparsedCustomFieldBundle)[]
+ > = {
+ ApexClass: flow(apply(getApexSourceComponents, options.includeMetadata), (apexSourceComponents) =>
+ toUnparsedApexBundle(fileSystem, apexSourceComponents),
+ ),
+ CustomObject: flow(getCustomObjectSourceComponents, (customObjectSourceComponents) =>
+ toUnparsedSObjectBundle(fileSystem, customObjectSourceComponents),
+ ),
+ CustomField: flow(getCustomFieldSourceComponents, (customFieldSourceComponents) =>
+ toUnparsedCustomFieldBundle(fileSystem, customFieldSourceComponents),
+ ),
+ };
+
+ const convertersToUse = componentTypesToRetrieve.map((componentType) => converters[componentType]);
+
+ return (rootPath: string, exclude: string[]) => {
+ return pipe(
+ fileSystem.getComponents(rootPath),
+ (components) => components.filter((component) => !isExcluded(component.content!, exclude)),
+ (components) => convertersToUse.map((converter) => converter(components)),
+ (bundles) => bundles.flat(),
+ );
+ };
+ };
+}
+
+function isExcluded(filePath: string, exclude: string[]): boolean {
+ return exclude.some((pattern) => minimatch(filePath, pattern));
+}
diff --git a/src/cli/args.ts b/src/cli/args.ts
index 52e38f74..9f6cedc5 100644
--- a/src/cli/args.ts
+++ b/src/cli/args.ts
@@ -122,7 +122,6 @@ function extractArgsForCommandsProvidedInConfig(
return pipe(
extractMultiCommandConfig(extractFromProcessFn, 'markdown', generatorConfig),
E.map((cliArgs) => {
- console.log('markdown', cliArgs);
return cliArgs;
}),
E.map((cliArgs) => ({ ...configOnlyMarkdownDefaults, ...generatorConfig, ...cliArgs })),
@@ -136,7 +135,6 @@ function extractArgsForCommandsProvidedInConfig(
return pipe(
extractMultiCommandConfig(extractFromProcessFn, 'changelog', generatorConfig),
E.map((cliArgs) => {
- console.log('changelog', cliArgs);
return cliArgs;
}),
E.map((cliArgs) => ({ ...configOnlyChangelogDefaults, ...generatorConfig, ...cliArgs })),
@@ -224,7 +222,6 @@ function extractMultiCommandConfig(
}
const options = getOptions(command);
- console.log('config', config);
return E.tryCatch(() => {
return yargs(extractFromProcessFn())
.config(config)
diff --git a/src/cli/commands/markdown.ts b/src/cli/commands/markdown.ts
index 46cfb46b..b8531a9f 100644
--- a/src/cli/commands/markdown.ts
+++ b/src/cli/commands/markdown.ts
@@ -28,6 +28,11 @@ export const markdownOptions: { [key: string]: Options } = {
default: markdownDefaults.defaultGroupName,
describe: 'Defines the @group name to be used when a file does not specify it.',
},
+ customObjectGroupName: {
+ type: 'string',
+ default: markdownDefaults.customObjectsGroupName,
+ describe: 'The name under which custom objects will be grouped in the Reference Guide',
+ },
namespace: {
type: 'string',
describe: 'The package namespace, if any. If provided, it will be added to the generated files.',
diff --git a/src/core/changelog/__test__/generating-change-log.spec.ts b/src/core/changelog/__test__/generating-change-log.spec.ts
index 55c9bf33..28e9512e 100644
--- a/src/core/changelog/__test__/generating-change-log.spec.ts
+++ b/src/core/changelog/__test__/generating-change-log.spec.ts
@@ -1,4 +1,4 @@
-import { UnparsedSourceFile } from '../../shared/types';
+import { UnparsedApexBundle } from '../../shared/types';
import { ChangeLogPageData, generateChangeLog } from '../generate-change-log';
import { assertEither } from '../../test-helpers/assert-either';
import { isSkip } from '../../shared/utils';
@@ -34,8 +34,8 @@ describe('when generating a changelog', () => {
describe('that does not include new classes', () => {
it('should not have a section for new classes', async () => {
- const oldBundle: UnparsedSourceFile[] = [];
- const newBundle: UnparsedSourceFile[] = [];
+ const oldBundle: UnparsedApexBundle[] = [];
+ const newBundle: UnparsedApexBundle[] = [];
const result = await generateChangeLog(oldBundle, newBundle, config)();
@@ -47,9 +47,9 @@ describe('when generating a changelog', () => {
it('should include a section for new classes', async () => {
const newClassSource = 'class Test {}';
- const oldBundle: UnparsedSourceFile[] = [];
- const newBundle: UnparsedSourceFile[] = [
- { content: newClassSource, filePath: 'Test.cls', metadataContent: null },
+ const oldBundle: UnparsedApexBundle[] = [];
+ const newBundle: UnparsedApexBundle[] = [
+ { type: 'apex', name: 'Test', content: newClassSource, filePath: 'Test.cls', metadataContent: null },
];
const result = await generateChangeLog(oldBundle, newBundle, config)();
@@ -60,9 +60,9 @@ describe('when generating a changelog', () => {
it('should include the new class name', async () => {
const newClassSource = 'class Test {}';
- const oldBundle: UnparsedSourceFile[] = [];
- const newBundle: UnparsedSourceFile[] = [
- { content: newClassSource, filePath: 'Test.cls', metadataContent: null },
+ const oldBundle: UnparsedApexBundle[] = [];
+ const newBundle: UnparsedApexBundle[] = [
+ { type: 'apex', name: 'Test', content: newClassSource, filePath: 'Test.cls', metadataContent: null },
];
const result = await generateChangeLog(oldBundle, newBundle, config)();
@@ -78,9 +78,9 @@ describe('when generating a changelog', () => {
class Test {}
`;
- const oldBundle: UnparsedSourceFile[] = [];
- const newBundle: UnparsedSourceFile[] = [
- { content: newClassSource, filePath: 'Test.cls', metadataContent: null },
+ const oldBundle: UnparsedApexBundle[] = [];
+ const newBundle: UnparsedApexBundle[] = [
+ { type: 'apex', name: 'Test', content: newClassSource, filePath: 'Test.cls', metadataContent: null },
];
const result = await generateChangeLog(oldBundle, newBundle, config)();
@@ -93,9 +93,9 @@ describe('when generating a changelog', () => {
it('should include a section for new interfaces', async () => {
const newInterfaceSource = 'interface Test {}';
- const oldBundle: UnparsedSourceFile[] = [];
- const newBundle: UnparsedSourceFile[] = [
- { content: newInterfaceSource, filePath: 'Test.cls', metadataContent: null },
+ const oldBundle: UnparsedApexBundle[] = [];
+ const newBundle: UnparsedApexBundle[] = [
+ { type: 'apex', name: 'Test', content: newInterfaceSource, filePath: 'Test.cls', metadataContent: null },
];
const result = await generateChangeLog(oldBundle, newBundle, config)();
@@ -106,9 +106,9 @@ describe('when generating a changelog', () => {
it('should include the new interface name', async () => {
const newInterfaceSource = 'interface Test {}';
- const oldBundle: UnparsedSourceFile[] = [];
- const newBundle: UnparsedSourceFile[] = [
- { content: newInterfaceSource, filePath: 'Test.cls', metadataContent: null },
+ const oldBundle: UnparsedApexBundle[] = [];
+ const newBundle: UnparsedApexBundle[] = [
+ { type: 'apex', name: 'Test', content: newInterfaceSource, filePath: 'Test.cls', metadataContent: null },
];
const result = await generateChangeLog(oldBundle, newBundle, config)();
@@ -124,9 +124,9 @@ describe('when generating a changelog', () => {
interface Test {}
`;
- const oldBundle: UnparsedSourceFile[] = [];
- const newBundle: UnparsedSourceFile[] = [
- { content: newInterfaceSource, filePath: 'Test.cls', metadataContent: null },
+ const oldBundle: UnparsedApexBundle[] = [];
+ const newBundle: UnparsedApexBundle[] = [
+ { type: 'apex', name: 'Test', content: newInterfaceSource, filePath: 'Test.cls', metadataContent: null },
];
const result = await generateChangeLog(oldBundle, newBundle, config)();
@@ -141,8 +141,10 @@ describe('when generating a changelog', () => {
it('should include a section for new enums', async () => {
const newEnumSource = 'enum Test {}';
- const oldBundle: UnparsedSourceFile[] = [];
- const newBundle: UnparsedSourceFile[] = [{ content: newEnumSource, filePath: 'Test.cls', metadataContent: null }];
+ const oldBundle: UnparsedApexBundle[] = [];
+ const newBundle: UnparsedApexBundle[] = [
+ { type: 'apex', name: 'Test', content: newEnumSource, filePath: 'Test.cls', metadataContent: null },
+ ];
const result = await generateChangeLog(oldBundle, newBundle, config)();
@@ -152,8 +154,10 @@ describe('when generating a changelog', () => {
it('should include the new enum name', async () => {
const newEnumSource = 'enum Test {}';
- const oldBundle: UnparsedSourceFile[] = [];
- const newBundle: UnparsedSourceFile[] = [{ content: newEnumSource, filePath: 'Test.cls', metadataContent: null }];
+ const oldBundle: UnparsedApexBundle[] = [];
+ const newBundle: UnparsedApexBundle[] = [
+ { type: 'apex', name: 'Test', content: newEnumSource, filePath: 'Test.cls', metadataContent: null },
+ ];
const result = await generateChangeLog(oldBundle, newBundle, config)();
@@ -168,8 +172,10 @@ describe('when generating a changelog', () => {
enum Test {}
`;
- const oldBundle: UnparsedSourceFile[] = [];
- const newBundle: UnparsedSourceFile[] = [{ content: newEnumSource, filePath: 'Test.cls', metadataContent: null }];
+ const oldBundle: UnparsedApexBundle[] = [];
+ const newBundle: UnparsedApexBundle[] = [
+ { type: 'apex', name: 'Test', content: newEnumSource, filePath: 'Test.cls', metadataContent: null },
+ ];
const result = await generateChangeLog(oldBundle, newBundle, config)();
@@ -181,9 +187,9 @@ describe('when generating a changelog', () => {
it('should not include them', async () => {
const newClassSource = 'class Test {}';
- const oldBundle: UnparsedSourceFile[] = [];
- const newBundle: UnparsedSourceFile[] = [
- { content: newClassSource, filePath: 'Test.cls', metadataContent: null },
+ const oldBundle: UnparsedApexBundle[] = [];
+ const newBundle: UnparsedApexBundle[] = [
+ { type: 'apex', name: 'Test', content: newClassSource, filePath: 'Test.cls', metadataContent: null },
];
const result = await generateChangeLog(oldBundle, newBundle, { ...config, scope: ['global'] })();
@@ -196,10 +202,10 @@ describe('when generating a changelog', () => {
it('should include a section for removed types', async () => {
const oldClassSource = 'class Test {}';
- const oldBundle: UnparsedSourceFile[] = [
- { content: oldClassSource, filePath: 'Test.cls', metadataContent: null },
+ const oldBundle: UnparsedApexBundle[] = [
+ { type: 'apex', name: 'Test', content: oldClassSource, filePath: 'Test.cls', metadataContent: null },
];
- const newBundle: UnparsedSourceFile[] = [];
+ const newBundle: UnparsedApexBundle[] = [];
const result = await generateChangeLog(oldBundle, newBundle, config)();
@@ -209,10 +215,10 @@ describe('when generating a changelog', () => {
it('should include the removed type name', async () => {
const oldClassSource = 'class Test {}';
- const oldBundle: UnparsedSourceFile[] = [
- { content: oldClassSource, filePath: 'Test.cls', metadataContent: null },
+ const oldBundle: UnparsedApexBundle[] = [
+ { type: 'apex', name: 'Test', content: oldClassSource, filePath: 'Test.cls', metadataContent: null },
];
- const newBundle: UnparsedSourceFile[] = [];
+ const newBundle: UnparsedApexBundle[] = [];
const result = await generateChangeLog(oldBundle, newBundle, config)();
@@ -225,12 +231,12 @@ describe('when generating a changelog', () => {
const oldClassSource = 'class Test {}';
const newClassSource = 'class Test { void myMethod() {} }';
- const oldBundle: UnparsedSourceFile[] = [
- { content: oldClassSource, filePath: 'Test.cls', metadataContent: null },
+ const oldBundle: UnparsedApexBundle[] = [
+ { type: 'apex', name: 'Test', content: oldClassSource, filePath: 'Test.cls', metadataContent: null },
];
- const newBundle: UnparsedSourceFile[] = [
- { content: newClassSource, filePath: 'Test.cls', metadataContent: null },
+ const newBundle: UnparsedApexBundle[] = [
+ { type: 'apex', name: 'Test', content: newClassSource, filePath: 'Test.cls', metadataContent: null },
];
const result = await generateChangeLog(oldBundle, newBundle, config)();
@@ -244,12 +250,12 @@ describe('when generating a changelog', () => {
const oldClassSource = 'class Test {}';
const newClassSource = 'class Test { void myMethod() {} }';
- const oldBundle: UnparsedSourceFile[] = [
- { content: oldClassSource, filePath: 'Test.cls', metadataContent: null },
+ const oldBundle: UnparsedApexBundle[] = [
+ { type: 'apex', name: 'Test', content: oldClassSource, filePath: 'Test.cls', metadataContent: null },
];
- const newBundle: UnparsedSourceFile[] = [
- { content: newClassSource, filePath: 'Test.cls', metadataContent: null },
+ const newBundle: UnparsedApexBundle[] = [
+ { type: 'apex', name: 'Test', content: newClassSource, filePath: 'Test.cls', metadataContent: null },
];
const result = await generateChangeLog(oldBundle, newBundle, config)();
@@ -261,12 +267,12 @@ describe('when generating a changelog', () => {
const oldClassSource = 'class Test {}';
const newClassSource = 'class Test { void myMethod() {} }';
- const oldBundle: UnparsedSourceFile[] = [
- { content: oldClassSource, filePath: 'Test.cls', metadataContent: null },
+ const oldBundle: UnparsedApexBundle[] = [
+ { type: 'apex', name: 'Test', content: oldClassSource, filePath: 'Test.cls', metadataContent: null },
];
- const newBundle: UnparsedSourceFile[] = [
- { content: newClassSource, filePath: 'Test.cls', metadataContent: null },
+ const newBundle: UnparsedApexBundle[] = [
+ { type: 'apex', name: 'Test', content: newClassSource, filePath: 'Test.cls', metadataContent: null },
];
const result = await generateChangeLog(oldBundle, newBundle, config)();
diff --git a/src/core/changelog/generate-change-log.ts b/src/core/changelog/generate-change-log.ts
index 371073ca..9552308f 100644
--- a/src/core/changelog/generate-change-log.ts
+++ b/src/core/changelog/generate-change-log.ts
@@ -1,15 +1,15 @@
-import { ParsedFile, Skip, UnparsedSourceFile, UserDefinedChangelogConfig } from '../shared/types';
+import { ParsedFile, Skip, UnparsedApexBundle, UserDefinedChangelogConfig } from '../shared/types';
import { pipe } from 'fp-ts/function';
import * as TE from 'fp-ts/TaskEither';
-import { reflectBundles } from '../reflection/reflect-source';
+import { reflectApexSource } from '../reflection/apex/reflect-apex-source';
import { Changelog, hasChanges, processChangelog, VersionManifest } from './process-changelog';
import { convertToRenderableChangelog, RenderableChangelog } from './renderable-changelog';
import { CompilationRequest, Template } from '../template';
import { changelogTemplate } from './templates/changelog-template';
import { ReflectionErrors } from '../errors/errors';
import { apply } from '#utils/fp';
-import { filterScope } from '../reflection/filter-scope';
-import { skip } from '../shared/utils';
+import { filterScope } from '../reflection/apex/filter-scope';
+import { isApexType, skip } from '../shared/utils';
export type ChangeLogPageData = {
content: string;
@@ -17,14 +17,14 @@ export type ChangeLogPageData = {
};
export function generateChangeLog(
- oldBundles: UnparsedSourceFile[],
- newBundles: UnparsedSourceFile[],
+ oldBundles: UnparsedApexBundle[],
+ newBundles: UnparsedApexBundle[],
config: Omit,
): TE.TaskEither {
const filterOutOfScope = apply(filterScope, config.scope);
- function reflect(sourceFiles: UnparsedSourceFile[]) {
- return pipe(reflectBundles(sourceFiles), TE.map(filterOutOfScope));
+ function reflect(sourceFiles: UnparsedApexBundle[]) {
+ return pipe(reflectApexSource(sourceFiles), TE.map(filterOutOfScope));
}
const convertToPageData = apply(toPageData, config.fileName);
@@ -52,7 +52,10 @@ export function generateChangeLog(
function toManifests({ oldVersion, newVersion }: { oldVersion: ParsedFile[]; newVersion: ParsedFile[] }) {
function parsedFilesToManifest(parsedFiles: ParsedFile[]): VersionManifest {
return {
- types: parsedFiles.map((parsedFile) => parsedFile.type),
+ types: parsedFiles
+ .map((parsedFile) => parsedFile.type)
+ // Changelog does not currently support object types
+ .filter((type) => isApexType(type)),
};
}
diff --git a/src/core/markdown/__test__/generating-any-apex-doc.spec.ts b/src/core/markdown/__test__/generating-any-apex-doc.spec.ts
new file mode 100644
index 00000000..44ce4404
--- /dev/null
+++ b/src/core/markdown/__test__/generating-any-apex-doc.spec.ts
@@ -0,0 +1,269 @@
+import { extendExpect } from './expect-extensions';
+import { unparsedApexBundleFromRawString, generateDocs } from './test-helpers';
+import { assertEither } from '../../test-helpers/assert-either';
+
+describe('When generating documentation', () => {
+ beforeAll(() => {
+ extendExpect();
+ });
+
+ describe('the documentation content', () => {
+ it('displays type level annotations', async () => {
+ const input = `
+ @NamespaceAccessible
+ public class MyClass {
+ @Deprecated
+ public void myMethod() {}
+ }
+ `;
+
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
+
+ expect(result).documentationBundleHasLength(1);
+ assertEither(result, (data) => expect(data).firstDocContains('NAMESPACEACCESSIBLE'));
+ assertEither(result, (data) => expect(data).firstDocContains('DEPRECATED'));
+ });
+
+ it('displays metadata as annotations', async () => {
+ const input = 'public class MyClass {}';
+ const metadata = `
+
+
+ 59.0
+ Active
+
+ `;
+
+ const result = await generateDocs([unparsedApexBundleFromRawString(input, metadata)])();
+
+ expect(result).documentationBundleHasLength(1);
+ assertEither(result, (data) => expect(data).firstDocContains('APIVERSION'));
+ assertEither(result, (data) => expect(data).firstDocContains('STATUS'));
+ });
+
+ it('displays the description when no @description tag is used', async () => {
+ const input = `
+ /**
+ * This is a description
+ */
+ public class MyClass {}
+ `;
+
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
+
+ expect(result).documentationBundleHasLength(1);
+ assertEither(result, (data) => expect(data).firstDocContains('This is a description'));
+ });
+
+ it('displays the description when a @description tag is used', async () => {
+ const input = `
+ /**
+ * @description This is a description
+ */
+ public class MyClass {}`;
+
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
+ expect(result).documentationBundleHasLength(1);
+ assertEither(result, (data) => expect(data).firstDocContains('This is a description'));
+ });
+
+ it('display custom documentation tags', async () => {
+ const input = `
+ /**
+ * @custom-tag My Value
+ */
+ public class MyClass {}
+ `;
+
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
+ expect(result).documentationBundleHasLength(1);
+ assertEither(result, (data) => expect(data).firstDocContains('Custom Tag'));
+ assertEither(result, (data) => expect(data).firstDocContains('My Value'));
+ });
+
+ it('displays the group', async () => {
+ const input = `
+ /**
+ * @group MyGroup
+ */
+ public class MyClass {}`;
+
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
+ expect(result).documentationBundleHasLength(1);
+ assertEither(result, (data) => expect(data).firstDocContains('Group'));
+ assertEither(result, (data) => expect(data).firstDocContains('MyGroup'));
+ });
+
+ it('displays the author', async () => {
+ const input = `
+ /**
+ * @author John Doe
+ */
+ public class MyClass {}`;
+
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
+ expect(result).documentationBundleHasLength(1);
+ assertEither(result, (data) => expect(data).firstDocContains('Author'));
+ assertEither(result, (data) => expect(data).firstDocContains('John Doe'));
+ });
+
+ it('displays the date', async () => {
+ const input = `
+ /**
+ * @date 2021-01-01
+ */
+ public class MyClass {}`;
+
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
+ expect(result).documentationBundleHasLength(1);
+ assertEither(result, (data) => expect(data).firstDocContains('Date'));
+ assertEither(result, (data) => expect(data).firstDocContains('2021-01-01'));
+ });
+
+ it('displays descriptions with links', async () => {
+ const input1 = `
+ /**
+ * @description This is a description with a {@link ClassRef} reference
+ */
+ public enum MyClass {}
+ `;
+
+ const input2 = 'public class ClassRef {}';
+
+ const result = await generateDocs([
+ unparsedApexBundleFromRawString(input1),
+ unparsedApexBundleFromRawString(input2),
+ ])();
+ expect(result).documentationBundleHasLength(2);
+ assertEither(result, (data) =>
+ expect(data).firstDocContains('This is a description with a [ClassRef](ClassRef.md) reference'),
+ );
+ });
+
+ it('displays descriptions with emails', async () => {
+ const input = `
+ /**
+ * @description This is a description with an {@email test@testerson.com} email
+ */
+ public class MyClass {}
+ `;
+
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
+ expect(result).documentationBundleHasLength(1);
+ assertEither(result, (data) =>
+ expect(data).firstDocContains(
+ 'This is a description with an [test@testerson.com](mailto:test@testerson.com) email',
+ ),
+ );
+ });
+
+ it('displays @sees with accurately resolved links', async () => {
+ const input1 = `
+ /**
+ * @see ClassRef
+ */
+ public class MyClass {}
+ `;
+
+ const input2 = 'public class ClassRef {}';
+
+ const result = await generateDocs([
+ unparsedApexBundleFromRawString(input1),
+ unparsedApexBundleFromRawString(input2),
+ ])();
+ expect(result).documentationBundleHasLength(2);
+ assertEither(result, (data) => expect(data).firstDocContains('See'));
+ assertEither(result, (data) => expect(data).firstDocContains('[ClassRef](ClassRef.md)'));
+ });
+
+ it('displays @sees without links when the reference is not found', async () => {
+ const input = `
+ /**
+ * @see ClassRef
+ */
+ public class MyClass {}
+ `;
+
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
+
+ expect(result).documentationBundleHasLength(1);
+ assertEither(result, (data) => expect(data).firstDocContains('See'));
+ assertEither(result, (data) => expect(data).firstDocContains('ClassRef'));
+ });
+
+ it('displays the namespace if present in the config', async () => {
+ const input = 'public class MyClass {}';
+
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)], { namespace: 'MyNamespace' })();
+ expect(result).documentationBundleHasLength(1);
+ assertEither(result, (data) => expect(data).firstDocContains('## Namespace'));
+ assertEither(result, (data) => expect(data).firstDocContains('MyNamespace'));
+ });
+
+ it('does not display the namespace if not present in the config', async () => {
+ const input = 'public class MyClass {}';
+
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
+ expect(result).documentationBundleHasLength(1);
+ assertEither(result, (data) => expect(data).firstDocContainsNot('## Namespace'));
+ });
+
+ it('displays a mermaid diagram', async () => {
+ const input = `
+ /**
+ * @mermaid
+ * \`\`\`mermaid
+ * graph TD
+ * A[Square Rect] -- Link text --> B((Circle))
+ * A --> C(Round Rect)
+ * B --> D{Rhombus}
+ * C --> D
+ * \`\`\`
+ */
+ public class MyClass {}
+ `;
+
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
+ expect(result).documentationBundleHasLength(1);
+ assertEither(result, (data) => expect(data).firstDocContains('```mermaid'));
+ assertEither(result, (data) => expect(data).firstDocContains('graph TD'));
+ });
+
+ it('displays an example code block', async () => {
+ const input = `
+ /**
+ * @example
+ * \`\`\`apex
+ * public class MyClass {
+ * public void myMethod() {
+ * System.debug('Hello, World!');
+ * }
+ * }
+ * \`\`\`
+ */
+ public class MyClass {}`;
+
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
+
+ expect(result).documentationBundleHasLength(1);
+ assertEither(result, (data) => expect(data).firstDocContains('```apex'));
+ assertEither(result, (data) => expect(data).firstDocContains('public class MyClass'));
+ });
+
+ it('does not display tags marked as excluded', async () => {
+ const input = `
+ /**
+ * @see ClassRef
+ */
+ public class MyClass {}
+ `;
+
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)], {
+ excludeTags: ['see'],
+ })();
+
+ expect(result).documentationBundleHasLength(1);
+ assertEither(result, (data) => expect(data).firstDocContainsNot('See'));
+ });
+ });
+});
diff --git a/src/core/markdown/__test__/generating-class-docs.spec.ts b/src/core/markdown/__test__/generating-class-docs.spec.ts
index 9c4ab2c5..56ad9a36 100644
--- a/src/core/markdown/__test__/generating-class-docs.spec.ts
+++ b/src/core/markdown/__test__/generating-class-docs.spec.ts
@@ -1,5 +1,5 @@
import { extendExpect } from './expect-extensions';
-import { apexBundleFromRawString, generateDocs } from './test-helpers';
+import { unparsedApexBundleFromRawString, generateDocs } from './test-helpers';
import { assertEither } from '../../test-helpers/assert-either';
describe('When generating documentation for a class', () => {
@@ -15,7 +15,7 @@ describe('When generating documentation for a class', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)])();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => expect(data).firstDocContains('## Methods'));
});
@@ -28,7 +28,7 @@ describe('When generating documentation for a class', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)], { sortAlphabetically: true })();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)], { sortAlphabetically: true })();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => {
const aMethodIndex = data.docs[0].content.indexOf('aMethod');
@@ -45,7 +45,7 @@ describe('When generating documentation for a class', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)], { sortAlphabetically: false })();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)], { sortAlphabetically: false })();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => {
const aMethodIndex = data.docs[0].content.indexOf('aMethod');
@@ -61,7 +61,7 @@ describe('When generating documentation for a class', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)])();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => expect(data).firstDocContains('## Properties'));
});
@@ -74,7 +74,7 @@ describe('When generating documentation for a class', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)], { sortAlphabetically: true })();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)], { sortAlphabetically: true })();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => {
const aPropertyIndex = data.docs[0].content.indexOf('aProperty');
@@ -91,7 +91,7 @@ describe('When generating documentation for a class', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)], { sortAlphabetically: false })();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)], { sortAlphabetically: false })();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => {
const aPropertyIndex = data.docs[0].content.indexOf('aProperty');
@@ -107,7 +107,7 @@ describe('When generating documentation for a class', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)])();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => expect(data).firstDocContains('## Fields'));
});
@@ -120,7 +120,7 @@ describe('When generating documentation for a class', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)], { sortAlphabetically: true })();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)], { sortAlphabetically: true })();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => {
const aFieldIndex = data.docs[0].content.indexOf('aField');
@@ -137,7 +137,7 @@ describe('When generating documentation for a class', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)], { sortAlphabetically: false })();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)], { sortAlphabetically: false })();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => {
const aFieldIndex = data.docs[0].content.indexOf('aField');
@@ -153,7 +153,7 @@ describe('When generating documentation for a class', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)])();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => expect(data).firstDocContains('## Constructors'));
});
@@ -165,7 +165,7 @@ describe('When generating documentation for a class', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)])();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => expect(data).firstDocContains('## Classes'));
});
@@ -178,7 +178,7 @@ describe('When generating documentation for a class', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)], { sortAlphabetically: true })();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)], { sortAlphabetically: true })();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => {
const aInnerClassIndex = data.docs[0].content.indexOf('AInnerClass');
@@ -195,7 +195,7 @@ describe('When generating documentation for a class', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)], { sortAlphabetically: false })();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)], { sortAlphabetically: false })();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => {
const aInnerClassIndex = data.docs[0].content.indexOf('AInnerClass');
@@ -211,7 +211,7 @@ describe('When generating documentation for a class', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)])();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => expect(data).firstDocContains('## Interfaces'));
});
@@ -224,7 +224,7 @@ describe('When generating documentation for a class', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)], { sortAlphabetically: true })();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)], { sortAlphabetically: true })();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => {
const aInnerInterfaceIndex = data.docs[0].content.indexOf('AInnerInterface');
@@ -241,7 +241,7 @@ describe('When generating documentation for a class', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)], { sortAlphabetically: false })();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)], { sortAlphabetically: false })();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => {
const aInnerInterfaceIndex = data.docs[0].content.indexOf('AInnerInterface');
@@ -257,7 +257,7 @@ describe('When generating documentation for a class', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)])();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => expect(data).firstDocContains('## Enums'));
});
@@ -270,7 +270,7 @@ describe('When generating documentation for a class', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)], { sortAlphabetically: true })();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)], { sortAlphabetically: true })();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => {
const aInnerEnumIndex = data.docs[0].content.indexOf('AInnerEnum');
@@ -287,7 +287,7 @@ describe('When generating documentation for a class', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)], { sortAlphabetically: false })();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)], { sortAlphabetically: false })();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => {
const aInnerEnumIndex = data.docs[0].content.indexOf('AInnerEnum');
@@ -313,7 +313,7 @@ describe('When generating documentation for a class', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)])();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => expect(data).firstDocContains('```mermaid'));
assertEither(result, (data) => expect(data).firstDocContains('graph TD'));
@@ -334,7 +334,7 @@ describe('When generating documentation for a class', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)])();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => expect(data).firstDocContains('```apex'));
assertEither(result, (data) => expect(data).firstDocContains('public class MyClass'));
@@ -351,7 +351,10 @@ describe('When generating documentation for a class', () => {
public class AnotherClass extends MyClass {}
`;
- const result = await generateDocs([apexBundleFromRawString(input1), apexBundleFromRawString(input2)])();
+ const result = await generateDocs([
+ unparsedApexBundleFromRawString(input1),
+ unparsedApexBundleFromRawString(input2),
+ ])();
expect(result).documentationBundleHasLength(2);
assertEither(result, (data) =>
expect(data.docs.find((doc) => doc.source.name === 'AnotherClass')?.content).toContain('Inherited'),
diff --git a/src/core/markdown/__test__/generating-custom-object-docs.spec.ts b/src/core/markdown/__test__/generating-custom-object-docs.spec.ts
new file mode 100644
index 00000000..f08d0499
--- /dev/null
+++ b/src/core/markdown/__test__/generating-custom-object-docs.spec.ts
@@ -0,0 +1,129 @@
+import { extendExpect } from './expect-extensions';
+import {
+ customField,
+ customObjectGenerator,
+ generateDocs,
+ unparsedFieldBundleFromRawString,
+ unparsedObjectBundleFromRawString,
+} from './test-helpers';
+import { assertEither } from '../../test-helpers/assert-either';
+
+describe('Generates Custom Object documentation', () => {
+ beforeAll(() => {
+ extendExpect();
+ });
+
+ describe('documentation content', () => {
+ it('displays the object label as a heading', async () => {
+ const input = unparsedObjectBundleFromRawString({
+ rawContent: customObjectGenerator(),
+ filePath: 'src/object/TestObject__c.object-meta.xml',
+ });
+
+ const result = await generateDocs([input])();
+ expect(result).documentationBundleHasLength(1);
+ assertEither(result, (data) => expect(data).firstDocContains('# MyTestObject'));
+ });
+
+ it('displays the object description', async () => {
+ const input = unparsedObjectBundleFromRawString({
+ rawContent: customObjectGenerator(),
+ filePath: 'src/object/TestObject__c.object-meta.xml',
+ });
+
+ const result = await generateDocs([input])();
+ expect(result).documentationBundleHasLength(1);
+ assertEither(result, (data) => expect(data).firstDocContains('test object for testing'));
+ });
+
+ it('displays the object api name', async () => {
+ const input = unparsedObjectBundleFromRawString({
+ rawContent: customObjectGenerator(),
+ filePath: 'src/object/TestObject__c.object-meta.xml',
+ });
+
+ const result = await generateDocs([input])();
+ 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(),
+ filePath: 'src/object/TestObject__c.object-meta.xml',
+ });
+
+ const customFieldBundle = unparsedFieldBundleFromRawString({
+ rawContent: customField,
+ 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('## Fields'));
+ });
+
+ it('does not display the Fields heading if no fields are present', async () => {
+ const input = unparsedObjectBundleFromRawString({
+ rawContent: customObjectGenerator(),
+ filePath: 'src/object/TestObject__c.object-meta.xml',
+ });
+
+ const result = await generateDocs([input])();
+ expect(result).documentationBundleHasLength(1);
+ assertEither(result, (data) => expect(data).not.firstDocContains('## Fields'));
+ });
+
+ it('displays the field label as a heading', async () => {
+ const customObjectBundle = unparsedObjectBundleFromRawString({
+ rawContent: customObjectGenerator(),
+ filePath: 'src/object/TestObject__c.object-meta.xml',
+ });
+
+ const customFieldBundle = unparsedFieldBundleFromRawString({
+ rawContent: customField,
+ 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('## PhotoUrl'));
+ });
+
+ it('displays the field description', async () => {
+ const customObjectBundle = unparsedObjectBundleFromRawString({
+ rawContent: customObjectGenerator(),
+ filePath: 'src/object/TestObject__c.object-meta.xml',
+ });
+
+ const customFieldBundle = unparsedFieldBundleFromRawString({
+ rawContent: customField,
+ 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('A URL that points to a photo'));
+ });
+
+ it('displays the field api name', async () => {
+ const customObjectBundle = unparsedObjectBundleFromRawString({
+ rawContent: customObjectGenerator(),
+ filePath: 'src/object/TestObject__c.object-meta.xml',
+ });
+
+ const customFieldBundle = unparsedFieldBundleFromRawString({
+ rawContent: customField,
+ 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('`TestField__c`'));
+ });
+ });
+});
diff --git a/src/core/markdown/__test__/generating-docs.spec.ts b/src/core/markdown/__test__/generating-docs.spec.ts
index 769300f4..e8f6fb32 100644
--- a/src/core/markdown/__test__/generating-docs.spec.ts
+++ b/src/core/markdown/__test__/generating-docs.spec.ts
@@ -1,6 +1,11 @@
import { DocPageData, PostHookDocumentationBundle } from '../../shared/types';
import { extendExpect } from './expect-extensions';
-import { apexBundleFromRawString, generateDocs } from './test-helpers';
+import {
+ unparsedApexBundleFromRawString,
+ generateDocs,
+ unparsedObjectBundleFromRawString,
+ customObjectGenerator,
+} from './test-helpers';
import { assertEither } from '../../test-helpers/assert-either';
function aSingleDoc(result: PostHookDocumentationBundle): DocPageData {
@@ -14,7 +19,7 @@ describe('When generating documentation', () => {
});
describe('the resulting files', () => {
- it('are named after the type', async () => {
+ it('Apex code is named after the type', async () => {
const properties: [string, string][] = [
['public class MyClass {}', 'MyClass.md'],
['public interface MyInterface {}', 'MyInterface.md'],
@@ -22,12 +27,12 @@ describe('When generating documentation', () => {
];
for (const [input, expected] of properties) {
- const result = await generateDocs([apexBundleFromRawString(input)])();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
assertEither(result, (data) => expect(aSingleDoc(data).outputDocPath).toContain(expected));
}
});
- it('are placed in the miscellaneous folder if no group is provided', async () => {
+ it('Apex code is placed in the miscellaneous folder if no group is provided', async () => {
const properties: [string, string][] = [
['public class MyClass {}', 'miscellaneous'],
['public interface MyInterface {}', 'miscellaneous'],
@@ -35,12 +40,42 @@ describe('When generating documentation', () => {
];
for (const [input, expected] of properties) {
- const result = await generateDocs([apexBundleFromRawString(input)])();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
assertEither(result, (data) => expect(aSingleDoc(data).outputDocPath).toContain(expected));
}
});
- it('are placed in the slugified group folder if a group is provided', async () => {
+ it('SObject code is placed in the custom objects folder', async () => {
+ const properties: [
+ {
+ rawContent: string;
+ filePath: string;
+ },
+ string,
+ ][] = [
+ [
+ {
+ rawContent: customObjectGenerator(),
+ filePath: 'src/object/MyFirstObject__c.object-meta.xml',
+ },
+ 'custom-objects',
+ ],
+ [
+ {
+ rawContent: customObjectGenerator(),
+ filePath: 'src/object/MySecondObject__c.object-meta.xml',
+ },
+ 'custom-objects',
+ ],
+ ];
+
+ for (const [input, expected] of properties) {
+ const result = await generateDocs([unparsedObjectBundleFromRawString(input)])();
+ assertEither(result, (data) => expect(aSingleDoc(data).outputDocPath).toContain(expected));
+ }
+ });
+
+ it('Apex code is placed in the slugified group folder if a group is provided', async () => {
const properties: [string, string][] = [
[
`/**
@@ -66,14 +101,14 @@ describe('When generating documentation', () => {
];
for (const [input, expected] of properties) {
- const result = await generateDocs([apexBundleFromRawString(input)])();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
assertEither(result, (data) => expect(aSingleDoc(data).outputDocPath).toContain(expected));
}
});
});
describe('the generated bundles', () => {
- it('return the type', async () => {
+ it('Apex code returns the type', async () => {
const properties: [string, string][] = [
['public class MyClass {}', 'class'],
['public interface MyInterface {}', 'interface'],
@@ -81,21 +116,61 @@ describe('When generating documentation', () => {
];
for (const [input, expected] of properties) {
- const result = await generateDocs([apexBundleFromRawString(input)])();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
assertEither(result, (data) => expect(aSingleDoc(data).source.type).toBe(expected));
}
});
- it('do not return files out of scope', async () => {
+ it('SObjects return the type', async () => {
+ const properties: [
+ {
+ rawContent: string;
+ filePath: string;
+ },
+ string,
+ ][] = [
+ [
+ {
+ rawContent: customObjectGenerator(),
+ filePath: 'src/object/MyFirstObject__c.object-meta.xml',
+ },
+ 'customobject',
+ ],
+ ];
+
+ for (const [input, expected] of properties) {
+ const result = await generateDocs([unparsedObjectBundleFromRawString(input)])();
+ assertEither(result, (data) => expect(aSingleDoc(data).source.type).toBe(expected));
+ }
+ });
+
+ it('do not return Apex files out of scope', async () => {
const input1 = 'global class MyClass {}';
const input2 = 'public class AnotherClass {}';
- const result = await generateDocs([apexBundleFromRawString(input1), apexBundleFromRawString(input2)], {
- scope: ['global'],
- })();
+ const result = await generateDocs(
+ [unparsedApexBundleFromRawString(input1), unparsedApexBundleFromRawString(input2)],
+ {
+ scope: ['global'],
+ },
+ )();
expect(result).documentationBundleHasLength(1);
});
+ it('does not return non-deployed custom objects', async () => {
+ const input = customObjectGenerator({ deploymentStatus: 'InDevelopment', visibility: 'Public' });
+
+ const result = await generateDocs([unparsedObjectBundleFromRawString({ rawContent: input, filePath: 'test' })])();
+ expect(result).documentationBundleHasLength(0);
+ });
+
+ it('does not return non-public custom objects', async () => {
+ const input = customObjectGenerator({ deploymentStatus: 'Deployed', visibility: 'Protected' });
+
+ const result = await generateDocs([unparsedObjectBundleFromRawString({ rawContent: input, filePath: 'test' })])();
+ expect(result).documentationBundleHasLength(0);
+ });
+
it('do not return files that have an @ignore in the docs', async () => {
const input = `
/**
@@ -103,13 +178,13 @@ describe('When generating documentation', () => {
*/
public class MyClass {}`;
- const result = await generateDocs([apexBundleFromRawString(input)])();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
expect(result).documentationBundleHasLength(0);
});
});
describe('the documentation content', () => {
- it('includes a heading with the type name', async () => {
+ it('includes a heading with the type name for Apex code', async () => {
const properties: [string, string][] = [
['public class MyClass {}', 'MyClass Class'],
['public enum MyEnum {}', 'MyEnum Enum'],
@@ -117,263 +192,19 @@ describe('When generating documentation', () => {
];
for (const [input, expected] of properties) {
- const result = await generateDocs([apexBundleFromRawString(input)])();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => expect(data).firstDocContains(expected));
}
});
- it('displays type level annotations', async () => {
- const input = `
- @NamespaceAccessible
- public class MyClass {
- @Deprecated
- public void myMethod() {}
- }
- `;
-
- const result = await generateDocs([apexBundleFromRawString(input)])();
-
- expect(result).documentationBundleHasLength(1);
- assertEither(result, (data) => expect(data).firstDocContains('NAMESPACEACCESSIBLE'));
- assertEither(result, (data) => expect(data).firstDocContains('DEPRECATED'));
- });
-
- it('displays metadata as annotations', async () => {
- const input = 'public class MyClass {}';
- const metadata = `
-
-
- 59.0
- Active
-
- `;
-
- const result = await generateDocs([apexBundleFromRawString(input, metadata)])();
-
- expect(result).documentationBundleHasLength(1);
- assertEither(result, (data) => expect(data).firstDocContains('APIVERSION'));
- assertEither(result, (data) => expect(data).firstDocContains('STATUS'));
- });
-
- it('displays the description when no @description tag is used', async () => {
- const input = `
- /**
- * This is a description
- */
- public class MyClass {}
- `;
-
- const result = await generateDocs([apexBundleFromRawString(input)])();
-
- expect(result).documentationBundleHasLength(1);
- assertEither(result, (data) => expect(data).firstDocContains('This is a description'));
- });
-
- it('displays the description when a @description tag is used', async () => {
- const input = `
- /**
- * @description This is a description
- */
- public class MyClass {}`;
-
- const result = await generateDocs([apexBundleFromRawString(input)])();
- expect(result).documentationBundleHasLength(1);
- assertEither(result, (data) => expect(data).firstDocContains('This is a description'));
- });
-
- it('display custom documentation tags', async () => {
- const input = `
- /**
- * @custom-tag My Value
- */
- public class MyClass {}
- `;
-
- const result = await generateDocs([apexBundleFromRawString(input)])();
- expect(result).documentationBundleHasLength(1);
- assertEither(result, (data) => expect(data).firstDocContains('Custom Tag'));
- assertEither(result, (data) => expect(data).firstDocContains('My Value'));
- });
-
- it('displays the group', async () => {
- const input = `
- /**
- * @group MyGroup
- */
- public class MyClass {}`;
-
- const result = await generateDocs([apexBundleFromRawString(input)])();
- expect(result).documentationBundleHasLength(1);
- assertEither(result, (data) => expect(data).firstDocContains('Group'));
- assertEither(result, (data) => expect(data).firstDocContains('MyGroup'));
- });
-
- it('displays the author', async () => {
- const input = `
- /**
- * @author John Doe
- */
- public class MyClass {}`;
-
- const result = await generateDocs([apexBundleFromRawString(input)])();
- expect(result).documentationBundleHasLength(1);
- assertEither(result, (data) => expect(data).firstDocContains('Author'));
- assertEither(result, (data) => expect(data).firstDocContains('John Doe'));
- });
-
- it('displays the date', async () => {
- const input = `
- /**
- * @date 2021-01-01
- */
- public class MyClass {}`;
-
- const result = await generateDocs([apexBundleFromRawString(input)])();
- expect(result).documentationBundleHasLength(1);
- assertEither(result, (data) => expect(data).firstDocContains('Date'));
- assertEither(result, (data) => expect(data).firstDocContains('2021-01-01'));
- });
-
- it('displays descriptions with links', async () => {
- const input1 = `
- /**
- * @description This is a description with a {@link ClassRef} reference
- */
- public enum MyClass {}
- `;
-
- const input2 = 'public class ClassRef {}';
-
- const result = await generateDocs([apexBundleFromRawString(input1), apexBundleFromRawString(input2)])();
- expect(result).documentationBundleHasLength(2);
- assertEither(result, (data) =>
- expect(data).firstDocContains('This is a description with a [ClassRef](ClassRef.md) reference'),
- );
- });
-
- it('displays descriptions with emails', async () => {
- const input = `
- /**
- * @description This is a description with an {@email test@testerson.com} email
- */
- public class MyClass {}
- `;
-
- const result = await generateDocs([apexBundleFromRawString(input)])();
- expect(result).documentationBundleHasLength(1);
- assertEither(result, (data) =>
- expect(data).firstDocContains(
- 'This is a description with an [test@testerson.com](mailto:test@testerson.com) email',
- ),
- );
- });
-
- it('displays @sees with accurately resolved links', async () => {
- const input1 = `
- /**
- * @see ClassRef
- */
- public class MyClass {}
- `;
-
- const input2 = 'public class ClassRef {}';
-
- const result = await generateDocs([apexBundleFromRawString(input1), apexBundleFromRawString(input2)])();
- expect(result).documentationBundleHasLength(2);
- assertEither(result, (data) => expect(data).firstDocContains('See'));
- assertEither(result, (data) => expect(data).firstDocContains('[ClassRef](ClassRef.md)'));
- });
-
- it('displays @sees without links when the reference is not found', async () => {
- const input = `
- /**
- * @see ClassRef
- */
- public class MyClass {}
- `;
-
- const result = await generateDocs([apexBundleFromRawString(input)])();
-
- expect(result).documentationBundleHasLength(1);
- assertEither(result, (data) => expect(data).firstDocContains('See'));
- assertEither(result, (data) => expect(data).firstDocContains('ClassRef'));
- });
-
- it('displays the namespace if present in the config', async () => {
- const input = 'public class MyClass {}';
-
- const result = await generateDocs([apexBundleFromRawString(input)], { namespace: 'MyNamespace' })();
- expect(result).documentationBundleHasLength(1);
- assertEither(result, (data) => expect(data).firstDocContains('## Namespace'));
- assertEither(result, (data) => expect(data).firstDocContains('MyNamespace'));
- });
-
- it('does not display the namespace if not present in the config', async () => {
- const input = 'public class MyClass {}';
-
- const result = await generateDocs([apexBundleFromRawString(input)])();
- expect(result).documentationBundleHasLength(1);
- assertEither(result, (data) => expect(data).firstDocContainsNot('## Namespace'));
- });
-
- it('displays a mermaid diagram', async () => {
- const input = `
- /**
- * @mermaid
- * \`\`\`mermaid
- * graph TD
- * A[Square Rect] -- Link text --> B((Circle))
- * A --> C(Round Rect)
- * B --> D{Rhombus}
- * C --> D
- * \`\`\`
- */
- public class MyClass {}
- `;
-
- const result = await generateDocs([apexBundleFromRawString(input)])();
- expect(result).documentationBundleHasLength(1);
- assertEither(result, (data) => expect(data).firstDocContains('```mermaid'));
- assertEither(result, (data) => expect(data).firstDocContains('graph TD'));
- });
-
- it('displays an example code block', async () => {
- const input = `
- /**
- * @example
- * \`\`\`apex
- * public class MyClass {
- * public void myMethod() {
- * System.debug('Hello, World!');
- * }
- * }
- * \`\`\`
- */
- public class MyClass {}`;
-
- const result = await generateDocs([apexBundleFromRawString(input)])();
-
- expect(result).documentationBundleHasLength(1);
- assertEither(result, (data) => expect(data).firstDocContains('```apex'));
- assertEither(result, (data) => expect(data).firstDocContains('public class MyClass'));
- });
-
- it('does not display tags marked as excluded', async () => {
- const input = `
- /**
- * @see ClassRef
- */
- public class MyClass {}
- `;
-
- const result = await generateDocs([apexBundleFromRawString(input)], {
- excludeTags: ['see'],
- })();
+ it('includes a heading with the Custom Object label', async () => {
+ const input = customObjectGenerator();
+ const result = await generateDocs([unparsedObjectBundleFromRawString({ rawContent: input, filePath: 'test' })])();
expect(result).documentationBundleHasLength(1);
- assertEither(result, (data) => expect(data).firstDocContainsNot('See'));
+ assertEither(result, (data) => expect(data).firstDocContains('MyTestObject'));
});
});
});
diff --git a/src/core/markdown/__test__/generating-enum-docs.spec.ts b/src/core/markdown/__test__/generating-enum-docs.spec.ts
index f0f7aa67..66bf94bb 100644
--- a/src/core/markdown/__test__/generating-enum-docs.spec.ts
+++ b/src/core/markdown/__test__/generating-enum-docs.spec.ts
@@ -1,5 +1,5 @@
import { extendExpect } from './expect-extensions';
-import { apexBundleFromRawString, generateDocs } from './test-helpers';
+import { unparsedApexBundleFromRawString, generateDocs } from './test-helpers';
import { assertEither } from '../../test-helpers/assert-either';
describe('Generates enum documentation', () => {
@@ -16,7 +16,7 @@ describe('Generates enum documentation', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)])();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => expect(data).firstDocContains('## Values'));
assertEither(result, (data) => expect(data).firstDocContains('VALUE1'));
@@ -31,7 +31,7 @@ describe('Generates enum documentation', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)], { sortAlphabetically: true })();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)], { sortAlphabetically: true })();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => expect(data).firstDocContains('## Values'));
assertEither(result, (data) => {
@@ -49,7 +49,7 @@ describe('Generates enum documentation', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)], { sortAlphabetically: false })();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)], { sortAlphabetically: false })();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => expect(data).firstDocContains('## Values'));
assertEither(result, (data) => {
diff --git a/src/core/markdown/__test__/generating-interface-docs.spec.ts b/src/core/markdown/__test__/generating-interface-docs.spec.ts
index c6d7e964..21afaf9c 100644
--- a/src/core/markdown/__test__/generating-interface-docs.spec.ts
+++ b/src/core/markdown/__test__/generating-interface-docs.spec.ts
@@ -1,5 +1,5 @@
import { extendExpect } from './expect-extensions';
-import { apexBundleFromRawString, generateDocs } from './test-helpers';
+import { unparsedApexBundleFromRawString, generateDocs } from './test-helpers';
import { assertEither } from '../../test-helpers/assert-either';
describe('Generates interface documentation', () => {
@@ -16,7 +16,7 @@ describe('Generates interface documentation', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)])();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => expect(data).firstDocContains('## Methods'));
});
@@ -29,7 +29,7 @@ describe('Generates interface documentation', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)], { sortAlphabetically: true })();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)], { sortAlphabetically: true })();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => {
expect(data.docs[0].content.indexOf('anotherMethod')).toBeLessThan(data.docs[0].content.indexOf('myMethod'));
@@ -44,7 +44,7 @@ describe('Generates interface documentation', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)], { sortAlphabetically: false })();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)], { sortAlphabetically: false })();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => {
expect(data.docs[0].content.indexOf('myMethod')).toBeLessThan(data.docs[0].content.indexOf('anotherMethod'));
@@ -68,7 +68,7 @@ describe('Generates interface documentation', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)])();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => expect(data).firstDocContains('```mermaid'));
assertEither(result, (data) => expect(data).firstDocContains('graph TD'));
@@ -89,7 +89,7 @@ describe('Generates interface documentation', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)])();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => expect(data).firstDocContains('```apex'));
assertEither(result, (data) => expect(data).firstDocContains('public class MyClass'));
@@ -102,7 +102,7 @@ describe('Generates interface documentation', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)])();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => expect(data).firstDocContains('### Signature'));
});
@@ -114,7 +114,7 @@ describe('Generates interface documentation', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)])();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => expect(data).firstDocContains('### Parameters'));
});
@@ -126,7 +126,7 @@ describe('Generates interface documentation', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)])();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => expect(data).firstDocContains('### Return Type'));
});
@@ -141,7 +141,7 @@ describe('Generates interface documentation', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)])();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) => expect(data).firstDocContains('### Throws'));
});
@@ -157,7 +157,10 @@ describe('Generates interface documentation', () => {
public interface AnotherInterface extends MyInterface {}
`;
- const result = await generateDocs([apexBundleFromRawString(input1), apexBundleFromRawString(input2)])();
+ const result = await generateDocs([
+ unparsedApexBundleFromRawString(input1),
+ unparsedApexBundleFromRawString(input2),
+ ])();
expect(result).documentationBundleHasLength(2);
assertEither(result, (data) =>
expect(data.docs.find((doc) => doc.outputDocPath.includes('AnotherInterface'))?.content).toContain(
diff --git a/src/core/markdown/__test__/generating-reference-guide.spec.ts b/src/core/markdown/__test__/generating-reference-guide.spec.ts
index ad64980c..510e9458 100644
--- a/src/core/markdown/__test__/generating-reference-guide.spec.ts
+++ b/src/core/markdown/__test__/generating-reference-guide.spec.ts
@@ -1,7 +1,12 @@
import { extendExpect } from './expect-extensions';
import { pipe } from 'fp-ts/function';
import * as E from 'fp-ts/Either';
-import { apexBundleFromRawString, generateDocs } from './test-helpers';
+import {
+ unparsedApexBundleFromRawString,
+ generateDocs,
+ customObjectGenerator,
+ unparsedObjectBundleFromRawString,
+} from './test-helpers';
import { ReferenceGuidePageData } from '../../shared/types';
import { assertEither } from '../../test-helpers/assert-either';
@@ -38,8 +43,17 @@ describe('When generating the Reference Guide', () => {
public class MyClass {}
`;
- const result = await generateDocs([apexBundleFromRawString(input1), apexBundleFromRawString(input2)])();
- expect(result).documentationBundleHasLength(2);
+ const input3 = {
+ rawContent: customObjectGenerator(),
+ filePath: 'src/object/TestObject__c.object-meta.xml',
+ };
+
+ const result = await generateDocs([
+ unparsedApexBundleFromRawString(input1),
+ unparsedApexBundleFromRawString(input2),
+ unparsedObjectBundleFromRawString(input3),
+ ])();
+ expect(result).documentationBundleHasLength(3);
assertEither(result, (data) =>
expect((data.referenceGuide as ReferenceGuidePageData).content).toContain('[MyEnum](miscellaneous/MyEnum.md)'),
@@ -47,9 +61,14 @@ describe('When generating the Reference Guide', () => {
assertEither(result, (data) =>
expect((data.referenceGuide as ReferenceGuidePageData).content).toContain('[MyClass](miscellaneous/MyClass.md)'),
);
+ assertEither(result, (data) =>
+ expect((data.referenceGuide as ReferenceGuidePageData).content).toContain(
+ '[TestObject__c](custom-objects/TestObject__c.md)',
+ ),
+ );
});
- it('groups things under Miscellaneous if no group is provided', async () => {
+ it('groups Apex code under Miscellaneous if no group is provided', async () => {
const input = `
public enum MyEnum {
VALUE1,
@@ -57,14 +76,14 @@ describe('When generating the Reference Guide', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)])();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) =>
expect((data.referenceGuide as ReferenceGuidePageData).content).toContain('## Miscellaneous'),
);
});
- it('group things under the provided group', async () => {
+ it('group Apex code under the provided group', async () => {
const input = `
/**
* @group MyGroup
@@ -75,13 +94,41 @@ describe('When generating the Reference Guide', () => {
}
`;
- const result = await generateDocs([apexBundleFromRawString(input)])();
+ const result = await generateDocs([unparsedApexBundleFromRawString(input)])();
expect(result).documentationBundleHasLength(1);
assertEither(result, (data) =>
expect((data.referenceGuide as ReferenceGuidePageData).content).toContain('## MyGroup'),
);
});
+ it('group SObjects under the Custom Objects group by default', async () => {
+ const input = {
+ rawContent: customObjectGenerator(),
+ filePath: 'src/object/TestObject__c.object-meta.xml',
+ };
+
+ const result = await generateDocs([unparsedObjectBundleFromRawString(input)])();
+ expect(result).documentationBundleHasLength(1);
+ assertEither(result, (data) =>
+ expect((data.referenceGuide as ReferenceGuidePageData).content).toContain('## Custom Objects'),
+ );
+ });
+
+ it('groups SObjects under the provided group', async () => {
+ const input = {
+ rawContent: customObjectGenerator(),
+ filePath: 'src/object/TestObject__c.object-meta.xml',
+ };
+
+ const result = await generateDocs([unparsedObjectBundleFromRawString(input)], {
+ customObjectsGroupName: 'MyCustomObjects',
+ })();
+ expect(result).documentationBundleHasLength(1);
+ assertEither(result, (data) =>
+ expect((data.referenceGuide as ReferenceGuidePageData).content).toContain('## MyCustomObjects'),
+ );
+ });
+
it('displays groups in alphabetical order', async () => {
const input1 = `
/**
@@ -100,7 +147,10 @@ describe('When generating the Reference Guide', () => {
public class MyClass {}
`;
- const result = await generateDocs([apexBundleFromRawString(input1), apexBundleFromRawString(input2)])();
+ const result = await generateDocs([
+ unparsedApexBundleFromRawString(input1),
+ unparsedApexBundleFromRawString(input2),
+ ])();
expect(result).documentationBundleHasLength(2);
pipe(
result,
@@ -133,14 +183,27 @@ describe('When generating the Reference Guide', () => {
public class MyClass {}
`;
- const result = await generateDocs([apexBundleFromRawString(input1), apexBundleFromRawString(input2)])();
- expect(result).documentationBundleHasLength(2);
+ const input3 = {
+ rawContent: customObjectGenerator(),
+ filePath: 'src/object/TestObject__c.object-meta.xml',
+ };
+
+ const result = await generateDocs([
+ unparsedApexBundleFromRawString(input1),
+ unparsedApexBundleFromRawString(input2),
+ unparsedObjectBundleFromRawString(input3),
+ ])();
+
+ expect(result).documentationBundleHasLength(3);
assertEither(result, (data) =>
expect((data.referenceGuide as ReferenceGuidePageData).content).toContain('## Group1'),
);
assertEither(result, (data) =>
expect((data.referenceGuide as ReferenceGuidePageData).content).toContain('MyClass'),
);
+ assertEither(result, (data) =>
+ expect((data.referenceGuide as ReferenceGuidePageData).content).toContain('TestObject__c'),
+ );
assertEither(result, (data) => expect((data.referenceGuide as ReferenceGuidePageData).content).toContain('MyEnum'));
});
@@ -162,11 +225,24 @@ describe('When generating the Reference Guide', () => {
public class MyClass {}
`;
- const result = await generateDocs([apexBundleFromRawString(input1), apexBundleFromRawString(input2)])();
- expect(result).documentationBundleHasLength(2);
+ const input3 = {
+ rawContent: customObjectGenerator(),
+ filePath: 'src/object/ATestObject__c.object-meta.xml',
+ };
+
+ const result = await generateDocs([
+ unparsedApexBundleFromRawString(input1),
+ unparsedApexBundleFromRawString(input2),
+ unparsedObjectBundleFromRawString(input3),
+ ])();
+
+ expect(result).documentationBundleHasLength(3);
assertEither(result, (data) =>
expect((data.referenceGuide as ReferenceGuidePageData).content).toContain('This is a description'),
);
+ assertEither(result, (data) =>
+ expect((data.referenceGuide as ReferenceGuidePageData).content).toContain('test object for testing'),
+ );
});
it('returns a reference guide with descriptions with links to all other files', async () => {
@@ -188,7 +264,10 @@ describe('When generating the Reference Guide', () => {
public class MyClass {}
`;
- const result = await generateDocs([apexBundleFromRawString(input1), apexBundleFromRawString(input2)])();
+ const result = await generateDocs([
+ unparsedApexBundleFromRawString(input1),
+ unparsedApexBundleFromRawString(input2),
+ ])();
expect(result).documentationBundleHasLength(2);
assertEither(result, (data) =>
expect((data.referenceGuide as ReferenceGuidePageData).content).toContain('with a [MyClass](group2/MyClass.md)'),
diff --git a/src/core/markdown/__test__/inheritance-chain.test.ts b/src/core/markdown/__test__/inheritance-chain.test.ts
index 4b97fdaa..f6c76e59 100644
--- a/src/core/markdown/__test__/inheritance-chain.test.ts
+++ b/src/core/markdown/__test__/inheritance-chain.test.ts
@@ -1,5 +1,5 @@
import { ClassMirrorBuilder } from '../../../test-helpers/ClassMirrorBuilder';
-import { createInheritanceChain } from '../../reflection/inheritance-chain';
+import { createInheritanceChain } from '../../reflection/apex/inheritance-chain';
describe('inheritance chain for classes', () => {
test('returns an empty list of the class does not extend any other class', () => {
diff --git a/src/core/markdown/__test__/test-helpers.ts b/src/core/markdown/__test__/test-helpers.ts
index a3cd95a8..d884958f 100644
--- a/src/core/markdown/__test__/test-helpers.ts
+++ b/src/core/markdown/__test__/test-helpers.ts
@@ -1,20 +1,54 @@
-import { UnparsedSourceFile } from '../../shared/types';
+import {
+ UnparsedApexBundle,
+ UnparsedCustomFieldBundle,
+ UnparsedCustomObjectBundle,
+ UnparsedSourceBundle,
+} from '../../shared/types';
import { generateDocs as gen, MarkdownGeneratorConfig } from '../generate-docs';
import { referenceGuideTemplate } from '../templates/reference-guide';
-export function apexBundleFromRawString(raw: string, rawMetadata?: string): UnparsedSourceFile {
+export function unparsedApexBundleFromRawString(raw: string, rawMetadata?: string): UnparsedApexBundle {
return {
+ type: 'apex',
+ name: 'Test',
filePath: 'test.cls',
content: raw,
metadataContent: rawMetadata ?? null,
};
}
-export function generateDocs(apexBundles: UnparsedSourceFile[], config?: Partial) {
+export function unparsedObjectBundleFromRawString(meta: {
+ rawContent: string;
+ filePath: string;
+}): UnparsedCustomObjectBundle {
+ return {
+ type: 'customobject',
+ name: 'TestObject__c',
+ filePath: meta.filePath,
+ content: meta.rawContent,
+ };
+}
+
+export function unparsedFieldBundleFromRawString(meta: {
+ rawContent: string;
+ filePath: string;
+ parentName: string;
+}): UnparsedCustomFieldBundle {
+ return {
+ type: 'customfield',
+ name: 'TestField__c',
+ filePath: meta.filePath,
+ content: meta.rawContent,
+ parentName: meta.parentName,
+ };
+}
+
+export function generateDocs(apexBundles: UnparsedSourceBundle[], config?: Partial) {
return gen(apexBundles, {
targetDir: 'target',
scope: ['global', 'public'],
defaultGroupName: 'Miscellaneous',
+ customObjectsGroupName: 'Custom Objects',
sortAlphabetically: false,
referenceGuideTemplate: referenceGuideTemplate,
linkingStrategy: 'relative',
@@ -24,3 +58,29 @@ export function generateDocs(apexBundles: UnparsedSourceFile[], config?: Partial
...config,
});
}
+
+export function customObjectGenerator(
+ config: { deploymentStatus: string; visibility: string } = { deploymentStatus: 'Deployed', visibility: 'Public' },
+) {
+ return `
+
+
+ ${config.deploymentStatus}
+ test object for testing
+
+ MyFirstObjects
+ ${config.visibility}
+ `;
+}
+
+export const customField = `
+
+
+ PhotoUrl__c
+ false
+
+ false
+ false
+ Url
+ A URL that points to a photo
+`;
diff --git a/src/core/markdown/adapters/__tests__/interface-adapter.spec.ts b/src/core/markdown/adapters/__tests__/interface-adapter.spec.ts
index 6b818cea..b69fdd7b 100644
--- a/src/core/markdown/adapters/__tests__/interface-adapter.spec.ts
+++ b/src/core/markdown/adapters/__tests__/interface-adapter.spec.ts
@@ -1,4 +1,4 @@
-import { typeToRenderable } from '../apex-types';
+import { typeToRenderable } from '../type-to-renderable';
import { InterfaceMirrorBuilder } from '../../../../test-helpers/InterfaceMirrorBuilder';
import { AnnotationBuilder } from '../../../../test-helpers/AnnotationBuilder';
import { MethodMirrorBuilder, ParameterBuilder } from '../../../../test-helpers/MethodMirrorBuilder';
@@ -13,6 +13,7 @@ const defaultMarkdownGeneratorConfig: MarkdownGeneratorConfig = {
scope: ['global', 'public'],
namespace: '',
defaultGroupName: 'Miscellaneous',
+ customObjectsGroupName: 'Custom Objects',
referenceGuideTemplate: '',
sortAlphabetically: false,
linkingStrategy: 'relative',
diff --git a/src/core/markdown/adapters/fields-and-properties.ts b/src/core/markdown/adapters/fields-and-properties.ts
index f8450ce1..500fe5cc 100644
--- a/src/core/markdown/adapters/fields-and-properties.ts
+++ b/src/core/markdown/adapters/fields-and-properties.ts
@@ -2,7 +2,7 @@ import {
CodeBlock,
FieldMirrorWithInheritance,
PropertyMirrorWithInheritance,
- RenderableField,
+ RenderableApexField,
GetRenderableContentByTypeName,
} from '../../renderables/types';
import { adaptDocumentable } from '../../renderables/documentables';
@@ -11,7 +11,7 @@ export function adaptFieldOrProperty(
field: FieldMirrorWithInheritance | PropertyMirrorWithInheritance,
linkGenerator: GetRenderableContentByTypeName,
baseHeadingLevel: number,
-): RenderableField {
+): RenderableApexField {
function buildSignature(): CodeBlock {
const { access_modifier, name } = field;
const memberModifiers = field.memberModifiers.join(' ');
diff --git a/src/core/markdown/adapters/reference-guide.ts b/src/core/markdown/adapters/reference-guide.ts
index 5e645cd7..81804530 100644
--- a/src/core/markdown/adapters/reference-guide.ts
+++ b/src/core/markdown/adapters/reference-guide.ts
@@ -1,32 +1,32 @@
import { MarkdownGeneratorConfig } from '../generate-docs';
import { DocPageReference, ParsedFile } from '../../shared/types';
+import { getTypeGroup } from '../../shared/utils';
+import { ObjectMetadata } from '../../reflection/sobject/reflect-custom-object-sources';
import { Type } from '@cparra/apex-reflection';
export function parsedFilesToReferenceGuide(
config: MarkdownGeneratorConfig,
- parsedFiles: ParsedFile[],
+ parsedFiles: ParsedFile[],
): Record {
return parsedFiles.reduce>((acc, parsedFile) => {
- acc[parsedFile.type.name] = parsedFileToDocPageReference(config, parsedFile);
+ acc[parsedFile.source.name] = parsedFileToDocPageReference(config, parsedFile);
return acc;
}, {});
}
-function parsedFileToDocPageReference(config: MarkdownGeneratorConfig, parsedFile: ParsedFile): DocPageReference {
- const path = `${slugify(getTypeGroup(parsedFile.type, config))}/${parsedFile.type.name}.md`;
+function parsedFileToDocPageReference(
+ config: MarkdownGeneratorConfig,
+ parsedFile: ParsedFile,
+): DocPageReference {
+ const path = `${slugify(getTypeGroup(parsedFile.type, config))}/${parsedFile.source.name}.md`;
return {
source: parsedFile.source,
- displayName: parsedFile.type.name,
+ displayName: parsedFile.source.name,
outputDocPath: path,
referencePath: path,
};
}
-function getTypeGroup(type: Type, config: MarkdownGeneratorConfig): string {
- const groupAnnotation = type.docComment?.annotations.find((annotation) => annotation.name.toLowerCase() === 'group');
- return groupAnnotation?.body ?? config.defaultGroupName;
-}
-
function slugify(text: string): string {
return text
.toLowerCase()
diff --git a/src/core/markdown/adapters/renderable-bundle.ts b/src/core/markdown/adapters/renderable-bundle.ts
index 2b0e580d..af4cd633 100644
--- a/src/core/markdown/adapters/renderable-bundle.ts
+++ b/src/core/markdown/adapters/renderable-bundle.ts
@@ -1,27 +1,37 @@
import { DocPageReference, ParsedFile } from '../../shared/types';
-import { Link, ReferenceGuideReference, Renderable, RenderableBundle } from '../../renderables/types';
-import { typeToRenderable } from './apex-types';
+import {
+ Link,
+ ReferenceGuideReference,
+ Renderable,
+ RenderableBundle,
+ RenderableContent,
+} from '../../renderables/types';
+import { typeToRenderable } from './type-to-renderable';
import { adaptDescribable } from '../../renderables/documentables';
import { MarkdownGeneratorConfig } from '../generate-docs';
import { apply } from '#utils/fp';
-import { Type } from '@cparra/apex-reflection';
import { generateLink } from './generate-link';
+import { getTypeGroup } from '../../shared/utils';
+import { Type } from '@cparra/apex-reflection';
+import { ObjectMetadata } from '../../reflection/sobject/reflect-custom-object-sources';
export function parsedFilesToRenderableBundle(
config: MarkdownGeneratorConfig,
- parsedFiles: ParsedFile[],
+ parsedFiles: ParsedFile[],
references: Record,
): RenderableBundle {
const referenceFinder = apply(generateLink(config.linkingStrategy), references);
- function toReferenceGuide(parsedFiles: ParsedFile[]): Record {
+ function toReferenceGuide(
+ parsedFiles: ParsedFile[],
+ ): Record {
return parsedFiles.reduce>(
addToReferenceGuide(apply(referenceFinder, '__base__'), config, references),
{},
);
}
- function toRenderables(parsedFiles: ParsedFile[]): Renderable[] {
+ function toRenderables(parsedFiles: ParsedFile[]): Renderable[] {
return parsedFiles.reduce((acc, parsedFile) => {
const renderable = typeToRenderable(parsedFile, apply(referenceFinder, parsedFile.source.name), config);
acc.push(renderable);
@@ -40,22 +50,29 @@ function addToReferenceGuide(
config: MarkdownGeneratorConfig,
references: Record,
) {
- return (acc: Record, parsedFile: ParsedFile) => {
+ return (acc: Record, parsedFile: ParsedFile) => {
const group: string = getTypeGroup(parsedFile.type, config);
if (!acc[group]) {
acc[group] = [];
}
acc[group].push({
- reference: references[parsedFile.type.name],
- title: findLinkFromHome(parsedFile.type.name) as Link,
- description: adaptDescribable(parsedFile.type.docComment?.descriptionLines, findLinkFromHome).description ?? null,
+ reference: references[parsedFile.source.name],
+ title: findLinkFromHome(parsedFile.source.name) as Link,
+ description: getRenderableDescription(parsedFile.type, findLinkFromHome),
});
return acc;
};
}
-function getTypeGroup(type: Type, config: MarkdownGeneratorConfig): string {
- const groupAnnotation = type.docComment?.annotations.find((annotation) => annotation.name.toLowerCase() === 'group');
- return groupAnnotation?.body ?? config.defaultGroupName;
+function getRenderableDescription(
+ type: Type | ObjectMetadata,
+ findLinkFromHome: (referenceName: string) => string | Link,
+): RenderableContent[] | null {
+ switch (type.type_name) {
+ case 'customobject':
+ return type.description ? [type.description] : null;
+ default:
+ return adaptDescribable(type.docComment?.descriptionLines, findLinkFromHome).description ?? null;
+ }
}
diff --git a/src/core/markdown/adapters/renderable-to-page-data.ts b/src/core/markdown/adapters/renderable-to-page-data.ts
index cc291602..f5d84776 100644
--- a/src/core/markdown/adapters/renderable-to-page-data.ts
+++ b/src/core/markdown/adapters/renderable-to-page-data.ts
@@ -6,6 +6,7 @@ import { enumMarkdownTemplate } from '../templates/enum-template';
import { interfaceMarkdownTemplate } from '../templates/interface-template';
import { classMarkdownTemplate } from '../templates/class-template';
import { markdownDefaults } from '../../../defaults';
+import { customObjectTemplate } from '../templates/custom-object-template';
export const convertToDocumentationBundle = (
referenceGuideTitle: string,
@@ -62,6 +63,7 @@ function renderableToPageData(referenceGuideReference: ReferenceGuideReference[]
frontmatter: null,
content: docContents,
group: renderable.doc.group ?? markdownDefaults.defaultGroupName,
+ type: renderable.type,
};
}
@@ -77,6 +79,8 @@ function resolveApexTypeTemplate(renderable: Renderable): CompilationRequest {
return interfaceMarkdownTemplate;
case 'class':
return classMarkdownTemplate;
+ case 'customobject':
+ return customObjectTemplate;
}
}
diff --git a/src/core/markdown/adapters/apex-types.ts b/src/core/markdown/adapters/type-to-renderable.ts
similarity index 77%
rename from src/core/markdown/adapters/apex-types.ts
rename to src/core/markdown/adapters/type-to-renderable.ts
index 35708c37..cd66d8ec 100644
--- a/src/core/markdown/adapters/apex-types.ts
+++ b/src/core/markdown/adapters/type-to-renderable.ts
@@ -10,33 +10,42 @@ import {
FieldMirrorWithInheritance,
PropertyMirrorWithInheritance,
GetRenderableContentByTypeName,
+ RenderableCustomObject,
+ RenderableCustomField,
} from '../../renderables/types';
import { adaptDescribable, adaptDocumentable } from '../../renderables/documentables';
import { adaptConstructor, adaptMethod } from './methods-and-constructors';
import { adaptFieldOrProperty } from './fields-and-properties';
import { MarkdownGeneratorConfig } from '../generate-docs';
import { SourceFileMetadata } from '../../shared/types';
+import { ObjectMetadata } from '../../reflection/sobject/reflect-custom-object-sources';
+import { getTypeGroup } from '../../shared/utils';
+import { CustomFieldMetadata } from '../../reflection/sobject/reflect-custom-field-source';
-type GetReturnRenderable = T extends InterfaceMirror
+type GetReturnRenderable = T extends InterfaceMirror
? RenderableInterface
: T extends ClassMirror
? RenderableClass
- : RenderableEnum;
+ : T extends EnumMirror
+ ? RenderableEnum
+ : RenderableCustomObject;
-export function typeToRenderable(
+export function typeToRenderable(
parsedFile: { source: SourceFileMetadata; type: T },
linkGenerator: GetRenderableContentByTypeName,
config: MarkdownGeneratorConfig,
): GetReturnRenderable & { filePath: string; namespace?: string } {
- function getRenderable(): RenderableInterface | RenderableClass | RenderableEnum {
+ function getRenderable(): RenderableInterface | RenderableClass | RenderableEnum | RenderableCustomObject {
const { type } = parsedFile;
switch (type.type_name) {
case 'enum':
- return enumTypeToEnumSource(type as EnumMirror, linkGenerator) as RenderableEnum;
+ return enumTypeToEnumSource(type as EnumMirror, linkGenerator);
case 'interface':
- return interfaceTypeToInterfaceSource(type as InterfaceMirror, linkGenerator) as RenderableInterface;
+ return interfaceTypeToInterfaceSource(type as InterfaceMirror, linkGenerator);
case 'class':
- return classTypeToClassSource(type as ClassMirrorWithInheritanceChain, linkGenerator) as RenderableClass;
+ return classTypeToClassSource(type as ClassMirrorWithInheritanceChain, linkGenerator);
+ case 'customobject':
+ return objectMetadataToRenderable(type as ObjectMetadata, config);
}
}
@@ -236,3 +245,55 @@ function singleGroup(
value: toFlat(members, adapter, linkGenerator, headingLevel + 1),
};
}
+
+function objectMetadataToRenderable(
+ objectMetadata: ObjectMetadata,
+ config: MarkdownGeneratorConfig,
+): RenderableCustomObject {
+ return {
+ type: 'customobject',
+ headingLevel: 1,
+ apiName: getApiName(objectMetadata.name, config),
+ heading: objectMetadata.label,
+ name: objectMetadata.name,
+ doc: {
+ description: objectMetadata.description ? [objectMetadata.description] : [],
+ group: getTypeGroup(objectMetadata, config),
+ },
+ hasFields: objectMetadata.fields.length > 0,
+ fields: {
+ headingLevel: 2,
+ heading: 'Fields',
+ value: objectMetadata.fields.map((field) => fieldMetadataToRenderable(field.type, config, 3)),
+ },
+ };
+}
+
+function fieldMetadataToRenderable(
+ field: CustomFieldMetadata,
+ config: MarkdownGeneratorConfig,
+ headingLevel: number,
+): RenderableCustomField {
+ return {
+ type: 'field',
+ headingLevel: headingLevel,
+ heading: field.label,
+ description: field.description ? [field.description] : [],
+ apiName: getApiName(field.name, config),
+ fieldType: field.type,
+ };
+}
+
+function getApiName(currentName: string, config: MarkdownGeneratorConfig) {
+ if (config.namespace) {
+ // first remove any `__c` suffix
+ const name = currentName.replace(/__c$/, '');
+ // if the name still has an __, it's already namespaced
+ if (name.includes('__')) {
+ return name;
+ }
+
+ return `${config.namespace}__${currentName}`;
+ }
+ return currentName;
+}
diff --git a/src/core/markdown/generate-docs.ts b/src/core/markdown/generate-docs.ts
index 6bb0d92d..71a53ec9 100644
--- a/src/core/markdown/generate-docs.ts
+++ b/src/core/markdown/generate-docs.ts
@@ -9,7 +9,7 @@ import {
Frontmatter,
PostHookDocumentationBundle,
ReferenceGuidePageData,
- UnparsedSourceFile,
+ UnparsedApexBundle,
TransformDocPage,
TransformDocs,
TransformReferenceGuide,
@@ -17,20 +17,26 @@ import {
DocPageReference,
TransformReference,
ParsedFile,
+ UnparsedCustomObjectBundle,
+ UnparsedSourceBundle,
+ UnparsedCustomFieldBundle,
} from '../shared/types';
import { parsedFilesToRenderableBundle } from './adapters/renderable-bundle';
-import { reflectBundles } from '../reflection/reflect-source';
-import { addInheritanceChainToTypes } from '../reflection/inheritance-chain-expanion';
-import { addInheritedMembersToTypes } from '../reflection/inherited-member-expansion';
+import { reflectApexSource } from '../reflection/apex/reflect-apex-source';
+import { addInheritanceChainToTypes } from '../reflection/apex/inheritance-chain-expanion';
+import { addInheritedMembersToTypes } from '../reflection/apex/inherited-member-expansion';
import { convertToDocumentationBundle } from './adapters/renderable-to-page-data';
-import { filterScope } from '../reflection/filter-scope';
+import { filterScope } from '../reflection/apex/filter-scope';
import { Template } from '../template';
import { hookableTemplate } from './templates/hookable';
import { sortTypesAndMembers } from '../reflection/sort-types-and-members';
import { isSkip } from '../shared/utils';
import { parsedFilesToReferenceGuide } from './adapters/reference-guide';
-import { removeExcludedTags } from '../reflection/remove-excluded-tags';
-import { HookError } from '../errors/errors';
+import { removeExcludedTags } from '../reflection/apex/remove-excluded-tags';
+import { HookError, ReflectionErrors } from '../errors/errors';
+import { ObjectMetadata, reflectCustomObjectSources } from '../reflection/sobject/reflect-custom-object-sources';
+import { CustomFieldMetadata, reflectCustomFieldSources } from '../reflection/sobject/reflect-custom-field-source';
+import { Type } from '@cparra/apex-reflection';
export type MarkdownGeneratorConfig = Omit<
UserDefinedMarkdownConfig,
@@ -39,8 +45,7 @@ export type MarkdownGeneratorConfig = Omit<
referenceGuideTemplate: string;
};
-export function generateDocs(apexBundles: UnparsedSourceFile[], config: MarkdownGeneratorConfig) {
- const filterOutOfScope = apply(filterScope, config.scope);
+export function generateDocs(unparsedApexFiles: UnparsedSourceBundle[], config: MarkdownGeneratorConfig) {
const convertToReferences = apply(parsedFilesToReferenceGuide, config);
const convertToRenderableBundle = apply(parsedFilesToRenderableBundle, config);
const convertToDocumentationBundleForTemplate = apply(
@@ -49,23 +54,107 @@ export function generateDocs(apexBundles: UnparsedSourceFile[], config: Markdown
config.referenceGuideTemplate,
);
const sort = apply(sortTypesAndMembers, config.sortAlphabetically);
+
+ function filterApexSourceFiles(sourceFiles: UnparsedSourceBundle[]): UnparsedApexBundle[] {
+ return sourceFiles.filter((sourceFile): sourceFile is UnparsedApexBundle => sourceFile.type === 'apex');
+ }
+
+ function filterCustomObjectsAndFields(
+ sourceFiles: UnparsedSourceBundle[],
+ ): (UnparsedCustomObjectBundle | UnparsedCustomFieldBundle)[] {
+ return sourceFiles.filter(
+ (sourceFile): sourceFile is UnparsedCustomObjectBundle =>
+ sourceFile.type === 'customobject' || sourceFile.type === 'customfield',
+ );
+ }
+
+ function filterOutCustomFields(parsedFiles: ParsedFile[]): ParsedFile[] {
+ return parsedFiles.filter(
+ (parsedFile): parsedFile is ParsedFile => parsedFile.source.type !== 'customfield',
+ );
+ }
+
+ return pipe(
+ generateForApex(filterApexSourceFiles(unparsedApexFiles), config),
+ TE.chain((parsedApexFiles) => {
+ return pipe(
+ generateForObject(filterCustomObjectsAndFields(unparsedApexFiles)),
+ TE.map((parsedObjectFiles) => [...parsedApexFiles, ...parsedObjectFiles]),
+ );
+ }),
+ TE.map((parsedFiles) => sort(filterOutCustomFields(parsedFiles))),
+ TE.bindTo('parsedFiles'),
+ TE.bind('references', ({ parsedFiles }) =>
+ TE.right(
+ // Custom fields should not show up in the reference guide
+ convertToReferences(parsedFiles),
+ ),
+ ),
+ TE.flatMap(({ parsedFiles, references }) => transformReferenceHook(config)({ references, parsedFiles })),
+ TE.map(({ parsedFiles, references }) => convertToRenderableBundle(filterOutCustomFields(parsedFiles), references)),
+ TE.map(convertToDocumentationBundleForTemplate),
+ TE.flatMap(transformDocumentationBundleHook(config)),
+ TE.map(postHookCompile),
+ );
+}
+
+function generateForApex(apexBundles: UnparsedApexBundle[], config: MarkdownGeneratorConfig) {
+ const filterOutOfScope = apply(filterScope, config.scope);
const removeExcluded = apply(removeExcludedTags, config.excludeTags);
return pipe(
apexBundles,
- reflectBundles,
+ reflectApexSource,
TE.map(filterOutOfScope),
TE.map(addInheritedMembersToTypes),
TE.map(addInheritanceChainToTypes),
- TE.map(sort),
TE.map(removeExcluded),
- TE.bindTo('parsedFiles'),
- TE.bind('references', ({ parsedFiles }) => TE.right(convertToReferences(parsedFiles))),
- TE.flatMap(({ parsedFiles, references }) => transformReferenceHook(config)({ references, parsedFiles })),
- TE.map(({ parsedFiles, references }) => convertToRenderableBundle(parsedFiles, references)),
- TE.map(convertToDocumentationBundleForTemplate),
- TE.flatMap(transformDocumentationBundleHook(config)),
- TE.map(postHookCompile),
+ );
+}
+
+function generateForObject(objectBundles: (UnparsedCustomObjectBundle | UnparsedCustomFieldBundle)[]) {
+ function filterNonPublished(parsedFiles: ParsedFile[]): ParsedFile[] {
+ return parsedFiles.filter((parsedFile) => parsedFile.type.deploymentStatus === 'Deployed');
+ }
+
+ function filterNonPublic(parsedFiles: ParsedFile[]): ParsedFile[] {
+ return parsedFiles.filter((parsedFile) => parsedFile.type.visibility === 'Public');
+ }
+
+ const customObjects = objectBundles.filter(
+ (object): object is UnparsedCustomObjectBundle => object.type === 'customobject',
+ );
+
+ const customFields = objectBundles.filter(
+ (object): object is UnparsedCustomFieldBundle => object.type === 'customfield',
+ );
+
+ function generateForFields(
+ fields: UnparsedCustomFieldBundle[],
+ ): TE.TaskEither[]> {
+ return pipe(fields, reflectCustomFieldSources);
+ }
+
+ return pipe(
+ customObjects,
+ reflectCustomObjectSources,
+ TE.map(filterNonPublished),
+ TE.map(filterNonPublic),
+ TE.bindTo('objects'),
+ TE.bind('fields', () => generateForFields(customFields)),
+ // Locate the fields for each object by using the parentName property
+ TE.map(({ objects, fields }) => {
+ return objects.map((object) => {
+ const objectFields = fields.filter((field) => field.type.parentName === object.type.name);
+ return {
+ ...object,
+ type: {
+ ...object.type,
+ fields: objectFields,
+ },
+ } as ParsedFile;
+ });
+ }),
);
}
diff --git a/src/core/markdown/templates/custom-object-template.ts b/src/core/markdown/templates/custom-object-template.ts
new file mode 100644
index 00000000..ff0af90b
--- /dev/null
+++ b/src/core/markdown/templates/custom-object-template.ts
@@ -0,0 +1,30 @@
+export const customObjectTemplate = `
+{{ heading headingLevel heading }}
+
+{{{renderContent doc.description}}}
+
+## API Name
+\`{{apiName}}\`
+
+{{#if hasFields}}
+{{ heading fields.headingLevel fields.heading }}
+{{#each fields.value}}
+{{ heading headingLevel heading }}
+
+{{#if description}}
+{{{renderContent description}}}
+{{/if}}
+
+**API Name**
+
+\`{{{apiName}}}\`
+
+**Type**
+
+*{{fieldType}}*
+
+{{#unless @last}}---{{/unless}}
+{{/each}}
+{{/if}}
+
+`.trim();
diff --git a/src/core/markdown/utils.ts b/src/core/markdown/utils.ts
index 06f54064..39df2217 100644
--- a/src/core/markdown/utils.ts
+++ b/src/core/markdown/utils.ts
@@ -1,3 +1,5 @@
import { ParsedFile } from '../shared/types';
+import { Type } from '@cparra/apex-reflection';
-export const parsedFilesToTypes = (parsedFiles: ParsedFile[]) => parsedFiles.map((parsedFile) => parsedFile.type);
+export const parsedFilesToTypes = (parsedFiles: ParsedFile[]) =>
+ parsedFiles.map((parsedFile) => parsedFile.type);
diff --git a/src/core/openapi/__tests__/open-api-docs-processor.spec.ts b/src/core/openapi/__tests__/open-api-docs-processor.spec.ts
index 45817899..3951b896 100644
--- a/src/core/openapi/__tests__/open-api-docs-processor.spec.ts
+++ b/src/core/openapi/__tests__/open-api-docs-processor.spec.ts
@@ -1,5 +1,5 @@
import { OpenApiDocsProcessor } from '../open-api-docs-processor';
-import { OpenApiSettings } from '../../openApiSettings';
+import { OpenApiSettings } from '../openApiSettings';
import { SettingsBuilder } from '../../../test-helpers/SettingsBuilder';
import { DocCommentBuilder } from '../../../test-helpers/DocCommentBuilder';
import { AnnotationBuilder } from '../../../test-helpers/AnnotationBuilder';
diff --git a/src/core/openapi/manifest-factory.ts b/src/core/openapi/manifest-factory.ts
index 9ba277a1..19124275 100644
--- a/src/core/openapi/manifest-factory.ts
+++ b/src/core/openapi/manifest-factory.ts
@@ -1,7 +1,7 @@
import Manifest from '../manifest';
import { TypeParser } from './parser';
import { ReflectionResult } from '@cparra/apex-reflection';
-import { UnparsedSourceFile } from '../shared/types';
+import { UnparsedApexBundle } from '../shared/types';
/**
* Builds a new Manifest object, sourcing its types from the received TypeParser.
@@ -10,7 +10,7 @@ import { UnparsedSourceFile } from '../shared/types';
*/
export function createManifest(
typeParser: TypeParser,
- reflect: (apexBundle: UnparsedSourceFile) => ReflectionResult,
+ reflect: (apexBundle: UnparsedApexBundle) => ReflectionResult,
): Manifest {
return new Manifest(typeParser.parse(reflect));
}
diff --git a/src/core/openapi/open-api-docs-processor.ts b/src/core/openapi/open-api-docs-processor.ts
index 5f52ae21..5f076348 100644
--- a/src/core/openapi/open-api-docs-processor.ts
+++ b/src/core/openapi/open-api-docs-processor.ts
@@ -2,7 +2,7 @@ import { FileContainer } from './file-container';
import { ClassMirror, Type } from '@cparra/apex-reflection';
import { Logger } from '#utils/logger';
import { OpenApi } from './open-api';
-import { OpenApiSettings } from '../openApiSettings';
+import { OpenApiSettings } from './openApiSettings';
import { MethodParser } from './parsers/MethodParser';
import { camel2title } from '#utils/string-utils';
import { createOpenApiFile } from './openapi-type-file';
diff --git a/src/core/openApiSettings.ts b/src/core/openapi/openApiSettings.ts
similarity index 100%
rename from src/core/openApiSettings.ts
rename to src/core/openapi/openApiSettings.ts
diff --git a/src/core/openapi/parser.ts b/src/core/openapi/parser.ts
index 1ce9594b..ea34f47e 100644
--- a/src/core/openapi/parser.ts
+++ b/src/core/openapi/parser.ts
@@ -1,9 +1,9 @@
import { ClassMirror, InterfaceMirror, ReflectionResult, Type } from '@cparra/apex-reflection';
import { Logger } from '#utils/logger';
-import { UnparsedSourceFile } from '../shared/types';
+import { UnparsedApexBundle } from '../shared/types';
export interface TypeParser {
- parse(reflect: (apexBundle: UnparsedSourceFile) => ReflectionResult): Type[];
+ parse(reflect: (apexBundle: UnparsedApexBundle) => ReflectionResult): Type[];
}
type NameAware = { name: string };
@@ -11,10 +11,10 @@ type NameAware = { name: string };
export class RawBodyParser implements TypeParser {
constructor(
private logger: Logger,
- public typeBundles: UnparsedSourceFile[],
+ public typeBundles: UnparsedApexBundle[],
) {}
- parse(reflect: (apexBundle: UnparsedSourceFile) => ReflectionResult): Type[] {
+ parse(reflect: (apexBundle: UnparsedApexBundle) => ReflectionResult): Type[] {
const types = this.typeBundles
.map((currentBundle) => {
this.logger.log(`Parsing file: ${currentBundle.filePath}`);
diff --git a/src/core/reflection/__test__/filter-scope.spec.ts b/src/core/reflection/apex/__test__/filter-scope.spec.ts
similarity index 99%
rename from src/core/reflection/__test__/filter-scope.spec.ts
rename to src/core/reflection/apex/__test__/filter-scope.spec.ts
index edf8f2b8..8eb5e782 100644
--- a/src/core/reflection/__test__/filter-scope.spec.ts
+++ b/src/core/reflection/apex/__test__/filter-scope.spec.ts
@@ -1,6 +1,7 @@
import { ClassMirror, EnumMirror, InterfaceMirror } from '@cparra/apex-reflection';
-import { filterScope } from '../filter-scope';
+
import { parsedFileFromRawString } from './helpers';
+import { filterScope } from '../filter-scope';
describe('When filtering scope', () => {
it('filters out files with the @ignore annotation', () => {
diff --git a/src/core/reflection/__test__/helpers.ts b/src/core/reflection/apex/__test__/helpers.ts
similarity index 73%
rename from src/core/reflection/__test__/helpers.ts
rename to src/core/reflection/apex/__test__/helpers.ts
index 15ca7a53..f9d1a5a0 100644
--- a/src/core/reflection/__test__/helpers.ts
+++ b/src/core/reflection/apex/__test__/helpers.ts
@@ -1,7 +1,7 @@
-import { reflect } from '@cparra/apex-reflection';
-import { ParsedFile } from '../../shared/types';
+import { reflect, Type } from '@cparra/apex-reflection';
+import { ParsedFile } from '../../../shared/types';
-export function parsedFileFromRawString(raw: string): ParsedFile {
+export function parsedFileFromRawString(raw: string): ParsedFile {
const { error, typeMirror } = reflect(raw);
if (error) {
throw new Error(error.message);
diff --git a/src/core/reflection/__test__/remove-excluded-tags.spec.ts b/src/core/reflection/apex/__test__/remove-excluded-tags.spec.ts
similarity index 100%
rename from src/core/reflection/__test__/remove-excluded-tags.spec.ts
rename to src/core/reflection/apex/__test__/remove-excluded-tags.spec.ts
index 108e5c14..83daa879 100644
--- a/src/core/reflection/__test__/remove-excluded-tags.spec.ts
+++ b/src/core/reflection/apex/__test__/remove-excluded-tags.spec.ts
@@ -1,6 +1,6 @@
import { parsedFileFromRawString } from './helpers';
-import { removeExcludedTags } from '../remove-excluded-tags';
import { ClassMirror, InterfaceMirror } from '@cparra/apex-reflection';
+import { removeExcludedTags } from '../remove-excluded-tags';
describe('when removing excluded tags', () => {
describe('from any type', () => {
diff --git a/src/core/reflection/filter-scope.ts b/src/core/reflection/apex/filter-scope.ts
similarity index 64%
rename from src/core/reflection/filter-scope.ts
rename to src/core/reflection/apex/filter-scope.ts
index bb9c153e..2f0fa9b3 100644
--- a/src/core/reflection/filter-scope.ts
+++ b/src/core/reflection/apex/filter-scope.ts
@@ -1,7 +1,8 @@
-import Manifest from '../manifest';
-import { ParsedFile } from '../shared/types';
+import Manifest from '../../manifest';
+import { ParsedFile } from '../../shared/types';
+import { Type } from '@cparra/apex-reflection';
-export function filterScope(scopes: string[], parsedFiles: ParsedFile[]): ParsedFile[] {
+export function filterScope(scopes: string[], parsedFiles: ParsedFile[]): ParsedFile[] {
return parsedFiles
.filter(({ type }) => Manifest.shouldFilterType(type, scopes))
.map((parsedFile) => {
diff --git a/src/core/reflection/inheritance-chain-expanion.ts b/src/core/reflection/apex/inheritance-chain-expanion.ts
similarity index 82%
rename from src/core/reflection/inheritance-chain-expanion.ts
rename to src/core/reflection/apex/inheritance-chain-expanion.ts
index 108b84a8..77da29b0 100644
--- a/src/core/reflection/inheritance-chain-expanion.ts
+++ b/src/core/reflection/apex/inheritance-chain-expanion.ts
@@ -1,9 +1,9 @@
import { ClassMirror, Type } from '@cparra/apex-reflection';
import { createInheritanceChain } from './inheritance-chain';
-import { parsedFilesToTypes } from '../markdown/utils';
-import { ParsedFile } from '../shared/types';
+import { parsedFilesToTypes } from '../../markdown/utils';
+import { ParsedFile } from '../../shared/types';
-export const addInheritanceChainToTypes = (parsedFiles: ParsedFile[]): ParsedFile[] =>
+export const addInheritanceChainToTypes = (parsedFiles: ParsedFile[]): ParsedFile[] =>
parsedFiles.map((parsedFile) => ({
...parsedFile,
type: addInheritanceChain(parsedFile.type, parsedFilesToTypes(parsedFiles)),
diff --git a/src/core/reflection/inheritance-chain.ts b/src/core/reflection/apex/inheritance-chain.ts
similarity index 100%
rename from src/core/reflection/inheritance-chain.ts
rename to src/core/reflection/apex/inheritance-chain.ts
diff --git a/src/core/reflection/inherited-member-expansion.ts b/src/core/reflection/apex/inherited-member-expansion.ts
similarity index 95%
rename from src/core/reflection/inherited-member-expansion.ts
rename to src/core/reflection/apex/inherited-member-expansion.ts
index 0cfba92a..0df9db3d 100644
--- a/src/core/reflection/inherited-member-expansion.ts
+++ b/src/core/reflection/apex/inherited-member-expansion.ts
@@ -1,12 +1,12 @@
import { ClassMirror, InterfaceMirror, Type } from '@cparra/apex-reflection';
import { pipe } from 'fp-ts/function';
-import { ParsedFile } from '../shared/types';
-import { parsedFilesToTypes } from '../markdown/utils';
+import { ParsedFile } from '../../shared/types';
+import { parsedFilesToTypes } from '../../markdown/utils';
-export const addInheritedMembersToTypes = (parsedFiles: ParsedFile[]) =>
+export const addInheritedMembersToTypes = (parsedFiles: ParsedFile[]) =>
parsedFiles.map((parsedFile) => addInheritedMembers(parsedFilesToTypes(parsedFiles), parsedFile));
-export function addInheritedMembers(repository: Type[], parsedFile: ParsedFile): ParsedFile {
+export function addInheritedMembers(repository: Type[], parsedFile: ParsedFile): ParsedFile {
function addInheritedMembersToType(repository: Type[], current: T): T {
if (current.type_name === 'enum') {
return current;
diff --git a/src/core/parse-apex-metadata.ts b/src/core/reflection/apex/parse-apex-metadata.ts
similarity index 100%
rename from src/core/parse-apex-metadata.ts
rename to src/core/reflection/apex/parse-apex-metadata.ts
diff --git a/src/core/reflection/reflect-source.ts b/src/core/reflection/apex/reflect-apex-source.ts
similarity index 80%
rename from src/core/reflection/reflect-source.ts
rename to src/core/reflection/apex/reflect-apex-source.ts
index f83199ee..67206fcb 100644
--- a/src/core/reflection/reflect-source.ts
+++ b/src/core/reflection/apex/reflect-apex-source.ts
@@ -8,9 +8,9 @@ import * as O from 'fp-ts/Option';
import { ParsingError } from '@cparra/apex-reflection';
import { apply } from '#utils/fp';
import { Semigroup } from 'fp-ts/Semigroup';
-import { ParsedFile, UnparsedSourceFile } from '../shared/types';
-import { ReflectionError, ReflectionErrors } from '../errors/errors';
-import { parseApexMetadata } from '../parse-apex-metadata';
+import { ParsedFile, UnparsedApexBundle } from '../../shared/types';
+import { ReflectionError, ReflectionErrors } from '../../errors/errors';
+import { parseApexMetadata } from './parse-apex-metadata';
async function reflectAsync(rawSource: string): Promise {
return new Promise((resolve, reject) => {
@@ -25,7 +25,7 @@ async function reflectAsync(rawSource: string): Promise {
});
}
-export function reflectBundles(apexBundles: UnparsedSourceFile[]) {
+export function reflectApexSource(apexBundles: UnparsedApexBundle[]) {
const semiGroupReflectionError: Semigroup = {
concat: (x, y) => new ReflectionErrors([...x.errors, ...y.errors]),
};
@@ -34,14 +34,14 @@ export function reflectBundles(apexBundles: UnparsedSourceFile[]) {
return pipe(apexBundles, A.traverse(Ap)(reflectBundle));
}
-function reflectBundle(apexBundle: UnparsedSourceFile): TE.TaskEither {
- const convertToParsedFile: (typeMirror: Type) => ParsedFile = apply(toParsedFile, apexBundle.filePath);
+function reflectBundle(apexBundle: UnparsedApexBundle): TE.TaskEither> {
+ const convertToParsedFile: (typeMirror: Type) => ParsedFile = apply(toParsedFile, apexBundle.filePath);
const withMetadata = apply(addMetadata, apexBundle.metadataContent);
return pipe(apexBundle, reflectAsTask, TE.map(convertToParsedFile), TE.flatMap(withMetadata));
}
-function reflectAsTask(apexBundle: UnparsedSourceFile): TE.TaskEither {
+function reflectAsTask(apexBundle: UnparsedApexBundle): TE.TaskEither {
return TE.tryCatch(
() => reflectAsync(apexBundle.content),
(error) =>
@@ -49,7 +49,7 @@ function reflectAsTask(apexBundle: UnparsedSourceFile): TE.TaskEither {
return {
source: {
filePath: filePath,
@@ -62,12 +62,12 @@ function toParsedFile(filePath: string, typeMirror: Type): ParsedFile {
function addMetadata(
rawMetadataContent: string | null,
- parsedFile: ParsedFile,
-): TE.TaskEither {
+ parsedFile: ParsedFile,
+): TE.TaskEither> {
return TE.fromEither(
pipe(
parsedFile.type,
- (type) => addFileMetadataToTypeAnnotation(type, rawMetadataContent),
+ (type) => addFileMetadataToTypeAnnotation(type as Type, rawMetadataContent),
E.map((type) => ({ ...parsedFile, type })),
E.mapLeft((error) => errorToReflectionErrors(error, parsedFile.source.filePath)),
),
diff --git a/src/core/reflection/remove-excluded-tags.ts b/src/core/reflection/apex/remove-excluded-tags.ts
similarity index 98%
rename from src/core/reflection/remove-excluded-tags.ts
rename to src/core/reflection/apex/remove-excluded-tags.ts
index 9c6a4b1d..fa88c66e 100644
--- a/src/core/reflection/remove-excluded-tags.ts
+++ b/src/core/reflection/apex/remove-excluded-tags.ts
@@ -3,13 +3,13 @@ import { match } from 'fp-ts/boolean';
import { ClassMirror, DocComment, InterfaceMirror, Type } from '@cparra/apex-reflection';
import { pipe } from 'fp-ts/function';
import { apply } from '#utils/fp';
-import { ParsedFile } from '../shared/types';
+import { ParsedFile } from '../../shared/types';
type AppliedRemoveTagFn = (tagName: string, removeFn: RemoveTagFn) => DocComment;
type RemoveTagFn = (docComment: DocComment) => DocComment;
type Documentable = { docComment?: DocComment };
-export const removeExcludedTags = (excludedTags: string[], parsedFiles: ParsedFile[]): ParsedFile[] => {
+export const removeExcludedTags = (excludedTags: string[], parsedFiles: ParsedFile[]): ParsedFile[] => {
return parsedFiles.map((parsedFile) => {
return {
...parsedFile,
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
new file mode 100644
index 00000000..0eba7e3c
--- /dev/null
+++ b/src/core/reflection/sobject/__test__/reflect-custom-field-sources.spec.ts
@@ -0,0 +1,202 @@
+import { UnparsedCustomFieldBundle } from '../../../shared/types';
+import { reflectCustomFieldSources } from '../reflect-custom-field-source';
+import { assertEither } from '../../../test-helpers/assert-either';
+import * as E from 'fp-ts/Either';
+
+const customFieldContent = `
+
+
+ PhotoUrl__c
+ false
+
+ false
+ false
+ Url
+ A Photo URL field
+`;
+
+describe('when parsing custom field metadata', () => {
+ test('the resulting type contains the file path', 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].source.filePath).toBe('src/field/PhotoUrl__c.field-meta.xml'));
+ });
+
+ test('the resulting type contains the correct name', 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.name).toBe('PhotoUrl__c'));
+ });
+
+ test('the resulting type contains the correct parent name', 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.parentName).toBe('MyFirstObject__c'));
+ });
+
+ test('the resulting type contains the correct label', 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.label).toBe('PhotoUrl'));
+ });
+
+ test('the resulting type contains the correct type', 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.type).toBe('Url'));
+ });
+
+ test('the resulting type contains the correct description', 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.description).toBe('A Photo URL field'));
+ });
+
+ test('An error is returned when the XML is in an invalid format', async () => {
+ const unparsed: UnparsedCustomFieldBundle = {
+ type: 'customfield',
+ name: 'PhotoUrl__c',
+ parentName: 'MyFirstObject__c',
+ filePath: 'src/field/PhotoUrl__c.field-meta.xml',
+ content: 'invalid-xml',
+ };
+
+ const result = await reflectCustomFieldSources([unparsed])();
+
+ expect(E.isLeft(result)).toBe(true);
+ });
+
+ test('An error is returned when the XML is missing the CustomField 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 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
new file mode 100644
index 00000000..f923feee
--- /dev/null
+++ b/src/core/reflection/sobject/__test__/reflect-custom-object-sources.spec.ts
@@ -0,0 +1,181 @@
+import { reflectCustomObjectSources } from '../reflect-custom-object-sources';
+import { UnparsedCustomObjectBundle } from '../../../shared/types';
+import { assertEither } from '../../../test-helpers/assert-either';
+import * as E from 'fp-ts/Either';
+
+const sObjectContent = `
+
+
+ Deployed
+ test object for testing
+
+ MyFirstObjects
+ Public
+ `;
+
+describe('when parsing SObject metadata', () => {
+ test('the resulting type contains the file path', async () => {
+ const unparsed: UnparsedCustomObjectBundle = {
+ type: 'customobject',
+ name: 'MyFirstObject__c',
+ filePath: 'src/object/MyFirstObject__c.object-meta.xml',
+ content: sObjectContent,
+ };
+
+ const result = await reflectCustomObjectSources([unparsed])();
+
+ assertEither(result, (data) => expect(data[0].source.filePath).toBe('src/object/MyFirstObject__c.object-meta.xml'));
+ });
+
+ test('the resulting type contains the correct label', async () => {
+ const unparsed: UnparsedCustomObjectBundle = {
+ type: 'customobject',
+ name: 'MyFirstObject__c',
+ filePath: 'src/object/MyFirstObject__c.object-meta.xml',
+ content: sObjectContent,
+ };
+
+ const result = await reflectCustomObjectSources([unparsed])();
+
+ assertEither(result, (data) => {
+ expect(data[0].type.label).toBe('MyFirstObject');
+ });
+ });
+
+ test('the resulting type contains the correct name', async () => {
+ const unparsed: UnparsedCustomObjectBundle = {
+ type: 'customobject',
+ name: 'MyFirstObject__c',
+ filePath: 'src/object/MyFirstObject__c.object-meta.xml',
+ content: sObjectContent,
+ };
+
+ const result = await reflectCustomObjectSources([unparsed])();
+
+ assertEither(result, (data) => {
+ expect(data[0].type.name).toBe('MyFirstObject__c');
+ });
+ });
+
+ test('the resulting type contains the deployment status', async () => {
+ const unparsed: UnparsedCustomObjectBundle = {
+ type: 'customobject',
+ name: 'MyFirstObject__c',
+ filePath: 'src/object/MyFirstObject__c.object-meta.xml',
+ content: sObjectContent,
+ };
+
+ const result = await reflectCustomObjectSources([unparsed])();
+
+ assertEither(result, (data) => {
+ expect(data[0].type.deploymentStatus).toBe('Deployed');
+ });
+ });
+
+ test('the deployment status is "Deployed" by default', async () => {
+ const sObjectContent = `
+
+
+ test object for testing
+
+ MyFirstObjects
+ `;
+
+ const unparsed: UnparsedCustomObjectBundle = {
+ type: 'customobject',
+ name: 'MyFirstObject__c',
+ filePath: 'src/object/MyFirstObject__c.object-meta.xml',
+ content: sObjectContent,
+ };
+
+ const result = await reflectCustomObjectSources([unparsed])();
+
+ assertEither(result, (data) => {
+ expect(data[0].type.deploymentStatus).toBe('Deployed');
+ });
+ });
+
+ test('the resulting type contains the visibility', async () => {
+ const unparsed: UnparsedCustomObjectBundle = {
+ type: 'customobject',
+ name: 'MyFirstObject__c',
+ filePath: 'src/object/MyFirstObject__c.object-meta.xml',
+ content: sObjectContent,
+ };
+
+ const result = await reflectCustomObjectSources([unparsed])();
+
+ assertEither(result, (data) => {
+ expect(data[0].type.visibility).toBe('Public');
+ });
+ });
+
+ test('the visibility is "Public" by default', async () => {
+ const sObjectContent = `
+
+
+ Deployed
+ test object for testing
+
+ MyFirstObjects
+ `;
+
+ const unparsed: UnparsedCustomObjectBundle = {
+ type: 'customobject',
+ name: 'MyFirstObject__c',
+ filePath: 'src/object/MyFirstObject__c.object-meta.xml',
+ content: sObjectContent,
+ };
+
+ const result = await reflectCustomObjectSources([unparsed])();
+
+ assertEither(result, (data) => {
+ expect(data[0].type.visibility).toBe('Public');
+ });
+ });
+
+ test('an error is thrown when the XML is in an invalid format', 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);
+ });
+
+ 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
new file mode 100644
index 00000000..a0affa80
--- /dev/null
+++ b/src/core/reflection/sobject/reflect-custom-field-source.ts
@@ -0,0 +1,104 @@
+import { ParsedFile, UnparsedCustomFieldBundle } from '../../shared/types';
+import { ReflectionError, ReflectionErrors } from '../../errors/errors';
+import { Semigroup } from 'fp-ts/Semigroup';
+import * as TE from 'fp-ts/TaskEither';
+import * as T from 'fp-ts/Task';
+import { pipe } from 'fp-ts/function';
+import * as A from 'fp-ts/Array';
+import { XMLParser } from 'fast-xml-parser';
+import * as E from 'fp-ts/Either';
+
+export type CustomFieldMetadata = {
+ type_name: 'customfield';
+ description: string | null;
+ name: string;
+ label: string;
+ type: string;
+ parentName: string;
+};
+
+export function reflectCustomFieldSources(
+ customFieldSources: UnparsedCustomFieldBundle[],
+): TE.TaskEither[]> {
+ const semiGroupReflectionError: Semigroup = {
+ concat: (x, y) => new ReflectionErrors([...x.errors, ...y.errors]),
+ };
+ const Ap = TE.getApplicativeTaskValidation(T.ApplyPar, semiGroupReflectionError);
+
+ return pipe(customFieldSources, A.traverse(Ap)(reflectCustomFieldSource));
+}
+
+function reflectCustomFieldSource(
+ customFieldSource: UnparsedCustomFieldBundle,
+): TE.TaskEither> {
+ return pipe(
+ E.tryCatch(() => new XMLParser().parse(customFieldSource.content), E.toError),
+ E.flatMap(validate),
+ E.map(toCustomFieldMetadata),
+ E.map((metadata) => addName(metadata, customFieldSource.name)),
+ E.map((metadata) => addParentName(metadata, customFieldSource.parentName)),
+ E.map((metadata) => toParsedFile(customFieldSource.filePath, metadata)),
+ E.mapLeft((error) => new ReflectionErrors([new ReflectionError(customFieldSource.filePath, error.message)])),
+ TE.fromEither,
+ );
+}
+
+function validate(parsedResult: unknown): E.Either {
+ const err = E.left(new Error('Invalid custom field metadata'));
+
+ function isObject(value: unknown) {
+ return typeof value === 'object' && value !== null ? E.right(value) : err;
+ }
+
+ function hasTheCustomFieldKey(value: object) {
+ return 'CustomField' in value ? E.right(value) : err;
+ }
+
+ function theCustomFieldKeyIsAnObject(value: Record<'CustomField', unknown>) {
+ 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),
+ );
+}
+
+function toCustomFieldMetadata(parserResult: { CustomField: object }): CustomFieldMetadata {
+ const defaultValues = {
+ description: null,
+ };
+
+ return { ...defaultValues, ...parserResult.CustomField, type_name: 'customfield' } as CustomFieldMetadata;
+}
+
+function addName(metadata: CustomFieldMetadata, name: string): CustomFieldMetadata {
+ return { ...metadata, name };
+}
+
+function addParentName(metadata: CustomFieldMetadata, parentName: string): CustomFieldMetadata {
+ return { ...metadata, parentName };
+}
+
+function toParsedFile(filePath: string, typeMirror: CustomFieldMetadata): ParsedFile {
+ return {
+ source: {
+ filePath,
+ name: typeMirror.name,
+ type: typeMirror.type_name,
+ },
+ type: typeMirror,
+ };
+}
diff --git a/src/core/reflection/sobject/reflect-custom-object-sources.ts b/src/core/reflection/sobject/reflect-custom-object-sources.ts
new file mode 100644
index 00000000..e301c4c1
--- /dev/null
+++ b/src/core/reflection/sobject/reflect-custom-object-sources.ts
@@ -0,0 +1,109 @@
+import { ParsedFile, UnparsedCustomObjectBundle } from '../../shared/types';
+import { XMLParser } from 'fast-xml-parser';
+import * as TE from 'fp-ts/TaskEither';
+import { ReflectionError, ReflectionErrors } from '../../errors/errors';
+import { Semigroup } from 'fp-ts/Semigroup';
+import * as T from 'fp-ts/Task';
+import { pipe } from 'fp-ts/function';
+import * as A from 'fp-ts/Array';
+import * as E from 'fp-ts/Either';
+import { CustomFieldMetadata } from './reflect-custom-field-source';
+
+export type ObjectMetadata = {
+ type_name: 'customobject';
+ deploymentStatus: string;
+ visibility: string;
+ label: string;
+ name: string;
+ description: string | null;
+ fields: ParsedFile[];
+};
+
+export function reflectCustomObjectSources(
+ objectSources: UnparsedCustomObjectBundle[],
+): TE.TaskEither[]> {
+ const semiGroupReflectionError: Semigroup = {
+ concat: (x, y) => new ReflectionErrors([...x.errors, ...y.errors]),
+ };
+ const Ap = TE.getApplicativeTaskValidation(T.ApplyPar, semiGroupReflectionError);
+
+ return pipe(objectSources, A.traverse(Ap)(reflectCustomObjectSource));
+}
+
+function reflectCustomObjectSource(
+ objectSource: UnparsedCustomObjectBundle,
+): TE.TaskEither> {
+ return pipe(
+ E.tryCatch(() => new XMLParser().parse(objectSource.content), E.toError),
+ E.flatMap(validate),
+ E.map(toObjectMetadata),
+ E.map((metadata) => addName(metadata, objectSource.name)),
+ E.map(addTypeName),
+ E.map((metadata) => toParsedFile(objectSource.filePath, metadata)),
+ E.mapLeft((error) => new ReflectionErrors([new ReflectionError(objectSource.filePath, error.message)])),
+ TE.fromEither,
+ );
+}
+
+function validate(parseResult: unknown): E.Either {
+ const err = E.left(new Error('Invalid SObject metadata'));
+
+ function isObject(value: unknown) {
+ return typeof value === 'object' && value !== null ? E.right(value) : err;
+ }
+
+ function hasTheCustomObjectKey(value: object) {
+ return 'CustomObject' in value ? E.right(value) : err;
+ }
+
+ function theCustomObjectKeyIsAnObject(value: Record<'CustomObject', unknown>) {
+ 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),
+ );
+}
+
+function toObjectMetadata(parserResult: { CustomObject: object }): ObjectMetadata {
+ const defaultValues = {
+ deploymentStatus: 'Deployed',
+ visibility: 'Public',
+ description: null,
+ fields: [] as ParsedFile[],
+ };
+ return { ...defaultValues, ...parserResult.CustomObject } as ObjectMetadata;
+}
+
+function addName(objectMetadata: ObjectMetadata, name: string): ObjectMetadata {
+ return {
+ ...objectMetadata,
+ name,
+ };
+}
+
+function addTypeName(objectMetadata: ObjectMetadata): ObjectMetadata {
+ return {
+ ...objectMetadata,
+ type_name: 'customobject',
+ };
+}
+
+function toParsedFile(filePath: string, typeMirror: ObjectMetadata): ParsedFile {
+ return {
+ source: {
+ filePath: filePath,
+ name: typeMirror.name,
+ type: typeMirror.type_name,
+ },
+ type: typeMirror,
+ };
+}
diff --git a/src/core/reflection/sort-types-and-members.ts b/src/core/reflection/sort-types-and-members.ts
index 9c2e3e8e..fde5f41e 100644
--- a/src/core/reflection/sort-types-and-members.ts
+++ b/src/core/reflection/sort-types-and-members.ts
@@ -1,13 +1,21 @@
import { ClassMirror, EnumMirror, InterfaceMirror, Type } from '@cparra/apex-reflection';
import { ParsedFile } from '../shared/types';
+import { isApexType } from '../shared/utils';
+import { ObjectMetadata } from './sobject/reflect-custom-object-sources';
+import { CustomFieldMetadata } from './sobject/reflect-custom-field-source';
type Named = { name: string };
-export function sortTypesAndMembers(shouldSort: boolean, parsedFiles: ParsedFile[]): ParsedFile[] {
+export function sortTypesAndMembers(
+ shouldSort: boolean,
+ parsedFiles: ParsedFile[],
+): ParsedFile[] {
return parsedFiles
.map((parsedFile) => ({
...parsedFile,
- type: sortTypeMember(parsedFile.type, shouldSort),
+ type: isApexType(parsedFile.type)
+ ? sortTypeMember(parsedFile.type, shouldSort)
+ : sortCustomObjectFields(parsedFile.type, shouldSort),
}))
.sort((a, b) => sortByNames(shouldSort, a.type, b.type));
}
@@ -34,6 +42,17 @@ function sortTypeMember(type: Type, shouldSort: boolean): Type {
}
}
+function sortCustomObjectFields(type: ObjectMetadata, shouldSort: boolean): ObjectMetadata {
+ return {
+ ...type,
+ fields: sortFields(type.fields, shouldSort),
+ };
+}
+
+function sortFields(fields: ParsedFile[], shouldSort: boolean): ParsedFile[] {
+ return fields.sort((a, b) => sortByNames(shouldSort, a.type, b.type));
+}
+
function sortEnumValues(shouldSort: boolean, enumType: EnumMirror): EnumMirror {
return {
...enumType,
diff --git a/src/core/renderables/types.d.ts b/src/core/renderables/types.d.ts
index 878bc918..ddf50728 100644
--- a/src/core/renderables/types.d.ts
+++ b/src/core/renderables/types.d.ts
@@ -82,7 +82,7 @@ type RenderableDocumentation = {
annotations?: Annotation[];
description?: RenderableContent[];
customTags?: CustomTag[];
- example: RenderableSection;
+ example?: RenderableSection;
group?: string;
author?: string;
date?: string;
@@ -131,7 +131,7 @@ type RenderableMethod = {
inherited?: boolean;
};
-type RenderableField = {
+type RenderableApexField = {
headingLevel: number;
heading: string;
type: RenderableSection;
@@ -159,8 +159,8 @@ export type RenderableClass = RenderableType & {
isGrouped: boolean;
};
methods: RenderableSection[]> & { isGrouped: boolean };
- fields: RenderableSection[]> & { isGrouped: boolean };
- properties: RenderableSection[]> & { isGrouped: boolean };
+ fields: RenderableSection[]> & { isGrouped: boolean };
+ properties: RenderableSection[]> & { isGrouped: boolean };
innerClasses: RenderableSection;
innerEnums: RenderableSection;
innerInterfaces: RenderableSection;
@@ -177,4 +177,22 @@ export type RenderableEnum = RenderableType & {
values: RenderableSection;
};
-export type Renderable = (RenderableClass | RenderableInterface | RenderableEnum) & { filePath: string };
+export type RenderableCustomObject = Omit & {
+ apiName: string;
+ type: 'customobject';
+ hasFields: boolean;
+ fields: RenderableSection;
+};
+
+export type RenderableCustomField = {
+ headingLevel: number;
+ heading: string;
+ apiName: string;
+ description: RenderableContent[];
+ type: 'field';
+ fieldType: string;
+};
+
+export type Renderable = (RenderableClass | RenderableInterface | RenderableEnum | RenderableCustomObject) & {
+ filePath: string;
+};
diff --git a/src/core/shared/types.d.ts b/src/core/shared/types.d.ts
index 74d31854..a3c5cac1 100644
--- a/src/core/shared/types.d.ts
+++ b/src/core/shared/types.d.ts
@@ -1,5 +1,7 @@
import { Type } from '@cparra/apex-reflection';
import { ChangeLogPageData } from '../changelog/generate-change-log';
+import { ObjectMetadata } from '../reflection/sobject/reflect-custom-object-sources';
+import { CustomFieldMetadata } from '../reflection/sobject/reflect-custom-field-source';
export type Generators = 'markdown' | 'openapi' | 'changelog';
@@ -21,11 +23,13 @@ export type UserDefinedMarkdownConfig = {
scope: string[];
namespace?: string;
defaultGroupName: string;
+ customObjectsGroupName: string;
sortAlphabetically: boolean;
includeMetadata: boolean;
linkingStrategy: LinkingStrategy;
excludeTags: string[];
referenceGuideTitle: string;
+ /** Glob patterns to exclude files from the documentation. */
exclude: string[];
} & Partial;
@@ -53,7 +57,26 @@ export type UserDefinedChangelogConfig = {
export type UserDefinedConfig = UserDefinedMarkdownConfig | UserDefinedOpenApiConfig | UserDefinedChangelogConfig;
-export type UnparsedSourceFile = {
+export type UnparsedSourceBundle = UnparsedApexBundle | UnparsedCustomObjectBundle | UnparsedCustomFieldBundle;
+
+export type UnparsedCustomObjectBundle = {
+ type: 'customobject';
+ name: string;
+ filePath: string;
+ content: string;
+};
+
+export type UnparsedCustomFieldBundle = {
+ type: 'customfield';
+ name: string;
+ filePath: string;
+ content: string;
+ parentName: string;
+};
+
+export type UnparsedApexBundle = {
+ type: 'apex';
+ name: string;
filePath: string;
content: string;
metadataContent: string | null;
@@ -62,12 +85,14 @@ export type UnparsedSourceFile = {
export type SourceFileMetadata = {
filePath: string;
name: string;
- type: 'interface' | 'class' | 'enum';
+ type: 'interface' | 'class' | 'enum' | 'customobject' | 'customfield';
};
-export type ParsedFile = {
+export type ParsedFile<
+ T extends Type | ObjectMetadata | CustomFieldMetadata = Type | ObjectMetadata | CustomFieldMetadata,
+> = {
source: SourceFileMetadata;
- type: Type;
+ type: T;
};
export type DocPageReference = {
@@ -84,7 +109,7 @@ export type DocPageReference = {
referencePath: string;
};
-type Frontmatter = string | Record | null;
+export type Frontmatter = string | Record | null;
export type ReferenceGuidePageData = {
frontmatter: Frontmatter;
@@ -98,9 +123,10 @@ export type DocPageData = {
outputDocPath: string;
frontmatter: Frontmatter;
content: string;
+ type: 'class' | 'interface' | 'enum' | 'customobject';
};
-export type OpenApiPageData = Omit;
+export type OpenApiPageData = Omit;
export type PageData = DocPageData | OpenApiPageData | ReferenceGuidePageData | ChangeLogPageData;
diff --git a/src/core/shared/utils.ts b/src/core/shared/utils.ts
index 233b0899..12982c74 100644
--- a/src/core/shared/utils.ts
+++ b/src/core/shared/utils.ts
@@ -1,4 +1,8 @@
import { Skip } from './types';
+import { Type } from '@cparra/apex-reflection';
+import { ObjectMetadata } from '../reflection/sobject/reflect-custom-object-sources';
+import { MarkdownGeneratorConfig } from '../markdown/generate-docs';
+import { CustomFieldMetadata } from '../reflection/sobject/reflect-custom-field-source';
/**
* Represents a file to be skipped.
@@ -12,3 +16,27 @@ export function skip(): Skip {
export function isSkip(value: unknown): value is Skip {
return Object.prototype.hasOwnProperty.call(value, '_tag') && (value as Skip)._tag === 'Skip';
}
+
+export function isObjectType(type: Type | ObjectMetadata | CustomFieldMetadata): type is ObjectMetadata {
+ return (type as ObjectMetadata).type_name === 'customobject';
+}
+
+export function isApexType(type: Type | ObjectMetadata | CustomFieldMetadata): type is Type {
+ return !isObjectType(type);
+}
+
+export function getTypeGroup(type: Type | ObjectMetadata, config: MarkdownGeneratorConfig): string {
+ function getGroup(type: Type, config: MarkdownGeneratorConfig): string {
+ const groupAnnotation = type.docComment?.annotations.find(
+ (annotation) => annotation.name.toLowerCase() === 'group',
+ );
+ return groupAnnotation?.body ?? config.defaultGroupName;
+ }
+
+ switch (type.type_name) {
+ case 'customobject':
+ return config.customObjectsGroupName;
+ default:
+ return getGroup(type, config);
+ }
+}
diff --git a/src/defaults.ts b/src/defaults.ts
index 0182cb1f..8510cf7a 100644
--- a/src/defaults.ts
+++ b/src/defaults.ts
@@ -6,10 +6,11 @@ export const markdownDefaults = {
...commonDefaults,
scope: ['global'],
defaultGroupName: 'Miscellaneous',
+ customObjectsGroupName: 'Custom Objects',
includeMetadata: false,
sortAlphabetically: false,
linkingStrategy: 'relative' as const,
- referenceGuideTitle: 'Apex Reference Guide',
+ referenceGuideTitle: 'Reference Guide',
excludeTags: [],
exclude: [],
};
diff --git a/src/test-helpers/SettingsBuilder.ts b/src/test-helpers/SettingsBuilder.ts
index 72738598..64e992aa 100644
--- a/src/test-helpers/SettingsBuilder.ts
+++ b/src/test-helpers/SettingsBuilder.ts
@@ -1,4 +1,4 @@
-import { SettingsConfig } from '../core/openApiSettings';
+import { SettingsConfig } from '../core/openapi/openApiSettings';
/**
* Builder class to create SettingsConfig objects.