Advertisement
captaindavepdx

Untitled

Aug 10th, 2019
321
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Swift 12.56 KB | None | 0 0
  1. //
  2. //  SingleFile.swift
  3. //  SingleFile
  4. //
  5. //  Created by David Littlefield on 8/5/19.
  6. //  Copyright © 2019 David Littlefield. All rights reserved.
  7. //
  8.  
  9. import Cocoa
  10. import Foundation
  11.  
  12. class SingleFile {
  13.    
  14.     static let shared = SingleFile()
  15.    
  16.     let javaScript = JavaScript.shared
  17.     let fileManager = FileManager.default
  18.    
  19.     var libraryFilePaths = [
  20.         "/index.js",
  21.         "/lib/hooks/content/content-hooks-web.js",
  22.         "/lib/hooks/content/content-hooks.js",
  23.         "/lib/hooks/content/content-hooks-frames-web.js",
  24.         "/lib/hooks/content/content-hooks-frames.js",
  25.         "/lib/fetch/content/content-fetch-resources.js",
  26.         "/lib/frame-tree/content/content-frame-tree.js",
  27.         "/lib/lazy/content/content-lazy-loader.js",
  28.         "/lib/single-file/single-file-util.js",
  29.         "/lib/single-file/single-file-helper.js",
  30.         "/lib/single-file/vendor/css-tree.js",
  31.         "/lib/single-file/vendor/html-srcset-parser.js",
  32.         "/lib/single-file/vendor/css-minifier.js",
  33.         "/lib/single-file/vendor/css-font-property-parser.js",
  34.         "/lib/single-file/vendor/css-media-query-parser.js",
  35.         "/lib/single-file/modules/html-minifier.js",
  36.         "/lib/single-file/modules/css-fonts-minifier.js",
  37.         "/lib/single-file/modules/css-fonts-alt-minifier.js",
  38.         "/lib/single-file/modules/css-matched-rules.js",
  39.         "/lib/single-file/modules/css-medias-alt-minifier.js",
  40.         "/lib/single-file/modules/css-rules-minifier.js",
  41.         "/lib/single-file/modules/html-images-alt-minifier.js",
  42.         "/lib/single-file/modules/html-serializer.js",
  43.         "/lib/single-file/single-file-core.js",
  44.         "/lib/single-file/single-file.js"
  45.     ]
  46.    
  47.     var optionsFilePath = [
  48.         "/extension/core/bg/config.js"
  49.     ]
  50.    
  51.     var singleFileFilePath = [
  52.         "/cli/back-ends/puppeteer.js"
  53.     ]
  54.    
  55.     var folderContent = [
  56.         "demo",
  57.         "extension",
  58.         "LICENSE",
  59.         "privacy.md",
  60.         "faq.md",
  61.         "index.js",
  62.         "cli",
  63.         "README.MD",
  64.         ".gitignore",
  65.         ".github",
  66.         "manifest.json",
  67.         ".eslintrc.js",
  68.         "lib",
  69.         "_locales",
  70.         "build-extension.sh"
  71.     ]
  72.    
  73.     init() {}
  74.    
  75.     func convert() {
  76.         convertLibrary()
  77.         convertOptions()
  78.         convertSingleFile()
  79.         removeDirectory()
  80.     }
  81.    
  82.     private func convertLibrary() {
  83.         convertContentHooksWeb()
  84.         convertContentHooks()
  85.         convertContentHooksFramesWeb()
  86.         convertContentFetchResources()
  87.         convertIndex()
  88.         convertFiles()
  89.         mergeFiles()
  90.     }
  91.    
  92.     private func convertContentHooksWeb() {
  93.         let filePath = libraryFilePaths[1]
  94.         let defaultStart = "(() => {"
  95.         let defaultEnd = "})();"
  96.         let customStart = "var contentHooksWeb = `"
  97.         let customEnd = "`"
  98.         javaScript.replace(javaScript: defaultStart, withJavaScript: customStart, inPath: filePath)
  99.         javaScript.replace(javaScript: defaultEnd, withJavaScript: customEnd, inPath: filePath)
  100.         javaScript.removeNewLines(inPath: filePath)
  101.     }
  102.    
  103.     private func convertContentHooks() {
  104.         let filePath = libraryFilePaths[2]
  105.         let defaultStart = """
  106.        if (this.browser && browser.runtime && browser.runtime.getURL) {
  107.            scriptElement.src = browser.runtime.getURL("/lib/hooks/content/content-hooks-web.js");
  108.            scriptElement.async = false;
  109.        } else if (this.singlefile.lib.getFileContent) {
  110.            scriptElement.textContent = this.singlefile.lib.getFileContent("/lib/hooks/content/content-hooks-web.js");
  111.        }
  112.        """
  113.         let customStart = ""
  114.         let defaultEnd = "scriptElement.async = false;"
  115.         let customEnd = "scriptElement.textContent = contentHooksWeb;"
  116.         javaScript.replace(javaScript: defaultStart, withJavaScript: customStart, inPath: filePath)
  117.         javaScript.insert(javaScript: customEnd, afterJavaScript: defaultEnd, inPath: filePath)
  118.         javaScript.removeNewLines(inPath: filePath)
  119.     }
  120.    
  121.     private func convertContentHooksFramesWeb() {
  122.         let filePath = libraryFilePaths[3]
  123.         let defaultStart = "(() => {"
  124.         let defaultEnd = "})();"
  125.         let customStart = "var contentHooksFramesWeb = `"
  126.         let customEnd = "`"
  127.         javaScript.replace(javaScript:defaultStart, withJavaScript: customStart, inPath: filePath)
  128.         javaScript.replace(javaScript: defaultEnd, withJavaScript: customEnd, inPath: filePath)
  129.         javaScript.removeNewLines(inPath: filePath)
  130.     }
  131.    
  132.     private func convertContentHooksFramesFile() {
  133.         let filePath = libraryFilePaths[4]
  134.         let defaultStart = """
  135.        if (this.browser && browser.runtime && browser.runtime.getURL) {
  136.            scriptElement.src = browser.runtime.getURL("/lib/hooks/content/content-hooks-frames-web.js");
  137.            scriptElement.async = false;
  138.        } else if (this.singlefile.lib.getFileContent) {
  139.            scriptElement.textContent = this.singlefile.lib.getFileContent("/lib/hooks/content/content-hooks-frames-web.js");
  140.        }
  141.        """
  142.         let customStart = ""
  143.         let defaultEnd = "scriptElement.async = false;"
  144.         let customEnd = "scriptElement.textContent = contentHooksFramesWeb;"
  145.         javaScript.replace(javaScript: defaultStart, withJavaScript: customStart, inPath: filePath)
  146.         javaScript.insert(javaScript: customEnd, afterJavaScript: defaultEnd, inPath: filePath)
  147.         javaScript.removeNewLines(inPath: filePath)
  148.     }
  149.    
  150.     private func convertContentFetchResources() {
  151.         let filePath = libraryFilePaths[5]
  152.         let defaultStart = """
  153.        const FETCH_REQUEST_EVENT = "single-file-request-fetch";
  154.        const FETCH_RESPONSE_EVENT = "single-file-response-fetch";
  155.        """
  156.         let customStart = ""
  157.         let defaultMiddle1 = """
  158.        this.singlefile.lib.fetch.content.resources = this.singlefile.lib.fetch.content.resources || (() => {
  159.        """
  160.         let customMiddle1 = "const pendingMessages = new Map();"
  161.         let defaultMiddle2 = "response = await hostFetch(url);"
  162.         let customMiddle2 = "return nativeFetch(url);"
  163.         let defaultMiddle3 = "catch (error) {"
  164.         let customMiddle3 = "return nativeFetch(url);"
  165.         let customEnd1 = "}"
  166.         let customEnd2 = "},"
  167.         let customEnd3 = """
  168.        callbackFetch: message => {
  169.            const callbacks = pendingMessages.get(message.url);
  170.            if (callbacks) {
  171.                pendingMessages.delete(message.url);
  172.                if (message.error) {
  173.                    callbacks.forEach(callback => callback.reject(message.error));
  174.                } else {
  175.                    const data = {
  176.                        status: message.status,
  177.                        headers: { get: name => message.headers[name] },
  178.                        arrayBuffer: async () => new Uint8Array(message.body).buffer
  179.                    };
  180.                    callbacks.forEach(callback => callback.resolve(data));
  181.                }
  182.            }
  183.        }
  184.        """
  185.         let customEnd4 = "};"
  186.         let customEnd5 = """
  187.        function nativeFetch(url) {
  188.            return new Promise((resolve, reject) => {
  189.                webkit.messageHandlers.performHttpRequest.postMessage(url);
  190.                let callbacks = pendingMessages.get(url);
  191.                if (!callbacks) {
  192.                    callbacks = [];
  193.                    pendingMessages.set(url, callbacks);
  194.                }
  195.                callbacks.push({ resolve, reject });
  196.            });
  197.        }
  198.        """
  199.         let customEnd6 = "})();"
  200.         javaScript.replace(javaScript: defaultStart, withJavaScript: customStart, inPath: filePath)
  201.         javaScript.insert(javaScript: customMiddle1, afterJavaScript: defaultMiddle1, inPath: filePath)
  202.         javaScript.replace(javaScript: defaultMiddle2, withJavaScript: customMiddle2, inPath: filePath)
  203.         javaScript.trim(javaScript: defaultMiddle3, toEnd: true, inPath: filePath)
  204.         javaScript.insert(javaScript: customMiddle3, afterJavaScript: defaultMiddle3, inPath: filePath)
  205.         javaScript.insert(javaScript: customEnd1, atEnd: true, inPath: filePath)
  206.         javaScript.insert(javaScript: customEnd2, atEnd: true, inPath: filePath)
  207.         javaScript.insert(javaScript: customEnd3, atEnd: true, inPath: filePath)
  208.         javaScript.insert(javaScript: customEnd4, atEnd: true, inPath: filePath)
  209.         javaScript.insert(javaScript: customEnd5, atEnd: true, inPath: filePath)
  210.         javaScript.insert(javaScript: customEnd6, atEnd: true, inPath: filePath)
  211.         javaScript.removeNewLines(inPath: filePath)
  212.     }
  213.    
  214.     private func convertIndex() {
  215.         let filePath = libraryFilePaths[0]
  216.         let defaultStart = "this.singlefile = this.singlefile || {"
  217.         let customStart = "var singlefile = {"
  218.         javaScript.replace(javaScript: defaultStart, withJavaScript: customStart, inPath: filePath)
  219.         javaScript.removeNewLines(inPath: filePath)
  220.     }
  221.    
  222.     private func convertFiles() {
  223.         let filePaths = libraryFilePaths
  224.         for index in 1 ..< filePaths.count {
  225.             let filePath = filePaths[index]
  226.             let defaultStart = "this.singlefile"
  227.             let customStart = "window.singlefile"
  228.             javaScript.replace(javaScript: defaultStart, withJavaScript: customStart, inPath: filePath)
  229.             javaScript.removeNewLines(inPath: filePath)
  230.         }
  231.     }
  232.    
  233.     private func mergeFiles() {
  234.         let directoryPath = fileManager.currentDirectoryPath
  235.         let filePaths = libraryFilePaths
  236.         var string = ""
  237.         for index in 0 ..< filePaths.count {
  238.             let filePath = directoryPath + filePaths[index]
  239.             let source = try! String(contentsOfFile: filePath, encoding: .utf8)
  240.             string.append(contentsOf: source)
  241.             string.append(contentsOf: "\n\n")
  242.             if index == filePaths.count - 1 {
  243.                 javaScript.save(asFileName: "library.js", inPath: filePath)
  244.             }
  245.         }
  246.     }
  247.    
  248.     private func convertOptions() {
  249.         let filePath: String = optionsFilePath[0]
  250.         let defaultStart: String = "const DEFAULT_CONFIG = {"
  251.         let defaultEnd: String = "};"
  252.         javaScript.trim(javaScript: defaultStart, fromStart: true, inPath: filePath)
  253.         javaScript.trim(javaScript: defaultEnd, toEnd: true, inPath: filePath)
  254.         javaScript.replace(javaScript: defaultStart, withJavaScript: "", inPath: filePath)
  255.         javaScript.replace(javaScript: defaultEnd, withJavaScript: "", inPath: filePath)
  256.     }
  257.    
  258.     private func saveOptions() {
  259.         let directoryPath: String = fileManager.currentDirectoryPath
  260.         let filePath: String = directoryPath + optionsFilePath[0]
  261.         let customStart: String = "var options = { "
  262.         let customEnd: String = " }"
  263.         let source: String = try! String(contentsOfFile: filePath, encoding: .utf8)
  264.         var lines: [String] = source.components(separatedBy: ",")
  265.         lines = lines.map({ $0.trimmingCharacters(in: .whitespacesAndNewlines) })
  266.         var options: String = lines.joined(separator: ",\n")
  267.         options = customStart + options + customEnd
  268.         defaults.set(options, forKey: "defaultOptions")
  269.         defaults.set(nil, forKey: "customOptions")
  270.         javaScript.save(asFileName: "options.js", inPath: filePath)
  271.     }
  272.  
  273.     private func convertSingleFile() {
  274.         let filePath = singleFileFilePath[0]
  275.         let defaultStart = "return await page.evaluate(async options => {"
  276.         let defaultEnd = "}, options);"
  277.         let customStart = "async function runSingleFile() {"
  278.         let customEnd =  "webkit.messageHandlers.websiteHasBeenSaved.postMessage(html);"
  279.         let defaultMiddle = "return await singleFile.getPageData();"
  280.         let customMiddle = "var html = (await singleFile.getPageData()).content;"
  281.         javaScript.trim(javaScript: defaultStart, fromStart: true, inPath: filePath)
  282.         javaScript.trim(javaScript: defaultEnd, toEnd: true, inPath: filePath)
  283.         javaScript.replace(javaScript: defaultMiddle, withJavaScript: customMiddle, inPath: filePath)
  284.         javaScript.replace(javaScript: defaultStart, withJavaScript: customStart, inPath: filePath)
  285.         javaScript.replace(javaScript: defaultEnd, withJavaScript: customEnd, inPath: filePath)
  286.         javaScript.insert(javaScript: "}", atEnd: true, inPath: filePath)
  287.         javaScript.save(asFileName: "singlefile.js", inPath: filePath)
  288.     }
  289.    
  290.     private func removeDirectory() {
  291.        
  292.     }
  293. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement