rsyntaxtree 2.0.0 → 2.1.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 +17 -0
- data/README.md +2 -2
- data/bin/rsyntaxtree +9 -2
- data/lib/rsyntaxtree/{lsif_graph.rb → json_graph.rb} +49 -13
- data/lib/rsyntaxtree/notation_core.md +1 -1
- data/lib/rsyntaxtree/version.rb +1 -1
- data/lib/rsyntaxtree.rb +18 -8
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 231de78b2e34e37f4a5bbccd641839e8cf5ae1babc2d8d4362d86dcf782d28b4
|
|
4
|
+
data.tar.gz: a4d04e71e6587592540400aa9a7e23d9dadae0d19912078d5d6cc5ebd65c117d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f97797690b6d8e0ad8404c00a10c061c89d2213e582915a33fc9d739305d5fb10cdd0afde6bffe0b16f504b5d5854d7dcb0249f50a22b10599638fb22180aed3
|
|
7
|
+
data.tar.gz: 7f5814cc9bf0875b21982cf6c143397d467fb900a7973c8f6213934387ba4f80e0605ddccec63f02bc7bacc6d182a9da1bda3237f909414ba4c64f63a1da1d12
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.1.0] - 2026-08-29
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
- The JSON output's format name is `json`: `-f json`, writing `syntree.json`.
|
|
7
|
+
The old name `lsif` collided with an established code-intelligence format
|
|
8
|
+
of the same initials, and called itself an interchange format when only
|
|
9
|
+
one tool had ever written or read it. It remains an accepted alias — the
|
|
10
|
+
CLI says so on stderr — until 3.0. The document now identifies itself in a
|
|
11
|
+
top-level `format` object (`name: "rsyntaxtree-json"`, schema 0.4.0) in
|
|
12
|
+
place of the `lsif` key.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- A feature matrix in the JSON output carries its rows: cells split on the
|
|
16
|
+
tab stops, rules as rows of their own, and a matrix inside a cell
|
|
17
|
+
recursing. It used to arrive as an empty segment marked "matrix", its
|
|
18
|
+
attribute-value pairs recoverable only by re-parsing the raw label.
|
|
19
|
+
|
|
3
20
|
## [2.0.0] - 2026-08-28
|
|
4
21
|
|
|
5
22
|
The removals announced in 1.10.0 and 1.12.0, and the fixes that came out of
|
data/README.md
CHANGED
|
@@ -69,7 +69,7 @@ Connect nodes with lines or arrows:
|
|
|
69
69
|
|
|
70
70
|
### Multiple Output Formats
|
|
71
71
|
|
|
72
|
-
Generate trees in PNG, SVG, PDF, TikZ, or
|
|
72
|
+
Generate trees in PNG, SVG, PDF, TikZ, or JSON format — the last carrying the laid-out tree as structured data.
|
|
73
73
|
|
|
74
74
|
## Web Interface
|
|
75
75
|
|
|
@@ -170,7 +170,7 @@ Usage:
|
|
|
170
170
|
| Option | Description | Default |
|
|
171
171
|
|--------|-------------|---------|
|
|
172
172
|
| `-o, --outdir` | Output directory | `./` |
|
|
173
|
-
| `-f, --format` | Output format: png, svg, pdf,
|
|
173
|
+
| `-f, --format` | Output format: png, svg, pdf, json, tikz | `png` |
|
|
174
174
|
| `-l, --leafstyle` | Leaf style: auto, triangle, bar, nothing | `auto` |
|
|
175
175
|
| `-n, --fontstyle` | Font style: sans, serif, cjk, mono | `sans` |
|
|
176
176
|
| `-s, --fontsize` | Font size: 6-26 | `16` |
|
data/bin/rsyntaxtree
CHANGED
|
@@ -9,7 +9,7 @@ require_relative '../lib/rsyntaxtree'
|
|
|
9
9
|
require_relative '../lib/rsyntaxtree/utils'
|
|
10
10
|
require_relative '../lib/rsyntaxtree/format_converter'
|
|
11
11
|
|
|
12
|
-
# "png, pdf, svg,
|
|
12
|
+
# "png, pdf, svg, json, or tikz" — built once from the library's
|
|
13
13
|
# own list so the three places that name the formats cannot drift apart.
|
|
14
14
|
FORMAT_LIST_MESSAGE = FORMATS.join(", ").sub(/, ([^,]+)\z/, ', or \1')
|
|
15
15
|
|
|
@@ -17,7 +17,7 @@ FORMAT_LIST_MESSAGE = FORMATS.join(", ").sub(/, ([^,]+)\z/, ', or \1')
|
|
|
17
17
|
CONFIG_VALIDATORS = {
|
|
18
18
|
outdir: ->(v) { FileTest.directory?(v) ? nil : "must be an existing directory path" },
|
|
19
19
|
outfilename: ->(v) { v.is_a?(String) ? nil : "must be a string" },
|
|
20
|
-
format: ->(v) { FORMATS.include?(v.to_s) ? nil : "must be #{FORMAT_LIST_MESSAGE}" },
|
|
20
|
+
format: ->(v) { FORMATS.include?(v.to_s) || v.to_s == "lsif" ? nil : "must be #{FORMAT_LIST_MESSAGE}" },
|
|
21
21
|
leafstyle: ->(v) { OPTION_VALUES[:leafstyle].include?(v.to_s) ? nil : "must be auto, triangle, bar, or nothing" },
|
|
22
22
|
fontstyle: ->(v) { OPTION_VALUES[:fontstyle].include?(v.to_s) ? nil : "must be sans, serif, cjk, or mono" },
|
|
23
23
|
fontsize: ->(v) { v.is_a?(Integer) && v >= 6 && v <= 26 ? nil : "must be in the range of 6-26" },
|
|
@@ -133,6 +133,13 @@ opts = Optimist.options do
|
|
|
133
133
|
opt :help, "This is a custom help message", short: :h
|
|
134
134
|
end
|
|
135
135
|
|
|
136
|
+
# The name the JSON format wore from 1.11.0 to 2.0.0. Accepted until 3.0,
|
|
137
|
+
# and said out loud, the way JPG and GIF were seen out.
|
|
138
|
+
if opts[:format] == "lsif"
|
|
139
|
+
warn "Warning: the format name 'lsif' is now 'json'. The old name will be removed in RSyntaxTree 3.0."
|
|
140
|
+
opts[:format] = "json"
|
|
141
|
+
end
|
|
142
|
+
|
|
136
143
|
Optimist.die :outdir, "must be an exsting directory path" unless FileTest.directory?(opts[:outdir])
|
|
137
144
|
Optimist.die :direction, "must be one of: #{OPTION_VALUES[:direction].join(', ')}" unless OPTION_VALUES[:direction].include?(opts[:direction])
|
|
138
145
|
Optimist.die :derivation, "must be one of: #{OPTION_VALUES[:derivation].join(', ')}" unless OPTION_VALUES[:derivation].include?(opts[:derivation])
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
#==========================
|
|
4
|
-
#
|
|
4
|
+
# json_graph.rb
|
|
5
5
|
#==========================
|
|
6
6
|
#
|
|
7
7
|
# Generates LSIF (Linguistic Structure Interchange Format) JSON output.
|
|
@@ -12,7 +12,7 @@ require_relative 'base_graph'
|
|
|
12
12
|
require_relative 'utils'
|
|
13
13
|
|
|
14
14
|
module RSyntaxTree
|
|
15
|
-
class
|
|
15
|
+
class JSONGraph < BaseGraph
|
|
16
16
|
attr_accessor :width, :height
|
|
17
17
|
|
|
18
18
|
def initialize(element_list, params, global)
|
|
@@ -30,7 +30,7 @@ module RSyntaxTree
|
|
|
30
30
|
@global = global
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
def
|
|
33
|
+
def json_data
|
|
34
34
|
metrics = parse_list
|
|
35
35
|
@width = metrics[:width] + @global[:h_gap_between_nodes] * 2
|
|
36
36
|
@height = metrics[:height] + @global[:height_connector_to_text] / 2
|
|
@@ -241,14 +241,7 @@ module RSyntaxTree
|
|
|
241
241
|
element.content.each do |l|
|
|
242
242
|
next unless l[:type] == :text
|
|
243
243
|
|
|
244
|
-
segments = l[:elements].map
|
|
245
|
-
next if e[:decoration].include?(:whitespace) && e[:text].strip.empty?
|
|
246
|
-
|
|
247
|
-
{
|
|
248
|
-
text: e[:text].gsub(WHITESPACE_BLOCK, " ").gsub('>', '>').gsub('<', '<'),
|
|
249
|
-
decorations: e[:decoration].map(&:to_s).reject { |d| d == "whitespace" }
|
|
250
|
-
}
|
|
251
|
-
end.compact
|
|
244
|
+
segments = l[:elements].map { |e| build_segment(e) }.compact
|
|
252
245
|
lines << { segments: segments } unless segments.empty?
|
|
253
246
|
end
|
|
254
247
|
|
|
@@ -258,6 +251,43 @@ module RSyntaxTree
|
|
|
258
251
|
}
|
|
259
252
|
end
|
|
260
253
|
|
|
254
|
+
def build_segment(run)
|
|
255
|
+
return nil if run[:decoration].include?(:whitespace) && run[:text].strip.empty?
|
|
256
|
+
|
|
257
|
+
segment = {
|
|
258
|
+
text: run[:text].gsub(WHITESPACE_BLOCK, " ").gsub('>', '>').gsub('<', '<'),
|
|
259
|
+
decorations: run[:decoration].map(&:to_s).reject { |d| d == "whitespace" }
|
|
260
|
+
}
|
|
261
|
+
# A feature matrix used to reach this document as an empty segment
|
|
262
|
+
# marked "matrix", its attribute-value pairs recoverable only by
|
|
263
|
+
# re-parsing the raw label — which is no way to score whether a model
|
|
264
|
+
# wrote CASE nom where CASE nom was wanted. The rows come through now:
|
|
265
|
+
# cells split on the tab stops, rules kept as rows of their own, a
|
|
266
|
+
# matrix inside a cell recursing.
|
|
267
|
+
segment[:matrix] = { rows: build_matrix_rows(run[:matrix]) } if run[:decoration].include?(:matrix) && run[:matrix]
|
|
268
|
+
segment
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def build_matrix_rows(matrix_lines)
|
|
272
|
+
matrix_lines.filter_map do |line|
|
|
273
|
+
case line[:type]
|
|
274
|
+
when :border then { rule: "single" }
|
|
275
|
+
when :bborder then { rule: "double" }
|
|
276
|
+
when :text
|
|
277
|
+
cells = [[]]
|
|
278
|
+
line[:elements].each do |run|
|
|
279
|
+
if run[:decoration].include?(:tabstop)
|
|
280
|
+
cells << []
|
|
281
|
+
else
|
|
282
|
+
segment = build_segment(run)
|
|
283
|
+
cells.last << segment if segment
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
{ cells: cells }
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
|
|
261
291
|
def map_enclosure(enclosure)
|
|
262
292
|
case enclosure
|
|
263
293
|
when :brackets then "brackets"
|
|
@@ -273,8 +303,14 @@ module RSyntaxTree
|
|
|
273
303
|
|
|
274
304
|
def build_json
|
|
275
305
|
data = {
|
|
276
|
-
|
|
277
|
-
|
|
306
|
+
# What this document is, said by a field rather than by the key, so a
|
|
307
|
+
# reader checks ["format"]["name"] and the key never has to change
|
|
308
|
+
# again. Documents up to schema 0.3.0 said it with a top-level "lsif"
|
|
309
|
+
# key instead — a name that collided with the code-intelligence
|
|
310
|
+
# format of the same initials.
|
|
311
|
+
format: {
|
|
312
|
+
name: "rsyntaxtree-json",
|
|
313
|
+
version: "0.4.0",
|
|
278
314
|
generator: "rsyntaxtree #{RSyntaxTree::VERSION}",
|
|
279
315
|
level: "rendered"
|
|
280
316
|
},
|
|
@@ -87,7 +87,7 @@ Options (the command line spells them --like-this):
|
|
|
87
87
|
|
|
88
88
|
| option | what it decides |
|
|
89
89
|
|------------|-----------------|
|
|
90
|
-
| format | png, svg, pdf, tikz,
|
|
90
|
+
| format | png, svg, pdf, tikz, json (the tree as structured data) |
|
|
91
91
|
| fontstyle | sans, serif, mono, cjk |
|
|
92
92
|
| fontsize | 6–26 |
|
|
93
93
|
| color | modern, traditional, off, gray |
|
data/lib/rsyntaxtree/version.rb
CHANGED
data/lib/rsyntaxtree.rb
CHANGED
|
@@ -34,12 +34,12 @@ WHITESPACE_BLOCK = "■"
|
|
|
34
34
|
# Every format the library can produce, and the file extension each one
|
|
35
35
|
# writes. The CLI builds its --format validation, help text, and output
|
|
36
36
|
# filename from these, so a new format is added here and nowhere else.
|
|
37
|
-
FORMATS = %w[png pdf svg
|
|
37
|
+
FORMATS = %w[png pdf svg json tikz].freeze
|
|
38
38
|
FORMAT_EXTENSIONS = {
|
|
39
39
|
"png" => "png",
|
|
40
40
|
"pdf" => "pdf",
|
|
41
41
|
"svg" => "svg",
|
|
42
|
-
"
|
|
42
|
+
"json" => "json",
|
|
43
43
|
"tikz" => "tex" # forest code, to be included in a LaTeX document
|
|
44
44
|
}.freeze
|
|
45
45
|
|
|
@@ -51,7 +51,10 @@ FORMAT_EXTENSIONS = {
|
|
|
51
51
|
# purpose (see switched_on?); unknown keys are not rejected, because callers
|
|
52
52
|
# pass their own extra parameters through.
|
|
53
53
|
OPTION_VALUES = {
|
|
54
|
-
format
|
|
54
|
+
# lsif is the name the JSON format wore from 1.11.0 to 2.0.0, accepted as
|
|
55
|
+
# an alias until 3.0. It collided with a code-intelligence format of the
|
|
56
|
+
# same initials, and claimed an interchange nobody else had implemented.
|
|
57
|
+
format: FORMATS + ["lsif"],
|
|
55
58
|
leafstyle: %w[auto triangle bar nothing],
|
|
56
59
|
fontstyle: ["sans", "serif", "cjk", "mono", "noto-sans", "noto-serif", "noto-sans-mono", "cjk zenhei"],
|
|
57
60
|
color: %w[modern traditional gray grey off none on true false],
|
|
@@ -152,7 +155,7 @@ require_relative 'rsyntaxtree/utils'
|
|
|
152
155
|
require_relative 'rsyntaxtree/element'
|
|
153
156
|
require_relative 'rsyntaxtree/elementlist'
|
|
154
157
|
require_relative 'rsyntaxtree/svg_graph'
|
|
155
|
-
require_relative 'rsyntaxtree/
|
|
158
|
+
require_relative 'rsyntaxtree/json_graph'
|
|
156
159
|
require_relative 'rsyntaxtree/tikz_generator'
|
|
157
160
|
require_relative 'rsyntaxtree/version'
|
|
158
161
|
require_relative 'rsyntaxtree/string_parser'
|
|
@@ -263,6 +266,8 @@ module RSyntaxTree
|
|
|
263
266
|
else
|
|
264
267
|
"off"
|
|
265
268
|
end
|
|
269
|
+
when :format
|
|
270
|
+
new_params[key] = value.to_s == "lsif" ? "json" : value.to_s
|
|
266
271
|
when :hyphen
|
|
267
272
|
new_params[key] = value.to_s == "literal" ? "literal" : "markup"
|
|
268
273
|
when :fontsize
|
|
@@ -461,7 +466,7 @@ module RSyntaxTree
|
|
|
461
466
|
case @params[:format]
|
|
462
467
|
when "png" then raster_surface_for(draw_svg, &:finish)
|
|
463
468
|
when "pdf" then pdf_surface_for(draw_svg, StringIO.new, &:finish)
|
|
464
|
-
when "
|
|
469
|
+
when "json" then draw_json
|
|
465
470
|
when "tikz" then draw_tikz
|
|
466
471
|
else draw_svg
|
|
467
472
|
end
|
|
@@ -535,11 +540,16 @@ module RSyntaxTree
|
|
|
535
540
|
graph.svg_data
|
|
536
541
|
end
|
|
537
542
|
|
|
538
|
-
def
|
|
543
|
+
def draw_json
|
|
539
544
|
sp = StringParser.new(@params[:data].gsub('&', '&'), @params[:fontset], @params[:fontsize], @global)
|
|
540
545
|
sp.parse
|
|
541
|
-
graph =
|
|
542
|
-
graph.
|
|
546
|
+
graph = JSONGraph.new(sp.get_elementlist, @params, @global)
|
|
547
|
+
graph.json_data
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
# The name the JSON output wore from 1.11.0 to 2.0.0; removed in 3.0.
|
|
551
|
+
def draw_lsif
|
|
552
|
+
draw_json
|
|
543
553
|
end
|
|
544
554
|
|
|
545
555
|
def draw_tikz(standalone: false, font: nil)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rsyntaxtree
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yoichiro Hasebe
|
|
@@ -126,7 +126,7 @@ files:
|
|
|
126
126
|
- lib/rsyntaxtree/element.rb
|
|
127
127
|
- lib/rsyntaxtree/elementlist.rb
|
|
128
128
|
- lib/rsyntaxtree/format_converter.rb
|
|
129
|
-
- lib/rsyntaxtree/
|
|
129
|
+
- lib/rsyntaxtree/json_graph.rb
|
|
130
130
|
- lib/rsyntaxtree/markup_parser.rb
|
|
131
131
|
- lib/rsyntaxtree/notation_core.md
|
|
132
132
|
- lib/rsyntaxtree/notation_examples.md
|