5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-03 23:21:58 +08:00
wails/v2/pkg/parser/generate.go
Lea Anthony 62374b9b53
Js package generation (#554)
* WIP

* Generation of index.js

* Add RelativeToCwd

* Add JSDoc comments

* Convert to ES6 syntax

* Fix typo

* Initial generation of typescript declarations

* Typescript improvements

* Improved @returns jsdoc

* Improved declaration files

* Simplified output

* Rename file

* Tidy up

* Revert "Simplified output"

This reverts commit 15cdf7382b.

* Now parsing actual code

* Support Array types

* Reimagined parser

* Wrap parsing in Parser

* Rewritten module generator (TS Only)

* Final touches

* Slight refactor to improve output

* Struct comments. External struct literal binding

* Reworked project parser *working*

* remove debug info

* Refactor of parser

* remove the spew

* Better Ts support

* Better project generation logic

* Support local functions in bind()

* JS Object generation. Linting.

* Support json tags in module generation

* Updated mod files

* Support vscode file generation

* Better global.d.ts

* add ts-check to templates

* Support TS declaration files

* improved 'generate' command for module
2020-11-15 09:25:38 +11:00

249 lines
5.8 KiB
Go

package parser
import (
"bytes"
"io/ioutil"
"os"
"path/filepath"
"text/template"
"github.com/pkg/errors"
"github.com/wailsapp/wails/v2/internal/fs"
)
// GenerateWailsFrontendPackage will generate a Javascript/Typescript
// package in `<project>/frontend/wails` that defines which methods
// and structs are bound to your frontend
func GenerateWailsFrontendPackage() (*ParserReport, error) {
dir, err := os.Getwd()
if err != nil {
return nil, err
}
p := NewParser()
err = p.ParseProject(dir)
if err != nil {
return nil, err
}
err = p.generateModule()
return p.parserReport(), err
}
func (p *Parser) generateModule() error {
moduleDir, err := createBackendJSDirectory()
if err != nil {
return err
}
packagesToGenerate := p.packagesToGenerate()
for _, pkg := range packagesToGenerate {
err := generatePackage(pkg, moduleDir)
if err != nil {
return err
}
}
// Copy the standard files
srcFile := fs.RelativePath("./package.json")
tgtFile := filepath.Join(moduleDir, "package.json")
err = fs.CopyFile(srcFile, tgtFile)
if err != nil {
return err
}
// Generate the globals.d.ts file
err = generateGlobalsTS(moduleDir, packagesToGenerate)
if err != nil {
return err
}
// Generate the index.js file
err = generateIndexJS(moduleDir, packagesToGenerate)
if err != nil {
return err
}
// Generate the index.d.ts file
err = generateIndexTS(moduleDir, packagesToGenerate)
if err != nil {
return err
}
return nil
}
func createBackendJSDirectory() (string, error) {
// Calculate the package directory
// Note this is *always* called from the project directory
// so using paths relative to CWD is fine
dir, err := fs.RelativeToCwd("./frontend/backend")
if err != nil {
return "", errors.Wrap(err, "Error creating backend module directory")
}
// Remove directory if it exists - REGENERATION!
err = os.RemoveAll(dir)
if err != nil {
return "", errors.Wrap(err, "Error removing module directory")
}
// Make the directory
err = fs.Mkdir(dir)
return dir, err
}
func generatePackage(pkg *Package, moduledir string) error {
// Get path to local file
typescriptTemplateFile := fs.RelativePath("./package.d.template")
// Load typescript template
typescriptTemplateData := fs.MustLoadString(typescriptTemplateFile)
typescriptTemplate, err := template.New("typescript").Parse(typescriptTemplateData)
if err != nil {
return errors.Wrap(err, "Error creating template")
}
// Execute javascript template
var buffer bytes.Buffer
err = typescriptTemplate.Execute(&buffer, pkg)
if err != nil {
return errors.Wrap(err, "Error generating code")
}
// Save typescript file
err = ioutil.WriteFile(filepath.Join(moduledir, "_"+pkg.Name+".d.ts"), buffer.Bytes(), 0755)
if err != nil {
return errors.Wrap(err, "Error writing backend package file")
}
// Get path to local file
javascriptTemplateFile := fs.RelativePath("./package.template")
// Load javascript template
javascriptTemplateData := fs.MustLoadString(javascriptTemplateFile)
javascriptTemplate, err := template.New("javascript").Parse(javascriptTemplateData)
if err != nil {
return errors.Wrap(err, "Error creating template")
}
// Reset the buffer
buffer.Reset()
err = javascriptTemplate.Execute(&buffer, pkg)
if err != nil {
return errors.Wrap(err, "Error generating code")
}
// Save javascript file
err = ioutil.WriteFile(filepath.Join(moduledir, "_"+pkg.Name+".js"), buffer.Bytes(), 0755)
if err != nil {
return errors.Wrap(err, "Error writing backend package file")
}
return nil
}
func generateIndexJS(dir string, packages []*Package) error {
// Get path to local file
templateFile := fs.RelativePath("./index.template")
// Load template
templateData := fs.MustLoadString(templateFile)
packagesTemplate, err := template.New("index").Parse(templateData)
if err != nil {
return errors.Wrap(err, "Error creating template")
}
// Execute template
var buffer bytes.Buffer
err = packagesTemplate.Execute(&buffer, packages)
if err != nil {
return errors.Wrap(err, "Error generating code")
}
// Calculate target filename
indexJS := filepath.Join(dir, "index.js")
err = ioutil.WriteFile(indexJS, buffer.Bytes(), 0755)
if err != nil {
return errors.Wrap(err, "Error writing backend package index.js file")
}
return nil
}
func generateIndexTS(dir string, packages []*Package) error {
// Get path to local file
templateFile := fs.RelativePath("./index.d.template")
// Load template
templateData := fs.MustLoadString(templateFile)
indexTSTemplate, err := template.New("index.d").Parse(templateData)
if err != nil {
return errors.Wrap(err, "Error creating template")
}
// Execute template
var buffer bytes.Buffer
err = indexTSTemplate.Execute(&buffer, packages)
if err != nil {
return errors.Wrap(err, "Error generating code")
}
// Calculate target filename
indexJS := filepath.Join(dir, "index.d.ts")
err = ioutil.WriteFile(indexJS, buffer.Bytes(), 0755)
if err != nil {
return errors.Wrap(err, "Error writing backend package index.d.ts file")
}
return nil
}
func generateGlobalsTS(dir string, packages []*Package) error {
// Get path to local file
templateFile := fs.RelativePath("./globals.d.template")
// Load template
templateData := fs.MustLoadString(templateFile)
packagesTemplate, err := template.New("globals").Parse(templateData)
if err != nil {
return errors.Wrap(err, "Error creating template")
}
// Execute template
var buffer bytes.Buffer
err = packagesTemplate.Execute(&buffer, packages)
if err != nil {
return errors.Wrap(err, "Error generating code")
}
// Calculate target filename
indexJS := filepath.Join(dir, "globals.d.ts")
err = ioutil.WriteFile(indexJS, buffer.Bytes(), 0755)
if err != nil {
return errors.Wrap(err, "Error writing backend package globals.d.ts file")
}
return nil
}
func (p *Parser) parserReport() *ParserReport {
return &ParserReport{
Packages: p.packagesToGenerate(),
}
}