summaryrefslogtreecommitdiff
path: root/runner
diff options
context:
space:
mode:
authorewy <ewy0@protonmail.com>2026-05-02 18:28:40 +0200
committerewy <ewy0@protonmail.com>2026-05-02 18:28:40 +0200
commite8b9ca135642c76000bc0ec2e78674c602a748dd (patch)
tree4e502ce767a4a4f70e40d6e72a3817bc139f1300 /runner
parent35e6ac334f6a62cf63b743182cd5355f6baf4406 (diff)
add .js and .ts support
also: remove unused/duplicate method runner.Hydrate
Diffstat (limited to 'runner')
-rw-r--r--runner/exc/runner.go8
-rw-r--r--runner/js/indexer.go39
-rw-r--r--runner/js/js.go106
-rw-r--r--runner/js/runner.go28
-rw-r--r--runner/js/target_npm.go42
-rw-r--r--runner/js/target_script.go55
-rw-r--r--runner/python/runner.go5
-rw-r--r--runner/shell/hydrated.go14
-rw-r--r--runner/shell/target.go4
9 files changed, 274 insertions, 27 deletions
diff --git a/runner/exc/runner.go b/runner/exc/runner.go
index 092fd80..2eae44c 100644
--- a/runner/exc/runner.go
+++ b/runner/exc/runner.go
@@ -9,14 +9,6 @@ import (
"path/filepath"
)
-func (e *exc) Hydrate(target model.Target) (model.HydratedTarget, error) {
- return &Hydrated{
- BaseHydration: &runner.BaseHydration[*Executable]{
- Self: target.(*Executable),
- },
- }, nil
-}
-
func (e *exc) Wants(fs fs.FS, file string, entry fs.DirEntry) (bool, error) {
if entry.IsDir() {
return false, nil
diff --git a/runner/js/indexer.go b/runner/js/indexer.go
new file mode 100644
index 0000000..8a2a6b2
--- /dev/null
+++ b/runner/js/indexer.go
@@ -0,0 +1,39 @@
+package js
+
+import (
+ "encoding/json"
+ "errors"
+ "github.com/ewy1/pik/model"
+ "io/fs"
+ "os"
+ "path/filepath"
+)
+
+type Package struct {
+ Scripts map[string]string `json:"scripts"`
+}
+
+func (n *js) Index(path string, f fs.FS, runners []model.Runner) ([]model.Target, error) {
+ p := &Package{}
+ // are there any other package.jsons? i hope not, because i don't know them
+ content, err := os.ReadFile(filepath.Join(path, "package.json"))
+ if errors.Is(err, fs.ErrNotExist) {
+ return nil, nil
+ } else if err != nil {
+ return nil, err
+ }
+ err = json.Unmarshal(content, p)
+ if err != nil {
+ return nil, err
+ }
+
+ var targets []model.Target
+ if n.Npm == "" {
+ return nil, NoNpm
+ }
+ for k, s := range p.Scripts {
+ targets = append(targets, n.CreateRun(k, s))
+ }
+
+ return targets, nil
+}
diff --git a/runner/js/js.go b/runner/js/js.go
new file mode 100644
index 0000000..7c2af58
--- /dev/null
+++ b/runner/js/js.go
@@ -0,0 +1,106 @@
+package js
+
+import (
+ "errors"
+ "github.com/ewy1/pik/identity"
+ "github.com/ewy1/pik/model"
+ "github.com/ewy1/pik/runner"
+ "os/exec"
+ "path/filepath"
+ "slices"
+)
+
+var jsExtensions = []string{
+ ".js",
+ ".cjs",
+}
+
+var tsExtensions = []string{
+ ".ts",
+}
+
+var extensions = append(jsExtensions, tsExtensions...)
+
+var managers = []string{
+ "pnpm",
+ "yarn",
+ "npm",
+}
+
+var jsInterpreters = []string{
+ "node",
+ "bun",
+}
+
+var tsInterpeters = []string{
+ "ts",
+ "ts-node",
+ "bun",
+}
+
+type js struct {
+ JsInterpreter string
+ TsInterpreter string
+ Npm string
+}
+
+var Js = &js{}
+
+var UnsupportedFile = errors.New("unsupported file")
+var NoJsInterpreter = errors.New("no js interpreter found in $PATH")
+var NoTsInterpreter = errors.New("no ts interpreter found in $PATH")
+var NoNpm = errors.New("npm not found in $PATH")
+
+func (n *js) Interpreter(file string) (string, error) {
+ ext := filepath.Ext(file)
+ if slices.Contains(jsInterpreters, ext) {
+ if n.JsInterpreter == "" {
+ return "", NoJsInterpreter
+ }
+ return n.JsInterpreter, nil
+ }
+ if slices.Contains(tsInterpeters, ext) {
+ if n.TsInterpreter == "" {
+ return "", NoTsInterpreter
+ }
+ return n.TsInterpreter, nil
+ }
+ return "", UnsupportedFile
+}
+
+func (n *js) Init() error {
+ for _, p := range jsInterpreters {
+ if r, err := exec.LookPath(p); err != nil {
+ n.JsInterpreter = r
+ }
+ }
+ for _, p := range tsInterpeters {
+ if r, err := exec.LookPath(p); err != nil {
+ n.TsInterpreter = r
+ }
+ }
+
+ for _, m := range managers {
+ if r, err := exec.LookPath(m); err == nil {
+ n.Npm = r
+ }
+ }
+
+ return nil
+}
+
+var npmSub = []string{
+ "npm",
+}
+
+func (n *js) CreateRun(name, cmd string) model.Target {
+ return &Npm{
+ BaseTarget: runner.BaseTarget{
+ Identity: identity.New(cmd),
+ MyTags: model.TagsFromFilename(cmd),
+ MySub: npmSub,
+ },
+ Name: name,
+ Cmd: cmd,
+ }
+}
diff --git a/runner/js/runner.go b/runner/js/runner.go
new file mode 100644
index 0000000..8b5f4f1
--- /dev/null
+++ b/runner/js/runner.go
@@ -0,0 +1,28 @@
+package js
+
+import (
+ "github.com/ewy1/pik/identity"
+ "github.com/ewy1/pik/model"
+ "github.com/ewy1/pik/runner"
+ "io/fs"
+ "path/filepath"
+ "slices"
+)
+
+func (n *js) Wants(fs fs.FS, file string, entry fs.DirEntry) (bool, error) {
+ ext := filepath.Ext(entry.Name())
+ return slices.Contains(extensions, ext), nil
+}
+
+func (n *js) CreateTarget(fs fs.FS, source string, file string, entry fs.DirEntry) (model.Target, error) {
+ ext := filepath.Ext(entry.Name())
+ typed := slices.Contains(tsExtensions, ext)
+ return &Script{
+ BaseTarget: runner.BaseTarget{
+ Identity: identity.New(entry.Name()),
+ MyTags: model.TagsFromFilename(entry.Name()),
+ MySub: runner.SubFromFile(file),
+ },
+ Typed: typed,
+ }, nil
+}
diff --git a/runner/js/target_npm.go b/runner/js/target_npm.go
new file mode 100644
index 0000000..8319fad
--- /dev/null
+++ b/runner/js/target_npm.go
@@ -0,0 +1,42 @@
+package js
+
+import (
+ "github.com/ewy1/pik/model"
+ "github.com/ewy1/pik/runner"
+ "os/exec"
+ "path/filepath"
+)
+
+type Npm struct {
+ runner.BaseTarget
+ Name string
+ Cmd string
+}
+
+func (n *Npm) Icon() string {
+ return "\uE60B"
+}
+
+func (n *Npm) Description(src *model.HydratedSource) string {
+ return n.Cmd
+}
+
+func (n *Npm) Target() model.Target {
+ return n
+}
+
+func (n *Npm) Create(s *model.Source) *exec.Cmd {
+ return exec.Command(Js.Npm, "run", n.Name)
+}
+
+func (n *Npm) Label() string {
+ return n.Name
+}
+
+func (n *Npm) Hydrate(src *model.Source) (model.HydratedTarget, error) {
+ return n, nil
+}
+
+func (n *Npm) File(src *model.Source) string {
+ return filepath.Join(src.Path, "package.json")
+}
diff --git a/runner/js/target_script.go b/runner/js/target_script.go
new file mode 100644
index 0000000..6ad213d
--- /dev/null
+++ b/runner/js/target_script.go
@@ -0,0 +1,55 @@
+package js
+
+import (
+ "github.com/ewy1/pik/describe"
+ "github.com/ewy1/pik/model"
+ "github.com/ewy1/pik/runner"
+ "github.com/ewy1/pik/spool"
+ "os/exec"
+ "path/filepath"
+)
+
+type Script struct {
+ runner.BaseTarget
+ Typed bool
+}
+
+func (t *Script) Icon() string {
+ if t.Typed {
+ return "\uE628"
+ } else {
+ return "\uE60C"
+ }
+}
+
+func (t *Script) Description(src *model.HydratedSource) string {
+ d, err := describe.Describe(t, t.File(src.Source))
+ if err != nil {
+ _, _ = spool.Warn("%v\n", err)
+ }
+ return d
+}
+
+func (t *Script) Target() model.Target {
+ return t
+}
+
+func (t *Script) Create(s *model.Source) *exec.Cmd {
+ if t.Typed {
+ return exec.Command(Js.TsInterpreter, t.File(s))
+ } else {
+ return exec.Command(Js.JsInterpreter, t.File(s))
+ }
+}
+
+func (t *Script) Label() string {
+ return t.Identity.Full
+}
+
+func (t *Script) Hydrate(src *model.Source) (model.HydratedTarget, error) {
+ return t, nil
+}
+
+func (t *Script) File(src *model.Source) string {
+ return filepath.Join(src.Path, "package.json")
+}
diff --git a/runner/python/runner.go b/runner/python/runner.go
index 6aa6017..8d03f52 100644
--- a/runner/python/runner.go
+++ b/runner/python/runner.go
@@ -30,11 +30,6 @@ func (p python) Init() error {
return err
}
-func (p python) Hydrate(target model.Target) (model.HydratedTarget, error) {
- //TODO implement me
- panic("implement me")
-}
-
func (p python) Wants(fs fs.FS, file string, entry fs.DirEntry) (bool, error) {
return !entry.IsDir() && filepath.Ext(entry.Name()) == ".py", nil
}
diff --git a/runner/shell/hydrated.go b/runner/shell/hydrated.go
index fec74f1..440d9cd 100644
--- a/runner/shell/hydrated.go
+++ b/runner/shell/hydrated.go
@@ -1,7 +1,6 @@
package shell
import (
- "errors"
"github.com/ewy1/pik/describe"
"github.com/ewy1/pik/model"
"github.com/ewy1/pik/runner"
@@ -19,19 +18,8 @@ func (h *Hydrated) Icon() string {
func (h *Hydrated) Description(src *model.HydratedSource) string {
desc, err := describe.Describe(h.Target(), h.Target().File(src.Source))
if err != nil {
- spool.Warn("%v\n", err)
+ _, _ = spool.Warn("%v\n", err)
return ""
}
return desc
}
-
-var WrongTargetError = errors.New("wrong target type")
-
-func (s *shell) Hydrate(target model.Target) (model.HydratedTarget, error) {
- cast, ok := target.(*Target)
- if !ok {
- return nil, WrongTargetError
- }
- hyd := &Hydrated{BaseHydration: runner.Hydrated(cast)}
- return hyd, nil
-}
diff --git a/runner/shell/target.go b/runner/shell/target.go
index 49f7a18..d1262af 100644
--- a/runner/shell/target.go
+++ b/runner/shell/target.go
@@ -21,7 +21,9 @@ func (s *Target) String() string {
}
func (s *Target) Hydrate(_ *model.Source) (model.HydratedTarget, error) {
- return Runner.Hydrate(s)
+ return &Hydrated{
+ BaseHydration: runner.Hydrated(s),
+ }, nil
}
func (s *Target) Sub() []string {