mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
This pull request upgrades the GoFrame framework and all related dependencies from version `v2.9.8` (and similar) to `v2.10.0` across the codebase. It also refactors the `.make_version.sh` script to improve cross-platform compatibility when editing files, and ensures documentation reflects the new version. These changes help keep the project up-to-date and simplify version management. **Dependency upgrades:** * Updated all `go.mod` files in the main repo and contrib modules to require `github.com/gogf/gf/v2 v2.10.0` (replacing `v2.9.8` and similar) for consistency and latest features/bugfixes. [[1]](diffhunk://#diff-ee0abb9c50b9f91f424349123e31b7b1ba1e1e4f7497250422696c5bda2e74ceL6-R12) [[2]](diffhunk://#diff-cef597d401b6dad225f9e2e431bdde7e53cb60bdf287624cef38a6a7bb9ae7a3L7-R7) [[3]](diffhunk://#diff-970f7eacff9cd97a0d8a00d59ea8041eedaa21c7544c6669aaa58ca692c6b274L6-R6) [[4]](diffhunk://#diff-c23d0ca80cd6588b7df84de8ef84713f0ce0555ba05d2d9e7f5d1e0324b1ed3aL6-R6) [[5]](diffhunk://#diff-aa230a2b1198e6ef8afeb7f48335eb2e2f51d87d918d63c4d891fea612d18ff0L6-R6) [[6]](diffhunk://#diff-86c2390edbede20803cd862908fe95e7207f7dbabd5089ddd4838e1f26e7fecaL6-R6) [[7]](diffhunk://#diff-5e1af33d38ced461fc0e13981d7051e125876d1692efc3aa9cb4b7faa4c18addL7-R7) [[8]](diffhunk://#diff-8c6247829130f219981483ccf25af699a63de99afedeb0dd5c1b7bd8ff0919bdL9-R9) [[9]](diffhunk://#diff-accbd2d37d45e51db3fcb0468043b1e1fd53eeac9e3d3558467ef24444188d2fL7-R7) [[10]](diffhunk://#diff-15fac9b8e76d2782594c91da72f6a6f42fc18e359c3be35bf6564ac3ca09f700L6-R7) [[11]](diffhunk://#diff-8e1a76afd564b6073aac7b02ca59f296ae45a24da3dc4d5c40f18169f48ceba1L6-R6) [[12]](diffhunk://#diff-00a9db26966c21305c72e8f659628dffaff0d6e9dc98a751406d2141d51a5d90L7-R7) [[13]](diffhunk://#diff-2cbf2f66d5cb77d9f4d00e4c0ce45055620fff50c941a588da31729f09a81f1bL6-R7) [[14]](diffhunk://#diff-20a21d07addeea398c4adb76d077875894a73b4b5b181b9df1fafe497d3fc843L6-R6) [[15]](diffhunk://#diff-909670f1c29b0bba24faf1420504b9eacdff124c4cbbec1ddec5de60653ad007L6-R6) [[16]](diffhunk://#diff-8eef5f0c081743f8002e0faba686e838b323cb53b749706ea42e0440aaa793f1L7-R7) [[17]](diffhunk://#diff-82345842a29e8eaffa4f51aab96fa2aa78597e6639fe4b0ece797bc60edacea8L6-R6) **Script improvements:** * Refactored `.make_version.sh` to use a new `sed_inplace` function for in-place file editing, improving cross-platform support (Linux/macOS) and removing reliance on a global variable for the sed command. * Updated `.make_version.sh` to use `sed_inplace` consistently for version replacement and dependency cleanup steps, ensuring robust file modification regardless of OS. [[1]](diffhunk://#diff-546db9206ba1b7973e6187a1025b3904a0b08681d40d0ee4767082040fd0f661L46-R47) [[2]](diffhunk://#diff-546db9206ba1b7973e6187a1025b3904a0b08681d40d0ee4767082040fd0f661L84-R97) * Added a step in `.make_version.sh` to insert local development replace directives for Go modules, streamlining local testing and development. **Documentation updates:** * Updated contributor badge version in `README.MD` and `README.zh_CN.MD` to reflect the new GoFrame version (`v2.10.0`). [[1]](diffhunk://#diff-01e6d9ffed056a02cae8d8a0ec5d476a64d017bf85c0d5a94bb23ca21f33f5aaL48-R48) [[2]](diffhunk://#diff-c93759cb9a9500f20e551c741eb167fc72825fd638d36121357feb8253ce6ac1L48-R48)
380 lines
9.9 KiB
Go
380 lines
9.9 KiB
Go
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
|
//
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
// If a copy of the MIT was not distributed with this file,
|
|
// You can obtain one at https://github.com/gogf/gf.
|
|
|
|
package gjson
|
|
|
|
import (
|
|
"bytes"
|
|
|
|
"github.com/gogf/gf/v2/encoding/gini"
|
|
"github.com/gogf/gf/v2/encoding/gproperties"
|
|
"github.com/gogf/gf/v2/encoding/gtoml"
|
|
"github.com/gogf/gf/v2/encoding/gxml"
|
|
"github.com/gogf/gf/v2/encoding/gyaml"
|
|
"github.com/gogf/gf/v2/errors/gcode"
|
|
"github.com/gogf/gf/v2/errors/gerror"
|
|
"github.com/gogf/gf/v2/internal/json"
|
|
"github.com/gogf/gf/v2/text/gregex"
|
|
"github.com/gogf/gf/v2/text/gstr"
|
|
)
|
|
|
|
// LoadWithOptions creates a Json object from given JSON format content and options.
|
|
func LoadWithOptions(data []byte, options Options) (*Json, error) {
|
|
return loadContentWithOptions(data, options)
|
|
}
|
|
|
|
// LoadJson creates a Json object from given JSON format content.
|
|
func LoadJson(data []byte, safe ...bool) (*Json, error) {
|
|
var option = Options{
|
|
Type: ContentTypeJSON,
|
|
}
|
|
if len(safe) > 0 && safe[0] {
|
|
option.Safe = true
|
|
}
|
|
return loadContentWithOptions(data, option)
|
|
}
|
|
|
|
// LoadXml creates a Json object from given XML format content.
|
|
func LoadXml(data []byte, safe ...bool) (*Json, error) {
|
|
var option = Options{
|
|
Type: ContentTypeXML,
|
|
}
|
|
if len(safe) > 0 && safe[0] {
|
|
option.Safe = true
|
|
}
|
|
return loadContentWithOptions(data, option)
|
|
}
|
|
|
|
// LoadIni creates a Json object from given INI format content.
|
|
func LoadIni(data []byte, safe ...bool) (*Json, error) {
|
|
var option = Options{
|
|
Type: ContentTypeIni,
|
|
}
|
|
if len(safe) > 0 && safe[0] {
|
|
option.Safe = true
|
|
}
|
|
return loadContentWithOptions(data, option)
|
|
}
|
|
|
|
// LoadYaml creates a Json object from given YAML format content.
|
|
func LoadYaml(data []byte, safe ...bool) (*Json, error) {
|
|
var option = Options{
|
|
Type: ContentTypeYaml,
|
|
}
|
|
if len(safe) > 0 && safe[0] {
|
|
option.Safe = true
|
|
}
|
|
return loadContentWithOptions(data, option)
|
|
}
|
|
|
|
// LoadToml creates a Json object from given TOML format content.
|
|
func LoadToml(data []byte, safe ...bool) (*Json, error) {
|
|
var option = Options{
|
|
Type: ContentTypeToml,
|
|
}
|
|
if len(safe) > 0 && safe[0] {
|
|
option.Safe = true
|
|
}
|
|
return loadContentWithOptions(data, option)
|
|
}
|
|
|
|
// LoadProperties creates a Json object from given TOML format content.
|
|
func LoadProperties(data []byte, safe ...bool) (*Json, error) {
|
|
var option = Options{
|
|
Type: ContentTypeProperties,
|
|
}
|
|
if len(safe) > 0 && safe[0] {
|
|
option.Safe = true
|
|
}
|
|
return loadContentWithOptions(data, option)
|
|
}
|
|
|
|
// LoadContent creates a Json object from given content, it checks the data type of `content`
|
|
// automatically, supporting data content type as follows:
|
|
// JSON, XML, INI, YAML and TOML.
|
|
func LoadContent(data []byte, safe ...bool) (*Json, error) {
|
|
return LoadContentType("", data, safe...)
|
|
}
|
|
|
|
// LoadContentType creates a Json object from given type and content,
|
|
// supporting data content type as follows:
|
|
// JSON, XML, INI, YAML and TOML.
|
|
func LoadContentType(dataType ContentType, data []byte, safe ...bool) (*Json, error) {
|
|
if len(data) == 0 {
|
|
return New(nil, safe...), nil
|
|
}
|
|
var options = Options{
|
|
Type: dataType,
|
|
StrNumber: true,
|
|
}
|
|
if len(safe) > 0 && safe[0] {
|
|
options.Safe = true
|
|
}
|
|
return loadContentWithOptions(data, options)
|
|
}
|
|
|
|
// IsValidDataType checks and returns whether given `dataType` a valid data type for loading.
|
|
func IsValidDataType(dataType ContentType) bool {
|
|
if dataType == "" {
|
|
return false
|
|
}
|
|
if dataType[0] == '.' {
|
|
dataType = dataType[1:]
|
|
}
|
|
switch dataType {
|
|
case
|
|
ContentTypeJSON,
|
|
ContentTypeJs,
|
|
ContentTypeXML,
|
|
ContentTypeYaml,
|
|
ContentTypeYml,
|
|
ContentTypeToml,
|
|
ContentTypeIni,
|
|
ContentTypeProperties:
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func trimBOM(data []byte) []byte {
|
|
if len(data) < 3 {
|
|
return data
|
|
}
|
|
if data[0] == 0xEF && data[1] == 0xBB && data[2] == 0xBF {
|
|
data = data[3:]
|
|
}
|
|
return data
|
|
}
|
|
|
|
// loadContentWithOptions creates a Json object from given content.
|
|
// It supports data content type as follows:
|
|
// JSON, XML, INI, YAML and TOML.
|
|
func loadContentWithOptions(data []byte, options Options) (*Json, error) {
|
|
var (
|
|
err error
|
|
result any
|
|
)
|
|
data = trimBOM(data)
|
|
if len(data) == 0 {
|
|
return NewWithOptions(nil, options), nil
|
|
}
|
|
var (
|
|
checkType ContentType
|
|
decodedData any
|
|
)
|
|
if options.Type != "" {
|
|
checkType = gstr.TrimLeft(options.Type, ".")
|
|
} else {
|
|
checkType, err = checkDataType(data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
switch checkType {
|
|
case ContentTypeJSON, ContentTypeJs:
|
|
decoder := json.NewDecoder(bytes.NewReader(data))
|
|
if options.StrNumber {
|
|
decoder.UseNumber()
|
|
}
|
|
if err = decoder.Decode(&result); err != nil {
|
|
return nil, err
|
|
}
|
|
switch result.(type) {
|
|
case string, []byte:
|
|
return nil, gerror.Newf(`json decoding failed for content: %s`, data)
|
|
}
|
|
return NewWithOptions(result, options), nil
|
|
|
|
case ContentTypeXML:
|
|
decodedData, err = gxml.Decode(data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return NewWithOptions(decodedData, options), nil
|
|
|
|
case ContentTypeYaml, ContentTypeYml:
|
|
decodedData, err = gyaml.Decode(data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return NewWithOptions(decodedData, options), nil
|
|
|
|
case ContentTypeToml:
|
|
decodedData, err = gtoml.Decode(data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return NewWithOptions(decodedData, options), nil
|
|
|
|
case ContentTypeIni:
|
|
decodedData, err = gini.Decode(data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return NewWithOptions(decodedData, options), nil
|
|
|
|
case ContentTypeProperties:
|
|
decodedData, err = gproperties.Decode(data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return NewWithOptions(decodedData, options), nil
|
|
|
|
default:
|
|
}
|
|
// ignore some duplicated types, like js and yml,
|
|
// which are not necessary shown in error message.
|
|
allSupportedTypes := []string{
|
|
ContentTypeJSON,
|
|
ContentTypeXML,
|
|
ContentTypeYaml,
|
|
ContentTypeToml,
|
|
ContentTypeIni,
|
|
ContentTypeProperties,
|
|
}
|
|
return nil, gerror.NewCodef(
|
|
gcode.CodeInvalidParameter,
|
|
`unsupported type "%s" for loading, all supported types: %s`,
|
|
options.Type, gstr.Join(allSupportedTypes, ", "),
|
|
)
|
|
}
|
|
|
|
// checkDataType automatically checks and returns the data type for `content`.
|
|
// Note that it uses regular expression for loose checking, you can use LoadXXX/LoadContentType
|
|
// functions to load the content for certain content type.
|
|
// TODO it is not graceful here automatic judging the data type.
|
|
// TODO it might be removed in the future, which lets the user explicitly specify the data type not automatic checking.
|
|
func checkDataType(data []byte) (ContentType, error) {
|
|
switch {
|
|
case json.Valid(data):
|
|
return ContentTypeJSON, nil
|
|
|
|
case isXMLContent(data):
|
|
return ContentTypeXML, nil
|
|
|
|
case isYamlContent(data):
|
|
return ContentTypeYaml, nil
|
|
|
|
case isTomlContent(data):
|
|
return ContentTypeToml, nil
|
|
|
|
case isIniContent(data):
|
|
// Must contain "[xxx]" section.
|
|
return ContentTypeIni, nil
|
|
|
|
case isPropertyContent(data):
|
|
return ContentTypeProperties, nil
|
|
|
|
default:
|
|
return "", gerror.NewCode(
|
|
gcode.CodeOperationFailed,
|
|
`unable auto check the data format type`,
|
|
)
|
|
}
|
|
}
|
|
|
|
// isXMLContent checks whether given content is XML format.
|
|
// XML format is easy to be identified using regular expression.
|
|
func isXMLContent(data []byte) bool {
|
|
return gregex.IsMatch(`^\s*<.+>[\S\s]+<.+>\s*$`, data)
|
|
}
|
|
|
|
// isYamlContent checks whether given content is YAML format.
|
|
func isYamlContent(data []byte) bool {
|
|
// x = y
|
|
// "x.x" = "y"
|
|
tomlFormat1 := gregex.IsMatch(`[\n\r]*[\s\t\w\-\."]+\s*=\s*"""[\s\S]+"""`, data)
|
|
if tomlFormat1 {
|
|
return false
|
|
}
|
|
// "x.x" = '''
|
|
// y
|
|
// '''
|
|
tomlFormat2 := gregex.IsMatch(`[\n\r]*[\s\t\w\-\."]+\s*=\s*'''[\s\S]+'''`, data)
|
|
if tomlFormat2 {
|
|
return false
|
|
}
|
|
|
|
// content starts with:
|
|
// x : "y"
|
|
yamlFormat1 := gregex.IsMatch(`^[\n\r]*[\w\-\s\t]+\s*:\s+".+"`, data)
|
|
|
|
// content starts with:
|
|
// x : y
|
|
yamlFormat2 := gregex.IsMatch(`^[\n\r]*[\w\-\s\t]+\s*:\s+\w+`, data)
|
|
|
|
// line starts with:
|
|
// x : "y"
|
|
yamlFormat3 := gregex.IsMatch(`[\n\r]+[\w\-\s\t]+\s*:\s+".+"`, data)
|
|
|
|
// line starts with:
|
|
// x : y
|
|
yamlFormat4 := gregex.IsMatch(`[\n\r]+[\w\-\s\t]+\s*:\s+\w+`, data)
|
|
|
|
// content starts with:
|
|
// "x" : "y"
|
|
yamlFormat5 := gregex.IsMatch(`^[\n\r]*".+":\s+".+"`, data)
|
|
|
|
// line starts with:
|
|
// "x" : y
|
|
yamlFormat6 := gregex.IsMatch(`[\n\r]+".+":\s+\w+`, data)
|
|
|
|
return yamlFormat1 || yamlFormat2 || yamlFormat3 || yamlFormat4 || yamlFormat5 || yamlFormat6
|
|
}
|
|
|
|
// isTomlContent checks whether given content is TOML format.
|
|
func isTomlContent(data []byte) bool {
|
|
// content starts with:
|
|
// ; comment line
|
|
contentStartsWithSemicolonComment := gregex.IsMatch(`^[\s\t\n\r]*;.+`, data)
|
|
if contentStartsWithSemicolonComment {
|
|
return false
|
|
}
|
|
// line starts with:
|
|
// ; comment line
|
|
lineStartsWithSemicolonComment := gregex.IsMatch(`[\s\t\n\r]+;.+`, data)
|
|
if lineStartsWithSemicolonComment {
|
|
return false
|
|
}
|
|
|
|
// line starts with, this should not be toml format:
|
|
// key.with.dot = value
|
|
keyWithDot := gregex.IsMatch(`[\n\r]+[\s\t\w\-]+\.[\s\t\w\-]+\s*=\s*.+`, data)
|
|
if keyWithDot {
|
|
return false
|
|
}
|
|
|
|
// line starts with:
|
|
// key = value
|
|
// key = "value"
|
|
// "key" = "value"
|
|
// "key" = value
|
|
tomlFormat1 := gregex.IsMatch(`[\n\r]*[\s\t\w\-\."]+\s*=\s*".+"`, data)
|
|
tomlFormat2 := gregex.IsMatch(`[\n\r]*[\s\t\w\-\."]+\s*=\s*\w+`, data)
|
|
return tomlFormat1 || tomlFormat2
|
|
}
|
|
|
|
// isIniContent checks whether given content is INI format.
|
|
func isIniContent(data []byte) bool {
|
|
// no section like: [section], but ini format must have sections.
|
|
hasBrackets := gregex.IsMatch(`\[[\w\.]+\]`, data)
|
|
if !hasBrackets {
|
|
return false
|
|
}
|
|
iniFormat1 := gregex.IsMatch(`[\n\r]*[\s\t\w\-\."]+\s*=\s*".+"`, data)
|
|
iniFormat2 := gregex.IsMatch(`[\n\r]*[\s\t\w\-\."]+\s*=\s*\w+`, data)
|
|
return iniFormat1 || iniFormat2
|
|
}
|
|
|
|
// isPropertyContent checks whether given content is Properties format.
|
|
func isPropertyContent(data []byte) bool {
|
|
// line starts with:
|
|
// key = value
|
|
// "key" = value
|
|
propertyFormat := gregex.IsMatch(`[\n\r]*[\s\t\w\-\."]+\s*=\s*\w+`, data)
|
|
return propertyFormat
|
|
}
|