Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: tsconfig paths are not expanded correctly for tsconfigs and libs not placed at workspace root #502

Merged
merged 4 commits into from
Aug 14, 2023
Merged
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
1 change: 1 addition & 0 deletions gazelle/js/tests/tsconfig_baseurl/BUILD.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# gazelle:js_generation_mode none
13 changes: 13 additions & 0 deletions gazelle/js/tests/tsconfig_baseurl/BUILD.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
load("@aspect_rules_ts//ts:defs.bzl", "ts_project")

# gazelle:js_generation_mode none

ts_project(
name = "tsconfig_rootdir",
srcs = ["src/index.ts"],
deps = [
"//lib/a",
"//lib/b",
"//lib/c",
],
)
2 changes: 2 additions & 0 deletions gazelle/js/tests/tsconfig_baseurl/WORKSPACE
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# This is a Bazel workspace for the Gazelle test data.
workspace(name = "tsconfig_rootdir")
Empty file.
10 changes: 10 additions & 0 deletions gazelle/js/tests/tsconfig_baseurl/inheriter/BUILD.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
load("@aspect_rules_ts//ts:defs.bzl", "ts_project")

ts_project(
name = "inheriter",
srcs = ["main.ts"],
deps = [
"//lib/a",
"//lib/c",
],
)
4 changes: 4 additions & 0 deletions gazelle/js/tests/tsconfig_baseurl/inheriter/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { A } from 'lib/a';
import { C1 } from 'lib/c/first/c1';

console.log(A, C1);
4 changes: 4 additions & 0 deletions gazelle/js/tests/tsconfig_baseurl/inheriter/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "../tsconfig.json",
"include": ["./**/*.ts"]
}
Empty file.
6 changes: 6 additions & 0 deletions gazelle/js/tests/tsconfig_baseurl/lib/a/BUILD.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
load("@aspect_rules_ts//ts:defs.bzl", "ts_project")

ts_project(
name = "a",
srcs = ["index.ts"],
)
1 change: 1 addition & 0 deletions gazelle/js/tests/tsconfig_baseurl/lib/a/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const A = 'a';
Empty file.
6 changes: 6 additions & 0 deletions gazelle/js/tests/tsconfig_baseurl/lib/b/BUILD.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
load("@aspect_rules_ts//ts:defs.bzl", "ts_project")

ts_project(
name = "b",
srcs = ["index.ts"],
)
1 change: 1 addition & 0 deletions gazelle/js/tests/tsconfig_baseurl/lib/b/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const B = 'b';
Empty file.
9 changes: 9 additions & 0 deletions gazelle/js/tests/tsconfig_baseurl/lib/c/BUILD.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
load("@aspect_rules_ts//ts:defs.bzl", "ts_project")

ts_project(
name = "c",
srcs = [
"first/c1.ts",
"second/c2.ts",
],
)
1 change: 1 addition & 0 deletions gazelle/js/tests/tsconfig_baseurl/lib/c/first/c1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const C1 = 'c1';
1 change: 1 addition & 0 deletions gazelle/js/tests/tsconfig_baseurl/lib/c/second/c2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const C2 = 'c2';
1 change: 1 addition & 0 deletions gazelle/js/tests/tsconfig_baseurl/projects/p1/BUILD.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# gazelle:js_generation_mode none
9 changes: 9 additions & 0 deletions gazelle/js/tests/tsconfig_baseurl/projects/p1/BUILD.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
load("@aspect_rules_ts//ts:defs.bzl", "ts_project")

# gazelle:js_generation_mode none

ts_project(
name = "p1",
srcs = ["index.ts"],
deps = ["//projects/p1/nested_lib/a"],
)
3 changes: 3 additions & 0 deletions gazelle/js/tests/tsconfig_baseurl/projects/p1/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { NestedA } from 'nested_lib/a/a';

console.log(NestedA);
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# gazelle:js_generation_mode none
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
load("@aspect_rules_ts//ts:defs.bzl", "ts_project")

# gazelle:js_generation_mode none

ts_project(
name = "a",
srcs = ["a.ts"],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const NestedA = 'internal lib';
6 changes: 6 additions & 0 deletions gazelle/js/tests/tsconfig_baseurl/projects/p1/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"compilerOptions": {
"baseUrl": "."
},
"include": ["./**/*.ts"]
}
6 changes: 6 additions & 0 deletions gazelle/js/tests/tsconfig_baseurl/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { A } from '../lib/a';
import { B } from '../lib/b';
import { C1 } from '../lib/c/first/c1';
import { C2 } from '../lib/c/second/c2';

console.log(A, B, C1, C2);
6 changes: 6 additions & 0 deletions gazelle/js/tests/tsconfig_baseurl/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"compilerOptions": {
"baseUrl": "."
},
"include": ["./src/**/*.ts"]
}
Empty file.
13 changes: 13 additions & 0 deletions gazelle/js/tests/tsconfig_paths/custom/BUILD.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
load("@aspect_rules_ts//ts:defs.bzl", "ts_project")

ts_project(
name = "custom",
srcs = ["main.ts"],
deps = [
"//custom/nested",
"//fallback",
"//lib/a",
"//lib/b",
"//lib/c",
],
)
10 changes: 10 additions & 0 deletions gazelle/js/tests/tsconfig_paths/custom/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { A } from 'star/a';
import { B } from 'star/b';
import { A as AliasA } from 'alias-a';
import { A as RootDotA } from 'lib/a';
import { C1 } from 'multi-c/c1';
import { C2 } from 'multi-c/c2';
import { F } from 'f1';
import { Test } from '@/nested/test';

console.log(A, B, AliasA, RootDotA, C1, C2, F, Test);
Empty file.
7 changes: 7 additions & 0 deletions gazelle/js/tests/tsconfig_paths/custom/nested/BUILD.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
load("@aspect_rules_ts//ts:defs.bzl", "ts_project")

ts_project(
name = "nested",
srcs = ["test.ts"],
deps = ["//lib/a"],
)
5 changes: 5 additions & 0 deletions gazelle/js/tests/tsconfig_paths/custom/nested/test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { A as AliasA } from 'alias-a';

console.log(AliasA);

export const Test = 'Test';
13 changes: 13 additions & 0 deletions gazelle/js/tests/tsconfig_paths/custom/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"alias-a": ["../lib/a"],
"star/*": ["../lib/*"],
"multi-c/*": ["../lib/c/first/*", "../lib/c/second/*"],
"@/*": ["*"],
"*": ["../fallback/*", "../*"]
}
},
"include": ["**/*.ts"]
}
3 changes: 2 additions & 1 deletion gazelle/js/tests/tsconfig_paths/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
"multi-c/*": ["./lib/c/first/*", "./lib/c/second/*"],
"*": ["./fallback/*", "*"]
}
}
},
"include": ["./src/**/*.ts"]
}
2 changes: 1 addition & 1 deletion gazelle/js/typescript/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ go_library(
importpath = "aspect.build/cli/gazelle/js/typescript",
visibility = ["//visibility:public"],
deps = [
"//gazelle/common/log",
"@com_github_msolo_jsonr//:jsonr",
"@com_github_sirupsen_logrus//:logrus",
],
)

Expand Down
65 changes: 53 additions & 12 deletions gazelle/js/typescript/tsconfig.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
/*
* Copyright 2022 Aspect Build Systems, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package typescript

import (
Expand All @@ -7,8 +23,8 @@ import (
"sort"
"strings"

. "aspect.build/cli/gazelle/common/log"
"github.com/msolo/jsonr"
"github.com/sirupsen/logrus"
)

type tsCompilerOptionsJSON struct {
Expand Down Expand Up @@ -44,7 +60,13 @@ var DefaultConfigPaths = TsConfigPaths{
Map: &map[string][]string{},
}

var Log = logrus.New()
func isRelativePath(p string) bool {
if path.IsAbs(p) {
return false
}

return strings.HasPrefix(p, "./") || strings.HasPrefix(p, "../")
}

// parseTsConfigJSONFile loads a tsconfig.json file and return the compilerOptions config
func parseTsConfigJSONFile(cm *TsConfigMap, root, dir, tsconfig string) (*TsConfig, error) {
Expand Down Expand Up @@ -73,7 +95,7 @@ func parseTsConfigJSON(cm *TsConfigMap, root, configDir string, tsconfigContent
if c.Extends != "" {
base, err := parseTsConfigJSONFile(cm, root, path.Join(configDir, path.Dir(c.Extends)), path.Base(c.Extends))
if err != nil {
Log.Warnf("Failed to load base tsconfig file %s: %v", path.Join(configDir, c.Extends), err)
BazelLog.Warnf("Failed to load base tsconfig file %s: %v", path.Join(configDir, c.Extends), err)
}

baseConfig = base
Expand All @@ -83,7 +105,7 @@ func parseTsConfigJSON(cm *TsConfigMap, root, configDir string, tsconfigContent
if baseConfig != nil {
rel, relErr := filepath.Rel(configDir, baseConfig.ConfigDir)
if relErr != nil {
Log.Warnf("Failed to resolve relative path from %s to %s: %v", configDir, baseConfig.ConfigDir, relErr)
BazelLog.Warnf("Failed to resolve relative path from %s to %s: %v", configDir, baseConfig.ConfigDir, relErr)
} else {
baseConfigRel = rel
}
Expand Down Expand Up @@ -140,21 +162,33 @@ func parseTsConfigJSON(cm *TsConfigMap, root, configDir string, tsconfigContent
return &config, nil
}

// Returns the path from the project base to the active tsconfig.json file
// This is used to build the path from the project base to the file being imported
// because gazelle seems to resolve files relative to the project base
// if the passed path is not absolute.
// Or an empty string if the path is absolute
func (c TsConfig) expandRelativePath(importPath string) string {
// Absolute paths must never be expanded but everything else must be relative to the bazel-root
// and therefore expanded with the path to the current active tsconfig.json
if !path.IsAbs(importPath) {
BazelLog.Tracef("Found local path %s in tsconfig.json. Should be expanded with tsconfig dir: %s", importPath, c.ConfigDir)
return c.ConfigDir
}
return ""
}

// Expand the given path to all possible mapped paths for this config, in priority order.
//
// Path matching algorithm based on ESBuild implementation
// Inspired by: https://github.com/evanw/esbuild/blob/deb93e92267a96575a6e434ff18421f4ef0605e4/internal/resolver/resolver.go#L1831-L1945
func (c TsConfig) ExpandPaths(from, p string) []string {
pathMap := c.Paths.Map

possible := make([]string, 0)

// Check for exact 'paths' matches first
exact := (*pathMap)[p]
if exact != nil {
for _, m := range exact {
possible = append(possible, path.Clean(path.Join(c.Paths.Rel, m)))
}
for _, m := range exact {
possible = append(possible, path.Join(c.expandRelativePath(m), c.Paths.Rel, m))
}

// Check for pattern matches next
Expand Down Expand Up @@ -183,18 +217,25 @@ func (c TsConfig) ExpandPaths(from, p string) []string {
matchedText := p[len(m.prefix) : len(p)-len(m.suffix)]
mappedPath := strings.Replace(originalPath, "*", matchedText, 1)

mappedPath = path.Clean(mappedPath)

possible = append(possible, path.Join(c.Paths.Rel, mappedPath))
possible = append(possible, path.Join(c.expandRelativePath(mappedPath), c.Paths.Rel, mappedPath))
}
}

// Expand paths from baseUrl
// Must not to be absolute or relative to be expanded
// https://www.typescriptlang.org/tsconfig#baseUrl
if !isRelativePath(p) {
possible = append(possible, path.Join(c.expandRelativePath(p), c.BaseUrl, p))
}

// Add 'rootDirs' as alternate directories for relative imports
// https://www.typescriptlang.org/tsconfig#rootDirs
for _, v := range c.VirtualRootDirs {
possible = append(possible, path.Join(v, p))
}

BazelLog.Tracef("Found %d possible paths for %s: %v", len(possible), p, possible)

return possible
}

Expand Down
Loading
Loading