diff --git a/cli/asc.d.ts b/cli/asc.d.ts index 3244b4e80b..7957ac7c2f 100644 --- a/cli/asc.d.ts +++ b/cli/asc.d.ts @@ -56,7 +56,7 @@ export interface MemoryStream extends OutputStream { } /** Compiler options. */ -interface CompilerOptions { +export interface CompilerOptions { /** Prints just the compiler's version and exits. */ version?: boolean; /** Prints the help message and exits. */ @@ -146,7 +146,7 @@ interface CompilerOptions { } /** Compiler API options. */ -interface APIOptions { +export interface APIOptions { /** Standard output stream to use. */ stdout?: OutputStream; /** Standard error stream to use. */ diff --git a/cli/asc.js b/cli/asc.js index 14fcf11d61..f66ec687b1 100644 --- a/cli/asc.js +++ b/cli/asc.js @@ -193,8 +193,9 @@ exports.main = function main(argv, options, callback) { if (!stdout) throw Error("'options.stdout' must be specified"); if (!stderr) throw Error("'options.stderr' must be specified"); - const opts = optionsUtil.parse(argv, exports.options); - let args = opts.options; + const opts = optionsUtil.parse(argv, exports.options, false); + let args = optionsUtil.addDefaults(exports.options, opts.options); + let cliArgs = opts.options; argv = opts.arguments; if (args.noColors) { @@ -280,11 +281,14 @@ exports.main = function main(argv, options, callback) { const seenAsconfig = new Set(); seenAsconfig.add(path.join(baseDir, args.config)); + // First find all parent configs and add them each to the front + let entries = new Set(); while (asconfig) { - // merge target first, then merge options, then merge extended asconfigs + // First merge targets if (asconfig.targets && asconfig.targets[target]) { - args = optionsUtil.merge(exports.options, asconfig.targets[target], args); + cliArgs = optionsUtil.merge(exports.options, cliArgs, asconfig.targets[target]); } + if (asconfig.options) { if (asconfig.options.transform) { // ensure that a transform's path is relative to the current config @@ -298,22 +302,20 @@ exports.main = function main(argv, options, callback) { return p; }); } - args = optionsUtil.merge(exports.options, args, asconfig.options); + cliArgs = optionsUtil.merge(exports.options, cliArgs, asconfig.options); } - + // entries are added to the compilation if (asconfig.entries) { for (const entry of asconfig.entries) { - argv.push( - path.isAbsolute(entry) + entries.add( + path.relative(baseDir, path.isAbsolute(entry) ? entry // the entry is relative to the asconfig directory : path.join(asconfigDir, entry) - ); + )); } } - - // asconfig "extends" another config, merging options of it's parent if (asconfig.extends) { asconfigDir = path.isAbsolute(asconfig.extends) // absolute extension path means we know the exact directory and location @@ -329,12 +331,17 @@ exports.main = function main(argv, options, callback) { asconfig = getAsconfig(fileName, asconfigDir, readFile); } } else { - asconfig = null; // finished resolving the configuration chain + break; } } + // Merge in cli args + args = optionsUtil.merge(exports.options, cliArgs, args); + // Add entries + argv = argv.concat(Array.from(entries)); // If showConfig print args and exit if (args.showConfig) { + args.argv = argv; stderr.write(JSON.stringify(args, null, 2)); return callback(null); } diff --git a/cli/util/options.js b/cli/util/options.js index 742df4d8cc..37c119dde2 100644 --- a/cli/util/options.js +++ b/cli/util/options.js @@ -31,7 +31,7 @@ function parse(argv, config, propagateDefaults = true) { if (typeof option.alias === "string") aliases[option.alias] = key; else if (Array.isArray(option.alias)) option.alias.forEach(alias => aliases[alias] = key); } - if (option.default != null) options[key] = option.default; + if (option.default != null && propagateDefaults) options[key] = option.default; }); // iterate over argv @@ -87,7 +87,9 @@ function parse(argv, config, propagateDefaults = true) { } else unknown.push(arg); } while (i < k) trailing.push(argv[i++]); // trailing - if (propagateDefaults) addDefaults(config, options); + if (propagateDefaults) { + options = addDefaults(config, options); + } return { options, unknown, arguments: args, trailing }; } @@ -224,12 +226,17 @@ exports.merge = merge; /** Populates default values on a parsed options result. */ function addDefaults(config, options) { + const newOptions = {}; for (const [key, { default: defaultValue }] of Object.entries(config)) { - if (options[key] == null && defaultValue != null) { - options[key] = defaultValue; + if (options[key] == null) { + if (defaultValue != null) { + newOptions[key] = defaultValue; + } + } else { + newOptions[key] = options[key]; } } - return options; + return newOptions; } exports.addDefaults = addDefaults; diff --git a/tests/asconfig/complicated/assembly/index.ts b/tests/asconfig/complicated/assembly/index.ts index ae67e9d6f5..ccc7edfb32 100644 --- a/tests/asconfig/complicated/assembly/index.ts +++ b/tests/asconfig/complicated/assembly/index.ts @@ -1,6 +1,6 @@ -assert(ASC_OPTIMIZE_LEVEL == 3); -assert(ASC_SHRINK_LEVEL == 1); -assert(ASC_FEATURE_SIMD); +assert(ASC_OPTIMIZE_LEVEL == 3, "expected optimize level == 3"); +assert(ASC_SHRINK_LEVEL == 1, "expected shrink level == 1"); +assert(ASC_FEATURE_SIMD, "expected SIMD enabled"); let size = memory.size(); trace("size", 1, size); -assert(size == 30); +assert(size == 30, "expected 30 got " + size.toString()); diff --git a/tests/asconfig/extends/asconfig.json b/tests/asconfig/extends/asconfig.json index d052236111..e9ef74654a 100644 --- a/tests/asconfig/extends/asconfig.json +++ b/tests/asconfig/extends/asconfig.json @@ -5,7 +5,9 @@ } }, "options": { - "enable": ["simd"] + "enable": ["simd"], + "runtime": "half", + "noEmit": false }, "extends": "./extends.json" } diff --git a/tests/asconfig/extends/expected.json b/tests/asconfig/extends/expected.json new file mode 100644 index 0000000000..4d3b6048fd --- /dev/null +++ b/tests/asconfig/extends/expected.json @@ -0,0 +1,6 @@ +{ + "runtime": "half", + "noEmit": false, + "noAssert": true, + "enable": ["simd"] +} \ No newline at end of file diff --git a/tests/asconfig/extends/extends.json b/tests/asconfig/extends/extends.json index 44d1411849..21e9a62fa3 100644 --- a/tests/asconfig/extends/extends.json +++ b/tests/asconfig/extends/extends.json @@ -6,6 +6,8 @@ } }, "options": { - "disable": ["simd"] + "disable": ["simd"], + "noEmit": true, + "noAssert": true } } diff --git a/tests/asconfig/extends/package.json b/tests/asconfig/extends/package.json index f98424bae9..fdbb9ed043 100644 --- a/tests/asconfig/extends/package.json +++ b/tests/asconfig/extends/package.json @@ -1,6 +1,6 @@ { "private": true, "scripts": { - "test": "node ../index.js" + "test": "node ../index.js --showConfig && node ../index.js" } } diff --git a/tests/asconfig/index.js b/tests/asconfig/index.js index 55ee7a6d87..5fcf60ae55 100644 --- a/tests/asconfig/index.js +++ b/tests/asconfig/index.js @@ -1,7 +1,11 @@ const asc = require("../../cli/asc"); const loader = require("../../lib/loader"); const args = process.argv.slice(2); +const path = require('path'); +const fs = require("fs"); +/** @type {string} */ +let stderr; /** @type {Uint8Array} */ let binary; asc.main(["assembly/index.ts", "--outFile", "output.wasm", "--explicitStart", ...args], { @@ -11,13 +15,51 @@ asc.main(["assembly/index.ts", "--outFile", "output.wasm", "--explicitStart", .. } else if (name !== "output.wasm.map") { throw Error("Unexpected output file: " + name); } + }, + stderr: { + write(s) { + stderr = s; + } } + }, (err) => { if (err) { console.error(err); + console.error(stderr); process.exit(1); } + const jsonPath = path.join(process.cwd(), "expected.json"); + if (fs.existsSync(jsonPath) && stderr) { + const actual = JSON.parse(stderr); + const expected = require(jsonPath); + let errored = false; + for (let name of Object.getOwnPropertyNames(expected)) { + if (actual[name] !== expected[name]) { + // If object check just first level + if (typeof actual[name] === 'object' && typeof expected[name] === 'object') { + let error = false; + for (let field of Object.getOwnPropertyNames(actual[name])) { + if (actual[name][field] !== expected[name][field]) { + error = true; + break; + } + } + if (!error) { + continue; + } + } + console.error(name + ": " + actual[name] + " expected " + expected[name]); + errored = true; + } + } + if (errored) { + process.exit(1); + } + process.exit(0); + } + + if (!binary) { console.error("No binary was generated for the asconfig test in " + process.cwd()); process.exit(1); @@ -29,6 +71,7 @@ asc.main(["assembly/index.ts", "--outFile", "output.wasm", "--explicitStart", .. theModule.exports._start(); } catch (err) { console.error("The wasm module _start() function failed in " + process.cwd()); + console.error(err); process.exit(1); } return 0; diff --git a/tests/asconfig/package.json b/tests/asconfig/package.json index 58789240bc..1c6818ce3b 100644 --- a/tests/asconfig/package.json +++ b/tests/asconfig/package.json @@ -1,12 +1,13 @@ { "private": true, "scripts": { - "test": "npm run test:use-consts && npm run test:target && npm run test:entry-points && npm run test:complicated", + "test": "npm run test:use-consts && npm run test:target && npm run test:entry-points && npm run test:complicated && npm run test:extends", "test:use-consts": "cd use-consts && npm run test", "test:entry-points": "cd entry-points && npm run test", "test:respect-inheritence": "cd respect-inheritence && npm run test", "test:target": "cd target && npm run test", "test:cyclical": "cd cyclical && npm run test", - "test:complicated": "cd complicated && npm run test" + "test:complicated": "cd complicated && npm run test", + "test:extends": "cd extends && npm run test" } } diff --git a/tests/asconfig/target/asconfig.json b/tests/asconfig/target/asconfig.json index aaadbf8119..6d99b903fd 100644 --- a/tests/asconfig/target/asconfig.json +++ b/tests/asconfig/target/asconfig.json @@ -9,5 +9,7 @@ "debug": true } }, - "options": {} + "options": { + "runtime": "stub" + } } diff --git a/tests/asconfig/target/assembly/index.ts b/tests/asconfig/target/assembly/index.ts index 5c03e37224..a3353e3c36 100644 --- a/tests/asconfig/target/assembly/index.ts +++ b/tests/asconfig/target/assembly/index.ts @@ -1,3 +1,3 @@ -assert(ASC_OPTIMIZE_LEVEL == 3); -assert(ASC_SHRINK_LEVEL == 1); -assert(ASC_FEATURE_SIMD); +assert(ASC_OPTIMIZE_LEVEL == 3, "expected optimize level == 3"); +assert(ASC_SHRINK_LEVEL == 1, "expected shrink level == 1"); +assert(ASC_FEATURE_SIMD, "expected SIMD enabled"); diff --git a/tests/asconfig/target/expected.json b/tests/asconfig/target/expected.json new file mode 100644 index 0000000000..4c58af9e68 --- /dev/null +++ b/tests/asconfig/target/expected.json @@ -0,0 +1,3 @@ +{ + "runtime": "none" +} \ No newline at end of file diff --git a/tests/asconfig/target/package.json b/tests/asconfig/target/package.json index f98424bae9..04409bf0b6 100644 --- a/tests/asconfig/target/package.json +++ b/tests/asconfig/target/package.json @@ -1,6 +1,6 @@ { "private": true, "scripts": { - "test": "node ../index.js" + "test": "node ../index.js --target && node ../index.js --showConfig --runtime none" } }