@@ -315,74 +315,93 @@ type linker struct {
315
315
// different files.
316
316
imports map [string ]string
317
317
318
- // idToAnchor is a map from an ID to the anchor URL for that ID.
319
- idToAnchor map [string ]string
318
+ // idToAnchor is a map from package path to a map from ID to the anchor for
319
+ // that ID.
320
+ idToAnchor map [string ]map [string ]string
321
+
322
+ // sameDomainModules is a map from package path to module for every imported
323
+ // package that should cross link on the same domain.
324
+ sameDomainModules map [string ]* packages.Module
320
325
}
321
326
322
327
func newLinker (pi pkgInfo ) * linker {
328
+ sameDomainPrefixes := []string {"cloud.google.com/go" }
329
+
323
330
imports := map [string ]string {}
331
+ sameDomainModules := map [string ]* packages.Module {}
332
+ idToAnchor := map [string ]map [string ]string {}
333
+
324
334
for path , pkg := range pi .pkg .Imports {
325
335
name := pkg .Name
326
336
if rename := pi .importRenames [path ]; rename != "" {
327
337
name = rename
328
338
}
329
339
imports [name ] = path
340
+
341
+ // TODO: Consider documenting internal packages so we don't have to link
342
+ // out.
343
+ if pkg .Module != nil && hasPrefix (pkg .PkgPath , sameDomainPrefixes ) && ! strings .Contains (pkg .PkgPath , "internal" ) {
344
+ sameDomainModules [path ] = pkg .Module
345
+
346
+ docPkg , _ := doc .NewFromFiles (pkg .Fset , pkg .Syntax , path )
347
+ idToAnchor [path ] = buildIDToAnchor (docPkg )
348
+ }
330
349
}
331
350
332
- idToAnchor : = buildIDToAnchor (pi )
351
+ idToAnchor [ "" ] = buildIDToAnchor (pi . doc )
333
352
334
- return & linker {imports : imports , idToAnchor : idToAnchor }
353
+ return & linker {imports : imports , idToAnchor : idToAnchor , sameDomainModules : sameDomainModules }
335
354
}
336
355
337
356
// nonWordRegex is based on
338
357
// https://github.com/googleapis/doc-templates/blob/70eba5908e7b9aef5525d0f1f24194ae750f267e/third_party/docfx/templates/devsite/common.js#L27-L30.
339
358
var nonWordRegex = regexp .MustCompile ("\\ W" )
340
359
341
- func buildIDToAnchor (pi pkgInfo ) map [string ]string {
360
+ func buildIDToAnchor (pkg * doc. Package ) map [string ]string {
342
361
idToAnchor := map [string ]string {}
343
- idToAnchor [pi . doc . ImportPath ] = pi . doc .ImportPath
362
+ idToAnchor [pkg . ImportPath ] = pkg .ImportPath
344
363
345
- for _ , c := range pi . doc .Consts {
364
+ for _ , c := range pkg .Consts {
346
365
commaID := strings .Join (c .Names , "," )
347
- uid := pi . doc .ImportPath + "." + commaID
366
+ uid := pkg .ImportPath + "." + commaID
348
367
for _ , name := range c .Names {
349
368
idToAnchor [name ] = uid
350
369
}
351
370
}
352
- for _ , v := range pi . doc .Vars {
371
+ for _ , v := range pkg .Vars {
353
372
commaID := strings .Join (v .Names , "," )
354
- uid := pi . doc .ImportPath + "." + commaID
373
+ uid := pkg .ImportPath + "." + commaID
355
374
for _ , name := range v .Names {
356
375
idToAnchor [name ] = uid
357
376
}
358
377
}
359
- for _ , f := range pi . doc .Funcs {
360
- uid := pi . doc .ImportPath + "." + f .Name
378
+ for _ , f := range pkg .Funcs {
379
+ uid := pkg .ImportPath + "." + f .Name
361
380
idToAnchor [f .Name ] = uid
362
381
}
363
- for _ , t := range pi . doc .Types {
364
- uid := pi . doc .ImportPath + "." + t .Name
382
+ for _ , t := range pkg .Types {
383
+ uid := pkg .ImportPath + "." + t .Name
365
384
idToAnchor [t .Name ] = uid
366
385
for _ , c := range t .Consts {
367
386
commaID := strings .Join (c .Names , "," )
368
- uid := pi . doc .ImportPath + "." + commaID
387
+ uid := pkg .ImportPath + "." + commaID
369
388
for _ , name := range c .Names {
370
389
idToAnchor [name ] = uid
371
390
}
372
391
}
373
392
for _ , v := range t .Vars {
374
393
commaID := strings .Join (v .Names , "," )
375
- uid := pi . doc .ImportPath + "." + commaID
394
+ uid := pkg .ImportPath + "." + commaID
376
395
for _ , name := range v .Names {
377
396
idToAnchor [name ] = uid
378
397
}
379
398
}
380
399
for _ , f := range t .Funcs {
381
- uid := pi . doc .ImportPath + "." + t .Name + "." + f .Name
400
+ uid := pkg .ImportPath + "." + t .Name + "." + f .Name
382
401
idToAnchor [f .Name ] = uid
383
402
}
384
403
for _ , m := range t .Methods {
385
- uid := pi . doc .ImportPath + "." + t .Name + "." + m .Name
404
+ uid := pkg .ImportPath + "." + t .Name + "." + m .Name
386
405
idToAnchor [m .Name ] = uid
387
406
}
388
407
}
@@ -436,11 +455,20 @@ func (l *linker) linkify(s string) string {
436
455
// pattern.
437
456
func (l * linker ) toURL (pkg , name string ) string {
438
457
if pkg == "" {
439
- if anchor := l .idToAnchor [name ]; anchor != "" {
458
+ if anchor := l .idToAnchor ["" ][ name ]; anchor != "" {
440
459
name = anchor
441
460
}
442
461
return fmt .Sprintf ("#%s" , name )
443
462
}
463
+ if mod , ok := l .sameDomainModules [pkg ]; ok {
464
+ pkgRemainder := pkg [len (mod .Path )+ 1 :] // +1 to skip slash.
465
+ // Note: we always link to latest. One day, we'll link to mod.Version.
466
+ baseURL := fmt .Sprintf ("/go/docs/reference/%v/latest/%v" , mod .Path , pkgRemainder )
467
+ if anchor := l.idToAnchor [pkg ][name ]; anchor != "" {
468
+ return fmt .Sprintf ("%s#%s" , baseURL , anchor )
469
+ }
470
+ return baseURL
471
+ }
444
472
baseURL := "https://pkg.go.dev"
445
473
if name == "" {
446
474
return fmt .Sprintf ("%s/%s" , baseURL , pkg )
@@ -558,7 +586,7 @@ type pkgInfo struct {
558
586
559
587
func loadPackages (glob , workingDir string ) ([]pkgInfo , error ) {
560
588
config := & packages.Config {
561
- Mode : packages .NeedName | packages .NeedSyntax | packages .NeedTypes | packages .NeedTypesInfo | packages .NeedModule | packages .NeedImports ,
589
+ Mode : packages .NeedName | packages .NeedSyntax | packages .NeedTypes | packages .NeedTypesInfo | packages .NeedModule | packages .NeedImports | packages . NeedDeps ,
562
590
Tests : true ,
563
591
Dir : workingDir ,
564
592
}
@@ -594,7 +622,7 @@ func loadPackages(glob, workingDir string) ([]pkgInfo, error) {
594
622
}
595
623
if strings .Contains (id , "_test" ) {
596
624
id = id [0 :strings .Index (id , "_test [" )]
597
- } else {
625
+ } else if pkg . Module != nil {
598
626
idToPkg [pkg .PkgPath ] = pkg
599
627
pkgNames = append (pkgNames , pkg .PkgPath )
600
628
// The test package doesn't have Module set.
@@ -674,3 +702,12 @@ func loadPackages(glob, workingDir string) ([]pkgInfo, error) {
674
702
675
703
return result , nil
676
704
}
705
+
706
+ func hasPrefix (s string , prefixes []string ) bool {
707
+ for _ , prefix := range prefixes {
708
+ if strings .HasPrefix (s , prefix ) {
709
+ return true
710
+ }
711
+ }
712
+ return false
713
+ }
0 commit comments