Files
玉澜andCursor 286a84edcd refactor(cmdcore): move annotate/ContractFinal store under corecmd
Break the remaining corecmd→cli reverse dependency by owning
runtimeannotate and contractfinal on the framework side, with cli
keeping thin re-exports. Document the three authoring tiers and that
Shortcut may use DeclareLeafMetadata.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-02 00:10:03 +08:00

107 lines
3.6 KiB
Go

// Copyright 2026 Alibaba Group
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package runtimeannotate
import (
"encoding/json"
"strings"
"github.com/spf13/cobra"
)
// RuntimeSchemaConstraints describes cross-parameter rules that cannot be
// represented by an individual parameter's required bit.
type RuntimeSchemaConstraints struct {
MutuallyExclusive [][]string `json:"mutually_exclusive,omitempty"`
RequireOneOf [][]string `json:"require_one_of,omitempty"`
RequireTogether [][]string `json:"require_together,omitempty"`
}
// AnnotateRuntimeConstraints records command-level parameter relationships.
func AnnotateRuntimeConstraints(cmd *cobra.Command, constraints RuntimeSchemaConstraints) {
if cmd == nil {
return
}
constraints = NormalizeConstraints(constraints)
if ConstraintsEmpty(constraints) {
return
}
if existing := CommandConstraints(cmd); !ConstraintsEmpty(existing) {
constraints.MutuallyExclusive = append(existing.MutuallyExclusive, constraints.MutuallyExclusive...)
constraints.RequireOneOf = append(existing.RequireOneOf, constraints.RequireOneOf...)
constraints.RequireTogether = append(existing.RequireTogether, constraints.RequireTogether...)
constraints = NormalizeConstraints(constraints)
}
encoded, _ := json.Marshal(constraints)
SetCommandAnnotation(cmd, AnnotationConstraints, string(encoded))
}
// CommandConstraints reads the annotated constraint payload (empty on miss/error).
func CommandConstraints(cmd *cobra.Command) RuntimeSchemaConstraints {
if cmd == nil || cmd.Annotations == nil {
return RuntimeSchemaConstraints{}
}
raw := strings.TrimSpace(cmd.Annotations[AnnotationConstraints])
if raw == "" {
return RuntimeSchemaConstraints{}
}
var constraints RuntimeSchemaConstraints
if json.Unmarshal([]byte(raw), &constraints) != nil {
return RuntimeSchemaConstraints{}
}
return NormalizeConstraints(constraints)
}
// NormalizeConstraints trims, deduplicates, and drops undersized groups.
func NormalizeConstraints(constraints RuntimeSchemaConstraints) RuntimeSchemaConstraints {
constraints.MutuallyExclusive = normalizeGroups(constraints.MutuallyExclusive, 2)
constraints.RequireOneOf = normalizeGroups(constraints.RequireOneOf, 1)
constraints.RequireTogether = normalizeGroups(constraints.RequireTogether, 2)
return constraints
}
// ConstraintsEmpty reports whether no constraint groups remain.
func ConstraintsEmpty(constraints RuntimeSchemaConstraints) bool {
return len(constraints.MutuallyExclusive) == 0 &&
len(constraints.RequireOneOf) == 0 &&
len(constraints.RequireTogether) == 0
}
func normalizeGroups(groups [][]string, minimum int) [][]string {
out := make([][]string, 0, len(groups))
seenGroups := map[string]bool{}
for _, group := range groups {
clean := make([]string, 0, len(group))
seenNames := map[string]bool{}
for _, name := range group {
name = strings.TrimSpace(name)
if name == "" || seenNames[name] {
continue
}
seenNames[name] = true
clean = append(clean, name)
}
if len(clean) < minimum {
continue
}
key := strings.Join(clean, "\x00")
if seenGroups[key] {
continue
}
seenGroups[key] = true
out = append(out, clean)
}
return out
}