Skip to content

Commit 24656d9

Browse files
authored
Merge PR #150: Plan 85: extract shared type-conversion helpers (Phase 1)
2 parents 6b68491 + 3778fb9 commit 24656d9

16 files changed

Lines changed: 245 additions & 343 deletions

File tree

PLAN.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ footer: |
4242
| 82 || [YAML billion-laughs mitigation](plan/82_yaml-billion-laughs.md) |
4343
| 83 | 🔳 | [Security hardening batch](plan/83_security-hardening-batch.md) |
4444
| 84 | 🔲 | [Symlink default-deny for file discovery](plan/84_symlink-default-deny.md) |
45-
| 85 | 🔲 | [Increase test coverage to 95% by extracting shared rule helpers](plan/85_coverage-to-95-percent.md) |
45+
| 85 | 🔳 | [Increase test coverage to 95% by extracting shared rule helpers](plan/85_coverage-to-95-percent.md) |
4646
| 86 | 🔲 | [Markdown flavor validation](plan/86_markdown-flavor-validation.md) |
4747
| 87 | 🔲 | [Flavor validation for GitHub Alerts](plan/87_markdown-flavor-github-alerts.md) |
4848
| 88 || [TOC directive migration aid](plan/88_toc-directive-migration.md) |

internal/rules/concisenessscoring/rule.go

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/jeduden/mdsmith/internal/lint"
1010
"github.com/jeduden/mdsmith/internal/mdtext"
1111
"github.com/jeduden/mdsmith/internal/rule"
12+
"github.com/jeduden/mdsmith/internal/rules/settings"
1213
"github.com/yuin/goldmark/ast"
1314
)
1415

@@ -168,8 +169,8 @@ func isTable(para *ast.Paragraph, f *lint.File) bool {
168169
}
169170

170171
// ApplySettings implements rule.Configurable.
171-
func (r *Rule) ApplySettings(settings map[string]any) error {
172-
for k, v := range settings {
172+
func (r *Rule) ApplySettings(s map[string]any) error {
173+
for k, v := range s {
173174
switch k {
174175
case "min-score":
175176
if err := r.setMinScore(v); err != nil {
@@ -187,7 +188,7 @@ func (r *Rule) ApplySettings(settings map[string]any) error {
187188
}
188189

189190
func (r *Rule) setMinScore(v any) error {
190-
n, ok := toFloat(v)
191+
n, ok := settings.ToFloat(v)
191192
if !ok {
192193
return fmt.Errorf(
193194
"conciseness-scoring: min-score must be a number, got %T",
@@ -205,7 +206,7 @@ func (r *Rule) setMinScore(v any) error {
205206
}
206207

207208
func (r *Rule) setMinWords(v any) error {
208-
n, ok := toInt(v)
209+
n, ok := settings.ToInt(v)
209210
if !ok {
210211
return fmt.Errorf(
211212
"conciseness-scoring: min-words must be an integer, got %T",
@@ -230,29 +231,5 @@ func (r *Rule) DefaultSettings() map[string]any {
230231
}
231232
}
232233

233-
func toFloat(v any) (float64, bool) {
234-
switch n := v.(type) {
235-
case float64:
236-
return n, true
237-
case int:
238-
return float64(n), true
239-
case int64:
240-
return float64(n), true
241-
}
242-
return 0, false
243-
}
244-
245-
func toInt(v any) (int, bool) {
246-
switch n := v.(type) {
247-
case int:
248-
return n, true
249-
case float64:
250-
return int(n), true
251-
case int64:
252-
return int(n), true
253-
}
254-
return 0, false
255-
}
256-
257234
var _ rule.Configurable = (*Rule)(nil)
258235
var _ rule.Defaultable = (*Rule)(nil)

internal/rules/firstlineheading/rule.go

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55

66
"github.com/jeduden/mdsmith/internal/lint"
77
"github.com/jeduden/mdsmith/internal/rule"
8+
"github.com/jeduden/mdsmith/internal/rules/settings"
89
"github.com/yuin/goldmark/ast"
910
)
1011

@@ -74,11 +75,11 @@ func (r *Rule) diag(f *lint.File, msg string) []lint.Diagnostic {
7475
}
7576

7677
// ApplySettings implements rule.Configurable.
77-
func (r *Rule) ApplySettings(settings map[string]any) error {
78-
for k, v := range settings {
78+
func (r *Rule) ApplySettings(s map[string]any) error {
79+
for k, v := range s {
7980
switch k {
8081
case "level":
81-
n, ok := toInt(v)
82+
n, ok := settings.ToInt(v)
8283
if !ok {
8384
return fmt.Errorf("first-line-heading: level must be an integer, got %T", v)
8485
}
@@ -100,19 +101,6 @@ func (r *Rule) DefaultSettings() map[string]any {
100101
}
101102
}
102103

103-
// toInt converts a value to int.
104-
func toInt(v any) (int, bool) {
105-
switch n := v.(type) {
106-
case int:
107-
return n, true
108-
case float64:
109-
return int(n), true
110-
case int64:
111-
return int(n), true
112-
}
113-
return 0, false
114-
}
115-
116104
var _ rule.Configurable = (*Rule)(nil)
117105

118106
func headingLine(heading *ast.Heading, f *lint.File) int {

internal/rules/linelength/rule.go

Lines changed: 6 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
"github.com/jeduden/mdsmith/internal/lint"
1010
"github.com/jeduden/mdsmith/internal/rule"
11+
"github.com/jeduden/mdsmith/internal/rules/settings"
1112
"github.com/yuin/goldmark/ast"
1213
)
1314

@@ -55,8 +56,8 @@ func (r *Rule) isExcluded(category string) bool {
5556
}
5657

5758
// ApplySettings implements rule.Configurable.
58-
func (r *Rule) ApplySettings(settings map[string]any) error {
59-
for k, v := range settings {
59+
func (r *Rule) ApplySettings(s map[string]any) error {
60+
for k, v := range s {
6061
if err := r.applySetting(k, v); err != nil {
6162
return err
6263
}
@@ -84,7 +85,7 @@ func (r *Rule) applySetting(k string, v any) error {
8485
}
8586

8687
func (r *Rule) applyMax(v any) error {
87-
n, ok := toInt(v)
88+
n, ok := settings.ToInt(v)
8889
if !ok {
8990
return fmt.Errorf("line-length: max must be an integer, got %T", v)
9091
}
@@ -93,7 +94,7 @@ func (r *Rule) applyMax(v any) error {
9394
}
9495

9596
func (r *Rule) applyPositiveIntPtr(v any, name string, target **int) error {
96-
n, ok := toInt(v)
97+
n, ok := settings.ToInt(v)
9798
if !ok {
9899
return fmt.Errorf("line-length: %s must be an integer, got %T", name, v)
99100
}
@@ -114,7 +115,7 @@ func (r *Rule) applyStern(v any) error {
114115
}
115116

116117
func (r *Rule) applyExclude(v any) error {
117-
list, ok := toStringSlice(v)
118+
list, ok := settings.ToStringSlice(v)
118119
if !ok {
119120
return fmt.Errorf("line-length: exclude must be a list of strings, got %T", v)
120121
}
@@ -315,40 +316,6 @@ func headingLineNum(h *ast.Heading, f *lint.File) int {
315316
return 0
316317
}
317318

318-
// toInt converts a value to int. Supports int and float64 (YAML decodes
319-
// numbers as int or float64 depending on context).
320-
func toInt(v any) (int, bool) {
321-
switch n := v.(type) {
322-
case int:
323-
return n, true
324-
case float64:
325-
return int(n), true
326-
case int64:
327-
return int(n), true
328-
}
329-
return 0, false
330-
}
331-
332-
// toStringSlice converts a value to []string. YAML decodes sequences as
333-
// []any with string elements.
334-
func toStringSlice(v any) ([]string, bool) {
335-
switch s := v.(type) {
336-
case []string:
337-
return s, true
338-
case []any:
339-
result := make([]string, 0, len(s))
340-
for _, item := range s {
341-
str, ok := item.(string)
342-
if !ok {
343-
return nil, false
344-
}
345-
result = append(result, str)
346-
}
347-
return result, true
348-
}
349-
return nil, false
350-
}
351-
352319
func isValidExclude(s string) bool {
353320
return s == "code-blocks" || s == "tables" || s == "urls"
354321
}

internal/rules/maxfilelength/rule.go

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55

66
"github.com/jeduden/mdsmith/internal/lint"
77
"github.com/jeduden/mdsmith/internal/rule"
8+
"github.com/jeduden/mdsmith/internal/rules/settings"
89
)
910

1011
func init() {
@@ -52,11 +53,11 @@ func (r *Rule) Check(f *lint.File) []lint.Diagnostic {
5253
}
5354

5455
// ApplySettings implements rule.Configurable.
55-
func (r *Rule) ApplySettings(settings map[string]any) error {
56-
for k, v := range settings {
56+
func (r *Rule) ApplySettings(s map[string]any) error {
57+
for k, v := range s {
5758
switch k {
5859
case "max":
59-
n, ok := toInt(v)
60+
n, ok := settings.ToInt(v)
6061
if !ok {
6162
return fmt.Errorf(
6263
"max-file-length: max must be an integer, got %T", v,
@@ -77,17 +78,4 @@ func (r *Rule) DefaultSettings() map[string]any {
7778
return map[string]any{"max": 300}
7879
}
7980

80-
// toInt converts a value to int.
81-
func toInt(v any) (int, bool) {
82-
switch n := v.(type) {
83-
case int:
84-
return n, true
85-
case float64:
86-
return int(n), true
87-
case int64:
88-
return int(n), true
89-
}
90-
return 0, false
91-
}
92-
9381
var _ rule.Configurable = (*Rule)(nil)

internal/rules/nomultipleblanks/rule.go

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77

88
"github.com/jeduden/mdsmith/internal/lint"
99
"github.com/jeduden/mdsmith/internal/rule"
10+
"github.com/jeduden/mdsmith/internal/rules/settings"
1011
)
1112

1213
func init() {
@@ -100,11 +101,11 @@ func (r *Rule) Fix(f *lint.File) []byte {
100101
}
101102

102103
// ApplySettings implements rule.Configurable.
103-
func (r *Rule) ApplySettings(settings map[string]any) error {
104-
for k, v := range settings {
104+
func (r *Rule) ApplySettings(s map[string]any) error {
105+
for k, v := range s {
105106
switch k {
106107
case "max":
107-
n, ok := toInt(v)
108+
n, ok := settings.ToInt(v)
108109
if !ok {
109110
return fmt.Errorf("no-multiple-blanks: max must be an integer, got %T", v)
110111
}
@@ -123,17 +124,4 @@ func (r *Rule) DefaultSettings() map[string]any {
123124
}
124125
}
125126

126-
// toInt converts a value to int.
127-
func toInt(v any) (int, bool) {
128-
switch n := v.(type) {
129-
case int:
130-
return n, true
131-
case float64:
132-
return int(n), true
133-
case int64:
134-
return int(n), true
135-
}
136-
return 0, false
137-
}
138-
139127
var _ rule.Configurable = (*Rule)(nil)

internal/rules/paragraphreadability/rule.go

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/jeduden/mdsmith/internal/lint"
99
"github.com/jeduden/mdsmith/internal/mdtext"
1010
"github.com/jeduden/mdsmith/internal/rule"
11+
"github.com/jeduden/mdsmith/internal/rules/settings"
1112
"github.com/yuin/goldmark/ast"
1213
)
1314

@@ -111,11 +112,11 @@ func paragraphLine(para *ast.Paragraph, f *lint.File) int {
111112
}
112113

113114
// ApplySettings implements rule.Configurable.
114-
func (r *Rule) ApplySettings(settings map[string]any) error {
115-
for k, v := range settings {
115+
func (r *Rule) ApplySettings(s map[string]any) error {
116+
for k, v := range s {
116117
switch k {
117118
case "max-index":
118-
n, ok := toFloat(v)
119+
n, ok := settings.ToFloat(v)
119120
if !ok {
120121
return fmt.Errorf(
121122
"paragraph-readability: max-index must be a number, got %T",
@@ -124,7 +125,7 @@ func (r *Rule) ApplySettings(settings map[string]any) error {
124125
}
125126
r.MaxIndex = n
126127
case "min-words":
127-
n, ok := toInt(v)
128+
n, ok := settings.ToInt(v)
128129
if !ok {
129130
return fmt.Errorf(
130131
"paragraph-readability: min-words must be an integer, got %T",
@@ -149,30 +150,6 @@ func (r *Rule) DefaultSettings() map[string]any {
149150
}
150151
}
151152

152-
func toFloat(v any) (float64, bool) {
153-
switch n := v.(type) {
154-
case float64:
155-
return n, true
156-
case int:
157-
return float64(n), true
158-
case int64:
159-
return float64(n), true
160-
}
161-
return 0, false
162-
}
163-
164-
func toInt(v any) (int, bool) {
165-
switch n := v.(type) {
166-
case int:
167-
return n, true
168-
case float64:
169-
return int(n), true
170-
case int64:
171-
return int(n), true
172-
}
173-
return 0, false
174-
}
175-
176153
// isTable returns true if the paragraph's first line starts with a pipe,
177154
// indicating it is a markdown table (goldmark without the table extension
178155
// parses tables as paragraphs).

0 commit comments

Comments
 (0)