Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions bazel/jasmine/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
load("@aspect_rules_js//js:defs.bzl", "js_library")

js_library(
name = "stack-traces",
srcs = [
"stack-traces.mjs",
],
visibility = [
"//visibility:public",
],
deps = [
"//bazel:node_modules/source-map-support",
],
)
22 changes: 22 additions & 0 deletions bazel/jasmine/jasmine.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
load("@aspect_rules_jasmine//jasmine:defs.bzl", _jasmine_test = "jasmine_test")

def jasmine_test(name, data = [], tsconfig = None, node_options = [], env = {}, **kwargs):
if tsconfig:
env = dict(env, **{
"NODE_OPTIONS_TSCONFIG_PATH": "$(rlocationpath %s)" % tsconfig,
})

_jasmine_test(
name = name,
data = data + [
"@devinfra//bazel/jasmine:stack-traces",
"@devinfra//bazel/private/node_loader:node_loader",
],
env = env,
size = kwargs.pop("size", "medium"),
node_options = [
"--import=$$JS_BINARY__RUNFILES/$(rlocationpath @devinfra//bazel/private/node_loader:node_loader)",
"--import=$$JS_BINARY__RUNFILES/$(rlocationpath @devinfra//bazel/jasmine:stack-traces)",
] + node_options,
**kwargs
)
19 changes: 19 additions & 0 deletions bazel/jasmine/stack-traces.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {install} from 'source-map-support';

// Set up source map support to ensure we are logging the stack trace for the source file (i.e. .ts file) and
// not the generated file (i.e. .js. file).
install();

/** The root path that the test files are running from within. */
let rootPath = `${process.env.RUNFILES}/${process.env.TEST_WORKSPACE}/`;
/** The root path match for when test files are not within the sandbox, but the executation is happening within the sandbox. */
let sandboxPath = `/.*${process.env.JS_BINARY__WORKSPACE}/${process.env.JS_BINARY__BINDIR}/`;
/** Regex to capture the content and name of the function in the stack trace. */
const basePathRegex = new RegExp(`(at.*)(?:file.*${rootPath}|file.*${sandboxPath})`, 'g');

// Replace the prepareStackTrace function with one which replaces the full path execution location with
// relative paths to the base of the workspace source files.
const originalPrepareStackTrace = Error.prepareStackTrace;
Error.prepareStackTrace = function (e, s) {
return originalPrepareStackTrace(e, s).replaceAll(basePathRegex, '$1./');
};
3 changes: 3 additions & 0 deletions bazel/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
"@types/selenium-webdriver": "^4.1.28",
"@types/send": "0.17.5",
"@types/wait-on": "^5.3.4",
"@types/source-map-support": "0.5.10",
"@types/yargs": "17.0.33",
"browser-sync": "3.0.4",
"chalk": "5.6.0",
"get-tsconfig": "4.10.1",
"piscina": "^5.0.0",
"send": "1.2.0",
"true-case-path": "2.2.1",
Expand All @@ -20,6 +22,7 @@
"protractor": "7.0.0",
"semver": "7.7.2",
"selenium-webdriver": "4.35.0",
"source-map-support": "0.5.21",
"tinyglobby": "0.2.14"
}
}
15 changes: 15 additions & 0 deletions bazel/private/node_loader/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
load("@aspect_rules_js//js:defs.bzl", "js_library")

js_library(
name = "node_loader_lib",
srcs = ["hooks.mjs"],
visibility = ["//visibility:public"],
deps = ["//bazel:node_modules/get-tsconfig"],
)

js_library(
name = "node_loader",
srcs = ["index.mjs"],
visibility = ["//visibility:public"],
deps = [":node_loader_lib"],
)
75 changes: 75 additions & 0 deletions bazel/private/node_loader/hooks.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/

/**
* @fileoverview
*
* Module loader that augments NodeJS's execution to:
*
* - support native execution of Angular JavaScript output
* that isn't strict ESM at this point (lack of explicit extensions).
* - support path mappings at runtime. This allows us to natively execute ESM
* without having to pre-bundle for testing, or use the slow full npm linked packages
*/

import {parseTsconfig, createPathsMatcher} from 'get-tsconfig';

import path from 'node:path';

const explicitExtensionRe = /\.[mc]?js$/;
const nonModuleImportRe = /^[.\/]/;

const runfilesRoot = process.env.JS_BINARY__RUNFILES;
const tsconfigPath = process.env.NODE_OPTIONS_TSCONFIG_PATH;

let pathMappingMatcher;
// When no tsconfig is provided no match can be generated so we always return an empty list.
if (tsconfigPath === undefined) {
pathMappingMatcher = () => [];
} else {
const tsconfigFullPath = path.join(runfilesRoot, tsconfigPath);
const tsconfig = parseTsconfig(tsconfigFullPath);
pathMappingMatcher = createPathsMatcher({config: tsconfig, path: tsconfigFullPath});
}

/** @type {import('module').ResolveHook} */
export const resolve = async (specifier, context, nextResolve) => {
// True when it's a non-module import without explicit extensions.
const isNonModuleExtensionlessImport =
nonModuleImportRe.test(specifier) && !explicitExtensionRe.test(specifier);
const pathMappings = !nonModuleImportRe.test(specifier) ? pathMappingMatcher(specifier) : [];

// If it's neither path mapped, nor an extension-less import that may be fixed up, exit early.
if (!isNonModuleExtensionlessImport && pathMappings.length === 0) {
return nextResolve(specifier, context);
}

if (pathMappings.length > 0) {
for (const mapping of pathMappings) {
const res = await resolve(mapping, context, nextResolve).catch(() => null);
if (res !== null) {
return res;
}
}
} else {
const specifiers = [
`${specifier}.js`,
`${specifier}/index.js`,
// Legacy variants for the `zone.js` variant using still `ts_library`.
// TODO(rules_js migration): Remove this.
`${specifier}.mjs`,
`${specifier}/index.mjs`,
];
for (const specifier of specifiers) {
try {
return await nextResolve(specifier, context);
} catch {}
}
}
return nextResolve(specifier, context);
};
11 changes: 11 additions & 0 deletions bazel/private/node_loader/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/

import {register} from 'node:module';

register('./hooks.mjs', {parentURL: import.meta.url});
29 changes: 29 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions tools/defaults.bzl
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
load("@aspect_bazel_lib//lib:copy_to_bin.bzl", _copy_to_bin = "copy_to_bin")
load("@aspect_bazel_lib//lib:write_source_files.bzl", _write_source_file = "write_source_file")
load("@aspect_rules_esbuild//esbuild:defs.bzl", _esbuild = "esbuild")
load("@aspect_rules_jasmine//jasmine:defs.bzl", _jasmine_test = "jasmine_test")
load("@aspect_rules_js//js:defs.bzl", _js_binary = "js_binary")
load("@aspect_rules_js//npm:defs.bzl", _npm_package = "npm_package")
load("@aspect_rules_ts//ts:defs.bzl", _ts_config = "ts_config")
Expand All @@ -10,6 +9,7 @@ load("@rules_angular//src/ng_project:index.bzl", _ng_project = "ng_project")
load("@rules_angular//src/ts_project:index.bzl", _ts_project = "ts_project")
load("@rules_sass//src:index.bzl", _npm_sass_library = "npm_sass_library", _sass_binary = "sass_binary")
load("//bazel:extract_types.bzl", _extract_types = "extract_types")
load("//bazel/jasmine:jasmine.bzl", _jasmine_test = "jasmine_test")
load("//bazel/ts_project:index.bzl", _strict_deps_test = "strict_deps_test")

copy_to_bin = _copy_to_bin
Expand Down Expand Up @@ -110,7 +110,6 @@ def jasmine_test(name, **kwargs):
_jasmine_test(
name = name,
node_modules = "//:node_modules",
chdir = native.package_name(),
fixed_args = [
"'**/*+(.|_)spec.js'",
],
Expand Down
Loading