remove the 'typescript' package entirely in favor of iris-cli and because the alm editor was deprecated by its author (consider using the designtsx.com instead)

Former-commit-id: 52888ae3fd0da9e5b98e095c665a1a538381ddef
This commit is contained in:
Gerasimos (Makis) Maropoulos 2020-04-19 16:47:15 +03:00
parent 340664dca9
commit c5392ede6a
19 changed files with 2 additions and 1129 deletions

View File

@ -18,11 +18,6 @@ after_script:
- go get ./...
- go test -count=1 -v -cover ./...
- cd ../
# typescript examples
- cd ./typescript/_examples
- go get ./...
- go test -count=1 -v -cover ./...
- cd ../../
# make sure that the _benchmarks code is working
- cd ./_benchmarks
- go get ./...

View File

@ -204,7 +204,8 @@ Breaking Changes:
- `var mvc.AutoBinding` removed as the default behavior now resolves such dependencies automatically (see [[FEATURE REQUEST] MVC serving gRPC-compatible controller](https://github.com/kataras/iris/issues/1449))
- `mvc#Application.SortByNumMethods()` removed as the default behavior now binds the "thinnest" empty `interface{}` automatically (see [MVC: service injecting fails](https://github.com/kataras/iris/issues/1343))
- `mvc#BeforeActivation.Dependencies().Add` should be replaced with `mvc#BeforeActivation.Dependencies().Register` instead.
- `mvc#BeforeActivation.Dependencies().Add` should be replaced with `mvc#BeforeActivation.Dependencies().Register` instead
- **REMOVE** the `kataras/iris/v12/typescript` package in favor of the new [iris-cli](https://github.com/kataras/iris-cli). Also, the alm typescript online editor was removed as it is deprecated by its author, please consider using the [designtsx](https://designtsx.com/) instead.
# Su, 16 February 2020 | v12.1.8

View File

@ -357,12 +357,6 @@ iris session manager lives on its own [package](https://github.com/kataras/iris/
- [Native Messages](websocket/native-messages/main.go)
- [TLS Enabled](websocket/secure/README.md)
### Typescript Automation Tools
typescript automation tools have their own repository: [https://github.com/kataras/iris/tree/master/typescript](https://github.com/kataras/iris/tree/master/typescript) **it contains examples**
> I'd like to tell you that you can use your favourite but I don't think you will find such a thing anywhere else.
### Hey, You
Developers should read the [godocs](https://godoc.org/github.com/kataras/iris) and https://docs.iris-go.com for a better understanding.

View File

@ -441,10 +441,6 @@ Iris session 管理独立包 [package](https://github.com/kataras/iris/tree/mast
- [原生消息](websocket/native-messages/main.go) **更新**
- [TLS支持](websocket/secure/README.md)
### Typescript 自动化工具
Typescript 自动化工具独立库: [https://github.com/kataras/iris/tree/master/typescript](https://github.com/kataras/iris/tree/master/typescript) **包含相关示例**
### 大兄弟
进一步学习可通过 [godocs](https://godoc.org/github.com/kataras/iris) 和 https://docs.iris-go.com

View File

@ -1,9 +0,0 @@
# Typescript
[Typescript](http://www.typescriptlang.org/) and [alm-tools cloud editor](http://alm.tools/) automation tools for the [iris](https://github.com/kataras/iris) web framework.
## Table of contents
* [Typescript compiler](_examples/typescript/main.go)
* [Alm-tools cloud editor](_examples/editor/main.go)

View File

@ -1,33 +0,0 @@
package main
import (
"github.com/kataras/iris/v12"
"github.com/kataras/iris/v12/typescript/editor"
)
func main() {
app := iris.New()
app.HandleDir("/scripts", "./www/scripts") // serve the scripts
// when you edit a typescript file from the alm-tools
// it compiles it to javascript, have fun!
app.Get("/", func(ctx iris.Context) {
ctx.ServeFile("./www/index.html", false)
})
editorConfig := editor.Config{
Hostname: "localhost",
Port: 4444,
WorkingDir: "./www/scripts/", // "/path/to/the/client/side/directory/",
Username: "myusername",
Password: "mypassword",
}
e := editor.New(editorConfig)
e.Run(app.Logger().Infof) // start the editor's server
// http://localhost:8080
// http://localhost:4444
app.Listen(":8080")
e.Stop()
}

View File

@ -1,8 +0,0 @@
<html>
<head>
<title>Load my script</title>
</head>
<body>
<script src="scripts/app.js"></script>
</body>
</html>

View File

@ -1,12 +0,0 @@
var User = (function () {
function User(fullname) {
this.name = fullname;
}
User.prototype.Hi = function (msg) {
return msg + " " + this.name;
};
return User;
}());
var user = new User("iris web framework!");
var hi = user.Hi("Hello");
window.alert(hi);

View File

@ -1,16 +0,0 @@
class User{
private name: string;
constructor(fullname:string) {
this.name = fullname;
}
Hi(msg: string): string {
return msg + " " + this.name;
}
}
var user = new User("iris web framework!");
var hi = user.Hi("Hello");
window.alert(hi);

View File

@ -1,22 +0,0 @@
{
"compilerOptions": {
"module": "commonjs",
"noImplicitAny": false,
"removeComments": true,
"preserveConstEnums": true,
"sourceMap": false,
"target": "ES5",
"noEmit": false,
"watch":true,
"noEmitOnError": true,
"experimentalDecorators": false,
"outDir": "./",
"charset": "UTF-8",
"noLib": false,
"diagnostics": true,
"declaration": false
},
"files": [
"./app.ts"
]
}

View File

@ -1,40 +0,0 @@
package main
import (
"github.com/kataras/iris/v12"
"github.com/kataras/iris/v12/typescript"
)
// NOTE: Some machines don't allow to install typescript automatically, so if you don't have typescript installed
// and the typescript adaptor doesn't works for you then follow the below steps:
// 1. close the iris server
// 2. open your terminal and execute: npm install -g typescript
// 3. start your iris server, it should be work, as expected, now.
func main() {
app := iris.New()
app.HandleDir("/scripts", "./www") // serve the scripts
app.Get("/", func(ctx iris.Context) {
ctx.ServeFile("./www/index.html", false)
})
ts := typescript.New()
ts.Config.Dir = "./www/scripts"
ts.Run(app.Logger().Infof)
// http://localhost:8080
app.Listen(":8080")
}
// open http://localhost:8080
// go to ./www/scripts/app.ts
// make a change
// reload the http://localhost:8080 and you should see the changes
//
// what it does?
// - compiles the typescript files using default compiler options if not tsconfig found
// - watches for changes on typescript files, if a change then it recompiles the .ts to .js
//
// same as you used to do with gulp-like tools, but here I do my bests to help GO developers.

View File

@ -1,8 +0,0 @@
<html>
<head>
<title>Load my script</title>
</head>
<body>
<script src="scripts/app.js"></script>
</body>
</html>

View File

@ -1,16 +0,0 @@
class User{
private name: string;
constructor(fullname:string) {
this.name = fullname;
}
Hi(msg: string): string {
return msg + " "+ this.name;
}
}
var user = new User("iris web framework");
var hi = user.Hi("Hello");
window.alert(hi);

View File

@ -1,194 +0,0 @@
package typescript
import (
"encoding/json"
"io/ioutil"
"os"
"reflect"
"strconv"
"github.com/kataras/iris/v12/typescript/npm"
)
var (
pathSeparator = string(os.PathSeparator)
nodeModules = pathSeparator + "node_modules" + pathSeparator
)
type (
// Tsconfig the struct for tsconfig.json
Tsconfig struct {
CompilerOptions CompilerOptions `json:"compilerOptions"`
Exclude []string `json:"exclude"`
}
// CompilerOptions contains all the compiler options used by the tsc (typescript compiler)
CompilerOptions struct {
Declaration bool `json:"declaration"`
Module string `json:"module"`
Target string `json:"target"`
Watch bool `json:"watch"`
Charset string `json:"charset"`
Diagnostics bool `json:"diagnostics"`
EmitBOM bool `json:"emitBOM"`
EmitDecoratorMetadata bool `json:"emitDecoratorMetadata"`
ExperimentalDecorators bool `json:"experimentalDecorators"`
InlineSourceMap bool `json:"inlineSourceMap"`
InlineSources bool `json:"inlineSources"`
IsolatedModules bool `json:"isolatedModules"`
Jsx string `json:"jsx"`
ReactNamespace string `json:"reactNamespace"`
ListFiles bool `json:"listFiles"`
Locale string `json:"locale"`
MapRoot string `json:"mapRoot"`
ModuleResolution string `json:"moduleResolution"`
NewLine string `json:"newLine"`
NoEmit bool `json:"noEmit"`
NoEmitOnError bool `json:"noEmitOnError"`
NoEmitHelpers bool `json:"noEmitHelpers"`
NoImplicitAny bool `json:"noImplicitAny"`
NoLib bool `json:"noLib"`
NoResolve bool `json:"noResolve"`
SkipDefaultLibCheck bool `json:"skipDefaultLibCheck"`
OutDir string `json:"outDir"`
OutFile string `json:"outFile"`
PreserveConstEnums bool `json:"preserveConstEnums"`
Pretty bool `json:"pretty"`
RemoveComments bool `json:"removeComments"`
RootDir string `json:"rootDir"`
SourceMap bool `json:"sourceMap"`
SourceRoot string `json:"sourceRoot"`
StripInternal bool `json:"stripInternal"`
SuppressExcessPropertyErrors bool `json:"suppressExcessPropertyErrors"`
SuppressImplicitAnyIndexErrors bool `json:"suppressImplicitAnyIndexErrors"`
AllowUnusedLabels bool `json:"allowUnusedLabels"`
NoImplicitReturns bool `json:"noImplicitReturns"`
NoFallthroughCasesInSwitch bool `json:"noFallthroughCasesInSwitch"`
AllowUnreachableCode bool `json:"allowUnreachableCode"`
ForceConsistentCasingInFileNames bool `json:"forceConsistentCasingInFileNames"`
AllowSyntheticDefaultImports bool `json:"allowSyntheticDefaultImports"`
AllowJs bool `json:"allowJs"`
NoImplicitUseStrict bool `json:"noImplicitUseStrict"`
}
// Config the configs for the Typescript plugin
// Has five (5) fields
//
// 1. Bin: string, the typescript installation directory/typescript/lib/tsc.js, if empty it will search inside global npm modules
// 2. Dir: string, Dir set the root, where to search for typescript files/project. Default "./"
// 3. Ignore: string, comma separated ignore typescript files/project from these directories. Default "" (node_modules are always ignored)
// 4. Tsconfig: &typescript.Tsconfig{}, here you can set all compilerOptions if no tsconfig.json exists inside the 'Dir'
// 5. Editor: typescript.Editor("username","password"), if set then alm-tools browser-based typescript IDE will be available. Defailt is nil
Config struct {
// Bin the path of the tsc binary file
// if empty then the plugin tries to find it
Bin string
// Dir the client side directory, which typescript (.ts) files are live
Dir string
// Ignore ignore folders, default is /node_modules/
Ignore string
// Tsconfig the typescript build configs, including the compiler's options
Tsconfig *Tsconfig
}
)
// CompilerArgs returns the CompilerOptions' contents of the Tsconfig
// it reads the json tags, add '--' at the start of each one and returns an array of strings
// this is from file
func (tsconfig *Tsconfig) CompilerArgs() []string {
val := reflect.ValueOf(tsconfig).Elem().FieldByName("CompilerOptions") // -> for tsconfig *Tsconfig
// val := reflect.ValueOf(tsconfig.CompilerOptions)
compilerOpts := make([]string, 0) // 0 because we don't know the real valid options yet.
for i := 0; i < val.NumField(); i++ {
typeField := val.Type().Field(i)
valueFieldG := val.Field(i)
var valueField string
// only if it's string or int we need to put that
if valueFieldG.Kind() == reflect.String {
// if valueFieldG.String() != "" {
// valueField = strconv.QuoteToASCII(valueFieldG.String())
// }
valueField = valueFieldG.String()
} else if valueFieldG.Kind() == reflect.Int {
if valueFieldG.Int() > 0 {
valueField = strconv.Itoa(int(valueFieldG.Int()))
}
} else if valueFieldG.Kind() == reflect.Bool {
valueField = strconv.FormatBool(valueFieldG.Bool())
}
if valueField != "" && valueField != "false" {
// var opt string
// key := typeField.Tag.Get("json")
// // it's bool value of true then just --key, for example --watch
// if valueField == "true" {
// opt = "--" + key
// } else {
// // it's a string now, for example -m commonjs
// opt = "-" + string(key[0]) + " " + valueField
// }
key := "--" + typeField.Tag.Get("json")
compilerOpts = append(compilerOpts, key)
// the form is not '--module ES6' but os.Exec should recognise them as arguments
// so we need to put the values on the next index
if valueField != "true" {
// it's a string now, for example -m commonjs
compilerOpts = append(compilerOpts, valueField)
}
}
}
return compilerOpts
}
// FromFile reads a file & returns the Tsconfig by its contents
func FromFile(tsConfigAbsPath string) (config Tsconfig, err error) {
file, err := ioutil.ReadFile(tsConfigAbsPath)
if err != nil {
return
}
config = Tsconfig{}
err = json.Unmarshal(file, &config)
return
}
// DefaultTsconfig returns the default Tsconfig, with CompilerOptions module: commonjs, target: es5 and ignore the node_modules
func DefaultTsconfig() Tsconfig {
return Tsconfig{
CompilerOptions: CompilerOptions{
Module: "commonjs",
Target: "ES6",
Jsx: "react",
ModuleResolution: "classic",
Locale: "en",
Watch: false,
NoImplicitAny: false,
SourceMap: false,
Diagnostics: true,
NoEmit: false,
OutDir: "", // taken from Config.Dir if it's not empty, otherwise ./ on Run()
},
Exclude: []string{"node_modules"},
}
}
// DefaultConfig returns the default Options of the Typescript adaptor
// Bin and Editor are setting in runtime via the adaptor
func DefaultConfig() Config {
root, err := os.Getwd()
if err != nil {
panic("typescript: cannot get the cwd")
}
compilerTsConfig := DefaultTsconfig()
c := Config{
Dir: root + pathSeparator,
Ignore: nodeModules,
Tsconfig: &compilerTsConfig,
}
c.Bin = npm.NodeModuleAbs("typescript/lib/tsc.js")
return c
}

View File

@ -1,46 +0,0 @@
package editor
import (
"os"
)
// Default values for the configuration
const (
DefaultPort = 4444
)
// Config the configs for the Editor plugin
type Config struct {
// Hostname if empty used the iris server's hostname
Hostname string
// Port if 0 4444
Port int
// KeyFile the key file(ssl optional)
KeyFile string
// CertFile the cert file (ssl optional)
CertFile string
// WorkingDir if empty "./"
WorkingDir string
// Username defaults to empty, you should set this
Username string
// Password defaults to empty, you should set this
Password string
// DisableOutput set that to true if you don't care about alm-tools' messages
// they are useful because that the default value is "false"
DisableOutput bool
}
// DefaultConfig returns the default configs for the Editor plugin
func DefaultConfig() Config {
// explicit
return Config{
Hostname: "",
Port: 4444,
KeyFile: "",
CertFile: "",
WorkingDir: "." + string(os.PathSeparator), // alm-tools should end with path separator.
Username: "",
Password: "",
DisableOutput: false,
}
}

View File

@ -1,209 +0,0 @@
package editor
/* Package editor provides alm-tools cloud editor automation for the iris web framework.
Usage:
import "github.com/kataras/iris/v12/typescript/editor"
[...]
app := iris.New()
e := editor.New(editor.Config{})
e.Run(app.Logger().Infof)
[...]
app.Listen(":8080")
e.Stop()
General notes for authentication
The Authorization specifies the authentication mechanism (in this case Basic) followed by the username and password.
Although, the string aHR0cHdhdGNoOmY= may look encrypted it is simply a base64 encoded version of <username>:<password>.
Would be readily available to anyone who could intercept the HTTP request.
*/
import (
"bufio"
"os"
"path/filepath"
"strconv"
"github.com/kataras/iris/v12/typescript/npm"
)
type (
// Editor is the alm-tools adaptor.
//
// It holds a logger from the iris' station
// username,password for basic auth
// directory which the client side code is
// keyfile,certfile for TLS listening
// and a host which is listening for
Editor struct {
config *Config
log func(format string, a ...interface{})
enabled bool // default true
// after alm started
process *os.Process
}
)
// NoOpLogger can be used as the logger argument, it prints nothing.
var NoOpLogger = func(string, ...interface{}) {}
// New creates and returns an Editor Plugin instance
func New(cfg ...Config) *Editor {
c := DefaultConfig()
if len(cfg) > 0 {
c = cfg[0]
}
c.WorkingDir = validateWorkingDir(c.WorkingDir) // add "/" if not exists
return &Editor{
enabled: true,
config: &c,
}
}
// User set a user, accepts two parameters: username (string), string (string)
func (e *Editor) User(username string, password string) *Editor {
e.config.Username = username
e.config.Password = password
return e
}
func validateWorkingDir(workingDir string) string {
l := workingDir[len(workingDir)-1]
if l != '/' && l != os.PathSeparator {
workingDir += "/"
}
return workingDir
}
// Dir sets the directory which the client side source code alive
func (e *Editor) Dir(workingDir string) *Editor {
e.config.WorkingDir = validateWorkingDir(workingDir)
return e
}
// Port sets the port (int) for the editor adaptor's standalone server
func (e *Editor) Port(port int) *Editor {
e.config.Port = port
return e
}
// SetEnable if true enables the editor adaptor, otherwise disables it
func (e *Editor) SetEnable(enable bool) {
e.enabled = enable
}
// DisableOutput call that if you don't care about alm-tools' messages
// they are useful because that the default configuration shows them
func (e *Editor) DisableOutput() {
e.config.DisableOutput = true
}
// GetDescription EditorPlugin is a bridge between iris and the alm-tools, the browser-based IDE for client-side sources.
func (e *Editor) GetDescription() string {
return "A bridge between iris and the alm-tools, the browser-based IDE."
}
// Run starts the editor's server.
//
// Developers should call the `Stop` to shutdown the editor's server when main server will be closed.
func (e *Editor) Run(logger func(format string, a ...interface{})) {
if logger == nil {
logger = NoOpLogger
}
e.log = logger
if e.config.Hostname == "" {
e.config.Hostname = "0.0.0.0"
}
if e.config.Port <= 0 {
e.config.Port = DefaultPort
}
if s, err := filepath.Abs(e.config.WorkingDir); err == nil {
e.config.WorkingDir = s
}
e.start()
}
// Stop kills the editor's server.
func (e *Editor) Stop() {
if e.process != nil {
err := e.process.Kill()
if err != nil {
e.log("error while trying to terminate the Editor,please kill this process by yourself, process id: %d", e.process.Pid)
}
}
}
// start starts the job
func (e *Editor) start() {
if e.config.Username == "" || e.config.Password == "" {
e.log("error before running alm-tools. You have to set username & password for security reasons, otherwise this adaptor won't run.")
return
}
if !npm.NodeModuleExists("alm/bin/alm") {
e.log("installing alm-tools, please wait...")
res := npm.NodeModuleInstall("alm")
if res.Error != nil {
e.log(res.Error.Error())
return
}
e.log(res.Message)
}
cmd := npm.CommandBuilder("node", npm.NodeModuleAbs("alm/src/server.js"))
cmd.AppendArguments("-a", e.config.Username+":"+e.config.Password,
"-h", e.config.Hostname, "-t", strconv.Itoa(e.config.Port), "-d", e.config.WorkingDir)
// for auto-start in the browser: cmd.AppendArguments("-o")
if e.config.KeyFile != "" && e.config.CertFile != "" {
cmd.AppendArguments("--httpskey", e.config.KeyFile, "--httpscert", e.config.CertFile)
}
prefix := ""
// when debug is not disabled
// show any messages to the user( they are useful here)
// to the io.Writer that iris' user is defined from configuration
if !e.config.DisableOutput {
outputReader, err := cmd.StdoutPipe()
if err == nil {
outputScanner := bufio.NewScanner(outputReader)
go func() {
for outputScanner.Scan() {
e.log(prefix + outputScanner.Text())
}
}()
errReader, err := cmd.StderrPipe()
if err == nil {
errScanner := bufio.NewScanner(errReader)
go func() {
for errScanner.Scan() {
e.log(prefix + errScanner.Text())
}
}()
}
}
}
err := cmd.Start()
if err != nil {
e.log(prefix + err.Error())
return
}
// no need, alm-tools post these
// e.logger.Printf("Editor is running at %s:%d | %s", e.config.Hostname, e.config.Port, e.config.WorkingDir)
}

View File

@ -1,112 +0,0 @@
package npm // #nosec
import (
"fmt"
"os"
"os/exec"
"strings"
)
// PathSeparator is the string of os.PathSeparator
var PathSeparator = string(os.PathSeparator)
type (
// Cmd is a custom struch which 'implements' the *exec.Cmd
Cmd struct {
*exec.Cmd
}
)
// Arguments sets the command line arguments, including the command as Args[0].
// If the args parameter is empty or nil, Run uses {Path}.
//
// In typical use, both Path and args are set by calling Command.
func (cmd *Cmd) Arguments(args ...string) *Cmd {
cmd.Cmd.Args = append(cmd.Cmd.Args[0:1], args...) // we need the first argument which is the command
return cmd
}
// AppendArguments appends the arguments to the exists
func (cmd *Cmd) AppendArguments(args ...string) *Cmd {
cmd.Cmd.Args = append(cmd.Cmd.Args, args...)
return cmd
}
// ResetArguments resets the arguments
func (cmd *Cmd) ResetArguments() *Cmd {
cmd.Args = cmd.Args[0:1] // keep only the first because is the command
return cmd
}
// Directory sets the working directory of the command.
// If workingDirectory is the empty string, Run runs the command in the
// calling process's current directory.
func (cmd *Cmd) Directory(workingDirectory string) *Cmd {
cmd.Cmd.Dir = workingDirectory
return cmd
}
// CommandBuilder creates a Cmd object and returns it
// accepts 2 parameters, one is optionally
// first parameter is the command (string)
// second variatic parameter is the argument(s) (slice of string)
//
// the difference from the normal Command function is that you can re-use this Cmd, it doesn't execute until you call its Command function
func CommandBuilder(command string, args ...string) *Cmd {
return &Cmd{Cmd: exec.Command(command, args...)}
}
// the below is just for exec.Command:
// Command executes a command in shell and returns it's output, it's block version
func Command(command string, a ...string) (output string, err error) {
var out []byte
// if no args given, try to get them from the command
if len(a) == 0 {
commandArgs := strings.Split(command, " ")
for _, commandArg := range commandArgs {
if commandArg[0] == '-' { // if starts with - means that this is an argument, append it to the arguments
a = append(a, commandArg)
}
}
}
out, err = exec.Command(command, a...).Output()
if err == nil {
output = string(out)
}
return
}
// MustCommand executes a command in shell and returns it's output, it's block version. It panics on an error
func MustCommand(command string, a ...string) (output string) {
var out []byte
var err error
if len(a) == 0 {
commandArgs := strings.Split(command, " ")
for _, commandArg := range commandArgs {
if commandArg[0] == '-' { // if starts with - means that this is an argument, append it to the arguments
a = append(a, commandArg)
}
}
}
out, err = exec.Command(command, a...).Output()
if err != nil {
argsToString := strings.Join(a, " ")
panic(fmt.Sprintf("\nError running the command %s", command+" "+argsToString))
}
output = string(out)
return
}
// Exists returns true if directory||file exists
func Exists(dir string) bool {
if _, err := os.Stat(dir); os.IsNotExist(err) {
return false
}
return true
}

View File

@ -1,118 +0,0 @@
package npm
import (
"fmt"
"path/filepath"
"strings"
"time"
)
// nodeModulesPath is the path of the root npm modules
// Ex: C:\\Users\\iris\\AppData\\Roaming\\npm\\node_modules
var nodeModulesPath string
type (
// NodeModuleResult holds Message and Error, if error != nil then the npm command has failed
NodeModuleResult struct {
// Message the message (string)
Message string
// Error the error (if any)
Error error
}
)
// NodeModulesPath sets the root directory for the node_modules and returns that
func NodeModulesPath() string {
if nodeModulesPath == "" {
nodeModulesPath = MustCommand("npm", "root", "-g") // here it ends with \n we have to remove it
nodeModulesPath = nodeModulesPath[0 : len(nodeModulesPath)-1]
}
return nodeModulesPath
}
func success(output string, a ...interface{}) NodeModuleResult {
return NodeModuleResult{fmt.Sprintf(output, a...), nil}
}
func fail(errMsg string, a ...interface{}) NodeModuleResult {
return NodeModuleResult{"", fmt.Errorf("\n"+errMsg, a...)}
}
// Output returns the error message if result.Error exists, otherwise returns the result.Message
func (res NodeModuleResult) Output() (out string) {
if res.Error != nil {
out = res.Error.Error()
} else {
out = res.Message
}
return
}
// NodeModuleInstall installs a module
func NodeModuleInstall(moduleName string) NodeModuleResult {
finish := make(chan bool)
go func() {
print("\n|")
print("_")
print("|")
for {
select {
case v := <-finish:
{
if v {
print("\010\010\010") // remove the loading chars
close(finish)
return
}
}
default:
print("\010\010-")
time.Sleep(time.Second / 2)
print("\010\\")
time.Sleep(time.Second / 2)
print("\010|")
time.Sleep(time.Second / 2)
print("\010/")
time.Sleep(time.Second / 2)
print("\010-")
time.Sleep(time.Second / 2)
print("|")
}
}
}()
out, err := Command("npm", "install", moduleName, "-g")
finish <- true
if err != nil {
return fail("Error installing module %s. Trace: %s", moduleName, err.Error())
}
return success("\n%s installed %s", moduleName, out)
}
// NodeModuleUnistall removes a module
func NodeModuleUnistall(moduleName string) NodeModuleResult {
out, err := Command("npm", "unistall", "-g", moduleName)
if err != nil {
return fail("Error unstalling module %s. Trace: %s", moduleName, err.Error())
}
return success("\n %s unistalled %s", moduleName, out)
}
// NodeModuleAbs returns the absolute path of the global node_modules directory + relative
func NodeModuleAbs(relativePath string) string {
return NodeModulesPath() + PathSeparator + strings.Replace(relativePath, "/", PathSeparator, -1)
}
// NodeModuleExists returns true if a module exists
// here we have two options
// 1 . search by command something like npm -ls -g --depth=x
// 2. search on files, we choose the second
func NodeModuleExists(execPath string) bool {
if !filepath.IsAbs(execPath) {
execPath = NodeModuleAbs(execPath)
}
return Exists(execPath)
}

View File

@ -1,270 +0,0 @@
// Package typescript provides a typescript compiler with hot-reloader
// and optionally a cloud-based editor, called 'alm-tools'.
// typescript (by microsoft) and alm-tools (by @basarat) have their own (open-source) licenses
// the tools are not used directly by this adaptor, but it's good to know where you can find
// the software.
package typescript
import (
"errors"
"os"
"path/filepath"
"strings"
"github.com/kataras/iris/v12/typescript/npm"
)
type (
// Typescript contains the unique iris' typescript loader, holds all necessary fields & methods.
Typescript struct {
Config *Config
log func(format string, a ...interface{})
}
)
// New creates & returns a new instnace typescript plugin
func New(cfg ...Config) *Typescript {
c := DefaultConfig()
if len(cfg) > 0 {
c = cfg[0]
}
return &Typescript{Config: &c}
}
// NoOpLogger can be used as the logger argument, it prints nothing.
var NoOpLogger = func(string, ...interface{}) {}
// Run starts the typescript filewatcher watcher and the typescript compiler.
func (t *Typescript) Run(logger func(format string, a ...interface{})) {
c := t.Config
if c.Tsconfig == nil {
tsC := DefaultTsconfig()
c.Tsconfig = &tsC
}
if c.Dir == "" {
c.Tsconfig.CompilerOptions.OutDir = c.Dir
}
if c.Dir == "" {
c.Dir = "./"
}
if !strings.Contains(c.Ignore, nodeModules) {
c.Ignore += "," + nodeModules
}
if logger == nil {
logger = NoOpLogger
}
t.log = logger
t.start()
}
func (t *Typescript) start() {
if t.hasTypescriptFiles() {
// Can't check if permission denied returns always exists = true....
if !npm.NodeModuleExists(t.Config.Bin) {
t.log("installing typescript, please wait...")
res := npm.NodeModuleInstall("typescript")
if res.Error != nil {
t.log(res.Error.Error())
return
}
t.log(res.Message)
}
projects := t.getTypescriptProjects()
if len(projects) > 0 {
watchedProjects := 0
// typescript project (.tsconfig) found
for _, project := range projects {
cmd := npm.CommandBuilder("node", t.Config.Bin, "-p", project[0:strings.LastIndex(project, npm.PathSeparator)]) // remove the /tsconfig.json)
projectConfig, perr := FromFile(project)
if perr != nil {
t.log("error while trying to read tsconfig: %s", perr.Error())
continue
}
if projectConfig.CompilerOptions.Watch {
watchedProjects++
// if has watch : true then we have to wrap the command to a goroutine (I don't want to use the .Start here)
go func() {
_, err := cmd.Output()
if err != nil {
t.log("error when 'watch' is true: %v", err)
return
}
}()
} else {
_, err := cmd.Output()
if err != nil {
t.log("unexpected error from output: %v", err)
return
}
}
}
return
}
// search for standalone typescript (.ts) files and compile them
files := t.getTypescriptFiles()
if len(files) > 0 {
/* watchedFiles := 0
if t.Config.Tsconfig.CompilerOptions.Watch {
watchedFiles = len(files)
}*/
//it must be always > 0 if we came here, because of if hasTypescriptFiles == true.
for _, file := range files {
absPath, err := filepath.Abs(file)
if err != nil {
t.log("error while trying to resolve absolute path for %s: %v", file, err)
continue
}
// these will be used if no .tsconfig found.
// cmd := npm.CommandBuilder("node", t.Config.Bin)
// cmd.Arguments(t.Config.Bin, t.Config.Tsconfig.CompilerArgs()...)
// cmd.AppendArguments(absPath)
compilerArgs := t.Config.Tsconfig.CompilerArgs()
cmd := npm.CommandBuilder("node", t.Config.Bin)
for _, s := range compilerArgs {
cmd.AppendArguments(s)
}
cmd.AppendArguments(absPath)
go func() {
compilerMsgB, _ := cmd.Output()
compilerMsg := string(compilerMsgB)
cmd.Args = cmd.Args[0 : len(cmd.Args)-1] // remove the last, which is the file
if strings.Contains(compilerMsg, "error") {
t.log(compilerMsg)
}
}()
}
return
}
return
}
absPath, err := filepath.Abs(t.Config.Dir)
if err != nil {
t.log("no typescript file, the directory cannot be resolved: %v", err)
return
}
t.log("no typescript files found on : %s", absPath)
}
func (t *Typescript) hasTypescriptFiles() bool {
root := t.Config.Dir
ignoreFolders := t.getIgnoreFolders()
hasTs := false
if !npm.Exists(root) {
t.log("typescript error: directory '%s' couldn't be found,\nplease specify a valid path for your *.ts files", root)
return false
}
err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
if fi.IsDir() {
return nil
}
for _, s := range ignoreFolders {
if strings.HasSuffix(path, s) || path == s {
return filepath.SkipDir
}
}
if strings.HasSuffix(path, ".ts") {
hasTs = true
return errors.New("typescript found, hope that will stop here")
}
return nil
})
if err != nil {
t.log("typescript: hasTypescriptFiles: %v", err)
}
return hasTs
}
func (t *Typescript) getIgnoreFolders() (folders []string) {
ignoreFolders := strings.Split(t.Config.Ignore, ",")
for _, s := range ignoreFolders {
if s != "" {
folders = append(folders, s)
}
}
return folders
}
func (t *Typescript) getTypescriptProjects() []string {
var projects []string
ignoreFolders := t.getIgnoreFolders()
root := t.Config.Dir
// t.logger.Printf("\nSearching for typescript projects in %s", root)
err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
if fi.IsDir() {
return nil
}
for _, s := range ignoreFolders {
if strings.HasSuffix(path, s) || path == s {
return filepath.SkipDir
}
}
if strings.HasSuffix(path, npm.PathSeparator+"tsconfig.json") {
// t.logger.Printf("\nTypescript project found in %s", path)
projects = append(projects, path)
}
return nil
})
if err != nil {
t.log("typescript: getTypescriptProjects: %v", err)
}
return projects
}
// this is being called if getTypescriptProjects return 0 len, then we are searching for files using that:
func (t *Typescript) getTypescriptFiles() []string {
var files []string
ignoreFolders := t.getIgnoreFolders()
root := t.Config.Dir
err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
if fi.IsDir() {
return nil
}
for _, s := range ignoreFolders {
if strings.HasSuffix(path, s) || path == s {
return nil
}
}
if strings.HasSuffix(path, ".ts") {
// t.logger.Printf("\nTypescript file found in %s", path)
files = append(files, path)
}
return nil
})
if err != nil {
t.log("typescript: getTypescriptFiles: %v", err)
}
return files
}