Skip to content

Commit c9afab8

Browse files
Copilotjeduden
andauthored
fix: handle empty archetype roots and dot-root schema detection
Agent-Logs-Url: https://github.com/jeduden/mdsmith/sessions/31dd099c-4fd7-425e-b885-0ac1eec24901 Co-authored-by: jeduden <1117699+jeduden@users.noreply.github.com>
1 parent 6802276 commit c9afab8

5 files changed

Lines changed: 32 additions & 6 deletions

File tree

internal/archetypes/archetypes.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,14 @@ type Resolver struct {
4040
// configured. It is applied when Resolver.Roots is empty.
4141
const DefaultRoot = "archetypes"
4242

43-
// ValidateRoot returns an error when root is an absolute path or a
43+
// ValidateRoot returns an error when root is empty, absolute, or a
4444
// parent-traversal path. Archetype roots are expected to be
4545
// relative to the project root so they cannot reach outside it.
4646
func ValidateRoot(root string) error {
47+
if strings.TrimSpace(root) == "" {
48+
return fmt.Errorf(
49+
"archetype root %q must not be empty", root)
50+
}
4751
if filepath.IsAbs(root) {
4852
return fmt.Errorf(
4953
"archetype root %q must be a relative path", root)

internal/archetypes/archetypes_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,11 @@ func TestValidateRoot(t *testing.T) {
252252
root string
253253
wantErr bool
254254
}{
255+
{"", true},
256+
{" ", true},
255257
{"archetypes", false},
256258
{"./archetypes", false},
259+
{".", false},
257260
{"internal/archetypes", false},
258261
{"/abs", true},
259262
{"..", true},

internal/rules/requiredstructure/rule.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -252,10 +252,16 @@ func (r *Rule) isSchemaOrArchetypeFile(f *lint.File) bool {
252252
}
253253
}
254254
for _, root := range roots {
255-
cleanRoot := filepath.ToSlash(filepath.Clean(root)) + "/"
255+
cleanRoot := filepath.ToSlash(filepath.Clean(root))
256+
if cleanRoot == "." {
257+
cleanRoot = ""
258+
} else {
259+
cleanRoot += "/"
260+
}
256261
for _, c := range candidates {
257-
if strings.HasPrefix(c, cleanRoot) &&
258-
strings.HasSuffix(c, ".md") {
262+
if strings.HasSuffix(c, ".md") &&
263+
(cleanRoot == "" ||
264+
strings.HasPrefix(c, cleanRoot)) {
259265
return true
260266
}
261267
}

internal/rules/requiredstructure/rule_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,17 @@ func TestCheck_ArchetypeRootFileSuppressesRequireWarning(t *testing.T) {
414414
}
415415
}
416416

417+
func TestCheck_DotArchetypeRootFileSuppressesRequireWarning(t *testing.T) {
418+
root := t.TempDir()
419+
f := newFileInRoot(t, root, "story.md",
420+
"<?require\nfilename: \"story-*.md\"\n?>\n# ?\n")
421+
r := &Rule{ArchetypeRoots: []string{"."}}
422+
diags := r.Check(f)
423+
for _, d := range diags {
424+
assert.NotContains(t, d.Message, "<?require?>")
425+
}
426+
}
427+
417428
func TestCheck_ArchetypeEarlierRootShadowsLater(t *testing.T) {
418429
root := t.TempDir()
419430
writeArchetype(t, filepath.Join(root, "custom"), "story",

plan/52_archetype-template-library.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,10 @@ against those roots.
4242
config file).
4343
5. Add `mdsmith archetypes list` to print each
4444
discovered archetype as `<name>\t<path>`, one per
45-
line, sorted by name. Exit non-zero if no roots
46-
are configured.
45+
line, sorted by name. When `archetypes.roots` is
46+
omitted, search the default `./archetypes`
47+
directory. Exit non-zero if no archetypes are
48+
discovered.
4749
6. Add `mdsmith archetypes show <name>` to print the
4850
archetype source (including front matter) to
4951
stdout. Exit non-zero with a clear error when the

0 commit comments

Comments
 (0)