diff --git a/action.go b/action.go new file mode 100644 index 0000000..545accf --- /dev/null +++ b/action.go @@ -0,0 +1,71 @@ +package main + +import ( + "fmt" + "strings" +) + +type Action struct { + ResourceOptions +} + +func (a *Action) GetDir() string { + return "actions" +} + +func (a *Action) GetFileName() string { + return a.ResourceOptions.Domain + "-actions.js" +} + +func (a *Action) GetFileContent() string { + domainFirstCharUpper := strings.ToUpper(a.Domain[:1]) + a.Domain[1:] + return fmt.Sprintf(a.getTemplate(), domainFirstCharUpper, a.Domain, a.Action, a.Constant) +} + +func (a *Action) getTemplate() string { + content := a.getHeaderTemplate() + content = content + a.getBodyTemplateVariation() + content = content + a.getFooterTemplate() + + return content +} + +func (a *Action) getHeaderTemplate() string { + return "var AppDispatcher = require('../dispatcher/app-dispatcher');\n" + + "var %[1]sConstants = require('../constants/%[2]s-constants');\n" +} + +func (a *Action) getBodyTemplateVariation() string { + if a.IsApi { + return "" + + "var %[1]sApi = require('../webapi/%[2]s-api');\n\n" + + "var %[1]sActions = {\n" + + " %[3]s: function() {\n" + + " AppDispatcher.dispatch({\n" + + " actionType: %[1]sConstants.%[4]s,\n" + + " });\n\n" + + " %[1]sApi.%[3]s(%[1]sActions.%[3]sSuccess);\n" + + " },\n\n" + + " %[3]sSuccess: function(%[2]ss) {\n" + + " AppDispatcher.dispatch({\n" + + " actionType: %[1]sConstants.%[4]s_SUCCESS,\n" + + " %[2]ss: %[2]ss\n" + + " });\n" + + " }\n" + } else { + return "\n" + + "var %[1]sActions = {\n" + + " %[3]s: function(%[2]s) {\n" + + " AppDispatcher.dispatch({\n" + + " actionType: %[1]sConstants.%[4]s,\n" + + " %[2]s: %[2]s\n" + + " });\n" + + " }\n" + } +} + +func (a *Action) getFooterTemplate() string { + return "" + + "};\n\n" + + "module.exports = %[1]sActions;" +} diff --git a/api.go b/api.go new file mode 100644 index 0000000..a1be021 --- /dev/null +++ b/api.go @@ -0,0 +1,42 @@ +package main + +import ( + "fmt" + "strings" +) + +type Api struct { + ResourceOptions +} + +func (s *Api) GetDir() string { + return "webapi" +} + +func (s *Api) GetFileName() string { + return s.ResourceOptions.Domain + "-api.js" +} + +func (s *Api) GetFileContent() string { + domainFirstCharUpper := strings.ToUpper(s.Domain[:1]) + s.Domain[1:] + return fmt.Sprintf(s.getTemplate(), domainFirstCharUpper, s.Action, s.Domain) +} + +func (s *Api) getTemplate() string { + return "var request = require('superagent');\n" + + "var ApiResponseHandler = require('./api-response-handler');\n\n" + + "var %[1]sApi = {\n" + + " %[2]s: function(successCallback) {\n" + + " var url = Routing.generate('%[3]s_list');\n\n" + + " request\n" + + " .get(url)\n" + + " .set('Accept', 'application/json')\n" + + " .end(function(err, res) {\n" + + " ApiResponseHandler.handle(err, res, successCallback);\n" + + " })\n" + + " ;\n" + + " }\n" + + "};\n\n" + + + "module.exports = %[1]sApi;" +} diff --git a/constant.go b/constant.go new file mode 100644 index 0000000..5bd707b --- /dev/null +++ b/constant.go @@ -0,0 +1,43 @@ +package main + +import ( + "fmt" + "strings" +) + +type Constant struct { + ResourceOptions +} + +func (c *Constant) GetDir() string { + return "constants" +} + +func (c *Constant) GetFileName() string { + return c.ResourceOptions.Domain + "-constants.js" +} + +func (c *Constant) GetFileContent() string { + domainFirstCharUpper := strings.ToUpper(c.Domain[:1]) + c.Domain[1:] + return fmt.Sprintf(c.getTemplate(), domainFirstCharUpper, c.Constant) +} + +func (c *Constant) getTemplate() string { + content := "var keyMirror = require('keymirror');\n\n" + + "var %[1]sConstants = keyMirror({\n"; + + if c.IsApi { + content = content + + " %[2]s: null,\n" + + " %[2]s_SUCCESS: null\n" + } else { + content = content + + " %[2]s: null\n" + } + + content = content + + "});\n\n" + + "module.exports = %[1]sConstants;" + + return content +} diff --git a/fileutils.go b/fileutils.go new file mode 100644 index 0000000..2838c66 --- /dev/null +++ b/fileutils.go @@ -0,0 +1,48 @@ +package main + +import ( + "fmt" + "path/filepath" + "os" +) + +func PathExists(path string) (bool, error) { + _, err := os.Stat(path) + if err == nil { return true, nil } + if os.IsNotExist(err) { return false, nil } + + return false, err +} + +func GetFullDirPath(dir string) string { + return GetRootDir() + dir +} + +func GetFullFilePath(dir, fileName string) string { + return GetRootDir() + dir + string(filepath.Separator) + fileName +} + +func CreateDir(fullDirPath string) { + os.Mkdir(fullDirPath, 0777) +} + +func GetRootDir() string { + //return "." + string(filepath.Separator) + return "/Volumes/Data/test/" +} + +func CreateFile(fullFilePath string) *os.File { + f, err := os.Create(fullFilePath) + if err != nil { + panic(err) + } + return f +} + +func WriteFile(f *os.File, content string, fullFilePath string) { + fmt.Fprintln(f, content) +} + +func CloseFile(f *os.File, fullFilePath string) { + f.Close() +} diff --git a/fluxscaffold.go b/fluxscaffold.go new file mode 100644 index 0000000..054f1fb --- /dev/null +++ b/fluxscaffold.go @@ -0,0 +1,38 @@ +package main + +import ( + "fmt" + "flag" + "os" +) + +func main() { + var domain, constant, action string + var isApi bool + + flag.StringVar(&domain, "domain", "", "A domain object name e.g user, product"); + flag.StringVar(&constant, "const", "", "A constant name, eg. USERS_FETCH"); + flag.StringVar(&action, "action", "", "An action name, fetchUsers"); + flag.BoolVar(&isApi, "api", false, "If enabled, will create an api file and import it in the action-creator file") + + flag.Parse(); + + if (domain == "" || constant == "" || action == "") { + fmt.Println("domain, constant and action are required \n"); + os.Exit(1); + } + + resourceOptions := ResourceOptions{Domain: domain, Constant: constant, Action: action, IsApi: isApi} + constantGenerator := ResourceGenerator{&Constant{ResourceOptions(resourceOptions)}} + actionGenerator := ResourceGenerator{&Action{ResourceOptions(resourceOptions)}} + storeGenerator := ResourceGenerator{&Store{ResourceOptions(resourceOptions)}} + + constantGenerator.Execute() + actionGenerator.Execute() + storeGenerator.Execute() + + if (isApi) { + apiGenerator := ResourceGenerator{&Api{ResourceOptions(resourceOptions)}} + apiGenerator.Execute() + } +} diff --git a/resource-generator.go b/resource-generator.go new file mode 100644 index 0000000..f2fc7b1 --- /dev/null +++ b/resource-generator.go @@ -0,0 +1,47 @@ +package main + +import ( + "fmt" + "os" +) + +type ResourceGenerator struct { + Res ResourceInterface +} + +func (rg *ResourceGenerator) Execute() { + rg.createDirIfNotExists() + rg.createFileIfNotExists() +} + +func (rg *ResourceGenerator) createDirIfNotExists() { + fullDirPath := GetFullDirPath(rg.Res.GetDir()) + exists, err := PathExists(fullDirPath) + + if err != nil { + fmt.Println("Unexpected error while checking ", rg.Res.GetDir(), err) + os.Exit(1) + } + + if exists == false { + CreateDir(fullDirPath) + } +} + +func (rg *ResourceGenerator) createFileIfNotExists() bool { + fullFilePath := GetFullFilePath(rg.Res.GetDir(), rg.Res.GetFileName()) + exists, err := PathExists(fullFilePath) + + if exists || err != nil { + fmt.Println("File alrady exists, skipping", fullFilePath) + return false + } + + file := CreateFile(fullFilePath); + defer CloseFile(file, fullFilePath); + + WriteFile(file, rg.Res.GetFileContent(), fullFilePath) + fmt.Println("File", fullFilePath, "created") + + return true +} diff --git a/resource-interface.go b/resource-interface.go new file mode 100644 index 0000000..cb73fb2 --- /dev/null +++ b/resource-interface.go @@ -0,0 +1,7 @@ +package main + +type ResourceInterface interface { + GetDir() string + GetFileName() string + GetFileContent() string +} \ No newline at end of file diff --git a/resource-options.go b/resource-options.go new file mode 100644 index 0000000..fdaab8b --- /dev/null +++ b/resource-options.go @@ -0,0 +1,8 @@ +package main + +type ResourceOptions struct { + Domain string + Constant string + Action string + IsApi bool +} \ No newline at end of file diff --git a/store.go b/store.go new file mode 100644 index 0000000..0a13037 --- /dev/null +++ b/store.go @@ -0,0 +1,112 @@ +package main + +import ( + "fmt" + "strings" +) + +type Store struct { + ResourceOptions +} + +func (s *Store) GetDir() string { + return "stores" +} + +func (s *Store) GetFileName() string { + return s.ResourceOptions.Domain + "-store.js" +} + +func (s *Store) GetFileContent() string { + domainFirstCharUpper := strings.ToUpper(s.Domain[:1]) + s.Domain[1:] + return fmt.Sprintf(s.getTemplate(), domainFirstCharUpper, s.Domain, s.Constant) +} + +func (s *Store) getTemplate() string { + content := s.getHeaderTemplate() + content = content + s.getBodyVariationTemplate() + content = content + s.getFooterTemplate() + + return content +} + +func (s *Store) getHeaderTemplate() string { + return "var AppDispatcher = require('../dispatcher/app-dispatcher');\n" + + "var EventEmitter = require('events').EventEmitter;\n" + + "var assign = require('object-assign');\n" + + "var %[1]sConstants = require('../constants/%[2]s-constants');\n" + + "var CHANGE_EVENT = 'change';\n\n" +} + +func (s *Store) getBodyVariationTemplate() string { + if s.IsApi { + return "" + + "var _data = {\n" + + " %[2]ss: null\n" + + "};\n\n" + + "var %[1]sStore = assign({}, EventEmitter.prototype, {\n" + + " getData: function() {\n" + + " return _data;\n" + + " },\n\n" + + " get%[1]ss: function() {\n" + + " return _data.%[2]ss;\n" + + " },\n\n" + + " emitChange: function() {\n" + + " this.emit(CHANGE_EVENT);\n" + + " },\n\n" + + " addChangeListener: function(callback) {\n" + + " this.on(CHANGE_EVENT, callback);\n" + + " },\n\n" + + " removeChangeListener: function(callback) {\n" + + " this.removeListener(CHANGE_EVENT, callback);\n" + + " }\n" + + "});\n\n" + + "AppDispatcher.register(function(action) {\n" + + " switch (action.actionType) {\n" + + " case %[1]sConstants.%[3]s_SUCCESS:\n" + + " _data.%[2]ss = action.%[2]ss;\n" + + " %[1]sStore.emitChange();\n" + + " break;\n\n" + + " default:\n" + + " // no op\n" + + " }\n" + + "});\n\n" + + } else { + return "" + + "var _data = {\n" + + " %[2]s: null\n" + + "};\n\n" + + "var %[1]sStore = assign({}, EventEmitter.prototype, {\n" + + " getData: function() {\n" + + " return _data;\n" + + " },\n\n" + + " get%[1]s: function() {\n" + + " return _data.%[2]s;\n" + + " },\n\n" + + " emitChange: function() {\n" + + " this.emit(CHANGE_EVENT);\n" + + " },\n\n" + + " addChangeListener: function(callback) {\n" + + " this.on(CHANGE_EVENT, callback);\n" + + " },\n\n" + + " removeChangeListener: function(callback) {\n" + + " this.removeListener(CHANGE_EVENT, callback);\n" + + " }\n" + + "});\n\n" + + "AppDispatcher.register(function(action) {\n" + + " switch (action.actionType) {\n" + + " case %[1]sConstants.%[3]s:\n" + + " _data.%[2]s = action.%[2]s;\n" + + " %[1]sStore.emitChange();\n" + + " break;\n\n" + + " default:\n" + + " // no op\n" + + " }\n" + + "});\n\n" + } +} + +func (s *Store) getFooterTemplate() string { + return "module.exports = %[1]sStore;" +}