diff --git a/build.js b/build.js index 74af2c0..41782fd 100644 --- a/build.js +++ b/build.js @@ -31,6 +31,7 @@ await build({ ), }, bundle: true, + treeShaking: true, logLevel: 'info', outdir: 'dist/', }); diff --git a/package-lock.json b/package-lock.json index ecee640..c1833d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,14 +10,13 @@ "license": "MIT", "devDependencies": { "@mercuryworkshop/bare-mux": "^2.0.1", + "astring": "^1.8.6", "css-tree": "^2.3.1", "esbuild": "^0.18.11", "eslint": "^8.28.0", - "esotope-hammerhead": "^0.6.4", "events": "^3.3.0", "idb": "^7.1.1", "meriyah": "^4.3.7", - "mime-db": "^1.52.0", "parse5": "^7.1.2", "prettier": "^2.8.0", "rimraf": "^5.0.1", @@ -536,12 +535,6 @@ "node": ">=14" } }, - "node_modules/@types/estree": { - "version": "0.0.46", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.46.tgz", - "integrity": "sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg==", - "dev": true - }, "node_modules/acorn": { "version": "8.8.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", @@ -609,6 +602,16 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "node_modules/astring": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.8.6.tgz", + "integrity": "sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==", + "dev": true, + "license": "MIT", + "bin": { + "astring": "bin/astring" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -914,15 +917,6 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/esotope-hammerhead": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/esotope-hammerhead/-/esotope-hammerhead-0.6.4.tgz", - "integrity": "sha512-QY4HXqvjLSFGoGgHvm3H1QUMNcpwnUpGRBaVVFWE5uqbPQh9HSWcA1YD7KwwL/IrgerDwZn00z5dtYT9Ot/C/A==", - "dev": true, - "dependencies": { - "@types/estree": "0.0.46" - } - }, "node_modules/espree": { "version": "9.4.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", @@ -1421,15 +1415,6 @@ "node": ">=10.4.0" } }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -2317,12 +2302,6 @@ "dev": true, "optional": true }, - "@types/estree": { - "version": "0.0.46", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.46.tgz", - "integrity": "sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg==", - "dev": true - }, "acorn": { "version": "8.8.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", @@ -2369,6 +2348,12 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "astring": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.8.6.tgz", + "integrity": "sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==", + "dev": true + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -2601,15 +2586,6 @@ "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true }, - "esotope-hammerhead": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/esotope-hammerhead/-/esotope-hammerhead-0.6.4.tgz", - "integrity": "sha512-QY4HXqvjLSFGoGgHvm3H1QUMNcpwnUpGRBaVVFWE5uqbPQh9HSWcA1YD7KwwL/IrgerDwZn00z5dtYT9Ot/C/A==", - "dev": true, - "requires": { - "@types/estree": "0.0.46" - } - }, "espree": { "version": "9.4.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", @@ -2980,12 +2956,6 @@ "integrity": "sha512-JAlSOUqFU/rmLy2CEdZO5hN5E5dyUj1f4AlRR4GCQMjfobvd5lcm9JLkrqq0MgVaLQ/Zur590A+0RyUZhj0b5A==", "dev": true }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true - }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", diff --git a/package.json b/package.json index 263f5c3..97bf694 100644 --- a/package.json +++ b/package.json @@ -22,14 +22,13 @@ }, "devDependencies": { "@mercuryworkshop/bare-mux": "^2.0.1", + "astring": "^1.8.6", "css-tree": "^2.3.1", "esbuild": "^0.18.11", "eslint": "^8.28.0", - "esotope-hammerhead": "^0.6.4", "events": "^3.3.0", "idb": "^7.1.1", "meriyah": "^4.3.7", - "mime-db": "^1.52.0", "parse5": "^7.1.2", "prettier": "^2.8.0", "rimraf": "^5.0.1", diff --git a/src/rewrite/css.js b/src/rewrite/css.js index 7c0821e..5835e6f 100644 --- a/src/rewrite/css.js +++ b/src/rewrite/css.js @@ -1,4 +1,4 @@ -import { parse, walk, generate } from 'css-tree'; + import EventEmitter from 'events'; class CSS extends EventEmitter { @@ -6,9 +6,6 @@ class CSS extends EventEmitter { super(); this.ctx = ctx; this.meta = ctx.meta; - this.parse = parse; - this.walk = walk; - this.generate = generate; } rewrite(str, options) { return this.recast(str, options, 'rewrite'); @@ -19,18 +16,8 @@ class CSS extends EventEmitter { recast(str, options, type) { if (!str) return str; str = new String(str).toString(); - try { - const ast = this.parse(str, { - ...options, - parseCustomProperty: true, - }); - this.walk(ast, (node) => { - this.emit(node.type, node, options, type); - }); - return this.generate(ast); - } catch (e) { - return str; - } + // no rewriting rn cry ab it + return str; } } diff --git a/src/rewrite/index.js b/src/rewrite/index.js index cf53f5f..8e149cb 100644 --- a/src/rewrite/index.js +++ b/src/rewrite/index.js @@ -3,7 +3,6 @@ import CSS from './css.js'; import JS from './js.js'; import setCookie from 'set-cookie-parser'; import { xor, base64, plain } from './codecs.js'; -import * as mimeTypes from './mime.js'; import { validateCookie, db, @@ -23,7 +22,6 @@ import { createHtmlInject, createJsInject, } from './rewrite.html.js'; -import { importStyle, url } from './rewrite.css.js'; //import { call, destructureDeclaration, dynamicImport, getProperty, importDeclaration, setProperty, sourceMethods, wrapEval, wrapIdentifier } from './rewrite.script.js'; import { dynamicImport, @@ -157,9 +155,6 @@ class Ultraviolet { attributes(this); text(this); injectHead(this); - // CSS - url(this); - importStyle(this); // JS importDeclaration(this); dynamicImport(this); @@ -187,7 +182,6 @@ class Ultraviolet { return this.js.source.bind(this.js); } static codec = { xor, base64, plain }; - static mime = mimeTypes; static setCookie = setCookie; static openDB = openDB; static BareClient = BareClient; diff --git a/src/rewrite/js.js b/src/rewrite/js.js index 2189cef..6bb7b1d 100644 --- a/src/rewrite/js.js +++ b/src/rewrite/js.js @@ -1,6 +1,6 @@ import { parseScript } from 'meriyah'; // import { parse } from 'acorn-hammerhead'; -import { generate } from 'esotope-hammerhead'; +import { generate } from 'astring'; import EventEmitter from 'events'; class JS extends EventEmitter { diff --git a/src/rewrite/mime.js b/src/rewrite/mime.js deleted file mode 100644 index faf5195..0000000 --- a/src/rewrite/mime.js +++ /dev/null @@ -1,169 +0,0 @@ -import db from 'mime-db'; - -const EXTRACT_TYPE_REGEXP = /^\s*([^;\s]*)(?:;|\s|$)/; -const TEXT_TYPE_REGEXP = /^text\//i; -const extensions = Object.create(null); -const types = Object.create(null); -const charsets = { lookup: charset }; - -// Populate the extensions/types maps -populateMaps(extensions, types); - -/** - * Get the default charset for a MIME type. - * - * @param {string} type - * @return {boolean|string} - */ - -function charset(type) { - if (!type || typeof type !== 'string') { - return false; - } - - // TODO: use media-typer - const match = EXTRACT_TYPE_REGEXP.exec(type); - const mime = match && db[match[1].toLowerCase()]; - - if (mime && mime.charset) { - return mime.charset; - } - - // default text/* to utf-8 - if (match && TEXT_TYPE_REGEXP.test(match[1])) { - return 'UTF-8'; - } - - return false; -} - -/** - * Create a full Content-Type header given a MIME type or extension. - * - * @param {string} str - * @return {boolean|string} - */ - -function contentType(str) { - // TODO: should this even be in this module? - if (!str || typeof str !== 'string') { - return false; - } - - let mime = str.indexOf('/') === -1 ? lookup(str) : str; - - if (!mime) { - return false; - } - - // TODO: use content-type or other module - if (mime.indexOf('charset') === -1) { - const detected = charset(mime); - if (detected) mime += '; charset=' + detected.toLowerCase(); - } - - return mime; -} - -/** - * Get the default extension for a MIME type. - * - * @param {string} type - * @return {boolean|string} - */ - -function extension(type) { - if (!type || typeof type !== 'string') { - return false; - } - - // TODO: use media-typer - const match = EXTRACT_TYPE_REGEXP.exec(type); - - // get extensions - const exts = match && extensions[match[1].toLowerCase()]; - - if (!exts || !exts.length) { - return false; - } - - return exts[0]; -} - -/** - * Lookup the MIME type for a file path/extension. - * - * @param {string} path - * @return {boolean|string} - */ - -function lookup(path) { - if (!path || typeof path !== 'string') { - return false; - } - - // get the extension ("ext" or ".ext" or full path) - const extension = extname('x.' + path) - .toLowerCase() - .slice(1); - - if (!extension) { - return false; - } - - return types[extension] || false; -} - -/** - * Populate the extensions and types maps. - * @private - */ - -function populateMaps(extensions, types) { - // source preference (least -> most) - const preference = ['nginx', 'apache', undefined, 'iana']; - - for (const type in db) { - const mime = db[type]; - const exts = mime.extensions; - - if (!exts || !exts.length) { - return; - } - - // mime -> extensions - extensions[type] = exts; - - // extension -> mime - for (let i = 0; i < exts.length; i++) { - const extension = exts[i]; - - if (types[extension]) { - const from = preference.indexOf(db[types[extension]].source); - const to = preference.indexOf(mime.source); - - if ( - types[extension] !== 'application/octet-stream' && - (from > to || - (from === to && - types[extension].substr(0, 12) === 'application/')) - ) { - // skip the remapping - continue; - } - } - - // set the extension -> mime - types[extension] = type; - } - } -} - -function extname(path = '') { - if (!path.includes('.')) return ''; - const map = path.split('.'); - - return '.' + map[map.length - 1]; -} - -export { charset, charsets, contentType, extension, lookup }; diff --git a/src/rewrite/rewrite.css.js b/src/rewrite/rewrite.css.js deleted file mode 100644 index 59b12c2..0000000 --- a/src/rewrite/rewrite.css.js +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @typedef {import('./index').default} Ultraviolet - */ - -/** - * - * @param {Ultraviolet} ctx - */ -function url(ctx) { - const { css } = ctx; - css.on('Url', (node, data, type) => { - node.value = - type === 'rewrite' - ? ctx.rewriteUrl(node.value) - : ctx.sourceUrl(node.value); - }); -} - -/** - * - * @param {Ultraviolet} ctx - */ -function importStyle(ctx) { - const { css } = ctx; - css.on('Atrule', (node, data, type) => { - if (node.name !== 'import') return false; - const { data: url } = node.prelude.children.head; - // Already handling Url's - if (url.type === 'Url') return false; - url.value = - type === 'rewrite' - ? ctx.rewriteUrl(url.value) - : ctx.sourceUrl(url.value); - }); -} - -export { url, importStyle }; diff --git a/src/rewrite/rewrite.script.js b/src/rewrite/rewrite.script.js index a9d1dde..3cae824 100644 --- a/src/rewrite/rewrite.script.js +++ b/src/rewrite/rewrite.script.js @@ -1,5 +1,3 @@ -import { Syntax } from 'esotope-hammerhead'; - /** * @typedef {import('./index').default} Ultraviolet */ @@ -108,7 +106,7 @@ function property(ctx) { !node.computed && node.property.name === '__uv$setSource' && type === 'source' && - node.parent.type === Syntax.CallExpression + node.parent.type === "CallExpression" ) { const { parent, property } = node; data.changes.push({ @@ -137,57 +135,57 @@ function identifier(ctx) { const { parent } = node; if (!['location', 'eval', 'parent', 'top'].includes(node.name)) return false; - if (parent.type === Syntax.VariableDeclarator && parent.id === node) + if (parent.type === "VariableDeclarator" && parent.id === node) return false; if ( - (parent.type === Syntax.AssignmentExpression || - parent.type === Syntax.AssignmentPattern) && + (parent.type === "AssignmentExpression" || + parent.type === "AssignmentPattern") && parent.left === node ) return false; if ( - (parent.type === Syntax.FunctionExpression || - parent.type === Syntax.FunctionDeclaration) && + (parent.type === "FunctionExpression" || + parent.type === "FunctionDeclaration") && parent.id === node ) return false; if ( - parent.type === Syntax.MemberExpression && + parent.type === "MemberExpression" && parent.property === node && !parent.computed ) return false; if ( node.name === 'eval' && - parent.type === Syntax.CallExpression && + parent.type === "CallExpression" && parent.callee === node ) return false; - if (parent.type === Syntax.Property && parent.key === node) + if (parent.type === "Property" && parent.key === node) return false; if ( - parent.type === Syntax.Property && + parent.type === "Property" && parent.value === node && parent.shorthand ) return false; if ( - parent.type === Syntax.UpdateExpression && + parent.type === "UpdateExpression" && (parent.operator === '++' || parent.operator === '--') ) return false; if ( - (parent.type === Syntax.FunctionExpression || - parent.type === Syntax.FunctionDeclaration || - parent.type === Syntax.ArrowFunctionExpression) && + (parent.type === "FunctionExpression" || + parent.type === "FunctionDeclaration" || + parent.type === "ArrowFunctionExpression") && parent.params.indexOf(node) !== -1 ) return false; - if (parent.type === Syntax.MethodDefinition) return false; - if (parent.type === Syntax.ClassDeclaration) return false; - if (parent.type === Syntax.RestElement) return false; - if (parent.type === Syntax.ExportSpecifier) return false; - if (parent.type === Syntax.ImportSpecifier) return false; + if (parent.type === "MethodDefinition") return false; + if (parent.type === "ClassDeclaration") return false; + if (parent.type === "RestElement") return false; + if (parent.type === "ExportSpecifier") return false; + if (parent.type === "ImportSpecifier") return false; data.changes.push({ start: node.start, @@ -232,12 +230,12 @@ function wrapEval(ctx) { */ function importDeclaration(ctx) { const { js } = ctx; - js.on(Syntax.Literal, (node, data, type) => { + js.on("Literal", (node, data, type) => { if ( !( - (node.parent.type === Syntax.ImportDeclaration || - node.parent.type === Syntax.ExportAllDeclaration || - node.parent.type === Syntax.ExportNamedDeclaration) && + (node.parent.type === "ImportDeclaration" || + node.parent.type === "ExportAllDeclaration" || + node.parent.type === "ExportNamedDeclaration") && node.parent.source === node ) ) @@ -260,7 +258,7 @@ function importDeclaration(ctx) { */ function dynamicImport(ctx) { const { js } = ctx; - js.on(Syntax.ImportExpression, (node, data, type) => { + js.on("ImportExpression", (node, data, type) => { if (type !== 'rewrite') return false; data.changes.push({ // pass script URL to dynamicImport @@ -294,7 +292,7 @@ function unwrap(ctx) { { if ( !node.arguments || - node.parent.type !== Syntax.MemberExpression || + node.parent.type !== "MemberExpression" || node.parent.property !== node ) return false; @@ -351,9 +349,9 @@ function unwrap(ctx) { } function isWrapped(node) { - if (node.type !== Syntax.MemberExpression) return false; + if (node.type !== "MemberExpression") return false; if (node.property.name === 'rewrite' && isWrapped(node.object)) return true; - if (node.object.type !== Syntax.Identifier || node.object.name !== '__uv') + if (node.object.type !== "Identifier" || node.object.name !== '__uv') return false; if (!['js', '$get', '$wrap', 'rewriteUrl'].includes(node.property.name)) return false; diff --git a/src/uv.sw.js b/src/uv.sw.js index 80af907..58ab794 100644 --- a/src/uv.sw.js +++ b/src/uv.sw.js @@ -236,12 +236,8 @@ class UVServiceWorker extends Ultraviolet.EventEmitter { break; case 'iframe': case 'document': - if ( - isHtml( - ultraviolet.meta.url, - responseCtx.headers['content-type'] || '' - ) - ) { + console.log(responseCtx.headers["content-type"]) + if (responseCtx.headers["content-type"].startsWith("text/html")) { responseCtx.body = ultraviolet.rewriteHtml( await response.text(), { @@ -261,6 +257,9 @@ class UVServiceWorker extends Ultraviolet.EventEmitter { } ); } + break; + default: + break; } } @@ -356,15 +355,6 @@ class RequestContext { } } -function isHtml(url, contentType = '') { - return ( - ( - Ultraviolet.mime.contentType(contentType || url.pathname) || - 'text/html' - ).split(';')[0] === 'text/html' - ); -} - class HookEvent { #intercepted; #returnValue;