github.com/stackb/rules_proto@v0.0.0-20240221195024-5428336c51f1/pkg/rule/rules_nodejs/proto_ts_library.go (about)

     1  package rules_nodejs
     2  
     3  import (
     4  	"flag"
     5  	"log"
     6  	"strings"
     7  
     8  	"github.com/bazelbuild/bazel-gazelle/config"
     9  	"github.com/bazelbuild/bazel-gazelle/label"
    10  	"github.com/bazelbuild/bazel-gazelle/resolve"
    11  	"github.com/bazelbuild/bazel-gazelle/rule"
    12  
    13  	"github.com/stackb/rules_proto/pkg/protoc"
    14  )
    15  
    16  const (
    17  	ProtoTsLibraryRuleName   = "proto_ts_library"
    18  	ProtoTsLibraryRuleSuffix = "_ts_proto"
    19  )
    20  
    21  func init() {
    22  	protoc.Rules().MustRegisterRule("stackb:rules_proto:proto_ts_library", &protoTsLibrary{})
    23  }
    24  
    25  // protoTsLibrary implements LanguageRule for the 'proto_ts_library' rule from
    26  // @rules_proto.
    27  type protoTsLibrary struct{}
    28  
    29  // Name implements part of the LanguageRule interface.
    30  func (s *protoTsLibrary) Name() string {
    31  	return ProtoTsLibraryRuleName
    32  }
    33  
    34  // KindInfo implements part of the LanguageRule interface.
    35  func (s *protoTsLibrary) KindInfo() rule.KindInfo {
    36  	return rule.KindInfo{
    37  		MergeableAttrs: map[string]bool{
    38  			"srcs":     true,
    39  			"tsc":      true,
    40  			"args":     true,
    41  			"data":     true,
    42  			"tsconfig": true,
    43  			"out_dir":  true,
    44  		},
    45  		NonEmptyAttrs: map[string]bool{
    46  			"srcs": true,
    47  		},
    48  		ResolveAttrs: map[string]bool{
    49  			"deps": true,
    50  		},
    51  	}
    52  
    53  }
    54  
    55  // LoadInfo implements part of the LanguageRule interface.
    56  func (s *protoTsLibrary) LoadInfo() rule.LoadInfo {
    57  	return rule.LoadInfo{
    58  		Name:    "@build_stack_rules_proto//rules/ts:proto_ts_library.bzl",
    59  		Symbols: []string{ProtoTsLibraryRuleName},
    60  	}
    61  }
    62  
    63  // ProvideRule implements part of the LanguageRule interface.
    64  func (s *protoTsLibrary) ProvideRule(cfg *protoc.LanguageRuleConfig, pc *protoc.ProtocConfiguration) protoc.RuleProvider {
    65  	flags := parseProtoTsLibraryFlags(ProtoTsLibraryRuleName, cfg.GetOptions())
    66  
    67  	outputs := make([]string, 0)
    68  	for _, out := range pc.Outputs {
    69  		if strings.HasSuffix(out, ".ts") {
    70  			outputs = append(outputs, out)
    71  		}
    72  	}
    73  	if len(outputs) == 0 {
    74  		return nil
    75  	}
    76  	return &tsLibrary{
    77  		flags:          flags,
    78  		KindName:       ProtoTsLibraryRuleName,
    79  		RuleNameSuffix: ProtoTsLibraryRuleSuffix,
    80  		Outputs:        outputs,
    81  		RuleConfig:     cfg,
    82  		Config:         pc,
    83  	}
    84  }
    85  
    86  // tsLibrary implements RuleProvider for 'ts_library'-like rules.
    87  type tsLibrary struct {
    88  	flags          *protoTsLibraryFlags
    89  	KindName       string
    90  	RuleNameSuffix string
    91  	Outputs        []string
    92  	Config         *protoc.ProtocConfiguration
    93  	RuleConfig     *protoc.LanguageRuleConfig
    94  }
    95  
    96  // Kind implements part of the ruleProvider interface.
    97  func (s *tsLibrary) Kind() string {
    98  	return s.KindName
    99  }
   100  
   101  // Name implements part of the ruleProvider interface.
   102  func (s *tsLibrary) Name() string {
   103  	return s.Config.Library.BaseName() + s.RuleNameSuffix
   104  }
   105  
   106  // Srcs computes the srcs list for the rule.
   107  func (s *tsLibrary) Srcs() []string {
   108  	return s.Outputs
   109  }
   110  
   111  // Deps computes the deps list for the rule.
   112  func (s *tsLibrary) Deps() []string {
   113  	return s.RuleConfig.GetDeps()
   114  }
   115  
   116  // Visibility provides visibility labels.
   117  func (s *tsLibrary) Visibility() []string {
   118  	return s.RuleConfig.GetVisibility()
   119  }
   120  
   121  // Rule implements part of the ruleProvider interface.
   122  func (s *tsLibrary) Rule(otherGen ...*rule.Rule) *rule.Rule {
   123  	newRule := rule.NewRule(s.Kind(), s.Name())
   124  
   125  	newRule.SetAttr("srcs", s.Srcs())
   126  
   127  	deps := s.Deps()
   128  	if len(deps) > 0 {
   129  		newRule.SetAttr("deps", deps)
   130  	}
   131  
   132  	args := s.RuleConfig.GetAttr("args")
   133  	if len(args) > 0 {
   134  		newRule.SetAttr("args", args)
   135  	}
   136  
   137  	tsconfig := s.RuleConfig.GetAttr("tsconfig")
   138  	if len(tsconfig) > 0 {
   139  		if len(tsconfig) > 1 {
   140  			log.Printf("warning (%s) found multiple entries for 'tsconfig', choosing last one: %v", s.Kind(), tsconfig)
   141  		}
   142  		newRule.SetAttr("tsconfig", tsconfig[len(tsconfig)-1])
   143  	}
   144  
   145  	outdir := s.RuleConfig.GetAttr("out_dir")
   146  	if len(outdir) > 0 {
   147  		if len(outdir) > 1 {
   148  			log.Printf("warning (%s) found multiple entries for 'out_dir', choosing last one: %v", s.Kind(), outdir)
   149  		}
   150  		newRule.SetAttr("out_dir", outdir[len(outdir)-1])
   151  	}
   152  
   153  	if s.flags.includeProtoLibraryData {
   154  		newRule.SetAttr("data", []string{s.Config.Library.Name()})
   155  	}
   156  
   157  	visibility := s.Visibility()
   158  	if len(visibility) > 0 {
   159  		newRule.SetAttr("visibility", visibility)
   160  	}
   161  
   162  	return newRule
   163  }
   164  
   165  // Imports implements part of the RuleProvider interface.
   166  func (s *tsLibrary) Imports(c *config.Config, r *rule.Rule, file *rule.File) []resolve.ImportSpec {
   167  	if lib, ok := r.PrivateAttr(protoc.ProtoLibraryKey).(protoc.ProtoLibrary); ok {
   168  		return protoc.ProtoLibraryImportSpecsForKind(r.Kind(), lib)
   169  	}
   170  	return nil
   171  }
   172  
   173  // Resolve implements part of the RuleProvider interface.
   174  func (s *tsLibrary) Resolve(c *config.Config, ix *resolve.RuleIndex, r *rule.Rule, imports []string, from label.Label) {
   175  	protoc.ResolveDepsAttr("deps", false /* resolve wkts */)(c, ix, r, imports, from)
   176  }
   177  
   178  // protoTsLibraryFlags represents the parsed flag configuration for the
   179  // proto_ts_library rule.
   180  type protoTsLibraryFlags struct {
   181  	// includeProtoLibraryData is true if the rule should populate the data
   182  	// attribute with the proto_library rule.
   183  	includeProtoLibraryData bool
   184  }
   185  
   186  func parseProtoTsLibraryFlags(kindName string, args []string) *protoTsLibraryFlags {
   187  	flags := flag.NewFlagSet(kindName, flag.ExitOnError)
   188  
   189  	var includeProtoLibraryData bool
   190  	flags.BoolVar(&includeProtoLibraryData, "include_proto_library_data", false, "--include_proto_library_data=true populates the data attribute with the proto_library rule")
   191  
   192  	if err := flags.Parse(args); err != nil {
   193  		log.Fatalf("failed to parse flags for %q: %v", kindName, err)
   194  	}
   195  
   196  	return &protoTsLibraryFlags{includeProtoLibraryData}
   197  }