ronantakizawa/codereview-bench huggingface dataset:
Repository: etcd-io/etcd
File: tests/integration/v3_lease_test.go (Go)

Code before:
	oldLeadC := clus.Client(oldLeadIdx)

	leaseResp, err := oldLeadC.Grant(ctx, 100)
	require.NoError(t, err)

	require.NoError(t, gofail.Enable(fpName, `sleep("3s")`))
	t.Cleanup(func() {
		terr := gofail.Disable(fpName)
		if terr != nil && !errors.Is(terr, gofail.ErrDisabled) {
			t.Fatalf("failed to disable %s: %v", fpName, terr)
		}
	})

	readyCh := make(chan struct{})
	errCh := make(chan error, 1)

	var targetC *clientv3.Client
	switch fpName {
	case "beforeLookupWhenLeaseTimeToLive":
		targetC = oldLeadC
	case "beforeLookupWhenForwardLeaseTimeToLive":
		targetC = clus.Client((oldLeadIdx + 2) % 3)
	default:
		t.Fatalf("unsupported %s failpoint", fpName)
	}

	go func() {
		<-readyCh
		time.Sleep(1 * time.Second)

		_, merr := oldLeadC.MoveLeader(ctx, uint64(followerMemberID))
		assert.NoError(t, gofail.Disable(fpName))
		errCh <- merr
	}()

	close(readyCh)

	ttlResp, err := targetC.TimeToLive(ctx, leaseResp.ID)
	require.NoError(t, err)
	require.GreaterOrEqual(t, int64(100), ttlResp.TTL)

	require.NoError(t, <-errCh)
}

// acquireLeaseAndKey creates a new lease and creates an attached key.
func acquireLeaseAndKey(clus *integration.Cluster, key string) (int64, error) {
	// create lease
	lresp, err := integration.ToGRPC(clus.RandClient()).Lease.LeaseGrant(
		context.TODO(),
		&pb.LeaseGrantRequest{TTL: 1})
	if err != nil {

Review comment (bug):
```suggestion
	integration.BeforeTest(t, WithFailpoint(fpName))
```

Code after:
		t.Fatalf("only detached lease removed, key should remain")
	}

	// revoke the latest lease
	_, err = lsc.LeaseRevoke(t.Context(), &pb.LeaseRevokeRequest{ID: leaseIDs[1]})
	require.NoError(t, err)
	rresp, err = kvc.Range(t.Context(), &pb.RangeRequest{Key: []byte("foo")})
	require.NoError(t, err)
	if len(rresp.Kvs) != 0 {
		t.Fatalf("lease removed but key remains")
	}
}

func TestV3LeaseTimeToLiveWithLeaderChanged(t *testing.T) {
	t.Run("normal", func(subT *testing.T) {
		testV3LeaseTimeToLiveWithLeaderChanged(subT, "beforeLookupWhenLeaseTimeToLive")
	})

	t.Run("forward", func(subT *testing.T) {
		testV3LeaseTimeToLiveWithLeaderChanged(subT, "beforeLookupWhenForwardLeaseTimeToLive")
	})
}

func testV3LeaseTimeToLiveWithLeaderChanged(t *testing.T, fpName string) {
	integration.SkipIfNoGoFail(t)
	integration.BeforeTest(t)

	clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 3})
	defer clus.Terminate(t)

	ctx, cancel := context.WithTimeout(t.Context(), 30*time.Second)
	defer cancel()

	oldLeadIdx := clus.WaitLeader(t)
	followerIdx := (oldLeadIdx + 1) % 3

	followerMemberID := clus.Members[followerIdx].ID()

	oldLeadC := clus.Client(oldLeadIdx)

	leaseResp, err := oldLeadC.Grant(ctx, 100)
	require.NoError(t, err)

	require.NoError(t, gofail.Enable(fpName, `sleep("3s")`))
	t.Cleanup(func() {
		terr := gofail.Disable(fpName)
		if terr != nil && !errors.Is(terr, gofail.ErrDisabled) {
			t.Fatalf("failed to disable %s: %v", fpName, terr)
		}
	})
Repository: etcd-io/etcd
File: tests/robustness/traffic/etcd.go (Go)

Code before:
	"golang.org/x/time/rate"

	"go.etcd.io/etcd/api/v3/mvccpb"
	clientv3 "go.etcd.io/etcd/client/v3"
	"go.etcd.io/etcd/tests/v3/robustness/client"
	"go.etcd.io/etcd/tests/v3/robustness/identity"
	"go.etcd.io/etcd/tests/v3/robustness/model"
	"go.etcd.io/etcd/tests/v3/robustness/random"
)

var (
	EtcdPutDeleteLease Traffic = etcdTraffic{
		keyCount: 10,
		leaseTTL: DefaultLeaseTTL,
		// Please keep the sum of weights equal 100.
		requests: []random.ChoiceWeight[etcdRequestType]{
			{Choice: Get, Weight: 15},
			{Choice: List, Weight: 15},
			{Choice: StaleGet, Weight: 10},
			{Choice: StaleList, Weight: 10},
			{Choice: Delete, Weight: 5},
			{Choice: MultiOpTxn, Weight: 10},
			{Choice: PutWithLease, Weight: 5},
			{Choice: LeaseRevoke, Weight: 5},
			{Choice: CompareAndSet, Weight: 5},
			{Choice: Put, Weight: 25},
		},
	}
	EtcdPut Traffic = etcdTraffic{
		keyCount: 10,
		leaseTTL: DefaultLeaseTTL,
		// Please keep the sum of weights equal 100.
		requests: []random.ChoiceWeight[etcdRequestType]{
			{Choice: Get, Weight: 15},
			{Choice: List, Weight: 15},
			{Choice: StaleGet, Weight: 10},
			{Choice: StaleList, Weight: 10},
			{Choice: MultiOpTxn, Weight: 10},
			{Choice: Put, Weight: 40},
		},
	}
	EtcdDelete Traffic = etcdTraffic{
		keyCount: 10,
		leaseTTL: DefaultLeaseTTL,
		// Please keep the sum of weights equal 100.
		requests: []random.ChoiceWeight[etcdRequestType]{
			{Choice: Put, Weight: 50},
			{Choice: Delete, Weight: 50},
		},
	}
)

Review comment (suggestion):
```suggestion
			{Choice: Put, Weight: 20},
```

The sum is now 105 :(

Code after:
	"golang.org/x/time/rate"

	"go.etcd.io/etcd/api/v3/mvccpb"
	clientv3 "go.etcd.io/etcd/client/v3"
	"go.etcd.io/etcd/tests/v3/robustness/client"
	"go.etcd.io/etcd/tests/v3/robustness/identity"
	"go.etcd.io/etcd/tests/v3/robustness/model"
	"go.etcd.io/etcd/tests/v3/robustness/random"
)

var (
	EtcdPutDeleteLease Traffic = etcdTraffic{
		keyCount: 10,
		leaseTTL: DefaultLeaseTTL,
		// Please keep the sum of weights equal 100.
		requests: []random.ChoiceWeight[etcdRequestType]{
			{Choice: Get, Weight: 15},
			{Choice: List, Weight: 15},
			{Choice: StaleGet, Weight: 10},
			{Choice: StaleList, Weight: 10},
			{Choice: Delete, Weight: 5},
			{Choice: MultiOpTxn, Weight: 10},
			{Choice: PutWithLease, Weight: 5},
			{Choice: LeaseRevoke, Weight: 5},
			{Choice: CompareAndSet, Weight: 5},
			{Choice: Put, Weight: 20},
		},
	}
	EtcdPut Traffic = etcdTraffic{
		keyCount: 10,
		leaseTTL: DefaultLeaseTTL,
		// Please keep the sum of weights equal 100.
		requests: []random.ChoiceWeight[etcdRequestType]{
			{Choice: Get, Weight: 15},
			{Choice: List, Weight: 15},
			{Choice: StaleGet, Weight: 10},
			{Choice: StaleList, Weight: 10},
			{Choice: MultiOpTxn, Weight: 10},
			{Choice: Put, Weight: 40},
		},
	}
	EtcdDelete Traffic = etcdTraffic{
		keyCount: 10,
		leaseTTL: DefaultLeaseTTL,
		// Please keep the sum of weights equal 100.
		requests: []random.ChoiceWeight[etcdRequestType]{
			{Choice: Put, Weight: 50},
			{Choice: Delete, Weight: 50},
		},
	}
)
Repository: etcd-io/etcd
File: tests/robustness/model/types.go (Go)

Code before:
// * Error response. Client observed error, but we don't know if it was persisted. Only Error is set.
type MaybeEtcdResponse struct {
	EtcdResponse
	Persisted         bool
	PersistedRevision int64
	Error             string
}

var ErrEtcdFutureRev = errors.New("future rev")

type MemberID uint64

// MarshalJSON implements the json.Marshaler interface for MemberID.
// It marshals the MemberID as a hexadecimal string.
func (m MemberID) MarshalJSON() ([]byte, error) {
	return json.Marshal(fmt.Sprintf("%x", m))
}

// UnmarshalJSON implements the json.Unmarshaler interface for MemberID.
// It unmarshals the MemberID from a hexadecimal string.
func (m *MemberID) UnmarshalJSON(data []byte) error {
	var s string
	if err := json.Unmarshal(data, &s); err != nil {
		return err
	}

	id, err := types.IDFromString(s)
	if err != nil {
		return err
	}
	*m = MemberID(id)
	return nil
}

type EtcdResponse struct {
	Txn         *TxnResponse
	Range       *RangeResponse
	LeaseGrant  *LeaseGrantReponse
	LeaseRevoke *LeaseRevokeResponse
	Defragment  *DefragmentResponse
	Compact     *CompactResponse
	ClientError string
	Revision    int64
	MemberID    MemberID `json:"member-id,omitempty"`
}

func Match(r1, r2 MaybeEtcdResponse) bool {
	r1Revision := r1.Revision
	if r1.Persisted {
		r1Revision = r1.PersistedRevision
	}

Review comment (suggestion):
If we are using IDFromString, for unmarshall we should use symmetrical function during Marshaling. If there is none, we should add it. Expect we should use `types.Id(m).String()` instead of `fmt.Sprintf("%x", m)`

Code after:
type MaybeEtcdResponse struct {
	EtcdResponse
	Persisted         bool
	PersistedRevision int64
	Error             string
}

var ErrEtcdFutureRev = errors.New("future rev")

type MemberID uint64

// MarshalJSON implements the json.Marshaler interface for MemberID.
// It marshals the MemberID as a hexadecimal string.
func (m MemberID) MarshalJSON() ([]byte, error) {
	return json.Marshal(types.ID(m).String())
}

// UnmarshalJSON implements the json.Unmarshaler interface for MemberID.
// It unmarshals the MemberID from a hexadecimal string.
func (m *MemberID) UnmarshalJSON(data []byte) error {
	var s string
	if err := json.Unmarshal(data, &s); err != nil {
		return err
	}

	id, err := types.IDFromString(s)
	if err != nil {
		return err
	}
	*m = MemberID(id)
	return nil
}

type EtcdResponse struct {
	Txn         *TxnResponse
	Range       *RangeResponse
	LeaseGrant  *LeaseGrantReponse
	LeaseRevoke *LeaseRevokeResponse
	Defragment  *DefragmentResponse
	Compact     *CompactResponse
	ClientError string
	Revision    int64
	MemberID    MemberID `json:"member-id,omitempty"`
}

func Match(r1, r2 MaybeEtcdResponse) bool {
	r1Revision := r1.Revision
	if r1.Persisted {
		r1Revision = r1.PersistedRevision
	}
	r2Revision := r2.Revision
Repository: etcd-io/etcd
File: server/etcdserver/api/snap/snapshotter_test.go (Go)

Code before:
	defer os.RemoveAll(dir)
	for i := 1; i <= 5; i++ {
		var f *os.File
		if f, err = os.Create(filepath.Join(dir, fmt.Sprintf("%d.snap", i))); err != nil {
			t.Fatal(err)
		} else {
			f.Close()
		}
	}
	ss := New(zaptest.NewLogger(t), dir)
	names, err := ss.snapNames()
	if err != nil {
		t.Errorf("err = %v, want nil", err)
	}
	if len(names) != 5 {
		t.Errorf("len = %d, want 10", len(names))
	}
	w := []string{"5.snap", "4.snap", "3.snap", "2.snap", "1.snap"}
	if !reflect.DeepEqual(names, w) {
		t.Errorf("names = %v, want %v", names, w)
	}
}

func ptr[T any](a T) *T {
	return &a
}

func TestLoadNewestSnap(t *testing.T) {
	dir := filepath.Join(os.TempDir(), "snapshot")
	err := os.Mkdir(dir, 0o700)
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)
	ss := New(zaptest.NewLogger(t), dir)
	err = ss.save(testSnap)
	if err != nil {
		t.Fatal(err)
	}

	newSnap := *testSnap
	newSnap.Metadata.Index = 5
	err = ss.save(&newSnap)
	if err != nil {
		t.Fatal(err)
	}

	cases := []struct {
		name              string
		availableWALSnaps []walpb.Snapshot
		expected          *raftpb.Snapshot

Review comment (suggestion):
```suggestion
// TODO: Replace with built-in new(a) when etcd requires Go 1.26 or later.
// See https://go.dev/doc/go1.26#language for details.
func ptr[T any](a T) *T {
	return &a
}
```

Code after:
	defer os.RemoveAll(dir)
	for i := 1; i <= 5; i++ {
		var f *os.File
		if f, err = os.Create(filepath.Join(dir, fmt.Sprintf("%d.snap", i))); err != nil {
			t.Fatal(err)
		} else {
			f.Close()
		}
	}
	ss := New(zaptest.NewLogger(t), dir)
	names, err := ss.snapNames()
	if err != nil {
		t.Errorf("err = %v, want nil", err)
	}
	if len(names) != 5 {
		t.Errorf("len = %d, want 10", len(names))
	}
	w := []string{"5.snap", "4.snap", "3.snap", "2.snap", "1.snap"}
	if !reflect.DeepEqual(names, w) {
		t.Errorf("names = %v, want %v", names, w)
	}
}

func TestLoadNewestSnap(t *testing.T) {
	dir := filepath.Join(os.TempDir(), "snapshot")
	err := os.Mkdir(dir, 0o700)
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)
	ss := New(zaptest.NewLogger(t), dir)
	err = ss.save(testSnap)
	if err != nil {
		t.Fatal(err)
	}

	newSnap := *testSnap
	newSnap.Metadata.Index = 5
	err = ss.save(&newSnap)
	if err != nil {
		t.Fatal(err)
	}

	cases := []struct {
		name              string
		availableWALSnaps []walpb.Snapshot
		expected          *raftpb.Snapshot
	}{
		{
			name:     "load-newest",
			expected: &newSnap,
Repository: etcd-io/etcd
File: server/etcdserver/v3_server.go (Go)

Code before:
				slowReadIndex.Inc()
				continue
			}
			return rs.Index, nil
		case <-leaderChangedNotifier:
			readIndexFailed.Inc()
			// return a retryable error.
			return 0, errors.ErrLeaderChanged
		case <-firstCommitInTermNotifier:
			firstCommitInTermNotifier = s.firstCommitInTerm.Receive()
			lg.Info("first commit in current term: resending ReadIndex request")
			retryTimer.Reset(readIndexRetryTime)
			requestID := s.reqIDGen.Next()
			err := s.sendReadIndex(requestID)
			if err != nil {
				return 0, err
			}
			continue
		case <-retryTimer.C:
			lg.Warn(
				"waiting for ReadIndex response took too long, retrying",
				zap.Uint64("sent-request-id", requestID),
				zap.Duration("retry-timeout", readIndexRetryTime),
			)
			retryTimer.Reset(readIndexRetryTime)
			requestID := s.reqIDGen.Next()
			err := s.sendReadIndex(requestID)
			if err != nil {
				return 0, err
			}
			continue
		case <-errorTimer.C:
			lg.Warn(
				"timed out waiting for read index response (local node might have slow network)",
				zap.Duration("timeout", s.Cfg.ReqTimeout()),
			)
			slowReadIndex.Inc()
			return 0, errors.ErrTimeout
		case <-s.stopping:
			return 0, errors.ErrStopped
		}
	}
}

func uint64ToBigEndianBytes(number uint64) []byte {
	byteResult := make([]byte, 8)
	binary.BigEndian.PutUint64(byteResult, number)
	return byteResult
}

func (s *EtcdServer) sendReadIndex(requestIndex uint64) error {

Review comment (suggestion):
```suggestion
			requestID = s.reqIDGen.Next()
```

Code after:
				continue
			}
			return rs.Index, nil
		case <-leaderChangedNotifier:
			readIndexFailed.Inc()
			// return a retryable error.
			return 0, errors.ErrLeaderChanged
		case <-firstCommitInTermNotifier:
			firstCommitInTermNotifier = s.firstCommitInTerm.Receive()
			lg.Info("first commit in current term: resending ReadIndex request")
			requestID = s.reqIDGen.Next()
			requestIDs[requestID] = struct{}{}
			err := s.sendReadIndex(requestID)
			if err != nil {
				return 0, err
			}
			retryTimer.Reset(readIndexRetryTime)
			continue
		case <-retryTimer.C:
			lg.Warn(
				"waiting for ReadIndex response took too long, retrying",
				zap.Uint64("sent-request-id", requestID),
				zap.Duration("retry-timeout", readIndexRetryTime),
			)
			requestID = s.reqIDGen.Next()
			requestIDs[requestID] = struct{}{}
			err := s.sendReadIndex(requestID)
			if err != nil {
				return 0, err
			}
			retryTimer.Reset(readIndexRetryTime)
			continue
		case <-errorTimer.C:
			lg.Warn(
				"timed out waiting for read index response (local node might have slow network)",
				zap.Duration("timeout", s.Cfg.ReqTimeout()),
			)
			slowReadIndex.Inc()
			return 0, errors.ErrTimeout
		case <-s.stopping:
			return 0, errors.ErrStopped
		}
	}
}

func uint64ToBigEndianBytes(number uint64) []byte {
	byteResult := make([]byte, 8)
	binary.BigEndian.PutUint64(byteResult, number)
	return byteResult
}
Repository: evanw/esbuild
File: internal/resolver/resolver.go (Go)

Code before:
	for {
		// Handle TypeScript base URLs for TypeScript code
		if dirInfo.tsConfigJson != nil {

			if dirInfo.tsConfigJson.absPathBaseUrl != nil {
				if dirInfo.tsConfigJson.paths != nil {
					for key, originalPaths := range dirInfo.tsConfigJson.paths {
						for _, originalPath := range originalPaths {
							if matched, err := regexp.MatchString("^"+key, path); matched && err == nil {
								if absoluteOriginalPath, err := resolvePathWithoutStar(*dirInfo.tsConfigJson.absPathBaseUrl, originalPath); err == nil {
									elements := strings.Split(path, "/")

									elements = elements[1:]

									resolved := append(strings.Split(absoluteOriginalPath, string(os.PathSeparator)), elements...)
									basePath := strings.Join(resolved, "/")
									if absolute, ok := r.loadAsFileOrDirectory(basePath); ok {
										return absolute, true
									}
								}
							}
						}

					}
				} else {
					basePath := r.fs.Join(*dirInfo.tsConfigJson.absPathBaseUrl, path)
					if absolute, ok := r.loadAsFileOrDirectory(basePath); ok {
						return absolute, true
					}
				}

			}
		}

		// Skip "node_modules" folders
		if dirInfo.hasNodeModules {
			absolute, ok := r.loadAsFileOrDirectory(r.fs.Join(dirInfo.absPath, "node_modules", path))
			if ok {
				return absolute, true
			}
		}

		// Go to the parent directory, stopping at the file system root
		dirInfo = dirInfo.parent
		if dirInfo == nil {
			break
		}
	}

	return "", false
}

Review comment (suggestion):
It looks like the TypeScript compiler still respects `baseUrl` if no `paths` matched, so we should do that too.


Code after:
		suffix := elements[1]
		return strings.Replace(path, suffix, "", 1), strings.HasSuffix(path, suffix)
	}
	prefix := elements[0]
	return strings.Replace(path, prefix, "", 1), strings.HasPrefix(path, prefix)
}

func (r *resolver) loadNodeModules(path string, dirInfo *dirInfo) (string, bool) {
	for {
		// Handle TypeScript base URLs for TypeScript code
		if dirInfo.tsConfigJson != nil {

			if dirInfo.tsConfigJson.absPathBaseUrl != nil {
				if dirInfo.tsConfigJson.paths != nil {
					for key, originalPaths := range dirInfo.tsConfigJson.paths {
						for _, originalPath := range originalPaths {
							if parts, ok := isTsConfigPathMatch(key, path); ok {
								absoluteOriginalPath := r.fs.Join(*dirInfo.tsConfigJson.absPathBaseUrl, originalPath)
								basePath := strings.Replace(absoluteOriginalPath, "*", parts, 1)
								if absolute, ok := r.loadAsFileOrDirectory(basePath); ok {
									return absolute, true
								}
							}
						}

					}
				}
				basePath := r.fs.Join(*dirInfo.tsConfigJson.absPathBaseUrl, path)
				if absolute, ok := r.loadAsFileOrDirectory(basePath); ok {
					return absolute, true
				}

			}
		}

		// Skip "node_modules" folders
		if dirInfo.hasNodeModules {
			absolute, ok := r.loadAsFileOrDirectory(r.fs.Join(dirInfo.absPath, "node_modules", path))
			if ok {
				return absolute, true
			}
		}

		// Go to the parent directory, stopping at the file system root
		dirInfo = dirInfo.parent
		if dirInfo == nil {
			break
		}
	}

	return "", false
Repository: evanw/esbuild
File: internal/bundler/bundler_test.go (Go)

Code before:
		parseOptions: parser.ParseOptions{
			IsBundling: true,
		},
		bundleOptions: BundleOptions{
			IsBundling:    true,
			AbsOutputFile: "/Users/user/project/out.js",
		},
		expected: map[string]string{
			"/Users/user/project/out.js": `// /Users/user/project/node_modules/demo-pkg/main.esm.js
function main_esm_default() {
  return 123;
}

// /Users/user/project/src/entry.js
console.log(main_esm_default());
`,
		},
	})
}

func TestPackageJsonBrowserString(t *testing.T) {
	expectBundled(t, bundled{
		files: map[string]string{
			"/Users/user/project/src/entry.js": `
				import fn from 'demo-pkg'
				console.log(fn())
			`,
			"/Users/user/project/node_modules/demo-pkg/package.json": `
				{
					"browser": "./browser"
				}
			`,
			"/Users/user/project/node_modules/demo-pkg/browser.js": `
				module.exports = function() {
					return 123
				}
			`,
		},
		entryPaths: []string{"/Users/user/project/src/entry.js"},
		parseOptions: parser.ParseOptions{
			IsBundling: true,
		},
		bundleOptions: BundleOptions{
			IsBundling:    true,
			AbsOutputFile: "/Users/user/project/out.js",
		},
		expected: map[string]string{
			"/Users/user/project/out.js": `// /Users/user/project/node_modules/demo-pkg/browser.js
var require_browser = __commonJS((exports, module) => {
  module.exports = function() {
    return 123;

Review comment (bug):
It appears this case isn't actually supposed to work. At least the TypeScript compiler throws an error here. I can do the testing work and make adjustments to the algorithm as appropriate.


Code after:
		parseOptions: parser.ParseOptions{
			IsBundling: true,
		},
		bundleOptions: BundleOptions{
			IsBundling:    true,
			AbsOutputFile: "/Users/user/project/out.js",
		},
		expected: map[string]string{
			"/Users/user/project/out.js": `// /Users/user/project/node_modules/demo-pkg/main.esm.js
function main_esm_default() {
  return 123;
}

// /Users/user/project/src/entry.js
console.log(main_esm_default());
`,
		},
	})
}

func TestTsConfigPaths(t *testing.T) {
	expectBundled(t, bundled{
		files: map[string]string{
			"/Users/user/project/src/entry.js": `
				import fn from 'core/test'
				import fn2 from 'testing/test'

				console.log(fn())
				console.log(fn2())

			`,
			"/Users/user/project/tsconfig.json": `
				{
					"compilerOptions": {
						"baseUrl": ".",
						"paths": {
							"core/*": ["./src/*"],
							"testing": ["./someotherdir/*"]
						}
					}
				}
			`,
			"/Users/user/project/src/test.js": `
				module.exports = function() {
					return 123
				}
			`,
			"/Users/user/project/someotherdir/test.js": `
				module.exports = function() {
					return 123
				}
Repository: evanw/esbuild
File: internal/resolver/resolver.go (Go)

Code before:
		dirInfo = dirInfo.parent
		if dirInfo == nil {
			break
		}
	}

	return "", false
}

func IsNonModulePath(path string) bool {
	return strings.HasPrefix(path, "/") || strings.HasPrefix(path, "./") ||
		strings.HasPrefix(path, "../") || path == "." || path == ".."
}

var externalModulesForNode = []string{
	"assert",
	"async_hooks",
	"buffer",
	"child_process",
	"cluster",
	"console",
	"constants",
	"crypto",
	"dgram",
	"dns",
	"domain",
	"events",
	"fs",
	"http",
	"http2",
	"https",
	"inspector",
	"module",
	"net",
	"os",
	"path",
	"perf_hooks",
	"process",
	"punycode",
	"querystring",
	"readline",
	"repl",
	"stream",
	"string_decoder",
	"sys",
	"timers",
	"tls",
	"trace_events",
	"tty",
	"url",
	"util",

Review comment (suggestion):
This doesn't follow the behavior of the TypeScript compiler which prefers exact matches over pattern matches and prefers matches with longer prefixes over matches with shorter prefixes. That's ok though, I'll fix it.


Code after:

func isTsConfigPathMatch(pattern string, path string) (string, bool) {
	starIndex := strings.IndexRune(pattern, '*')
	if starIndex == -1 {
		firstPath := strings.Split(path, "/")[0]
		return strings.Replace(path, pattern+"/", "", 1), firstPath == pattern
	}

	elements := strings.Split(pattern, "*")
	if starIndex == 0 {
		suffix := elements[1]
		return strings.Replace(path, suffix, "", 1), strings.HasSuffix(path, suffix)
	}
	prefix := elements[0]
	return strings.Replace(path, prefix, "", 1), strings.HasPrefix(path, prefix)
}

func (r *resolver) loadNodeModules(path string, dirInfo *dirInfo) (string, bool) {
	for {
		// Handle TypeScript base URLs for TypeScript code
		if dirInfo.tsConfigJson != nil {

			if dirInfo.tsConfigJson.absPathBaseUrl != nil {
				if dirInfo.tsConfigJson.paths != nil {
					for key, originalPaths := range dirInfo.tsConfigJson.paths {
						for _, originalPath := range originalPaths {
							if parts, ok := isTsConfigPathMatch(key, path); ok {
								absoluteOriginalPath := r.fs.Join(*dirInfo.tsConfigJson.absPathBaseUrl, originalPath)
								basePath := strings.Replace(absoluteOriginalPath, "*", parts, 1)
								if absolute, ok := r.loadAsFileOrDirectory(basePath); ok {
									return absolute, true
								}
							}
						}

					}
				}
				basePath := r.fs.Join(*dirInfo.tsConfigJson.absPathBaseUrl, path)
				if absolute, ok := r.loadAsFileOrDirectory(basePath); ok {
					return absolute, true
				}

			}
		}

		// Skip "node_modules" folders
		if dirInfo.hasNodeModules {
			absolute, ok := r.loadAsFileOrDirectory(r.fs.Join(dirInfo.absPath, "node_modules", path))
			if ok {
				return absolute, true
			}