Skip to content

Commit e4add14

Browse files
committed
feat(cli): support orion dependencies on npm packages (#7717)
Change the npm package resolution to a gazelle `CrossResolver` so other gazelle languages (such as orion) can resolve npm dependencies. The first commit just moves code around so the main commit has a simpler diff. --- ### Changes are visible to end-users: yes - Searched for relevant documentation and updated as needed: yes - Breaking change (forces users to change their own code or config): no - Suggested release notes appear below: yes Support BUILD-generation dependencies on npm packages from other gazelle languages such as orion. ### Test plan - Covered by existing test cases - New test cases added GitOrigin-RevId: a3779b341711d5bb4ab89fd9ad7f005352e27e64
1 parent 0a5a746 commit e4add14

File tree

3 files changed

+87
-72
lines changed

3 files changed

+87
-72
lines changed

gazelle/common/set.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ func (s *LabelSet) Add(l *label.Label) {
5555
s.labels.Add(relL)
5656
}
5757

58+
func (s *LabelSet) Size() int {
59+
return s.labels.Size()
60+
}
61+
5862
func (s *LabelSet) Empty() bool {
5963
return s.labels.Empty()
6064
}

gazelle/js/generate.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ const (
5454

5555
DefaultRootTargetName = "root"
5656

57+
configRelExtension = "__aspect_js_rel"
58+
5759
MaxWorkerCount = 12
5860
)
5961

@@ -65,6 +67,9 @@ func (ts *typeScriptLang) getImportLabel(imp string) *label.Label {
6567
// GenerateRules is called in each directory where an update is requested
6668
// in depth-first post-order.
6769
func (ts *typeScriptLang) GenerateRules(args language.GenerateArgs) language.GenerateResult {
70+
// TODO: move to common location or fix/patch a feature in gazelle
71+
args.Config.Exts[configRelExtension] = args.Rel
72+
6873
cfg := args.Config.Exts[LanguageName].(*JsGazelleConfig)
6974

7075
// Collect any labels that could be imported

gazelle/js/resolve.go

Lines changed: 78 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,12 @@ import (
2525
var _ resolve.Resolver = (*typeScriptLang)(nil)
2626

2727
const (
28-
Resolution_Error = -1
29-
Resolution_None = 0
30-
Resolution_NotFound = 1
31-
Resolution_Package = 2
32-
Resolution_Label = 3
33-
Resolution_NativeNode = 4
34-
Resolution_Override = 5
28+
Resolution_Error = iota
29+
Resolution_None
30+
Resolution_NotFound
31+
Resolution_Label
32+
Resolution_NativeNode
33+
Resolution_Override
3534
)
3635

3736
type ResolutionType = int
@@ -183,12 +182,40 @@ func (ts *typeScriptLang) Embeds(r *rule.Rule, from label.Label) []label.Label {
183182
}
184183

185184
return tsEmbeds
185+
case NpmLinkAllKind:
186+
// Do not return the embedded :node_modules/{pkg} targets.
187+
// Instead the npm CrossResolver will resolve to specific package targets.
188+
break
186189
}
187190

188191
// TODO(jbedard): ts_proto_library() embeds
189192

190193
// TODO(jbedard): implement other rule kinds
191-
return make([]label.Label, 0)
194+
return []label.Label{}
195+
}
196+
197+
var _ resolve.CrossResolver = (*typeScriptLang)(nil)
198+
199+
func (ts *typeScriptLang) CrossResolve(c *config.Config, ix *resolve.RuleIndex, imp resolve.ImportSpec, lang string) []resolve.FindResult {
200+
// Only resolve imports of js, can be from any language.
201+
if imp.Lang != LanguageName {
202+
return nil
203+
}
204+
205+
fromRel := c.Exts[configRelExtension].(string)
206+
207+
results := []resolve.FindResult{}
208+
209+
// Imports of npm packages
210+
if impPkg, _ := node.ParseImportPath(imp.Imp); impPkg != "" {
211+
if pkg := ts.findPackage(fromRel, impPkg); pkg != nil {
212+
results = append(results, resolve.FindResult{
213+
Label: *pkg,
214+
})
215+
}
216+
}
217+
218+
return results
192219
}
193220

194221
// Resolve translates imported libraries for a given rule into Bazel
@@ -279,7 +306,7 @@ func (ts *typeScriptLang) addTsLib(
279306
) {
280307
_, tsconfig := ts.tsconfig.FindConfig(from.Pkg)
281308
if tsconfig != nil && tsconfig.ImportHelpers {
282-
if tslibLabel := ts.resolvePackage(from, "tslib"); tslibLabel != nil {
309+
if tslibLabel := ts.findPackage(from.Pkg, "tslib"); tslibLabel != nil {
283310
deps.Add(tslibLabel)
284311
}
285312
}
@@ -300,12 +327,24 @@ func (ts *typeScriptLang) resolveImports(
300327
for it.Next() {
301328
imp := it.Value().(ImportStatement)
302329

330+
// Overrides override all
331+
if override, ok := resolve.FindRuleWithOverride(c, imp.ImportSpec, LanguageName); ok {
332+
deps.Add(&override)
333+
continue
334+
}
335+
336+
// JS Overrides (js_resolve) override all
337+
if res := cfg.GetResolution(imp.Imp); res != nil {
338+
deps.Add(res)
339+
continue
340+
}
341+
303342
resolutionType, dep, err := ts.resolveImport(c, ix, from, imp)
304343
if err != nil {
305344
return err
306345
}
307346

308-
types := ts.resolveImportTypes(resolutionType, from, imp)
347+
types := ts.resolveImportTypes(c, ix, resolutionType, from, imp)
309348
for _, typesDep := range types {
310349
deps.Add(typesDep)
311350
}
@@ -363,22 +402,10 @@ func (ts *typeScriptLang) resolveImport(
363402
from label.Label,
364403
impStm ImportStatement,
365404
) (ResolutionType, *label.Label, error) {
366-
cfg := c.Exts[LanguageName].(*JsGazelleConfig)
367-
368405
imp := impStm.ImportSpec
369406

370-
// Overrides
371-
if override, ok := resolve.FindRuleWithOverride(c, imp, LanguageName); ok {
372-
return Resolution_Override, &override, nil
373-
}
374-
375-
// JS Overrides (js_resolve)
376-
if res := cfg.GetResolution(imp.Imp); res != nil {
377-
return Resolution_Override, res, nil
378-
}
379-
380407
// Gazelle rule index
381-
if resolution, match, err := ts.resolveImportFromIndex(c, ix, from, impStm); resolution != Resolution_NotFound {
408+
if resolution, match, err := ts.resolveExplicitImportFromIndex(c, ix, from, impStm); resolution != Resolution_NotFound {
382409
return resolution, match, err
383410
}
384411

@@ -387,11 +414,6 @@ func (ts *typeScriptLang) resolveImport(
387414
return Resolution_Label, importLabel, nil
388415
}
389416

390-
// References to an npm package, pnpm workspace projects etc.
391-
if pkg := ts.resolvePackageImport(from, impStm.Imp); pkg != nil {
392-
return Resolution_Package, pkg, nil
393-
}
394-
395417
// References via tsconfig mappings (paths, baseUrl, rootDirs etc.)
396418
if tsconfigPaths := ts.tsconfig.ExpandPaths(impStm.SourcePath, impStm.ImportPath); len(tsconfigPaths) > 0 {
397419
for _, p := range tsconfigPaths {
@@ -404,7 +426,7 @@ func (ts *typeScriptLang) resolveImport(
404426
ImportPath: impStm.ImportPath,
405427
Optional: impStm.Optional,
406428
}
407-
if resolution, match, err := ts.resolveImportFromIndex(c, ix, from, pImp); resolution != Resolution_NotFound {
429+
if resolution, match, err := ts.resolveExplicitImportFromIndex(c, ix, from, pImp); resolution != Resolution_NotFound {
408430
return resolution, match, err
409431
}
410432
}
@@ -418,7 +440,7 @@ func (ts *typeScriptLang) resolveImport(
418440
return Resolution_NotFound, nil, nil
419441
}
420442

421-
func (ts *typeScriptLang) resolveImportFromIndex(
443+
func (ts *typeScriptLang) resolveExplicitImportFromIndex(
422444
c *config.Config,
423445
ix *resolve.RuleIndex,
424446
from label.Label,
@@ -429,82 +451,78 @@ func (ts *typeScriptLang) resolveImportFromIndex(
429451
return Resolution_NotFound, nil, nil
430452
}
431453

432-
filteredMatches := make([]label.Label, 0, len(matches))
454+
filteredMatches := common.NewLabelSet(from)
433455
for _, match := range matches {
434456
// Prevent from adding itself as a dependency.
435457
if !match.IsSelfImport(from) {
436-
filteredMatches = append(filteredMatches, match.Label)
458+
filteredMatches.Add(&match.Label)
437459
}
438460
}
439461

440462
// Too many results, don't know which is correct
441-
if len(filteredMatches) > 1 {
463+
if filteredMatches.Size() > 1 {
442464
return Resolution_Error, nil, fmt.Errorf(
443465
"Import %q from %q resolved to multiple targets (%s) - this must be fixed using the \"aspect:resolve\" directive",
444466
impStm.ImportPath, impStm.SourcePath, targetListFromResults(matches))
445467
}
446468

447469
// The matches were self imports, no dependency is needed
448-
if len(filteredMatches) == 0 {
470+
if filteredMatches.Size() == 0 {
449471
return Resolution_None, nil, nil
450472
}
451473

452-
match := filteredMatches[0]
474+
match := filteredMatches.Labels()[0]
453475

454476
BazelLog.Tracef("resolve %q import %q as %q", from, impStm.Imp, match)
455477

456-
return Resolution_Override, &match, nil
457-
}
458-
459-
func (ts *typeScriptLang) resolvePackageImport(from label.Label, imp string) *label.Label {
460-
impPkg, _ := node.ParseImportPath(imp)
461-
462-
// Imports not in the form of a package
463-
if impPkg == "" {
464-
return nil
465-
}
466-
467-
return ts.resolvePackage(from, impPkg)
478+
return Resolution_Label, &match, nil
468479
}
469480

470-
func (ts *typeScriptLang) resolvePackage(from label.Label, impPkg string) *label.Label {
471-
fromProject := ts.pnpmProjects.GetProject(from.Pkg)
481+
func (ts *typeScriptLang) findPackage(from string, impPkg string) *label.Label {
482+
fromProject := ts.pnpmProjects.GetProject(from)
472483
if fromProject == nil {
473-
BazelLog.Tracef("resolve %q import %q project not found", from.String(), impPkg)
484+
BazelLog.Tracef("resolve %q import %q project not found", from, impPkg)
474485
return nil
475486
}
476487

477488
impPkgLabel := fromProject.Get(impPkg)
478489
if impPkgLabel == nil {
479-
BazelLog.Tracef("resolve %q import %q not found", from.String(), impPkg)
490+
BazelLog.Tracef("resolve %q import %q not found", from, impPkg)
480491
return nil
481492
}
482493

483-
BazelLog.Tracef("resolve %q import %q to %q", from.String(), impPkg, impPkgLabel)
494+
BazelLog.Tracef("resolve %q import %q to %q", from, impPkg, impPkgLabel)
484495

485496
return impPkgLabel
486497
}
487498

488-
func (ts *typeScriptLang) resolveImportTypes(resolutionType ResolutionType, from label.Label, imp ImportStatement) []*label.Label {
499+
func (ts *typeScriptLang) resolveImportTypes(c *config.Config, ix *resolve.RuleIndex, resolutionType ResolutionType, from label.Label, imp ImportStatement) []*label.Label {
489500
// Overrides are not extended with additional types
490501
if resolutionType == Resolution_Override {
491502
return nil
492503
}
493504

494-
// Types for native node imports are always resolved to @types/node
505+
// The package the @types are for
506+
var typesPkg string
495507
if resolutionType == Resolution_NativeNode {
496-
if typesNode := ts.resolveAtTypes(from, "node"); typesNode != nil {
497-
return []*label.Label{typesNode}
508+
typesPkg = "@types/node"
509+
} else {
510+
typesPkg, _ = node.ParseImportPath(imp.ImportSpec.Imp)
511+
if typesPkg == "" {
512+
return nil
498513
}
499514

500-
return nil
515+
typesPkg = toAtTypesPackage(typesPkg)
501516
}
502517

503-
// Packages with specific @types/* definitions
504-
if typesPkg := ts.resolveAtTypes(from, imp.Imp); typesPkg != nil {
518+
typesSpec := resolve.ImportSpec{
519+
Lang: LanguageName,
520+
Imp: typesPkg,
521+
}
522+
if matches := ix.FindRulesByImportWithConfig(c, typesSpec, LanguageName); len(matches) > 0 {
505523
// @types packages for any named imports
506524
// The import may be a package, may be an unresolved import with only @types
507-
return []*label.Label{typesPkg}
525+
return []*label.Label{&matches[0].Label}
508526
}
509527

510528
// If an import has not been found and has no designated package or @types package
@@ -537,18 +555,6 @@ func toAtTypesPackage(pkg string) string {
537555
return "@types/" + pkg
538556
}
539557

540-
// Find and resolve any @types package for an import
541-
func (ts *typeScriptLang) resolveAtTypes(from label.Label, imp string) *label.Label {
542-
fromProject := ts.pnpmProjects.GetProject(from.Pkg)
543-
if fromProject == nil {
544-
return nil
545-
}
546-
547-
typesPkg := toAtTypesPackage(imp)
548-
549-
return fromProject.Get(typesPkg)
550-
}
551-
552558
// targetListFromResults returns a string with the human-readable list of
553559
// targets contained in the given results.
554560
func targetListFromResults(results []resolve.FindResult) string {

0 commit comments

Comments
 (0)