Swap-Aggregator-Subgraph/node_modules/assemblyscript/cli/asc.js
Richa-iitr d211083153 Revert "Revert "added handler""
This reverts commit c36ee8c5ca.
2022-07-03 07:30:05 +05:30

1491 lines
48 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @license
* Copyright 2020 Daniel Wirtz / The AssemblyScript Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview Compiler frontend for node.js
*
* Uses the low-level API exported from src/index.ts so it works with the compiler compiled to
* JavaScript as well as the compiler compiled to WebAssembly (eventually). Runs the sources
* directly through ts-node if distribution files are not present.
*
* Can also be packaged as a bundle suitable for in-browser use with the standard library injected
* in the build step. See dist/asc.js for the bundle and webpack.config.js for building details.
*/
/* global BUNDLE_VERSION, BUNDLE_LIBRARY, BUNDLE_DEFINITIONS */
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 dynrequire = typeof __webpack_require__ === "function"
? __non_webpack_require__
: require;
const WIN = process.platform === "win32";
const EOL = WIN ? "\r\n" : "\n";
const SEP = WIN ? "\\" : "/";
function toUpperSnakeCase(str) {
return str.replace(/-/g, "_").toUpperCase();
}
// Sets up an extension with its definition counterpart and relevant regexes.
function setupExtension(ext) {
if (!ext.startsWith(".")) ext = `.${ext}`;
return {
ext,
ext_d: `.d${ext}`,
re: new RegExp("\\" + ext + "$"),
re_d: new RegExp("\\.d\\" + ext + "$"),
re_except_d: new RegExp("^(?!.*\\.d\\" + ext + "$).*\\" + ext + "$"),
re_index: new RegExp("(?:^|[\\\\\\/])index\\" + ext + "$")
};
}
const defaultExtension = setupExtension(".ts");
// Proxy Binaryen's ready event
Object.defineProperty(exports, "ready", {
get() { return binaryen.ready; }
});
// Emscripten adds an `uncaughtException` listener to Binaryen that results in an additional
// useless code fragment on top of an actual error. suppress this:
if (process.removeAllListeners) {
process.removeAllListeners("uncaughtException");
}
// Use distribution files if present, otherwise run the sources directly.
function loadAssemblyScriptJS() {
var exports;
try {
// note that this case will always trigger in recent node.js versions for typical installs
// see: https://nodejs.org/api/packages.html#packages_self_referencing_a_package_using_its_name
exports = require("assemblyscript");
} catch (e) {
try { // `asc` on the command line (unnecessary in recent node)
exports = dynrequire("../dist/assemblyscript.js");
} catch (e) {
try { // `asc` on the command line without dist files (unnecessary in recent node)
dynrequire("ts-node").register({
project: path.join(__dirname, "..", "src", "tsconfig.json"),
skipIgnore: true,
compilerOptions: { target: "ES2016" }
});
dynrequire("../src/glue/js");
exports = dynrequire("../src");
} catch (e_ts) {
try { // `require("dist/asc.js")` in explicit browser tests
exports = dynrequire("./assemblyscript");
} catch (e) {
throw Error(`${e_ts.stack}\n---\n${e.stack}`);
}
}
}
}
return exports;
}
// Loads the specified bootstrapped Wasm binary of the compiler.
function loadAssemblyScriptWasm(binaryPath) {
const loader = require("../lib/loader/umd/index");
const rtrace = new (require("../lib/rtrace/umd/index").Rtrace)({
onerror(err, info) {
console.log(err, info);
},
getMemory() {
return exports.memory;
},
oncollect() {
var gcProfile = rtrace.gcProfile;
if (gcProfile && gcProfile.length && fs.writeFileSync) {
let timestamp = Date.now();
fs.writeFileSync(
`rtrace-gc-profile-${timestamp}.json`,
JSON.stringify(gcProfile)
);
fs.writeFileSync(
`rtrace-gc-profile-${timestamp}.csv`,
`time,memory,pause\n${gcProfile.join("\n")}`
);
}
}
});
var { exports } = loader.instantiateSync(fs.readFileSync(binaryPath), rtrace.install({ binaryen }));
if (exports._start) exports._start();
return exports;
}
/** Ensures that an object is a wrapper class instead of just a pointer. */
function __wrap(ptrOrObj, wrapperClass) {
if (typeof ptrOrObj === "number") {
return ptrOrObj === 0 ? null : wrapperClass.wrap(ptrOrObj);
}
return ptrOrObj;
}
var assemblyscript, __newString, __getString, __pin, __unpin, __collect;
function loadAssemblyScript() {
const wasmArg = process.argv.findIndex(arg => arg == "--wasm");
if (~wasmArg) {
let binaryPath = process.argv[wasmArg + 1];
process.argv.splice(wasmArg, 2);
assemblyscript = loadAssemblyScriptWasm(binaryPath);
__newString = assemblyscript.__newString;
__getString = assemblyscript.__getString;
__pin = assemblyscript.__pin;
__unpin = assemblyscript.__unpin;
__collect = assemblyscript.__collect;
} else {
assemblyscript = loadAssemblyScriptJS();
__newString = str => str;
__getString = ptr => ptr;
__pin = ptr => ptr;
__unpin = _ => undefined;
__collect = _ => undefined;
}
}
loadAssemblyScript();
/** Whether this is a webpack bundle or not. */
exports.isBundle = typeof BUNDLE_VERSION === "string";
/** AssemblyScript version. */
exports.version = exports.isBundle ? BUNDLE_VERSION : dynrequire("../package.json").version;
/** Available CLI options. */
exports.options = require("./asc.json");
/** Prefix used for library files. */
exports.libraryPrefix = __getString(assemblyscript.LIBRARY_PREFIX.valueOf());
/** Default Binaryen optimization level. */
exports.defaultOptimizeLevel = 3;
/** Default Binaryen shrink level. */
exports.defaultShrinkLevel = 0;
/** Bundled library files. */
exports.libraryFiles = exports.isBundle ? BUNDLE_LIBRARY : (() => { // set up if not a bundle
const libDir = path.join(__dirname, "..", "std", "assembly");
const bundled = {};
find
.files(libDir, defaultExtension.re_except_d)
.forEach(file => {
bundled[file.replace(defaultExtension.re, "")] = fs.readFileSync(path.join(libDir, file), "utf8");
});
return bundled;
})();
/** Bundled definition files. */
exports.definitionFiles = exports.isBundle ? BUNDLE_DEFINITIONS : (() => { // set up if not a bundle
const readDefinition = name => fs.readFileSync(
path.join(__dirname, "..", "std", name, `index${defaultExtension.ext_d}`),
"utf8"
);
return {
assembly: readDefinition("assembly"),
portable: readDefinition("portable")
};
})();
/** Convenience function that parses and compiles source strings directly. */
exports.compileString = (sources, options) => {
if (typeof sources === "string") sources = { [`input${defaultExtension.ext}`]: sources };
const output = Object.create({
stdout: createMemoryStream(),
stderr: createMemoryStream()
});
var argv = [
"--binaryFile", "binary",
"--textFile", "text",
];
Object.keys(options || {}).forEach(key => {
var val = options[key];
var opt = exports.options[key];
if (opt && opt.type === "b") {
if (val) argv.push(`--${key}`);
} else {
if (Array.isArray(val)) {
val.forEach(val => { argv.push(`--${key}`, String(val)); });
}
else argv.push(`--${key}`, String(val));
}
});
exports.main(argv.concat(Object.keys(sources)), {
stdout: output.stdout,
stderr: output.stderr,
readFile: name => Object.prototype.hasOwnProperty.call(sources, name) ? sources[name] : null,
writeFile: (name, contents) => { output[name] = contents; },
listFiles: () => []
});
return output;
};
/** Runs the command line utility using the specified arguments array. */
exports.main = function main(argv, options, callback) {
if (typeof options === "function") {
callback = options;
options = {};
} else if (!options) {
options = {};
}
// Bundle semantic version
let bundleMinorVersion = 0, bundleMajorVersion = 0, bundlePatchVersion = 0;
const versionParts = (exports.version || "").split(".");
if (versionParts.length === 3) {
bundleMajorVersion = parseInt(versionParts[0]) | 0;
bundleMinorVersion = parseInt(versionParts[1]) | 0;
bundlePatchVersion = parseInt(versionParts[2]) | 0;
}
const stdout = options.stdout || process.stdout;
const stderr = options.stderr || process.stderr;
const readFile = options.readFile || readFileNode;
const writeFile = options.writeFile || writeFileNode;
const listFiles = options.listFiles || listFilesNode;
const stats = options.stats || createStats();
let extension = defaultExtension;
// Output must be specified if not present in the environment
if (!stdout) throw Error("'options.stdout' must be specified");
if (!stderr) throw Error("'options.stderr' must be specified");
// Parse command line options but do not populate option defaults yet
const optionsResult = optionsUtil.parse(argv, exports.options, false);
let opts = optionsResult.options;
argv = optionsResult.arguments;
if (opts.noColors) {
colorsUtil.stdout.supported =
colorsUtil.stderr.supported = false;
} else {
colorsUtil.stdout = colorsUtil.from(stdout);
colorsUtil.stderr = colorsUtil.from(stderr);
}
// Check for unknown options
const unknownOpts = optionsResult.unknown;
if (unknownOpts.length) {
unknownOpts.forEach(arg => {
stderr.write(
`${colorsUtil.stderr.yellow("WARNING ")}Unknown option '${arg}'%{EOL}`
);
});
}
// Check for trailing arguments
const trailingArgv = optionsResult.trailing;
if (trailingArgv.length) {
stderr.write(
`${colorsUtil.stderr.yellow("WARNING ")}Unsupported trailing arguments: ${trailingArgv.join(" ")}${EOL}`
);
}
// Use default callback if none is provided
if (!callback) callback = function defaultCallback(err) {
var code = 0;
if (err) {
stderr.write(`${colorsUtil.stderr.red("FAILURE ")}${err.stack.replace(/^ERROR: /i, "")}${EOL}`);
code = 1;
}
return code;
};
// Just print the version if requested
if (opts.version) {
stdout.write(`Version ${exports.version}${EOL}`);
return callback(null);
}
// Use another extension if requested
if (typeof opts.extension === "string") {
if (/^\.?[0-9a-zA-Z]{1,14}$/.test(opts.extension)) {
extension = setupExtension(opts.extension);
} else {
return callback(Error(`Invalid extension: ${opts.extension}`));
}
}
// Set up base directory
const baseDir = path.normalize(opts.baseDir || ".");
// Check if a config file is present
let asconfigPath = optionsUtil.resolvePath(opts.config || "asconfig.json", baseDir);
let asconfigFile = path.basename(asconfigPath);
let asconfigDir = path.dirname(asconfigPath);
let asconfig = getAsconfig(asconfigFile, asconfigDir, readFile);
let asconfigHasEntries = asconfig != null && Array.isArray(asconfig.entries) && asconfig.entries.length;
// Print the help message if requested or no source files are provided
if (opts.help || (!argv.length && !asconfigHasEntries)) {
var out = opts.help ? stdout : stderr;
var color = opts.help ? colorsUtil.stdout : colorsUtil.stderr;
out.write([
color.white("SYNTAX"),
" " + color.cyan("asc") + " [entryFile ...] [options]",
"",
color.white("EXAMPLES"),
" " + color.cyan("asc") + " hello" + extension.ext,
" " + color.cyan("asc") + " hello" + extension.ext + " -b hello.wasm -t hello.wat",
" " + color.cyan("asc") + " hello1" + extension.ext + " hello2" + extension.ext + " -b -O > hello.wasm",
" " + color.cyan("asc") + " --config asconfig.json --target release",
"",
color.white("OPTIONS"),
].concat(
optionsUtil.help(exports.options, 24, EOL)
).join(EOL) + EOL);
return callback(null);
}
// I/O must be specified if not present in the environment
if (!fs.readFileSync) {
if (readFile === readFileNode) throw Error("'options.readFile' must be specified");
if (writeFile === writeFileNode) throw Error("'options.writeFile' must be specified");
if (listFiles === listFilesNode) throw Error("'options.listFiles' must be specified");
}
// Load additional options from asconfig.json
const seenAsconfig = new Set();
seenAsconfig.add(asconfigPath);
const target = opts.target || "release";
while (asconfig) {
// Merge target first
if (asconfig.targets) {
const targetOptions = asconfig.targets[target];
if (targetOptions) {
opts = optionsUtil.merge(exports.options, opts, targetOptions, asconfigDir);
}
}
// Merge general options
const generalOptions = asconfig.options;
if (generalOptions) {
opts = optionsUtil.merge(exports.options, opts, generalOptions, asconfigDir);
}
// Append entries
if (asconfig.entries) {
for (let entry of asconfig.entries) {
argv.push(optionsUtil.resolvePath(entry, asconfigDir));
}
}
// Look up extended asconfig and repeat
if (asconfig.extends) {
asconfigPath = optionsUtil.resolvePath(asconfig.extends, asconfigDir, true);
asconfigFile = path.basename(asconfigPath);
asconfigDir = path.dirname(asconfigPath);
if (seenAsconfig.has(asconfigPath)) break;
seenAsconfig.add(asconfigPath);
asconfig = getAsconfig(asconfigFile, asconfigDir, readFile);
} else {
break;
}
}
// Populate option defaults once user-defined options are set
optionsUtil.addDefaults(exports.options, opts);
// If showConfig print options and exit
if (opts.showConfig) {
stderr.write(JSON.stringify({
options: opts,
entries: argv
}, null, 2));
return callback(null);
}
// create a unique set of values
function unique(values) {
return [...new Set(values)];
}
// Set up options
var program;
const compilerOptions = __pin(assemblyscript.newOptions());
assemblyscript.setTarget(compilerOptions, 0);
assemblyscript.setNoAssert(compilerOptions, opts.noAssert);
assemblyscript.setExportMemory(compilerOptions, !opts.noExportMemory);
assemblyscript.setImportMemory(compilerOptions, opts.importMemory);
assemblyscript.setInitialMemory(compilerOptions, opts.initialMemory >>> 0);
assemblyscript.setMaximumMemory(compilerOptions, opts.maximumMemory >>> 0);
assemblyscript.setSharedMemory(compilerOptions, opts.sharedMemory);
assemblyscript.setImportTable(compilerOptions, opts.importTable);
assemblyscript.setExportTable(compilerOptions, opts.exportTable);
assemblyscript.setExplicitStart(compilerOptions, opts.explicitStart);
assemblyscript.setMemoryBase(compilerOptions, opts.memoryBase >>> 0);
assemblyscript.setTableBase(compilerOptions, opts.tableBase >>> 0);
assemblyscript.setSourceMap(compilerOptions, opts.sourceMap != null);
assemblyscript.setNoUnsafe(compilerOptions, opts.noUnsafe);
assemblyscript.setPedantic(compilerOptions, opts.pedantic);
assemblyscript.setLowMemoryLimit(compilerOptions, opts.lowMemoryLimit >>> 0);
assemblyscript.setExportRuntime(compilerOptions, opts.exportRuntime);
assemblyscript.setBundleVersion(compilerOptions, bundleMajorVersion, bundleMinorVersion, bundlePatchVersion);
if (!opts.stackSize && opts.runtime == "incremental") {
opts.stackSize = assemblyscript.DEFAULT_STACK_SIZE;
}
assemblyscript.setStackSize(compilerOptions, opts.stackSize);
// Instrument callback to perform GC
callback = (function(callback) {
return function wrappedCallback(err) {
__unpin(compilerOptions);
if (program) __unpin(program);
__collect();
return callback(err);
};
})(callback);
// Add or override aliases if specified
if (opts.use) {
let aliases = opts.use;
for (let i = 0, k = aliases.length; i < k; ++i) {
let part = aliases[i];
let p = part.indexOf("=");
if (p < 0) return callback(Error(`Global alias '${part}' is invalid.`));
let alias = part.substring(0, p).trim();
let name = part.substring(p + 1).trim();
if (!alias.length) {
return callback(Error(`Global alias '${part}' is invalid.`));
}
{
let aliasPtr = __pin(__newString(alias));
let namePtr = __newString(name);
assemblyscript.setGlobalAlias(compilerOptions, aliasPtr, namePtr);
__unpin(aliasPtr);
}
}
}
// Disable default features if specified
var features;
if ((features = opts.disable) != null) {
if (typeof features === "string") features = features.split(",");
for (let i = 0, k = features.length; i < k; ++i) {
let name = features[i].trim();
let flag = assemblyscript[`FEATURE_${toUpperSnakeCase(name)}`];
if (!flag) return callback(Error(`Feature '${name}' is unknown.`));
assemblyscript.disableFeature(compilerOptions, flag);
}
}
// Enable experimental features if specified
if ((features = opts.enable) != null) {
if (typeof features === "string") features = features.split(",");
for (let i = 0, k = features.length; i < k; ++i) {
let name = features[i].trim();
let flag = assemblyscript[`FEATURE_${toUpperSnakeCase(name)}`];
if (!flag) return callback(Error(`Feature '${name}' is unknown.`));
assemblyscript.enableFeature(compilerOptions, flag);
}
}
// Set up optimization levels
var optimizeLevel = 0;
var shrinkLevel = 0;
if (opts.optimize) {
optimizeLevel = exports.defaultOptimizeLevel;
shrinkLevel = exports.defaultShrinkLevel;
}
if (typeof opts.optimizeLevel === "number") optimizeLevel = opts.optimizeLevel;
if (typeof opts.shrinkLevel === "number") shrinkLevel = opts.shrinkLevel;
optimizeLevel = Math.min(Math.max(optimizeLevel, 0), 3);
shrinkLevel = Math.min(Math.max(shrinkLevel, 0), 2);
assemblyscript.setOptimizeLevelHints(compilerOptions, optimizeLevel, shrinkLevel);
// Initialize the program
program = __pin(assemblyscript.newProgram(compilerOptions));
// Collect transforms *constructors* from the `--transform` CLI flag as well
// as the `transform` option into the `transforms` array.
let transforms = [];
// `transform` option from `main()`
if (Array.isArray(options.transforms)) {
transforms.push(...options.transforms);
}
// `--transform` CLI flag
if (opts.transform) {
let tsNodeRegistered = false;
let transformArgs = unique(opts.transform);
for (let i = 0, k = transformArgs.length; i < k; ++i) {
let filename = transformArgs[i].trim();
if (!tsNodeRegistered && filename.endsWith(".ts")) { // ts-node requires .ts specifically
dynrequire("ts-node").register({
transpileOnly: true,
skipProject: true,
compilerOptions: { target: "ES2016" }
});
tsNodeRegistered = true;
}
try {
transforms.push(dynrequire(dynrequire.resolve(filename, {
paths: [baseDir, process.cwd()]
})));
} catch (e) {
return callback(e);
}
}
}
// Fix up the prototype of the transforms constructors and instantiate them.
try {
transforms = transforms.map(classOrModule => {
// Except if its a legacy module, just pass it through.
if (typeof classOrModule !== "function") {
return classOrModule;
}
Object.assign(classOrModule.prototype, {
program,
baseDir,
stdout,
stderr,
log: console.error,
readFile,
writeFile,
listFiles
});
return new classOrModule();
});
} catch (e) {
return callback(e);
}
function applyTransform(name, ...args) {
for (let i = 0, k = transforms.length; i < k; ++i) {
let transform = transforms[i];
if (typeof transform[name] === "function") {
try {
stats.transformCount++;
stats.transfromTime += measure(() => {
transform[name](...args);
});
} catch (e) {
return e;
}
}
}
}
// Parse library files
Object.keys(exports.libraryFiles).forEach(libPath => {
if (libPath.includes("/")) return; // in sub-directory: imported on demand
stats.parseCount++;
stats.parseTime += measure(() => {
let textPtr = __pin(__newString(exports.libraryFiles[libPath]));
let pathPtr = __newString(exports.libraryPrefix + libPath + extension.ext);
assemblyscript.parse(program, textPtr, pathPtr, false);
__unpin(textPtr);
});
});
let customLibDirs = [];
if (opts.lib) {
let lib = opts.lib;
if (typeof lib === "string") lib = lib.split(",");
customLibDirs.push(...lib.map(p => p.trim()));
customLibDirs = unique(customLibDirs); // `lib` and `customLibDirs` may include duplicates
for (let i = 0, k = customLibDirs.length; i < k; ++i) { // custom
let libDir = customLibDirs[i];
let libFiles;
if (libDir.endsWith(extension.ext)) {
libFiles = [ path.basename(libDir) ];
libDir = path.dirname(libDir);
} else {
libFiles = listFiles(libDir, baseDir) || [];
}
for (let j = 0, l = libFiles.length; j < l; ++j) {
let libPath = libFiles[j];
let libText = readFile(libPath, libDir);
if (libText == null) {
return callback(Error(`Library file '${libPath}' not found.`));
}
stats.parseCount++;
exports.libraryFiles[libPath.replace(extension.re, "")] = libText;
stats.parseTime += measure(() => {
let textPtr = __pin(__newString(libText));
let pathPtr = __newString(exports.libraryPrefix + libPath);
assemblyscript.parse(program, textPtr, pathPtr, false);
__unpin(textPtr);
});
}
}
}
opts.path = opts.path || [];
// Maps package names to parent directory
const packageMains = new Map();
const packageBases = new Map();
// Gets the file matching the specified source path, imported at the given dependee path
function getFile(internalPath, dependeePath) {
var sourceText = null; // text reported back to the compiler
var sourcePath = null; // path reported back to the compiler
const libraryPrefix = exports.libraryPrefix;
const libraryFiles = exports.libraryFiles;
// Try file.ext, file/index.ext, file.d.ext
if (!internalPath.startsWith(libraryPrefix)) {
if ((sourceText = readFile(sourcePath = internalPath + extension.ext, baseDir)) == null) {
if ((sourceText = readFile(sourcePath = internalPath + "/index" + extension.ext, baseDir)) == null) {
// portable d.ext: uses the .js file next to it in JS or becomes an import in Wasm
sourcePath = internalPath + extension.ext;
sourceText = readFile(internalPath + extension.ext_d, baseDir);
}
}
// Search library in this order: stdlib, custom lib dirs, paths
} else {
const plainName = internalPath.substring(libraryPrefix.length);
const indexName = `${plainName}/index`;
if (Object.prototype.hasOwnProperty.call(libraryFiles, plainName)) {
sourceText = libraryFiles[plainName];
sourcePath = libraryPrefix + plainName + extension.ext;
} else if (Object.prototype.hasOwnProperty.call(libraryFiles, indexName)) {
sourceText = libraryFiles[indexName];
sourcePath = libraryPrefix + indexName + extension.ext;
} else { // custom lib dirs
for (const libDir of customLibDirs) {
if ((sourceText = readFile(plainName + extension.ext, libDir)) != null) {
sourcePath = libraryPrefix + plainName + extension.ext;
break;
} else {
if ((sourceText = readFile(indexName + extension.ext, libDir)) != null) {
sourcePath = libraryPrefix + indexName + extension.ext;
break;
}
}
}
if (sourceText == null) { // paths
const match = internalPath.match(/^~lib\/((?:@[^/]+\/)?[^/]+)(?:\/(.+))?/); // ~lib/(pkg)/(path), ~lib/(@org/pkg)/(path)
if (match) {
const packageName = match[1];
const isPackageRoot = match[2] === undefined;
const filePath = isPackageRoot ? "index" : match[2];
const basePath = packageBases.has(dependeePath)
? packageBases.get(dependeePath)
: ".";
if (opts.traceResolution) {
stderr.write(`Looking for package '${packageName}' file '${filePath}' relative to '${basePath}'${EOL}`);
}
const paths = [];
const parts = path.resolve(baseDir, basePath).split(SEP);
for (let i = parts.length, k = WIN ? 1 : 0; i >= k; --i) {
if (parts[i - 1] !== "node_modules") {
paths.push(`${parts.slice(0, i).join(SEP)}${SEP}node_modules`);
}
}
for (const currentPath of paths.concat(...opts.path).map(p => path.relative(baseDir, p))) {
if (opts.traceResolution) {
stderr.write(` in ${path.join(currentPath, packageName)}${EOL}`);
}
let mainPath = "assembly";
if (packageMains.has(packageName)) { // use cached
mainPath = packageMains.get(packageName);
} else { // evaluate package.json
let jsonPath = path.join(currentPath, packageName, "package.json");
let jsonText = readFile(jsonPath, baseDir);
if (jsonText != null) {
try {
let json = JSON.parse(jsonText);
if (typeof json.ascMain === "string") {
mainPath = json.ascMain.replace(extension.re_index, "");
packageMains.set(packageName, mainPath);
}
} catch (e) { /* nop */ }
}
}
const mainDir = path.join(currentPath, packageName, mainPath);
const plainName = filePath;
if ((sourceText = readFile(path.join(mainDir, plainName + extension.ext), baseDir)) != null) {
sourcePath = `${libraryPrefix}${packageName}/${plainName}${extension.ext}`;
packageBases.set(sourcePath.replace(extension.re, ""), path.join(currentPath, packageName));
if (opts.traceResolution) {
stderr.write(` -> ${path.join(mainDir, plainName + extension.ext)}${EOL}`);
}
break;
} else if (!isPackageRoot) {
const indexName = `${filePath}/index`;
if ((sourceText = readFile(path.join(mainDir, indexName + extension.ext), baseDir)) !== null) {
sourcePath = `${libraryPrefix}${packageName}/${indexName}${extension.ext}`;
packageBases.set(sourcePath.replace(extension.re, ""), path.join(currentPath, packageName));
if (opts.traceResolution) {
stderr.write(` -> ${path.join(mainDir, indexName + extension.ext)}${EOL}`);
}
break;
}
}
}
}
}
}
}
// No such file
if (sourceText == null) return null;
return { sourceText, sourcePath };
}
// Parses the backlog of imported files after including entry files
function parseBacklog() {
var internalPath;
while ((internalPath = __getString(assemblyscript.nextFile(program)))) {
let file = getFile(internalPath, assemblyscript.getDependee(program, internalPath));
if (file) {
stats.parseCount++;
stats.parseTime += measure(() => {
let textPtr = __pin(__newString(file.sourceText));
let pathPtr = __newString(file.sourcePath);
assemblyscript.parse(program, textPtr, pathPtr, false);
__unpin(textPtr);
});
} else {
stats.parseTime += measure(() => {
let textPtr = __newString(null); // no need to pin
let pathPtr = __newString(internalPath + extension.ext);
assemblyscript.parse(program, textPtr, pathPtr, false);
});
}
}
var numErrors = checkDiagnostics(program, stderr, options.reportDiagnostic);
if (numErrors) {
const err = Error(`${numErrors} parse error(s)`);
err.stack = err.message; // omit stack
return callback(err);
}
}
// Include runtime before entry files so its setup runs first
{
let runtimeName = String(opts.runtime);
let runtimePath = `rt/index-${runtimeName}`;
let runtimeText = exports.libraryFiles[runtimePath];
if (runtimeText == null) {
runtimePath = runtimeName;
runtimeText = readFile(runtimePath + extension.ext, baseDir);
if (runtimeText == null) return callback(Error(`Runtime '${runtimeName}' not found.`));
} else {
runtimePath = `~lib/${runtimePath}`;
}
stats.parseCount++;
stats.parseTime += measure(() => {
let textPtr = __pin(__newString(runtimeText));
let pathPtr = __newString(runtimePath + extension.ext);
assemblyscript.parse(program, textPtr, pathPtr, true);
__unpin(textPtr);
});
}
// Include entry files
for (let i = 0, k = argv.length; i < k; ++i) {
const filename = argv[i];
let sourcePath = String(filename)
.replace(/\\/g, "/")
.replace(extension.re, "")
.replace(/[\\/]$/, "");
// Setting the path to relative path
sourcePath = path.isAbsolute(sourcePath)
? path.relative(baseDir, sourcePath).replace(/\\/g, "/")
: sourcePath;
// Try entryPath.ext, then entryPath/index.ext
let sourceText = readFile(sourcePath + extension.ext, baseDir);
if (sourceText == null) {
const path = `${sourcePath}/index${extension.ext}`;
sourceText = readFile(path, baseDir);
if (sourceText != null) sourcePath = path;
else sourcePath += extension.ext;
} else {
sourcePath += extension.ext;
}
stats.parseCount++;
stats.parseTime += measure(() => {
let textPtr = __pin(__newString(sourceText));
let pathPtr = __newString(sourcePath);
assemblyscript.parse(program, textPtr, pathPtr, true);
__unpin(textPtr);
});
}
// Parse entry files
{
let code = parseBacklog();
if (code) return code;
}
// Call afterParse transform hook
{
let error = applyTransform("afterParse", program.parser);
if (error) return callback(error);
}
// Parse additional files, if any
{
let code = parseBacklog();
if (code) return code;
}
// Print files and exit if listFiles
if (opts.listFiles) {
// FIXME: not a proper C-like API
stderr.write(program.sources.map(s => s.normalizedPath).sort().join(EOL) + EOL);
return callback(null);
}
// Pre-emptively initialize the program
stats.initializeCount++;
stats.initializeTime += measure(() => {
try {
assemblyscript.initializeProgram(program);
} catch (e) {
crash("initialize", e);
}
});
// Call afterInitialize transform hook
{
let error = applyTransform("afterInitialize", program);
if (error) return callback(error);
}
var module;
stats.compileCount++;
stats.compileTime += measure(() => {
try {
module = assemblyscript.compile(program);
} catch (e) {
crash("compile", e);
}
// From here on we are going to use Binaryen.js, except that we keep pass
// order as defined in the compiler.
if (typeof module === "number") { // Wasm
const original = assemblyscript.Module.wrap(module);
module = binaryen.wrapModule(original.ref);
module.optimize = function(...args) {
original.optimize(...args);
};
} else { // JS
const original = module;
module = binaryen.wrapModule(module.ref);
module.optimize = function(...args) {
original.optimize(...args);
};
}
});
var numErrors = checkDiagnostics(program, stderr, options.reportDiagnostic);
if (numErrors) {
if (module) module.dispose();
const err = Error(`${numErrors} compile error(s)`);
err.stack = err.message; // omit stack
return callback(err);
}
// Call afterCompile transform hook
{
let error = applyTransform("afterCompile", module);
if (error) return callback(error);
}
// Validate the module if requested
if (!opts.noValidate) {
stats.validateCount++;
let isValid;
stats.validateTime += measure(() => {
isValid = module.validate();
});
if (!isValid) {
module.dispose();
return callback(Error("validate error"));
}
}
// Set Binaryen-specific options
if (opts.trapMode === "clamp" || opts.trapMode === "js") {
stats.optimizeCount++;
stats.optimizeTime += measure(() => {
try {
module.runPasses([`trap-mode-${opts.trapMode}`]);
} catch (e) {
crash("runPasses", e);
}
});
} else if (opts.trapMode !== "allow") {
module.dispose();
return callback(Error("Unsupported trap mode"));
}
// Optimize the module
const debugInfo = opts.debug;
const converge = opts.converge;
const runPasses = [];
if (opts.runPasses) {
if (typeof opts.runPasses === "string") {
opts.runPasses = opts.runPasses.split(",");
}
if (opts.runPasses.length) {
opts.runPasses.forEach(pass => {
if (!runPasses.includes(pass = pass.trim())) {
runPasses.push(pass);
}
});
}
}
stats.optimizeTime += measure(() => {
stats.optimizeCount++;
try {
module.optimize(optimizeLevel, shrinkLevel, debugInfo);
} catch (e) {
crash("optimize", e);
}
try {
module.runPasses(runPasses);
} catch (e) {
crash("runPasses", e);
}
if (converge) {
let last;
try {
last = module.emitBinary();
} catch (e) {
crash("emitBinary (converge)", e);
}
do {
stats.optimizeCount++;
try {
module.optimize(optimizeLevel, shrinkLevel, debugInfo);
} catch (e) {
crash("optimize (converge)", e);
}
try {
module.runPasses(runPasses);
} catch (e) {
crash("runPasses (converge)", e);
}
let next;
try {
next = module.emitBinary();
} catch (e) {
crash("emitBinary (converge)", e);
}
if (next.length >= last.length) {
if (next.length > last.length) {
stderr.write(`Last converge was suboptimial.${EOL}`);
}
break;
}
last = next;
} while (true);
}
});
// Prepare output
if (!opts.noEmit) {
if (opts.outFile != null) {
if (opts.textFile == null && /\.was?t$/.test(opts.outFile)) {
opts.textFile = opts.outFile;
} else if (opts.jsFile == null && /\.js$/.test(opts.outFile)) {
opts.jsFile = opts.outFile;
} else if (opts.binaryFile == null) {
opts.binaryFile = opts.outFile;
}
}
let hasStdout = false;
let hasOutput = opts.textFile != null
|| opts.binaryFile != null
|| opts.jsFile != null
|| opts.tsdFile != null
|| opts.idlFile != null;
// Write binary
if (opts.binaryFile != null) {
let basename = path.basename(opts.binaryFile);
let sourceMapURL = opts.sourceMap != null
? opts.sourceMap.length
? opts.sourceMap
: `./${basename}.map`
: null;
let wasm;
stats.emitCount++;
stats.emitTime += measure(() => {
try {
wasm = module.emitBinary(sourceMapURL);
} catch (e) {
crash("emitBinary", e);
}
});
if (opts.binaryFile.length) {
writeFile(opts.binaryFile, wasm.binary, baseDir);
} else {
writeStdout(wasm.binary);
hasStdout = true;
}
// Post-process source map
if (wasm.sourceMap != "") {
if (opts.binaryFile.length) {
let map = JSON.parse(wasm.sourceMap);
map.sourceRoot = `./${basename}`;
let contents = [];
map.sources.forEach((name, index) => {
let text = assemblyscript.getSource(program, __newString(name.replace(extension.re, "")));
if (text == null) return callback(Error(`Source of file '${name}' not found.`));
contents[index] = text;
});
map.sourcesContent = contents;
writeFile(path.join(
path.dirname(opts.binaryFile),
path.basename(sourceMapURL)
).replace(/^\.\//, ""), JSON.stringify(map), baseDir);
} else {
stderr.write(`Skipped source map (stdout already occupied)${EOL}`);
}
}
}
// Write text (also fallback)
if (opts.textFile != null || !hasOutput) {
let out;
if (opts.textFile != null && opts.textFile.length) {
// use superset text format when extension is `.wast`.
// Otherwise use official stack IR format (wat).
let wastFormat = opts.textFile.endsWith(".wast");
stats.emitCount++;
stats.emitTime += measure(() => {
try {
out = wastFormat
? module.emitText()
: module.emitStackIR(true);
} catch (e) {
crash("emitText", e);
}
});
writeFile(opts.textFile, out, baseDir);
} else if (!hasStdout) {
stats.emitCount++;
stats.emitTime += measure(() => {
try {
out = module.emitStackIR(true);
} catch (e) {
crash("emitText", e);
}
});
writeStdout(out);
}
}
// Write WebIDL
if (opts.idlFile != null) {
let idl;
if (opts.idlFile.length) {
stats.emitCount++;
stats.emitTime += measure(() => {
try {
idl = assemblyscript.buildIDL(program);
} catch (e) {
crash("buildIDL", e);
}
});
writeFile(opts.idlFile, __getString(idl), baseDir);
} else if (!hasStdout) {
stats.emitCount++;
stats.emitTime += measure(() => {
try {
idl = assemblyscript.buildIDL(program);
} catch (e) {
crash("buildIDL", e);
}
});
writeStdout(__getString(idl));
hasStdout = true;
}
}
// Write TypeScript definition
if (opts.tsdFile != null) {
let tsd;
if (opts.tsdFile.length) {
stats.emitCount++;
stats.emitTime += measure(() => {
try {
tsd = assemblyscript.buildTSD(program);
} catch (e) {
crash("buildTSD", e);
}
});
writeFile(opts.tsdFile, __getString(tsd), baseDir);
} else if (!hasStdout) {
stats.emitCount++;
stats.emitTime += measure(() => {
try {
tsd = assemblyscript.buildTSD(program);
} catch (e) {
crash("buildTSD", e);
}
});
writeStdout(__getString(tsd));
hasStdout = true;
}
}
// Write JS (modifies the binary, so must be last)
if (opts.jsFile != null) {
let js;
if (opts.jsFile.length) {
stats.emitCount++;
stats.emitTime += measure(() => {
try {
js = module.emitAsmjs();
} catch (e) {
crash("emitJS", e);
}
});
writeFile(opts.jsFile, js, baseDir);
} else if (!hasStdout) {
stats.emitCount++;
stats.emitTime += measure(() => {
try {
js = module.emitAsmjs();
} catch (e) {
crash("emitJS", e);
}
});
writeStdout(js);
}
}
}
module.dispose();
if (opts.measure) {
printStats(stats, stderr);
}
return callback(null);
function readFileNode(filename, baseDir) {
let name = path.resolve(baseDir, filename);
try {
let text;
stats.readCount++;
stats.readTime += measure(() => {
text = fs.readFileSync(name, "utf8");
});
return text;
} catch (e) {
return null;
}
}
function writeFileNode(filename, contents, baseDir) {
try {
stats.writeCount++;
stats.writeTime += measure(() => {
const dirPath = path.resolve(baseDir, path.dirname(filename));
filename = path.basename(filename);
const outputFilePath = path.join(dirPath, filename);
if (!fs.existsSync(dirPath)) mkdirp(dirPath);
fs.writeFileSync(outputFilePath, contents);
});
return true;
} catch (e) {
return false;
}
}
function listFilesNode(dirname, baseDir) {
var files;
try {
stats.readCount++;
stats.readTime += measure(() => {
files = fs.readdirSync(path.join(baseDir, dirname))
.filter(file => extension.re_except_d.test(file));
});
return files;
} catch (e) {
return null;
}
}
function writeStdout(contents) {
if (!writeStdout.used) {
stats.writeCount++;
writeStdout.used = true;
}
stats.writeTime += measure(() => {
stdout.write(contents);
});
}
};
const toString = Object.prototype.toString;
function isObject(arg) {
return toString.call(arg) === "[object Object]";
}
function getAsconfig(file, baseDir, readFile) {
const contents = readFile(file, baseDir);
const location = path.join(baseDir, file);
if (!contents) return null;
// obtain the configuration
let config;
try {
config = JSON.parse(contents);
} catch(ex) {
throw new Error(`Asconfig is not valid json: ${location}`);
}
// validate asconfig shape
if (config.options && !isObject(config.options)) {
throw new Error(`Asconfig.options is not an object: ${location}`);
}
if (config.include && !Array.isArray(config.include)) {
throw new Error(`Asconfig.include is not an array: ${location}`);
}
if (config.targets) {
if (!isObject(config.targets)) {
throw new Error(`Asconfig.targets is not an object: ${location}`);
}
const targets = Object.keys(config.targets);
for (let i = 0; i < targets.length; i++) {
const target = targets[i];
if (!isObject(config.targets[target])) {
throw new Error(`Asconfig.targets.${target} is not an object: ${location}`);
}
}
}
if (config.extends && typeof config.extends !== "string") {
throw new Error(`Asconfig.extends is not a string: ${location}`);
}
return config;
}
exports.getAsconfig = getAsconfig;
/** Checks diagnostics emitted so far for errors. */
function checkDiagnostics(program, stderr, reportDiagnostic) {
var numErrors = 0;
do {
let diagnosticPtr = assemblyscript.nextDiagnostic(program);
if (!diagnosticPtr) break;
__pin(diagnosticPtr);
if (stderr) {
stderr.write(
__getString(assemblyscript.formatDiagnostic(diagnosticPtr, stderr.isTTY, true)) +
EOL + EOL
);
}
if (reportDiagnostic) {
const diagnostic = __wrap(diagnosticPtr, assemblyscript.DiagnosticMessage);
const range = __wrap(diagnostic.range, assemblyscript.Range);
const relatedRange = __wrap(diagnostic.relatedRange, assemblyscript.Range);
const rangeSource = range ? __wrap(range.source, assemblyscript.Source) : null;
const relatedRangeSource = relatedRange ? __wrap(relatedRange.source, assemblyscript.Source) : null;
reportDiagnostic({
message: __getString(diagnostic.message),
code: diagnostic.code,
category: diagnostic.category,
range: range ? {
start: range.start,
end: range.end,
source: rangeSource ? {
normalizedPath: __getString(rangeSource.normalizedPath)
} : null,
} : null,
relatedRange: relatedRange ? {
start: relatedRange.start,
end: relatedRange.end,
source: relatedRangeSource ? {
normalizedPath: __getString(relatedRangeSource.normalizedPath)
} : null
} : null
});
}
if (assemblyscript.isError(diagnosticPtr)) ++numErrors;
__unpin(diagnosticPtr);
} while (true);
return numErrors;
}
exports.checkDiagnostics = checkDiagnostics;
/** Creates an empty set of stats. */
function createStats() {
return {
readTime: 0,
readCount: 0,
writeTime: 0,
writeCount: 0,
parseTime: 0,
parseCount: 0,
initializeTime: 0,
initializeCount: 0,
compileTime: 0,
compileCount: 0,
emitTime: 0,
emitCount: 0,
validateTime: 0,
validateCount: 0,
optimizeTime: 0,
optimizeCount: 0,
transformTime: 0,
transformCount: 0
};
}
exports.createStats = createStats;
/** Measures the execution time of the specified function. */
function measure(fn) {
const start = process.hrtime();
fn();
const times = process.hrtime(start);
return times[0] * 1e9 + times[1];
}
exports.measure = measure;
function pad(str, len) {
while (str.length < len) str = ` ${str}`;
return str;
}
/** Formats a high resolution time to a human readable string. */
function formatTime(time) {
return time ? `${(time / 1e6).toFixed(3)} ms` : "n/a";
}
exports.formatTime = formatTime;
/** Formats and prints out the contents of a set of stats. */
function printStats(stats, output) {
const format = (time, count) => `${pad(formatTime(time), 12)} n=${count}`;
(output || process.stdout).write([
"I/O Read : " + format(stats.readTime, stats.readCount),
"I/O Write : " + format(stats.writeTime, stats.writeCount),
"Parse : " + format(stats.parseTime, stats.parseCount),
"Initialize : " + format(stats.initializeTime, stats.initializeCount),
"Compile : " + format(stats.compileTime, stats.compileCount),
"Emit : " + format(stats.emitTime, stats.emitCount),
"Validate : " + format(stats.validateTime, stats.validateCount),
"Optimize : " + format(stats.optimizeTime, stats.optimizeCount),
"Transform : " + format(stats.transformTime, stats.transformCount),
""
].join(EOL) + EOL);
}
exports.printStats = printStats;
var allocBuffer = typeof global !== "undefined" && global.Buffer
? global.Buffer.allocUnsafe || (len => new global.Buffer(len))
: len => new Uint8Array(len);
/** Creates a memory stream that can be used in place of stdout/stderr. */
function createMemoryStream(fn) {
var stream = [];
stream.write = function(chunk) {
if (fn) fn(chunk);
if (typeof chunk === "string") {
let buffer = allocBuffer(utf8.length(chunk));
utf8.write(chunk, buffer, 0);
chunk = buffer;
}
this.push(chunk);
};
stream.reset = function() {
stream.length = 0;
};
stream.toBuffer = function() {
var offset = 0, i = 0, k = this.length;
while (i < k) offset += this[i++].length;
var buffer = allocBuffer(offset);
offset = i = 0;
while (i < k) {
buffer.set(this[i], offset);
offset += this[i].length;
++i;
}
return buffer;
};
stream.toString = function() {
var buffer = this.toBuffer();
return utf8.read(buffer, 0, buffer.length);
};
return stream;
}
exports.createMemoryStream = createMemoryStream;
/** Compatible TypeScript compiler options for syntax highlighting etc. */
exports.tscOptions = {
alwaysStrict: true,
noImplicitAny: true,
noImplicitReturns: true,
noImplicitThis: true,
noEmitOnError: true,
strictNullChecks: true,
experimentalDecorators: true,
target: "esnext",
module: "commonjs",
noLib: true,
types: [],
allowJs: false
};
// Gracefully handle crashes
function crash(stage, e) {
const BAR = colorsUtil.red("▌ ");
console.error([
EOL,
BAR, "Whoops, the AssemblyScript compiler has crashed during ", stage, " :-(", EOL,
BAR, EOL,
BAR, "Here is a stack trace that may or may not be useful:", EOL,
BAR, EOL,
e.stack.replace(/^/mg, BAR), EOL,
BAR, EOL,
BAR, "If it refers to the dist files, try to 'npm install source-map-support' and", EOL,
BAR, "run again, which should then show the actual code location in the sources.", EOL,
BAR, EOL,
BAR, "If you see where the error is, feel free to send us a pull request. If not,", EOL,
BAR, "please let us know: https://github.com/AssemblyScript/assemblyscript/issues", EOL,
BAR, EOL,
BAR, "Thank you!", EOL
].join(""));
process.exit(1);
}