-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdsl_reference.go
More file actions
176 lines (161 loc) · 4.4 KB
/
dsl_reference.go
File metadata and controls
176 lines (161 loc) · 4.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
package lsp
import (
"fmt"
"os"
"path/filepath"
"regexp"
"strings"
)
// DSLSectionDoc holds abbreviated documentation for one DSL section, used for hover.
type DSLSectionDoc struct {
ID string
Title string
Description string
Example string
}
// topLevelKeyToSectionID maps top-level YAML keys to DSL section IDs in dsl-reference.md.
var topLevelKeyToSectionID = map[string]string{
"name": "application",
"version": "application",
"description": "application",
"requires": "application",
"modules": "modules",
"workflows": "workflows",
"pipelines": "pipelines",
"triggers": "triggers",
"imports": "imports",
"configProviders": "config-providers",
"platform": "platform",
"infrastructure": "platform",
"sidecars": "platform",
}
// sectionKindToSectionID maps SectionKind values to DSL section IDs.
var sectionKindToSectionID = map[SectionKind]string{
SectionModules: "modules",
SectionWorkflow: "workflows",
SectionPipeline: "pipelines",
SectionTriggers: "triggers",
SectionImports: "imports",
SectionRequires: "application",
}
// loadDSLSections locates docs/dsl-reference.md by searching upward from cwd,
// parses it, and returns a map of section ID → DSLSectionDoc.
// Returns nil (no error) if the file cannot be found — hover will skip DSL docs.
func loadDSLSections() map[string]*DSLSectionDoc {
data, err := findDSLReferenceFile()
if err != nil {
return nil
}
return parseDSLSections(string(data))
}
// findDSLReferenceFile searches for docs/dsl-reference.md upward from the cwd.
func findDSLReferenceFile() ([]byte, error) {
cwd, err := os.Getwd()
if err != nil {
return nil, fmt.Errorf("getwd: %w", err)
}
for dir := cwd; ; dir = filepath.Dir(dir) {
p := filepath.Join(dir, "docs", "dsl-reference.md")
if data, err2 := os.ReadFile(p); err2 == nil {
return data, nil
}
parent := filepath.Dir(dir)
if parent == dir {
break
}
}
return nil, fmt.Errorf("docs/dsl-reference.md not found")
}
var reDSLSectionComment = regexp.MustCompile(`<!--\s*section:\s*(\S+)\s*-->`)
// parseDSLSections parses the dsl-reference.md content and returns a map of
// section ID → DSLSectionDoc.
func parseDSLSections(md string) map[string]*DSLSectionDoc {
lines := strings.Split(md, "\n")
// Collect section boundaries.
type boundary struct {
id string
start int
}
var boundaries []boundary
for i, line := range lines {
if m := reDSLSectionComment.FindStringSubmatch(line); m != nil {
boundaries = append(boundaries, boundary{id: m[1], start: i})
}
}
out := make(map[string]*DSLSectionDoc, len(boundaries))
for bi, b := range boundaries {
end := len(lines)
if bi+1 < len(boundaries) {
end = boundaries[bi+1].start
}
doc := parseDSLSectionDoc(b.id, lines[b.start:end])
out[b.id] = doc
}
return out
}
// parseDSLSectionDoc extracts the title, first-paragraph description, and example
// from a section's lines.
func parseDSLSectionDoc(id string, lines []string) *DSLSectionDoc {
doc := &DSLSectionDoc{ID: id}
const (
stateInit = iota
stateDesc // collecting first paragraph
stateExample // inside fenced code block under ### Example
stateOther
)
state := stateInit
var descLines []string
var exampleLines []string
inFence := false
for _, raw := range lines {
if reDSLSectionComment.MatchString(raw) {
continue
}
if strings.HasPrefix(raw, "## ") {
doc.Title = strings.TrimPrefix(raw, "## ")
state = stateDesc
continue
}
if strings.HasPrefix(raw, "### ") {
sub := strings.ToLower(strings.TrimPrefix(raw, "### "))
if strings.Contains(sub, "example") {
state = stateExample
} else {
state = stateOther
}
continue
}
if strings.HasPrefix(raw, "```") {
if state == stateExample {
if !inFence {
inFence = true
continue
}
inFence = false
continue
}
}
switch state {
case stateDesc:
if raw == "---" {
continue
}
if len(descLines) == 0 && strings.TrimSpace(raw) == "" {
continue
}
// Stop at first blank line after content.
if strings.TrimSpace(raw) == "" && len(descLines) > 0 {
state = stateOther
continue
}
descLines = append(descLines, raw)
case stateExample:
if inFence {
exampleLines = append(exampleLines, raw)
}
}
}
doc.Description = strings.TrimSpace(strings.Join(descLines, " "))
doc.Example = strings.Join(exampleLines, "\n")
return doc
}