< Summary - Repometa Coverage

Information
Class: jsDetector
Assembly: repometa
File(s): /home/runner/work/repometa/repometa/detect_node.go
Line coverage
100%
Covered lines: 55
Uncovered lines: 0
Coverable lines: 55
Total lines: 135
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
detect0%00100%

File(s)

/home/runner/work/repometa/repometa/detect_node.go

#LineLine coverage
 1package repometa
 2
 3import (
 4  "encoding/json"
 5  "path/filepath"
 6
 7  "gopkg.in/yaml.v3"
 8)
 9
 10type jsDetector struct{}
 11
 12type packageJSON struct {
 13  Name            string            `json:"name"`
 14  Workspaces      json.RawMessage   `json:"workspaces"`
 15  Dependencies    map[string]string `json:"dependencies"`
 16  DevDependencies map[string]string `json:"devDependencies"`
 17}
 18
 19type pnpmWorkspaceYAML struct {
 20  Packages []string `yaml:"packages"`
 21}
 22
 8423func (jsDetector) detect(dv dirVisit, cfg options) []finding {
 7424  if !hasFile(dv.files, "package.json") {
 7425    return nil
 7426  }
 27
 1028  attrs := map[string]string{}
 1029  evidence := []Evidence{{Path: relJoin(dv.rel, "package.json"), Reason: "package.json at directory root"}}
 1030  var workspaces []Workspace
 1031  confidence := 1.0
 1032
 1033  data, err := readManifest(filepath.Join(dv.abs, "package.json"), cfg)
 1034  switch {
 135  case err != nil:
 136    confidence = confidenceUnreadable
 137    evidence = append(evidence, evidenceUnreadable(dv.rel, "package.json", err))
 938  default:
 939    var pkg packageJSON
 140    if uerr := json.Unmarshal(data, &pkg); uerr != nil {
 141      confidence = confidenceUnparsable
 142      evidence = append(evidence, evidenceUnparsable(dv.rel, "package.json", uerr))
 143      break
 44    }
 245    if fw := detectJSFramework(pkg); fw != "" {
 246      attrs["js.framework"] = fw
 247    }
 148    if members, ok := parseNpmYarnWorkspaces(pkg.Workspaces); ok {
 149      expanded := expandMembers(dv.abs, members, dv.rel)
 150      workspaces = append(workspaces, Workspace{Kind: WorkspaceNpmYarn, Members: expanded})
 151      evidence = append(evidence, Evidence{
 152        Path: relJoin(dv.rel, "package.json"), Reason: `package.json "workspaces" declared`,
 153      })
 154    }
 55  }
 56
 157  if hasFile(dv.files, "pnpm-workspace.yaml") {
 158    members := parsePnpmWorkspace(filepath.Join(dv.abs, "pnpm-workspace.yaml"), cfg)
 159    expanded := expandMembers(dv.abs, members, dv.rel)
 160    workspaces = append(workspaces, Workspace{Kind: WorkspacePnpm, Members: expanded})
 161    evidence = append(evidence, Evidence{Path: relJoin(dv.rel, "pnpm-workspace.yaml"), Reason: "pnpm-workspace.yaml pres
 162  }
 163  if hasFile(dv.files, "nx.json") {
 164    workspaces = append(workspaces, Workspace{Kind: WorkspaceNx})
 165    evidence = append(evidence, Evidence{Path: relJoin(dv.rel, "nx.json"), Reason: "nx.json present"})
 166  }
 167  if hasFile(dv.files, "turbo.json") {
 168    workspaces = append(workspaces, Workspace{Kind: WorkspaceTurborepo})
 169    evidence = append(evidence, Evidence{Path: relJoin(dv.rel, "turbo.json"), Reason: "turbo.json present"})
 170  }
 71
 72  // Angular's canonical marker is angular.json, which may exist even
 73  // without @angular/core being an obvious dependency line.
 174  if hasFile(dv.files, "angular.json") {
 175    attrs["js.framework"] = "angular"
 176    evidence = append(evidence, Evidence{Path: relJoin(dv.rel, "angular.json"), Reason: "angular.json present"})
 177  }
 78
 1079  return []finding{{
 1080    Kind:       KindNodePackage,
 1081    Confidence: confidence,
 1082    Evidence:   evidence,
 1083    Workspaces: workspaces,
 1084    Attributes: attrs,
 1085  }}
 86}
 87
 88func detectJSFramework(pkg packageJSON) string {
 89  if _, ok := pkg.Dependencies["next"]; ok {
 90    return "nextjs"
 91  }
 92  if _, ok := pkg.DevDependencies["next"]; ok {
 93    return "nextjs"
 94  }
 95  if _, ok := pkg.Dependencies["@angular/core"]; ok {
 96    return "angular"
 97  }
 98  if _, ok := pkg.DevDependencies["@angular/core"]; ok {
 99    return "angular"
 100  }
 101  return ""
 102}
 103
 104// parseNpmYarnWorkspaces handles both shapes:
 105//
 106//  "workspaces": ["packages/*"]
 107//  "workspaces": {"packages": ["packages/*"], "nohoist": [...]}
 108func parseNpmYarnWorkspaces(raw json.RawMessage) ([]string, bool) {
 109  if len(raw) == 0 {
 110    return nil, false
 111  }
 112  var arr []string
 113  if err := json.Unmarshal(raw, &arr); err == nil {
 114    return arr, true
 115  }
 116  var obj struct {
 117    Packages []string `json:"packages"`
 118  }
 119  if err := json.Unmarshal(raw, &obj); err == nil {
 120    return obj.Packages, true
 121  }
 122  return nil, false
 123}
 124
 125func parsePnpmWorkspace(path string, cfg options) []string {
 126  data := readManifestOrNil(path, cfg)
 127  if data == nil {
 128    return nil
 129  }
 130  var ws pnpmWorkspaceYAML
 131  if err := yaml.Unmarshal(data, &ws); err != nil {
 132    return nil
 133  }
 134  return ws.Packages
 135}

Methods/Properties

detect