| // Copyright 2022 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| //go:build go1.19 |
| // +build go1.19 |
| |
| package main |
| |
| import ( |
| "fmt" |
| "sort" |
| ) |
| |
| // Model contains the parsed version of the spec |
| type Model struct { |
| Version Metadata `json:"metaData"` |
| Requests []*Request `json:"requests"` |
| Notifications []*Notification `json:"notifications"` |
| Structures []*Structure `json:"structures"` |
| Enumerations []*Enumeration `json:"enumerations"` |
| TypeAliases []*TypeAlias `json:"typeAliases"` |
| Line int `json:"line"` |
| } |
| |
| // Metadata is information about the version of the spec |
| type Metadata struct { |
| Version string `json:"version"` |
| Line int `json:"line"` |
| } |
| |
| // A Request is the parsed version of an LSP request |
| type Request struct { |
| Documentation string `json:"documentation"` |
| ErrorData *Type `json:"errorData"` |
| Direction string `json:"messageDirection"` |
| Method string `json:"method"` |
| Params *Type `json:"params"` |
| PartialResult *Type `json:"partialResult"` |
| Proposed bool `json:"proposed"` |
| RegistrationMethod string `json:"registrationMethod"` |
| RegistrationOptions *Type `json:"registrationOptions"` |
| Result *Type `json:"result"` |
| Since string `json:"since"` |
| Line int `json:"line"` |
| } |
| |
| // A Notificatin is the parsed version of an LSP notification |
| type Notification struct { |
| Documentation string `json:"documentation"` |
| Direction string `json:"messageDirection"` |
| Method string `json:"method"` |
| Params *Type `json:"params"` |
| Proposed bool `json:"proposed"` |
| RegistrationMethod string `json:"registrationMethod"` |
| RegistrationOptions *Type `json:"registrationOptions"` |
| Since string `json:"since"` |
| Line int `json:"line"` |
| } |
| |
| // A Structure is the parsed version of an LSP structure from the spec |
| type Structure struct { |
| Documentation string `json:"documentation"` |
| Extends []*Type `json:"extends"` |
| Mixins []*Type `json:"mixins"` |
| Name string `json:"name"` |
| Properties []NameType `json:"properties"` |
| Proposed bool `json:"proposed"` |
| Since string `json:"since"` |
| Line int `json:"line"` |
| } |
| |
| // An enumeration is the parsed version of an LSP enumeration from the spec |
| type Enumeration struct { |
| Documentation string `json:"documentation"` |
| Name string `json:"name"` |
| Proposed bool `json:"proposed"` |
| Since string `json:"since"` |
| SupportsCustomValues bool `json:"supportsCustomValues"` |
| Type *Type `json:"type"` |
| Values []NameValue `json:"values"` |
| Line int `json:"line"` |
| } |
| |
| // A TypeAlias is the parsed version of an LSP type alias from the spec |
| type TypeAlias struct { |
| Documentation string `json:"documentation"` |
| Deprecated string `json:"deprecated"` |
| Name string `json:"name"` |
| Proposed bool `json:"proposed"` |
| Since string `json:"since"` |
| Type *Type `json:"type"` |
| Line int `json:"line"` |
| } |
| |
| // A NameValue describes an enumeration constant |
| type NameValue struct { |
| Documentation string `json:"documentation"` |
| Name string `json:"name"` |
| Proposed bool `json:"proposed"` |
| Since string `json:"since"` |
| Value any `json:"value"` // number or string |
| Line int `json:"line"` |
| } |
| |
| // A Type is the parsed version of an LSP type from the spec, |
| // or a Type the code constructs |
| type Type struct { |
| Kind string `json:"kind"` // -- which kind goes with which field -- |
| Items []*Type `json:"items"` // "and", "or", "tuple" |
| Element *Type `json:"element"` // "array" |
| Name string `json:"name"` // "base", "reference" |
| Key *Type `json:"key"` // "map" |
| Value any `json:"value"` // "map", "stringLiteral", "literal" |
| Line int `json:"line"` // JSON source line |
| } |
| |
| // ParsedLiteral is Type.Value when Type.Kind is "literal" |
| type ParseLiteral struct { |
| Properties `json:"properties"` |
| } |
| |
| // A NameType represents the name and type of a structure element |
| type NameType struct { |
| Name string `json:"name"` |
| Type *Type `json:"type"` |
| Optional bool `json:"optional"` |
| Documentation string `json:"documentation"` |
| Deprecated string `json:"deprecated"` |
| Since string `json:"since"` |
| Proposed bool `json:"proposed"` |
| Line int `json:"line"` |
| } |
| |
| // Properties are the collection of structure fields |
| type Properties []NameType |
| |
| // addLineNumbers adds a "line" field to each object in the JSON. |
| func addLineNumbers(buf []byte) []byte { |
| var ans []byte |
| // In the specification .json file, the delimiter '{' is |
| // always followed by a newline. There are other {s embedded in strings. |
| // json.Token does not return \n, or :, or , so using it would |
| // require parsing the json to reconstruct the missing information. |
| for linecnt, i := 1, 0; i < len(buf); i++ { |
| ans = append(ans, buf[i]) |
| switch buf[i] { |
| case '{': |
| if buf[i+1] == '\n' { |
| ans = append(ans, fmt.Sprintf(`"line": %d, `, linecnt)...) |
| // warning: this would fail if the spec file had |
| // `"value": {\n}`, but it does not, as comma is a separator. |
| } |
| case '\n': |
| linecnt++ |
| } |
| } |
| return ans |
| } |
| |
| type sortedMap[T any] map[string]T |
| |
| func (s sortedMap[T]) keys() []string { |
| var keys []string |
| for k := range s { |
| keys = append(keys, k) |
| } |
| sort.Strings(keys) |
| return keys |
| } |