diff --git a/.github/workflows/as-test.yml b/.github/workflows/as-test.yml index 0690ff5..51add74 100644 --- a/.github/workflows/as-test.yml +++ b/.github/workflows/as-test.yml @@ -21,7 +21,7 @@ jobs: - name: Build reporter run: bun run build:log - + - name: Build tests run: bun run pretest diff --git a/as-test.config.json b/as-test.config.json index 9dde69a..cf12e9f 100644 --- a/as-test.config.json +++ b/as-test.config.json @@ -1,7 +1,7 @@ { "input": ["./assembly/__tests__/*.spec.ts"], "outDir": "./build", - "config": "./asconfig.json", + "config": "none", "plugins": { "coverage": true }, diff --git a/assembly/__tests__/array.spec.ts b/assembly/__tests__/array.spec.ts index 304a946..cd971ea 100644 --- a/assembly/__tests__/array.spec.ts +++ b/assembly/__tests__/array.spec.ts @@ -11,7 +11,9 @@ describe("Array manipulation", () => { expect(myArray).toContain(2); }); - it("should be empty", () => {}); + it("should be empty", () => { + expect("ag").toBe("asd") + }); }); run({ diff --git a/assembly/__tests__/sleep.spec.ts b/assembly/__tests__/sleep.spec.ts index 106deb0..dbc27a4 100644 --- a/assembly/__tests__/sleep.spec.ts +++ b/assembly/__tests__/sleep.spec.ts @@ -1,26 +1,26 @@ import { describe, expect, run, test } from ".."; import { sleep } from "as-sleep/assembly"; describe("Should sleep", () => { - test("1ms", () => { - const start = Date.now(); - sleep(1); - expect(Date.now() - start).toBeGreaterOrEqualTo(1); - }); - test("10ms", () => { - const start = Date.now(); - sleep(10); - expect(Date.now() - start).toBeGreaterOrEqualTo(10); - }); - test("100ms", () => { - const start = Date.now(); - sleep(100); - expect(Date.now() - start).toBeGreaterOrEqualTo(1010); - }); - test("1s", () => { - const start = Date.now(); - sleep(1000); - expect(Date.now() - start).toBeGreaterOrEqualTo(1000); - }); + test("1ms", () => { + const start = Date.now(); + sleep(1); + expect(Date.now() - start).toBeGreaterOrEqualTo(1); + }); + test("10ms", () => { + const start = Date.now(); + sleep(10); + expect(Date.now() - start).toBeGreaterOrEqualTo(10); + }); + test("100ms", () => { + const start = Date.now(); + sleep(100); + expect(Date.now() - start).toBeGreaterOrEqualTo(100); + }); + test("1s", () => { + const start = Date.now(); + sleep(1000); + expect(Date.now() - start).toBeGreaterOrEqualTo(1000); + }); }); -run(); \ No newline at end of file +run(); diff --git a/assembly/index.ts b/assembly/index.ts index fd749fc..cfe8690 100644 --- a/assembly/index.ts +++ b/assembly/index.ts @@ -20,7 +20,9 @@ let entrySuites: Suite[] = []; // Globals @global let suites: Suite[] = []; + @global let depth: i32 = -1; + @global let current_suite: Suite | null = null; let before_all_callback: (() => void) | null = null; @@ -226,17 +228,13 @@ export function mockFn( * Unmock all references to an existing function to instead point to the original function * @param {string} fn - name of function to override */ -export function unmockFn( - fn: string -): void {} +export function unmockFn(fn: string): void {} /** * Re-mock all references to an existing function to instead point to the declared function * @param {string} fn - name of function to override */ -export function remockFn( - fn: string -): void {} +export function remockFn(fn: string): void {} /** * Class defining options that can be passed to the `run` function. diff --git a/assembly/src/suite.ts b/assembly/src/suite.ts index 87d3529..5db5d41 100644 --- a/assembly/src/suite.ts +++ b/assembly/src/suite.ts @@ -16,7 +16,7 @@ export class Suite { public depth: i32 = 0; public suites: Suite[] = []; public tests: Tests[] = []; - public kind!: SuiteKind; + public kind: SuiteKind; public verdict: Verdict = Verdict.None; @@ -64,4 +64,4 @@ export class Suite { if (this.suites.length) this.verdict = Verdict.Ok; } } -} \ No newline at end of file +} diff --git a/bin/about.js b/bin/about.js index 4e74a05..b311b5e 100644 --- a/bin/about.js +++ b/bin/about.js @@ -1,99 +1,135 @@ import chalk from "chalk"; export function about() { - console.log(chalk.bold.blueBright("as-test") + - " is a testing framework for AssemblyScript. " + - chalk.dim("(v" + version + ")") + - "\n"); - console.log(chalk.bold("Usage: as-test") + - " " + - chalk.dim("") + - " " + - chalk.bold.blueBright("[...flags]") + - " " + - chalk.bold("[...args]") + - " " + - chalk.dim("(alias: ast)") + - "\n"); - console.log(chalk.bold("Commands:")); - console.log(" " + - chalk.bold.blueBright("run") + - " " + - chalk.dim("") + - " " + - "Run unit tests with selected runtime"); - console.log(" " + - chalk.bold.blueBright("build") + - " " + - chalk.dim("") + - " " + - "Build unit tests and compile"); - console.log(" " + - chalk.bold.blueBright("test") + - " " + - chalk.dim("") + - " " + - "Build and run unit tests with selected runtime" + - "\n"); - console.log(" " + - chalk.bold.magentaBright("init") + - " " + - chalk.strikethrough.dim("") + - " " + - "Initialize an empty testing template"); - console.log(" " + - chalk.strikethrough.bold.magentaBright("config") + - " " + - chalk.strikethrough.dim("as-test.config.json") + - " " + - "Specify the configuration file"); - console.log(" " + - chalk.strikethrough.bold.magentaBright("reporter") + - " " + - chalk.strikethrough.dim("") + - " " + - "Specify the test reporter to use"); - console.log(" " + - chalk.strikethrough.bold.magentaBright("use") + - " " + - chalk.strikethrough.dim("wasmtime") + - " " + - "Specify the runtime to use" + - "\n"); - console.log(chalk.bold("Flags:")); - console.log(" " + - chalk.strikethrough.dim("run") + - " " + - chalk.strikethrough.bold.blue("--coverage") + - " " + - "Use code coverage"); - console.log(" " + - chalk.strikethrough.dim("run") + - " " + - chalk.strikethrough.bold.blue("--snapshot") + - " " + - "Take a snapshot of the tests"); - console.log(" " + - chalk.strikethrough.dim("use") + - " " + - chalk.strikethrough.bold.blue("--list") + - " " + - "List supported runtimes"); - console.log(" " + - chalk.strikethrough.dim("reporter") + - " " + - chalk.strikethrough.bold.blue("--list") + - " " + - "List supported reporters"); - console.log(" " + - chalk.strikethrough.dim("") + - " " + - chalk.strikethrough.bold.blue("--help") + - " " + - "Print info about command" + - "\n"); - console.log(chalk.dim("If your using this, consider dropping a star, it would help a lot!") + "\n"); - console.log("View the repo: " + - chalk.magenta("https://github.com/JairusSW/as-test")); - console.log("View the docs: " + - chalk.strikethrough.blue("https://docs.jairus.dev/as-test")); + console.log( + chalk.bold.blueBright("as-test") + + " is a testing framework for AssemblyScript. " + + chalk.dim("(v" + version + ")") + + "\n", + ); + console.log( + chalk.bold("Usage: as-test") + + " " + + chalk.dim("") + + " " + + chalk.bold.blueBright("[...flags]") + + " " + + chalk.bold("[...args]") + + " " + + chalk.dim("(alias: ast)") + + "\n", + ); + console.log(chalk.bold("Commands:")); + console.log( + " " + + chalk.bold.blueBright("run") + + " " + + chalk.dim("") + + " " + + "Run unit tests with selected runtime", + ); + console.log( + " " + + chalk.bold.blueBright("build") + + " " + + chalk.dim("") + + " " + + "Build unit tests and compile", + ); + console.log( + " " + + chalk.bold.blueBright("test") + + " " + + chalk.dim("") + + " " + + "Build and run unit tests with selected runtime" + + "\n", + ); + console.log( + " " + + chalk.bold.magentaBright("init") + + " " + + chalk.strikethrough.dim("") + + " " + + "Initialize an empty testing template", + ); + console.log( + " " + + chalk.strikethrough.bold.magentaBright("config") + + " " + + chalk.strikethrough.dim("as-test.config.json") + + " " + + "Specify the configuration file", + ); + console.log( + " " + + chalk.strikethrough.bold.magentaBright("reporter") + + " " + + chalk.strikethrough.dim("") + + " " + + "Specify the test reporter to use", + ); + console.log( + " " + + chalk.strikethrough.bold.magentaBright("use") + + " " + + chalk.strikethrough.dim("wasmtime") + + " " + + "Specify the runtime to use" + + "\n", + ); + console.log(chalk.bold("Flags:")); + console.log( + " " + + chalk.strikethrough.dim("run") + + " " + + chalk.strikethrough.bold.blue("--coverage") + + " " + + "Use code coverage", + ); + console.log( + " " + + chalk.strikethrough.dim("run") + + " " + + chalk.strikethrough.bold.blue("--snapshot") + + " " + + "Take a snapshot of the tests", + ); + console.log( + " " + + chalk.strikethrough.dim("use") + + " " + + chalk.strikethrough.bold.blue("--list") + + " " + + "List supported runtimes", + ); + console.log( + " " + + chalk.strikethrough.dim("reporter") + + " " + + chalk.strikethrough.bold.blue("--list") + + " " + + "List supported reporters", + ); + console.log( + " " + + chalk.strikethrough.dim("") + + " " + + chalk.strikethrough.bold.blue("--help") + + " " + + "Print info about command" + + "\n", + ); + console.log( + chalk.dim( + "If your using this, consider dropping a star, it would help a lot!", + ) + "\n", + ); + console.log( + "View the repo: " + + chalk.magenta("https://github.com/JairusSW/as-test"), + ); + console.log( + "View the docs: " + + chalk.strikethrough.blue("https://docs.jairus.dev/as-test"), + ); } diff --git a/bin/build.js b/bin/build.js index e8e2249..23f0f69 100644 --- a/bin/build.js +++ b/bin/build.js @@ -1,84 +1,35 @@ import { existsSync, readFileSync } from "fs"; -import { Config } from "./types.js"; import { glob } from "glob"; import chalk from "chalk"; -import { exec } from "child_process"; -import { formatTime } from "./util.js"; +import { execSync } from "child_process"; import * as path from "path"; +import { loadConfig } from "./util.js"; const CONFIG_PATH = path.join(process.cwd(), "./as-test.config.json"); const PKG_PATH = path.join(process.cwd(), "./package.json"); -export async function build(args) { - let config = loadConfig(); +export async function build() { + let config = loadConfig(CONFIG_PATH, true); const ASCONFIG_PATH = path.join(process.cwd(), config.config); - if (!existsSync(ASCONFIG_PATH)) { - console.log(chalk.bgMagentaBright(" WARN ") + - chalk.dim(":") + - ' Could not locate asconfig.json file! If you do not want to provide a config, set "config": "none". Continuing with default config.' + - "\n"); + if (config.config && config.config !== "none" && !existsSync(ASCONFIG_PATH)) { + console.log(`${chalk.bgMagentaBright(" WARN ")}${chalk.dim(":")} Could not locate asconfig.json file! If you do not want to provide a config, set "config": "none"`); } - verifyPackagesInstalled(config); - let pkgMan = getPkgManager(); - console.log(""); - const buildCommands = []; + ensureDeps(config); + let pkgRunner = getPkgRunner(); const inputFiles = await glob(config.input); + let buildArgs = getBuildArgs(config); for (const file of inputFiles) { - console.log(chalk.dim("Including " + file)); - let command = `${pkgMan} asc ${file}${args.length ? " " + args.join(" ") : ""}`; - if (config.config !== "none") { - command += " --config " + config.config; - } - if (config.buildOptions.target == "wasi") { - command += - " --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json"; - } - const outFile = config.outDir + - "/" + - file.slice(file.lastIndexOf("/") + 1).replace(".ts", ".wasm"); + let cmd = `${pkgRunner} asc ${file}${buildArgs}`; + const outFile = `${config.outDir}/${file.slice(file.lastIndexOf("/") + 1).replace(".ts", ".wasm")}`; if (config.outDir) { - command += " -o " + outFile; - } - if (config.plugins["coverage"]) { - command += " --use COVERAGE_USE=1 --transform as-test/transform"; - command += " --use COVERAGE_SHOW=1"; - } - if (config.buildOptions.args) { - command += " " + config.buildOptions.args.join(" "); - } - if (["node", "deno", "bun"].includes(config.runOptions.runtime.run.split(" ")[0])) { - command += " --exportStart"; + cmd += " -o " + outFile; } - buildCommands.push(command); + buildFile(cmd); } - const build = (command) => { - return new Promise((resolve, _) => { - console.log(chalk.dim("Building: " + command)); - exec(command, (err, stdout, stderr) => { - process.stdout.write(stdout); - if (err) { - process.stderr.write(stderr + "\n"); - process.exit(1); - } - resolve(); - }); - }); - }; - console.log(chalk.dim("Building sources in parallel...")); - const start = performance.now(); - let builders = []; - for (const command of buildCommands) { - builders.push(build(command)); - } - await Promise.all(builders); - console.log(chalk.dim("Compiled in " + formatTime(performance.now() - start)) + "\n"); } -function verifyPackagesInstalled(config) { +function ensureDeps(config) { const pkg = JSON.parse(readFileSync(PKG_PATH).toString()); if (config.buildOptions.target == "wasi") { if (!existsSync("./node_modules/@assemblyscript/wasi-shim/asconfig.json")) { - console.log(chalk.bgRed(" ERROR ") + - chalk.dim(":") + - " " + - "could not find @assemblyscript/wasi-shim! Add it to your dependencies to run with WASI!"); + console.log(`${chalk.bgRed(" ERROR ")}${chalk.dim(":")} could not find @assemblyscript/wasi-shim! Add it to your dependencies to run with WASI!`); process.exit(1); } if (pkg.dependencies && @@ -88,27 +39,11 @@ function verifyPackagesInstalled(config) { pkg.peerDependencies && !Object.keys(pkg.peerDependencies).includes("@assemblyscript/wasi-shim") && existsSync("./node_modules/@assemblyscript/wasi-shim/asconfig.json")) { - console.log(chalk.bold.bgMagentaBright(" WARN ") + - chalk.dim(": @assemblyscript/wasi-shim") + - " is not included in project dependencies!"); + console.log(`${chalk.bold.bgMagentaBright(" WARN ")}${chalk.dim(":")} @assemblyscript/wasi-shim is not included in project dependencies!"`); } } } -function loadConfig() { - if (!existsSync(CONFIG_PATH)) { - console.log(chalk.bgMagentaBright(" WARN ") + - chalk.dim(":") + - " Could not locate config file in the current directory! Continuing with default config." + - "\n"); - console.log(chalk.dim("Using default configuration") + "\n"); - return new Config(); - } - else { - console.log(chalk.dim("Loading config from: " + CONFIG_PATH) + "\n"); - return Object.assign(new Config(), JSON.parse(readFileSync(CONFIG_PATH).toString())); - } -} -function getPkgManager() { +function getPkgRunner() { switch (process.env.npm_config_user_agent) { case "pnpm": { return "pnpx"; @@ -122,3 +57,30 @@ function getPkgManager() { } return "npx"; } +function buildFile(command) { + execSync(command, { stdio: "inherit" }); +} +function getBuildArgs(config) { + let buildArgs = ""; + buildArgs += " --transform as-test/transform"; + if (config.config && config.config !== "none") { + buildArgs += " --config " + config.config; + } + // Should also strip any bindings-enabling from asconfig + if (config.buildOptions.target == "bindings") { + buildArgs += " --bindings esm --exportRuntime --exportStart"; + } + else if (config.buildOptions.target == "wasi") { + buildArgs += + " --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json"; + } + else { + console.log(`${chalk.bgRed(" ERROR ")}${chalk.dim(":")} could determine target in config! Set target to 'bindings' or 'wasi'`); + process.exit(0); + } + if (config.buildOptions.args.length && + config.buildOptions.args.find((v) => v.length > 0)) { + buildArgs += " " + config.buildOptions.args.join(" "); + } + return buildArgs; +} diff --git a/bin/cli/about.js b/bin/cli/about.js index 4e74a05..b311b5e 100644 --- a/bin/cli/about.js +++ b/bin/cli/about.js @@ -1,99 +1,135 @@ import chalk from "chalk"; export function about() { - console.log(chalk.bold.blueBright("as-test") + - " is a testing framework for AssemblyScript. " + - chalk.dim("(v" + version + ")") + - "\n"); - console.log(chalk.bold("Usage: as-test") + - " " + - chalk.dim("") + - " " + - chalk.bold.blueBright("[...flags]") + - " " + - chalk.bold("[...args]") + - " " + - chalk.dim("(alias: ast)") + - "\n"); - console.log(chalk.bold("Commands:")); - console.log(" " + - chalk.bold.blueBright("run") + - " " + - chalk.dim("") + - " " + - "Run unit tests with selected runtime"); - console.log(" " + - chalk.bold.blueBright("build") + - " " + - chalk.dim("") + - " " + - "Build unit tests and compile"); - console.log(" " + - chalk.bold.blueBright("test") + - " " + - chalk.dim("") + - " " + - "Build and run unit tests with selected runtime" + - "\n"); - console.log(" " + - chalk.bold.magentaBright("init") + - " " + - chalk.strikethrough.dim("") + - " " + - "Initialize an empty testing template"); - console.log(" " + - chalk.strikethrough.bold.magentaBright("config") + - " " + - chalk.strikethrough.dim("as-test.config.json") + - " " + - "Specify the configuration file"); - console.log(" " + - chalk.strikethrough.bold.magentaBright("reporter") + - " " + - chalk.strikethrough.dim("") + - " " + - "Specify the test reporter to use"); - console.log(" " + - chalk.strikethrough.bold.magentaBright("use") + - " " + - chalk.strikethrough.dim("wasmtime") + - " " + - "Specify the runtime to use" + - "\n"); - console.log(chalk.bold("Flags:")); - console.log(" " + - chalk.strikethrough.dim("run") + - " " + - chalk.strikethrough.bold.blue("--coverage") + - " " + - "Use code coverage"); - console.log(" " + - chalk.strikethrough.dim("run") + - " " + - chalk.strikethrough.bold.blue("--snapshot") + - " " + - "Take a snapshot of the tests"); - console.log(" " + - chalk.strikethrough.dim("use") + - " " + - chalk.strikethrough.bold.blue("--list") + - " " + - "List supported runtimes"); - console.log(" " + - chalk.strikethrough.dim("reporter") + - " " + - chalk.strikethrough.bold.blue("--list") + - " " + - "List supported reporters"); - console.log(" " + - chalk.strikethrough.dim("") + - " " + - chalk.strikethrough.bold.blue("--help") + - " " + - "Print info about command" + - "\n"); - console.log(chalk.dim("If your using this, consider dropping a star, it would help a lot!") + "\n"); - console.log("View the repo: " + - chalk.magenta("https://github.com/JairusSW/as-test")); - console.log("View the docs: " + - chalk.strikethrough.blue("https://docs.jairus.dev/as-test")); + console.log( + chalk.bold.blueBright("as-test") + + " is a testing framework for AssemblyScript. " + + chalk.dim("(v" + version + ")") + + "\n", + ); + console.log( + chalk.bold("Usage: as-test") + + " " + + chalk.dim("") + + " " + + chalk.bold.blueBright("[...flags]") + + " " + + chalk.bold("[...args]") + + " " + + chalk.dim("(alias: ast)") + + "\n", + ); + console.log(chalk.bold("Commands:")); + console.log( + " " + + chalk.bold.blueBright("run") + + " " + + chalk.dim("") + + " " + + "Run unit tests with selected runtime", + ); + console.log( + " " + + chalk.bold.blueBright("build") + + " " + + chalk.dim("") + + " " + + "Build unit tests and compile", + ); + console.log( + " " + + chalk.bold.blueBright("test") + + " " + + chalk.dim("") + + " " + + "Build and run unit tests with selected runtime" + + "\n", + ); + console.log( + " " + + chalk.bold.magentaBright("init") + + " " + + chalk.strikethrough.dim("") + + " " + + "Initialize an empty testing template", + ); + console.log( + " " + + chalk.strikethrough.bold.magentaBright("config") + + " " + + chalk.strikethrough.dim("as-test.config.json") + + " " + + "Specify the configuration file", + ); + console.log( + " " + + chalk.strikethrough.bold.magentaBright("reporter") + + " " + + chalk.strikethrough.dim("") + + " " + + "Specify the test reporter to use", + ); + console.log( + " " + + chalk.strikethrough.bold.magentaBright("use") + + " " + + chalk.strikethrough.dim("wasmtime") + + " " + + "Specify the runtime to use" + + "\n", + ); + console.log(chalk.bold("Flags:")); + console.log( + " " + + chalk.strikethrough.dim("run") + + " " + + chalk.strikethrough.bold.blue("--coverage") + + " " + + "Use code coverage", + ); + console.log( + " " + + chalk.strikethrough.dim("run") + + " " + + chalk.strikethrough.bold.blue("--snapshot") + + " " + + "Take a snapshot of the tests", + ); + console.log( + " " + + chalk.strikethrough.dim("use") + + " " + + chalk.strikethrough.bold.blue("--list") + + " " + + "List supported runtimes", + ); + console.log( + " " + + chalk.strikethrough.dim("reporter") + + " " + + chalk.strikethrough.bold.blue("--list") + + " " + + "List supported reporters", + ); + console.log( + " " + + chalk.strikethrough.dim("") + + " " + + chalk.strikethrough.bold.blue("--help") + + " " + + "Print info about command" + + "\n", + ); + console.log( + chalk.dim( + "If your using this, consider dropping a star, it would help a lot!", + ) + "\n", + ); + console.log( + "View the repo: " + + chalk.magenta("https://github.com/JairusSW/as-test"), + ); + console.log( + "View the docs: " + + chalk.strikethrough.blue("https://docs.jairus.dev/as-test"), + ); } diff --git a/bin/cli/build.js b/bin/cli/build.js index 4b5445f..248b82e 100644 --- a/bin/cli/build.js +++ b/bin/cli/build.js @@ -8,122 +8,142 @@ import * as path from "path"; const CONFIG_PATH = path.join(process.cwd(), "./as-test.config.json"); const PKG_PATH = path.join(process.cwd(), "./package.json"); export async function build(args) { - let config = loadConfig(); - const ASCONFIG_PATH = path.join(process.cwd(), config.config); - if (!existsSync(ASCONFIG_PATH)) { - console.log(chalk.bgMagentaBright(" WARN ") + - chalk.dim(":") + - ' Could not locate asconfig.json file! If you do not want to provide a config, set "config": "none". Continuing with default config.' + - "\n"); + let config = loadConfig(); + const ASCONFIG_PATH = path.join(process.cwd(), config.config); + if (!existsSync(ASCONFIG_PATH)) { + console.log( + chalk.bgMagentaBright(" WARN ") + + chalk.dim(":") + + ' Could not locate asconfig.json file! If you do not want to provide a config, set "config": "none". Continuing with default config.' + + "\n", + ); + } + verifyPackagesInstalled(config); + let pkgMan = getPkgManager(); + console.log(""); + const inputFiles = await glob(config.input); + for (const file of inputFiles) { + console.log(chalk.dim("Including " + file)); + let command = `${pkgMan} asc ${file}${args.length ? " " + args.join(" ") : ""}`; + if (config.config !== "none") { + command += " --config " + config.config; } - verifyPackagesInstalled(config); - let pkgMan = getPkgManager(); - console.log(""); - const inputFiles = await glob(config.input); - for (const file of inputFiles) { - console.log(chalk.dim("Including " + file)); - let command = `${pkgMan} asc ${file}${args.length ? " " + args.join(" ") : ""}`; - if (config.config !== "none") { - command += " --config " + config.config; - } - if (config.buildOptions.wasi) { - command += - " --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json"; - } - const outFile = config.outDir + - "/" + - file.slice(file.lastIndexOf("/") + 1).replace(".ts", ".wasm"); - if (config.outDir) { - command += " -o " + outFile; - } - if (config.coverage.enabled) { - console.log(chalk.dim("Enabling coverage")); - command += " --use COVERAGE_USE=1 --transform as-test/transform"; - if (config.coverage.show) - command += " --use COVERAGE_SHOW=1"; - } - if (config.buildOptions.args) { - command += " " + config.buildOptions.args.join(" "); - } - if (["node", "deno", "bun"].includes(config.runOptions.runtime.run.split(" ")[0])) { - command += " --exportStart"; - } - buildCommands.push(command); + if (config.buildOptions.wasi) { + command += + " --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json"; } - const build = (command) => { - return new Promise((resolve, _) => { - console.log(chalk.dim("Building: " + command)); - exec(command, (err, stdout, stderr) => { - if (config.buildOptions.verbose) { - process.stdout.write(stdout); - } - if (err) { - process.stderr.write(stderr + "\n"); - process.exit(1); - } - resolve(); - }); - }); - }; - if (config.buildOptions.parallel) { - console.log(chalk.dim("Building sources in parallel...")); - const start = performance.now(); - let builders = []; - for (const command of buildCommands) { - builders.push(build(command)); - } - await Promise.all(builders); - console.log(chalk.dim("Compiled in " + formatTime(performance.now() - start)) + "\n"); + const outFile = + config.outDir + + "/" + + file.slice(file.lastIndexOf("/") + 1).replace(".ts", ".wasm"); + if (config.outDir) { + command += " -o " + outFile; } -} -function verifyPackagesInstalled(config) { - const pkg = JSON.parse(readFileSync(PKG_PATH).toString()); - if (config.buildOptions.wasi) { - if (!existsSync("./node_modules/@assemblyscript/wasi-shim/asconfig.json")) { - console.log(chalk.bgRed(" ERROR ") + - chalk.dim(":") + - " " + - "could not find @assemblyscript/wasi-shim! Add it to your dependencies to run with WASI!"); - process.exit(1); + if (config.coverage.enabled) { + console.log(chalk.dim("Enabling coverage")); + command += " --use COVERAGE_USE=1 --transform as-test/transform"; + if (config.coverage.show) command += " --use COVERAGE_SHOW=1"; + } + if (config.buildOptions.args) { + command += " " + config.buildOptions.args.join(" "); + } + if ( + ["node", "deno", "bun"].includes( + config.runOptions.runtime.run.split(" ")[0], + ) + ) { + command += " --exportStart"; + } + buildCommands.push(command); + } + const build = (command) => { + return new Promise((resolve, _) => { + console.log(chalk.dim("Building: " + command)); + exec(command, (err, stdout, stderr) => { + if (config.buildOptions.verbose) { + process.stdout.write(stdout); } - if (pkg.dependencies && - !Object.keys(pkg.dependencies).includes("@assemblyscript/wasi-shim") && - pkg.devDependencies && - !Object.keys(pkg.devDependencies).includes("@assemblyscript/wasi-shim") && - pkg.peerDependencies && - !Object.keys(pkg.peerDependencies).includes("@assemblyscript/wasi-shim") && - existsSync("./node_modules/@assemblyscript/wasi-shim/asconfig.json")) { - console.log(chalk.bold.bgMagentaBright(" WARN ") + - chalk.dim(": @assemblyscript/wasi-shim") + - " is not included in project dependencies!"); + if (err) { + process.stderr.write(stderr + "\n"); + process.exit(1); } + resolve(); + }); + }); + }; + if (config.buildOptions.parallel) { + console.log(chalk.dim("Building sources in parallel...")); + const start = performance.now(); + let builders = []; + for (const command of buildCommands) { + builders.push(build(command)); } + await Promise.all(builders); + console.log( + chalk.dim("Compiled in " + formatTime(performance.now() - start)) + "\n", + ); + } } -function loadConfig() { - if (!existsSync(CONFIG_PATH)) { - console.log(chalk.bgMagentaBright(" WARN ") + - chalk.dim(":") + - " Could not locate config file in the current directory! Continuing with default config." + - "\n"); - console.log(chalk.dim("Using default configuration") + "\n"); - return new Config(); +function verifyPackagesInstalled(config) { + const pkg = JSON.parse(readFileSync(PKG_PATH).toString()); + if (config.buildOptions.wasi) { + if (!existsSync("./node_modules/@assemblyscript/wasi-shim/asconfig.json")) { + console.log( + chalk.bgRed(" ERROR ") + + chalk.dim(":") + + " " + + "could not find @assemblyscript/wasi-shim! Add it to your dependencies to run with WASI!", + ); + process.exit(1); } - else { - console.log(chalk.dim("Loading config from: " + CONFIG_PATH) + "\n"); - return Object.assign(new Config(), JSON.parse(readFileSync(CONFIG_PATH).toString())); + if ( + pkg.dependencies && + !Object.keys(pkg.dependencies).includes("@assemblyscript/wasi-shim") && + pkg.devDependencies && + !Object.keys(pkg.devDependencies).includes("@assemblyscript/wasi-shim") && + pkg.peerDependencies && + !Object.keys(pkg.peerDependencies).includes( + "@assemblyscript/wasi-shim", + ) && + existsSync("./node_modules/@assemblyscript/wasi-shim/asconfig.json") + ) { + console.log( + chalk.bold.bgMagentaBright(" WARN ") + + chalk.dim(": @assemblyscript/wasi-shim") + + " is not included in project dependencies!", + ); } + } +} +function loadConfig() { + if (!existsSync(CONFIG_PATH)) { + console.log( + chalk.bgMagentaBright(" WARN ") + + chalk.dim(":") + + " Could not locate config file in the current directory! Continuing with default config." + + "\n", + ); + console.log(chalk.dim("Using default configuration") + "\n"); + return new Config(); + } else { + console.log(chalk.dim("Loading config from: " + CONFIG_PATH) + "\n"); + return Object.assign( + new Config(), + JSON.parse(readFileSync(CONFIG_PATH).toString()), + ); + } } function getPkgManager() { - switch (process.env.npm_config_user_agent) { - case "pnpm": { - return "pnpx"; - } - case "yarn": { - return "yarn"; - } - case "bun": { - return "bunx"; - } + switch (process.env.npm_config_user_agent) { + case "pnpm": { + return "pnpx"; + } + case "yarn": { + return "yarn"; + } + case "bun": { + return "bunx"; } - return "npx"; + } + return "npx"; } diff --git a/bin/cli/index.js b/bin/cli/index.js index 7c36bff..371ed24 100644 --- a/bin/cli/index.js +++ b/bin/cli/index.js @@ -9,138 +9,168 @@ const args = []; const COMMANDS = ["run", "build", "test", "init"]; const version = "0.2.1"; for (const arg of _args) { - if (arg.startsWith("-")) - flags.push(arg); - else - args.push(arg); + if (arg.startsWith("-")) flags.push(arg); + else args.push(arg); } if (!args.length) { - if (flags.includes("--version") || flags.includes("-v")) { - console.log("as-test v" + version.toString()); - } - else { - info(); - } -} -else if (COMMANDS.includes(args[0])) { - const command = args.shift(); - if (command === "build") { - build(args); - } - else if (command === "run") { - run(); - } - else if (command === "test") { - build(args).then(() => { - run(); - }); - } - else if (command === "init") { - init(args); - } -} -else { - console.log(chalk.bgRed(" ERROR ") + - chalk.dim(":") + - " " + - chalk.bold("Unknown command: ") + - args[0]); + if (flags.includes("--version") || flags.includes("-v")) { + console.log("as-test v" + version.toString()); + } else { + info(); + } +} else if (COMMANDS.includes(args[0])) { + const command = args.shift(); + if (command === "build") { + build(args); + } else if (command === "run") { + run(); + } else if (command === "test") { + build(args).then(() => { + run(); + }); + } else if (command === "init") { + init(args); + } +} else { + console.log( + chalk.bgRed(" ERROR ") + + chalk.dim(":") + + " " + + chalk.bold("Unknown command: ") + + args[0], + ); } function info() { - console.log(chalk.bold.blueBright("as-test") + - " is a testing framework for AssemblyScript. " + - chalk.dim("(v" + version + ")") + - "\n"); - console.log(chalk.bold("Usage: as-test") + - " " + - chalk.dim("") + - " " + - chalk.bold.blueBright("[...flags]") + - " " + - chalk.bold("[...args]") + - " " + - chalk.dim("(alias: ast)") + - "\n"); - console.log(chalk.bold("Commands:")); - console.log(" " + - chalk.bold.blueBright("run") + - " " + - chalk.dim("") + - " " + - "Run unit tests with selected runtime"); - console.log(" " + - chalk.bold.blueBright("build") + - " " + - chalk.dim("") + - " " + - "Build unit tests and compile"); - console.log(" " + - chalk.bold.blueBright("test") + - " " + - chalk.dim("") + - " " + - "Build and run unit tests with selected runtime" + - "\n"); - console.log(" " + - chalk.bold.magentaBright("init") + - " " + - chalk.strikethrough.dim("") + - " " + - "Initialize an empty testing template"); - console.log(" " + - chalk.strikethrough.bold.magentaBright("config") + - " " + - chalk.strikethrough.dim("as-test.config.json") + - " " + - "Specify the configuration file"); - console.log(" " + - chalk.strikethrough.bold.magentaBright("reporter") + - " " + - chalk.strikethrough.dim("") + - " " + - "Specify the test reporter to use"); - console.log(" " + - chalk.strikethrough.bold.magentaBright("use") + - " " + - chalk.strikethrough.dim("wasmtime") + - " " + - "Specify the runtime to use" + - "\n"); - console.log(chalk.bold("Flags:")); - console.log(" " + - chalk.strikethrough.dim("run") + - " " + - chalk.strikethrough.bold.blue("--coverage") + - " " + - "Use code coverage"); - console.log(" " + - chalk.strikethrough.dim("run") + - " " + - chalk.strikethrough.bold.blue("--snapshot") + - " " + - "Take a snapshot of the tests"); - console.log(" " + - chalk.strikethrough.dim("use") + - " " + - chalk.strikethrough.bold.blue("--list") + - " " + - "List supported runtimes"); - console.log(" " + - chalk.strikethrough.dim("reporter") + - " " + - chalk.strikethrough.bold.blue("--list") + - " " + - "List supported reporters"); - console.log(" " + - chalk.strikethrough.dim("") + - " " + - chalk.strikethrough.bold.blue("--help") + - " " + - "Print info about command" + - "\n"); - console.log(chalk.dim("If your using this, consider dropping a star, it would help a lot!") + "\n"); - console.log("View the repo: " + - chalk.magenta("https://github.com/JairusSW/as-test")); - console.log("View the docs: " + - chalk.strikethrough.blue("https://docs.jairus.dev/as-test")); + console.log( + chalk.bold.blueBright("as-test") + + " is a testing framework for AssemblyScript. " + + chalk.dim("(v" + version + ")") + + "\n", + ); + console.log( + chalk.bold("Usage: as-test") + + " " + + chalk.dim("") + + " " + + chalk.bold.blueBright("[...flags]") + + " " + + chalk.bold("[...args]") + + " " + + chalk.dim("(alias: ast)") + + "\n", + ); + console.log(chalk.bold("Commands:")); + console.log( + " " + + chalk.bold.blueBright("run") + + " " + + chalk.dim("") + + " " + + "Run unit tests with selected runtime", + ); + console.log( + " " + + chalk.bold.blueBright("build") + + " " + + chalk.dim("") + + " " + + "Build unit tests and compile", + ); + console.log( + " " + + chalk.bold.blueBright("test") + + " " + + chalk.dim("") + + " " + + "Build and run unit tests with selected runtime" + + "\n", + ); + console.log( + " " + + chalk.bold.magentaBright("init") + + " " + + chalk.strikethrough.dim("") + + " " + + "Initialize an empty testing template", + ); + console.log( + " " + + chalk.strikethrough.bold.magentaBright("config") + + " " + + chalk.strikethrough.dim("as-test.config.json") + + " " + + "Specify the configuration file", + ); + console.log( + " " + + chalk.strikethrough.bold.magentaBright("reporter") + + " " + + chalk.strikethrough.dim("") + + " " + + "Specify the test reporter to use", + ); + console.log( + " " + + chalk.strikethrough.bold.magentaBright("use") + + " " + + chalk.strikethrough.dim("wasmtime") + + " " + + "Specify the runtime to use" + + "\n", + ); + console.log(chalk.bold("Flags:")); + console.log( + " " + + chalk.strikethrough.dim("run") + + " " + + chalk.strikethrough.bold.blue("--coverage") + + " " + + "Use code coverage", + ); + console.log( + " " + + chalk.strikethrough.dim("run") + + " " + + chalk.strikethrough.bold.blue("--snapshot") + + " " + + "Take a snapshot of the tests", + ); + console.log( + " " + + chalk.strikethrough.dim("use") + + " " + + chalk.strikethrough.bold.blue("--list") + + " " + + "List supported runtimes", + ); + console.log( + " " + + chalk.strikethrough.dim("reporter") + + " " + + chalk.strikethrough.bold.blue("--list") + + " " + + "List supported reporters", + ); + console.log( + " " + + chalk.strikethrough.dim("") + + " " + + chalk.strikethrough.bold.blue("--help") + + " " + + "Print info about command" + + "\n", + ); + console.log( + chalk.dim( + "If your using this, consider dropping a star, it would help a lot!", + ) + "\n", + ); + console.log( + "View the repo: " + + chalk.magenta("https://github.com/JairusSW/as-test"), + ); + console.log( + "View the docs: " + + chalk.strikethrough.blue("https://docs.jairus.dev/as-test"), + ); } diff --git a/bin/cli/init.js b/bin/cli/init.js index 9a4f94f..0749ee1 100644 --- a/bin/cli/init.js +++ b/bin/cli/init.js @@ -4,37 +4,41 @@ import * as path from "path"; import { createInterface } from "readline"; import { Config } from "./types.js"; export function init(args) { - console.log(chalk.bold("This command will make sure that the following files exist") + - "\n"); - console.log(" " + - chalk.bold.blueBright("./as-test.config.json") + - chalk.dim(" - The core config file for as-test") + - "\n"); - console.log("This command will attempt to update files to match the correct configuration.\n"); - console.log("Do you want to proceed? [Y/n] "); - createInterface({ - input: process.stdin, - output: process.stdout, - }).question("", (answer) => { - if (answer.toLowerCase() === "y") { - initialize(); - } - else { - console.log("Exiting..."); - process.exit(0); - } - }); + console.log( + chalk.bold("This command will make sure that the following files exist") + + "\n", + ); + console.log( + " " + + chalk.bold.blueBright("./as-test.config.json") + + chalk.dim(" - The core config file for as-test") + + "\n", + ); + console.log( + "This command will attempt to update files to match the correct configuration.\n", + ); + console.log("Do you want to proceed? [Y/n] "); + createInterface({ + input: process.stdin, + output: process.stdout, + }).question("", (answer) => { + if (answer.toLowerCase() === "y") { + initialize(); + } else { + console.log("Exiting..."); + process.exit(0); + } + }); } function initialize() { - const CONFIG_PATH = path.join(process.cwd(), "./as-test.config.json"); - if (existsSync(CONFIG_PATH)) { - console.log("Found ./as-test.config.json. Updating..."); - process.exit(0); - } - else { - console.log("Wrote ./as-test.config.json"); - writeFileSync(CONFIG_PATH, JSON.stringify(new Config(), null, 2)); - console.log(JSON.stringify(new Config(), null, 2)); - process.exit(0); - } + const CONFIG_PATH = path.join(process.cwd(), "./as-test.config.json"); + if (existsSync(CONFIG_PATH)) { + console.log("Found ./as-test.config.json. Updating..."); + process.exit(0); + } else { + console.log("Wrote ./as-test.config.json"); + writeFileSync(CONFIG_PATH, JSON.stringify(new Config(), null, 2)); + console.log(JSON.stringify(new Config(), null, 2)); + process.exit(0); + } } diff --git a/bin/cli/reporter.js b/bin/cli/reporter.js index 592ff22..7304f8d 100644 --- a/bin/cli/reporter.js +++ b/bin/cli/reporter.js @@ -1,2 +1 @@ -export function report() { -} +export function report() {} diff --git a/bin/cli/run.js b/bin/cli/run.js index a2bc505..da3772a 100644 --- a/bin/cli/run.js +++ b/bin/cli/run.js @@ -5,57 +5,74 @@ import { execSync } from "child_process"; import { glob } from "glob"; import { report } from "../build/log.reporter.js"; const installScripts = new Map([ - ["wasmtime", "curl https://wasmtime.dev/install.sh -sSf | bash"], - ["wasmer", "curl https://get.wasmer.io -sSfL | sh"], + ["wasmtime", "curl https://wasmtime.dev/install.sh -sSf | bash"], + ["wasmer", "curl https://get.wasmer.io -sSfL | sh"], ]); export async function run() { - const reports = []; - const config = Object.assign(new Config(), JSON.parse(readFileSync("./as-test.config.json").toString())); - const inputFiles = await glob(config.input); - console.log(chalk.dim("Running tests using " + config.runOptions.runtime.name + "")); - let execPath = ""; - const PATH = process.env["PATH"]?.split(":"); - for (const bin of PATH) { - if (bin.startsWith("/mnt/")) - continue; // WSL - if (!existsSync(bin)) - continue; - for (const file of readdirSync(bin)) { - if (file == config.runOptions.runtime.run.split(" ")[0] || - file == config.runOptions.runtime.run.split(" ")[0] + ".exe") { - execPath = bin + "/" + file; - } - } + const reports = []; + const config = Object.assign( + new Config(), + JSON.parse(readFileSync("./as-test.config.json").toString()), + ); + const inputFiles = await glob(config.input); + console.log( + chalk.dim("Running tests using " + config.runOptions.runtime.name + ""), + ); + let execPath = ""; + const PATH = process.env["PATH"]?.split(":"); + for (const bin of PATH) { + if (bin.startsWith("/mnt/")) continue; // WSL + if (!existsSync(bin)) continue; + for (const file of readdirSync(bin)) { + if ( + file == config.runOptions.runtime.run.split(" ")[0] || + file == config.runOptions.runtime.run.split(" ")[0] + ".exe" + ) { + execPath = bin + "/" + file; + } } - if (!execPath) { - console.log(chalk.bgRed(" ERROR ") + - chalk.dim(":") + - " could not locate " + - config.runOptions.runtime.run.split(" ")[0] + - " in your PATH variable. Either set it, or install it" + - (config.runOptions.runtime.run.split(" ")[0] - ? "using " + - chalk.dim(installScripts.get(config.runOptions.runtime.run.split(" ")[0])) - : ".")); + } + if (!execPath) { + console.log( + chalk.bgRed(" ERROR ") + + chalk.dim(":") + + " could not locate " + + config.runOptions.runtime.run.split(" ")[0] + + " in your PATH variable. Either set it, or install it" + + (config.runOptions.runtime.run.split(" ")[0] + ? "using " + + chalk.dim( + installScripts.get(config.runOptions.runtime.run.split(" ")[0]), + ) + : "."), + ); + } + for (const file of inputFiles) { + const outFile = + config.outDir + + "/" + + file.slice(file.lastIndexOf("/") + 1).replace(".ts", ".wasm"); + let cmd = config.runOptions.runtime.run + .replace(config.runOptions.runtime.name, execPath) + .replace("", outFile); + if ( + config.runOptions.runtime.run.startsWith("bun") || + config.runOptions.runtime.run.startsWith("node") || + config.runOptions.runtime.run.startsWith("deno") + ) { + cmd = config.runOptions.runtime.run + .replace(config.runOptions.runtime.name, execPath) + .replace("", outFile.replace(".wasm", ".js")); } - for (const file of inputFiles) { - const outFile = config.outDir + - "/" + - file.slice(file.lastIndexOf("/") + 1).replace(".ts", ".wasm"); - let cmd = config.runOptions.runtime.run - .replace(config.runOptions.runtime.name, execPath) - .replace("", outFile); - if (config.runOptions.runtime.run.startsWith("bun") || - config.runOptions.runtime.run.startsWith("node") || - config.runOptions.runtime.run.startsWith("deno")) { - cmd = config.runOptions.runtime.run - .replace(config.runOptions.runtime.name, execPath) - .replace("", outFile.replace(".wasm", ".js")); - } - const stdout = execSync(cmd); - const report = stdout.toString().slice(stdout.indexOf("--REPORT-START--") + 16, stdout.indexOf("--REPORT-END--")); - console.dir(JSON.parse(report), { depth: 256 }); - reports.push(JSON.parse(report)); - } - report(JSON.stringify(reports)); + const stdout = execSync(cmd); + const report = stdout + .toString() + .slice( + stdout.indexOf("--REPORT-START--") + 16, + stdout.indexOf("--REPORT-END--"), + ); + console.dir(JSON.parse(report), { depth: 256 }); + reports.push(JSON.parse(report)); + } + report(JSON.stringify(reports)); } diff --git a/bin/cli/types.js b/bin/cli/types.js index 46109c8..8c2a2c1 100644 --- a/bin/cli/types.js +++ b/bin/cli/types.js @@ -1,31 +1,31 @@ export class Config { - constructor() { - this.input = ["./assembly/__tests__/*.spec.ts"]; - this.outDir = "./build"; - this.config = "./asconfig.json"; - this.buildOptions = new BuildOptions(); - this.runOptions = new RunOptions(); - } + constructor() { + this.input = ["./assembly/__tests__/*.spec.ts"]; + this.outDir = "./build"; + this.config = "./asconfig.json"; + this.buildOptions = new BuildOptions(); + this.runOptions = new RunOptions(); + } } export class Suite { - constructor() { - this.name = ""; - } + constructor() { + this.name = ""; + } } export class BuildOptions { - constructor() { - this.args = []; - this.target = "wasi"; - } + constructor() { + this.args = []; + this.target = "wasi"; + } } export class RunOptions { - constructor() { - this.runtime = new Runtime(); - } + constructor() { + this.runtime = new Runtime(); + } } export class Runtime { - constructor() { - this.name = "wasmtime"; - this.run = "wasmtime "; - } + constructor() { + this.name = "wasmtime"; + this.run = "wasmtime "; + } } diff --git a/bin/cli/util.js b/bin/cli/util.js index 5e8224b..8da941f 100644 --- a/bin/cli/util.js +++ b/bin/cli/util.js @@ -1,23 +1,23 @@ export function formatTime(ms) { - if (ms < 0) { - throw new Error("Time should be a non-negative number."); + if (ms < 0) { + throw new Error("Time should be a non-negative number."); + } + // Convert milliseconds to microseconds + const us = ms * 1000; + const units = [ + { name: "μs", divisor: 1 }, + { name: "ms", divisor: 1000 }, + { name: "s", divisor: 1000 * 1000 }, + { name: "m", divisor: 60 * 1000 * 1000 }, + { name: "h", divisor: 60 * 60 * 1000 * 1000 }, + { name: "d", divisor: 24 * 60 * 60 * 1000 * 1000 }, + ]; + for (let i = units.length - 1; i >= 0; i--) { + const unit = units[i]; + if (us >= unit.divisor) { + const value = Math.round((us / unit.divisor) * 1000) / 1000; + return `${value}${unit.name}`; } - // Convert milliseconds to microseconds - const us = ms * 1000; - const units = [ - { name: "μs", divisor: 1 }, - { name: "ms", divisor: 1000 }, - { name: "s", divisor: 1000 * 1000 }, - { name: "m", divisor: 60 * 1000 * 1000 }, - { name: "h", divisor: 60 * 60 * 1000 * 1000 }, - { name: "d", divisor: 24 * 60 * 60 * 1000 * 1000 }, - ]; - for (let i = units.length - 1; i >= 0; i--) { - const unit = units[i]; - if (us >= unit.divisor) { - const value = Math.round((us / unit.divisor) * 1000) / 1000; - return `${value}${unit.name}`; - } - } - return `${us}us`; + } + return `${us}us`; } diff --git a/bin/index.js b/bin/index.js index 7c36bff..7bed525 100755 --- a/bin/index.js +++ b/bin/index.js @@ -25,13 +25,13 @@ if (!args.length) { else if (COMMANDS.includes(args[0])) { const command = args.shift(); if (command === "build") { - build(args); + build(); } else if (command === "run") { run(); } else if (command === "test") { - build(args).then(() => { + build().then(() => { run(); }); } diff --git a/bin/reporter.js b/bin/reporter.js index 592ff22..d9e8edf 100644 --- a/bin/reporter.js +++ b/bin/reporter.js @@ -1,2 +1 @@ -export function report() { -} +export function report() { } diff --git a/bin/run.js b/bin/run.js index a2bc505..57cac41 100644 --- a/bin/run.js +++ b/bin/run.js @@ -1,61 +1,42 @@ -import { existsSync, readFileSync, readdirSync } from "fs"; -import { Config } from "./types.js"; import chalk from "chalk"; import { execSync } from "child_process"; import { glob } from "glob"; import { report } from "../build/log.reporter.js"; -const installScripts = new Map([ - ["wasmtime", "curl https://wasmtime.dev/install.sh -sSf | bash"], - ["wasmer", "curl https://get.wasmer.io -sSfL | sh"], -]); +import { getExec, loadConfig } from "./util.js"; +import * as path from "path"; +const CONFIG_PATH = path.join(process.cwd(), "./as-test.config.json"); export async function run() { const reports = []; - const config = Object.assign(new Config(), JSON.parse(readFileSync("./as-test.config.json").toString())); + const config = loadConfig(CONFIG_PATH); const inputFiles = await glob(config.input); console.log(chalk.dim("Running tests using " + config.runOptions.runtime.name + "")); - let execPath = ""; - const PATH = process.env["PATH"]?.split(":"); - for (const bin of PATH) { - if (bin.startsWith("/mnt/")) - continue; // WSL - if (!existsSync(bin)) - continue; - for (const file of readdirSync(bin)) { - if (file == config.runOptions.runtime.run.split(" ")[0] || - file == config.runOptions.runtime.run.split(" ")[0] + ".exe") { - execPath = bin + "/" + file; - } - } - } + const exec = config.runOptions.runtime.run.split(" ")[0]; + let execPath = getExec(exec); if (!execPath) { - console.log(chalk.bgRed(" ERROR ") + - chalk.dim(":") + - " could not locate " + - config.runOptions.runtime.run.split(" ")[0] + - " in your PATH variable. Either set it, or install it" + - (config.runOptions.runtime.run.split(" ")[0] - ? "using " + - chalk.dim(installScripts.get(config.runOptions.runtime.run.split(" ")[0])) - : ".")); + console.log(`${chalk.bgRed(" ERROR ")}${chalk.dim(":")} could not locate ${exec} in PATH variable!`); + process.exit(0); } for (const file of inputFiles) { - const outFile = config.outDir + - "/" + - file.slice(file.lastIndexOf("/") + 1).replace(".ts", ".wasm"); + const outFile = path.join(config.outDir, file.slice(file.lastIndexOf("/") + 1).replace(".ts", ".wasm")); let cmd = config.runOptions.runtime.run - .replace(config.runOptions.runtime.name, execPath) + .replace(exec, execPath) .replace("", outFile); - if (config.runOptions.runtime.run.startsWith("bun") || - config.runOptions.runtime.run.startsWith("node") || - config.runOptions.runtime.run.startsWith("deno")) { + if (config.buildOptions.target == "bindings") { cmd = config.runOptions.runtime.run - .replace(config.runOptions.runtime.name, execPath) + .replace(exec, execPath) .replace("", outFile.replace(".wasm", ".js")); } const stdout = execSync(cmd); - const report = stdout.toString().slice(stdout.indexOf("--REPORT-START--") + 16, stdout.indexOf("--REPORT-END--")); - console.dir(JSON.parse(report), { depth: 256 }); + process.stdout.write(stdout.toString().slice(0, stdout.indexOf("--REPORT-START--"))); + const report = stdout + .toString() + .slice(stdout.indexOf("--REPORT-START--") + 16, stdout.indexOf("--REPORT-END--")); reports.push(JSON.parse(report)); } report(JSON.stringify(reports)); + for (const report of reports) { + if (report.verdict == "fail") + process.exit(1); + } + process.exit(0); } diff --git a/bin/util.js b/bin/util.js index 5e8224b..3a0a8c1 100644 --- a/bin/util.js +++ b/bin/util.js @@ -1,3 +1,7 @@ +import { existsSync, readFileSync } from "fs"; +import { Config } from "./types.js"; +import chalk from "chalk"; +import { delimiter, join } from "path"; export function formatTime(ms) { if (ms < 0) { throw new Error("Time should be a non-negative number."); @@ -21,3 +25,23 @@ export function formatTime(ms) { } return `${us}us`; } +export function loadConfig(CONFIG_PATH, warn = false) { + if (!existsSync(CONFIG_PATH)) { + if (warn) + console.log(`${chalk.bgMagentaBright(" WARN ")}${chalk.dim(":")} Could not locate config file in the current directory! Continuing with default config.`); + return new Config(); + } + else { + return Object.assign(new Config(), JSON.parse(readFileSync(CONFIG_PATH).toString())); + } +} +export function getExec(exec) { + const PATH = process.env.PATH.split(delimiter); + for (const pathDir of PATH) { + const fullPath = join(pathDir, exec + (process.platform === "win32" ? ".exe" : "")); + if (existsSync(fullPath)) { + return fullPath; + } + } + return null; +} diff --git a/cli/build.ts b/cli/build.ts index 6f886fd..1aff488 100644 --- a/cli/build.ts +++ b/cli/build.ts @@ -2,93 +2,40 @@ import { existsSync, readFileSync } from "fs"; import { Config } from "./types.js"; import { glob } from "glob"; import chalk from "chalk"; -import { exec } from "child_process"; -import { formatTime } from "./util.js"; +import { execSync } from "child_process"; import * as path from "path"; +import { loadConfig } from "./util.js"; const CONFIG_PATH = path.join(process.cwd(), "./as-test.config.json"); const PKG_PATH = path.join(process.cwd(), "./package.json"); -export async function build(args: string[]) { - let config = loadConfig(); +export async function build() { + let config = loadConfig(CONFIG_PATH, true); const ASCONFIG_PATH = path.join(process.cwd(), config.config); - if (!existsSync(ASCONFIG_PATH)) { + if (config.config && config.config !== "none" && !existsSync(ASCONFIG_PATH)) { console.log( - chalk.bgMagentaBright(" WARN ") + - chalk.dim(":") + - ' Could not locate asconfig.json file! If you do not want to provide a config, set "config": "none". Continuing with default config.' + - "\n", + `${chalk.bgMagentaBright(" WARN ")}${chalk.dim(":")} Could not locate asconfig.json file! If you do not want to provide a config, set "config": "none"`, ); } - verifyPackagesInstalled(config); + ensureDeps(config); - let pkgMan = getPkgManager(); - console.log(""); - const buildCommands: string[] = []; + let pkgRunner = getPkgRunner(); const inputFiles = await glob(config.input); + + let buildArgs = getBuildArgs(config); + for (const file of inputFiles) { - console.log(chalk.dim("Including " + file)); - let command = `${pkgMan} asc ${file}${args.length ? " " + args.join(" ") : ""}`; - if (config.config !== "none") { - command += " --config " + config.config; - } - if (config.buildOptions.target == "wasi") { - command += - " --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json"; - } - const outFile = - config.outDir + - "/" + - file.slice(file.lastIndexOf("/") + 1).replace(".ts", ".wasm"); + let cmd = `${pkgRunner} asc ${file}${buildArgs}`; + const outFile = `${config.outDir}/${file.slice(file.lastIndexOf("/") + 1).replace(".ts", ".wasm")}`; if (config.outDir) { - command += " -o " + outFile; - } - if (config.plugins["coverage"]) { - command += " --use COVERAGE_USE=1 --transform as-test/transform"; - command += " --use COVERAGE_SHOW=1"; - } - if (config.buildOptions.args) { - command += " " + config.buildOptions.args.join(" "); - } - if ( - ["node", "deno", "bun"].includes( - config.runOptions.runtime.run.split(" ")[0], - ) - ) { - command += " --exportStart"; + cmd += " -o " + outFile; } - buildCommands.push(command); + buildFile(cmd); } - - const build = (command: string) => { - return new Promise((resolve, _) => { - console.log(chalk.dim("Building: " + command)); - exec(command, (err, stdout, stderr) => { - process.stdout.write(stdout); - if (err) { - process.stderr.write(stderr + "\n"); - process.exit(1); - } - resolve(); - }); - }); - }; - - console.log(chalk.dim("Building sources in parallel...")); - const start = performance.now(); - let builders: Promise[] = []; - for (const command of buildCommands) { - builders.push(build(command)); - } - - await Promise.all(builders); - console.log( - chalk.dim("Compiled in " + formatTime(performance.now() - start)) + "\n", - ); } -function verifyPackagesInstalled(config: Config): void { +function ensureDeps(config: Config): void { const pkg = JSON.parse(readFileSync(PKG_PATH).toString()) as { dependencies: string[] | null; devDependencies: string[] | null; @@ -98,10 +45,7 @@ function verifyPackagesInstalled(config: Config): void { if (config.buildOptions.target == "wasi") { if (!existsSync("./node_modules/@assemblyscript/wasi-shim/asconfig.json")) { console.log( - chalk.bgRed(" ERROR ") + - chalk.dim(":") + - " " + - "could not find @assemblyscript/wasi-shim! Add it to your dependencies to run with WASI!", + `${chalk.bgRed(" ERROR ")}${chalk.dim(":")} could not find @assemblyscript/wasi-shim! Add it to your dependencies to run with WASI!`, ); process.exit(1); } @@ -117,34 +61,13 @@ function verifyPackagesInstalled(config: Config): void { existsSync("./node_modules/@assemblyscript/wasi-shim/asconfig.json") ) { console.log( - chalk.bold.bgMagentaBright(" WARN ") + - chalk.dim(": @assemblyscript/wasi-shim") + - " is not included in project dependencies!", + `${chalk.bold.bgMagentaBright(" WARN ")}${chalk.dim(":")} @assemblyscript/wasi-shim is not included in project dependencies!"`, ); } } } -function loadConfig(): Config { - if (!existsSync(CONFIG_PATH)) { - console.log( - chalk.bgMagentaBright(" WARN ") + - chalk.dim(":") + - " Could not locate config file in the current directory! Continuing with default config." + - "\n", - ); - console.log(chalk.dim("Using default configuration") + "\n"); - return new Config(); - } else { - console.log(chalk.dim("Loading config from: " + CONFIG_PATH) + "\n"); - return Object.assign( - new Config(), - JSON.parse(readFileSync(CONFIG_PATH).toString()), - ) as Config; - } -} - -function getPkgManager(): string { +function getPkgRunner(): string { switch (process.env.npm_config_user_agent) { case "pnpm": { return "pnpx"; @@ -157,4 +80,38 @@ function getPkgManager(): string { } } return "npx"; -} \ No newline at end of file +} + +function buildFile(command: string): void { + execSync(command, { stdio: "inherit" }); +} + +function getBuildArgs(config: Config): string { + let buildArgs = ""; + + buildArgs += " --transform as-test/transform"; + + if (config.config && config.config !== "none") { + buildArgs += " --config " + config.config; + } + // Should also strip any bindings-enabling from asconfig + if (config.buildOptions.target == "bindings") { + buildArgs += " --bindings esm --exportRuntime --exportStart"; + } else if (config.buildOptions.target == "wasi") { + buildArgs += + " --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json"; + } else { + console.log( + `${chalk.bgRed(" ERROR ")}${chalk.dim(":")} could determine target in config! Set target to 'bindings' or 'wasi'`, + ); + process.exit(0); + } + + if ( + config.buildOptions.args.length && + config.buildOptions.args.find((v) => v.length > 0) + ) { + buildArgs += " " + config.buildOptions.args.join(" "); + } + return buildArgs; +} diff --git a/cli/index.ts b/cli/index.ts index 8641701..453a8d1 100644 --- a/cli/index.ts +++ b/cli/index.ts @@ -27,11 +27,11 @@ if (!args.length) { } else if (COMMANDS.includes(args[0]!)) { const command = args.shift(); if (command === "build") { - build(args); + build(); } else if (command === "run") { run(); } else if (command === "test") { - build(args).then(() => { + build().then(() => { run(); }); } else if (command === "init") { diff --git a/cli/reporter.ts b/cli/reporter.ts index 5dd244d..8e8f1cd 100644 --- a/cli/reporter.ts +++ b/cli/reporter.ts @@ -1,3 +1 @@ -export function report(): void { - -} \ No newline at end of file +export function report(): void {} diff --git a/cli/run.ts b/cli/run.ts index f0fbd32..1015db9 100644 --- a/cli/run.ts +++ b/cli/run.ts @@ -1,83 +1,57 @@ import { existsSync, readFileSync, readdirSync } from "fs"; import { Config } from "./types.js"; import chalk from "chalk"; -import { exec, execSync } from "child_process"; +import { execSync } from "child_process"; import { glob } from "glob"; import { report } from "../build/log.reporter.js"; +import { getExec, loadConfig } from "./util.js"; +import * as path from "path"; -const installScripts = new Map([ - ["wasmtime", "curl https://wasmtime.dev/install.sh -sSf | bash"], - ["wasmer", "curl https://get.wasmer.io -sSfL | sh"], -]); +const CONFIG_PATH = path.join(process.cwd(), "./as-test.config.json"); export async function run() { const reports: any[] = []; - const config = Object.assign( - new Config(), - JSON.parse(readFileSync("./as-test.config.json").toString()), - ) as Config; + const config = loadConfig(CONFIG_PATH); const inputFiles = await glob(config.input); console.log( chalk.dim("Running tests using " + config.runOptions.runtime.name + ""), ); - let execPath = ""; - const PATH = process.env["PATH"]?.split(":")!; - for (const bin of PATH) { - if (bin.startsWith("/mnt/")) continue; // WSL - if (!existsSync(bin)) continue; - for (const file of readdirSync(bin)) { - if ( - file == config.runOptions.runtime.run.split(" ")[0] || - file == config.runOptions.runtime.run.split(" ")[0] + ".exe" - ) { - execPath = bin + "/" + file; - } - } - } + const exec = config.runOptions.runtime.run.split(" ")[0]; + let execPath = getExec(exec); if (!execPath) { - console.log( - chalk.bgRed(" ERROR ") + - chalk.dim(":") + - " could not locate " + - config.runOptions.runtime.run.split(" ")[0] + - " in your PATH variable. Either set it, or install it" + - (config.runOptions.runtime.run.split(" ")[0] - ? "using " + - chalk.dim( - installScripts.get(config.runOptions.runtime.run.split(" ")[0]), - ) - : "."), - ); + console.log(`${chalk.bgRed(" ERROR ")}${chalk.dim(":")} could not locate ${exec} in PATH variable!`); + process.exit(0); } for (const file of inputFiles) { - const outFile = - config.outDir + - "/" + - file.slice(file.lastIndexOf("/") + 1).replace(".ts", ".wasm"); + const outFile = path.join(config.outDir, file.slice(file.lastIndexOf("/") + 1).replace(".ts", ".wasm")); let cmd = config.runOptions.runtime.run - .replace(config.runOptions.runtime.name, execPath) + .replace(exec, execPath) .replace("", outFile); - if ( - config.runOptions.runtime.run.startsWith("bun") || - config.runOptions.runtime.run.startsWith("node") || - config.runOptions.runtime.run.startsWith("deno") - ) { + if (config.buildOptions.target == "bindings") { cmd = config.runOptions.runtime.run - .replace(config.runOptions.runtime.name, execPath) + .replace(exec, execPath) .replace("", outFile.replace(".wasm", ".js")); } - const stdout = execSync(cmd) - const report = stdout.toString().slice( - stdout.indexOf("--REPORT-START--") + 16, - stdout.indexOf("--REPORT-END--"), - ); + const stdout = execSync(cmd); + process.stdout.write(stdout.toString().slice(0, stdout.indexOf("--REPORT-START--"))); + const report = stdout + .toString() + .slice( + stdout.indexOf("--REPORT-START--") + 16, + stdout.indexOf("--REPORT-END--"), + ); reports.push(JSON.parse(report)); } - report(JSON.stringify(reports)) + report(JSON.stringify(reports)); + + for (const report of reports) { + if (report.verdict == "fail") process.exit(1); + } + process.exit(0); } diff --git a/cli/types.ts b/cli/types.ts index 641fb07..adf648a 100644 --- a/cli/types.ts +++ b/cli/types.ts @@ -2,7 +2,7 @@ export class Config { input: string[] = ["./assembly/__tests__/*.spec.ts"]; outDir: string = "./build"; config: string = "./asconfig.json"; - plugins: {} + plugins: {}; buildOptions: BuildOptions = new BuildOptions(); runOptions: RunOptions = new RunOptions(); } @@ -13,7 +13,7 @@ export class Suite { export class BuildOptions { args: string[] = []; - target: string = "wasi" + target: string = "wasi"; } export class RunOptions { diff --git a/cli/util.ts b/cli/util.ts index 6843044..c06f11e 100644 --- a/cli/util.ts +++ b/cli/util.ts @@ -1,3 +1,8 @@ +import { existsSync, readFileSync } from "fs"; +import { Config } from "./types.js"; +import chalk from "chalk"; +import { delimiter, join } from "path"; + export function formatTime(ms: number): string { if (ms < 0) { throw new Error("Time should be a non-negative number."); @@ -10,13 +15,13 @@ export function formatTime(ms: number): string { name: string; divisor: number; }[] = [ - { name: "μs", divisor: 1 }, - { name: "ms", divisor: 1000 }, - { name: "s", divisor: 1000 * 1000 }, - { name: "m", divisor: 60 * 1000 * 1000 }, - { name: "h", divisor: 60 * 60 * 1000 * 1000 }, - { name: "d", divisor: 24 * 60 * 60 * 1000 * 1000 }, - ]; + { name: "μs", divisor: 1 }, + { name: "ms", divisor: 1000 }, + { name: "s", divisor: 1000 * 1000 }, + { name: "m", divisor: 60 * 1000 * 1000 }, + { name: "h", divisor: 60 * 60 * 1000 * 1000 }, + { name: "d", divisor: 24 * 60 * 60 * 1000 * 1000 }, + ]; for (let i = units.length - 1; i >= 0; i--) { const unit = units[i]!; @@ -28,3 +33,29 @@ export function formatTime(ms: number): string { return `${us}us`; } + +export function loadConfig(CONFIG_PATH: string, warn: boolean = false): Config { + if (!existsSync(CONFIG_PATH)) { + if (warn) console.log( + `${chalk.bgMagentaBright(" WARN ")}${chalk.dim(":")} Could not locate config file in the current directory! Continuing with default config.`, + ); + return new Config(); + } else { + return Object.assign( + new Config(), + JSON.parse(readFileSync(CONFIG_PATH).toString()), + ) as Config; + } +} + +export function getExec(exec: string): string | null { + const PATH = process.env.PATH.split(delimiter); + + for (const pathDir of PATH) { + const fullPath = join(pathDir, exec + (process.platform === "win32" ? ".exe" : "")); + if (existsSync(fullPath)) { + return fullPath; + } + } + return null; +} \ No newline at end of file diff --git a/plugins/coverage/reporter.ts b/plugins/coverage/reporter.ts index 15e3367..768a0cd 100644 --- a/plugins/coverage/reporter.ts +++ b/plugins/coverage/reporter.ts @@ -1,6 +1,6 @@ import { __HASHES, __POINTS } from "../../assembly/coverage"; import { Result } from ".."; export function addToResults(): Result { - const result = new Result("Coverage", __HASHES().size, __POINTS()); - return result; -} \ No newline at end of file + const result = new Result("Coverage", __HASHES().size, __POINTS()); + return result; +} diff --git a/plugins/index.ts b/plugins/index.ts index 5ccbfce..3e55bf0 100644 --- a/plugins/index.ts +++ b/plugins/index.ts @@ -1,23 +1,23 @@ import { rainbow } from "as-rainbow"; export class Result { - public name: string; - public arg1: i32; - public arg2: i32; - constructor(name: string, arg1: i32, arg2: i32) { - this.name = name; - this.arg1 = arg1; - this.arg2 = arg2; + public name: string; + public arg1: i32; + public arg2: i32; + constructor(name: string, arg1: i32, arg2: i32) { + this.name = name; + this.arg1 = arg1; + this.arg2 = arg2; + } + display(): string { + let out = ""; + out += `${rainbow.boldMk(this.name)} `; + if (this.arg1) { + out += `${rainbow.boldMk(rainbow.red(this.arg1.toString() + " " + "failed"))}`; + } else { + out += `${rainbow.boldMk(rainbow.green("0 failed"))}`; } - display(): string { - let out = ""; - out += `${rainbow.boldMk(this.name)} `; - if (this.arg1) { - out += `${rainbow.boldMk(rainbow.red(this.arg1.toString() + " " + "failed"))}`; - } else { - out += `${rainbow.boldMk(rainbow.green("0 failed"))}`; - } - out += `, ${this.arg1 + this.arg2} total\n`; - return out; - } -} \ No newline at end of file + out += ` ${this.arg1 + this.arg2} total\n`; + return out; + } +} diff --git a/plugins/tsconfig.json b/plugins/tsconfig.json index 1e97f0f..86b8816 100644 --- a/plugins/tsconfig.json +++ b/plugins/tsconfig.json @@ -1,98 +1,97 @@ { - "extends": "assemblyscript/std/assembly.json", - "include": ["./**/*.ts"], - "compilerOptions": { - /* Visit https://aka.ms/tsconfig to read more about this file */ - /* Projects */ - // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ - // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ - // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ - // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ - // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ - // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - /* Language and Environment */ - "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, - // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ - // "jsx": "preserve", /* Specify what JSX code is generated. */ - "experimentalDecorators": true /* Enable experimental support for TC39 stage 2 draft decorators. */, - "emitDecoratorMetadata": true /* Emit design-type metadata for decorated declarations in source files. */, - // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ - // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ - // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ - // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ - // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ - // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ - /* Modules */ - "module": "commonjs" /* Specify what module code is generated. */, - // "rootDir": "./", /* Specify the root folder within your source files. */ - // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ - // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ - // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ - // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ - // "types": [], /* Specify type package names to be included without being referenced in a source file. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ - // "resolveJsonModule": true, /* Enable importing .json files. */ - // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ - /* JavaScript Support */ - // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ - // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ - // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ - /* Emit */ - // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ - // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ - // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - // "outDir": "./", /* Specify an output folder for all emitted files. */ - // "removeComments": true, /* Disable emitting comments. */ - // "noEmit": true, /* Disable emitting files from a compilation. */ - // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ - // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ - // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ - // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ - // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ - // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ - // "newLine": "crlf", /* Set the newline character for emitting files. */ - // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ - // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ - // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ - // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ - // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ - /* Interop Constraints */ - // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ - // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, - // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, - /* Type Checking */ - "strict": false /* Enable all strict type-checking options. */, - // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ - "strictNullChecks": true /* When type checking, take into account 'null' and 'undefined'. */, - // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ - // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ - // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ - // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ - // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ - // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ - "noUnusedLocals": true /* Enable error reporting when local variables aren't read. */, - "noUnusedParameters": true /* Raise an error when a function parameter isn't read. */, - // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ - // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ - // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ - // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ - // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ - // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - /* Completeness */ - // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ - } + "extends": "assemblyscript/std/assembly.json", + "include": ["./**/*.ts"], + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + /* Language and Environment */ + "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + "experimentalDecorators": true /* Enable experimental support for TC39 stage 2 draft decorators. */, + "emitDecoratorMetadata": true /* Emit design-type metadata for decorated declarations in source files. */, + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + /* Modules */ + "module": "commonjs" /* Specify what module code is generated. */, + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + /* Type Checking */ + "strict": false /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + "strictNullChecks": true /* When type checking, take into account 'null' and 'undefined'. */, + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + "noUnusedLocals": true /* Enable error reporting when local variables aren't read. */, + "noUnusedParameters": true /* Raise an error when a function parameter isn't read. */, + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ } - \ No newline at end of file +} diff --git a/reporters/json/index.ts b/reporters/json/index.ts new file mode 100644 index 0000000..035c06f --- /dev/null +++ b/reporters/json/index.ts @@ -0,0 +1,3 @@ +export function report(_logs: string): string { + return _logs; +} diff --git a/reporters/log/index.ts b/reporters/log/index.ts index a6ba2b8..ca6fd94 100644 --- a/reporters/log/index.ts +++ b/reporters/log/index.ts @@ -5,179 +5,190 @@ import { diff } from "../../assembly/util/helpers"; import { JSON } from "json-as"; import { Result } from "../../plugins/index"; class LogReporter { - public logs: Report[]; - private depth: string = ""; - - private passedFiles: i32 = 0; - private failedFiles: i32 = 0; - - private passedSuites: i32 = 0; - private failedSuites: i32 = 0; - - private passedTests: i32 = 0; - private failedTests: i32 = 0; - - private failed: SuiteReport[] = []; - - - private initialized: boolean = false; - constructor(logs: Report[]) { - this.logs = logs; + public logs: Report[]; + private depth: string = ""; + + private passedFiles: i32 = 0; + private failedFiles: i32 = 0; + + private passedSuites: i32 = 0; + private failedSuites: i32 = 0; + + private passedTests: i32 = 0; + private failedTests: i32 = 0; + + private failed: SuiteReport[] = []; + + private initialized: boolean = false; + constructor(logs: Report[]) { + this.logs = logs; + } + depthInc(): void { + this.depth += " "; + } + depthDec(): void { + this.depth = this.depth.slice(0, this.depth.length - 2); + } + init(): string { + if (this.initialized) return ""; + this.initialized = true; + let out: string = ""; + out += rainbow.boldMk( + rainbow.blueBright( + ` _____ _____ _____ _____ _____ _____ \n` + + `| _ || __| ___|_ _|| __|| __||_ _|\n` + + `| ||__ ||___| | | | __||__ | | | \n` + + `|__|__||_____| |_| |_____||_____| |_| \n`, + ), + ); + out += rainbow.dimMk( + "\n------------------- v0.2.1 -------------------\n\n", + ); + + // @ts-ignore + if (isDefined(COVERAGE_USE)) { + out += + rainbow.bgBlueBright(" PLUGIN ") + + " " + + rainbow.dimMk("Using Code Coverage") + + "\n\n"; } - depthInc(): void { - this.depth += " "; + return out; + } + report(): string { + let out: string = ""; + out += this.init(); + for (let i = 0; i < this.logs.length; i++) { + const log = unchecked(this.logs[i]); + if (log.verdict === Verdict.Fail) this.failedFiles++; + else this.passedFiles++; + out += this.reportLog(log); } - depthDec(): void { - this.depth = this.depth.slice(0, this.depth.length - 2); + out += this.summarize(); + return out; + } + reportLog(log: Report): string { + // @ts-ignore + let out: string = ""; + + out += `${rainbow.bgCyanBright(" FILE ")} ${rainbow.dimMk(log.file)} ${rainbow.italicMk(log.time.format())}\n\n`; + + for (let i = 0; i < log.groups.length; i++) { + const group = unchecked(log.groups[i]); + if (group.verdict === Verdict.Fail) { + this.failedSuites++; + } else { + this.passedSuites++; + } + out += this.reportSuite(group); } - init(): string { - if (this.initialized) return ""; - this.initialized = true; - let out: string = ""; - out += rainbow.boldMk( - rainbow.blueBright( - ` _____ _____ _____ _____ _____ _____ \n` + - `| _ || __| ___|_ _|| __|| __||_ _|\n` + - `| ||__ ||___| | | | __||__ | | | \n` + - `|__|__||_____| |_| |_____||_____| |_| \n`, - ), - ); - out += rainbow.dimMk( - "\n------------------- v0.2.1 -------------------\n\n", - ); - - // @ts-ignore - if (isDefined(COVERAGE_USE)) { - out += - rainbow.bgBlueBright(" PLUGIN ") + - " " + - rainbow.dimMk("Using Code Coverage") + - "\n\n"; - } - return out; - } - report(): string { - let out: string = ""; - out += this.init(); - for (let i = 0; i < this.logs.length; i++) { - const log = unchecked(this.logs[i]); - if (log.verdict === Verdict.Fail) this.failedFiles++; - else this.passedFiles++; - out += this.reportLog(log); - } - out += this.summarize(); - return out; - } - reportLog(log: Report): string { - // @ts-ignore - let out: string = ""; - - out += `${rainbow.bgCyanBright(" FILE ")} ${rainbow.dimMk(log.file)} ${rainbow.italicMk(log.time.format())}\n\n`; - - for (let i = 0; i < log.groups.length; i++) { - const group = unchecked(log.groups[i]); - if (group.verdict === Verdict.Fail) { - this.failedSuites++; - } else { - this.passedSuites++; - } - out += this.reportSuite(group); - } - return out; + return out; + } + reportSuite(suite: SuiteReport): string { + let out = ""; + this.depthInc(); + if (suite.verdict == Verdict.Ok) { + this.passedTests++; + out += `${this.depth}${rainbow.bgGreenBright(" PASS ")} ${rainbow.dimMk(suite.description)} ${rainbow.italicMk(suite.time.format())}\n\n`; + } else if (suite.verdict == Verdict.Fail) { + this.failedTests++; + out += `${this.depth}${rainbow.bgRed(" FAIL ")} ${rainbow.dimMk(suite.description)} ${rainbow.italicMk(suite.time.format())}\n\n`; + } else if (suite.verdict == Verdict.None) { + out += `${this.depth}${rainbow.bgBlackBright(" EMPTY ")} ${rainbow.dimMk(suite.description)} ${rainbow.italicMk("0.00μs")}\n\n`; } - reportSuite(suite: SuiteReport): string { - let out = ""; - this.depthInc(); - if (suite.verdict == Verdict.Ok) { - this.passedTests++; - out += `${this.depth}${rainbow.bgGreenBright(" PASS ")} ${rainbow.dimMk(suite.description)} ${rainbow.italicMk(suite.time.format())}\n\n`; - } else if (suite.verdict == Verdict.Fail) { - this.failedTests++; - out += `${this.depth}${rainbow.bgRed(" FAIL ")} ${rainbow.dimMk(suite.description)} ${rainbow.italicMk(suite.time.format())}\n\n`; - } else if (suite.verdict == Verdict.None) { - out += `${this.depth}${rainbow.bgBlackBright(" EMPTY ")} ${rainbow.dimMk(suite.description)} ${rainbow.italicMk("0.00μs")}\n\n`; - } - for (let i = 0; i < suite.tests.length; i++) { - const _test = unchecked(suite.tests[i]); - if (_test.verdict != Verdict.Ok) { - if (!this.failed.includes(suite)) this.failed.push(suite); - out += this.reportTest(_test); - } - } - - for (let i = 0; i < suite.suites.length; i++) { - const _suite = unchecked(suite.suites[i]); - out += this.reportSuite(_suite); - } - this.depthDec(); - return out; + for (let i = 0; i < suite.tests.length; i++) { + const _test = unchecked(suite.tests[i]); + if (_test.verdict != Verdict.Ok) { + if (!this.failed.includes(suite)) this.failed.push(suite); + } } - reportTest(test: TestReport): string { - let out: string = ""; - this.depthInc(); - const dif = diff(test.left, test.right); - out += - this.depth + - rainbow.dimMk("(expected) ->") + - " " + - rainbow.boldMk(dif.left) + - "\n"; - out += - this.depth + - rainbow.dimMk("(received) ->") + - " " + - rainbow.boldMk(dif.right) + - "\n\n"; - this.depthDec(); - return out; + + for (let i = 0; i < suite.suites.length; i++) { + const _suite = unchecked(suite.suites[i]); + out += this.reportSuite(_suite); } - errors(): string { - let out: string = ""; - if (!this.failed.length) return ""; - out += rainbow.dimMk("----------------- [FAILED] -------------------\n\n"); - for (let i = 0; i < this.failed.length; i++) { - const suite = unchecked(this.failed[i]); - out += `${rainbow.bgRed(" FAIL ")} ${rainbow.dimMk(suite.description)} ${rainbow.italicMk(suite.time.format())}\n\n`; - for (let i = 0; i < suite.tests.length; i++) { - const _test = unchecked(suite.tests[i]); - if (_test.verdict != Verdict.Ok) { - out += this.reportTest(_test); - } - } + this.depthDec(); + return out; + } + reportTest(test: TestReport): string { + let out: string = ""; + this.depthInc(); + const dif = diff(test.left, test.right); + out += + this.depth + + rainbow.dimMk("(expected) ->") + + " " + + rainbow.boldMk(dif.left) + + "\n"; + out += + this.depth + + rainbow.dimMk("(received) ->") + + " " + + rainbow.boldMk(dif.right) + + "\n\n"; + this.depthDec(); + return out; + } + errors(): string { + let out: string = ""; + if (!this.failed.length) return ""; + out += rainbow.dimMk("----------------- [FAILED] -------------------\n\n"); + for (let i = 0; i < this.failed.length; i++) { + const suite = unchecked(this.failed[i]); + out += `${rainbow.bgRed(" FAIL ")} ${rainbow.dimMk(suite.description)} ${rainbow.italicMk(suite.time.format())}\n\n`; + for (let i = 0; i < suite.tests.length; i++) { + const _test = unchecked(suite.tests[i]); + if (_test.verdict != Verdict.Ok) { + out += this.reportTest(_test); } - return out; + } } - summarize(): string { - let out: string = ""; - out += this.errors(); - out += rainbow.dimMk("----------------- [RESULTS] ------------------\n\n"); - - const filesResult = new Result("Files: ", this.failedFiles, this.passedFiles); - out += filesResult.display(); - - const suitesResult = new Result("Suites: ", this.failedSuites, this.passedSuites); - out += suitesResult.display(); - - const testsResult = new Result("Tests: ", this.failedTests, this.passedTests); - out += testsResult.display(); - - // @ts-ignore - const time = new Time(); - for (let i = 0; i < this.logs.length; i++) { - const log = unchecked(this.logs[i]); - time.end += log.time.end - log.time.start; - } - - out += `${rainbow.boldMk("Time:")} ${time.format()}`; - return out; + return out; + } + summarize(): string { + let out: string = ""; + out += this.errors(); + out += rainbow.dimMk("----------------- [RESULTS] ------------------\n\n"); + + const filesResult = new Result( + "Files: ", + this.failedFiles, + this.passedFiles, + ); + out += filesResult.display(); + + const suitesResult = new Result( + "Suites: ", + this.failedSuites, + this.passedSuites, + ); + out += suitesResult.display(); + + const testsResult = new Result( + "Tests: ", + this.failedTests, + this.passedTests, + ); + out += testsResult.display(); + + // @ts-ignore + const time = new Time(); + for (let i = 0; i < this.logs.length; i++) { + const log = unchecked(this.logs[i]); + time.end += log.time.end - log.time.start; } + + out += `${rainbow.boldMk("Time:")} ${time.format()}`; + + return out; + } } export function report(_logs: string): void { - const logs = JSON.parse(_logs); - const reporter = new LogReporter(logs); - const out = reporter.report(); - console.log(out); + const logs = JSON.parse(_logs); + const reporter = new LogReporter(logs); + const out = reporter.report(); + console.log(out); } diff --git a/reporters/report.ts b/reporters/report.ts index b67a9c7..b372b4c 100644 --- a/reporters/report.ts +++ b/reporters/report.ts @@ -2,6 +2,7 @@ import { Verdict } from "../assembly"; import { Suite } from "../assembly/src/suite"; import { Tests } from "../assembly/src/tests"; + @json export class Time { start: f64 = 0; @@ -11,6 +12,7 @@ export class Time { } } + @json export class Report { time: Time = new Time(); @@ -75,10 +77,8 @@ class Unit { divisor: number; } -function formatTime(time: number): string { - if (time < 0) { - throw new Error("Time should be a non-negative number."); - } +function formatTime(time: f64): string { + if (time < 0) return "0.00μs"; const us = time * 1000; @@ -94,10 +94,14 @@ function formatTime(time: number): string { for (let i = units.length - 1; i >= 0; i--) { const unit = units[i]; if (us >= unit.divisor) { - const value = Math.round((us / unit.divisor) * 100) / 100; - return `${value}${unit.name}`; + const value = (Math.round((us / unit.divisor) * 100) / 100).toString(); + const precision = value.indexOf("."); + return `${value.slice(0, precision) + value.slice(precision, precision + 3)}${unit.name}`; } } - return `${us}us`; -} \ No newline at end of file + const _us = us.toString(); + const precision = _us.indexOf("."); + + return `${_us.slice(0, precision) + _us.slice(precision, precision + 3)}μs`; +} diff --git a/reporters/tsconfig.json b/reporters/tsconfig.json index 1e97f0f..86b8816 100644 --- a/reporters/tsconfig.json +++ b/reporters/tsconfig.json @@ -1,98 +1,97 @@ { - "extends": "assemblyscript/std/assembly.json", - "include": ["./**/*.ts"], - "compilerOptions": { - /* Visit https://aka.ms/tsconfig to read more about this file */ - /* Projects */ - // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ - // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ - // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ - // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ - // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ - // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - /* Language and Environment */ - "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, - // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ - // "jsx": "preserve", /* Specify what JSX code is generated. */ - "experimentalDecorators": true /* Enable experimental support for TC39 stage 2 draft decorators. */, - "emitDecoratorMetadata": true /* Emit design-type metadata for decorated declarations in source files. */, - // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ - // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ - // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ - // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ - // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ - // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ - /* Modules */ - "module": "commonjs" /* Specify what module code is generated. */, - // "rootDir": "./", /* Specify the root folder within your source files. */ - // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ - // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ - // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ - // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ - // "types": [], /* Specify type package names to be included without being referenced in a source file. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ - // "resolveJsonModule": true, /* Enable importing .json files. */ - // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ - /* JavaScript Support */ - // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ - // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ - // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ - /* Emit */ - // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ - // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ - // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - // "outDir": "./", /* Specify an output folder for all emitted files. */ - // "removeComments": true, /* Disable emitting comments. */ - // "noEmit": true, /* Disable emitting files from a compilation. */ - // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ - // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ - // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ - // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ - // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ - // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ - // "newLine": "crlf", /* Set the newline character for emitting files. */ - // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ - // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ - // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ - // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ - // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ - /* Interop Constraints */ - // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ - // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, - // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, - /* Type Checking */ - "strict": false /* Enable all strict type-checking options. */, - // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ - "strictNullChecks": true /* When type checking, take into account 'null' and 'undefined'. */, - // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ - // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ - // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ - // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ - // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ - // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ - "noUnusedLocals": true /* Enable error reporting when local variables aren't read. */, - "noUnusedParameters": true /* Raise an error when a function parameter isn't read. */, - // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ - // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ - // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ - // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ - // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ - // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - /* Completeness */ - // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ - } + "extends": "assemblyscript/std/assembly.json", + "include": ["./**/*.ts"], + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + /* Language and Environment */ + "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + "experimentalDecorators": true /* Enable experimental support for TC39 stage 2 draft decorators. */, + "emitDecoratorMetadata": true /* Emit design-type metadata for decorated declarations in source files. */, + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + /* Modules */ + "module": "commonjs" /* Specify what module code is generated. */, + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + /* Type Checking */ + "strict": false /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + "strictNullChecks": true /* When type checking, take into account 'null' and 'undefined'. */, + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + "noUnusedLocals": true /* Enable error reporting when local variables aren't read. */, + "noUnusedParameters": true /* Raise an error when a function parameter isn't read. */, + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ } - \ No newline at end of file +} diff --git a/transform/lib/coverage.js b/transform/lib/coverage.js index 4df9aaf..0b23a27 100644 --- a/transform/lib/coverage.js +++ b/transform/lib/coverage.js @@ -1,44 +1,47 @@ -import { BlockStatement, ExpressionStatement, Node, } from "assemblyscript/dist/assemblyscript.js"; +import { + BlockStatement, + ExpressionStatement, + Node, +} from "assemblyscript/dist/assemblyscript.js"; import { BaseVisitor, SimpleParser } from "visitor-as/dist/index.js"; import { RangeTransform } from "visitor-as/dist/transformRange.js"; import { isStdlib } from "visitor-as/dist/utils.js"; var CoverType; (function (CoverType) { - CoverType[CoverType["Function"] = 0] = "Function"; - CoverType[CoverType["Expression"] = 1] = "Expression"; - CoverType[CoverType["Block"] = 2] = "Block"; + CoverType[(CoverType["Function"] = 0)] = "Function"; + CoverType[(CoverType["Expression"] = 1)] = "Expression"; + CoverType[(CoverType["Block"] = 2)] = "Block"; })(CoverType || (CoverType = {})); class CoverPoint { - file = ""; - hash = ""; - line = 0; - column = 0; - type; - executed = false; + file = ""; + hash = ""; + line = 0; + column = 0; + type; + executed = false; } export class CoverageTransform extends BaseVisitor { - mustImport = false; - points = new Map(); - globalStatements = []; - visitBinaryExpression(node) { - super.visitBinaryExpression(node); - if (node.visited) - return; - node.visited = true; - const path = node.range.source.normalizedPath; - switch (node.operator) { - case 98: - case 97: { - const right = node.right; - const rightLc = getLineCol(node); - const point = new CoverPoint(); - point.line = rightLc?.line; - point.column = rightLc?.column; - point.file = path; - point.type = CoverType.Expression; - point.hash = hash(point); - const replacer = new RangeTransform(node); - const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({ + mustImport = false; + points = new Map(); + globalStatements = []; + visitBinaryExpression(node) { + super.visitBinaryExpression(node); + if (node.visited) return; + node.visited = true; + const path = node.range.source.normalizedPath; + switch (node.operator) { + case 98: + case 97: { + const right = node.right; + const rightLc = getLineCol(node); + const point = new CoverPoint(); + point.line = rightLc?.line; + point.column = rightLc?.column; + point.file = path; + point.type = CoverType.Expression; + point.hash = hash(point); + const replacer = new RangeTransform(node); + const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({ file: "${point.file}", hash: "${point.hash}", line: ${point.line}, @@ -46,35 +49,35 @@ export class CoverageTransform extends BaseVisitor { type: "Expression", executed: false });`); - replacer.visit(registerStmt); - let coverExpression = SimpleParser.parseExpression(`(__COVER("${point.hash}"), $$REPLACE_ME)`); - replacer.visit(coverExpression); - coverExpression.expression.expressions[1] = right; - node.right = coverExpression; - this.globalStatements.push(registerStmt); - break; - } - } + replacer.visit(registerStmt); + let coverExpression = SimpleParser.parseExpression( + `(__COVER("${point.hash}"), $$REPLACE_ME)`, + ); + replacer.visit(coverExpression); + coverExpression.expression.expressions[1] = right; + node.right = coverExpression; + this.globalStatements.push(registerStmt); + break; + } } - visitMethodDeclaration(node) { - super.visitMethodDeclaration(node); - if (node.visited) - return; - node.visited = true; - if (node.body) { - if (node.body.visited) - return; - node.body.visited = true; - const path = node.range.source.normalizedPath; - const funcLc = getLineCol(node); - const point = new CoverPoint(); - point.line = funcLc?.line; - point.column = funcLc?.column; - point.file = path; - point.type = CoverType.Function; - point.hash = hash(point); - const replacer = new RangeTransform(node); - const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({ + } + visitMethodDeclaration(node) { + super.visitMethodDeclaration(node); + if (node.visited) return; + node.visited = true; + if (node.body) { + if (node.body.visited) return; + node.body.visited = true; + const path = node.range.source.normalizedPath; + const funcLc = getLineCol(node); + const point = new CoverPoint(); + point.line = funcLc?.line; + point.column = funcLc?.column; + point.file = path; + point.type = CoverType.Function; + point.hash = hash(point); + const replacer = new RangeTransform(node); + const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({ file: "${point.file}", hash: "${point.hash}", line: ${point.line}, @@ -82,33 +85,34 @@ export class CoverageTransform extends BaseVisitor { type: "Function", executed: false })`); - replacer.visit(registerStmt); - const coverStmt = SimpleParser.parseStatement(`__COVER("${point.hash}")`, true); - replacer.visit(coverStmt); - const bodyBlock = node.body; - bodyBlock.statements.unshift(coverStmt); - this.globalStatements.push(registerStmt); - } + replacer.visit(registerStmt); + const coverStmt = SimpleParser.parseStatement( + `__COVER("${point.hash}")`, + true, + ); + replacer.visit(coverStmt); + const bodyBlock = node.body; + bodyBlock.statements.unshift(coverStmt); + this.globalStatements.push(registerStmt); } - visitParameter(node) { - if (node.visited) - return; - node.visited = true; - const path = node.range.source.normalizedPath; - if (node.initializer) { - if (node.initializer.visited) - return; - node.initializer.visited = true; - super.visitParameter(node); - const paramLc = getLineCol(node.initializer); - const point = new CoverPoint(); - point.line = paramLc?.line; - point.column = paramLc?.column; - point.file = path; - point.type = CoverType.Expression; - point.hash = hash(point); - const replacer = new RangeTransform(node); - const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({ + } + visitParameter(node) { + if (node.visited) return; + node.visited = true; + const path = node.range.source.normalizedPath; + if (node.initializer) { + if (node.initializer.visited) return; + node.initializer.visited = true; + super.visitParameter(node); + const paramLc = getLineCol(node.initializer); + const point = new CoverPoint(); + point.line = paramLc?.line; + point.column = paramLc?.column; + point.file = path; + point.type = CoverType.Expression; + point.hash = hash(point); + const replacer = new RangeTransform(node); + const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({ file: "${point.file}", hash: "${point.hash}", line: ${point.line}, @@ -116,34 +120,33 @@ export class CoverageTransform extends BaseVisitor { type: "Expression", executed: false })`); - replacer.visit(registerStmt); - const coverExpression = SimpleParser.parseExpression(`(__COVER("${point.hash}"), $$REPLACE_ME)`); - replacer.visit(coverExpression); - coverExpression.expression.expressions[1] = - node.initializer; - node.initializer = coverExpression; - this.globalStatements.push(registerStmt); - } + replacer.visit(registerStmt); + const coverExpression = SimpleParser.parseExpression( + `(__COVER("${point.hash}"), $$REPLACE_ME)`, + ); + replacer.visit(coverExpression); + coverExpression.expression.expressions[1] = node.initializer; + node.initializer = coverExpression; + this.globalStatements.push(registerStmt); } - visitFunctionDeclaration(node, isDefault) { - super.visitFunctionDeclaration(node, isDefault); - if (node.visited) - return; - node.visited = true; - if (node.body) { - if (node.body.visited) - return; - node.body.visited = true; - const path = node.range.source.normalizedPath; - const funcLc = getLineCol(node); - const point = new CoverPoint(); - point.line = funcLc?.line; - point.column = funcLc?.column; - point.file = path; - point.type = CoverType.Function; - point.hash = hash(point); - const replacer = new RangeTransform(node); - const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({ + } + visitFunctionDeclaration(node, isDefault) { + super.visitFunctionDeclaration(node, isDefault); + if (node.visited) return; + node.visited = true; + if (node.body) { + if (node.body.visited) return; + node.body.visited = true; + const path = node.range.source.normalizedPath; + const funcLc = getLineCol(node); + const point = new CoverPoint(); + point.line = funcLc?.line; + point.column = funcLc?.column; + point.file = path; + point.type = CoverType.Function; + point.hash = hash(point); + const replacer = new RangeTransform(node); + const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({ file: "${point.file}", hash: "${point.hash}", line: ${point.line}, @@ -151,54 +154,57 @@ export class CoverageTransform extends BaseVisitor { type: "Function", executed: false })`); - replacer.visit(registerStmt); - this.globalStatements.push(registerStmt); - if (node.body.kind === 35) { - const coverStmt = SimpleParser.parseStatement(`{ + replacer.visit(registerStmt); + this.globalStatements.push(registerStmt); + if (node.body.kind === 35) { + const coverStmt = SimpleParser.parseStatement(`{ __COVER("${point.hash}") return $$REPLACE_ME }`); - replacer.visit(coverStmt); - const bodyReturn = coverStmt.statements[1]; - const body = node.body; - node.arrowKind = 2; - bodyReturn.value = body.expression; - node.body = body; - } - else { - const coverStmt = SimpleParser.parseStatement(`__COVER("${point.hash}")`, true); - replacer.visit(coverStmt); - if (node.body instanceof BlockStatement) { - node.body.statements.unshift(coverStmt); - } - else if (node.body instanceof ExpressionStatement) { - const expression = node.body.expression; - node.body = Node.createBlockStatement([Node.createReturnStatement(expression, expression.range)], expression.range); - const bodyBlock = node.body; - bodyBlock.statements.unshift(coverStmt); - } - } + replacer.visit(coverStmt); + const bodyReturn = coverStmt.statements[1]; + const body = node.body; + node.arrowKind = 2; + bodyReturn.value = body.expression; + node.body = body; + } else { + const coverStmt = SimpleParser.parseStatement( + `__COVER("${point.hash}")`, + true, + ); + replacer.visit(coverStmt); + if (node.body instanceof BlockStatement) { + node.body.statements.unshift(coverStmt); + } else if (node.body instanceof ExpressionStatement) { + const expression = node.body.expression; + node.body = Node.createBlockStatement( + [Node.createReturnStatement(expression, expression.range)], + expression.range, + ); + const bodyBlock = node.body; + bodyBlock.statements.unshift(coverStmt); } + } } - visitIfStatement(node) { - if (node.visited) - return; - node.visited = true; - let visitIfTrue = false; - let visitIfFalse = false; - const ifTrue = node.ifTrue; - const ifFalse = node.ifFalse; - const path = node.range.source.normalizedPath; - if (ifTrue.kind !== 30) { - const trueLc = getLineCol(ifTrue); - const point = new CoverPoint(); - point.line = trueLc?.line; - point.column = trueLc?.column; - point.file = path; - point.type = CoverType.Expression; - point.hash = hash(point); - const replacer = new RangeTransform(ifTrue); - const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({ + } + visitIfStatement(node) { + if (node.visited) return; + node.visited = true; + let visitIfTrue = false; + let visitIfFalse = false; + const ifTrue = node.ifTrue; + const ifFalse = node.ifFalse; + const path = node.range.source.normalizedPath; + if (ifTrue.kind !== 30) { + const trueLc = getLineCol(ifTrue); + const point = new CoverPoint(); + point.line = trueLc?.line; + point.column = trueLc?.column; + point.file = path; + point.type = CoverType.Expression; + point.hash = hash(point); + const replacer = new RangeTransform(ifTrue); + const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({ file: "${point.file}", hash: "${point.hash}", line: ${point.line}, @@ -206,25 +212,28 @@ export class CoverageTransform extends BaseVisitor { type: "Expression", executed: false })`); - replacer.visit(registerStmt); - const coverStmt = SimpleParser.parseStatement(`{__COVER("${point.hash}")};`, true); - replacer.visit(coverStmt); - coverStmt.statements.push(ifTrue); - node.ifTrue = coverStmt; - this.globalStatements.push(registerStmt); - visitIfTrue = true; - visitIfFalse = !!ifFalse; - } - if (ifFalse && ifFalse.kind !== 30) { - const falseLc = getLineCol(ifFalse); - const point = new CoverPoint(); - point.line = falseLc?.line; - point.column = falseLc?.column; - point.file = path; - point.type = CoverType.Expression; - point.hash = hash(point); - const replacer = new RangeTransform(ifTrue); - const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({ + replacer.visit(registerStmt); + const coverStmt = SimpleParser.parseStatement( + `{__COVER("${point.hash}")};`, + true, + ); + replacer.visit(coverStmt); + coverStmt.statements.push(ifTrue); + node.ifTrue = coverStmt; + this.globalStatements.push(registerStmt); + visitIfTrue = true; + visitIfFalse = !!ifFalse; + } + if (ifFalse && ifFalse.kind !== 30) { + const falseLc = getLineCol(ifFalse); + const point = new CoverPoint(); + point.line = falseLc?.line; + point.column = falseLc?.column; + point.file = path; + point.type = CoverType.Expression; + point.hash = hash(point); + const replacer = new RangeTransform(ifTrue); + const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({ file: "${point.file}", hash: "${point.hash}", line: ${point.line}, @@ -232,51 +241,50 @@ export class CoverageTransform extends BaseVisitor { type: "Expression", executed: false })`); - replacer.visit(registerStmt); - const coverStmt = SimpleParser.parseStatement(`{__COVER("${point.hash}")};`, true); - replacer.visit(coverStmt); - coverStmt.statements.push(ifFalse); - node.ifFalse = coverStmt; - this.globalStatements.push(registerStmt); - visitIfTrue = true; - visitIfFalse = true; - } - if (visitIfTrue || visitIfFalse) { - if (visitIfTrue) { - if (ifTrue.visited) - return; - ifTrue.visited = true; - this._visit(ifTrue); - } - if (visitIfFalse) { - if (ifFalse.visited) - return; - ifFalse.visited = true; - this._visit(ifFalse); - } - } - else { - super.visitIfStatement(node); - } + replacer.visit(registerStmt); + const coverStmt = SimpleParser.parseStatement( + `{__COVER("${point.hash}")};`, + true, + ); + replacer.visit(coverStmt); + coverStmt.statements.push(ifFalse); + node.ifFalse = coverStmt; + this.globalStatements.push(registerStmt); + visitIfTrue = true; + visitIfFalse = true; + } + if (visitIfTrue || visitIfFalse) { + if (visitIfTrue) { + if (ifTrue.visited) return; + ifTrue.visited = true; + this._visit(ifTrue); + } + if (visitIfFalse) { + if (ifFalse.visited) return; + ifFalse.visited = true; + this._visit(ifFalse); + } + } else { + super.visitIfStatement(node); } - visitTernaryExpression(node) { - if (node.visited) - return; - node.visited = true; - super.visitTernaryExpression(node); - const trueExpression = node.ifThen; - const falseExpression = node.ifElse; - const path = node.range.source.normalizedPath; - { - const trueLc = getLineCol(trueExpression); - const point = new CoverPoint(); - point.line = trueLc?.line; - point.column = trueLc?.column; - point.file = path; - point.type = CoverType.Expression; - point.hash = hash(point); - const replacer = new RangeTransform(trueExpression); - const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({ + } + visitTernaryExpression(node) { + if (node.visited) return; + node.visited = true; + super.visitTernaryExpression(node); + const trueExpression = node.ifThen; + const falseExpression = node.ifElse; + const path = node.range.source.normalizedPath; + { + const trueLc = getLineCol(trueExpression); + const point = new CoverPoint(); + point.line = trueLc?.line; + point.column = trueLc?.column; + point.file = path; + point.type = CoverType.Expression; + point.hash = hash(point); + const replacer = new RangeTransform(trueExpression); + const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({ file: "${point.file}", hash: "${point.hash}", line: ${point.line}, @@ -284,24 +292,25 @@ export class CoverageTransform extends BaseVisitor { type: "Expression", executed: false })`); - replacer.visit(registerStmt); - const coverExpression = SimpleParser.parseExpression(`(__COVER("${point.hash}"), $$REPLACE_ME)`); - replacer.visit(coverExpression); - coverExpression.expression.expressions[1] = - trueExpression; - node.ifThen = coverExpression; - this.globalStatements.push(registerStmt); - } - { - const falseLc = getLineCol(falseExpression); - const point = new CoverPoint(); - point.line = falseLc?.line; - point.column = falseLc?.column; - point.file = path; - point.type = CoverType.Expression; - point.hash = hash(point); - const replacer = new RangeTransform(falseExpression); - const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({ + replacer.visit(registerStmt); + const coverExpression = SimpleParser.parseExpression( + `(__COVER("${point.hash}"), $$REPLACE_ME)`, + ); + replacer.visit(coverExpression); + coverExpression.expression.expressions[1] = trueExpression; + node.ifThen = coverExpression; + this.globalStatements.push(registerStmt); + } + { + const falseLc = getLineCol(falseExpression); + const point = new CoverPoint(); + point.line = falseLc?.line; + point.column = falseLc?.column; + point.file = path; + point.type = CoverType.Expression; + point.hash = hash(point); + const replacer = new RangeTransform(falseExpression); + const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({ file: "${point.file}", hash: "${point.hash}", line: ${point.line}, @@ -309,29 +318,29 @@ export class CoverageTransform extends BaseVisitor { type: "Expression", executed: false })`); - replacer.visit(registerStmt); - const coverExpression = SimpleParser.parseExpression(`(__COVER("${point.hash}"), $$REPLACE_ME)`); - replacer.visit(coverExpression); - coverExpression.expression.expressions[1] = - falseExpression; - node.ifElse = coverExpression; - this.globalStatements.push(registerStmt); - } + replacer.visit(registerStmt); + const coverExpression = SimpleParser.parseExpression( + `(__COVER("${point.hash}"), $$REPLACE_ME)`, + ); + replacer.visit(coverExpression); + coverExpression.expression.expressions[1] = falseExpression; + node.ifElse = coverExpression; + this.globalStatements.push(registerStmt); } - visitSwitchCase(node) { - if (node.visited) - return; - node.visited = true; - const path = node.range.source.normalizedPath; - const caseLc = getLineCol(node); - const point = new CoverPoint(); - point.line = caseLc?.line; - point.column = caseLc?.column; - point.file = path; - point.type = CoverType.Block; - point.hash = hash(point); - const replacer = new RangeTransform(node); - const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({ + } + visitSwitchCase(node) { + if (node.visited) return; + node.visited = true; + const path = node.range.source.normalizedPath; + const caseLc = getLineCol(node); + const point = new CoverPoint(); + point.line = caseLc?.line; + point.column = caseLc?.column; + point.file = path; + point.type = CoverType.Block; + point.hash = hash(point); + const replacer = new RangeTransform(node); + const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({ file: "${point.file}", hash: "${point.hash}", line: ${point.line}, @@ -339,27 +348,26 @@ export class CoverageTransform extends BaseVisitor { type: "Block", executed: false })`); - replacer.visit(registerStmt); - const coverStmt = SimpleParser.parseStatement(`__COVER("${point.hash}")`); - replacer.visit(coverStmt); - this.globalStatements.push(registerStmt); - super.visitSwitchCase(node); - node.statements.unshift(coverStmt); - } - visitBlockStatement(node) { - if (node.visited) - return; - node.visited = true; - const path = node.range.source.normalizedPath; - const blockLc = getLineCol(node); - const point = new CoverPoint(); - point.line = blockLc?.line; - point.column = blockLc?.column; - point.file = path; - point.type = CoverType.Block; - point.hash = hash(point); - const replacer = new RangeTransform(node); - const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({ + replacer.visit(registerStmt); + const coverStmt = SimpleParser.parseStatement(`__COVER("${point.hash}")`); + replacer.visit(coverStmt); + this.globalStatements.push(registerStmt); + super.visitSwitchCase(node); + node.statements.unshift(coverStmt); + } + visitBlockStatement(node) { + if (node.visited) return; + node.visited = true; + const path = node.range.source.normalizedPath; + const blockLc = getLineCol(node); + const point = new CoverPoint(); + point.line = blockLc?.line; + point.column = blockLc?.column; + point.file = path; + point.type = CoverType.Block; + point.hash = hash(point); + const replacer = new RangeTransform(node); + const registerStmt = SimpleParser.parseTopLevelStatement(`__REGISTER({ file: "${point.file}", hash: "${point.hash}", line: ${point.line}, @@ -367,51 +375,49 @@ export class CoverageTransform extends BaseVisitor { type: "Block", executed: false })`); - replacer.visit(registerStmt); - const coverStmt = SimpleParser.parseStatement(`__COVER("${point.hash}")`); - replacer.visit(coverStmt); - this.globalStatements.push(registerStmt); - super.visitBlockStatement(node); - node.statements.unshift(coverStmt); - } - visitSource(node) { - if (node.isLibrary) - return; - if (node.simplePath === "coverage") - return; - if (isStdlib(node)) - return; - super.visitSource(node); - } + replacer.visit(registerStmt); + const coverStmt = SimpleParser.parseStatement(`__COVER("${point.hash}")`); + replacer.visit(coverStmt); + this.globalStatements.push(registerStmt); + super.visitBlockStatement(node); + node.statements.unshift(coverStmt); + } + visitSource(node) { + if (node.isLibrary) return; + if (node.simplePath === "coverage") return; + if (isStdlib(node)) return; + super.visitSource(node); + } } function djb2Hash(str) { - const points = Array.from(str); - let h = 5381; - for (let p = 0; p < points.length; p++) - h = ((h << 5) - h + points[p].codePointAt(0)) | 0; - return h; + const points = Array.from(str); + let h = 5381; + for (let p = 0; p < points.length; p++) + h = ((h << 5) - h + points[p].codePointAt(0)) | 0; + return h; } function hash(point) { - const hsh = djb2Hash(point.file + - point.line.toString() + - point.column.toString() + - point.type.toString()); - if (hsh < 0) { - const out = hsh.toString(16); - return "3" + out.slice(1); - } - else { - return hsh.toString(16); - } + const hsh = djb2Hash( + point.file + + point.line.toString() + + point.column.toString() + + point.type.toString(), + ); + if (hsh < 0) { + const out = hsh.toString(16); + return "3" + out.slice(1); + } else { + return hsh.toString(16); + } } class LineColumn { - line; - column; + line; + column; } function getLineCol(node) { - return { - line: node.range.source.lineAt(node.range.start), - column: node.range.source.columnAt(), - }; + return { + line: node.range.source.lineAt(node.range.start), + column: node.range.source.columnAt(), + }; } -//# sourceMappingURL=coverage.js.map \ No newline at end of file +//# sourceMappingURL=coverage.js.map diff --git a/transform/lib/index.js b/transform/lib/index.js index 7b453f5..8978b87 100644 --- a/transform/lib/index.js +++ b/transform/lib/index.js @@ -1,44 +1,39 @@ import { Transform } from "assemblyscript/dist/transform.js"; -import { Node, Source, Tokenizer, } from "assemblyscript/dist/assemblyscript.js"; +import { Node } from "assemblyscript/dist/assemblyscript.js"; import { isStdlib } from "visitor-as/dist/utils.js"; -import { CoverageTransform } from "./coverage.js"; -import { MockTransform } from "./mock.js"; export default class Transformer extends Transform { - afterParse(parser) { - const mock = new MockTransform(); - const coverage = new CoverageTransform(); - const sources = parser.sources - .filter((source) => !isStdlib(source)) - .sort((_a, _b) => { - const a = _a.internalPath; - const b = _b.internalPath; - if (a[0] === "~" && b[0] !== "~") { - return -1; - } - else if (a[0] !== "~" && b[0] === "~") { - return 1; - } - else { - return 0; - } - }); - const entryFile = sources.find(v => v.sourceKind == 1).simplePath; - for (const source of sources) { - const node = Node.createVariableStatement(null, [ - Node.createVariableDeclaration(Node.createIdentifierExpression("ENTRY_FILE", source.range), null, 8, null, Node.createStringLiteralExpression(entryFile + ".ts", source.range), source.range) - ], source.range); - source.statements.unshift(node); - mock.visit(source); - coverage.visit(source); - if (coverage.globalStatements.length) { - source.statements.unshift(...coverage.globalStatements); - const tokenizer = new Tokenizer(new Source(0, source.normalizedPath, 'import { __REGISTER, __COVER } from "as-test/assembly/coverage";')); - parser.currentSource = tokenizer.source; - source.statements.unshift(parser.parseTopLevelStatement(tokenizer)); - parser.currentSource = source; - } + afterParse(parser) { + const sources = parser.sources + .filter((source) => !isStdlib(source)) + .sort((_a, _b) => { + const a = _a.internalPath; + const b = _b.internalPath; + if (a[0] === "~" && b[0] !== "~") { + return -1; + } else if (a[0] !== "~" && b[0] === "~") { + return 1; + } else { + return 0; } - coverage.globalStatements = []; + }); + const entryFile = sources.find((v) => v.sourceKind == 1).simplePath; + for (const source of sources) { + const node = Node.createVariableStatement( + null, + [ + Node.createVariableDeclaration( + Node.createIdentifierExpression("ENTRY_FILE", source.range), + null, + 8, + null, + Node.createStringLiteralExpression(entryFile + ".ts", source.range), + source.range, + ), + ], + source.range, + ); + source.statements.unshift(node); } + } } -//# sourceMappingURL=index.js.map \ No newline at end of file +//# sourceMappingURL=index.js.map diff --git a/transform/lib/index.js.map b/transform/lib/index.js.map index 924207d..1eb96ac 100644 --- a/transform/lib/index.js.map +++ b/transform/lib/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAC7D,OAAO,EAEL,IAAI,EAGJ,MAAM,EAEN,SAAS,GAEV,MAAM,uCAAuC,CAAC;AAE/C,OAAO,EAAE,QAAQ,EAAY,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE1C,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,SAAS;IAEhD,UAAU,CAAC,MAAc;QAEvB,MAAM,IAAI,GAAG,IAAI,aAAa,EAAE,CAAC;QACjC,MAAM,QAAQ,GAAG,IAAI,iBAAiB,EAAE,CAAC;QAGzC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO;aAC3B,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;aACrC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE;YACf,MAAM,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC;YAC1B,MAAM,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC;YAC1B,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBACjC,OAAO,CAAC,CAAC,CAAC;YACZ,CAAC;iBAAM,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBACxC,OAAO,CAAC,CAAC;YACX,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,CAAC;YACX,CAAC;QACH,CAAC,CAAC,CAAC;QACL,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAwB,CAAC,CAAC,UAAU,CAAC;QAErF,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,IAAI,GAAG,IAAI,CAAC,uBAAuB,CACvC,IAAI,EACJ;gBACE,IAAI,CAAC,yBAAyB,CAC5B,IAAI,CAAC,0BAA0B,CAC7B,YAAY,EACZ,MAAM,CAAC,KAAK,CACb,EACD,IAAI,KAEJ,IAAI,EACJ,IAAI,CAAC,6BAA6B,CAChC,SAAS,GAAG,KAAK,EACjB,MAAM,CAAC,KAAK,CACb,EACD,MAAM,CAAC,KAAK,CACb;aACF,EACD,MAAM,CAAC,KAAK,CACb,CAAA;YACD,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAChC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACnB,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACvB,IAAI,QAAQ,CAAC,gBAAgB,CAAC,MAAM,EAAE,CAAC;gBACrC,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAC,gBAAgB,CAAC,CAAC;gBACxD,MAAM,SAAS,GAAG,IAAI,SAAS,CAC7B,IAAI,MAAM,IAER,MAAM,CAAC,cAAc,EACrB,kEAAkE,CACnE,CACF,CAAC;gBACF,MAAM,CAAC,aAAa,GAAG,SAAS,CAAC,MAAM,CAAC;gBACxC,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,sBAAsB,CAAC,SAAS,CAAE,CAAC,CAAC;gBACrE,MAAM,CAAC,aAAa,GAAG,MAAM,CAAC;YAChC,CAAC;QACH,CAAC;QACD,QAAQ,CAAC,gBAAgB,GAAG,EAAE,CAAC;IACjC,CAAC;CACF"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAC7D,OAAO,EAEL,IAAI,EAGL,MAAM,uCAAuC,CAAC;AAE/C,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEpD,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,SAAS;IAEhD,UAAU,CAAC,MAAc;QAMvB,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO;aAC3B,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;aACrC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE;YACf,MAAM,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC;YAC1B,MAAM,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC;YAC1B,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBACjC,OAAO,CAAC,CAAC,CAAC;YACZ,CAAC;iBAAM,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBACxC,OAAO,CAAC,CAAC;YACX,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,CAAC;YACX,CAAC;QACH,CAAC,CAAC,CAAC;QACL,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAwB,CAAC,CAAC,UAAU,CAAC;QAErF,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,IAAI,GAAG,IAAI,CAAC,uBAAuB,CACvC,IAAI,EACJ;gBACE,IAAI,CAAC,yBAAyB,CAC5B,IAAI,CAAC,0BAA0B,CAC7B,YAAY,EACZ,MAAM,CAAC,KAAK,CACb,EACD,IAAI,KAEJ,IAAI,EACJ,IAAI,CAAC,6BAA6B,CAChC,SAAS,GAAG,KAAK,EACjB,MAAM,CAAC,KAAK,CACb,EACD,MAAM,CAAC,KAAK,CACb;aACF,EACD,MAAM,CAAC,KAAK,CACb,CAAA;YACD,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAgBlC,CAAC;IAEH,CAAC;CACF"} \ No newline at end of file diff --git a/transform/lib/mock.js b/transform/lib/mock.js index eb52278..bf06e2a 100644 --- a/transform/lib/mock.js +++ b/transform/lib/mock.js @@ -1,60 +1,68 @@ -import { Node, } from "assemblyscript/dist/assemblyscript.js"; +import { Node } from "assemblyscript/dist/assemblyscript.js"; import { BaseVisitor } from "visitor-as/dist/index.js"; import { isStdlib, toString } from "visitor-as/dist/utils.js"; export class MockTransform extends BaseVisitor { - currentSource; - globalStatements = []; - fn = new Map(); - mocked = new Set(); - visitCallExpression(node) { - super.visitCallExpression(node); - const name = toString(node.expression) - .replaceAll(".", "_") - .replaceAll("[", "_") - .replaceAll("]", "_"); - if (this.mocked.has(name + "_mock")) { - node.expression = Node.createIdentifierExpression(name + "_mock", node.expression.range); - return; - } - if (name != "mockFn") - return; - const ov = node.args[0]; - const cb = node.args[1]; - const newName = ov.value - .replaceAll(".", "_") - .replaceAll("[", "_") - .replaceAll("]", "_"); - const newFn = Node.createFunctionDeclaration(Node.createIdentifierExpression(newName + "_mock", cb.range), cb.declaration.decorators, 0, cb.declaration.typeParameters, cb.declaration.signature, cb.declaration.body, cb.declaration.arrowKind, cb.range); - const stmts = this.currentSource.statements; - let index = -1; - for (let i = 0; i < stmts.length; i++) { - const stmt = stmts[i]; - if (stmt.range.start != node.range.start) - continue; - index = i; - break; - } - if (index === -1) - return; - stmts.splice(index, 1, newFn); - this.mocked.add(newFn.name.text); + currentSource; + globalStatements = []; + fn = new Map(); + mocked = new Set(); + visitCallExpression(node) { + super.visitCallExpression(node); + const name = toString(node.expression) + .replaceAll(".", "_") + .replaceAll("[", "_") + .replaceAll("]", "_"); + if (this.mocked.has(name + "_mock")) { + node.expression = Node.createIdentifierExpression( + name + "_mock", + node.expression.range, + ); + return; } - visitFunctionDeclaration(node, isDefault) { - super.visitFunctionDeclaration(node, isDefault); - const name = node.name.text; - if (!name) - return; - this.fn.set(name, node); + if (name != "mockFn") return; + const ov = node.args[0]; + const cb = node.args[1]; + const newName = ov.value + .replaceAll(".", "_") + .replaceAll("[", "_") + .replaceAll("]", "_"); + const newFn = Node.createFunctionDeclaration( + Node.createIdentifierExpression(newName + "_mock", cb.range), + cb.declaration.decorators, + 0, + cb.declaration.typeParameters, + cb.declaration.signature, + cb.declaration.body, + cb.declaration.arrowKind, + cb.range, + ); + const stmts = this.currentSource.statements; + let index = -1; + for (let i = 0; i < stmts.length; i++) { + const stmt = stmts[i]; + if (stmt.range.start != node.range.start) continue; + index = i; + break; } - visitSource(node) { - if (node.isLibrary || isStdlib(node)) { - if (!node.normalizedPath.startsWith("~lib/as-test")) { - return; - } - } - this.mocked = new Set(); - this.currentSource = node; - super.visitSource(node); + if (index === -1) return; + stmts.splice(index, 1, newFn); + this.mocked.add(newFn.name.text); + } + visitFunctionDeclaration(node, isDefault) { + super.visitFunctionDeclaration(node, isDefault); + const name = node.name.text; + if (!name) return; + this.fn.set(name, node); + } + visitSource(node) { + if (node.isLibrary || isStdlib(node)) { + if (!node.normalizedPath.startsWith("~lib/as-test")) { + return; + } } + this.mocked = new Set(); + this.currentSource = node; + super.visitSource(node); + } } -//# sourceMappingURL=mock.js.map \ No newline at end of file +//# sourceMappingURL=mock.js.map diff --git a/transform/src/index.ts b/transform/src/index.ts index cd20b33..7d9a3cc 100644 --- a/transform/src/index.ts +++ b/transform/src/index.ts @@ -2,24 +2,18 @@ import { Transform } from "assemblyscript/dist/transform.js"; import { CommonFlags, Node, - NodeKind, Parser, - Source, SourceKind, - Tokenizer, - TypeNode, } from "assemblyscript/dist/assemblyscript.js"; -import { isStdlib, toString } from "visitor-as/dist/utils.js"; -import { CoverageTransform } from "./coverage.js"; -import { MockTransform } from "./mock.js"; +import { isStdlib } from "visitor-as/dist/utils.js"; export default class Transformer extends Transform { // Trigger the transform after parse. afterParse(parser: Parser): void { // Create new transform - const mock = new MockTransform(); - const coverage = new CoverageTransform(); + //const mock = new MockTransform(); + //const coverage = new CoverageTransform(); // Sort the sources so that user scripts are visited last const sources = parser.sources @@ -35,46 +29,42 @@ export default class Transformer extends Transform { return 0; } }); - const entryFile = sources.find(v => v.sourceKind == SourceKind.UserEntry).simplePath; + const entryFile = sources.find( + (v) => v.sourceKind == SourceKind.UserEntry, + ).simplePath; // Loop over every source for (const source of sources) { const node = Node.createVariableStatement( null, [ Node.createVariableDeclaration( - Node.createIdentifierExpression( - "ENTRY_FILE", - source.range - ), + Node.createIdentifierExpression("ENTRY_FILE", source.range), null, CommonFlags.Const, null, - Node.createStringLiteralExpression( - entryFile + ".ts", - source.range - ), - source.range - ) + Node.createStringLiteralExpression(entryFile + ".ts", source.range), + source.range, + ), ], - source.range - ) + source.range, + ); source.statements.unshift(node); - mock.visit(source); - coverage.visit(source); - if (coverage.globalStatements.length) { - source.statements.unshift(...coverage.globalStatements); - const tokenizer = new Tokenizer( - new Source( - SourceKind.User, - source.normalizedPath, - 'import { __REGISTER, __COVER } from "as-test/assembly/coverage";', - ), - ); - parser.currentSource = tokenizer.source; - source.statements.unshift(parser.parseTopLevelStatement(tokenizer)!); - parser.currentSource = source; - } + // mock.visit(source); + // coverage.visit(source); + // if (coverage.globalStatements.length) { + // source.statements.unshift(...coverage.globalStatements); + // const tokenizer = new Tokenizer( + // new Source( + // SourceKind.User, + // source.normalizedPath, + // 'import { __REGISTER, __COVER } from "as-test/assembly/coverage";', + // ), + // ); + // parser.currentSource = tokenizer.source; + // source.statements.unshift(parser.parseTopLevelStatement(tokenizer)!); + // parser.currentSource = source; + // } } - coverage.globalStatements = []; + // coverage.globalStatements = []; } }