junoser 0.7.6 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/Gemfile.lock +1 -1
- data/README.md +2 -1
- data/Rakefile +6 -9
- data/exe/junoser +1 -2
- data/exe/junoser-squash +1 -2
- data/lib/junoser/js_ruler.rb +56 -16
- data/lib/junoser/parser.rb +9201 -5650
- data/lib/junoser/ruler.rb +8 -2
- data/lib/junoser/version.rb +1 -1
- data/lib/junoser/xsd/base.rb +2 -2
- data/lib/junoser/xsd/choice.rb +25 -2
- data/lib/junoser/xsd/sequence.rb +3 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 15ee47f89643f4f98a2382fd8be31c3a4758daf9ce84b0da6e1df20eaac1f90f
|
|
4
|
+
data.tar.gz: 1dbdef198298e901d75b43659427084dd6e6a3f701450d890fde32d51def2c65
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c8eff73a8e20c78062db8a30c8330d00ac919b7d16649139c92dbfee2e5c46d53638d697cafbcae8cfa9ba1a2bcac1be0aa5fa9a27cbd8cef1f7e6c51e2ada59
|
|
7
|
+
data.tar.gz: 59c3a183983e42497adb6534faf85582267adcbe5186739e802e43c8766c25cec32a34adf4647de4b05d87ad68352879bf170cd5b807d04054dff7f50285358e
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
## [0.8.0] - 2026-10-17
|
|
2
|
+
|
|
3
|
+
### Added
|
|
4
|
+
|
|
5
|
+
* Recreate parser based on MX 23.4R2-S7.4 xsd
|
|
6
|
+
* Newly supported syntax
|
|
7
|
+
* "mld-snooping vlan all disable"
|
|
8
|
+
* "poe fpc xxx"
|
|
9
|
+
* "chassis alarm fru-absence ignore fpc xxx pem xxx"
|
|
10
|
+
* "ethernet-switching-options voip interface xxx"
|
|
11
|
+
* Positional arguments of a choice
|
|
12
|
+
* "protocols mpls label-switched-path xxx priority xxx xxx"
|
|
13
|
+
* "routing-options aggregate route xxx as-path aggregator xxx xxx"
|
|
14
|
+
|
|
15
|
+
|
|
1
16
|
## [0.7.6] - 2026-10-01
|
|
2
17
|
|
|
3
18
|
### Fixed
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# Junoser
|
|
2
2
|
|
|
3
|
-
[](https://github.com/codeout/junoser/actions/workflows/test.yaml)
|
|
4
|
+
[](https://github.com/codeout/junoser/actions/workflows/lint.yaml)
|
|
4
5
|
[](http://inch-ci.org/github/codeout/junoser)
|
|
5
6
|
|
|
6
7
|
Junoser is a JUNOS configuration PEG parser which can be automatically generated from Juniper's netconf.xsd. (XML Schema Definition for NETCONF)
|
data/Rakefile
CHANGED
|
@@ -3,22 +3,19 @@
|
|
|
3
3
|
require 'bundler/gem_tasks'
|
|
4
4
|
require 'junoser/development'
|
|
5
5
|
require 'nokogiri'
|
|
6
|
-
require 'pathname'
|
|
7
6
|
require 'rake/testtask'
|
|
8
7
|
|
|
9
|
-
xsd_path = File.join(__dir__, 'tmp/junos-system-
|
|
8
|
+
xsd_path = File.join(__dir__, 'tmp/junos-system-23.4.xsd')
|
|
10
9
|
rule_path = File.join(__dir__, 'tmp/rule.rb')
|
|
11
10
|
ruby_parser_path = File.join(__dir__, 'lib/junoser/parser.rb')
|
|
12
11
|
js_parser_path = File.join(__dir__, 'tmp/junos.js')
|
|
13
12
|
|
|
14
13
|
def open_files(input, output)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
i.close
|
|
21
|
-
o.close
|
|
14
|
+
File.open(input) do |i|
|
|
15
|
+
File.open(output, 'w') do |o|
|
|
16
|
+
yield i, o
|
|
17
|
+
end
|
|
18
|
+
end
|
|
22
19
|
end
|
|
23
20
|
|
|
24
21
|
def move_wildcards(element)
|
data/exe/junoser
CHANGED
data/exe/junoser-squash
CHANGED
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
require 'English'
|
|
5
5
|
require 'optparse'
|
|
6
|
-
require 'pathname'
|
|
7
6
|
|
|
8
|
-
$LOAD_PATH << File.expand_path('../../lib',
|
|
7
|
+
$LOAD_PATH << File.expand_path('../../lib', File.realpath(__FILE__))
|
|
9
8
|
require 'junoser/squash'
|
|
10
9
|
|
|
11
10
|
command = :squash
|
data/lib/junoser/js_ruler.rb
CHANGED
|
@@ -77,6 +77,7 @@ module Junoser
|
|
|
77
77
|
|
|
78
78
|
def process_line(str)
|
|
79
79
|
str = remove_undefined_variables(str)
|
|
80
|
+
str = process_placeholder_syntax(str)
|
|
80
81
|
str = process_common_syntax(str)
|
|
81
82
|
str = process_argument_syntax(str)
|
|
82
83
|
str = process_structural_syntax(str)
|
|
@@ -90,6 +91,20 @@ module Junoser
|
|
|
90
91
|
|
|
91
92
|
# "$junos-interface-unit" |
|
|
92
93
|
str.gsub!(/"\$[\w-]+" \| /, '')
|
|
94
|
+
# | "$junos-pon-id-interface-set-name" (this one trails the other members)
|
|
95
|
+
str.gsub!(/ \| "\$[\w-]+"/, '')
|
|
96
|
+
|
|
97
|
+
str
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def process_placeholder_syntax(str)
|
|
101
|
+
# The .xsd puts a placeholder name where an argument belongs, so the parser would accept only that word.
|
|
102
|
+
# Ruler does the same.
|
|
103
|
+
str.gsub!(/\((.*) \| "name"\)/) { "(#{$1} | arg)" }
|
|
104
|
+
str.gsub!(/\("name" \| (.*?)\)/) { "(#{$1} | arg)" }
|
|
105
|
+
str.gsub! '"vlan" ("all" | "vlan-name")', '"vlan" ("all" | arg)'
|
|
106
|
+
str.gsub! '("all" | "fpc-slot-number")', '("all" | arg)'
|
|
107
|
+
str.gsub! '("all" | "psu-slot-number")', '("all" | arg)'
|
|
93
108
|
|
|
94
109
|
str
|
|
95
110
|
end
|
|
@@ -134,19 +149,27 @@ module Junoser
|
|
|
134
149
|
# "foo" arg ( -> "foo(arg)": {
|
|
135
150
|
str.gsub!(/^(\s*)"(\S+)" arg \(/) { "#{$1}\"#{$2}(arg)\": {" }
|
|
136
151
|
|
|
137
|
-
# "foo" (
|
|
138
|
-
str.gsub!(%r{^(\s*)"(\S+)" \(.* \| arg
|
|
152
|
+
# "foo" ("bar" | arg) /* doc */ -> "foo | doc": ["bar", "arg"]
|
|
153
|
+
str.gsub!(%r{^(\s*)"(\S+)" \((.* \| arg ?.*)\) /\* (.*) \*/(,?)$}) do
|
|
154
|
+
"#{$1}\"#{$2} | #{$4}\": #{array_members($3)}#{$5}"
|
|
155
|
+
end
|
|
139
156
|
|
|
140
|
-
# "foo" (
|
|
141
|
-
str.gsub!(%r{^(\s*)"(\S+)" \(.* \| arg
|
|
142
|
-
|
|
143
|
-
|
|
157
|
+
# "foo" ("bar" | arg) ( /* doc */ -> "foo(bar|arg) | doc": {
|
|
158
|
+
str.gsub!(%r{^(\s*)"(\S+)" \((.* \| arg ?.*)\) \( /\* (.*) \*/$}) do
|
|
159
|
+
"#{$1}\"#{$2}(#{pipe_members($3)}) | #{$4}\": {"
|
|
160
|
+
end
|
|
161
|
+
# "foo" ("bar" | arg) ( -> "foo(bar|arg)": {
|
|
162
|
+
str.gsub!(/^(\s*)"(\S+)" \((.* \| arg ?.*)\) \($/) { "#{$1}\"#{$2}(#{pipe_members($3)})\": {" }
|
|
144
163
|
|
|
145
|
-
# "foo" (arg |
|
|
146
|
-
str.gsub!(%r{^(\s*)"(\S+)" \(arg
|
|
164
|
+
# "foo" (arg | "bar") /* doc */ -> "foo | doc": ["arg", "bar"]
|
|
165
|
+
str.gsub!(%r{^(\s*)"(\S+)" \((arg ?.*)\) /\* (.*) \*/(,?)$}) do
|
|
166
|
+
"#{$1}\"#{$2} | #{$4}\": #{array_members($3)}#{$5}"
|
|
167
|
+
end
|
|
147
168
|
|
|
148
|
-
# "foo" (arg |
|
|
149
|
-
str.gsub!(%r{^(\s*)"(\S+)" \(arg
|
|
169
|
+
# "foo" (arg | "bar") ( /* doc */ -> "foo(arg|bar) | doc": {
|
|
170
|
+
str.gsub!(%r{^(\s*)"(\S+)" \((arg ?.*)\) \( /\* (.*) \*/(,?)$}) do
|
|
171
|
+
"#{$1}\"#{$2}(#{pipe_members($3)}) | #{$4}\": {#{$5}"
|
|
172
|
+
end
|
|
150
173
|
|
|
151
174
|
# "foo" ("bar" | "baz") ( /* doc */ -> "foo(bar|baz)": {
|
|
152
175
|
str.gsub!(%r{^(\s*)"(\S+)" \("([^)]+)"\) \( /\* (.*) \*/$}) do
|
|
@@ -182,9 +205,6 @@ module Junoser
|
|
|
182
205
|
# "foo" ( -> "foo": (opts) => {
|
|
183
206
|
str.gsub!(/^(\s*)"(\S+)" \($/) { "#{$1}\"#{$2}\": {" }
|
|
184
207
|
|
|
185
|
-
# "foo" arg ( /* doc */ -> "foo | doc": (opts) => {
|
|
186
|
-
str.gsub!(%r{^(\s*)"(\S+)" arg \( /\* (.*) \*/}) { "#{$1}\"#{$2} | #{$3}\": {" }
|
|
187
|
-
|
|
188
208
|
str
|
|
189
209
|
end
|
|
190
210
|
|
|
@@ -208,8 +228,13 @@ module Junoser
|
|
|
208
228
|
# enum(("bar" | "baz")) -> "foo": new Enumeration(["bar", "baz"])
|
|
209
229
|
str.gsub!(/^(\s*)enum\(\((.*)\)\)/) { "#{$1}new Enumeration(#{$2.gsub('"', '').split(' | ')})" }
|
|
210
230
|
|
|
211
|
-
# (arg | "foo") -> ["arg", "foo"]
|
|
212
|
-
|
|
231
|
+
# (arg | "foo" | "bar") -> ["arg", "foo", "bar"]
|
|
232
|
+
# capture the tail as a whole, because a repeated group keeps only its last match
|
|
233
|
+
str.gsub!(/^(\s*) \(arg((?: \| "[^"]+")+)\)/) do
|
|
234
|
+
indent = $1
|
|
235
|
+
members = ['"arg"'] + $2.scan(/"[^"]+"/)
|
|
236
|
+
"#{indent}[#{members.uniq.join(', ')}]"
|
|
237
|
+
end
|
|
213
238
|
|
|
214
239
|
str
|
|
215
240
|
end
|
|
@@ -261,6 +286,21 @@ module Junoser
|
|
|
261
286
|
str
|
|
262
287
|
end
|
|
263
288
|
|
|
289
|
+
# Join the members of a choice with a pipe, for the parentheses of a key: "all" | arg -> all|arg.
|
|
290
|
+
# Keep the keywords next to arg, because vscode-junos offers every member as a completion candidate.
|
|
291
|
+
def pipe_members(choice)
|
|
292
|
+
choice.gsub('"', '').split(' | ').join('|')
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
# Put the members of a choice in an array, for a value. A lone arg stays a scalar, which is the shape
|
|
296
|
+
# loadString handles.
|
|
297
|
+
def array_members(choice)
|
|
298
|
+
list = choice.gsub('"', '').split(' | ')
|
|
299
|
+
return 'arg' if list == ['arg']
|
|
300
|
+
|
|
301
|
+
"[#{list.map { |member| %("#{member}") }.join(', ')}]"
|
|
302
|
+
end
|
|
303
|
+
|
|
264
304
|
def finalize(lines)
|
|
265
305
|
lines = balance_parenthesis(lines)
|
|
266
306
|
objectize_arg_of_s(lines)
|
|
@@ -292,7 +332,7 @@ module Junoser
|
|
|
292
332
|
lines.gsub!(/([{,]\n\s*)([^ "(]+)/m) { "#{$1}\"null_#{sequence}\": #{$2}" }
|
|
293
333
|
|
|
294
334
|
# "arg" -> "arg_1"
|
|
295
|
-
lines.gsub('"arg":') { %("arg_#{sequence}":) }
|
|
335
|
+
lines.gsub!('"arg":') { %("arg_#{sequence}":) }
|
|
296
336
|
|
|
297
337
|
conditional_groups(lines)
|
|
298
338
|
end
|