refactor: generic language support

This commit is contained in:
Jan De Dobbeleer 2021-02-03 19:11:32 +01:00 committed by Jan De Dobbeleer
parent 7e813893ed
commit c43cbac284
7 changed files with 316 additions and 209 deletions

View file

@ -27,13 +27,15 @@ func (d *dotnet) init(props *properties, env environmentInfo) {
d.language = &language{ d.language = &language{
env: env, env: env,
props: props, props: props,
commands: []string{"dotnet"},
versionParam: "--version",
extensions: []string{"*.cs", "*.vb", "*.sln", "*.csproj", "*.vbproj"}, extensions: []string{"*.cs", "*.vb", "*.sln", "*.csproj", "*.vbproj"},
version: &version{ commands: []*cmd{
{
executable: "dotnet",
args: []string{"--version"},
regex: `(?:(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?:\d{2})(?P<patch>[0-9]{1}))))`, regex: `(?:(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?:\d{2})(?P<patch>[0-9]{1}))))`,
urlTemplate: "[%1s](https://github.com/dotnet/core/blob/master/release-notes/%[2]s.%[3]s/%[2]s.%[3]s.%[4]s/%[2]s.%[3]s.%[4]s.md)",
}, },
},
versionURLTemplate: "[%1s](https://github.com/dotnet/core/blob/master/release-notes/%[2]s.%[3]s/%[2]s.%[3]s.%[4]s/%[2]s.%[3]s.%[4]s.md)",
} }
} }

View file

@ -12,13 +12,15 @@ func (g *golang) init(props *properties, env environmentInfo) {
g.language = &language{ g.language = &language{
env: env, env: env,
props: props, props: props,
commands: []string{"go"},
versionParam: "version",
extensions: []string{"*.go", "go.mod"}, extensions: []string{"*.go", "go.mod"},
version: &version{ commands: []*cmd{
{
executable: "go",
args: []string{"version"},
regex: `(?:go(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`, regex: `(?:go(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,
urlTemplate: "[%s](https://golang.org/doc/go%s.%s)",
}, },
},
versionURLTemplate: "[%s](https://golang.org/doc/go%s.%s)",
} }
} }

View file

@ -12,12 +12,14 @@ func (j *julia) init(props *properties, env environmentInfo) {
j.language = &language{ j.language = &language{
env: env, env: env,
props: props, props: props,
commands: []string{"julia"},
versionParam: "--version",
extensions: []string{"*.jl"}, extensions: []string{"*.jl"},
version: &version{ commands: []*cmd{
{
executable: "julia",
args: []string{"--version"},
regex: `julia version (?P<version>[0-9]+.[0-9]+.[0-9]+)`, regex: `julia version (?P<version>[0-9]+.[0-9]+.[0-9]+)`,
}, },
},
} }
} }

View file

@ -15,31 +15,56 @@ type version struct {
major string major string
minor string minor string
patch string patch string
regex string
urlTemplate string
} }
func (v *version) parse(versionInfo string) error { type cmd struct {
values := findNamedRegexMatch(v.regex, versionInfo) executable string
args []string
regex string
version *version
}
func (c *cmd) parse(versionInfo string) error {
values := findNamedRegexMatch(c.regex, versionInfo)
if len(values) == 0 { if len(values) == 0 {
return errors.New("cannot parse version string") return errors.New("cannot parse version string")
} }
c.version = &version{}
v.full = values["version"] c.version.full = values["version"]
v.major = values["major"] c.version.major = values["major"]
v.minor = values["minor"] c.version.minor = values["minor"]
v.patch = values["patch"] c.version.patch = values["patch"]
return nil return nil
} }
func (c *cmd) buildVersionURL(template string) string {
if template == "" {
return c.version.full
}
truncatingSprintf := func(str string, args ...interface{}) (string, error) {
n := strings.Count(str, "%s")
if n > len(args) {
return "", errors.New("Too many parameters")
}
if n == 0 {
return fmt.Sprintf(str, args...), nil
}
return fmt.Sprintf(str, args[:n]...), nil
}
version, err := truncatingSprintf(template, c.version.full, c.version.major, c.version.minor, c.version.patch)
if err != nil {
return c.version.full
}
return version
}
type language struct { type language struct {
props *properties props *properties
env environmentInfo env environmentInfo
extensions []string extensions []string
commands []string commands []*cmd
executable string versionURLTemplate string
versionParam string activeCommand *cmd
version *version
exitCode int exitCode int
loadContext loadContext loadContext loadContext
inContext inContext inContext inContext
@ -66,24 +91,16 @@ func (l *language) string() string {
if !l.props.getBool(DisplayVersion, true) { if !l.props.getBool(DisplayVersion, true) {
return "" return ""
} }
if !l.hasCommand() {
return l.props.getString(MissingCommandTextProperty, MissingCommandText)
}
err := l.setVersion() err := l.setVersion()
if err != nil { if err != nil {
return "" return err.Error()
} }
// build release notes hyperlink if l.props.getBool(EnableHyperlink, false) {
if l.props.getBool(EnableHyperlink, false) && l.version.urlTemplate != "" { return l.activeCommand.buildVersionURL(l.versionURLTemplate)
version, err := TruncatingSprintf(l.version.urlTemplate, l.version.full, l.version.major, l.version.minor, l.version.patch)
if err != nil {
return l.version.full
} }
return version return l.activeCommand.version.full
}
return l.version.full
} }
func (l *language) enabled() bool { func (l *language) enabled() bool {
@ -119,30 +136,23 @@ func (l *language) hasLanguageFiles() bool {
// setVersion parses the version string returned by the command // setVersion parses the version string returned by the command
func (l *language) setVersion() error { func (l *language) setVersion() error {
versionInfo, err := l.env.runCommand(l.executable, l.versionParam) for _, command := range l.commands {
if !l.env.hasCommand(command.executable) {
continue
}
version, err := l.env.runCommand(command.executable, command.args...)
if exitErr, ok := err.(*commandError); ok { if exitErr, ok := err.(*commandError); ok {
l.exitCode = exitErr.exitCode l.exitCode = exitErr.exitCode
return errors.New("error executing command") return fmt.Errorf("err executing %s with %s", command.executable, command.args)
} }
err = l.version.parse(versionInfo) err = command.parse(version)
if err != nil { if err != nil {
return err return fmt.Errorf("err parsing info from %s with %s", command.executable, version)
} }
l.activeCommand = command
return nil return nil
} }
return errors.New(l.props.getString(MissingCommandTextProperty, MissingCommandText))
// hasCommand checks if one of the commands exists and sets it as executable
func (l *language) hasCommand() bool {
for i, command := range l.commands {
if l.env.hasCommand(command) {
l.executable = command
break
}
if i == len(l.commands)-1 {
return false
}
}
return true
} }
func (l *language) loadLanguageContext() { func (l *language) loadLanguageContext() {
@ -158,14 +168,3 @@ func (l *language) inLanguageContext() bool {
} }
return l.inContext() return l.inContext()
} }
func TruncatingSprintf(str string, args ...interface{}) (string, error) {
n := strings.Count(str, "%s")
if n > len(args) {
return "", errors.New("Too many parameters")
}
if n == 0 {
return fmt.Sprintf(str, args...), nil
}
return fmt.Sprintf(str, args[:n]...), nil
}

View file

@ -18,13 +18,12 @@ type languageArgs struct {
displayMode string displayMode string
extensions []string extensions []string
enabledExtensions []string enabledExtensions []string
commands []string commands []*cmd
enabledCommands []string enabledCommands []string
versionParam string
versionRegex string
missingCommandText string missingCommandText string
urlTemplate string versionURLTemplate string
enableHyperlink bool enableHyperlink bool
expectedError error
} }
func (l *languageArgs) hasvalue(value string, list []string) bool { func (l *languageArgs) hasvalue(value string, list []string) bool {
@ -39,8 +38,8 @@ func (l *languageArgs) hasvalue(value string, list []string) bool {
func bootStrapLanguageTest(args *languageArgs) *language { func bootStrapLanguageTest(args *languageArgs) *language {
env := new(MockedEnvironment) env := new(MockedEnvironment)
for _, command := range args.commands { for _, command := range args.commands {
env.On("hasCommand", command).Return(args.hasvalue(command, args.enabledCommands)) env.On("hasCommand", command.executable).Return(args.hasvalue(command.executable, args.enabledCommands))
env.On("runCommand", command, []string{args.versionParam}).Return(args.version, nil) env.On("runCommand", command.executable, command.args).Return(args.version, args.expectedError)
} }
for _, extension := range args.extensions { for _, extension := range args.extensions {
env.On("hasFiles", extension).Return(args.hasvalue(extension, args.enabledExtensions)) env.On("hasFiles", extension).Return(args.hasvalue(extension, args.enabledExtensions))
@ -60,19 +59,19 @@ func bootStrapLanguageTest(args *languageArgs) *language {
env: env, env: env,
extensions: args.extensions, extensions: args.extensions,
commands: args.commands, commands: args.commands,
versionParam: args.versionParam, versionURLTemplate: args.versionURLTemplate,
version: &version{
regex: args.versionRegex,
urlTemplate: args.urlTemplate,
},
} }
return l return l
} }
func TestLanguageFilesFoundButNoCommandAndVersionAndDisplayVersion(t *testing.T) { func TestLanguageFilesFoundButNoCommandAndVersionAndDisplayVersion(t *testing.T) {
args := &languageArgs{ args := &languageArgs{
commands: []string{"unicorn"}, commands: []*cmd{
versionParam: "--version", {
executable: "unicorn",
args: []string{"--version"},
},
},
extensions: []string{uni}, extensions: []string{uni},
enabledExtensions: []string{uni}, enabledExtensions: []string{uni},
displayVersion: true, displayVersion: true,
@ -84,8 +83,12 @@ func TestLanguageFilesFoundButNoCommandAndVersionAndDisplayVersion(t *testing.T)
func TestLanguageFilesFoundButNoCommandAndVersionAndDontDisplayVersion(t *testing.T) { func TestLanguageFilesFoundButNoCommandAndVersionAndDontDisplayVersion(t *testing.T) {
args := &languageArgs{ args := &languageArgs{
commands: []string{"unicorn"}, commands: []*cmd{
versionParam: "--version", {
executable: "unicorn",
args: []string{"--version"},
},
},
extensions: []string{uni}, extensions: []string{uni},
enabledExtensions: []string{uni}, enabledExtensions: []string{uni},
displayVersion: false, displayVersion: false,
@ -96,8 +99,12 @@ func TestLanguageFilesFoundButNoCommandAndVersionAndDontDisplayVersion(t *testin
func TestLanguageFilesFoundButNoCommandAndNoVersion(t *testing.T) { func TestLanguageFilesFoundButNoCommandAndNoVersion(t *testing.T) {
args := &languageArgs{ args := &languageArgs{
commands: []string{"unicorn"}, commands: []*cmd{
versionParam: "--version", {
executable: "unicorn",
args: []string{"--version"},
},
},
extensions: []string{uni}, extensions: []string{uni},
enabledExtensions: []string{uni}, enabledExtensions: []string{uni},
} }
@ -107,10 +114,16 @@ func TestLanguageFilesFoundButNoCommandAndNoVersion(t *testing.T) {
func TestLanguageDisabledNoFiles(t *testing.T) { func TestLanguageDisabledNoFiles(t *testing.T) {
args := &languageArgs{ args := &languageArgs{
versionParam: "--version", commands: []*cmd{
commands: []string{"unicorn"}, {
enabledCommands: []string{"unicorn"}, executable: "unicorn",
args: []string{"--version"},
},
},
extensions: []string{uni}, extensions: []string{uni},
enabledExtensions: []string{},
enabledCommands: []string{"unicorn"},
displayVersion: true,
} }
lang := bootStrapLanguageTest(args) lang := bootStrapLanguageTest(args)
assert.False(t, lang.enabled(), "no files in the current directory") assert.False(t, lang.enabled(), "no files in the current directory")
@ -118,12 +131,16 @@ func TestLanguageDisabledNoFiles(t *testing.T) {
func TestLanguageEnabledOneExtensionFound(t *testing.T) { func TestLanguageEnabledOneExtensionFound(t *testing.T) {
args := &languageArgs{ args := &languageArgs{
versionParam: "--version", commands: []*cmd{
commands: []string{"unicorn"}, {
enabledCommands: []string{"unicorn"}, executable: "unicorn",
args: []string{"--version"},
regex: "(?P<version>.*)",
},
},
extensions: []string{uni, corn}, extensions: []string{uni, corn},
enabledExtensions: []string{uni}, enabledExtensions: []string{uni},
versionRegex: "(?P<version>.*)", enabledCommands: []string{"unicorn"},
version: universion, version: universion,
displayVersion: true, displayVersion: true,
} }
@ -134,13 +151,17 @@ func TestLanguageEnabledOneExtensionFound(t *testing.T) {
func TestLanguageEnabledSecondExtensionFound(t *testing.T) { func TestLanguageEnabledSecondExtensionFound(t *testing.T) {
args := &languageArgs{ args := &languageArgs{
versionParam: "--version", commands: []*cmd{
commands: []string{"unicorn"}, {
enabledCommands: []string{"unicorn"}, executable: "unicorn",
args: []string{"--version"},
regex: "(?P<version>.*)",
},
},
extensions: []string{uni, corn}, extensions: []string{uni, corn},
versionRegex: "(?P<version>.*)",
version: universion,
enabledExtensions: []string{corn}, enabledExtensions: []string{corn},
enabledCommands: []string{"unicorn"},
version: universion,
displayVersion: true, displayVersion: true,
} }
lang := bootStrapLanguageTest(args) lang := bootStrapLanguageTest(args)
@ -150,13 +171,22 @@ func TestLanguageEnabledSecondExtensionFound(t *testing.T) {
func TestLanguageEnabledSecondCommand(t *testing.T) { func TestLanguageEnabledSecondCommand(t *testing.T) {
args := &languageArgs{ args := &languageArgs{
versionParam: "--version", commands: []*cmd{
commands: []string{"uni", "corn"}, {
enabledCommands: []string{"corn"}, executable: "uni",
args: []string{"--version"},
regex: "(?P<version>.*)",
},
{
executable: "corn",
args: []string{"--version"},
regex: "(?P<version>.*)",
},
},
extensions: []string{uni, corn}, extensions: []string{uni, corn},
versionRegex: "(?P<version>.*)",
version: universion,
enabledExtensions: []string{corn}, enabledExtensions: []string{corn},
enabledCommands: []string{"corn"},
version: universion,
displayVersion: true, displayVersion: true,
} }
lang := bootStrapLanguageTest(args) lang := bootStrapLanguageTest(args)
@ -166,13 +196,17 @@ func TestLanguageEnabledSecondCommand(t *testing.T) {
func TestLanguageEnabledAllExtensionsFound(t *testing.T) { func TestLanguageEnabledAllExtensionsFound(t *testing.T) {
args := &languageArgs{ args := &languageArgs{
versionParam: "--version", commands: []*cmd{
commands: []string{"unicorn"}, {
enabledCommands: []string{"unicorn"}, executable: "unicorn",
args: []string{"--version"},
regex: "(?P<version>.*)",
},
},
extensions: []string{uni, corn}, extensions: []string{uni, corn},
versionRegex: "(?P<version>.*)",
version: universion,
enabledExtensions: []string{uni, corn}, enabledExtensions: []string{uni, corn},
enabledCommands: []string{"unicorn"},
version: universion,
displayVersion: true, displayVersion: true,
} }
lang := bootStrapLanguageTest(args) lang := bootStrapLanguageTest(args)
@ -182,13 +216,17 @@ func TestLanguageEnabledAllExtensionsFound(t *testing.T) {
func TestLanguageEnabledNoVersion(t *testing.T) { func TestLanguageEnabledNoVersion(t *testing.T) {
args := &languageArgs{ args := &languageArgs{
versionParam: "--version", commands: []*cmd{
commands: []string{"unicorn"}, {
enabledCommands: []string{"unicorn"}, executable: "unicorn",
args: []string{"--version"},
regex: "(?P<version>.*)",
},
},
extensions: []string{uni, corn}, extensions: []string{uni, corn},
versionRegex: "(?P<version>.*)",
version: universion,
enabledExtensions: []string{uni, corn}, enabledExtensions: []string{uni, corn},
enabledCommands: []string{"unicorn"},
version: universion,
displayVersion: false, displayVersion: false,
} }
lang := bootStrapLanguageTest(args) lang := bootStrapLanguageTest(args)
@ -198,13 +236,11 @@ func TestLanguageEnabledNoVersion(t *testing.T) {
func TestLanguageEnabledMissingCommand(t *testing.T) { func TestLanguageEnabledMissingCommand(t *testing.T) {
args := &languageArgs{ args := &languageArgs{
versionParam: "--version", commands: []*cmd{},
commands: []string{""},
enabledCommands: []string{"unicorn"},
extensions: []string{uni, corn}, extensions: []string{uni, corn},
versionRegex: "(?P<version>.*)",
version: universion,
enabledExtensions: []string{uni, corn}, enabledExtensions: []string{uni, corn},
enabledCommands: []string{"unicorn"},
version: universion,
displayVersion: false, displayVersion: false,
} }
lang := bootStrapLanguageTest(args) lang := bootStrapLanguageTest(args)
@ -214,31 +250,61 @@ func TestLanguageEnabledMissingCommand(t *testing.T) {
func TestLanguageEnabledMissingCommandCustomText(t *testing.T) { func TestLanguageEnabledMissingCommandCustomText(t *testing.T) {
args := &languageArgs{ args := &languageArgs{
versionParam: "--version", commands: []*cmd{},
commands: []string{""},
enabledCommands: []string{"unicorn"},
extensions: []string{uni, corn}, extensions: []string{uni, corn},
versionRegex: "(?P<version>.*)",
version: universion,
enabledExtensions: []string{uni, corn}, enabledExtensions: []string{uni, corn},
displayVersion: true, enabledCommands: []string{"unicorn"},
version: universion,
missingCommandText: "missing", missingCommandText: "missing",
displayVersion: true,
} }
lang := bootStrapLanguageTest(args) lang := bootStrapLanguageTest(args)
assert.True(t, lang.enabled()) assert.True(t, lang.enabled())
assert.Equal(t, args.missingCommandText, lang.string(), "unicorn is available and uni and corn files are found") assert.Equal(t, args.missingCommandText, lang.string(), "unicorn is available and uni and corn files are found")
} }
func TestLanguageEnabledCommandExitCode(t *testing.T) {
expected := 200
args := &languageArgs{
commands: []*cmd{
{
executable: "uni",
args: []string{"--version"},
regex: `(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,
},
},
extensions: []string{uni, corn},
enabledExtensions: []string{uni, corn},
enabledCommands: []string{"uni"},
version: universion,
displayVersion: true,
expectedError: &commandError{exitCode: expected},
}
lang := bootStrapLanguageTest(args)
assert.True(t, lang.enabled())
assert.Equal(t, "err executing uni with [--version]", lang.string())
assert.Equal(t, expected, lang.exitCode)
}
func TestLanguageHyperlinkEnabled(t *testing.T) { func TestLanguageHyperlinkEnabled(t *testing.T) {
args := &languageArgs{ args := &languageArgs{
versionParam: "--version", commands: []*cmd{
commands: []string{"uni", "corn"}, {
enabledCommands: []string{"corn"}, executable: "uni",
args: []string{"--version"},
regex: `(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,
},
{
executable: "corn",
args: []string{"--version"},
regex: `(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,
},
},
versionURLTemplate: "[%s](https://unicor.org/doc/%s.%s.%s)",
extensions: []string{uni, corn}, extensions: []string{uni, corn},
versionRegex: `(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,
urlTemplate: "[%s](https://unicor.org/doc/%s.%s.%s)",
version: universion,
enabledExtensions: []string{corn}, enabledExtensions: []string{corn},
enabledCommands: []string{"corn"},
version: universion,
displayVersion: true, displayVersion: true,
enableHyperlink: true, enableHyperlink: true,
} }
@ -249,32 +315,50 @@ func TestLanguageHyperlinkEnabled(t *testing.T) {
func TestLanguageHyperlinkEnabledWrongRegex(t *testing.T) { func TestLanguageHyperlinkEnabledWrongRegex(t *testing.T) {
args := &languageArgs{ args := &languageArgs{
versionParam: "--version", commands: []*cmd{
commands: []string{"uni", "corn"}, {
enabledCommands: []string{"corn"}, executable: "uni",
args: []string{"--version"},
regex: `wrong`,
},
{
executable: "corn",
args: []string{"--version"},
regex: `wrong`,
},
},
versionURLTemplate: "[%s](https://unicor.org/doc/%s.%s.%s)",
extensions: []string{uni, corn}, extensions: []string{uni, corn},
versionRegex: `wrong`,
urlTemplate: "[%s](https://unicor.org/doc/%s.%s.%s)",
version: universion,
enabledExtensions: []string{corn}, enabledExtensions: []string{corn},
enabledCommands: []string{"corn"},
version: universion,
displayVersion: true, displayVersion: true,
enableHyperlink: true, enableHyperlink: true,
} }
lang := bootStrapLanguageTest(args) lang := bootStrapLanguageTest(args)
assert.True(t, lang.enabled()) assert.True(t, lang.enabled())
assert.Equal(t, "", lang.string()) assert.Equal(t, "err parsing info from corn with 1.3.307", lang.string())
} }
func TestLanguageHyperlinkEnabledLessParamInTemplate(t *testing.T) { func TestLanguageHyperlinkEnabledLessParamInTemplate(t *testing.T) {
args := &languageArgs{ args := &languageArgs{
versionParam: "--version", commands: []*cmd{
commands: []string{"uni", "corn"}, {
enabledCommands: []string{"corn"}, executable: "uni",
args: []string{"--version"},
regex: `(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,
},
{
executable: "corn",
args: []string{"--version"},
regex: `(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,
},
},
versionURLTemplate: "[%s](https://unicor.org/doc/%s)",
extensions: []string{uni, corn}, extensions: []string{uni, corn},
versionRegex: `(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,
urlTemplate: "[%s](https://unicor.org/doc/%s)",
version: universion,
enabledExtensions: []string{corn}, enabledExtensions: []string{corn},
enabledCommands: []string{"corn"},
version: universion,
displayVersion: true, displayVersion: true,
enableHyperlink: true, enableHyperlink: true,
} }
@ -285,14 +369,23 @@ func TestLanguageHyperlinkEnabledLessParamInTemplate(t *testing.T) {
func TestLanguageHyperlinkEnabledMoreParamInTemplate(t *testing.T) { func TestLanguageHyperlinkEnabledMoreParamInTemplate(t *testing.T) {
args := &languageArgs{ args := &languageArgs{
versionParam: "--version", commands: []*cmd{
commands: []string{"uni", "corn"}, {
enabledCommands: []string{"corn"}, executable: "uni",
args: []string{"--version"},
regex: `(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,
},
{
executable: "corn",
args: []string{"--version"},
regex: `(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,
},
},
versionURLTemplate: "[%s](https://unicor.org/doc/%s.%s.%s.%s)",
extensions: []string{uni, corn}, extensions: []string{uni, corn},
versionRegex: `(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,
urlTemplate: "[%s](https://unicor.org/doc/%s.%s.%s.%s)",
version: universion,
enabledExtensions: []string{corn}, enabledExtensions: []string{corn},
enabledCommands: []string{"corn"},
version: universion,
displayVersion: true, displayVersion: true,
enableHyperlink: true, enableHyperlink: true,
} }

View file

@ -12,13 +12,15 @@ func (n *node) init(props *properties, env environmentInfo) {
n.language = &language{ n.language = &language{
env: env, env: env,
props: props, props: props,
commands: []string{"node"},
versionParam: "--version",
extensions: []string{"*.js", "*.ts", "package.json"}, extensions: []string{"*.js", "*.ts", "package.json"},
version: &version{ commands: []*cmd{
{
executable: "node",
args: []string{"--version"},
regex: `(?:v(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`, regex: `(?:v(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,
urlTemplate: "[%[1]s](https://github.com/nodejs/node/blob/master/doc/changelogs/CHANGELOG_V%[2]s.md#%[1]s)",
}, },
},
versionURLTemplate: "[%[1]s](https://github.com/nodejs/node/blob/master/doc/changelogs/CHANGELOG_V%[2]s.md#%[1]s)",
} }
} }

View file

@ -29,15 +29,22 @@ func (p *python) init(props *properties, env environmentInfo) {
p.language = &language{ p.language = &language{
env: env, env: env,
props: props, props: props,
commands: []string{"python", "python3"},
versionParam: "--version",
extensions: []string{"*.py", "*.ipynb", "pyproject.toml", "venv.bak", "venv", ".venv"}, extensions: []string{"*.py", "*.ipynb", "pyproject.toml", "venv.bak", "venv", ".venv"},
loadContext: p.loadContext, loadContext: p.loadContext,
inContext: p.inContext, inContext: p.inContext,
version: &version{ commands: []*cmd{
{
executable: "python",
args: []string{"--version"},
regex: `(?:Python (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`, regex: `(?:Python (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,
urlTemplate: "[%s](https://www.python.org/downloads/release/python-%s%s%s/)",
}, },
{
executable: "python3",
args: []string{"--version"},
regex: `(?:Python (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,
},
},
versionURLTemplate: "[%s](https://www.python.org/downloads/release/python-%s%s%s/)",
} }
} }