diff --git a/examples/package.json b/examples/package.json index 80152ce8..7cfabbc7 100644 --- a/examples/package.json +++ b/examples/package.json @@ -14,6 +14,7 @@ "@types/node": "18.11.9", "date-fns": "2.29.3", "rxjs": "7.5.7", + "source-map-support": "^0.5.21", "typescript": "4.8.4", "zone.js": "0.12.0" } diff --git a/examples/pnpm-lock.yaml b/examples/pnpm-lock.yaml index ed74ce80..3dadd8cc 100644 --- a/examples/pnpm-lock.yaml +++ b/examples/pnpm-lock.yaml @@ -1,5 +1,41 @@ lockfileVersion: 5.4 +specifiers: + '@angular/compiler': 15.0.1 + '@angular/compiler-cli': 15.0.1 + '@angular/core': 15.0.1 + '@babel/cli': 7.19.3 + '@babel/core': 7.20.2 + '@babel/parser': 7.20.3 + '@babel/preset-typescript': 7.18.6 + '@babel/types': 7.20.2 + '@tsconfig/node16-strictest-esm': 1.0.3 + '@types/jasmine': 4.3.0 + '@types/node': 18.11.9 + date-fns: 2.29.3 + rxjs: 7.5.7 + source-map-support: ^0.5.21 + typescript: 4.8.4 + zone.js: 0.12.0 + +dependencies: + '@angular/compiler': 15.0.1_@angular+core@15.0.1 + '@angular/compiler-cli': 15.0.1_cjgqlygpi5ntpb3clzn7pzsmpy + '@angular/core': 15.0.1_rxjs@7.5.7+zone.js@0.12.0 + '@babel/cli': 7.19.3_@babel+core@7.20.2 + '@babel/core': 7.20.2 + '@babel/parser': 7.20.3 + '@babel/preset-typescript': 7.18.6_@babel+core@7.20.2 + '@babel/types': 7.20.2 + '@tsconfig/node16-strictest-esm': 1.0.3 + '@types/jasmine': 4.3.0 + '@types/node': 18.11.9 + date-fns: 2.29.3 + rxjs: 7.5.7 + source-map-support: 0.5.21 + typescript: 4.8.4 + zone.js: 0.12.0 + importers: .: @@ -586,6 +622,10 @@ packages: update-browserslist-db: 1.0.10_browserslist@4.21.4 dev: false + /buffer-from/1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + dev: false + /caniuse-lite/1.0.30001435: resolution: {integrity: sha512-kdCkUTjR+v4YAJelyiDTqiu82BDr4W4CP5sgTA0ZBmqn30XfS2ZghPLMowik9TPhS+psWJiUNxsqLyurDbmutA==} dev: false @@ -925,6 +965,18 @@ packages: engines: {node: '>=6'} dev: false + /source-map-support/0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + dev: false + + /source-map/0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + dev: false + /sourcemap-codec/1.4.8: resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} dev: false diff --git a/examples/source_map_support/BUILD.bazel b/examples/source_map_support/BUILD.bazel new file mode 100644 index 00000000..a38af2a1 --- /dev/null +++ b/examples/source_map_support/BUILD.bazel @@ -0,0 +1,11 @@ +load("@aspect_bazel_lib//lib:copy_to_bin.bzl", "copy_to_bin") + +exports_files([ + "defs.bzl", +]) + +copy_to_bin( + name = "stack-trace-support", + srcs = ["stack-trace-support.js"], + visibility = ["//visibility:public"], +) diff --git a/examples/source_map_support/defs.bzl b/examples/source_map_support/defs.bzl new file mode 100644 index 00000000..79023a86 --- /dev/null +++ b/examples/source_map_support/defs.bzl @@ -0,0 +1,28 @@ +""" +Macro wrappers around rules_js's `js_binary` and `js_test` that improve the DX of stack traces by automatically +registering source-map-support and removing the runfiles directory prefix. + +Use them wherever you would use rules_js's `js_binary` and `js_test`. +""" + +load("@aspect_rules_js//js:defs.bzl", _js_binary = "js_binary", _js_test = "js_test") + +def js_binary(data = [], node_options = [], **kwargs): + _js_binary( + data = [ + "//examples:node_modules/source-map-support", + "//examples/source_map_support:stack-trace-support", + ] + data, + node_options = ["--require", "$$RUNFILES/aspect_rules_ts/examples/source_map_support/stack-trace-support"] + node_options, + **kwargs + ) + +def js_test(data = [], node_options = [], **kwargs): + _js_test( + data = [ + "//examples:node_modules/source-map-support", + "//examples/source_map_support:stack-trace-support", + ] + data, + node_options = ["--require", "$$RUNFILES/aspect_rules_ts/examples/source_map_support/stack-trace-support"] + node_options, + **kwargs + ) diff --git a/examples/source_map_support/stack-trace-support.js b/examples/source_map_support/stack-trace-support.js new file mode 100644 index 00000000..56af58ba --- /dev/null +++ b/examples/source_map_support/stack-trace-support.js @@ -0,0 +1,42 @@ +// See defs.bzl for where this is used and what it does. + +require('source-map-support/register') + +let basePath = process.env.RUNFILES + ? `${process.env.RUNFILES}/${process.env.JS_BINARY__WORKSPACE}` + : process.cwd() + +if (!basePath.endsWith('/')) { + basePath = basePath + '/' +} + +/* +Before: + Error: test + at foo (/private/var/tmp/_bazel_john/67beefda950d56283b98d96980e6e332/execroot/figma/bazel-out/darwin_arm64-fastbuild/bin/bazel/js/test/stack_trace_support.sh.runfiles/figma/bazel/js/test/b.js:2:11) + at Object. (/private/var/tmp/_bazel_john/67beefda950d56283b98d96980e6e332/execroot/figma/bazel-out/darwin_arm64-fastbuild/bin/bazel/js/test/stack_trace_support.sh.runfiles/figma/bazel/js/test/a.js:4:1) + ... + +After: + Error: test + at foo (bazel/js/test/b.ts:2:9) + at Object. (bazel/js/test/a.ts:5:1) + ... +*/ + +const basePathRegex = new RegExp( + `(at | \\()${basePath + .replace(/\\/g, '/') + // Escape regex meta-characters. + .replace(/[|\\{}()[\]^$+*?.]/g, '\\$&') + .replace(/-/g, '\\x2d')}`, + 'g', +) + +const prepareStackTrace = Error.prepareStackTrace +Error.prepareStackTrace = function (error, stack) { + return prepareStackTrace(error, stack) + .split('\n') + .map((line) => line.replace(basePathRegex, '$1')) + .join('\n') +} diff --git a/examples/source_map_support/test/BUILD.bazel b/examples/source_map_support/test/BUILD.bazel new file mode 100644 index 00000000..1f6c446a --- /dev/null +++ b/examples/source_map_support/test/BUILD.bazel @@ -0,0 +1,33 @@ +load("//ts:defs.bzl", "ts_project") +load("//examples/source_map_support:defs.bzl", "js_test") + +ts_project( + name = "ts", + srcs = [ + "a.ts", + "b.ts", + ], + source_map = True, + tsconfig = { + "compilerOptions": { + "types": ["node"], + "sourceMap": True, + }, + }, + deps = [ + "//examples:node_modules/@types/node", + ], +) + +js_test( + name = "stack_trace_support_test", + data = [":ts"], + entry_point = ":a.js", +) + +js_test( + name = "stack_trace_support_with_chdir_test", + chdir = "examples", + data = [":ts"], + entry_point = ":a.js", +) diff --git a/examples/source_map_support/test/a.ts b/examples/source_map_support/test/a.ts new file mode 100644 index 00000000..dd811b0c --- /dev/null +++ b/examples/source_map_support/test/a.ts @@ -0,0 +1,17 @@ +try { + require('./b')() +} catch (e) { + const assert = require('assert') + const frames = e.stack + .split('\n') + .slice(1) + .map((s) => s.trim()) + assert.deepEqual( + frames.filter((f) => f.includes('source_map_support/test/a')), + [`at Object. (examples/source_map_support/test/a.ts:2:17)`], + ) + assert.deepEqual( + frames.filter((f) => f.includes('source_map_support/test/b')), + [`at foo (examples/source_map_support/test/b.ts:2:9)`], + ) +} diff --git a/examples/source_map_support/test/b.ts b/examples/source_map_support/test/b.ts new file mode 100644 index 00000000..7cb351ad --- /dev/null +++ b/examples/source_map_support/test/b.ts @@ -0,0 +1,3 @@ +module.exports = function foo() { + throw new Error('test') +}