// Analyze all parameters and categorize them // Initialize all fields of ParamAnalyzer struct func (p *ParamAnalyzer) Analyze() { // Order params using their length so "foo[bar]" is analyzed before "foo" params := p.rawParams paths := make([]string, len(params)) i := 0 for n := range params { paths[i] = n i++ } sort.Strings(paths) sort.Sort(ByReverseLength(paths)) rawLeafParams := []string{} for _, p := range paths { hasLeaf := false for _, r := range rawLeafParams { if strings.HasSuffix(r, "]") && strings.HasPrefix(r, p) { hasLeaf = true break } } if hasLeaf { continue } rawLeafParams = append(rawLeafParams, p) } sort.Strings(rawLeafParams) p.leafParamNames = rawLeafParams // Iterate through all params and build corresponding ActionParam structs p.parsed = map[string]*gen.ActionParam{} top := map[string]*gen.ActionParam{} for _, path := range paths { if strings.HasSuffix(path, "[*]") { // Cheat a little bit - there a couple of cases where parent type is // Hash instead of Enumerable, make that enumerable everywhere // There are also cases where there's no parent path, fix that up also matches := parentPathRegexp.FindStringSubmatch(path) if hashParam, ok := params[matches[1]].(map[string]interface{}); ok { hashParam["class"] = "Enumerable" } else { // Create parent rawParams := map[string]interface{}{} parentPath := matches[1] p.parsed[parentPath] = p.newParam(parentPath, rawParams, new(gen.EnumerableDataType)) if parentPathRegexp.FindStringSubmatch(parentPath) == nil { top[parentPath] = p.parsed[parentPath] } } continue } var child *gen.ActionParam origPath := path origParam := params[path].(map[string]interface{}) matches := parentPathRegexp.FindStringSubmatch(path) isTop := (matches == nil) if prev, ok := p.parsed[path]; ok { if isTop { top[path] = prev } continue } var branch []*gen.ActionParam for matches != nil { param := params[path].(map[string]interface{}) parentPath := matches[1] var isArrayChild bool if strings.HasSuffix(parentPath, "[]") { isArrayChild = true } if parent, ok := p.parsed[parentPath]; ok { a, ok := parent.Type.(*gen.ArrayDataType) if ok { parent = a.ElemType } child = p.parseParam(path, param, child) if !parent.Mandatory { // Make required fields of optional hashes optional. child.Mandatory = false } branch = append(branch, child) if _, ok = parent.Type.(*gen.EnumerableDataType); !ok { o := parent.Type.(*gen.ObjectDataType) o.Fields = appendSorted(o.Fields, child) p.parsed[path] = child } break // No need to keep going back, we already have a parent } else { child = p.parseParam(path, param, child) branch = append(branch, child) p.parsed[path] = child if isArrayChild { // Generate array item as it's not listed explicitly in JSON itemPath := matches[1] + "[item]" typeName := p.typeName(matches[1]) parent = p.newParam(itemPath, map[string]interface{}{}, &gen.ObjectDataType{typeName, []*gen.ActionParam{child}}) p.parsed[parentPath] = parent child = parent branch = append(branch, child) parentPath = parentPath[:len(parentPath)-2] } } path = parentPath matches = parentPathRegexp.FindStringSubmatch(path) } if isTop { if _, ok := p.parsed[path]; !ok { actionParam := p.parseParam(path, origParam, nil) p.parsed[path] = actionParam } top[path] = p.parsed[path] } else { matches := rootRegexp.FindStringSubmatch(origPath) rootPath := matches[1] if _, ok := p.parsed[rootPath]; !ok { p.parsed[rootPath] = p.parseParam(rootPath, params[rootPath].(map[string]interface{}), child) } actionParam, _ := p.parsed[rootPath] mandatory := actionParam.Mandatory if len(branch) > 0 { for i := len(branch) - 1; i >= 0; i-- { p := branch[i] if mandatory { if !p.Mandatory { mandatory = false } } else { p.Mandatory = false } } } } } // Now do a second pass on parsed params to generate their declarations p.ParamTypes = make(map[string]*gen.ObjectDataType) for _, param := range top { p.recordTypes(param.Type) } i = 0 res := make([]*gen.ActionParam, len(top)) for _, param := range top { res[i] = param i++ } sort.Sort(gen.ByName(res)) p.Params = res }
// Sort action params by name func appendSorted(params []*gen.ActionParam, param *gen.ActionParam) []*gen.ActionParam { params = append(params, param) sort.Sort(gen.ByName(params)) return params }