diff --git a/.github/workflows/integrate.yml b/.github/workflows/integrate.yml index 546d01c659..beb861139b 100644 --- a/.github/workflows/integrate.yml +++ b/.github/workflows/integrate.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [10, 12, 14] + node-version: [12, 14] name: Build steps: - uses: actions/checkout@v2 diff --git a/package.json b/package.json index 2e4b7e916c..74e49d0334 100644 --- a/package.json +++ b/package.json @@ -23,11 +23,9 @@ "devDependencies": { "@types/node": "^14.6.2", "axios": "^0.21.0", - "execa": "^5.0.0", "lerna": "^3.19.0", "minimist": "^1.2.0", "prettier": "2.2.1", - "source-map-support": "^0.5.16", "typescript": "^4.0.2" } } diff --git a/packages/alfa-test/package.json b/packages/alfa-test/package.json index eb1206ef40..c470914f2a 100644 --- a/packages/alfa-test/package.json +++ b/packages/alfa-test/package.json @@ -19,8 +19,7 @@ ], "dependencies": { "@siteimprove/alfa-highlight": "^0.10.0", - "@types/node": "^14.6.2", - "error-stack-parser": "^2.0.2" + "@types/node": "^14.6.2" }, "publishConfig": { "access": "public", diff --git a/packages/alfa-test/src/format.ts b/packages/alfa-test/src/format.ts index 350cb741f7..ec4b788a0a 100644 --- a/packages/alfa-test/src/format.ts +++ b/packages/alfa-test/src/format.ts @@ -3,18 +3,24 @@ import * as assert from "assert"; import * as path from "path"; -import * as stack from "error-stack-parser"; - import { mark } from "@siteimprove/alfa-highlight"; +import { stack } from "./stack"; + /** * @internal */ export function format(name: string, error: Error): string { - const [{ fileName, lineNumber, columnNumber }] = stack.parse(error); + const [callsite] = stack(error); - const filePath = - fileName === undefined ? "unknown" : path.relative(process.cwd(), fileName); + const [file, line, column] = + callsite.type === "native" + ? ["native", -1, -1] + : [ + path.relative(process.cwd(), callsite.file), + callsite.line, + callsite.column, + ]; let message: string; @@ -41,7 +47,7 @@ export function format(name: string, error: Error): string { } const output = ` -${mark.underline(`${filePath}(${lineNumber},${columnNumber}):`)} ${mark.bold( +${mark.underline(`${file}(${line},${column}):`)} ${mark.bold( name.trim().replace(/\s+/g, " ") )} ${message} diff --git a/packages/alfa-test/src/index.ts b/packages/alfa-test/src/index.ts index 04efde9d84..81524479d4 100644 --- a/packages/alfa-test/src/index.ts +++ b/packages/alfa-test/src/index.ts @@ -1,3 +1,4 @@ export * from "./format"; +export * from "./stack"; export * from "./test"; export * from "./types"; diff --git a/packages/alfa-test/src/stack.ts b/packages/alfa-test/src/stack.ts new file mode 100644 index 0000000000..31de6274c0 --- /dev/null +++ b/packages/alfa-test/src/stack.ts @@ -0,0 +1,69 @@ +/** + * @internal + */ +export function* stack(error: Error): Iterable { + const frames = error + .stack!.split("\n") + .slice(1) + .map((frame) => frame.trim()); + + for (let i = 0, n = frames.length; i < n; i++) { + const frame = frames[i]; + + // If the frame doesn't contain a location reference, skip the frame. + if (!/(\d+:\d+)/.test(frame)) { + continue; + } + + // If the next frame contains a source mapping for the current frame as + // indicated by an arrow, skip the frame. + if (i + 1 < n && frames[i + 1].startsWith("->")) { + continue; + } + + // Sanitize the frame and split it on colons. This will group the frame into + // 3 separate parts: The file, the line, and the column. + const parts = frame + .replace("(", "") + .replace(")", "") + .replace("->", "") + .split(":") + .map((part) => part.trim()); + + // The part containing the file may contain other things as well that we + // need to remove so we grab everything from the last space character and + // cut off the rest. + parts[0] = parts[0].substring(parts[0].lastIndexOf(" ") + 1); + + const [file, line, column] = parts; + + yield { + type: file.startsWith("internal") ? "internal" : "user", + file, + line: +line, + column: +column, + }; + } +} + +type Frame = Frame.Native | Frame.Internal | Frame.User; + +namespace Frame { + export interface Native { + type: "native"; + } + + export interface Internal { + type: "internal"; + file: string; + line: number; + column: number; + } + + export interface User { + type: "user"; + file: string; + line: number; + column: number; + } +} diff --git a/packages/alfa-test/tsconfig.json b/packages/alfa-test/tsconfig.json index a670135cd3..3a1eb83777 100644 --- a/packages/alfa-test/tsconfig.json +++ b/packages/alfa-test/tsconfig.json @@ -4,6 +4,7 @@ "files": [ "src/format.ts", "src/index.ts", + "src/stack.ts", "src/test.ts", "src/types.ts", "test/test.spec.ts" diff --git a/scripts/common/tester.js b/scripts/common/tester.js index bef02ddb7b..1c9df901d7 100644 --- a/scripts/common/tester.js +++ b/scripts/common/tester.js @@ -1,5 +1,5 @@ const os = require("os"); -const execa = require("execa"); +const child_process = require("child_process"); const { system } = require("./system"); @@ -14,17 +14,20 @@ exports.tester = { while (queue.length > 0) { const fileName = queue.shift().replace(/\.tsx?$/, ".js"); - try { - await execa.node(fileName, [], { - nodeOptions: [ - ...process.execArgv, - ...["--require", require.resolve("source-map-support/register")], - ], - stdio: "inherit", - }); - } catch { - system.exit(1); - } + const child = child_process.fork(fileName, [], { + execArgv: [...process.execArgv, "--enable-source-maps"], + stdio: "inherit", + }); + + await new Promise((resolve) => + child.on("close", (code) => { + if (code !== 0) { + system.exit(1); + } else { + resolve(); + } + }) + ); } }); }, diff --git a/yarn.lock b/yarn.lock index 536a31c75e..f398ff4fd3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3192,7 +3192,7 @@ cross-spawn@^6.0.0: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^7.0.0, cross-spawn@^7.0.3: +cross-spawn@^7.0.0: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -3794,13 +3794,6 @@ error-ex@^1.2.0, error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -error-stack-parser@^2.0.2: - version "2.0.6" - resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.0.6.tgz#5a99a707bd7a4c58a797902d48d82803ede6aad8" - integrity sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ== - dependencies: - stackframe "^1.1.1" - es-abstract@^1.17.0-next.1, es-abstract@^1.17.5: version "1.17.5" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.5.tgz#d8c9d1d66c8981fb9200e2251d799eee92774ae9" @@ -3924,21 +3917,6 @@ execa@^4.0.0, execa@^4.0.2: signal-exit "^3.0.2" strip-final-newline "^2.0.0" -execa@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.0.0.tgz#4029b0007998a841fbd1032e5f4de86a3c1e3376" - integrity sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" - executable@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/executable/-/executable-4.1.1.tgz#41532bff361d3e57af4d763b70582db18f5d133c" @@ -4376,11 +4354,6 @@ get-stream@^5.0.0, get-stream@^5.1.0: dependencies: pump "^3.0.0" -get-stream@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.0.tgz#3e0012cb6827319da2706e601a1583e8629a6718" - integrity sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg== - get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" @@ -4764,11 +4737,6 @@ human-signals@^1.1.1: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== -human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== - humanize-ms@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" @@ -6828,7 +6796,7 @@ npm-run-path@^2.0.0: dependencies: path-key "^2.0.0" -npm-run-path@^4.0.0, npm-run-path@^4.0.1: +npm-run-path@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== @@ -6975,7 +6943,7 @@ onetime@^2.0.0: dependencies: mimic-fn "^1.0.0" -onetime@^5.1.0, onetime@^5.1.2: +onetime@^5.1.0: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== @@ -8173,7 +8141,7 @@ sigmund@^1.0.1: resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" integrity sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA= -signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: +signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== @@ -8272,7 +8240,7 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@^0.5.16, source-map-support@^0.5.6: +source-map-support@^0.5.6: version "0.5.19" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== @@ -8388,11 +8356,6 @@ stack-utils@^2.0.2: dependencies: escape-string-regexp "^2.0.0" -stackframe@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.1.1.tgz#ffef0a3318b1b60c3b58564989aca5660729ec71" - integrity sha512-0PlYhdKh6AfFxRyK/v+6/k+/mMfyiEBbTM5L94D0ZytQnJ166wuwoTYLHFWGbs2dpA8Rgq763KGWmN1EQEYHRQ== - static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"