github.com/GeniusesGroup/libgo@v0.0.0-20220929090155-5ff932cb408e/www/js.go (about)

     1  /* For license and copyright information please see LEGAL file in repository */
     2  
     3  package www
     4  
     5  import (
     6  	"bytes"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"../file"
    11  	"../protocol"
    12  )
    13  
    14  // JS store data for its method
    15  type JS struct {
    16  	imports []protocol.File
    17  	inlined map[string]protocol.File
    18  }
    19  
    20  func (js *JS) checkInlined(srcJS protocol.File) (inlined bool) {
    21  	_, inlined = js.inlined[srcJS.Metadata().URI().Path()]
    22  	return
    23  }
    24  
    25  // AddJSToJS use to add a JS file to other!
    26  func (js *JS) addJSToJS(srcJS, desJS protocol.File) {
    27  	if js.checkInlined(srcJS) {
    28  		return
    29  	}
    30  	js.inlined[srcJS.Metadata().URI().Path()] = srcJS
    31  	desJS.Data().Append(srcJS.Data().Marshal())
    32  }
    33  
    34  // AddJSToJSRecursively use to add JSS and all import to JS file!
    35  func (js *JS) addJSToJSRecursively(srcJS, desJS protocol.File) {
    36  	if js.checkInlined(srcJS) {
    37  		return
    38  	}
    39  	// Tell other this file will add to desJS later!
    40  	js.inlined[srcJS.Metadata().URI().Path()] = srcJS
    41  
    42  	var imports = make([]protocol.File, 0, 16)
    43  	_ = js.extractJSImports(srcJS)
    44  	for _, imp := range imports {
    45  		js.addJSToJSRecursively(imp, desJS)
    46  	}
    47  	desJS.Data().Append(srcJS.Data().Marshal())
    48  }
    49  
    50  func (js *JS) extractJSImportsRecursively(jsFile protocol.File) (err protocol.Error) {
    51  	var lastImportIndex = len(js.imports)
    52  	_ = js.extractJSImports(jsFile)
    53  	for _, imp := range js.imports[lastImportIndex:] {
    54  		err = js.extractJSImportsRecursively(imp)
    55  	}
    56  	return
    57  }
    58  
    59  func (js *JS) extractJSImports(jsFile protocol.File) (err protocol.Error) {
    60  	var jsData = jsFile.Data().Marshal()
    61  	var importKeywordIndex, st, en int
    62  	for {
    63  		importKeywordIndex = bytes.Index(jsData, []byte("import "))
    64  		if importKeywordIndex == -1 {
    65  			break
    66  		}
    67  
    68  		// TODO::: check and don't parse dynamically import
    69  
    70  		// Find start and end of import file location!
    71  		st = importKeywordIndex + bytes.IndexByte(jsData[importKeywordIndex:], '\'') + 1
    72  		en = st + bytes.IndexByte(jsData[st:], '\'')
    73  		var importPath = string(jsData[st:en])
    74  		var importFile = file.FindByRelativeFrom(jsFile, importPath)
    75  		if importFile == nil {
    76  			if protocol.AppDevMode {
    77  				protocol.App.Log(protocol.LogType_Warning, "WWW - '", importPath, "' indicate as import in", jsFile.Metadata().URI().Name(), "not found")
    78  			}
    79  			// err =
    80  		} else {
    81  			js.imports = append(js.imports, importFile)
    82  		}
    83  
    84  		copy(jsData[importKeywordIndex-1:], jsData[en+1:])
    85  		jsData = jsData[:len(jsData)-(en-importKeywordIndex)-2]
    86  	}
    87  	jsFile.Data().Unmarshal(jsData)
    88  	return
    89  }
    90  
    91  func localeAndMixJSFile(jsFile protocol.File) (mixedData map[string][]byte) {
    92  	var js = jsFile.Data().Marshal()
    93  	var jsFileNameWithoutExtension = jsFile.Metadata().URI().NameWithoutExtension()
    94  
    95  	var lj = make(localize, 8)
    96  	var jsonFile, _ = jsFile.ParentDirectory().File(jsFileNameWithoutExtension + ".json")
    97  	if protocol.AppDevMode && jsonFile == nil {
    98  		protocol.App.Log(protocol.LogType_Warning, "WWW - ", jsFile.Metadata().URI().Name(), "Can't find JSON localize file, Localization skipped")
    99  		return
   100  	}
   101  
   102  	var cssFile, _ = jsFile.ParentDirectory().File(jsFileNameWithoutExtension + ".css")
   103  	if protocol.AppDevMode && cssFile == nil {
   104  		protocol.App.Log(protocol.LogType_Warning, "WWW - ", jsFile.Metadata().URI().Name(), "Can't find CSS style file, Mix CSS to JS file skipped")
   105  	}
   106  	if cssFile != nil {
   107  		js, _ = mixCSSToJS(js, cssFile.Data().Marshal())
   108  	}
   109  
   110  	lj.jsonDecoder(jsonFile.Data().Marshal())
   111  	mixedData, _ = localizeJSFile(js, lj)
   112  
   113  	var htmlFile, _ = jsFile.ParentDirectory().File(jsFileNameWithoutExtension + ".html")
   114  	if protocol.AppDevMode && htmlFile == nil {
   115  		protocol.App.Log(protocol.LogType_Warning, "WWW - ", jsFile.Metadata().URI().Name(), "Can't find HTML style file, Mix HTML to JS file skipped")
   116  	}
   117  	if htmlFile != nil {
   118  		var htmlMixedData, _ = localizeHTMLFile(htmlFile.Data().Marshal(), lj)
   119  		for lang, html := range htmlMixedData {
   120  			mixHTMLToJS(mixedData[lang], html)
   121  		}
   122  	}
   123  
   124  	for _, f := range jsFile.ParentDirectory().FindFiles(jsFileNameWithoutExtension+"-template-", 0) {
   125  		var namesPart = strings.Split(f.Metadata().URI().Name(), "-template-")
   126  		var htmlMixedData, _ = localizeHTMLFile(f.Data().Marshal(), lj)
   127  		for lang, f := range htmlMixedData {
   128  			mixHTMLTemplateToJS(mixedData[lang], f, namesPart[1])
   129  		}
   130  	}
   131  
   132  	return
   133  }
   134  
   135  // localizeJSFile make and returns number of localize file by number of language indicate in JSON localize text
   136  func localizeJSFile(js []byte, lj localize) (mixedData map[string][]byte, err protocol.Error) {
   137  	mixedData = make(map[string][]byte, len(lj))
   138  	for lang, text := range lj {
   139  		mixedData[lang], _ = replaceLocalizeTextInJS(js, text)
   140  	}
   141  	return
   142  }
   143  
   144  func replaceLocalizeTextInJS(js []byte, text []string) (mixData []byte, err protocol.Error) {
   145  	mixData = make([]byte, 0, len(js))
   146  
   147  	var replacerIndex int
   148  	var bracketIndex int
   149  	for {
   150  		replacerIndex = bytes.Index(js, []byte("LocaleText["))
   151  		if replacerIndex < 0 {
   152  			mixData = append(mixData, js...)
   153  			return
   154  		}
   155  		mixData = append(mixData, js[:replacerIndex]...)
   156  		js = js[replacerIndex:]
   157  
   158  		bracketIndex = bytes.IndexByte(js, ']')
   159  		var textIndex, err = strconv.ParseUint(string(js[11:bracketIndex]), 10, 8)
   160  		if err != nil {
   161  			// err = "Index numbers in desire file is not valid, double check your file for bad structures"
   162  		} else {
   163  			mixData = append(mixData, text[textIndex]...)
   164  		}
   165  
   166  		js = js[bracketIndex+1:]
   167  	}
   168  }