Build creates the shadow directory with all necessary files. If dingoFiles is empty, it discovers all .dingo files in the workspace. Uses incremental builds - only transpiles files that changed since last build.
(dingoFiles []string)
| 86 | // If dingoFiles is empty, it discovers all .dingo files in the workspace. |
| 87 | // Uses incremental builds - only transpiles files that changed since last build. |
| 88 | func (b *Builder) Build(dingoFiles []string) (*BuildResult, error) { |
| 89 | result := &BuildResult{ |
| 90 | ShadowDir: b.ShadowDir, |
| 91 | } |
| 92 | |
| 93 | // 1. Ensure shadow directory exists |
| 94 | if err := os.MkdirAll(b.ShadowDir, 0755); err != nil { |
| 95 | return nil, fmt.Errorf("failed to create shadow directory: %w", err) |
| 96 | } |
| 97 | |
| 98 | // 2. Copy go.mod and go.sum |
| 99 | if err := b.copyModFiles(); err != nil { |
| 100 | return nil, fmt.Errorf("failed to copy module files: %w", err) |
| 101 | } |
| 102 | result.CopiedFiles = append(result.CopiedFiles, "go.mod", "go.sum") |
| 103 | |
| 104 | // 3. Discover ALL .dingo files in the workspace |
| 105 | // We must transpile all .dingo files for the module to build correctly, |
| 106 | // since pure Go files are skipped if they have a .dingo counterpart. |
| 107 | // The dingoFiles parameter only affects which package is built at the end, |
| 108 | // not which files are transpiled. |
| 109 | targetDingoFiles, err := b.findAllDingoFiles() |
| 110 | if err != nil { |
| 111 | return nil, fmt.Errorf("failed to find .dingo files: %w", err) |
| 112 | } |
| 113 | _ = dingoFiles // dingoFiles is used by caller for go build path, not for transpilation |
| 114 | |
| 115 | // 4. Filter to only files that need transpilation (incremental build) |
| 116 | var filesToTranspile []string |
| 117 | for _, dingoFile := range targetDingoFiles { |
| 118 | if b.needsTranspile(dingoFile) { |
| 119 | filesToTranspile = append(filesToTranspile, dingoFile) |
| 120 | } else { |
| 121 | // Track as generated even if skipped (for pure Go copy logic) |
| 122 | relPath, _ := filepath.Rel(b.WorkspaceRoot, dingoFile) |
| 123 | goRelPath := strings.TrimSuffix(relPath, ".dingo") + ".go" |
| 124 | b.generatedFiles[goRelPath] = true |
| 125 | // Add to result (existing file) |
| 126 | goFile := filepath.Join(b.ShadowDir, goRelPath) |
| 127 | result.GeneratedFiles = append(result.GeneratedFiles, goFile) |
| 128 | result.SkippedCount++ |
| 129 | } |
| 130 | } |
| 131 | |
| 132 | // 4.5. Pre-load types for all files (performance optimization) |
| 133 | // Load types for ALL imports ONCE before transpilation. |
| 134 | // This is fast (~150ms total) and enables accurate cross-file type resolution. |
| 135 | if len(filesToTranspile) > 0 { |
| 136 | if b.Verbose { |
| 137 | fmt.Println("Pre-loading types for all files...") |
| 138 | } |
| 139 | |
| 140 | startTime := time.Now() |
| 141 | allImports := b.collectAllImports(filesToTranspile) |
| 142 | |
| 143 | b.TypeCache = typeloader.NewBuildCache(typeloader.LoaderConfig{ |
| 144 | WorkingDir: b.WorkspaceRoot, |
| 145 | FailFast: false, // Don't fail on first error - continue with partial type info |
no test coverage detected