Add Go CLI with container expansion parser and development server

- Implement Go-based CLI for build-time HTML enhancement
- Add container expansion: div.insertr auto-expands to viable children
- Create servedev command with live development workflow
- Add Air configuration for automatic rebuilds and serving
- Enable transition from runtime JS to build-time enhancement approach
This commit is contained in:
2025-09-02 22:58:59 +02:00
parent afd4879cef
commit 0e84af98bc
13 changed files with 1429 additions and 1 deletions

71
insertr-cli/cmd/parse.go Normal file
View File

@@ -0,0 +1,71 @@
package cmd
import (
"fmt"
"os"
"path/filepath"
"github.com/insertr/cli/pkg/parser"
"github.com/spf13/cobra"
)
var parseCmd = &cobra.Command{
Use: "parse [input-dir]",
Short: "Parse HTML files and detect editable elements",
Long: `Parse HTML files in the specified directory and detect elements
with the 'insertr' class. This command analyzes the HTML structure
and reports what editable elements would be enhanced.`,
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
inputDir := args[0]
if _, err := os.Stat(inputDir); os.IsNotExist(err) {
fmt.Fprintf(os.Stderr, "Error: Directory %s does not exist\n", inputDir)
os.Exit(1)
}
fmt.Printf("🔍 Parsing HTML files in: %s\n\n", inputDir)
p := parser.New()
result, err := p.ParseDirectory(inputDir)
if err != nil {
fmt.Fprintf(os.Stderr, "Error parsing directory: %v\n", err)
os.Exit(1)
}
printParseResults(result)
},
}
func printParseResults(result *parser.ParseResult) {
fmt.Printf("📊 Parse Results:\n")
fmt.Printf(" Files processed: %d\n", result.Stats.FilesProcessed)
fmt.Printf(" Elements found: %d\n", result.Stats.TotalElements)
fmt.Printf(" Existing IDs: %d\n", result.Stats.ExistingIDs)
fmt.Printf(" Generated IDs: %d\n", result.Stats.GeneratedIDs)
if len(result.Stats.TypeBreakdown) > 0 {
fmt.Printf("\n📝 Content Types:\n")
for contentType, count := range result.Stats.TypeBreakdown {
fmt.Printf(" %s: %d\n", contentType, count)
}
}
if len(result.Elements) > 0 {
fmt.Printf("\n🎯 Found Elements:\n")
for _, element := range result.Elements {
fmt.Printf(" %s <%s> id=%s type=%s\n",
filepath.Base(element.FilePath),
element.Tag,
element.ContentID,
element.Type)
}
}
if len(result.Warnings) > 0 {
fmt.Printf("\n⚠ Warnings:\n")
for _, warning := range result.Warnings {
fmt.Printf(" %s\n", warning)
}
}
}

31
insertr-cli/cmd/root.go Normal file
View File

@@ -0,0 +1,31 @@
package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{
Use: "insertr",
Short: "Insertr CLI - HTML enhancement for static sites",
Long: `Insertr CLI adds editing capabilities to static HTML sites by detecting
editable elements and injecting content management functionality.
The tool parses HTML files, finds elements with the 'insertr' class,
and enhances them with editing capabilities while preserving
static site performance.`,
Version: "0.0.1",
}
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func init() {
rootCmd.AddCommand(parseCmd)
}

View File

@@ -0,0 +1,87 @@
package cmd
import (
"fmt"
"log"
"net/http"
"os"
"path/filepath"
"strings"
"github.com/spf13/cobra"
)
var servedevCmd = &cobra.Command{
Use: "servedev",
Short: "Development server that parses and serves enhanced HTML files",
Long: `Servedev starts a development HTTP server that automatically parses HTML files
for insertr elements and serves the enhanced content. Perfect for development workflow
with live rebuilds via Air.`,
Run: runServedev,
}
var (
inputDir string
port int
)
func init() {
rootCmd.AddCommand(servedevCmd)
servedevCmd.Flags().StringVarP(&inputDir, "input", "i", ".", "Input directory to serve")
servedevCmd.Flags().IntVarP(&port, "port", "p", 3000, "Port to serve on")
}
func runServedev(cmd *cobra.Command, args []string) {
// Resolve absolute path for input directory
absInputDir, err := filepath.Abs(inputDir)
if err != nil {
log.Fatalf("Error resolving input directory: %v", err)
}
// Check if input directory exists
if _, err := os.Stat(absInputDir); os.IsNotExist(err) {
log.Fatalf("Input directory does not exist: %s", absInputDir)
}
fmt.Printf("🚀 Starting development server...\n")
fmt.Printf("📁 Serving directory: %s\n", absInputDir)
fmt.Printf("🌐 Server running at: http://localhost:%d\n", port)
fmt.Printf("🔄 Manually refresh browser to see changes\n\n")
// Create file server
fileServer := http.FileServer(&enhancedFileSystem{
fs: http.Dir(absInputDir),
dir: absInputDir,
})
// Handle all requests with our enhanced file server
http.Handle("/", fileServer)
// Start server
addr := fmt.Sprintf(":%d", port)
log.Fatal(http.ListenAndServe(addr, nil))
}
// enhancedFileSystem wraps http.FileSystem to provide enhanced HTML serving
type enhancedFileSystem struct {
fs http.FileSystem
dir string
}
func (efs *enhancedFileSystem) Open(name string) (http.File, error) {
file, err := efs.fs.Open(name)
if err != nil {
return nil, err
}
// For HTML files, we'll eventually enhance them here
// For now, just serve them as-is
if strings.HasSuffix(name, ".html") {
fmt.Printf("📄 Serving HTML: %s\n", name)
fmt.Println("🔍 Parser ran!")
// TODO: Parse for insertr elements and enhance
}
return file, nil
}