// 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 }
// GoBranchCompiler compiles individual branches of the Go source tree into selective binaries func GoBranchCompiler(goBranchOptions codeutilsShared.GoBranchOptions) { commandArgs := []string{"build"} // Set commandArgs to build if !goBranchOptions.DoInstall { // If we are not going to do an install (if we're creating a binary) commandArgs = append(commandArgs, []string{"-o", "build/" + goBranchOptions.BinaryName}...) // Redefine commandArgs as generating a binary as opposed to just compiling source } accurateSources := []string{} // Define accurateSources as an updated string array where each source in SourcesToInclude represents an accurate path for _, source := range goBranchOptions.SourcesToInclude { // For each source if strings.Contains(source, "*.go") { // If we are getting all the go files in a dir directoryOfFiles := filepath.Dir(source) // Get the directory of the files dirFileStruct, dirFileOpenError := os.Open(directoryOfFiles) // Open the directory and assign any error to dirFileOpenError if dirFileOpenError == nil { // If we successfully opened the directory directoryContents, _ := dirFileStruct.Readdir(-1) // Read everything in the directory, returns []os.FileInfo for _, fileInfoStruct := range directoryContents { if !fileInfoStruct.IsDir() && strings.HasSuffix(fileInfoStruct.Name(), ".go") { // If this is not a directory and ends with .go accurateSources = append(accurateSources, []string{directoryOfFiles + "/" + fileInfoStruct.Name()}...) // Append the file } } } else { // If we failed to open the directory fmt.Println("Failed to open: " + directoryOfFiles) } } else { // If we are adding a specific Go file absolutePath, _ := filepath.Abs(source) // Get the absolute patch of the source accurateSources = append(accurateSources, []string{absolutePath}...) // Append the absolute patch } } commandArgs = append(commandArgs, accurateSources...) // Append the accurate sources goCompilerOutput := codeutilsShared.ExecCommand("go", commandArgs, false) if strings.Contains(goCompilerOutput, ".go") || strings.Contains(goCompilerOutput, "# command") { // If running the go build shows there are obvious issues fmt.Println(goCompilerOutput) } else { // If there was no obvious issues fmt.Println("Build successful.") if goBranchOptions.DoInstall { // If we're building a package using this branch fmt.Println("Installing.") installOutput := codeutilsShared.ExecCommand("go", []string{"install"}, false) // Run go but using install rather than build if installOutput != "" { // If there was output by install fmt.Println(installOutput) } } } }
// InstallDependencies installs from either the system's package manager or npm func InstallDependencies(packager string, dependencies []string) string { var installResponse string if ((packager == "system") && (SystemPackager != "unknown")) || (packager == "npm") { // If the packager is system and known or NPM commandFlag := []string{"install"} // Set primative "install" if packager == "system" { // If this is the system packager packager = SystemPackager // Change packager to SystemPackager commandFlag = append(commandFlag, []string{"-y"}...) // Set to -y to auto-install } else { // If this is NPM commandFlag = append(commandFlag, []string{"--global"}...) // Install globally NPM packages } commandFlag = append(commandFlag, dependencies...) // Append the packages installResponse = codeutilsShared.ExecCommand(packager, commandFlag, true) // Call ExecCommand with packager and commandFlag } return installResponse }
// 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) } }
// CompileTypeScript compiles Typescript into Javascript and ensure JavaScript is minified and optimized func CompileTypeScript() error { var compileError error if codeutilsShared.ExecutableExists("tsc") { // If the tsc executable exists if codeutilsShared.IsDir("src/typescript") { // If src/typescript is a valid directory if !strings.HasPrefix(projectConfig.TypeScript.Target, "ES") { // If it either an empty string or does not begin with ES projectConfig.TypeScript.Target = "ES5" // Default to ES5 } typescriptFileName, _ := codeutilsShared.FindClosestFile("src/typescript/" + lowercaseProjectName + ".ts") // Define typescriptFileName as the closest file name to the one we're providing baseFileName := strings.Replace(filepath.Base(typescriptFileName), ".ts", "", -1) // Set baseFileName to typescript file name but with .ts removed typescriptCompileFlags := []string{ // Define typescriptCompileFlags as the following options "--declaration", // Create a declaration file "--forceConsistentCasingInFileNames", // Enforce consistency in file names "--noFallthroughCasesInSwitch", // Disallow fallthrough cases in switches "--noImplicitReturns", // Disallow implicit returns "--outFile", "build/" + baseFileName + ".js", // Output a single JS file in the build dir "--removeComments", // Remove comments "--target", projectConfig.TypeScript.Target, // Set the target typescriptFileName, // Append the .ts name } commandOutput := codeutilsShared.ExecCommand("tsc", typescriptCompileFlags, false) // Call execCommand and get its commandOutput if !strings.Contains(commandOutput, "error TS") { // If tsc did not report any errors if projectConfig.TypeScript.MinifyContent { // If we should minify the content minifyFailure := MinifyJavaScript() // Call the minification func, set any error to minifyFailure if minifyFailure == nil { // If there was no error minifying minifyFileName := baseFileName + ".min.js" if projectConfig.TypeScript.UseLibreJSHeader && (projectConfig.TypeScript.LibreJSLicense != "") { // If we should use the LibreJSHeader and the license value is set var finalMinifiedContent string // Define finalMinifiedContent as the content we get from AddLicense finalMinifiedContent, compileError = librejsgopher.AddLicense(projectConfig.TypeScript.LibreJSLicense, "build/"+minifyFileName, true) // Add the requested license to the JS file, return content if (compileError == nil) && projectConfig.TypeScript.UniqueHash { // If there was no issue adding the license and we should be using a unique hash uniqueFileName := baseFileName + "-" + codeutilsShared.Sha512Sum(finalMinifiedContent, 1)[0:12] + ".min.js" // Append first 12 characters of hash os.Rename("build/"+minifyFileName, "build/"+uniqueFileName) // Move the file to one with a unique file name minifyFileName = uniqueFileName // Change minifyFileName to uniqueName } } if projectConfig.UsesTests { // If we are using tests compileError = codeutilsShared.CopyFile("build/"+baseFileName+".js", "tests/design/js/"+baseFileName+".js") // Copy over the non-minified JS to the test js folder compileError = codeutilsShared.CopyFile("build/"+minifyFileName, "tests/design/js/"+minifyFileName) // Copy over the minified JS from build to the test js folder } } else { // If there was an error minifying compileError = minifyFailure // Set compileError to the minifyFailure } } } else { // If tsc did report errors compileError = errors.New(commandOutput) // Set compileError to the commandOutput } } else { // If src/typescript is not a valid directory compileError = errors.New("typescript" + dirDoesNotExistInSrc) } } else { // If the typescript compiler is not installed on this system compileError = errors.New("tsc" + executableNotInstalled) } return compileError }