From ee94e2e3db05531183dd2f8fced880eaac0623d1 Mon Sep 17 00:00:00 2001 From: dcode Date: Wed, 22 Jul 2020 09:19:42 +0200 Subject: [PATCH 1/2] Bundle specific shims with asc instead of relying on defaults --- cli/asc.js | 10 +- cli/shim/README.md | 1 + cli/shim/fs.js | 1 + cli/shim/path.js | 529 ++++++++++++++++++++++++++++++++++++++++++++ cli/shim/process.js | 60 +++++ cli/util/mkdirp.js | 1 + package-lock.json | 6 - package.json | 1 - webpack.config.js | 15 +- 9 files changed, 608 insertions(+), 16 deletions(-) create mode 100644 cli/shim/README.md create mode 100644 cli/shim/fs.js create mode 100644 cli/shim/path.js create mode 100644 cli/shim/process.js diff --git a/cli/asc.js b/cli/asc.js index 14fcf11d61..7c3379ebd0 100644 --- a/cli/asc.js +++ b/cli/asc.js @@ -30,19 +30,19 @@ /* global BUNDLE_VERSION, BUNDLE_LIBRARY, BUNDLE_DEFINITIONS */ -// Use "." instead of "/" as cwd in browsers -if (process.browser) process.cwd = function() { return "."; }; - const fs = require("fs"); const path = require("path"); +const process = require("process"); // ensure shim + const utf8 = require("./util/utf8"); const colorsUtil = require("./util/colors"); const optionsUtil = require("./util/options"); const mkdirp = require("./util/mkdirp"); const find = require("./util/find"); +const binaryen = global.binaryen || (global.binaryen = require("binaryen")); + const EOL = process.platform === "win32" ? "\r\n" : "\n"; const SEP = process.platform === "win32" ? "\\" : "/"; -const binaryen = global.binaryen || (global.binaryen = require("binaryen")); // Sets up an extension with its definition counterpart and relevant regexes. function setupExtension(extension) { @@ -1109,8 +1109,6 @@ function createStats() { exports.createStats = createStats; -if (!process.hrtime) process.hrtime = require("browser-process-hrtime"); - /** Measures the execution time of the specified function. */ function measure(fn) { const start = process.hrtime(); diff --git a/cli/shim/README.md b/cli/shim/README.md new file mode 100644 index 0000000000..73b7e60d3c --- /dev/null +++ b/cli/shim/README.md @@ -0,0 +1 @@ +Shims used when bundling asc for browser usage. diff --git a/cli/shim/fs.js b/cli/shim/fs.js new file mode 100644 index 0000000000..f053ebf797 --- /dev/null +++ b/cli/shim/fs.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/cli/shim/path.js b/cli/shim/path.js new file mode 100644 index 0000000000..c3c60f53df --- /dev/null +++ b/cli/shim/path.js @@ -0,0 +1,529 @@ +const process = require("process"); // ensure shim + +// https://github.com/browserify/path-browserify v1.0.1 +// +// Copyright (c) 2013 James Halliday +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +function assertPath(path) { + if (typeof path !== 'string') { + throw new TypeError('Path must be a string. Received ' + JSON.stringify(path)); + } +} + +// Resolves . and .. elements in a path with directory names +function normalizeStringPosix(path, allowAboveRoot) { + var res = ''; + var lastSegmentLength = 0; + var lastSlash = -1; + var dots = 0; + var code; + for (var i = 0; i <= path.length; ++i) { + if (i < path.length) + code = path.charCodeAt(i); + else if (code === 47 /*/*/) + break; + else + code = 47 /*/*/; + if (code === 47 /*/*/) { + if (lastSlash === i - 1 || dots === 1) { + // NOOP + } else if (lastSlash !== i - 1 && dots === 2) { + if (res.length < 2 || lastSegmentLength !== 2 || res.charCodeAt(res.length - 1) !== 46 || res.charCodeAt(res.length - 2) !== 46) { + if (res.length > 2) { + var lastSlashIndex = res.lastIndexOf('/'); + if (lastSlashIndex !== res.length - 1) { + if (lastSlashIndex === -1) { + res = ''; + lastSegmentLength = 0; + } else { + res = res.slice(0, lastSlashIndex); + lastSegmentLength = res.length - 1 - res.lastIndexOf('/'); + } + lastSlash = i; + dots = 0; + continue; + } + } else if (res.length === 2 || res.length === 1) { + res = ''; + lastSegmentLength = 0; + lastSlash = i; + dots = 0; + continue; + } + } + if (allowAboveRoot) { + if (res.length > 0) + res += '/..'; + else + res = '..'; + lastSegmentLength = 2; + } + } else { + if (res.length > 0) + res += '/' + path.slice(lastSlash + 1, i); + else + res = path.slice(lastSlash + 1, i); + lastSegmentLength = i - lastSlash - 1; + } + lastSlash = i; + dots = 0; + } else if (code === 46 && dots !== -1) { + ++dots; + } else { + dots = -1; + } + } + return res; +} + +function _format(sep, pathObject) { + var dir = pathObject.dir || pathObject.root; + var base = pathObject.base || (pathObject.name || '') + (pathObject.ext || ''); + if (!dir) { + return base; + } + if (dir === pathObject.root) { + return dir + base; + } + return dir + sep + base; +} + +var posix = { + // path.resolve([from ...], to) + resolve: function resolve() { + var resolvedPath = ''; + var resolvedAbsolute = false; + var cwd; + + for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { + var path; + if (i >= 0) + path = arguments[i]; + else { + if (cwd === undefined) + cwd = process.cwd(); + path = cwd; + } + + assertPath(path); + + // Skip empty entries + if (path.length === 0) { + continue; + } + + resolvedPath = path + '/' + resolvedPath; + resolvedAbsolute = path.charCodeAt(0) === 47 /*/*/; + } + + // At this point the path should be resolved to a full absolute path, but + // handle relative paths to be safe (might happen when process.cwd() fails) + + // Normalize the path + resolvedPath = normalizeStringPosix(resolvedPath, !resolvedAbsolute); + + if (resolvedAbsolute) { + if (resolvedPath.length > 0) + return '/' + resolvedPath; + else + return '/'; + } else if (resolvedPath.length > 0) { + return resolvedPath; + } else { + return '.'; + } + }, + + normalize: function normalize(path) { + assertPath(path); + + if (path.length === 0) return '.'; + + var isAbsolute = path.charCodeAt(0) === 47 /*/*/; + var trailingSeparator = path.charCodeAt(path.length - 1) === 47 /*/*/; + + // Normalize the path + path = normalizeStringPosix(path, !isAbsolute); + + if (path.length === 0 && !isAbsolute) path = '.'; + if (path.length > 0 && trailingSeparator) path += '/'; + + if (isAbsolute) return '/' + path; + return path; + }, + + isAbsolute: function isAbsolute(path) { + assertPath(path); + return path.length > 0 && path.charCodeAt(0) === 47 /*/*/; + }, + + join: function join() { + if (arguments.length === 0) + return '.'; + var joined; + for (var i = 0; i < arguments.length; ++i) { + var arg = arguments[i]; + assertPath(arg); + if (arg.length > 0) { + if (joined === undefined) + joined = arg; + else + joined += '/' + arg; + } + } + if (joined === undefined) + return '.'; + return posix.normalize(joined); + }, + + relative: function relative(from, to) { + assertPath(from); + assertPath(to); + + if (from === to) return ''; + + from = posix.resolve(from); + to = posix.resolve(to); + + if (from === to) return ''; + + // Trim any leading backslashes + var fromStart = 1; + for (; fromStart < from.length; ++fromStart) { + if (from.charCodeAt(fromStart) !== 47 /*/*/) + break; + } + var fromEnd = from.length; + var fromLen = fromEnd - fromStart; + + // Trim any leading backslashes + var toStart = 1; + for (; toStart < to.length; ++toStart) { + if (to.charCodeAt(toStart) !== 47 /*/*/) + break; + } + var toEnd = to.length; + var toLen = toEnd - toStart; + + // Compare paths to find the longest common path from root + var length = fromLen < toLen ? fromLen : toLen; + var lastCommonSep = -1; + var i = 0; + for (; i <= length; ++i) { + if (i === length) { + if (toLen > length) { + if (to.charCodeAt(toStart + i) === 47 /*/*/) { + // We get here if `from` is the exact base path for `to`. + // For example: from='/foo/bar'; to='/foo/bar/baz' + return to.slice(toStart + i + 1); + } else if (i === 0) { + // We get here if `from` is the root + // For example: from='/'; to='/foo' + return to.slice(toStart + i); + } + } else if (fromLen > length) { + if (from.charCodeAt(fromStart + i) === 47 /*/*/) { + // We get here if `to` is the exact base path for `from`. + // For example: from='/foo/bar/baz'; to='/foo/bar' + lastCommonSep = i; + } else if (i === 0) { + // We get here if `to` is the root. + // For example: from='/foo'; to='/' + lastCommonSep = 0; + } + } + break; + } + var fromCode = from.charCodeAt(fromStart + i); + var toCode = to.charCodeAt(toStart + i); + if (fromCode !== toCode) + break; + else if (fromCode === 47 /*/*/) + lastCommonSep = i; + } + + var out = ''; + // Generate the relative path based on the path difference between `to` + // and `from` + for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) { + if (i === fromEnd || from.charCodeAt(i) === 47 /*/*/) { + if (out.length === 0) + out += '..'; + else + out += '/..'; + } + } + + // Lastly, append the rest of the destination (`to`) path that comes after + // the common path parts + if (out.length > 0) + return out + to.slice(toStart + lastCommonSep); + else { + toStart += lastCommonSep; + if (to.charCodeAt(toStart) === 47 /*/*/) + ++toStart; + return to.slice(toStart); + } + }, + + _makeLong: function _makeLong(path) { + return path; + }, + + dirname: function dirname(path) { + assertPath(path); + if (path.length === 0) return '.'; + var code = path.charCodeAt(0); + var hasRoot = code === 47 /*/*/; + var end = -1; + var matchedSlash = true; + for (var i = path.length - 1; i >= 1; --i) { + code = path.charCodeAt(i); + if (code === 47 /*/*/) { + if (!matchedSlash) { + end = i; + break; + } + } else { + // We saw the first non-path separator + matchedSlash = false; + } + } + + if (end === -1) return hasRoot ? '/' : '.'; + if (hasRoot && end === 1) return '//'; + return path.slice(0, end); + }, + + basename: function basename(path, ext) { + if (ext !== undefined && typeof ext !== 'string') throw new TypeError('"ext" argument must be a string'); + assertPath(path); + + var start = 0; + var end = -1; + var matchedSlash = true; + var i; + + if (ext !== undefined && ext.length > 0 && ext.length <= path.length) { + if (ext.length === path.length && ext === path) return ''; + var extIdx = ext.length - 1; + var firstNonSlashEnd = -1; + for (i = path.length - 1; i >= 0; --i) { + var code = path.charCodeAt(i); + if (code === 47 /*/*/) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + start = i + 1; + break; + } + } else { + if (firstNonSlashEnd === -1) { + // We saw the first non-path separator, remember this index in case + // we need it if the extension ends up not matching + matchedSlash = false; + firstNonSlashEnd = i + 1; + } + if (extIdx >= 0) { + // Try to match the explicit extension + if (code === ext.charCodeAt(extIdx)) { + if (--extIdx === -1) { + // We matched the extension, so mark this as the end of our path + // component + end = i; + } + } else { + // Extension does not match, so our result is the entire path + // component + extIdx = -1; + end = firstNonSlashEnd; + } + } + } + } + + if (start === end) end = firstNonSlashEnd;else if (end === -1) end = path.length; + return path.slice(start, end); + } else { + for (i = path.length - 1; i >= 0; --i) { + if (path.charCodeAt(i) === 47 /*/*/) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + start = i + 1; + break; + } + } else if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // path component + matchedSlash = false; + end = i + 1; + } + } + + if (end === -1) return ''; + return path.slice(start, end); + } + }, + + extname: function extname(path) { + assertPath(path); + var startDot = -1; + var startPart = 0; + var end = -1; + var matchedSlash = true; + // Track the state of characters (if any) we see before our first dot and + // after any path separator we find + var preDotState = 0; + for (var i = path.length - 1; i >= 0; --i) { + var code = path.charCodeAt(i); + if (code === 47 /*/*/) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + startPart = i + 1; + break; + } + continue; + } + if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // extension + matchedSlash = false; + end = i + 1; + } + if (code === 46) { + // If this is our first dot, mark it as the start of our extension + if (startDot === -1) + startDot = i; + else if (preDotState !== 1) + preDotState = 1; + } else if (startDot !== -1) { + // We saw a non-dot and non-path separator before our dot, so we should + // have a good chance at having a non-empty extension + preDotState = -1; + } + } + + if (startDot === -1 || end === -1 || + // We saw a non-dot character immediately before the dot + preDotState === 0 || + // The (right-most) trimmed path component is exactly '..' + preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) { + return ''; + } + return path.slice(startDot, end); + }, + + format: function format(pathObject) { + if (pathObject === null || typeof pathObject !== 'object') { + throw new TypeError('The "pathObject" argument must be of type Object. Received type ' + typeof pathObject); + } + return _format('/', pathObject); + }, + + parse: function parse(path) { + assertPath(path); + + var ret = { root: '', dir: '', base: '', ext: '', name: '' }; + if (path.length === 0) return ret; + var code = path.charCodeAt(0); + var isAbsolute = code === 47 /*/*/; + var start; + if (isAbsolute) { + ret.root = '/'; + start = 1; + } else { + start = 0; + } + var startDot = -1; + var startPart = 0; + var end = -1; + var matchedSlash = true; + var i = path.length - 1; + + // Track the state of characters (if any) we see before our first dot and + // after any path separator we find + var preDotState = 0; + + // Get non-dir info + for (; i >= start; --i) { + code = path.charCodeAt(i); + if (code === 47 /*/*/) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + startPart = i + 1; + break; + } + continue; + } + if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // extension + matchedSlash = false; + end = i + 1; + } + if (code === 46) { + // If this is our first dot, mark it as the start of our extension + if (startDot === -1) startDot = i;else if (preDotState !== 1) preDotState = 1; + } else if (startDot !== -1) { + // We saw a non-dot and non-path separator before our dot, so we should + // have a good chance at having a non-empty extension + preDotState = -1; + } + } + + if (startDot === -1 || end === -1 || + // We saw a non-dot character immediately before the dot + preDotState === 0 || + // The (right-most) trimmed path component is exactly '..' + preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) { + if (end !== -1) { + if (startPart === 0 && isAbsolute) ret.base = ret.name = path.slice(1, end);else ret.base = ret.name = path.slice(startPart, end); + } + } else { + if (startPart === 0 && isAbsolute) { + ret.name = path.slice(1, startDot); + ret.base = path.slice(1, end); + } else { + ret.name = path.slice(startPart, startDot); + ret.base = path.slice(startPart, end); + } + ret.ext = path.slice(startDot, end); + } + + if (startPart > 0) ret.dir = path.slice(0, startPart - 1);else if (isAbsolute) ret.dir = '/'; + + return ret; + }, + + sep: '/', + delimiter: ':', + win32: null, + posix: null +}; + +posix.posix = posix; + +module.exports = posix; diff --git a/cli/shim/process.js b/cli/shim/process.js new file mode 100644 index 0000000000..5d5ad32b5d --- /dev/null +++ b/cli/shim/process.js @@ -0,0 +1,60 @@ +module.exports = { + platform: "linux", + cwd() { + return "."; + }, + umask() { + return 0; + }, + hrtime +}; + +// https://github.com/kumavis/browser-process-hrtime v1.0.0 +// +// Copyright 2014 kumavis +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +var performance = global.performance || {}; +var performanceNow = + performance.now || + performance.mozNow || + performance.msNow || + performance.oNow || + performance.webkitNow || + function(){ return (new Date()).getTime(); }; + +function hrtime(previousTimestamp) { + var clocktime = performanceNow.call(performance) * 1e-3; + var seconds = Math.floor(clocktime); + var nanoseconds = Math.floor((clocktime % 1) * 1e9); + if (previousTimestamp) { + seconds = seconds - previousTimestamp[0]; + nanoseconds = nanoseconds - previousTimestamp[1]; + if (nanoseconds < 0) { + seconds--; + nanoseconds += 1e9; + } + } + return [ seconds, nanoseconds ]; +} diff --git a/cli/util/mkdirp.js b/cli/util/mkdirp.js index 59da6513f0..24d94043b0 100644 --- a/cli/util/mkdirp.js +++ b/cli/util/mkdirp.js @@ -26,6 +26,7 @@ const path = require("path"); const fs = require("fs"); +const process = require("process"); // ensure shim module.exports = function mkdirp(p, opts, made) { if (!opts || typeof opts !== "object") { diff --git a/package-lock.json b/package-lock.json index 982752d20a..c66a88d808 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1237,12 +1237,6 @@ "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", "dev": true }, - "browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, "browserify-aes": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", diff --git a/package.json b/package.json index fcd37a7bf1..250c176d4c 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "@types/node": "^14.0.23", "@typescript-eslint/eslint-plugin": "^3.6.1", "@typescript-eslint/parser": "^3.6.1", - "browser-process-hrtime": "^1.0.0", "diff": "^4.0.2", "eslint": "^7.4.0", "glob": "^7.1.6", diff --git a/webpack.config.js b/webpack.config.js index e63a7cfe84..cfc902c815 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -60,6 +60,7 @@ const lib = { }; // Build asc for browser usage +const shimDir = path.join(__dirname, "cli", "shim"); const bin = { context: path.join(__dirname, "cli"), entry: [ "./asc.js" ], @@ -70,10 +71,11 @@ const bin = { ], node: { "buffer": false, - "fs": "empty", + "fs": false, "global": true, "os": false, - "process": "mock", + "path": false, + "process": false, "crypto": false }, output: { @@ -103,7 +105,14 @@ const bin = { }, __dirname: JSON.stringify(".") }), - new webpack.IgnorePlugin(/\.\/src|package\.json|^(ts-node|glob)$/) + + // Ignored node-only dependencies + new webpack.IgnorePlugin(/\.\/src|package\.json|^(ts-node|glob)$/), + + // Browser shims + new webpack.NormalModuleReplacementPlugin(/^path$/, path.join(shimDir, "path")), + new webpack.NormalModuleReplacementPlugin(/^process$/, path.join(shimDir, "process")), + new webpack.NormalModuleReplacementPlugin(/^fs$/, path.join(shimDir, "fs")) ], optimization: { minimize: true, From 59e0697c45bcb10ab9adba4bc7be2f0fb55a9895 Mon Sep 17 00:00:00 2001 From: dcode Date: Wed, 22 Jul 2020 09:27:40 +0200 Subject: [PATCH 2/2] revert old fix, apply new fix?! --- cli/asc.js | 2 -- cli/shim/path.js | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/asc.js b/cli/asc.js index 7c3379ebd0..bf724ff16d 100644 --- a/cli/asc.js +++ b/cli/asc.js @@ -351,8 +351,6 @@ exports.main = function main(argv, options, callback) { // returns a relative path from baseDir function makeRelative(arg) { - // FIXME: see https://github.com/AssemblyScript/assemblyscript/issues/1398 - if (baseDir === ".") return arg; return path.relative(baseDir, arg); } diff --git a/cli/shim/path.js b/cli/shim/path.js index c3c60f53df..28978caf27 100644 --- a/cli/shim/path.js +++ b/cli/shim/path.js @@ -207,6 +207,8 @@ var posix = { if (from === to) return ''; + if (from === ".") return to; // FIX for 'odule.ts' (see issue #1398) + // Trim any leading backslashes var fromStart = 1; for (; fromStart < from.length; ++fromStart) {