Skip to content

Commit a543af4

Browse files
committed
fix: review comment changes
1 parent 3726b80 commit a543af4

2 files changed

Lines changed: 329 additions & 104 deletions

File tree

internal/cli/quickstart_detect.go

Lines changed: 144 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ func DetectProject(dir string) DetectionResult {
3434
result := DetectionResult{
3535
AppName: filepath.Base(dir),
3636
}
37+
if name := readProjectName(dir); name != "" {
38+
result.AppName = name
39+
}
3740

3841
// ── 1. angular.json ─────────────────────────────────────────────────────
3942
if fileExists(dir, "angular.json") {
@@ -325,6 +328,143 @@ func readPackageJSONDeps(dir string) map[string]bool {
325328
return deps
326329
}
327330

331+
// readPackageJSONName reads the "name" field from package.json in dir.
332+
// Returns empty string if not found or on any error.
333+
func readPackageJSONName(dir string) string {
334+
data, err := os.ReadFile(filepath.Join(dir, "package.json"))
335+
if err != nil {
336+
return ""
337+
}
338+
var pkg struct {
339+
Name string `json:"name"`
340+
}
341+
if err := json.Unmarshal(data, &pkg); err != nil {
342+
return ""
343+
}
344+
return pkg.Name
345+
}
346+
347+
// readProjectName tries to extract a meaningful project name from language-specific
348+
// manifest files. It falls back to empty string if none are found; the caller then
349+
// uses filepath.Base(dir).
350+
func readProjectName(dir string) string {
351+
if name := readPackageJSONName(dir); name != "" {
352+
return name
353+
}
354+
if name := readGoModuleName(dir); name != "" {
355+
return name
356+
}
357+
if name := readPyprojectName(dir); name != "" {
358+
return name
359+
}
360+
if name := readPubspecName(dir); name != "" {
361+
return name
362+
}
363+
if name := readComposerName(dir); name != "" {
364+
return name
365+
}
366+
if name := readPomArtifactID(dir); name != "" {
367+
return name
368+
}
369+
return ""
370+
}
371+
372+
// readGoModuleName reads the module path from go.mod and returns its last path segment.
373+
func readGoModuleName(dir string) string {
374+
data, ok := readFileContent(dir, "go.mod")
375+
if !ok {
376+
return ""
377+
}
378+
for _, line := range strings.SplitN(data, "\n", 20) {
379+
line = strings.TrimSpace(line)
380+
if strings.HasPrefix(line, "module ") {
381+
modulePath := strings.TrimSpace(strings.TrimPrefix(line, "module "))
382+
return filepath.Base(modulePath)
383+
}
384+
}
385+
return ""
386+
}
387+
388+
// readPyprojectName reads the project name from pyproject.toml ([project] or [tool.poetry] section).
389+
func readPyprojectName(dir string) string {
390+
data, ok := readFileContent(dir, "pyproject.toml")
391+
if !ok {
392+
return ""
393+
}
394+
for _, line := range strings.Split(data, "\n") {
395+
line = strings.TrimSpace(line)
396+
if !strings.HasPrefix(line, "name ") && !strings.HasPrefix(line, "name=") {
397+
continue
398+
}
399+
parts := strings.SplitN(line, "=", 2)
400+
if len(parts) != 2 {
401+
continue
402+
}
403+
val := strings.TrimSpace(parts[1])
404+
val = strings.Trim(val, `"'`)
405+
if val != "" {
406+
return val
407+
}
408+
}
409+
return ""
410+
}
411+
412+
// readPubspecName reads the name field from pubspec.yaml.
413+
func readPubspecName(dir string) string {
414+
data, ok := readFileContent(dir, "pubspec.yaml")
415+
if !ok {
416+
return ""
417+
}
418+
for _, line := range strings.Split(data, "\n") {
419+
trimmed := strings.TrimSpace(line)
420+
if strings.HasPrefix(trimmed, "name:") {
421+
val := strings.TrimSpace(strings.TrimPrefix(trimmed, "name:"))
422+
if val != "" {
423+
return val
424+
}
425+
}
426+
}
427+
return ""
428+
}
429+
430+
// readComposerName reads the package name from composer.json and returns the part after "/".
431+
func readComposerName(dir string) string {
432+
data, err := os.ReadFile(filepath.Join(dir, "composer.json"))
433+
if err != nil {
434+
return ""
435+
}
436+
var pkg struct {
437+
Name string `json:"name"`
438+
}
439+
if err := json.Unmarshal(data, &pkg); err != nil || pkg.Name == "" {
440+
return ""
441+
}
442+
if idx := strings.LastIndex(pkg.Name, "/"); idx >= 0 {
443+
return pkg.Name[idx+1:]
444+
}
445+
return pkg.Name
446+
}
447+
448+
// readPomArtifactID reads the first <artifactId> value from pom.xml.
449+
func readPomArtifactID(dir string) string {
450+
data, ok := readFileContent(dir, "pom.xml")
451+
if !ok {
452+
return ""
453+
}
454+
const open = "<artifactId>"
455+
const close = "</artifactId>"
456+
start := strings.Index(data, open)
457+
if start == -1 {
458+
return ""
459+
}
460+
start += len(open)
461+
end := strings.Index(data[start:], close)
462+
if end == -1 {
463+
return ""
464+
}
465+
return strings.TrimSpace(data[start : start+end])
466+
}
467+
328468
// hasDep returns true if the named dependency is in the deps set.
329469
func hasDep(deps map[string]bool, name string) bool {
330470
return deps[name]
@@ -360,13 +500,13 @@ func findJavaBuildContent(dir string) (content, buildTool string, ok bool) {
360500
return "", "", false
361501
}
362502

363-
// friendlyAppType returns the human-readable label for an app type key.
364-
func friendlyAppType(qsType string) string {
503+
// detectionFriendlyAppType returns a concise label for the detection summary display.
504+
func detectionFriendlyAppType(qsType string) string {
365505
switch qsType {
366506
case "spa":
367-
return "Single Page App (SPA)"
507+
return "Single Page App"
368508
case "regular":
369-
return "Regular Web App / API / Backend"
509+
return "Regular Web App"
370510
case "native":
371511
return "Native / Mobile"
372512
case "m2m":

0 commit comments

Comments
 (0)