github.com/JarrahG/buffalocli@v0.0.0-20230801092127-b85bfd5d395a/internal/genny/fix/npm.go (about)

     1  package fix
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"html/template"
     8  	"os/exec"
     9  
    10  	"github.com/JarrahG/buffalocli/internal/genny/assets/webpack"
    11  	"github.com/gobuffalo/genny/v2"
    12  	"github.com/gobuffalo/meta"
    13  )
    14  
    15  // default scripts for package.json
    16  var defaultScripts = map[string]string{
    17  	"dev":   "webpack --watch",
    18  	"build": "webpack -p --progress",
    19  }
    20  
    21  // AddPackageJSONScripts rewrites the package.json file
    22  // to add dev and build scripts if there are missing.
    23  func AddPackageJSONScripts(opts *Options) genny.RunFn {
    24  	return func(r *genny.Runner) error {
    25  		if !opts.App.WithWebpack {
    26  			return nil
    27  		}
    28  
    29  		fmt.Println("~~~ Patching package.json to add dev and build scripts ~~~")
    30  		f, err := r.FindFile("package.json")
    31  		if err != nil {
    32  			return err
    33  		}
    34  
    35  		needRewrite := false
    36  		packageJSON := map[string]interface{}{}
    37  		if err := json.NewDecoder(f).Decode(&packageJSON); err != nil {
    38  			return fmt.Errorf("could not rewrite package.json: %s", err.Error())
    39  		}
    40  
    41  		if _, ok := packageJSON["scripts"]; !ok {
    42  			needRewrite = true
    43  			packageJSON["scripts"] = defaultScripts
    44  		} else {
    45  			scripts, ok := packageJSON["scripts"].(map[string]interface{})
    46  			if !ok {
    47  				return fmt.Errorf("could not rewrite package.json: invalid scripts section")
    48  			}
    49  
    50  			// Add missing scripts
    51  			for k, v := range defaultScripts {
    52  				if _, ok := scripts[k]; !ok {
    53  					scripts[k] = v
    54  					needRewrite = true
    55  				}
    56  			}
    57  			packageJSON["scripts"] = scripts
    58  		}
    59  
    60  		if !needRewrite {
    61  			fmt.Println("~~~ package.json doesn't need to be patched, skipping. ~~~")
    62  			return nil
    63  		}
    64  
    65  		enc := json.NewEncoder(f)
    66  		enc.SetIndent("", "  ")
    67  		if err := enc.Encode(packageJSON); err != nil {
    68  			return fmt.Errorf("could not rewrite package.json: %w", err)
    69  		}
    70  
    71  		return r.File(f)
    72  	}
    73  }
    74  
    75  // PackageJSONCheck will compare the current default Buffalo
    76  // package.json against the applications package.json. If they are
    77  // different you have the option to overwrite the existing package.json
    78  // file with the new one.
    79  func PackageJSONCheck(opts *Options) genny.RunFn {
    80  	return func(r *genny.Runner) error {
    81  		if !opts.App.WithWebpack {
    82  			return nil
    83  		}
    84  
    85  		fmt.Println("~~~ Checking package.json ~~~")
    86  		bb, err := defaultPackageJson(opts.App)
    87  		if err != nil {
    88  			return err
    89  		}
    90  
    91  		f, err := r.FindFile("package.json")
    92  		if err != nil {
    93  			return err
    94  		}
    95  
    96  		if f.String() == bb.String() {
    97  			return nil
    98  		}
    99  
   100  		if !opts.YesToAll && !ask("Your package.json file is different from the latest Buffalo template.\nWould you like to REPLACE yours with the latest template?") {
   101  			fmt.Println("\tskipping package.json")
   102  			return nil
   103  		}
   104  
   105  		if _, err := f.Write(bb.Bytes()); err != nil {
   106  			return err
   107  		}
   108  
   109  		if err := r.File(f); err != nil {
   110  			return err
   111  		}
   112  
   113  		if err := r.Delete("node_modules"); err != nil {
   114  			return err
   115  		}
   116  
   117  		if opts.App.WithYarn {
   118  			return r.Exec(exec.Command("yarn", "install"))
   119  		}
   120  
   121  		return r.Exec(exec.Command("npm", "install"))
   122  	}
   123  }
   124  
   125  func defaultPackageJson(app meta.App) (*bytes.Buffer, error) {
   126  	templates, err := webpack.Templates()
   127  	if err != nil {
   128  		return nil, err
   129  	}
   130  
   131  	tmpl, err := template.New("package.json").ParseFS(templates, "package.json.tmpl")
   132  	if err != nil {
   133  		return nil, err
   134  	}
   135  
   136  	bb := &bytes.Buffer{}
   137  	err = tmpl.ExecuteTemplate(bb, "package.json.tmpl", map[string]interface{}{
   138  		"opts": &webpack.Options{
   139  			App: app,
   140  		},
   141  	})
   142  	return bb, err
   143  }