Files
pack/core/providers/node/package_json.go
T
Michael BiancoandGitHub f672eb2f54 feat(node): support TanStack Start builds (#672)
* feat: add generation script for latest tanstack example

Generated-by: aiautocommit

* test(examples): add tanstack-latest example project setup

Generated-by: aiautocommit

* feat(node): add helper methods to check production and dev dependencies

Generated-by: aiautocommit

* feat(logger): support absolute URLs in DocsURL and suggestions

Generated-by: aiautocommit

* feat(node): exclude TanStack Start packages from Vite static build

Generated-by: aiautocommit

* feat(node): add support for TanStack Start srvx fallback

Generated-by: aiautocommit

* test(core): update test snapshots for TanStack build plan

Generated-by: aiautocommit

* docs(node): document TanStack Start detection and build behavior

Generated-by: aiautocommit

* feat(node): add TanStack Start framework support and fallback server

Generated-by: aiautocommit
2026-08-02 06:09:11 -06:00

124 lines
3.0 KiB
Go

package node
import (
"encoding/json"
"maps"
"strings"
)
type WorkspacesConfig struct {
Packages []string `json:"packages"`
}
type PackageJson struct {
Name string `json:"name"`
Version string `json:"version"`
Scripts map[string]string `json:"scripts"`
PackageManager *string `json:"packageManager"`
Dependencies map[string]string `json:"dependencies"`
DevDependencies map[string]string `json:"devDependencies"`
Engines map[string]string `json:"engines"`
Main string `json:"main"`
Workspaces []string `json:"-"`
}
func NewPackageJson() *PackageJson {
return &PackageJson{
Scripts: map[string]string{},
Engines: map[string]string{},
Workspaces: []string{},
}
}
func (p *PackageJson) HasScript(name string) bool {
return p.Scripts != nil && p.Scripts[name] != ""
}
func (p *PackageJson) GetScript(name string) string {
if p.Scripts == nil {
return ""
}
return p.Scripts[name]
}
func (p *PackageJson) BuildScriptContains(value string) bool {
return strings.Contains(p.GetScript("build"), value)
}
func (p *PackageJson) hasDependency(dependency string) bool {
return p.hasProductionDependency(dependency) || p.hasDevDependency(dependency)
}
// is there a dependency that requires the entire app to be loaded into the context
func (p *PackageJson) hasLocalDependency() bool {
allDeps := make(map[string]string)
maps.Copy(allDeps, p.Dependencies)
maps.Copy(allDeps, p.DevDependencies)
for _, dependency := range allDeps {
if strings.HasPrefix(dependency, "file:") {
return true
}
}
return false
}
// parse a packageManager string in the format "name@version" or "name@version+extra".
// Returns the package manager name and version as separate strings.
// returns empty strings for both name and version if it can't be parsed
func (p *PackageJson) GetPackageManagerInfo() (string, string) {
if p == nil || p.PackageManager == nil {
return "", ""
}
pmString := strings.TrimSpace(*p.PackageManager)
parts := strings.Split(pmString, "@")
if len(parts) == 2 {
versionParts := strings.Split(parts[1], "+")
return strings.TrimSpace(parts[0]), strings.TrimSpace(versionParts[0])
}
return "", ""
}
func (p *PackageJson) UnmarshalJSON(data []byte) error {
type WorkspacesObject struct {
Packages []string `json:"packages"`
}
type Alias PackageJson
aux := &struct {
*Alias
Workspaces any `json:"workspaces"`
}{
Alias: (*Alias)(p),
}
if err := json.Unmarshal(data, aux); err != nil {
return err
}
// Handle workspaces field based on its type
switch w := aux.Workspaces.(type) {
case []any:
p.Workspaces = make([]string, len(w))
for i, v := range w {
if s, ok := v.(string); ok {
p.Workspaces[i] = s
}
}
case map[string]any:
// Try to unmarshal as WorkspacesObject
var wo WorkspacesObject
if b, err := json.Marshal(w); err == nil {
if err := json.Unmarshal(b, &wo); err == nil {
p.Workspaces = wo.Packages
}
}
}
return nil
}