Repository: alecthomas/chroma
Pull request #348 (2020-04-13 14:36:01)

Add YANG lexer
Based on #347, I created the lexer in golang.

### Features
* Keywords based on [RFC7950](https://tools.ietf.org/html/rfc7950#page-184)
* Seperating keywords in groups, based on BNF definition of [RFC7950](https://tools.ietf.org/html/rfc7950#page-184) for maintenance
* Highlighting of constants, like `true`, `false` or `deprecated` with special token
* Highlighting of namespace-prefix, like `type namespace-prefix:counter64;`. `namespace-prefix` will have special token.
For example `namespace urn:ieee:std:802.1AX:yang:ieee802-dot1ax;` will have no special token
* Prefix-highlighting should be the complex regex pattern of all pattern. Due to that, I created test cases to validate prefix-highlighting
* Add some test cases for testing of another complex scenarios, like `revision-date`
* Create example yang file for testing

alecthomas: Hi, thanks! CI failed but it looks minor.

Patch:
diff --git a/go.mod b/go.mod
index 307b4ff..10e6d6e 100644
--- a/go.mod
+++ b/go.mod
@@ -5,13 +5,14 @@ go 1.13
 require (
 	github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38
 	github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 // indirect
-	github.com/alecthomas/kong v0.2.1-0.20190708041108-0548c6b1afae
+	github.com/alecthomas/kong v0.2.4
 	github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 // indirect
 	github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964
-	github.com/dlclark/regexp2 v1.1.6
-	github.com/mattn/go-colorable v0.0.9
-	github.com/mattn/go-isatty v0.0.4
+	github.com/dlclark/regexp2 v1.2.0
+	github.com/mattn/go-colorable v0.1.6
+	github.com/mattn/go-isatty v0.0.12
+	github.com/pkg/errors v0.9.1 // indirect
 	github.com/sergi/go-diff v1.0.0 // indirect
 	github.com/stretchr/testify v1.3.0 // indirect
-	golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35 // indirect
+	golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 // indirect
 )
diff --git a/go.sum b/go.sum
index 82643a3..fb943fc 100644
--- a/go.sum
+++ b/go.sum
@@ -2,8 +2,8 @@ github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm
 github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI=
 github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 h1:JHZL0hZKJ1VENNfmXvHbgYlbUOvpzYzvy2aZU5gXVeo=
 github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0=
-github.com/alecthomas/kong v0.2.1-0.20190708041108-0548c6b1afae h1:C4Q9m+oXOxcSWwYk9XzzafY2xAVAaeubZbUHJkw3PlY=
-github.com/alecthomas/kong v0.2.1-0.20190708041108-0548c6b1afae/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI=
+github.com/alecthomas/kong v0.2.4 h1:Y0ZBCHAvHhTHw7FFJ2FzCAAG4pkbTgA45nc7BpMhDNk=
+github.com/alecthomas/kong v0.2.4/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE=
 github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkxI1zYWl1QLnEqAqEARBEYa8FQnQcY=
 github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
 github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ=
@@ -11,15 +11,16 @@ github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/dlclark/regexp2 v1.1.6 h1:CqB4MjHw0MFCDj+PHHjiESmHX+N7t0tJzKvC6M97BRg=
-github.com/dlclark/regexp2 v1.1.6/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
-github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
-github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
-github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
-github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
-github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=
+github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
+github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
+github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
 github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
@@ -29,5 +30,7 @@ github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35 h1:YAFjXN64LMvktoUZH9zgY4lGc/msGN7HQfoSuKCgaDU=
-golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 h1:opSr2sbRXk5X5/givKrrKj9HXxFpW2sdCiP8MJSKLQY=
+golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/lexers/y/yang.go b/lexers/y/yang.go
new file mode 100644
index 0000000..73edb71
--- /dev/null
+++ b/lexers/y/yang.go
@@ -0,0 +1,67 @@
+package y
+
+import (
+	. "github.com/alecthomas/chroma" // nolint
+	"github.com/alecthomas/chroma/lexers/internal"
+)
+
+var YANG = internal.Register(MustNewLexer(
+	&Config{
+		Name:      "YANG",
+		Aliases:   []string{"yang"},
+		Filenames: []string{"*.yang"},
+		MimeTypes: []string{"application/yang"},
+	},
+	Rules{
+		"root": {
+			{`\s+`, Whitespace, nil},
+			{`[\{\}\;]+`, Punctuation, nil},
+			{`(?<![\-\w])(and|or|not|\+|\.)(?![\-\w])`, Operator, nil},
+
+			{`"(?:\\"|[^"])*?"`, StringDouble, nil},
+			{`'(?:\\'|[^'])*?'`, StringSingle, nil},
+
+			{`/\*`, CommentMultiline, Push("comments")},
+			{`//.*?$`, CommentSingle, nil},
+
+			//match BNF stmt for `node-identifier` with [ prefix ":"]
+			{`(?:^|(?<=[\s{};]))([\w.-]+)(:)([\w.-]+)(?=[\s{};])`, ByGroups(KeywordNamespace, Punctuation, Text), nil},
+
+			//match BNF stmt `date-arg-str`
+			{`([0-9]{4}\-[0-9]{2}\-[0-9]{2})(?=[\s\{\}\;])`, LiteralDate, nil},
+			{`([0-9]+\.[0-9]+)(?=[\s\{\}\;])`, NumberFloat, nil},
+			{`([0-9]+)(?=[\s\{\}\;])`, NumberInteger, nil},
+
+			//TOP_STMTS_KEYWORDS
+			{Words(``, `(?=[^\w\-\:])`, `module`, `submodule`), Keyword, nil},
+			//MODULE_HEADER_STMT_KEYWORDS
+			{Words(``, `(?=[^\w\-\:])`, `belongs-to`, `namespace`, `prefix`, `yang-version`), Keyword, nil},
+			//META_STMT_KEYWORDS
+			{Words(``, `(?=[^\w\-\:])`, `contact`, `description`, `organization`, `reference`, `revision`), Keyword, nil},
+			//LINKAGE_STMTS_KEYWORDS
+			{Words(``, `(?=[^\w\-\:])`, `import`, `include`, `revision-date`), Keyword, nil},
+			//BODY_STMT_KEYWORDS
+			{Words(``, `(?=[^\w\-\:])`, `action`, `argument`, `augment`, `deviation`, `extension`, `feature`, `grouping`, `identity`, `if-feature`, `input`, `notification`, `output`, `rpc`, `typedef`), Keyword, nil},
+			//DATA_DEF_STMT_KEYWORDS
+			{Words(``, `(?=[^\w\-\:])`, `anydata`, `anyxml`, `case`, `choice`, `config`, `container`, `deviate`, `leaf`, `leaf-list`, `list`, `must`, `presence`, `refine`, `uses`, `when`), Keyword, nil},
+			//TYPE_STMT_KEYWORDS
+			{Words(``, `(?=[^\w\-\:])`, `base`, `bit`, `default`, `enum`, `error-app-tag`, `error-message`, `fraction-digits`, `length`, `max-elements`, `min-elements`, `modifier`, `ordered-by`, `path`, `pattern`, `position`, `range`, `require-instance`, `status`, `type`, `units`, `value`, `yin-element`), Keyword, nil},
+			//LIST_STMT_KEYWORDS
+			{Words(``, `(?=[^\w\-\:])`, `key`, `mandatory`, `unique`), Keyword, nil},
+
+			//CONSTANTS_KEYWORDS - RFC7950 other keywords
+			{Words(``, `(?=[^\w\-\:])`, `add`, `current`, `delete`, `deprecated`, `false`, `invert-match`, `max`, `min`, `not-supported`, `obsolete`, `replace`, `true`, `unbounded`, `user`), NameClass, nil},
+
+			//RFC7950 Built-In Types
+			{Words(``, `(?=[^\w\-\:])`, `binary`, `bits`, `boolean`, `decimal64`, `empty`, `enumeration`, `identityref`, `instance-identifier`, `int16`, `int32`, `int64`, `int8`, `leafref`, `string`, `uint16`, `uint32`, `uint64`, `uint8`, `union`), NameClass, nil},
+
+			{`[^;{}\s\'\"]+`, Text, nil},
+		},
+		"comments": {
+			{`[^*/]`, CommentMultiline, nil},
+			{`/\*`, CommentMultiline, Push("comment")},
+			{`\*/`, CommentMultiline, Pop(1)},
+			{`[*/]`, CommentMultiline, nil},
+		},
+	},
+))


Test patch:
diff --git a/lexers/testdata/yang.actual b/lexers/testdata/yang.actual
new file mode 100644
index 0000000..2751130
--- /dev/null
+++ b/lexers/testdata/yang.actual
@@ -0,0 +1,64 @@
+module server-system {
+    yang-version 1.1;
+    namespace "http://autlan.dt/gribok/yang/example";
+    prefix ex;
+
+    import ietf-yang-types {
+      prefix yang;
+      reference
+        "RFC 6991: Common YANG Data Types.";
+    }
+
+    organization "Gribok";
+    contact "gribok@example.org";
+    description
+        "An example module";
+
+    revision 2020-04-03 {
+        description "Example yang";
+    }
+
+    /*
+     * Comment for container system
+     */
+
+    container system {
+        leaf host-name {
+            type string;
+            description "Hostname for this system";
+        }
+
+        leaf-list domain-search {
+            type string;
+            description "List of domain names to search";
+        }
+
+        container login {
+            leaf message {
+                type string;
+                description
+                    "Message given at start of login session";
+            }
+
+            list user {
+                key "name";
+                leaf name {
+                    type string;
+                }
+                leaf uuid {
+                  type yang:uuid;
+                }
+                leaf full-name {
+                    type string;
+                    mandatory true;
+                    description
+                      "The full name of user  See also 'name'.  This could
+                       be, for example, a reference to the user name";
+                }
+                leaf class {
+                    type string;
+                }
+            }
+        }
+    }
+}
diff --git a/lexers/testdata/yang.expected b/lexers/testdata/yang.expected
new file mode 100644
index 0000000..e4d8baa
--- /dev/null
+++ b/lexers/testdata/yang.expected
@@ -0,0 +1,220 @@
+[
+  {"type":"Keyword","value":"module"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Text","value":"server-system"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"TextWhitespace","value":"\n    "},
+  {"type":"Keyword","value":"yang-version"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralNumberFloat","value":"1.1"},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n    "},
+  {"type":"Keyword","value":"namespace"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralStringDouble","value":"\"http://autlan.dt/gribok/yang/example\""},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n    "},
+  {"type":"Keyword","value":"prefix"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Text","value":"ex"},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n\n    "},
+  {"type":"Keyword","value":"import"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Text","value":"ietf-yang-types"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"TextWhitespace","value":"\n      "},
+  {"type":"Keyword","value":"prefix"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Text","value":"yang"},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n      "},
+  {"type":"Keyword","value":"reference"},
+  {"type":"TextWhitespace","value":"\n        "},
+  {"type":"LiteralStringDouble","value":"\"RFC 6991: Common YANG Data Types.\""},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n    "},
+  {"type":"Punctuation","value":"}"},
+  {"type":"TextWhitespace","value":"\n\n    "},
+  {"type":"Keyword","value":"organization"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralStringDouble","value":"\"Gribok\""},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n    "},
+  {"type":"Keyword","value":"contact"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralStringDouble","value":"\"gribok@example.org\""},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n    "},
+  {"type":"Keyword","value":"description"},
+  {"type":"TextWhitespace","value":"\n        "},
+  {"type":"LiteralStringDouble","value":"\"An example module\""},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n\n    "},
+  {"type":"Keyword","value":"revision"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralDate","value":"2020-04-03"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"TextWhitespace","value":"\n        "},
+  {"type":"Keyword","value":"description"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralStringDouble","value":"\"Example yang\""},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n    "},
+  {"type":"Punctuation","value":"}"},
+  {"type":"TextWhitespace","value":"\n\n    "},
+  {"type":"CommentMultiline","value":"/*\n     * Comment for container system\n     */"},
+  {"type":"TextWhitespace","value":"\n\n    "},
+  {"type":"Keyword","value":"container"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Text","value":"system"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"TextWhitespace","value":"\n        "},
+  {"type":"Keyword","value":"leaf"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Text","value":"host-name"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"TextWhitespace","value":"\n            "},
+  {"type":"Keyword","value":"type"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameClass","value":"string"},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n            "},
+  {"type":"Keyword","value":"description"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralStringDouble","value":"\"Hostname for this system\""},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n        "},
+  {"type":"Punctuation","value":"}"},
+  {"type":"TextWhitespace","value":"\n\n        "},
+  {"type":"Keyword","value":"leaf-list"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Text","value":"domain-search"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"TextWhitespace","value":"\n            "},
+  {"type":"Keyword","value":"type"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameClass","value":"string"},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n            "},
+  {"type":"Keyword","value":"description"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralStringDouble","value":"\"List of domain names to search\""},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n        "},
+  {"type":"Punctuation","value":"}"},
+  {"type":"TextWhitespace","value":"\n\n        "},
+  {"type":"Keyword","value":"container"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Text","value":"login"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"TextWhitespace","value":"\n            "},
+  {"type":"Keyword","value":"leaf"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Text","value":"message"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"TextWhitespace","value":"\n                "},
+  {"type":"Keyword","value":"type"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameClass","value":"string"},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n                "},
+  {"type":"Keyword","value":"description"},
+  {"type":"TextWhitespace","value":"\n                    "},
+  {"type":"LiteralStringDouble","value":"\"Message given at start of login session\""},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n            "},
+  {"type":"Punctuation","value":"}"},
+  {"type":"TextWhitespace","value":"\n\n            "},
+  {"type":"Keyword","value":"list"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameClass","value":"user"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"TextWhitespace","value":"\n                "},
+  {"type":"Keyword","value":"key"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"LiteralStringDouble","value":"\"name\""},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n                "},
+  {"type":"Keyword","value":"leaf"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Text","value":"name"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"TextWhitespace","value":"\n                    "},
+  {"type":"Keyword","value":"type"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameClass","value":"string"},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n                "},
+  {"type":"Punctuation","value":"}"},
+  {"type":"TextWhitespace","value":"\n                "},
+  {"type":"Keyword","value":"leaf"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Text","value":"uuid"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"TextWhitespace","value":"\n                  "},
+  {"type":"Keyword","value":"type"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"KeywordNamespace","value":"yang"},
+  {"type":"Punctuation","value":":"},
+  {"type":"Text","value":"uuid"},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n                "},
+  {"type":"Punctuation","value":"}"},
+  {"type":"TextWhitespace","value":"\n                "},
+  {"type":"Keyword","value":"leaf"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Text","value":"full-name"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"TextWhitespace","value":"\n                    "},
+  {"type":"Keyword","value":"type"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameClass","value":"string"},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n                    "},
+  {"type":"Keyword","value":"mandatory"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameClass","value":"true"},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n                    "},
+  {"type":"Keyword","value":"description"},
+  {"type":"TextWhitespace","value":"\n                      "},
+  {"type":"LiteralStringDouble","value":"\"The full name of user  See also 'name'.  This could\n                       be, for example, a reference to the user name\""},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n                "},
+  {"type":"Punctuation","value":"}"},
+  {"type":"TextWhitespace","value":"\n                "},
+  {"type":"Keyword","value":"leaf"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Text","value":"class"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"Punctuation","value":"{"},
+  {"type":"TextWhitespace","value":"\n                    "},
+  {"type":"Keyword","value":"type"},
+  {"type":"TextWhitespace","value":" "},
+  {"type":"NameClass","value":"string"},
+  {"type":"Punctuation","value":";"},
+  {"type":"TextWhitespace","value":"\n                "},
+  {"type":"Punctuation","value":"}"},
+  {"type":"TextWhitespace","value":"\n            "},
+  {"type":"Punctuation","value":"}"},
+  {"type":"TextWhitespace","value":"\n        "},
+  {"type":"Punctuation","value":"}"},
+  {"type":"TextWhitespace","value":"\n    "},
+  {"type":"Punctuation","value":"}"},
+  {"type":"TextWhitespace","value":"\n"},
+  {"type":"Punctuation","value":"}"},
+  {"type":"TextWhitespace","value":"\n"}
+]