diff options
| author | 2023-04-28 01:36:44 +0800 | |
|---|---|---|
| committer | 2023-04-28 01:36:44 +0800 | |
| commit | dd84b9d64fb98746a230cd24233ff50a562c39c9 (patch) | |
| tree | b583261ef00b3afe72ec4d6dacb31e57779a6faf /cli/internal/fs/package_json.go | |
| parent | 0b46fcd72ac34382387b2bcf9095233efbcc52f4 (diff) | |
| download | HydroRoll-dd84b9d64fb98746a230cd24233ff50a562c39c9.tar.gz HydroRoll-dd84b9d64fb98746a230cd24233ff50a562c39c9.zip | |
Diffstat (limited to 'cli/internal/fs/package_json.go')
| -rw-r--r-- | cli/internal/fs/package_json.go | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/cli/internal/fs/package_json.go b/cli/internal/fs/package_json.go new file mode 100644 index 0000000..883f7a4 --- /dev/null +++ b/cli/internal/fs/package_json.go @@ -0,0 +1,142 @@ +package fs + +import ( + "bytes" + "encoding/json" + "sync" + + "github.com/vercel/turbo/cli/internal/lockfile" + "github.com/vercel/turbo/cli/internal/turbopath" +) + +// PackageJSON represents NodeJS package.json +type PackageJSON struct { + Name string `json:"name"` + Version string `json:"version"` + Scripts map[string]string `json:"scripts"` + Dependencies map[string]string `json:"dependencies"` + DevDependencies map[string]string `json:"devDependencies"` + OptionalDependencies map[string]string `json:"optionalDependencies"` + PeerDependencies map[string]string `json:"peerDependencies"` + PackageManager string `json:"packageManager"` + Os []string `json:"os"` + Workspaces Workspaces `json:"workspaces"` + Private bool `json:"private"` + // Exact JSON object stored in package.json including unknown fields + // During marshalling struct fields will take priority over raw fields + RawJSON map[string]interface{} `json:"-"` + + // relative path from repo root to the package.json file + PackageJSONPath turbopath.AnchoredSystemPath `json:"-"` + // relative path from repo root to the package + Dir turbopath.AnchoredSystemPath `json:"-"` + InternalDeps []string `json:"-"` + UnresolvedExternalDeps map[string]string `json:"-"` + TransitiveDeps []lockfile.Package `json:"-"` + LegacyTurboConfig *TurboJSON `json:"turbo"` + Mu sync.Mutex `json:"-"` + ExternalDepsHash string `json:"-"` +} + +type Workspaces []string + +type WorkspacesAlt struct { + Packages []string `json:"packages,omitempty"` +} + +func (r *Workspaces) UnmarshalJSON(data []byte) error { + var tmp = &WorkspacesAlt{} + if err := json.Unmarshal(data, tmp); err == nil { + *r = Workspaces(tmp.Packages) + return nil + } + var tempstr = []string{} + if err := json.Unmarshal(data, &tempstr); err != nil { + return err + } + *r = tempstr + return nil +} + +// ReadPackageJSON returns a struct of package.json +func ReadPackageJSON(path turbopath.AbsoluteSystemPath) (*PackageJSON, error) { + b, err := path.ReadFile() + if err != nil { + return nil, err + } + return UnmarshalPackageJSON(b) +} + +// UnmarshalPackageJSON decodes a byte slice into a PackageJSON struct +func UnmarshalPackageJSON(data []byte) (*PackageJSON, error) { + var rawJSON map[string]interface{} + if err := json.Unmarshal(data, &rawJSON); err != nil { + return nil, err + } + + pkgJSON := &PackageJSON{} + if err := json.Unmarshal(data, &pkgJSON); err != nil { + return nil, err + } + pkgJSON.RawJSON = rawJSON + + return pkgJSON, nil +} + +// MarshalPackageJSON Serialize PackageJSON to a slice of bytes +func MarshalPackageJSON(pkgJSON *PackageJSON) ([]byte, error) { + structuredContent, err := json.Marshal(pkgJSON) + if err != nil { + return nil, err + } + var structuredFields map[string]interface{} + if err := json.Unmarshal(structuredContent, &structuredFields); err != nil { + return nil, err + } + + fieldsToSerialize := make(map[string]interface{}, len(pkgJSON.RawJSON)) + + // copy pkgJSON.RawJSON + for key, value := range pkgJSON.RawJSON { + fieldsToSerialize[key] = value + } + + for key, value := range structuredFields { + if isEmpty(value) { + delete(fieldsToSerialize, key) + } else { + fieldsToSerialize[key] = value + } + } + + var b bytes.Buffer + encoder := json.NewEncoder(&b) + encoder.SetEscapeHTML(false) + encoder.SetIndent("", " ") + if err := encoder.Encode(fieldsToSerialize); err != nil { + return nil, err + } + + return b.Bytes(), nil +} + +func isEmpty(value interface{}) bool { + if value == nil { + return true + } + switch s := value.(type) { + case string: + return s == "" + case bool: + return !s + case []string: + return len(s) == 0 + case map[string]interface{}: + return len(s) == 0 + case Workspaces: + return len(s) == 0 + default: + // Assume any unknown types aren't empty + return false + } +} |
