// FralaParser gets the directory contents of tests/design (if it exists) and parse the files with Frala. func FralaParser(rootDirectory string, files []string) { if len(rootDirectory) != 0 && rootDirectory != "/" { // If the rootDirectory has content but NOT / rootDirectory += "/" // Append / to end of rootDirectory var fileNamesWithoutDir []string // Define filesWithoutDir as an empty []string that'll contain names of files without the directory string languagesToRecurse := []string{frala.Config.DefaultLanguage} // Set languagesToRecurse to a string slicen with Default Language by default if len(frala.Config.Languages) != 0 { // If pre-defined languages have been set languagesToRecurse = frala.Config.Languages // Set languagesToRecurse to the languages defined } for _, fileName := range files { // For each file in files fileNamesWithoutDir = append(fileNamesWithoutDir, filepath.Base(fileName)) // Append only the file name } for _, language := range languagesToRecurse { // For each language frala.Config.DefaultLanguage = language // Change DefaultLanguage in Frala to language frala.Config.Direction = frala.GetDirection(frala.Config.DefaultLanguage) // Ensure we have an accurate Direction against the updated DefaultLanguage listOfParseResponses := frala.MultiParse(files) // Parse all the HTML files in tests/design, return the ParseResponses for fileName, parseResponse := range listOfParseResponses { // For each file and parseResponse in listOfParseResponses if len(parseResponse.Content) != 0 && parseResponse.Error == nil { // If there is content returned from the parsing and there is no error codeutilsShared.WriteOrUpdateFile(rootDirectory+language+"/"+filepath.Base(fileName), []byte(parseResponse.Content), codeutilsShared.UniversalFileMode) // Update the file in lang specific design dir } } CompressHTML(rootDirectory+language, fileNamesWithoutDir) // Compress all the HTML files provided in this language directory } for _, fileName := range fileNamesWithoutDir { // For each file in fileNamesWithoutDir os.Remove(rootDirectory + fileName) // Remove the file in tests/design now that we have compressed forms in each individual language folder in tests/design } } }
// MinifyJavaScript minifies the JavaScript using Google Closure Compiler and then proceed to attempt to provide a zopfli compressed version. func MinifyJavaScript() error { var minifyError error if codeutilsShared.ExecutableExists("ccjs") { // If the ccjs executable exists fmt.Println("Minifying " + projectConfig.Name + " compiled JavaScript.") closureArgs := []string{ // Define closureArgs as "build/" + lowercaseProjectName + ".js", // Yes, I like to compress things. "--compilation_level=SIMPLE_OPTIMIZATIONS", // Simple optimizations "--warning_level=QUIET", // Shush you... } closureOutput := codeutilsShared.ExecCommand("ccjs", closureArgs, false) // Run Google Closure Compiler and store the output in closureOutput codeutilsShared.WriteOrUpdateFile("build/"+lowercaseProjectName+".min.js", []byte(closureOutput), codeutilsShared.UniversalFileMode) // Write or update the minified JS file content to build/lowercaseProjectName.min.js if codeutilsShared.ExecutableExists("zopfli") { // If zopfli exists codeutilsShared.ExecCommand("zopfli", []string{"build/" + lowercaseProjectName + ".min.js"}, false) // Have zopfli run and gzip the contents } } else { // If ccjs does not exist minifyError = errors.New("ccjs" + executableNotInstalled) } return minifyError }
// BootstrapProject assists in the bootstrap of a project. func BootstrapProject(projectName string) { var projectConfig codeutilsShared.ProjectConfig // Define projectConfig as a ProjectConfig struct from codeutilsShared projectConfig.Name = projectName // Set the Name to projectName contentTypesString := codeutilsShared.InputMessage("Please input the content types of this project, separated by commas") if contentTypesString != "" { // If the cocontentTypesStringntentTypes is not an empty string contentTypesString = strings.Replace(contentTypesString, " ", "", -1) // Remove any whitespace from contentTypesString contentTypesString = strings.ToLower(contentTypesString) // Lowercase all content contentTypes := strings.Split(contentTypesString, ",") // Split contentTypesString by , into contentTypes sort.Strings(contentTypes) // Sort the contentTypes projectConfig.ContentTypes = contentTypes // Set ContentTypes to sorted contentTypes for _, contentType := range contentTypes { // For each contentType in contentTypes fmt.Println("----- Configuring " + contentType + " -----") switch contentType { case "go": projectConfig.Go = GoCompilerOptionsPrompt() // Define Go's GoCompilerOptions as the GoCompilerOptions provided by GoCompilerOptionsPrompt case "html": // If this is HTML contenttype projectConfig.HTML = HTMLCompilerOptionsPrompt() // Define HTML's HTMLCompilerOptions as the HTMLCompilerOptions provided by HTMLCompilerOptionsPrompt projectConfig.UsesTests = true case "less": // If this is LESS contenttype projectConfig.LESS = LESSCompilerOptionsPrompt() // Define LESS's LESSCompilerOptions as the LESSCompilerOptions case "typescript": // If this is TypeScript contenttype projectConfig.TypeScript = TypeScriptCompilerOptionsPrompt() // Define TypeScript's TypeScriptCompilerOptions as one provided by TypeScriptCompilerOptionsPrompt } codeutilsShared.OutputStatus(true, "Configured "+contentType+".") fmt.Println("") // Force new-line } CreateFolderStructure(projectConfig) // Create the folder structure if necessary codeutilsShared.OutputStatus(true, "Created folder structure for project.") // Save config projectConfigBytes, _ := json.MarshalIndent(projectConfig, "", "\t") // Convert projectConfig to projectConfigBytes codeutilsShared.WriteOrUpdateFile("build/config.json", projectConfigBytes, codeutilsShared.UniversalFileMode) // Write the config to build/config codeutilsShared.OutputStatus(true, "Saved config.") } else { // If the contentTypes is an empty string fmt.Println("No content types provided for project creation.") } }
// CompressHTML compresses the HTML files provided func CompressHTML(directory string, files []string) error { var compressError error htmlMinifierFlags := []string{ // Oh god I am so sorry for all the flags "--case-sensitive", // Ensure case sensitivity for custom HTML tags "--collapse-whitespace", // Collapse any whitespace "--remove-comments", // Remove comments "--remove-comments-from-cdata", // Same as above but from CDATA "--remove-redundant-attributes", // Fix your damn HTML, no need for redundancies "--remove-script-type-attributes", // Remove script type attribute "--remove-style-link-type-attributes", // Remove style and link tag type attribute } if codeutilsShared.ExecutableExists("html-minifier") { // If the minifier exists if codeutilsShared.IsDir(directory) { // If the directory provided indeed exists if len(files) != 0 { // If there was files passed replacer := regexp.MustCompile(`"{{?\s?(type=")?\s(\w+)?\s(src="[^>]+)`) // Search for instances of messed up quoting due to html-minifier for _, file := range files { // For each file in files fmt.Println("Compressing " + file + " in " + directory) file = directory + "/" + file // Prepend the directory fileSpecificFlags := htmlMinifierFlags // Assign fileSpecificFlags flags as initially the same as htmlMinifierFlags fileSpecificFlags = append(fileSpecificFlags, []string{file}...) // Specify file to minify compressedFileContent := codeutilsShared.ExecCommand("html-minifier", fileSpecificFlags, false) // Run the html-minifier fixedContent := replacer.ReplaceAllString(compressedFileContent, `"{{ $1$2" $3 }}"`) // $1 is type, $2 is the type value, $3 is src+lang codeutilsShared.WriteOrUpdateFile(file, []byte(fixedContent), 0755) // Update the file contents } } else { // If there was no files passed fmt.Println("No files provided.") } } else { // If the directory provided is not, in fact, a directory fmt.Println(directory + " is not a directory.") } } else { // If the minifier does not exist compressError = errors.New("html-minifier" + executableNotInstalled) } return compressError }
// LESSBranchCompiler compiles individual branches of the Go source tree into selective CSS files func LESSBranchCompiler(lessBranchOptions codeutilsShared.LESSBranchOptions) { lessCompileFlags := []string{ "--clean-css", // Clean the CSS (such as minification, comment removal, so forth) "--no-color", "--no-ie-compat", // Disable IE Compatibility "--no-js", "--strict-math=on", // Do not process math } if lessBranchOptions.UseGlob { // If we should use globbing lessCompileFlags = append(lessCompileFlags, []string{"--glob"}...) // Provide --glob } if len(lessBranchOptions.AdditionalCompileOptions) != 0 { // If there was Additional Compile Options to pass lessCompileFlags = append(lessCompileFlags, lessBranchOptions.AdditionalCompileOptions...) } writeFileName, _ := codeutilsShared.FindClosestFile("src/less/" + lowercaseProjectName + ".less") // Define writeFileName as the file name we'll be compiling lessCompileFlags = append(lessCompileFlags, []string{writeFileName}...) commandOutput := codeutilsShared.ExecCommand("lessc", lessCompileFlags, false) // Run the less compiler errorIndex := strings.Index(commandOutput, "Error") if (errorIndex > 12) || (errorIndex == -1) { // If there was no initial error (any error string beyond a certain point should be assumed to be a part of the program) uniqueFileName := strings.Replace(filepath.Base(writeFileName), ".less", "", -1) if lessBranchOptions.UniqueHash { // If we should be using a unique hash uniqueFileName += "-" + codeutilsShared.Sha512Sum(commandOutput, 1)[0:12] // Append first 12 characters of hash } uniqueFileName += ".css" // Append .css codeutilsShared.WriteOrUpdateFile("build/"+uniqueFileName, []byte(commandOutput), codeutilsShared.UniversalFileMode) // Write to build folder codeutilsShared.CopyFile("build/"+uniqueFileName, "tests/design/css/"+uniqueFileName) // Copy from build folder to css folder } else { fmt.Println(commandOutput) } }