ronantakizawa/codereview-bench huggingface dataset:
Repository: go-gitea/gitea
File: web_src/js/components/RepoRecentCommits.vue (Vue)

Code before:
import 'chartjs-adapter-dayjs-4/dist/chartjs-adapter-dayjs-4.esm';
import {onMounted, ref, shallowRef} from 'vue';

const {pageData} = window.config;

Chart.defaults.color = chartJsColors.text;
Chart.defaults.borderColor = chartJsColors.border;

Chart.register(
  TimeScale,
  LinearScale,
  BarElement,
  Tooltip,
);

defineProps<{
  locale: {
    loadingTitle: string;
    loadingTitleFailed: string;
    loadingInfo: string;
  };
}>();

const isLoading = shallowRef(false);
const errorText = shallowRef('');
const repoLink = pageData.repoLink || [];
const data = ref<DayData[]>([]);

onMounted(() => {
  fetchGraphData();
});

async function fetchGraphData() {
  isLoading.value = true;
  try {
    let response: Response;
    do {
      response = await GET(`${repoLink}/activity/recent-commits/data`);
      if (response.status === 202) {
        await sleep(1000); // wait for 1 second before retrying
      }
    } while (response.status === 202);
    if (response.ok) {
      const dayDataObj: DayDataObject = await response.json();
      const start = Object.values(dayDataObj)[0].week;
      const end = firstStartDateAfterDate(new Date());
      const startDays = startDaysBetween(start, end);
      data.value = fillEmptyStartDaysWithZeroes(startDays, dayDataObj).slice(-52);
      errorText.value = '';
    } else {
      errorText.value = response.statusText;

Review comment (suggestion):
```suggestion
const repoLink = pageData.repoLink;
```

Code after:
import 'chartjs-adapter-dayjs-4/dist/chartjs-adapter-dayjs-4.esm';
import {onMounted, ref, shallowRef} from 'vue';

const {pageData} = window.config;

Chart.defaults.color = chartJsColors.text;
Chart.defaults.borderColor = chartJsColors.border;

Chart.register(
  TimeScale,
  LinearScale,
  BarElement,
  Tooltip,
);

defineProps<{
  locale: {
    loadingTitle: string;
    loadingTitleFailed: string;
    loadingInfo: string;
  };
}>();

const isLoading = shallowRef(false);
const errorText = shallowRef('');
const repoLink = pageData.repoLink;
const data = ref<DayData[]>([]);

onMounted(() => {
  fetchGraphData();
});

async function fetchGraphData() {
  isLoading.value = true;
  try {
    let response: Response;
    do {
      response = await GET(`${repoLink}/activity/recent-commits/data`);
      if (response.status === 202) {
        await sleep(1000); // wait for 1 second before retrying
      }
    } while (response.status === 202);
    if (response.ok) {
      const dayDataObj: DayDataObject = await response.json();
      const start = Object.values(dayDataObj)[0].week;
      const end = firstStartDateAfterDate(new Date());
      const startDays = startDaysBetween(start, end);
      data.value = fillEmptyStartDaysWithZeroes(startDays, dayDataObj).slice(-52);
      errorText.value = '';
    } else {
      errorText.value = response.statusText;
Repository: go-gitea/gitea
File: modules/htmlutil/html.go (Go)

Code before:
)

// ParseSizeAndClass get size and class from string with default values
// If present, "others" expects the new size first and then the classes to use
func ParseSizeAndClass(defaultSize int, defaultClass string, others ...any) (int, string) {
	size := defaultSize
	if len(others) >= 1 {
		if v, ok := others[0].(int); ok && v != 0 {
			size = v
		}
	}
	class := defaultClass
	if len(others) >= 2 {
		if v, ok := others[1].(string); ok && v != "" {
			if class != "" {
				class += " "
			}
			class += v
		}
	}
	return size, class
}

func HTMLFormat(s template.HTML, rawArgs ...any) template.HTML {
	if !strings.Contains(string(s), "%") || len(rawArgs) == 0 {
		panic("HTMLFormat requires at least one argument, don't abuse it")
	}
	args := slices.Clone(rawArgs)
	for i, v := range args {
		switch v := v.(type) {
		case nil, bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, template.HTML:
			// for most basic types (including template.HTML which is safe), just do nothing and use it
		case string:
			args[i] = template.HTMLEscapeString(v)
		case fmt.Stringer:
			args[i] = template.HTMLEscapeString(v.String())
		default:
			args[i] = template.HTMLEscapeString(fmt.Sprint(v))
		}
	}
	return template.HTML(fmt.Sprintf(string(s), args...))
}


Review comment (suggestion):
```suggestion
		panic("HTMLFormat requires one or more arguments")
```

More neutral message

Code after:
)

// ParseSizeAndClass get size and class from string with default values
// If present, "others" expects the new size first and then the classes to use
func ParseSizeAndClass(defaultSize int, defaultClass string, others ...any) (int, string) {
	size := defaultSize
	if len(others) >= 1 {
		if v, ok := others[0].(int); ok && v != 0 {
			size = v
		}
	}
	class := defaultClass
	if len(others) >= 2 {
		if v, ok := others[1].(string); ok && v != "" {
			if class != "" {
				class += " "
			}
			class += v
		}
	}
	return size, class
}

func HTMLFormat(s template.HTML, rawArgs ...any) template.HTML {
	if !strings.Contains(string(s), "%") || len(rawArgs) == 0 {
		panic("HTMLFormat requires one or more arguments")
	}
	args := slices.Clone(rawArgs)
	for i, v := range args {
		switch v := v.(type) {
		case nil, bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, template.HTML:
			// for most basic types (including template.HTML which is safe), just do nothing and use it
		case string:
			args[i] = template.HTMLEscapeString(v)
		case fmt.Stringer:
			args[i] = template.HTMLEscapeString(v.String())
		default:
			args[i] = template.HTMLEscapeString(fmt.Sprint(v))
		}
	}
	return template.HTML(fmt.Sprintf(string(s), args...))
}
Repository: go-gitea/gitea
File: services/lfs/server.go (Go)

Code before:
	claims, claimsOk := token.Claims.(*Claims)
	if !token.Valid || !claimsOk {
		return nil, errors.New("invalid token claim")
	}

	if claims.RepoID != target.ID {
		return nil, errors.New("invalid token claim")
	}

	if mode == perm_model.AccessModeWrite && claims.Op != "upload" {
		return nil, errors.New("invalid token claim")
	}

	u, err := user_model.GetUserByID(ctx, claims.UserID)
	if err != nil {
		log.Error("Unable to GetUserById[%d]: Error: %v", claims.UserID, err)
		return nil, err
	}
	return u, nil
}

func parseToken(ctx stdCtx.Context, authorization string, target *repo_model.Repository, mode perm_model.AccessMode) (*user_model.User, error) {
	if authorization == "" {
		return nil, errors.New("no token")
	}
	token, ok := httpauth.ParseAuthorizationHeaderBearerToken(authorization)
	if !ok {
		return nil, errors.New("token not found")
	}
	return handleLFSToken(ctx, token, target, mode)
}

func requireAuth(ctx *context.Context) {
	ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="gitea-lfs"`)
	writeStatus(ctx, http.StatusUnauthorized)
}


Review comment (security):
ref：[The Git LFS API uses HTTP Basic Authentication to authorize requests. ](https://github.com/git-lfs/git-lfs/blob/92dddf560e62ef7dd25877d87ce072f7595aa52d/docs/api/authentication.md?plain=1#L3)

I'm not sure, would there be any other issues with us using token?

Code after:
	claims, claimsOk := token.Claims.(*Claims)
	if !token.Valid || !claimsOk {
		return nil, errors.New("invalid token claim")
	}

	if claims.RepoID != target.ID {
		return nil, errors.New("invalid token claim")
	}

	if mode == perm_model.AccessModeWrite && claims.Op != "upload" {
		return nil, errors.New("invalid token claim")
	}

	u, err := user_model.GetUserByID(ctx, claims.UserID)
	if err != nil {
		log.Error("Unable to GetUserById[%d]: Error: %v", claims.UserID, err)
		return nil, err
	}
	return u, nil
}

func parseToken(ctx stdCtx.Context, authorization string, target *repo_model.Repository, mode perm_model.AccessMode) (*user_model.User, error) {
	if authorization == "" {
		return nil, errors.New("no token")
	}
	parsed, ok := httpauth.ParseAuthorizationHeader(authorization)
	if !ok || parsed.BearerToken == nil {
		return nil, errors.New("token not found")
	}
	return handleLFSToken(ctx, parsed.BearerToken.Token, target, mode)
}

func requireAuth(ctx *context.Context) {
	ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="gitea-lfs"`)
	writeStatus(ctx, http.StatusUnauthorized)
}
Repository: go-gitea/gitea
File: models/repo/language_stats.go (Go)

Code before:
	if err != nil {
		return err
	}
	defer committer.Close()
	sess := db.GetEngine(ctx)

	oldstats, err := GetLanguageStats(ctx, repo)
	if err != nil {
		return err
	}
	var topLang string
	var s int64
	for lang, size := range stats {
		if size > s {
			s = size
			topLang = lang
		}
	}

	for lang, size := range stats {
		upd := false
		for _, s := range oldstats {
			// Update already existing language
			if strings.EqualFold(s.Language, lang) {
				s.CommitID = commitID
				s.IsPrimary = strings.EqualFold(lang, topLang)
				s.Size = size
				if _, err := sess.ID(s.ID).Cols("`commit_id`", "`size`", "`is_primary`").Update(s); err != nil {
					return err
				}
				upd = true
				break
			}
		}
		// Insert new language
		if !upd {
			if err := db.Insert(ctx, &LanguageStat{
				RepoID:    repo.ID,
				CommitID:  commitID,
				IsPrimary: strings.EqualFold(lang, topLang),
				Language:  lang,
				Size:      size,
			}); err != nil {
				return err
			}
		}
	}
	// Delete old languages
	statsToDelete := make([]int64, 0, len(oldstats))
	for _, s := range oldstats {
		if s.CommitID != commitID {

Review comment (security):
Why are we comparing here case-insensitive anyways?
It's the same data. `lang == topLang` should suffice.

Code after:
	if err != nil {
		return err
	}
	defer committer.Close()
	sess := db.GetEngine(ctx)

	oldstats, err := GetLanguageStats(ctx, repo)
	if err != nil {
		return err
	}
	var topLang string
	var s int64
	for lang, size := range stats {
		if size > s {
			s = size
			topLang = lang
		}
	}

	for lang, size := range stats {
		upd := false
		for _, s := range oldstats {
			// Update already existing language
			if strings.EqualFold(s.Language, lang) {
				s.CommitID = commitID
				s.IsPrimary = lang == topLang
				s.Size = size
				if _, err := sess.ID(s.ID).Cols("`commit_id`", "`size`", "`is_primary`").Update(s); err != nil {
					return err
				}
				upd = true
				break
			}
		}
		// Insert new language
		if !upd {
			if err := db.Insert(ctx, &LanguageStat{
				RepoID:    repo.ID,
				CommitID:  commitID,
				IsPrimary: lang == topLang,
				Language:  lang,
				Size:      size,
			}); err != nil {
				return err
			}
		}
	}
	// Delete old languages
	statsToDelete := make([]int64, 0, len(oldstats))
	for _, s := range oldstats {
		if s.CommitID != commitID {
Repository: go-gitea/gitea
File: models/repo/language_stats.go (Go)

Code before:
	if err != nil {
		return err
	}
	defer committer.Close()
	sess := db.GetEngine(ctx)

	oldstats, err := GetLanguageStats(ctx, repo)
	if err != nil {
		return err
	}
	var topLang string
	var s int64
	for lang, size := range stats {
		if size > s {
			s = size
			topLang = lang
		}
	}

	for lang, size := range stats {
		upd := false
		for _, s := range oldstats {
			// Update already existing language
			if strings.EqualFold(s.Language, lang) {
				s.CommitID = commitID
				s.IsPrimary = strings.EqualFold(lang, topLang)
				s.Size = size
				if _, err := sess.ID(s.ID).Cols("`commit_id`", "`size`", "`is_primary`").Update(s); err != nil {
					return err
				}
				upd = true
				break
			}
		}
		// Insert new language
		if !upd {
			if err := db.Insert(ctx, &LanguageStat{
				RepoID:    repo.ID,
				CommitID:  commitID,
				IsPrimary: strings.EqualFold(lang, topLang),
				Language:  lang,
				Size:      size,
			}); err != nil {
				return err
			}
		}
	}
	// Delete old languages
	statsToDelete := make([]int64, 0, len(oldstats))
	for _, s := range oldstats {
		if s.CommitID != commitID {

Review comment (suggestion):
```suggestion
				s.IsPrimary = lang == topLang
```

Code after:
	if err != nil {
		return err
	}
	defer committer.Close()
	sess := db.GetEngine(ctx)

	oldstats, err := GetLanguageStats(ctx, repo)
	if err != nil {
		return err
	}
	var topLang string
	var s int64
	for lang, size := range stats {
		if size > s {
			s = size
			topLang = lang
		}
	}

	for lang, size := range stats {
		upd := false
		for _, s := range oldstats {
			// Update already existing language
			if strings.EqualFold(s.Language, lang) {
				s.CommitID = commitID
				s.IsPrimary = lang == topLang
				s.Size = size
				if _, err := sess.ID(s.ID).Cols("`commit_id`", "`size`", "`is_primary`").Update(s); err != nil {
					return err
				}
				upd = true
				break
			}
		}
		// Insert new language
		if !upd {
			if err := db.Insert(ctx, &LanguageStat{
				RepoID:    repo.ID,
				CommitID:  commitID,
				IsPrimary: lang == topLang,
				Language:  lang,
				Size:      size,
			}); err != nil {
				return err
			}
		}
	}
	// Delete old languages
	statsToDelete := make([]int64, 0, len(oldstats))
	for _, s := range oldstats {
		if s.CommitID != commitID {
Repository: go-gitea/gitea
File: models/repo/language_stats.go (Go)

Code before:
			s = size
			topLang = lang
		}
	}

	for lang, size := range stats {
		upd := false
		for _, s := range oldstats {
			// Update already existing language
			if strings.EqualFold(s.Language, lang) {
				s.CommitID = commitID
				s.IsPrimary = lang == topLang
				s.Size = size
				if _, err := sess.ID(s.ID).Cols("`commit_id`", "`size`", "`is_primary`").Update(s); err != nil {
					return err
				}
				upd = true
				break
			}
		}
		// Insert new language
		if !upd {
			if err := db.Insert(ctx, &LanguageStat{
				RepoID:    repo.ID,
				CommitID:  commitID,
				IsPrimary: strings.EqualFold(lang, topLang),
				Language:  lang,
				Size:      size,
			}); err != nil {
				return err
			}
		}
	}
	// Delete old languages
	statsToDelete := make([]int64, 0, len(oldstats))
	for _, s := range oldstats {
		if s.CommitID != commitID {
			statsToDelete = append(statsToDelete, s.ID)
		}
	}
	if len(statsToDelete) > 0 {
		if _, err := sess.In("`id`", statsToDelete).Delete(&LanguageStat{}); err != nil {
			return err
		}
	}

	// Update indexer status
	if err = UpdateIndexerStatus(ctx, repo, RepoIndexerTypeStats, commitID); err != nil {
		return err
	}


Review comment (suggestion):
```suggestion
				IsPrimary: lang == topLang,
```

Code after:
			s = size
			topLang = lang
		}
	}

	for lang, size := range stats {
		upd := false
		for _, s := range oldstats {
			// Update already existing language
			if strings.EqualFold(s.Language, lang) {
				s.CommitID = commitID
				s.IsPrimary = lang == topLang
				s.Size = size
				if _, err := sess.ID(s.ID).Cols("`commit_id`", "`size`", "`is_primary`").Update(s); err != nil {
					return err
				}
				upd = true
				break
			}
		}
		// Insert new language
		if !upd {
			if err := db.Insert(ctx, &LanguageStat{
				RepoID:    repo.ID,
				CommitID:  commitID,
				IsPrimary: lang == topLang,
				Language:  lang,
				Size:      size,
			}); err != nil {
				return err
			}
		}
	}
	// Delete old languages
	statsToDelete := make([]int64, 0, len(oldstats))
	for _, s := range oldstats {
		if s.CommitID != commitID {
			statsToDelete = append(statsToDelete, s.ID)
		}
	}
	if len(statsToDelete) > 0 {
		if _, err := sess.In("`id`", statsToDelete).Delete(&LanguageStat{}); err != nil {
			return err
		}
	}

	// Update indexer status
	if err = UpdateIndexerStatus(ctx, repo, RepoIndexerTypeStats, commitID); err != nil {
		return err
	}
Repository: go-gitea/gitea
File: services/mailer/mail_workflow_run.go (Go)

Code before:
}

func SendActionsWorkflowRunStatusEmail(ctx context.Context, sender *user_model.User, repo *repo_model.Repository, run *actions_model.ActionRun) {
	if setting.MailService == nil {
		return
	}
	if run.Status.IsSkipped() {
		return
	}

	recipients := make([]*user_model.User, 0)

	if !sender.IsGiteaActions() && !sender.IsGhost() && sender.IsMailable() {
		if run.Status.IsSuccess() {
			if sender.EmailNotificationsPreference == user_model.EmailNotificationsAndYourOwn {
				recipients = append(recipients, sender)
			}
			sendActionsWorkflowRunStatusEmail(ctx, repo, run, sender, recipients)
			return
		} else if sender.EmailNotificationsPreference != user_model.EmailNotificationsOnMention &&
			sender.EmailNotificationsPreference != user_model.EmailNotificationsDisabled {
			recipients = append(recipients, sender)
		}
	}

	watchers, err := repo_model.GetRepoWatchers(ctx, repo.ID, db.ListOptionsAll)
	if err != nil {
		log.Error("GetWatchers: %v", err)
	}
	for _, watcher := range watchers {
		if watcher.ID == sender.ID {
			continue
		}
		if watcher.IsMailable() && watcher.EmailNotificationsPreference != user_model.EmailNotificationsOnMention &&
			watcher.EmailNotificationsPreference != user_model.EmailNotificationsDisabled {
			recipients = append(recipients, watcher)
		}
	}
	sendActionsWorkflowRunStatusEmail(ctx, repo, run, sender, recipients)
}


Review comment (suggestion):
We need a clear definition about "who should receive the emails"

I don't think the "watchers" should receive, for example: on GitHub, I watched some repositories that I have interests, but it doesn't mean that I should receive their notifications.


Code after:
	}
}

func MailActionsTrigger(ctx context.Context, sender *user_model.User, repo *repo_model.Repository, run *actions_model.ActionRun) {
	if setting.MailService == nil {
		return
	}
	if run.Status.IsSkipped() {
		return
	}

	recipients := make([]*user_model.User, 0)

	if !sender.IsGiteaActions() && !sender.IsGhost() && sender.IsMailable() {
		notifyPref, err := user_model.GetUserSetting(ctx, sender.ID,
			user_model.SettingsKeyEmailNotificationGiteaActions, user_model.SettingEmailNotificationGiteaActionsFailureOnly)
		if err != nil {
			log.Error("GetUserSetting: %v", err)
			return
		}
		if notifyPref == user_model.SettingEmailNotificationGiteaActionsAll || !run.Status.IsSuccess() && notifyPref != user_model.SettingEmailNotificationGiteaActionsDisabled {
			recipients = append(recipients, sender)
		}
	}

	if len(recipients) > 0 {
		composeAndSendActionsWorkflowRunStatusEmail(ctx, repo, run, sender, recipients)
	}
}
Repository: go-gitea/gitea
File: services/repository/branch.go (Go)

Code before:
func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, gitRepo *git.Repository, branchName string, pr *issues_model.PullRequest) error {
	err := repo.MustNotBeArchived()
	if err != nil {
		return err
	}

	if err := CanDeleteBranch(ctx, repo, branchName, doer); err != nil {
		return err
	}

	rawBranch, err := git_model.GetBranch(ctx, repo.ID, branchName)
	if err != nil && !git_model.IsErrBranchNotExist(err) {
		return fmt.Errorf("GetBranch: %vc", err)
	}

	// database branch record not exist or it's a deleted branch
	notExist := git_model.IsErrBranchNotExist(err) || rawBranch.IsDeleted

	branchExistInGit := gitRepo.IsBranchExist(branchName)
	var commitID string
	if branchExistInGit {
		commit, err := gitRepo.GetBranchCommit(branchName)
		if err != nil {
			return err
		}
		commitID = commit.ID.String()
	}

	if err := db.WithTx(ctx, func(ctx context.Context) error {
		if !notExist {
			if err := git_model.AddDeletedBranch(ctx, repo.ID, branchName, doer.ID); err != nil {
				return err
			}
		}

		if pr != nil {
			if err := issues_model.AddDeletePRBranchComment(ctx, doer, pr.BaseRepo, pr.Issue.ID, pr.HeadBranch); err != nil {
				return fmt.Errorf("DeleteBranch: %v", err)
			}
		}
		if !branchExistInGit {
			return nil
		}

		return gitRepo.DeleteBranch(branchName, git.DeleteBranchOptions{
			Force: true,
		})
	}); err != nil {
		return err
	}


Review comment (suggestion):
```
branchCommit, err := gitRepo.GetBranchCommit(branchName)
if err != nil && !errors.Is(err, util.ErrNotExist) {
    return err
}
// branchCommit != nil means branch exists
```

Code after:
func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, gitRepo *git.Repository, branchName string, pr *issues_model.PullRequest) error {
	err := repo.MustNotBeArchived()
	if err != nil {
		return err
	}

	if err := CanDeleteBranch(ctx, repo, branchName, doer); err != nil {
		return err
	}

	rawBranch, err := git_model.GetBranch(ctx, repo.ID, branchName)
	if err != nil && !git_model.IsErrBranchNotExist(err) {
		return fmt.Errorf("GetBranch: %vc", err)
	}

	// database branch record not exist or it's a deleted branch
	notExist := git_model.IsErrBranchNotExist(err) || rawBranch.IsDeleted

	branchCommit, err := gitRepo.GetBranchCommit(branchName)
	if err != nil && !errors.Is(err, util.ErrNotExist) {
		return err
	}

	if err := db.WithTx(ctx, func(ctx context.Context) error {
		if !notExist {
			if err := git_model.AddDeletedBranch(ctx, repo.ID, branchName, doer.ID); err != nil {
				return err
			}
		}

		if pr != nil {
			if err := issues_model.AddDeletePRBranchComment(ctx, doer, pr.BaseRepo, pr.Issue.ID, pr.HeadBranch); err != nil {
				return fmt.Errorf("DeleteBranch: %v", err)
			}
		}
		if branchCommit == nil {
			return nil
		}

		return gitRepo.DeleteBranch(branchName, git.DeleteBranchOptions{
			Force: true,
		})
	}); err != nil {
		return err
	}

	if branchCommit == nil {
		return nil
	}

	// Don't return error below this
Repository: go-gitea/gitea
File: modules/json/jsonv2.go (Go)

Code before:
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package json

import (
	jsonv2 "encoding/json/v2"
	"io"
)

// isJSONv2Available returns true when JSON v2 is available (compiled with GOEXPERIMENT=jsonv2)
func isJSONv2Available() bool {
	return true
}

// marshalV2 uses JSON v2 marshal with v1 compatibility options
func marshalV2(v any) ([]byte, error) {
	opts := jsonv2.JoinOptions(
		jsonv2.MatchCaseInsensitiveNames(true),
		jsonv2.FormatNilSliceAsNull(true),
		jsonv2.FormatNilMapAsNull(true),
	)
	return jsonv2.Marshal(v, opts)
}

// unmarshalV2 uses JSON v2 unmarshal with v1 compatibility options
func unmarshalV2(data []byte, v any) error {
	opts := jsonv2.JoinOptions(

Review comment (suggestion):
```suggestion

//go:build goexperiment.jsonv2

```

Code after:
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

//go:build goexperiment.jsonv2

package json

import (
	"bytes"
	jsonv1 "encoding/json"    //nolint:depguard // this package wraps it
	jsonv2 "encoding/json/v2" //nolint:depguard // this package wraps it
	"io"
)

// JSONv2 implements Interface via encoding/json/v2
// Requires GOEXPERIMENT=jsonv2 to be set at build time
type JSONv2 struct {
	marshalOptions                  jsonv2.Options
	marshalKeepOptionalEmptyOptions jsonv2.Options
	unmarshalOptions                jsonv2.Options
	unmarshalCaseInsensitiveOptions jsonv2.Options
}

var jsonV2 JSONv2

func init() {
	commonMarshalOptions := []jsonv2.Options{
		jsonv2.FormatNilSliceAsNull(true),