diff --git a/Makefile b/Makefile
index e2d64a3..b97099a 100644
--- a/Makefile
+++ b/Makefile
@@ -4,9 +4,11 @@ default: all
.PHONY: all
all: package-apex package-vf package-lightning
-docset-gen:
+vendor:
dep ensure
- go build -x -o docset-gen ./SFDashC/
+
+docset-gen: vendor
+ go build -i -x -o docset-gen ./SFDashC/
.PHONY: run-apex
run-apex: clean-index docset-gen
@@ -55,3 +57,10 @@ clean: clean-index clean-package clean-archive
.PHONY: clean-build
clean-build:
rm -fr ./build
+
+.PHONY: clean-vendor
+clean-vendor:
+ rm -fr ./vendor
+
+.PHONY: clean-all
+clean-all: clean clean-build clean-vendor
diff --git a/README.md b/README.md
index a8cf2e9..3bd8998 100644
--- a/README.md
+++ b/README.md
@@ -9,12 +9,14 @@ Everything is wrapped with a Makefile and can be completely built by simply exec
That's it!
-It will generate 3 docsets: Salesforce Apex, Salesforce Visualforce, and Salesforce Combined
+It will generate 3 docsets: Salesforce Apex, Salesforce Visualforce, and Salesforce Lightning
Dependencies
------------
-Currently these are not auto resolved. You must install the following:
+All dependencies are being managed by [dep](https://github.com/golang/dep). Dep must be installed for the vendor folder to be built.
-* github.com/coopernurse/gorp
-* github.com/mattn/go-sqlite3
+To Do
+-----
+
+ - [ ] Now that new `ForceCascadeType` is available, some of the entries in `./SFDashC/supportedtypes.go` can be simplified
diff --git a/SFDashC/database.go b/SFDashC/database.go
index 7de9e39..3d631c8 100644
--- a/SFDashC/database.go
+++ b/SFDashC/database.go
@@ -11,6 +11,7 @@ import (
var dbmap *gorp.DbMap
var dbName = "docSet.dsidx"
+// InitDb will initialize a new instance of a sqlite db for indexing
func InitDb(buildDir string) *gorp.DbMap {
dbPath := filepath.Join(buildDir, dbName)
err := os.MkdirAll(filepath.Dir(dbPath), 0755)
@@ -32,13 +33,14 @@ func InitDb(buildDir string) *gorp.DbMap {
return dbmap
}
-func SaveSearchIndex(dbmap *gorp.DbMap, entry TOCEntry, entryType *SupportedType, toc *AtlasTOC) {
- if entry.LinkAttr.Href == "" || entryType == nil {
+// SaveSearchIndex will index a particular entry into the sqlite3 database
+func SaveSearchIndex(dbmap *gorp.DbMap, entry TOCEntry, entryType SupportedType, toc *AtlasTOC) {
+ if entry.LinkAttr.Href == "" || !entryType.IsValidType() {
return
}
relLink := entry.GetContentFilepath(toc, false)
- name := entry.CleanTitle(*entryType)
+ name := entry.CleanTitle(entryType)
if entryType.ShowNamespace && len(entryHierarchy) > 0 {
// Show namespace for methods
name = entryHierarchy[len(entryHierarchy)-1] + "." + name
@@ -50,6 +52,8 @@ func SaveSearchIndex(dbmap *gorp.DbMap, entry TOCEntry, entryType *SupportedType
Path: relLink,
}
- dbmap.Insert(&si)
+ err := dbmap.Insert(&si)
+ ExitIfError(err)
+
LogDebug("%s is indexed as a %s", entry.Text, entryType.TypeName)
}
diff --git a/SFDashC/main.go b/SFDashC/main.go
index 3108e24..43498b2 100644
--- a/SFDashC/main.go
+++ b/SFDashC/main.go
@@ -46,7 +46,9 @@ func getTOC(locale string, deliverable string) (toc *AtlasTOC, err error) {
ExitIfError(err)
// Read the downloaded JSON
- defer resp.Body.Close()
+ defer func() {
+ ExitIfError(resp.Body.Close())
+ }()
contents, err := ioutil.ReadAll(resp.Body)
ExitIfError(err)
@@ -91,7 +93,9 @@ func saveMainContent(toc *AtlasTOC) {
ofile, err := os.Create(filePath)
ExitIfError(err)
- defer ofile.Close()
+ defer func() {
+ ExitIfError(ofile.Close())
+ }()
_, err = ofile.WriteString(
"" +
content,
@@ -100,6 +104,7 @@ func saveMainContent(toc *AtlasTOC) {
}
}
+// saveContentVersion will retrieve the version number from the TOC and save that to a text file
func saveContentVersion(toc *AtlasTOC) {
filePath := fmt.Sprintf("%s-version.txt", toc.Deliverable)
// Prepend build dir
@@ -110,15 +115,20 @@ func saveContentVersion(toc *AtlasTOC) {
ofile, err := os.Create(filePath)
ExitIfError(err)
- defer ofile.Close()
+ defer func() {
+ ExitIfError(ofile.Close())
+ }()
_, err = ofile.WriteString(toc.Version.DocVersion)
ExitIfError(err)
}
+// downloadCSS will download a CSS file using the CSS base URL
func downloadCSS(fileName string, wg *sync.WaitGroup) {
downloadFile(cssBaseURL+"/"+fileName, fileName, wg)
}
+// downloadFile will download n aribtrary file to a given file path
+// It will also handle throttling if a WaitGroup is provided
func downloadFile(url string, fileName string, wg *sync.WaitGroup) {
if wg != nil {
defer wg.Done()
@@ -131,11 +141,15 @@ func downloadFile(url string, fileName string, wg *sync.WaitGroup) {
ofile, err := os.Create(filePath)
ExitIfError(err)
- defer ofile.Close()
+ defer func() {
+ ExitIfError(ofile.Close())
+ }()
response, err := http.Get(url)
ExitIfError(err)
- defer response.Body.Close()
+ defer func() {
+ ExitIfError(response.Body.Close())
+ }()
_, err = io.Copy(ofile, response.Body)
ExitIfError(err)
@@ -146,27 +160,43 @@ func downloadFile(url string, fileName string, wg *sync.WaitGroup) {
}
}
-func getEntryType(entry TOCEntry) (*SupportedType, error) {
+// getEntryType will return an entry type that should be used for a given entry and it's parent's type
+func getEntryType(entry TOCEntry, parentType SupportedType) (SupportedType, error) {
+ if parentType.ForceCascadeType {
+ return parentType.CreateChildType(), nil
+ }
+
+ childType, err := lookupEntryType(entry)
+ if err != nil && parentType.CascadeType {
+ childType = parentType.CreateChildType()
+ err = nil
+ }
+
+ return childType, err
+}
+
+// lookupEntryType returns the matching SupportedType for a given entry or returns an error
+func lookupEntryType(entry TOCEntry) (SupportedType, error) {
for _, t := range SupportedTypes {
if entry.IsType(t) {
- return &t, nil
+ return t, nil
}
}
- return nil, NewTypeNotFoundError(entry)
+ return SupportedType{}, NewTypeNotFoundError(entry)
}
// processEntryReference downloads html and indexes a toc item
-func processEntryReference(entry TOCEntry, entryType *SupportedType, toc *AtlasTOC) {
+func processEntryReference(entry TOCEntry, entryType SupportedType, toc *AtlasTOC) {
LogDebug("Processing: %s", entry.Text)
throttle <- 1
wg.Add(1)
go downloadContent(entry, toc, &wg)
- if entryType == nil {
- LogDebug("No entry type for %s. Cannot index", entry.Text)
- } else if entryType.IsContainer || entryType.IsHidden {
+ if entryType.ShouldSkipIndex() {
LogDebug("%s is a container or is hidden. Do not index", entry.Text)
+ } else if !entryType.IsValidType() {
+ LogDebug("No entry type for %s. Cannot index", entry.Text)
} else {
SaveSearchIndex(dbmap, entry, entryType, toc)
}
@@ -176,33 +206,23 @@ func processEntryReference(entry TOCEntry, entryType *SupportedType, toc *AtlasT
var entryHierarchy []string
// processChildReferences iterates through all child toc items, cascading types, and indexes them
-func processChildReferences(entry TOCEntry, entryType *SupportedType, toc *AtlasTOC) {
- if entryType != nil && entryType.PushName {
- entryHierarchy = append(entryHierarchy, entry.CleanTitle(*entryType))
+func processChildReferences(entry TOCEntry, entryType SupportedType, toc *AtlasTOC) {
+ if entryType.PushName {
+ entryHierarchy = append(entryHierarchy, entry.CleanTitle(entryType))
}
for _, child := range entry.Children {
LogDebug("Reading child: %s", child.Text)
var err error
- var childType *SupportedType
+ var childType SupportedType
// Skip anything without an HTML page
if child.LinkAttr.Href != "" {
- childType, err = getEntryType(child)
- if childType == nil && entryType != nil && (entryType.IsContainer || entryType.CascadeType) {
- // No child type, and parent is set to cascade
- LogDebug("Parent was container or cascade, using parent type of %s", entryType.TypeName)
- childType = entryType
- childType.IsContainer = false
- } else if childType != nil && entryType != nil {
- // We didn't cascade in full, but some features are still hereditary
- if entryType.IsHidden {
- childType.IsHidden = true
- }
- }
- if childType == nil && err != nil {
+ childType, err = getEntryType(child, entryType)
+ if err == nil {
+ processEntryReference(child, childType, toc)
+ } else {
WarnIfError(err)
}
- processEntryReference(child, childType, toc)
} else {
LogDebug("%s has no link. Skipping", child.Text)
}
@@ -212,7 +232,7 @@ func processChildReferences(entry TOCEntry, entryType *SupportedType, toc *Atlas
}
LogDebug("Done processing children for %s", entry.Text)
- if entryType != nil && entryType.PushName {
+ if entryType.PushName {
entryHierarchy = entryHierarchy[:len(entryHierarchy)-1]
}
}
@@ -244,7 +264,9 @@ func downloadContent(entry TOCEntry, toc *AtlasTOC, wg *sync.WaitGroup) {
}
header += ""
- defer ofile.Close()
+ defer func() {
+ ExitIfError(ofile.Close())
+ }()
_, err = ofile.WriteString(
header + content.Content,
)
@@ -286,8 +308,8 @@ func main() {
// Download each entry
for _, entry := range toc.TOCEntries {
- entryType, err := getEntryType(entry)
- if entryType != nil && err == nil {
+ entryType, err := lookupEntryType(entry)
+ if err == nil {
processEntryReference(entry, entryType, toc)
}
processChildReferences(entry, entryType, toc)
diff --git a/SFDashC/structs.go b/SFDashC/structs.go
index 9e704e2..a2e74ac 100644
--- a/SFDashC/structs.go
+++ b/SFDashC/structs.go
@@ -78,10 +78,6 @@ type SupportedType struct {
TypeName string
// Not sure...
AppendParents bool
- // Indicates that this just contains other nodes and we don't want to index this node
- IsContainer bool
- // Indicates that this and all nodes underneith should be hidden
- IsHidden bool
// Skip trimming of suffix from title
NoTrim bool
// Not sure...
@@ -90,8 +86,15 @@ type SupportedType struct {
PushName bool
// Should a namspace be prefixed to the database entry
ShowNamespace bool
- // Should cascade type downwards
+ // Indicates that this just contains other nodes and we don't want to index this node
+ // This is not hereditary
+ IsContainer bool
+ // Indicates that this and all nodes underneith should be hidden
+ IsHidden bool
+ // Should cascade type downwards unless the child has it's own type
CascadeType bool
+ // Should cascade type downwards, even if children have their own type
+ ForceCascadeType bool
}
// Sqlite Struct
@@ -103,17 +106,17 @@ type SearchIndex struct {
Path string `db:path`
}
+// matchesTitle returns true if the title matches that of the specified type
func (suppType SupportedType) matchesTitle(title string) bool {
match := false
- if suppType.TitlePrefix != "" {
- match = match || strings.HasPrefix(title, suppType.TitlePrefix)
- }
- if suppType.TitleSuffix != "" {
- match = match || strings.HasSuffix(title, suppType.TitleSuffix)
- }
+ match = match || (suppType.TitlePrefix != "" &&
+ strings.HasPrefix(title, suppType.TitlePrefix))
+ match = match || (suppType.TitleSuffix != "" &&
+ strings.HasSuffix(title, suppType.TitleSuffix))
return match
}
+// matchesID returns true if the ID matches that of the specified type
func (suppType SupportedType) matchesID(id string) bool {
if suppType.ID != "" && suppType.ID == id {
return true
@@ -124,6 +127,22 @@ func (suppType SupportedType) matchesID(id string) bool {
return false
}
+// CreateChildType returns a child type inheriting the current type
+func (suppType SupportedType) CreateChildType() SupportedType {
+ // Reset values that do not cascade
+ suppType.IsContainer = false
+ return suppType
+}
+
+func (suppType SupportedType) ShouldSkipIndex() bool {
+ return suppType.IsContainer || suppType.IsHidden
+}
+
+// IsValidType returns whether or not this is a valid type
+func (suppType SupportedType) IsValidType() bool {
+ return suppType.TypeName != ""
+}
+
// IsType indicates that the TOCEntry is of a given SupportedType
// This is done by checking the suffix of the entry text
func (entry TOCEntry) IsType(t SupportedType) bool {
@@ -173,14 +192,15 @@ func (entry TOCEntry) GetContent(toc *AtlasTOC) (content *TOCContent, err error)
toc.Version.DocVersion,
)
- // fmt.Println(url)
resp, err := http.Get(url)
if err != nil {
return
}
// Read the downloaded JSON
- defer resp.Body.Close()
+ defer func() {
+ ExitIfError(resp.Body.Close())
+ }()
contents, err := ioutil.ReadAll(resp.Body)
if err != nil {
return
diff --git a/SFDashC/supportedtypes.go b/SFDashC/supportedtypes.go
index 0e4c8e1..9199dec 100644
--- a/SFDashC/supportedtypes.go
+++ b/SFDashC/supportedtypes.go
@@ -19,6 +19,43 @@ var SupportedTypes = []SupportedType{
ID: "apex_intro_get_started",
CascadeType: true,
},
+ SupportedType{
+ TypeName: "Guide",
+ ID: "pages_flows_customize_runtime_ui",
+ },
+ SupportedType{
+ TypeName: "Guide",
+ ID: "pages_quick_start_controller_shell",
+ },
+ SupportedType{
+ TypeName: "Guide",
+ ID: "pages_email_custom_controller",
+ },
+ SupportedType{
+ TypeName: "Guide",
+ IDPrefix: "apex_qs_",
+ CascadeType: true,
+ },
+ SupportedType{
+ TypeName: "Guide",
+ ID: "apex_process_plugin_using",
+ },
+ SupportedType{
+ TypeName: "Guide",
+ ID: "apex_platform_cache_builder",
+ },
+ SupportedType{
+ TypeName: "Guide",
+ ID: "apex_classes_restful_http_testing_httpcalloutmock",
+ },
+ SupportedType{
+ TypeName: "Guide",
+ ID: "apex_classes_namespaces_and_invoking_methods",
+ },
+ SupportedType{
+ TypeName: "Guide",
+ ID: "apex_classes_schema_namespace_using",
+ },
// Apex types
SupportedType{
TypeName: "Method",
@@ -48,6 +85,13 @@ var SupportedTypes = []SupportedType{
AppendParents: true,
ShowNamespace: false,
},
+ SupportedType{
+ TypeName: "Interface",
+ TitleSuffix: "Global Interface",
+ PushName: true,
+ AppendParents: true,
+ ShowNamespace: false,
+ },
SupportedType{
TypeName: "Interface",
TitleSuffix: "Interface",