Skip to content

Commit

Permalink
Add detailed comments to improve code documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
matzefriedrich committed Sep 24, 2024
1 parent 1581a9a commit 99e581d
Show file tree
Hide file tree
Showing 27 changed files with 120 additions and 14 deletions.
7 changes: 7 additions & 0 deletions internal/commands/generate_mocks_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type mocksGeneratorCommand struct {
outputWriterFactory generator.OutputWriterFactory
}

// MocksGeneratorBehavior defines different behaviors for mock generation, which influence how mocks are handled based on annotations.
type MocksGeneratorBehavior int

const (
Expand All @@ -27,13 +28,15 @@ const (
ExcludeIgnored
)

// ParsleyMockAnnotationAttribute represents an attribute used to manage the behavior of mocking annotations during code generation, such as including or ignoring specified interface mocks based on annotations.
type ParsleyMockAnnotationAttribute int

const (
Mock ParsleyMockAnnotationAttribute = iota + 1
Ignore
)

// String provides a string representation of the ParsleyMockAnnotationAttribute enum.
func (p ParsleyMockAnnotationAttribute) String() string {
switch p {
case Mock:
Expand All @@ -45,6 +48,8 @@ func (p ParsleyMockAnnotationAttribute) String() string {
}
}

// Execute generates configurable mock implementations for all relevant interface types in the input source.
// It loads the template, configures the model, and writes the generated mocks to the specified output. The method also processes any errors encountered during code generation.
func (m *mocksGeneratorCommand) Execute() {

templateLoader := func(_ string) (string, error) {
Expand Down Expand Up @@ -108,6 +113,8 @@ func filterInterfaces(m *reflection.Model) []reflection.Interface {

var _ pkg.TypedCommand = (*mocksGeneratorCommand)(nil)

// NewGenerateMocksCommand creates a new cobra command to generate mock implementations for interfaces.
// This command uses the provided file accessor to read the source file and the output writer factory to write the generated mocks.
func NewGenerateMocksCommand(fileAccessor reflection.AstFileAccessor, outputWriterFactory generator.OutputWriterFactory) *cobra.Command {
if fileAccessor == nil {
panic("file accessor required")
Expand Down
2 changes: 2 additions & 0 deletions internal/commands/generate_proxy_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type generateProxyCommand struct {
outputWriterFactory generator.OutputWriterFactory
}

// Execute generates the code for a proxy.
func (g *generateProxyCommand) Execute() {

templateLoader := func(_ string) (string, error) {
Expand All @@ -39,6 +40,7 @@ func (g *generateProxyCommand) Execute() {

var _ pkg.TypedCommand = &generateProxyCommand{}

// NewGenerateProxyCommand creates a new cobra.Command for generating proxy code, enabling method call interception for interfaces.
func NewGenerateProxyCommand(fileAccessor reflection.AstFileAccessor, outputWriterFactory generator.OutputWriterFactory) *cobra.Command {
command := &generateProxyCommand{
fileAccessor: fileAccessor,
Expand Down
3 changes: 3 additions & 0 deletions internal/commands/init_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
// ScaffoldingFileWriterFactoryFunc defines a function type that returns a generator.ScaffoldingFileWriterFunc.
type ScaffoldingFileWriterFactoryFunc func(projectFolder string) (generator.ScaffoldingFileWriterFunc, error)

// ProjectLoaderFunc is a function type that loads a Go project given a project folder path.
type ProjectLoaderFunc func(projectFolderPath string) (generator.GoProject, error)

type initCommand struct {
Expand All @@ -24,6 +25,8 @@ type initCommand struct {
projectLoadFunc ProjectLoaderFunc
}

// Execute sets up a new project by loading the current project folder, adding necessary dependencies,
// and generating initial project files. It handles errors and ensures the minimum required version of dependencies.
func (g *initCommand) Execute() {

projectFolderPath, _ := os.Getwd()
Expand Down
2 changes: 2 additions & 0 deletions internal/commands/version_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type versionCommand struct {
httpClient utils.HttpClient
}

// Execute displays the current Parsley CLI version and checks for updates if enabled. Shows update instructions if a new version exists.
func (v *versionCommand) Execute() {

appVersion, appVersionErr := utils.ApplicationVersion()
Expand Down Expand Up @@ -55,6 +56,7 @@ func (v *versionCommand) Execute() {

var _ pkg.TypedCommand = (*versionCommand)(nil)

// NewVersionCommand creates a new cobra.Command that displays the current version of the Parsley CLI and checks for updates.
func NewVersionCommand(httpClient utils.HttpClient) *cobra.Command {
command := &versionCommand{
httpClient: httpClient,
Expand Down
9 changes: 9 additions & 0 deletions internal/core/function_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,22 @@ type functionParameterInfo struct {
parameterType types.ServiceType
}

// String returns the string representation of the reflected type of the function parameter.
func (f functionParameterInfo) String() string {
reflectedType := f.Type().ReflectedType()
return fmt.Sprintf("%s", reflectedType.String())
}

// Type returns the ServiceType of the function parameter, which provides meta information like name, package path, and reflect type.
func (f functionParameterInfo) Type() types.ServiceType {
return f.parameterType
}

var _ types.FunctionParameterInfo = &functionParameterInfo{}

// ReflectFunctionInfoFrom retrieves metadata about a given function using reflection, providing details about the function's type,
// return type, parameter types, and other characteristics. Ensures that the value provided is a valid function and returns
// appropriate errors if it is not. Useful for dynamically inspecting and working with functions.
func ReflectFunctionInfoFrom(value reflect.Value) (types.FunctionInfo, error) {
funcType := value.Type()
if funcType.Kind() != reflect.Func {
Expand All @@ -61,6 +66,7 @@ func ReflectFunctionInfoFrom(value reflect.Value) (types.FunctionInfo, error) {
}, nil
}

// Name retrieves the name of the reflected function.
func (f functionInfo) Name() string {
pointer := f.reflectedFunctionValue.Pointer()
functionFromPointer := runtime.FuncForPC(pointer)
Expand All @@ -70,6 +76,7 @@ func (f functionInfo) Name() string {
return ""
}

// Parameters returns a slice of FunctionParameterInfo representing the parameters of the function.
func (f functionInfo) Parameters() []types.FunctionParameterInfo {
return f.parameters
}
Expand All @@ -82,10 +89,12 @@ func (f functionInfo) ParameterTypes() []types.ServiceType {
return parameterTypes
}

// ReturnType returns the type of the service returned by the function.
func (f functionInfo) ReturnType() types.ServiceType {
return f.returnType
}

// String returns a string representation of the function's signature, including its name, parameters, and return type.
func (f functionInfo) String() string {
parameterTypeNames := make([]string, len(f.parameters))
for _, t := range f.parameters {
Expand Down
4 changes: 4 additions & 0 deletions internal/core/instances.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func NewInstancesBag(parent *InstanceBag, scope types.LifetimeScope) *InstanceBa
return bag
}

// TryResolveInstance attempts to locate an instance of a service identified by the given registration.
func (b *InstanceBag) TryResolveInstance(ctx context.Context, registration types.ServiceRegistration) (interface{}, bool) {
id := registration.Id()
instance, found := b.instances[id]
Expand All @@ -52,6 +53,9 @@ func (b *InstanceBag) TryResolveInstance(ctx context.Context, registration types
return nil, false
}

// KeepInstance stores an instance of a service based on the service's lifetime scope. Singleton instances are stored
// at the appropriate singleton level in the hierarchy. Scoped instances are stored in the context-specified scope.
// Transient instances are stored in the current instance bag.
func (b *InstanceBag) KeepInstance(ctx context.Context, registration types.ServiceRegistration, instance interface{}) {
id := registration.Id()
switch registration.LifetimeScope() {
Expand Down
2 changes: 2 additions & 0 deletions internal/core/service_id.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ type serviceId struct {
m sync.Mutex
}

// ServiceIdSequence is an interface for generating sequential service identifiers.
type ServiceIdSequence interface {
Next() uint64
}

var _ ServiceIdSequence = &serviceId{}

// NewServiceId creates a new instance of ServiceIdSequence starting from the specified initial value. This is useful for generating unique service identifiers in a thread-safe manner.
func NewServiceId(n uint64) ServiceIdSequence {
return &serviceId{n: n, m: sync.Mutex{}}
}
Expand Down
6 changes: 6 additions & 0 deletions internal/stack.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package internal

// Stack represents a last-in-first-out (LIFO) collection of items. It can be used to manage a set of elements with push and pop operations.
type Stack[TValue any] []TValue

// MakeStack creates and returns a new Stack initialized with the provided initial values. Useful for algorithm implementations needing LIFO structures.
func MakeStack[TValue any](initialValues ...TValue) Stack[TValue] {
s := Stack[TValue]{}
for _, v := range initialValues {
Expand All @@ -10,18 +12,22 @@ func MakeStack[TValue any](initialValues ...TValue) Stack[TValue] {
return s
}

// Any determines if the stack contains at least one element, indicating it is not empty.
func (s *Stack[TValue]) Any() bool {
return s.IsEmpty() == false
}

// IsEmpty checks whether the stack is empty, which can help determine if there are any elements left to process.
func (s *Stack[TValue]) IsEmpty() bool {
return len(*s) == 0
}

// Push appends one or more values to the top of the stack, allowing dynamic and flexible addition of elements.
func (s *Stack[TValue]) Push(value ...TValue) {
*s = append(*s, value...)
}

// Pop removes and returns the item at the top of the stack, allowing for a LIFO retrieval of elements.
func (s *Stack[TValue]) Pop() TValue {
lastItemIndex := len(*s) - 1
element := (*s)[lastItemIndex]
Expand Down
6 changes: 6 additions & 0 deletions internal/utils/github_api_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"time"
)

// GithubRelease represents a release from a GitHub repository, including essential metadata and URL for access.
type GithubRelease struct {
Id uint64 `json:"id"`
TagName string `json:"tag_name"`
Expand All @@ -18,6 +19,7 @@ type GithubRelease struct {
PublishedAt time.Time `json:"published_at"`
}

// TryParseVersionFromTag attempts to extract and parse semantic version details from the TagName of a GitHub release.
func (r GithubRelease) TryParseVersionFromTag() (*VersionInfo, error) {
version := r.TagName
return tryParseVersionInfo(version)
Expand All @@ -28,18 +30,22 @@ type githubApiClient struct {
options HttpClientOptions
}

// GitHubClient is an interface for interacting with GitHub's API, specifically for querying the latest release tag of a repository.
type GitHubClient interface {
QueryLatestReleaseTag(ctx context.Context) (*GithubRelease, error)
}

var _ GitHubClient = (*githubApiClient)(nil)

// HttpClientOptions holds configuration options for customizing the behavior of an HttpClient.
type HttpClientOptions struct {
RequestTimeout time.Duration
}

// HttpClientOptionsFunc represents a function that modifies HttpClientOptions to customize HttpClient's behavior.
type HttpClientOptionsFunc func(*HttpClientOptions)

// NewGitHubApiClient creates a new GitHubClient with customizable HTTP client options for querying GitHub's API.
func NewGitHubApiClient(httpClient HttpClient, config ...HttpClientOptionsFunc) GitHubClient {
options := HttpClientOptions{
RequestTimeout: 5 * time.Second,
Expand Down
4 changes: 1 addition & 3 deletions internal/utils/http_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ package utils

import "net/http"

//go:generate parsley-cli generate mocks

//parsley:mock
// HttpClient provides an interface for making HTTP requests, allowing for different implementations such as mocks or wrappers.
type HttpClient interface {
Do(req *http.Request) (*http.Response, error)
}
2 changes: 1 addition & 1 deletion internal/utils/map.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package utils

// Map applies a given function to each element of a slice and returns a new slice containing the results of the function.
// Map applies a given function to each element of a slice and returns a new slice with the results.
func Map[S ~[]E, E any, V any](ts S, fn func(E) V) []V {
result := make([]V, len(ts))
for i, t := range ts {
Expand Down
5 changes: 5 additions & 0 deletions internal/utils/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,33 @@ const (
VersionString string = "1.0.1"
)

// VersionInfo represents the version details using semantic versioning.
type VersionInfo struct {
Major int
Minor int
Patch int
}

// String returns the VersionInfo as a formatted string in the semantic versioning format (Major.Minor.Patch).
func (v VersionInfo) String() string {
return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
}

// LessThan determines if the current VersionInfo is less than the specified VersionInfo based on semantic versioning.
func (v VersionInfo) LessThan(other VersionInfo) bool {
a, _ := version.NewVersion(v.String())
b, _ := version.NewVersion(other.String())
return a.LessThan(b)
}

// Equal determines if two VersionInfo instances represent the same version based on semantic versioning.
func (v VersionInfo) Equal(other VersionInfo) bool {
a, _ := version.NewVersion(v.String())
b, _ := version.NewVersion(other.String())
return a.Equal(b)
}

// ApplicationVersion parses and returns the application's version information. If the version is not set, an error is returned.
func ApplicationVersion() (*VersionInfo, error) {
v, err := tryParseVersionInfo(VersionString)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions internal/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package internal

import "reflect"

// IsNil checks if the given instance of any type T is nil.
func IsNil[T any](instance T) bool {
// Use reflection to check if instance is nil
val := reflect.ValueOf(instance)
Expand Down
3 changes: 3 additions & 0 deletions pkg/bootstrap/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@ const (
ErrorCannotRegisterAppFactory = "cannot register application factory"
)

// ErrCannotRegisterAppFactory is returned when the application factory cannot be registered, indicating an issue with the bootstrap process.
var (
ErrCannotRegisterAppFactory = errors.New(ErrorCannotRegisterAppFactory)
)

var parsley infrastructure

// RunParsleyApplication initializes and runs the Parsley application lifecycle.
// It registers the application factory, configures additional modules, resolves the main application instance, and invokes its Run method.
func RunParsleyApplication(cxt context.Context, appFactoryFunc any, configure ...types.ModuleFunc) error {

registry := registration.NewServiceRegistry()
Expand Down
1 change: 1 addition & 0 deletions pkg/bootstrap/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package bootstrap

import "context"

// Application provides an abstract interface for creating and running an application. It primarily facilitates the use of dependency injection for resolving services and the managing application lifecycle.
type Application interface {
Run(context.Context) error
}
3 changes: 3 additions & 0 deletions pkg/features/lazy_services.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type lazy[T any] struct {
m sync.RWMutex
}

// Value returns the instance of the lazy-initialized type, generating it if not already created. Ensures thread-safety.
func (l *lazy[T]) Value() T {
l.m.RLock()
if internal.IsNil(l.instance) == false {
Expand All @@ -29,12 +30,14 @@ func (l *lazy[T]) Value() T {
return l.instance
}

// Lazy represents a type whose value is initialized lazily upon first access, typically to improve performance or manage resources.
type Lazy[T any] interface {
Value() T
}

var _ Lazy[any] = &lazy[any]{}

// RegisterLazy registers a lazily-activated service in the service registry using the provided activator function.
func RegisterLazy[T any](registry types.ServiceRegistry, activatorFunc func() T, _ types.LifetimeScope) error {

lazyActivator := newLazyServiceFactory[T](activatorFunc)
Expand Down
1 change: 1 addition & 0 deletions pkg/features/list_services.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/matzefriedrich/parsley/pkg/types"
)

// RegisterList registers a function that resolves and returns a list of services of type T with the specified registry.
func RegisterList[T any](registry types.ServiceRegistry) error {
return registry.Register(func(resolver types.Resolver) []T {
services, _ := resolving.ResolveRequiredServices[T](resolver, context.Background())
Expand Down
Loading

0 comments on commit 99e581d

Please sign in to comment.