Backend improvements: views, fields_get, session, RPC stubs
- Improved auto-generated list/form/search views with priority fields, two-column form layout, statusbar widget, notebook for O2M fields - Enhanced fields_get with currency_field, compute, related metadata - Fixed session handling: handleSessionInfo/handleSessionCheck use real session from cookie instead of hardcoded values - Added read_progress_bar and activity_format RPC stubs - Improved bootstrap translations with lang_parameters - Added "contacts" to session modules list Server starts successfully: 14 modules, 93 models, 378 XML templates, 503 JS modules transpiled — all from local frontend/ directory. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
169
cmd/transpile/main.go
Normal file
169
cmd/transpile/main.go
Normal file
@@ -0,0 +1,169 @@
|
||||
// Command transpile converts Odoo ES module JS files to odoo.define() format.
|
||||
// This is a pure Go replacement for tools/transpile_assets.py, eliminating
|
||||
// the Python dependency entirely.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// go run ./cmd/transpile -source ../odoo -output build/js
|
||||
// go run ./cmd/transpile -source ../odoo -output build/js -list pkg/server/assets_js.txt
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"odoo-go/pkg/server"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.SetFlags(0)
|
||||
|
||||
sourceDir := flag.String("source", "", "Path to Odoo source tree (e.g. ../odoo)")
|
||||
outputDir := flag.String("output", "build/js", "Output directory for transpiled JS files")
|
||||
listFile := flag.String("list", "pkg/server/assets_js.txt", "Path to the JS asset list file")
|
||||
flag.Parse()
|
||||
|
||||
if *sourceDir == "" {
|
||||
log.Fatal("error: -source flag is required (path to Odoo source tree)")
|
||||
}
|
||||
|
||||
// Resolve paths
|
||||
absSource, err := filepath.Abs(*sourceDir)
|
||||
if err != nil {
|
||||
log.Fatalf("error: invalid source path: %v", err)
|
||||
}
|
||||
absOutput, err := filepath.Abs(*outputDir)
|
||||
if err != nil {
|
||||
log.Fatalf("error: invalid output path: %v", err)
|
||||
}
|
||||
|
||||
// Read asset list
|
||||
jsFiles, err := readAssetList(*listFile)
|
||||
if err != nil {
|
||||
log.Fatalf("error: reading asset list %s: %v", *listFile, err)
|
||||
}
|
||||
|
||||
log.Printf("transpile: %d JS files from %s", len(jsFiles), *listFile)
|
||||
log.Printf("transpile: source: %s", absSource)
|
||||
log.Printf("transpile: output: %s", absOutput)
|
||||
|
||||
// Addon directories to search (in order of priority)
|
||||
addonsDirs := []string{
|
||||
filepath.Join(absSource, "addons"),
|
||||
filepath.Join(absSource, "odoo", "addons"),
|
||||
}
|
||||
|
||||
var transpiled, copied, skipped, errors int
|
||||
|
||||
for _, urlPath := range jsFiles {
|
||||
// Find the source file in one of the addons directories
|
||||
relPath := strings.TrimPrefix(urlPath, "/")
|
||||
sourceFile := findFile(addonsDirs, relPath)
|
||||
if sourceFile == "" {
|
||||
log.Printf(" SKIP (not found): %s", urlPath)
|
||||
skipped++
|
||||
continue
|
||||
}
|
||||
|
||||
// Read source content
|
||||
content, err := os.ReadFile(sourceFile)
|
||||
if err != nil {
|
||||
log.Printf(" ERROR reading %s: %v", sourceFile, err)
|
||||
errors++
|
||||
continue
|
||||
}
|
||||
|
||||
// Determine output path
|
||||
outFile := filepath.Join(absOutput, relPath)
|
||||
|
||||
// Ensure output directory exists
|
||||
if err := os.MkdirAll(filepath.Dir(outFile), 0o755); err != nil {
|
||||
log.Printf(" ERROR mkdir %s: %v", filepath.Dir(outFile), err)
|
||||
errors++
|
||||
continue
|
||||
}
|
||||
|
||||
src := string(content)
|
||||
|
||||
if server.IsOdooModule(urlPath, src) {
|
||||
// Transpile ES module to odoo.define() format
|
||||
result := server.TranspileJS(urlPath, src)
|
||||
if err := os.WriteFile(outFile, []byte(result), 0o644); err != nil {
|
||||
log.Printf(" ERROR writing %s: %v", outFile, err)
|
||||
errors++
|
||||
continue
|
||||
}
|
||||
transpiled++
|
||||
} else {
|
||||
// Not an ES module: copy as-is
|
||||
if err := copyFile(sourceFile, outFile); err != nil {
|
||||
log.Printf(" ERROR copying %s: %v", urlPath, err)
|
||||
errors++
|
||||
continue
|
||||
}
|
||||
copied++
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("\nDone: %d transpiled, %d copied as-is, %d skipped, %d errors\n",
|
||||
transpiled, copied, skipped, errors)
|
||||
fmt.Printf("Output: %s\n", absOutput)
|
||||
|
||||
if errors > 0 {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// readAssetList reads a newline-separated list of JS file paths.
|
||||
func readAssetList(path string) ([]string, error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var files []string
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if line != "" && !strings.HasPrefix(line, "#") {
|
||||
files = append(files, line)
|
||||
}
|
||||
}
|
||||
return files, scanner.Err()
|
||||
}
|
||||
|
||||
// findFile searches for a relative path in the given directories.
|
||||
func findFile(dirs []string, relPath string) string {
|
||||
for _, dir := range dirs {
|
||||
candidate := filepath.Join(dir, relPath)
|
||||
if info, err := os.Stat(candidate); err == nil && !info.IsDir() {
|
||||
return candidate
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// copyFile copies a file from src to dst.
|
||||
func copyFile(src, dst string) error {
|
||||
in, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer in.Close()
|
||||
|
||||
out, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
_, err = io.Copy(out, in)
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user