Repository: JanDeDobbeleer/oh-my-posh
Pull request #1385 (2021-12-07 06:30:31)

feat(language): parameter for version detection
### Prerequisites

- [x] I have read and understood the `CONTRIBUTING` guide
- [x] The commit message follows the [conventional commits][cc] guidelines
- [x] Tests for the changes have been added (for bug fixes/features)
- [ ] Docs have been added / updated (for bug fixes/features)

read angular version from angular project file. New parameter added for language  for custom version reading.

<!---

Tips:

If you're not comfortable with working with Git, we're working a guide (https://ohmyposh.dev/docs/contributing_git) to help you out.
Oh My Posh advises GitKraken (https://www.gitkraken.com/invite/nQmDPR9D) as your preferred cross platform Git GUI power tool.

-->

[cc]: https://www.conventionalcommits.org/en/v1.0.0/#summary


JanDeDobbeleer: @lnu question, do we ever see the need for additional logic to add that to cmd but rather have the function live on language level and only execute it once?
lnu: > @lnu question, do we ever see the need for additional logic to add that to cmd but rather have the function live on language level and only execute it once?

I put it at the command level because we still use the regex parsing part of the command.
JanDeDobbeleer: @lnu fair point, can you have a look at my comment? Then we can merge this in.

Patch:
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index e075b356..8307552f 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -30,7 +30,7 @@
       "type": "shell",
       "command": "go",
       "label": "devcontainer: rebuild oh-my-posh",
-      "detail": "Build oh-my-posh for all shells when inside the devcaontainer",
+      "detail": "Build oh-my-posh for all shells when inside the devcontainer",
       "options": {
         "cwd": "${workspaceRoot}/src",
         "shell": {
diff --git a/src/segment_angular.go b/src/segment_angular.go
index 52ffa21c..fb6fe2ca 100644
--- a/src/segment_angular.go
+++ b/src/segment_angular.go
@@ -1,5 +1,10 @@
 package main
 
+import (
+	"encoding/json"
+	"fmt"
+)
+
 type angular struct {
 	language
 }
@@ -15,9 +20,28 @@ func (a *angular) init(props properties, env environmentInfo) {
 		extensions: []string{"angular.json"},
 		commands: []*cmd{
 			{
-				executable: "ng",
-				args:       []string{"--version"},
-				regex:      `Angular CLI: (?:(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,
+				regex: `(?:(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,
+				getVersion: func() (string, error) {
+					const fileName string = "package.json"
+					const fileFolder string = "/node_modules/@angular/core"
+					angularFilePath := a.language.env.getcwd() + fileFolder
+					if !a.language.env.hasFilesInDir(angularFilePath, fileName) {
+						return "", fmt.Errorf("%s not found in %s", fileName, angularFilePath)
+					}
+					// parse file
+					objmap := map[string]json.RawMessage{}
+					content := a.language.env.getFileContent(a.language.env.getcwd() + fileFolder + "/" + fileName)
+					err := json.Unmarshal([]byte(content), &objmap)
+					if err != nil {
+						return "", err
+					}
+					var str string
+					err = json.Unmarshal(objmap["version"], &str)
+					if err != nil {
+						return "", err
+					}
+					return str, nil
+				},
 			},
 		},
 		versionURLTemplate: "[%s](https://github.com/angular/angular/releases/tag/%s.%s.%s)",
diff --git a/src/segment_language.go b/src/segment_language.go
index 998c13e7..95b64680 100644
--- a/src/segment_language.go
+++ b/src/segment_language.go
@@ -10,6 +10,7 @@ type loadContext func()
 
 type inContext func() bool
 
+type getVersion func() (string, error)
 type matchesVersionFile func() bool
 
 type version struct {
@@ -25,6 +26,7 @@ type cmd struct {
 	executable string
 	args       []string
 	regex      string
+	getVersion getVersion
 }
 
 func (c *cmd) parse(versionInfo string) (*version, error) {
@@ -166,13 +168,22 @@ func (l *language) hasLanguageFiles() bool {
 // setVersion parses the version string returned by the command
 func (l *language) setVersion() error {
 	for _, command := range l.commands {
-		if !l.env.hasCommand(command.executable) {
-			continue
-		}
-		versionStr, err := l.env.runCommand(command.executable, command.args...)
-		if exitErr, ok := err.(*commandError); ok {
-			l.exitCode = exitErr.exitCode
-			return fmt.Errorf("err executing %s with %s", command.executable, command.args)
+		var versionStr string
+		var err error
+		if command.getVersion == nil {
+			if !l.env.hasCommand(command.executable) {
+				continue
+			}
+			versionStr, err = l.env.runCommand(command.executable, command.args...)
+			if exitErr, ok := err.(*commandError); ok {
+				l.exitCode = exitErr.exitCode
+				return fmt.Errorf("err executing %s with %s", command.executable, command.args)
+			}
+		} else {
+			versionStr, err = command.getVersion()
+			if err != nil {
+				return err
+			}
 		}
 		if versionStr == "" {
 			continue


Test patch:
diff --git a/src/segment_angular_test.go b/src/segment_angular_test.go
index bf7d0e15..6a5d9b4f 100644
--- a/src/segment_angular_test.go
+++ b/src/segment_angular_test.go
@@ -13,18 +13,24 @@ func TestAngularCliVersionDisplayed(t *testing.T) {
 		ExpectedString string
 		Version        string
 	}{
-		{Case: "Angular 12.2.9", ExpectedString: "12.2.9", Version: "Angular CLI: 12.2.9"},
+		{Case: "Angular 13.0.3", ExpectedString: "13.0.3", Version: "{ \"name\": \"@angular/core\",\"version\": \"13.0.3\"}"},
+		{Case: "Angular 11.0.1", ExpectedString: "11.0.1", Version: "{ \"name\": \"@angular/core\",\"version\": \"11.0.1\"}"},
 	}
 
 	for _, ta := range cases {
 		params := &mockedLanguageParams{
-			cmd:           "ng",
-			versionParam:  "--version",
-			versionOutput: ta.Version,
-			extension:     "angular.json",
+			extension: "angular.json",
 		}
 
-		env, props := getMockedLanguageEnv(params)
+		var env = new(MockedEnvironment)
+		// mock  getVersion methods
+		env.On("getcwd", nil).Return("/usr/home/dev/my-app")
+		env.On("homeDir", nil).Return("/usr/home")
+		env.On("hasFiles", params.extension).Return(true)
+		env.On("hasFilesInDir", "/usr/home/dev/my-app/node_modules/@angular/core", "package.json").Return(true)
+		env.On("getFileContent", "/usr/home/dev/my-app/node_modules/@angular/core/package.json").Return(ta.Version)
+
+		var props properties = map[Property]interface{}{}
 		angular := &angular{}
 		angular.init(props, env)
 		assert.True(t, angular.enabled(), fmt.Sprintf("Failed in case: %s", ta.Case))