Name AMD module `foo` rather than `foo/module_root/index`
We already had logic to name it foo rather than foo/index, introduced in https://github.com/bazelbuild/rules_typescript/commit/c7b6880767eaae44d8777a7a1b137de92b8fd4d9
If the module_root is specified as a directory on the ts_library, it means that the index file is in that subdirectory of the package. We already handled this case correctly in type-checking, but at runtime the module identifiers don't match so the require('foo/module_root/index') fails.
Fixes bazelbuild/rules_nodejs#973
PiperOrigin-RevId: 262663195
diff --git a/internal/tsc_wrapped/compiler_host.ts b/internal/tsc_wrapped/compiler_host.ts
index 9008a08..9cae018 100644
--- a/internal/tsc_wrapped/compiler_host.ts
+++ b/internal/tsc_wrapped/compiler_host.ts
@@ -333,11 +333,14 @@
if (this.bazelOpts.moduleName) {
const relativeFileName = path.posix.relative(this.bazelOpts.package, fileName);
+ // check that the fileName was actually underneath the package directory
if (!relativeFileName.startsWith('..')) {
- if (this.bazelOpts.moduleRoot &&
- this.bazelOpts.moduleRoot.replace(SOURCE_EXT, '') ===
- relativeFileName) {
- return this.bazelOpts.moduleName;
+ if (this.bazelOpts.moduleRoot) {
+ const root = this.bazelOpts.moduleRoot.replace(SOURCE_EXT, '');
+ if (root === relativeFileName ||
+ path.posix.join(root, 'index') === relativeFileName) {
+ return this.bazelOpts.moduleName;
+ }
}
// Support the common case of commonjs convention that index is the
// default module in a directory.
diff --git a/internal/tsc_wrapped/compiler_host_test.ts b/internal/tsc_wrapped/compiler_host_test.ts
new file mode 100644
index 0000000..eaa0ac4
--- /dev/null
+++ b/internal/tsc_wrapped/compiler_host_test.ts
@@ -0,0 +1,62 @@
+import 'jasmine';
+
+import * as ts from 'typescript';
+
+import {CompilerHost} from './compiler_host';
+import {BazelOptions} from './tsconfig';
+
+describe('compiler host', () => {
+ describe('computes the amd module name of a .ts source file', () => {
+ const options: ts.CompilerOptions = {
+ rootDirs: [],
+ rootDir: 'base',
+ outDir: 'out',
+ };
+ const bazelOptions: BazelOptions = {
+ package: 'path/to/package',
+ compilationTargetSrc: [
+ 'path/to/package/index.ts',
+ 'path/to/package/root_dir/index.ts',
+ 'test.ts',
+ ],
+ workspaceName: 'my_wksp',
+ } as any;
+
+ const defaultHost =
+ new CompilerHost([], options, bazelOptions, null as any, null as any);
+ // A module is a file with at least an import or export statement.
+ function createTsModule(filename: string) {
+ return ts.createSourceFile(filename, 'export {}', ts.ScriptTarget.ES2015);
+ }
+
+ it('should name a module after the workspace and filename', () => {
+ expect(defaultHost.amdModuleName(createTsModule('test.ts')))
+ .toBe('my_wksp/test');
+ });
+
+ it('should not provide a name for files that are not in the compilation unit',
+ () => {
+ expect(
+ defaultHost.amdModuleName(createTsModule('some_other_file.d.ts')))
+ .toBeUndefined();
+ });
+
+ it('should name the index file with a short name', () => {
+ const host = new CompilerHost(
+ [], options, {...bazelOptions, moduleName: 'my_lib'}, null as any,
+ null as any);
+ expect(host.amdModuleName(createTsModule('path/to/package/index.ts')))
+ .toBe('my_lib');
+ });
+ it('should name an index file under a module_root with a short name',
+ () => {
+ const host = new CompilerHost(
+ [], options,
+ {...bazelOptions, moduleName: 'my_lib', moduleRoot: 'root_dir'},
+ null as any, null as any);
+ expect(host.amdModuleName(
+ createTsModule('path/to/package/root_dir/index.ts')))
+ .toBe('my_lib');
+ });
+ });
+});