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 }