Files
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

113 lines
3.4 KiB
Go

package contracts
import (
"fmt"
"strings"
"github.com/zzet/gortex/internal/graph"
"github.com/zzet/gortex/internal/parser"
)
// Play Framework conf/routes extraction. A Play app declares its HTTP routes
// in an extensionless `conf/routes` file (and per-module `*.routes` includes),
// one route per line:
//
// GET /users controllers.UserController.list()
// POST /users/:id controllers.UserController.update(id: Long)
//
// This pass parses each verb line into a route Contract and stamps the
// controller class + method so the module-wide cross-file pass binds it to the
// Scala/Java handler. `#` comments, `->` sub-router includes, and `+modifier`
// lines emit no routes (matching Play's own routes grammar).
// playRouteVerbs is the set of HTTP verbs a Play route line may start with.
var playRouteVerbs = map[string]bool{
"GET": true, "POST": true, "PUT": true, "DELETE": true,
"PATCH": true, "HEAD": true, "OPTIONS": true,
}
// extractPlayRoutes parses a Play conf/routes file into route Contracts.
func (h *HTTPExtractor) extractPlayRoutes(filePath, text string, lines []string, fileNodes []*graph.Node, lang string, tree *parser.ParseTree) []Contract {
var out []Contract
for i, raw := range lines {
line := strings.TrimSpace(raw)
// Comments, sub-router includes, and route modifiers are not routes.
if line == "" || strings.HasPrefix(line, "#") || strings.HasPrefix(line, "->") || strings.HasPrefix(line, "+") {
continue
}
fields := strings.Fields(line)
if len(fields) < 3 {
continue
}
verb := strings.ToUpper(fields[0])
if !playRouteVerbs[verb] {
continue
}
path := fields[1]
if !strings.HasPrefix(path, "/") {
continue
}
fqcn, hclass, hident := playHandlerRef(fields[2])
if hident == "" {
continue
}
normPath, origNames := NormalizeHTTPPathWithParams(path)
c := Contract{
ID: fmt.Sprintf("http::%s::%s", verb, normPath),
Type: ContractHTTP,
Role: RoleProvider,
FilePath: filePath,
Line: i + 1,
Confidence: 0.85,
Meta: map[string]any{
"method": verb,
"path": normPath,
"framework": "play",
},
}
if len(origNames) > 0 {
c.Meta["path_param_names"] = origNames
}
if fqcn != "" {
c.Meta["handler_fqcn"] = fqcn
}
if hclass != "" {
c.Meta["handler_class"] = hclass
}
c.Meta["handler_ident"] = hident
if id := findMethodByNameAndReceiver(fileNodes, hident, hclass); id != "" {
c.SymbolID = id
}
EnrichHTTPContractWithTree(&c, lines, fileNodes, lang, tree)
out = append(out, c)
}
return out
}
// playHandlerRef parses a Play route handler reference
// `controllers.UserController.list(id: Long)` into its qualified class
// (`controllers.UserController`), simple class (`UserController`), and method
// (`list`). A leading `@` (dependency-injected routing) is tolerated. Returns
// empty strings when the reference has no `Class.method` shape.
func playHandlerRef(ref string) (fqcn, hclass, hident string) {
ref = strings.TrimSpace(strings.TrimPrefix(strings.TrimSpace(ref), "@"))
if i := strings.IndexByte(ref, '('); i >= 0 {
ref = ref[:i]
}
ref = strings.TrimSpace(ref)
i := strings.LastIndex(ref, ".")
if i < 0 {
return "", "", ""
}
method := ref[i+1:]
cls := ref[:i]
if method == "" || cls == "" {
return "", "", ""
}
simple := cls
if j := strings.LastIndex(cls, "."); j >= 0 {
simple = cls[j+1:]
}
return cls, simple, method
}