Almirah 0.2.5 → 0.2.6
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/bin/almirah +4 -4
- data/lib/almirah/doc_fabric.rb +65 -65
- data/lib/almirah/doc_items/blockquote.rb +21 -21
- data/lib/almirah/doc_items/code_block.rb +26 -26
- data/lib/almirah/doc_items/controlled_paragraph.rb +112 -112
- data/lib/almirah/doc_items/controlled_table.rb +224 -224
- data/lib/almirah/doc_items/controlled_table_row.rb +22 -22
- data/lib/almirah/doc_items/doc_footer.rb +16 -16
- data/lib/almirah/doc_items/doc_item.rb +22 -22
- data/lib/almirah/doc_items/frontmatter.rb +9 -9
- data/lib/almirah/doc_items/heading.rb +93 -93
- data/lib/almirah/doc_items/image.rb +27 -27
- data/lib/almirah/doc_items/markdown_list.rb +156 -156
- data/lib/almirah/doc_items/markdown_table.rb +61 -61
- data/lib/almirah/doc_items/paragraph.rb +25 -25
- data/lib/almirah/doc_items/text_line.rb +296 -296
- data/lib/almirah/doc_items/todo_block.rb +21 -21
- data/lib/almirah/doc_parser.rb +378 -378
- data/lib/almirah/doc_types/base_document.rb +64 -64
- data/lib/almirah/doc_types/coverage.rb +95 -80
- data/lib/almirah/doc_types/index.rb +173 -173
- data/lib/almirah/doc_types/persistent_document.rb +17 -17
- data/lib/almirah/doc_types/protocol.rb +24 -24
- data/lib/almirah/doc_types/specification.rb +67 -67
- data/lib/almirah/doc_types/traceability.rb +142 -142
- data/lib/almirah/dom/doc_section.rb +25 -25
- data/lib/almirah/dom/document.rb +78 -78
- data/lib/almirah/navigation_pane.rb +16 -16
- data/lib/almirah/project.rb +287 -287
- data/lib/almirah/project_configuration.rb +41 -41
- data/lib/almirah/project_template.rb +298 -298
- data/lib/almirah/project_utility.rb +52 -0
- data/lib/almirah/search/specifications_db.rb +79 -79
- data/lib/almirah/templates/css/main.css +300 -300
- data/lib/almirah/templates/css/search.css +40 -40
- data/lib/almirah/templates/page.html +42 -42
- data/lib/almirah/templates/scripts/main.js +111 -111
- data/lib/almirah/templates/scripts/orama_search.js +138 -138
- data/lib/almirah.rb +93 -58
- metadata +4 -3
data/lib/almirah/doc_parser.rb
CHANGED
@@ -1,378 +1,378 @@
|
|
1
|
-
require_relative 'doc_items/text_line'
|
2
|
-
require_relative 'doc_items/doc_item'
|
3
|
-
require_relative 'doc_items/heading'
|
4
|
-
require_relative 'doc_items/paragraph'
|
5
|
-
require_relative 'doc_items/blockquote'
|
6
|
-
require_relative 'doc_items/code_block'
|
7
|
-
require_relative 'doc_items/todo_block'
|
8
|
-
require_relative 'doc_items/controlled_paragraph'
|
9
|
-
require_relative 'doc_items/markdown_table'
|
10
|
-
require_relative 'doc_items/controlled_table'
|
11
|
-
require_relative 'doc_items/image'
|
12
|
-
require_relative 'doc_items/markdown_list'
|
13
|
-
require_relative 'doc_items/doc_footer'
|
14
|
-
require_relative 'doc_items/frontmatter'
|
15
|
-
|
16
|
-
class DocParser # rubocop:disable Metrics/ClassLength,Style/Documentation
|
17
|
-
def self.try_to_extract_frontmatter(doc, text_lines) # rubocop:disable Metrics/MethodLength
|
18
|
-
lines_to_remove = 0
|
19
|
-
frontmatter_lines = ''
|
20
|
-
if /^(-{3,})/.match(text_lines[0])
|
21
|
-
frontmatter_started = false
|
22
|
-
text_lines.each do |s|
|
23
|
-
lines_to_remove += 1
|
24
|
-
if /^(-{3,})/.match(s)
|
25
|
-
if frontmatter_started
|
26
|
-
doc.frontmatter = Frontmatter.new(frontmatter_lines)
|
27
|
-
frontmatter_started = false
|
28
|
-
break
|
29
|
-
else
|
30
|
-
frontmatter_started = true
|
31
|
-
end
|
32
|
-
elsif frontmatter_started
|
33
|
-
frontmatter_lines += s
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
text_lines.shift(lines_to_remove)
|
38
|
-
text_lines
|
39
|
-
end
|
40
|
-
|
41
|
-
def self.parse(doc, text_lines)
|
42
|
-
temp_md_table = nil
|
43
|
-
temp_md_list = nil
|
44
|
-
temp_code_block = nil
|
45
|
-
# restart section numbering for each new document
|
46
|
-
Heading.reset_global_section_number
|
47
|
-
# try to get frontmatter first
|
48
|
-
text_lines = try_to_extract_frontmatter(doc, text_lines)
|
49
|
-
# There is no document without heading
|
50
|
-
title = "#{doc.id}.md"
|
51
|
-
item = Heading.new(doc, title, 0)
|
52
|
-
doc.items.append(item)
|
53
|
-
doc.headings.append(item)
|
54
|
-
doc.title = title
|
55
|
-
# replace dummy title with extracted from frontmatter
|
56
|
-
if doc.frontmatter && (doc.frontmatter.parameters.key? 'title')
|
57
|
-
doc.title = doc.frontmatter.parameters['title']
|
58
|
-
doc.headings[0].text = doc.frontmatter.parameters['title']
|
59
|
-
end
|
60
|
-
# main loop
|
61
|
-
text_lines.each do |s|
|
62
|
-
if s.lstrip != ''
|
63
|
-
if res = /^(\#{1,})\s(.*)/.match(s) # Heading
|
64
|
-
|
65
|
-
temp_md_table = process_temp_table(doc, temp_md_table)
|
66
|
-
if temp_md_list
|
67
|
-
doc.items.append temp_md_list
|
68
|
-
temp_md_list = nil
|
69
|
-
end
|
70
|
-
|
71
|
-
level = res[1].length
|
72
|
-
value = res[2]
|
73
|
-
|
74
|
-
item = Heading.new(doc, value, level)
|
75
|
-
doc.items.append(item)
|
76
|
-
doc.headings.append(item)
|
77
|
-
|
78
|
-
elsif res = /^%\s(.*)/.match(s) # Pandoc Document Title
|
79
|
-
|
80
|
-
title = res[1]
|
81
|
-
|
82
|
-
# Rewrite
|
83
|
-
doc.title = title
|
84
|
-
doc.headings[0].text = title
|
85
|
-
|
86
|
-
elsif res = /^\[(\S*)\]\s+(.*)/.match(s) # Controlled Paragraph
|
87
|
-
|
88
|
-
temp_md_table = process_temp_table(doc, temp_md_table)
|
89
|
-
if temp_md_list
|
90
|
-
doc.items.append temp_md_list
|
91
|
-
temp_md_list = nil
|
92
|
-
end
|
93
|
-
|
94
|
-
id = res[1].upcase
|
95
|
-
text = res[2]
|
96
|
-
up_links = nil
|
97
|
-
|
98
|
-
# check if it contains the uplink (one or many)
|
99
|
-
# TODO: check this regular expression
|
100
|
-
first_pos = text.length # for trailing commas
|
101
|
-
tmp = text.scan(/(>\[(?>[^\[\]]|\g<0>)*\])/) # >[SRS-001], >[SYS-002]
|
102
|
-
if tmp.length > 0
|
103
|
-
up_links = []
|
104
|
-
tmp.each do |ul|
|
105
|
-
lnk = ul[0]
|
106
|
-
# do not add links for the self document
|
107
|
-
doc_id = /([a-zA-Z]+)-\d+/.match(lnk) # SRS
|
108
|
-
up_links << lnk.upcase if doc_id and (doc_id[1].downcase != doc.id.downcase)
|
109
|
-
# try to find the real end of text
|
110
|
-
pos = text.index(lnk)
|
111
|
-
first_pos = pos if pos < first_pos
|
112
|
-
# remove uplink from text
|
113
|
-
text = text.split(lnk, 1).join('')
|
114
|
-
end
|
115
|
-
# remove trailing commas and spaces
|
116
|
-
if text.length > first_pos
|
117
|
-
first_pos -= 1
|
118
|
-
text = text[0..first_pos].strip
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
# since we already know id and text
|
123
|
-
item = ControlledParagraph.new(doc, text, id)
|
124
|
-
|
125
|
-
if up_links
|
126
|
-
up_links.uniq! # remove duplicates
|
127
|
-
doc.items_with_uplinks_number += 1 # for statistics
|
128
|
-
up_links.each do |ul|
|
129
|
-
next unless tmp = />\[(\S*)\]$/.match(ul) # >[SRS-001]
|
130
|
-
|
131
|
-
up_link_id = tmp[1]
|
132
|
-
|
133
|
-
item.up_link_ids = [] unless item.up_link_ids
|
134
|
-
|
135
|
-
item.up_link_ids.append(up_link_id)
|
136
|
-
|
137
|
-
if tmp = /^([a-zA-Z]+)-\d+/.match(up_link_id) # SRS
|
138
|
-
doc.up_link_docs[tmp[1].downcase.to_s] = tmp[1].downcase # multiple documents could be up-linked
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
doc.items.append(item)
|
144
|
-
# for statistics
|
145
|
-
if doc.dictionary.has_key?(id.to_s)
|
146
|
-
doc.duplicated_ids_number += 1
|
147
|
-
doc.duplicates_list.append(item)
|
148
|
-
else
|
149
|
-
doc.dictionary[id.to_s] = item # for fast search
|
150
|
-
end
|
151
|
-
doc.controlled_items.append(item) # for fast search
|
152
|
-
|
153
|
-
# for statistics
|
154
|
-
n = /\d+/.match(id)[0].to_i
|
155
|
-
if n > doc.last_used_id_number
|
156
|
-
doc.last_used_id = id
|
157
|
-
doc.last_used_id_number = n
|
158
|
-
end
|
159
|
-
|
160
|
-
elsif res = /^!\[(.*)\]\((.*)\)/.match(s) # Image
|
161
|
-
|
162
|
-
temp_md_table = process_temp_table(doc, temp_md_table)
|
163
|
-
if temp_md_list
|
164
|
-
doc.items.append temp_md_list
|
165
|
-
temp_md_list = nil
|
166
|
-
end
|
167
|
-
|
168
|
-
img_text = res[1]
|
169
|
-
img_path = res[2]
|
170
|
-
|
171
|
-
item = Image.new(img_text, img_path)
|
172
|
-
item.parent_doc = doc
|
173
|
-
item.parent_heading = doc.headings[-1]
|
174
|
-
|
175
|
-
doc.items.append(item)
|
176
|
-
|
177
|
-
elsif res = /^(\*\s+)(.*)/.match(s) # check if unordered list start
|
178
|
-
|
179
|
-
if doc.title == ''
|
180
|
-
# dummy section if root is not a Document Title (level 0)
|
181
|
-
title = "#{doc.id}.md"
|
182
|
-
item = Heading.new(doc, title, 0)
|
183
|
-
doc.items.append(item)
|
184
|
-
doc.headings.append(item)
|
185
|
-
doc.title = title
|
186
|
-
end
|
187
|
-
|
188
|
-
temp_md_table = process_temp_table(doc, temp_md_table)
|
189
|
-
|
190
|
-
row = res[2]
|
191
|
-
|
192
|
-
if temp_md_list
|
193
|
-
temp_md_list.add_row(s)
|
194
|
-
else
|
195
|
-
item = MarkdownList.new(doc, false)
|
196
|
-
item.add_row(s)
|
197
|
-
temp_md_list = item
|
198
|
-
end
|
199
|
-
|
200
|
-
elsif res = /^\d[.]\s(.*)/.match(s) # check if ordered list start
|
201
|
-
|
202
|
-
temp_md_table = process_temp_table(doc, temp_md_table)
|
203
|
-
|
204
|
-
row = res[1]
|
205
|
-
|
206
|
-
if temp_md_list
|
207
|
-
temp_md_list.add_row(s)
|
208
|
-
else
|
209
|
-
item = MarkdownList.new(doc, true)
|
210
|
-
item.add_row(s)
|
211
|
-
temp_md_list = item
|
212
|
-
end
|
213
|
-
|
214
|
-
elsif s[0] == '|' # check if table
|
215
|
-
|
216
|
-
if doc.title == ''
|
217
|
-
# dummy section if root is not a Document Title (level 0)
|
218
|
-
title = "#{doc.id}.md"
|
219
|
-
item = Heading.new(doc, title, 0)
|
220
|
-
doc.items.append(item)
|
221
|
-
doc.headings.append(item)
|
222
|
-
doc.title = title
|
223
|
-
end
|
224
|
-
|
225
|
-
if temp_md_list
|
226
|
-
doc.items.append temp_md_list
|
227
|
-
temp_md_list = nil
|
228
|
-
end
|
229
|
-
|
230
|
-
if res = /^[|](-{3,})[|]/.match(s) # check if it is a separator first
|
231
|
-
|
232
|
-
if temp_md_table
|
233
|
-
# separator is found after heading
|
234
|
-
temp_md_table.is_separator_detected = true
|
235
|
-
else
|
236
|
-
# separator out of table scope consider it just as a regular paragraph
|
237
|
-
item = Paragraph.new(doc, s)
|
238
|
-
doc.items.append(item)
|
239
|
-
end
|
240
|
-
|
241
|
-
elsif res = /^[|](.*[|])/.match(s) # check if it looks as a table row
|
242
|
-
|
243
|
-
row = res[1]
|
244
|
-
|
245
|
-
if temp_md_table
|
246
|
-
if temp_md_table.is_separator_detected # if there is a separator
|
247
|
-
# check if parent doc is a Protocol
|
248
|
-
if doc.instance_of? Protocol
|
249
|
-
# check if it is a controlled table
|
250
|
-
tmp = /(.*)\s+>\[(\S*)\]/.match(row)
|
251
|
-
if tmp && (temp_md_table.instance_of? MarkdownTable)
|
252
|
-
# this is not a regular Markdown table
|
253
|
-
# so the table type shall be changed and this row shall be passed one more time
|
254
|
-
temp_md_table = ControlledTable.new(doc, temp_md_table)
|
255
|
-
end
|
256
|
-
end
|
257
|
-
temp_md_table.add_row(row)
|
258
|
-
else
|
259
|
-
# replece table heading with regular paragraph
|
260
|
-
item = Paragraph.new(doc, temp_md_table.heading_row)
|
261
|
-
doc.items.append(item)
|
262
|
-
# and current row
|
263
|
-
item = Paragraph.new(doc, s)
|
264
|
-
doc.items.append(item)
|
265
|
-
temp_md_table = nil
|
266
|
-
end
|
267
|
-
else
|
268
|
-
# start table from heading
|
269
|
-
temp_md_table = MarkdownTable.new(doc, s)
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
|
-
elsif res = /^>(.*)/.match(s) # check if blockquote
|
274
|
-
|
275
|
-
temp_md_table = process_temp_table(doc, temp_md_table)
|
276
|
-
|
277
|
-
if temp_md_list
|
278
|
-
doc.items.append temp_md_list
|
279
|
-
temp_md_list = nil
|
280
|
-
end
|
281
|
-
|
282
|
-
item = Blockquote.new(res[1])
|
283
|
-
item.parent_doc = doc
|
284
|
-
item.parent_heading = doc.headings[-1]
|
285
|
-
doc.items.append(item)
|
286
|
-
|
287
|
-
elsif res = /^```(\w*)/.match(s) # check if code block
|
288
|
-
|
289
|
-
temp_md_table = process_temp_table(doc, temp_md_table)
|
290
|
-
if temp_md_list
|
291
|
-
doc.items.append temp_md_list
|
292
|
-
temp_md_list = nil
|
293
|
-
end
|
294
|
-
|
295
|
-
suggested_format = ''
|
296
|
-
suggested_format = res[1] if res.length == 2
|
297
|
-
|
298
|
-
if temp_code_block
|
299
|
-
# close already opened block
|
300
|
-
doc.items.append(temp_code_block)
|
301
|
-
temp_code_block = nil
|
302
|
-
else
|
303
|
-
# start code block
|
304
|
-
temp_code_block = CodeBlock.new(suggested_format)
|
305
|
-
temp_code_block.parent_doc = doc
|
306
|
-
temp_code_block.parent_heading = doc.headings[-1]
|
307
|
-
end
|
308
|
-
|
309
|
-
elsif res = /^TODO:(.*)/.match(s) # check if TODO block
|
310
|
-
|
311
|
-
temp_md_table = process_temp_table(doc, temp_md_table)
|
312
|
-
if temp_md_list
|
313
|
-
doc.items.append temp_md_list
|
314
|
-
temp_md_list = nil
|
315
|
-
end
|
316
|
-
|
317
|
-
text = '**TODO**: ' + res[1]
|
318
|
-
|
319
|
-
item = TodoBlock.new(text)
|
320
|
-
item.parent_doc = doc
|
321
|
-
item.parent_heading = doc.headings[-1]
|
322
|
-
doc.items.append(item)
|
323
|
-
doc.todo_blocks.append(item)
|
324
|
-
|
325
|
-
else # Reqular Paragraph
|
326
|
-
|
327
|
-
temp_md_table = process_temp_table(doc, temp_md_table)
|
328
|
-
if temp_md_list
|
329
|
-
if MarkdownList.unordered_list_item?(s) || MarkdownList.ordered_list_item?(s)
|
330
|
-
temp_md_list.add_row(s)
|
331
|
-
next
|
332
|
-
else
|
333
|
-
doc.items.append temp_md_list
|
334
|
-
temp_md_list = nil
|
335
|
-
end
|
336
|
-
end
|
337
|
-
if temp_code_block
|
338
|
-
temp_code_block.code_lines.append(s)
|
339
|
-
else
|
340
|
-
item = Paragraph.new(doc, s)
|
341
|
-
doc.items.append(item)
|
342
|
-
end
|
343
|
-
end
|
344
|
-
elsif temp_md_list
|
345
|
-
doc.items.append temp_md_list
|
346
|
-
temp_md_list = nil # lists are separated by emty line from each other
|
347
|
-
end
|
348
|
-
end
|
349
|
-
# Finalize non-closed elements
|
350
|
-
temp_md_table = process_temp_table(doc, temp_md_table)
|
351
|
-
if temp_md_list
|
352
|
-
doc.items.append temp_md_list
|
353
|
-
temp_md_list = nil
|
354
|
-
end
|
355
|
-
if temp_code_block
|
356
|
-
doc.items.append temp_code_block
|
357
|
-
temp_code_block = nil
|
358
|
-
end
|
359
|
-
# Add footer to close opened tables if any
|
360
|
-
item = DocFooter.new
|
361
|
-
item.parent_doc = doc
|
362
|
-
doc.items.append(item)
|
363
|
-
end
|
364
|
-
|
365
|
-
def self.process_temp_table(doc, temp_md_table)
|
366
|
-
if temp_md_table
|
367
|
-
if temp_md_table.is_separator_detected
|
368
|
-
doc.items.append temp_md_table
|
369
|
-
else # no separator
|
370
|
-
# replece table heading with regular paragraph
|
371
|
-
item = Paragraph.new(doc, temp_md_table.heading_row)
|
372
|
-
doc.items.append(item)
|
373
|
-
end
|
374
|
-
temp_md_table = nil
|
375
|
-
end
|
376
|
-
temp_md_table
|
377
|
-
end
|
378
|
-
end
|
1
|
+
require_relative 'doc_items/text_line'
|
2
|
+
require_relative 'doc_items/doc_item'
|
3
|
+
require_relative 'doc_items/heading'
|
4
|
+
require_relative 'doc_items/paragraph'
|
5
|
+
require_relative 'doc_items/blockquote'
|
6
|
+
require_relative 'doc_items/code_block'
|
7
|
+
require_relative 'doc_items/todo_block'
|
8
|
+
require_relative 'doc_items/controlled_paragraph'
|
9
|
+
require_relative 'doc_items/markdown_table'
|
10
|
+
require_relative 'doc_items/controlled_table'
|
11
|
+
require_relative 'doc_items/image'
|
12
|
+
require_relative 'doc_items/markdown_list'
|
13
|
+
require_relative 'doc_items/doc_footer'
|
14
|
+
require_relative 'doc_items/frontmatter'
|
15
|
+
|
16
|
+
class DocParser # rubocop:disable Metrics/ClassLength,Style/Documentation
|
17
|
+
def self.try_to_extract_frontmatter(doc, text_lines) # rubocop:disable Metrics/MethodLength
|
18
|
+
lines_to_remove = 0
|
19
|
+
frontmatter_lines = ''
|
20
|
+
if /^(-{3,})/.match(text_lines[0])
|
21
|
+
frontmatter_started = false
|
22
|
+
text_lines.each do |s|
|
23
|
+
lines_to_remove += 1
|
24
|
+
if /^(-{3,})/.match(s)
|
25
|
+
if frontmatter_started
|
26
|
+
doc.frontmatter = Frontmatter.new(frontmatter_lines)
|
27
|
+
frontmatter_started = false
|
28
|
+
break
|
29
|
+
else
|
30
|
+
frontmatter_started = true
|
31
|
+
end
|
32
|
+
elsif frontmatter_started
|
33
|
+
frontmatter_lines += s
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
text_lines.shift(lines_to_remove)
|
38
|
+
text_lines
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.parse(doc, text_lines)
|
42
|
+
temp_md_table = nil
|
43
|
+
temp_md_list = nil
|
44
|
+
temp_code_block = nil
|
45
|
+
# restart section numbering for each new document
|
46
|
+
Heading.reset_global_section_number
|
47
|
+
# try to get frontmatter first
|
48
|
+
text_lines = try_to_extract_frontmatter(doc, text_lines)
|
49
|
+
# There is no document without heading
|
50
|
+
title = "#{doc.id}.md"
|
51
|
+
item = Heading.new(doc, title, 0)
|
52
|
+
doc.items.append(item)
|
53
|
+
doc.headings.append(item)
|
54
|
+
doc.title = title
|
55
|
+
# replace dummy title with extracted from frontmatter
|
56
|
+
if doc.frontmatter && (doc.frontmatter.parameters.key? 'title')
|
57
|
+
doc.title = doc.frontmatter.parameters['title']
|
58
|
+
doc.headings[0].text = doc.frontmatter.parameters['title']
|
59
|
+
end
|
60
|
+
# main loop
|
61
|
+
text_lines.each do |s|
|
62
|
+
if s.lstrip != ''
|
63
|
+
if res = /^(\#{1,})\s(.*)/.match(s) # Heading
|
64
|
+
|
65
|
+
temp_md_table = process_temp_table(doc, temp_md_table)
|
66
|
+
if temp_md_list
|
67
|
+
doc.items.append temp_md_list
|
68
|
+
temp_md_list = nil
|
69
|
+
end
|
70
|
+
|
71
|
+
level = res[1].length
|
72
|
+
value = res[2]
|
73
|
+
|
74
|
+
item = Heading.new(doc, value, level)
|
75
|
+
doc.items.append(item)
|
76
|
+
doc.headings.append(item)
|
77
|
+
|
78
|
+
elsif res = /^%\s(.*)/.match(s) # Pandoc Document Title
|
79
|
+
|
80
|
+
title = res[1]
|
81
|
+
|
82
|
+
# Rewrite
|
83
|
+
doc.title = title
|
84
|
+
doc.headings[0].text = title
|
85
|
+
|
86
|
+
elsif res = /^\[(\S*)\]\s+(.*)/.match(s) # Controlled Paragraph
|
87
|
+
|
88
|
+
temp_md_table = process_temp_table(doc, temp_md_table)
|
89
|
+
if temp_md_list
|
90
|
+
doc.items.append temp_md_list
|
91
|
+
temp_md_list = nil
|
92
|
+
end
|
93
|
+
|
94
|
+
id = res[1].upcase
|
95
|
+
text = res[2]
|
96
|
+
up_links = nil
|
97
|
+
|
98
|
+
# check if it contains the uplink (one or many)
|
99
|
+
# TODO: check this regular expression
|
100
|
+
first_pos = text.length # for trailing commas
|
101
|
+
tmp = text.scan(/(>\[(?>[^\[\]]|\g<0>)*\])/) # >[SRS-001], >[SYS-002]
|
102
|
+
if tmp.length > 0
|
103
|
+
up_links = []
|
104
|
+
tmp.each do |ul|
|
105
|
+
lnk = ul[0]
|
106
|
+
# do not add links for the self document
|
107
|
+
doc_id = /([a-zA-Z]+)-\d+/.match(lnk) # SRS
|
108
|
+
up_links << lnk.upcase if doc_id and (doc_id[1].downcase != doc.id.downcase)
|
109
|
+
# try to find the real end of text
|
110
|
+
pos = text.index(lnk)
|
111
|
+
first_pos = pos if pos < first_pos
|
112
|
+
# remove uplink from text
|
113
|
+
text = text.split(lnk, 1).join('')
|
114
|
+
end
|
115
|
+
# remove trailing commas and spaces
|
116
|
+
if text.length > first_pos
|
117
|
+
first_pos -= 1
|
118
|
+
text = text[0..first_pos].strip
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# since we already know id and text
|
123
|
+
item = ControlledParagraph.new(doc, text, id)
|
124
|
+
|
125
|
+
if up_links
|
126
|
+
up_links.uniq! # remove duplicates
|
127
|
+
doc.items_with_uplinks_number += 1 # for statistics
|
128
|
+
up_links.each do |ul|
|
129
|
+
next unless tmp = />\[(\S*)\]$/.match(ul) # >[SRS-001]
|
130
|
+
|
131
|
+
up_link_id = tmp[1]
|
132
|
+
|
133
|
+
item.up_link_ids = [] unless item.up_link_ids
|
134
|
+
|
135
|
+
item.up_link_ids.append(up_link_id)
|
136
|
+
|
137
|
+
if tmp = /^([a-zA-Z]+)-\d+/.match(up_link_id) # SRS
|
138
|
+
doc.up_link_docs[tmp[1].downcase.to_s] = tmp[1].downcase # multiple documents could be up-linked
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
doc.items.append(item)
|
144
|
+
# for statistics
|
145
|
+
if doc.dictionary.has_key?(id.to_s)
|
146
|
+
doc.duplicated_ids_number += 1
|
147
|
+
doc.duplicates_list.append(item)
|
148
|
+
else
|
149
|
+
doc.dictionary[id.to_s] = item # for fast search
|
150
|
+
end
|
151
|
+
doc.controlled_items.append(item) # for fast search
|
152
|
+
|
153
|
+
# for statistics
|
154
|
+
n = /\d+/.match(id)[0].to_i
|
155
|
+
if n > doc.last_used_id_number
|
156
|
+
doc.last_used_id = id
|
157
|
+
doc.last_used_id_number = n
|
158
|
+
end
|
159
|
+
|
160
|
+
elsif res = /^!\[(.*)\]\((.*)\)/.match(s) # Image
|
161
|
+
|
162
|
+
temp_md_table = process_temp_table(doc, temp_md_table)
|
163
|
+
if temp_md_list
|
164
|
+
doc.items.append temp_md_list
|
165
|
+
temp_md_list = nil
|
166
|
+
end
|
167
|
+
|
168
|
+
img_text = res[1]
|
169
|
+
img_path = res[2]
|
170
|
+
|
171
|
+
item = Image.new(img_text, img_path)
|
172
|
+
item.parent_doc = doc
|
173
|
+
item.parent_heading = doc.headings[-1]
|
174
|
+
|
175
|
+
doc.items.append(item)
|
176
|
+
|
177
|
+
elsif res = /^(\*\s+)(.*)/.match(s) # check if unordered list start
|
178
|
+
|
179
|
+
if doc.title == ''
|
180
|
+
# dummy section if root is not a Document Title (level 0)
|
181
|
+
title = "#{doc.id}.md"
|
182
|
+
item = Heading.new(doc, title, 0)
|
183
|
+
doc.items.append(item)
|
184
|
+
doc.headings.append(item)
|
185
|
+
doc.title = title
|
186
|
+
end
|
187
|
+
|
188
|
+
temp_md_table = process_temp_table(doc, temp_md_table)
|
189
|
+
|
190
|
+
row = res[2]
|
191
|
+
|
192
|
+
if temp_md_list
|
193
|
+
temp_md_list.add_row(s)
|
194
|
+
else
|
195
|
+
item = MarkdownList.new(doc, false)
|
196
|
+
item.add_row(s)
|
197
|
+
temp_md_list = item
|
198
|
+
end
|
199
|
+
|
200
|
+
elsif res = /^\d[.]\s(.*)/.match(s) # check if ordered list start
|
201
|
+
|
202
|
+
temp_md_table = process_temp_table(doc, temp_md_table)
|
203
|
+
|
204
|
+
row = res[1]
|
205
|
+
|
206
|
+
if temp_md_list
|
207
|
+
temp_md_list.add_row(s)
|
208
|
+
else
|
209
|
+
item = MarkdownList.new(doc, true)
|
210
|
+
item.add_row(s)
|
211
|
+
temp_md_list = item
|
212
|
+
end
|
213
|
+
|
214
|
+
elsif s[0] == '|' # check if table
|
215
|
+
|
216
|
+
if doc.title == ''
|
217
|
+
# dummy section if root is not a Document Title (level 0)
|
218
|
+
title = "#{doc.id}.md"
|
219
|
+
item = Heading.new(doc, title, 0)
|
220
|
+
doc.items.append(item)
|
221
|
+
doc.headings.append(item)
|
222
|
+
doc.title = title
|
223
|
+
end
|
224
|
+
|
225
|
+
if temp_md_list
|
226
|
+
doc.items.append temp_md_list
|
227
|
+
temp_md_list = nil
|
228
|
+
end
|
229
|
+
|
230
|
+
if res = /^[|](-{3,})[|]/.match(s) # check if it is a separator first
|
231
|
+
|
232
|
+
if temp_md_table
|
233
|
+
# separator is found after heading
|
234
|
+
temp_md_table.is_separator_detected = true
|
235
|
+
else
|
236
|
+
# separator out of table scope consider it just as a regular paragraph
|
237
|
+
item = Paragraph.new(doc, s)
|
238
|
+
doc.items.append(item)
|
239
|
+
end
|
240
|
+
|
241
|
+
elsif res = /^[|](.*[|])/.match(s) # check if it looks as a table row
|
242
|
+
|
243
|
+
row = res[1]
|
244
|
+
|
245
|
+
if temp_md_table
|
246
|
+
if temp_md_table.is_separator_detected # if there is a separator
|
247
|
+
# check if parent doc is a Protocol
|
248
|
+
if doc.instance_of? Protocol
|
249
|
+
# check if it is a controlled table
|
250
|
+
tmp = /(.*)\s+>\[(\S*)\]/.match(row)
|
251
|
+
if tmp && (temp_md_table.instance_of? MarkdownTable)
|
252
|
+
# this is not a regular Markdown table
|
253
|
+
# so the table type shall be changed and this row shall be passed one more time
|
254
|
+
temp_md_table = ControlledTable.new(doc, temp_md_table)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
temp_md_table.add_row(row)
|
258
|
+
else
|
259
|
+
# replece table heading with regular paragraph
|
260
|
+
item = Paragraph.new(doc, temp_md_table.heading_row)
|
261
|
+
doc.items.append(item)
|
262
|
+
# and current row
|
263
|
+
item = Paragraph.new(doc, s)
|
264
|
+
doc.items.append(item)
|
265
|
+
temp_md_table = nil
|
266
|
+
end
|
267
|
+
else
|
268
|
+
# start table from heading
|
269
|
+
temp_md_table = MarkdownTable.new(doc, s)
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
elsif res = /^>(.*)/.match(s) # check if blockquote
|
274
|
+
|
275
|
+
temp_md_table = process_temp_table(doc, temp_md_table)
|
276
|
+
|
277
|
+
if temp_md_list
|
278
|
+
doc.items.append temp_md_list
|
279
|
+
temp_md_list = nil
|
280
|
+
end
|
281
|
+
|
282
|
+
item = Blockquote.new(res[1])
|
283
|
+
item.parent_doc = doc
|
284
|
+
item.parent_heading = doc.headings[-1]
|
285
|
+
doc.items.append(item)
|
286
|
+
|
287
|
+
elsif res = /^```(\w*)/.match(s) # check if code block
|
288
|
+
|
289
|
+
temp_md_table = process_temp_table(doc, temp_md_table)
|
290
|
+
if temp_md_list
|
291
|
+
doc.items.append temp_md_list
|
292
|
+
temp_md_list = nil
|
293
|
+
end
|
294
|
+
|
295
|
+
suggested_format = ''
|
296
|
+
suggested_format = res[1] if res.length == 2
|
297
|
+
|
298
|
+
if temp_code_block
|
299
|
+
# close already opened block
|
300
|
+
doc.items.append(temp_code_block)
|
301
|
+
temp_code_block = nil
|
302
|
+
else
|
303
|
+
# start code block
|
304
|
+
temp_code_block = CodeBlock.new(suggested_format)
|
305
|
+
temp_code_block.parent_doc = doc
|
306
|
+
temp_code_block.parent_heading = doc.headings[-1]
|
307
|
+
end
|
308
|
+
|
309
|
+
elsif res = /^TODO:(.*)/.match(s) # check if TODO block
|
310
|
+
|
311
|
+
temp_md_table = process_temp_table(doc, temp_md_table)
|
312
|
+
if temp_md_list
|
313
|
+
doc.items.append temp_md_list
|
314
|
+
temp_md_list = nil
|
315
|
+
end
|
316
|
+
|
317
|
+
text = '**TODO**: ' + res[1]
|
318
|
+
|
319
|
+
item = TodoBlock.new(text)
|
320
|
+
item.parent_doc = doc
|
321
|
+
item.parent_heading = doc.headings[-1]
|
322
|
+
doc.items.append(item)
|
323
|
+
doc.todo_blocks.append(item)
|
324
|
+
|
325
|
+
else # Reqular Paragraph
|
326
|
+
|
327
|
+
temp_md_table = process_temp_table(doc, temp_md_table)
|
328
|
+
if temp_md_list
|
329
|
+
if MarkdownList.unordered_list_item?(s) || MarkdownList.ordered_list_item?(s)
|
330
|
+
temp_md_list.add_row(s)
|
331
|
+
next
|
332
|
+
else
|
333
|
+
doc.items.append temp_md_list
|
334
|
+
temp_md_list = nil
|
335
|
+
end
|
336
|
+
end
|
337
|
+
if temp_code_block
|
338
|
+
temp_code_block.code_lines.append(s)
|
339
|
+
else
|
340
|
+
item = Paragraph.new(doc, s)
|
341
|
+
doc.items.append(item)
|
342
|
+
end
|
343
|
+
end
|
344
|
+
elsif temp_md_list
|
345
|
+
doc.items.append temp_md_list
|
346
|
+
temp_md_list = nil # lists are separated by emty line from each other
|
347
|
+
end
|
348
|
+
end
|
349
|
+
# Finalize non-closed elements
|
350
|
+
temp_md_table = process_temp_table(doc, temp_md_table)
|
351
|
+
if temp_md_list
|
352
|
+
doc.items.append temp_md_list
|
353
|
+
temp_md_list = nil
|
354
|
+
end
|
355
|
+
if temp_code_block
|
356
|
+
doc.items.append temp_code_block
|
357
|
+
temp_code_block = nil
|
358
|
+
end
|
359
|
+
# Add footer to close opened tables if any
|
360
|
+
item = DocFooter.new
|
361
|
+
item.parent_doc = doc
|
362
|
+
doc.items.append(item)
|
363
|
+
end
|
364
|
+
|
365
|
+
def self.process_temp_table(doc, temp_md_table)
|
366
|
+
if temp_md_table
|
367
|
+
if temp_md_table.is_separator_detected
|
368
|
+
doc.items.append temp_md_table
|
369
|
+
else # no separator
|
370
|
+
# replece table heading with regular paragraph
|
371
|
+
item = Paragraph.new(doc, temp_md_table.heading_row)
|
372
|
+
doc.items.append(item)
|
373
|
+
end
|
374
|
+
temp_md_table = nil
|
375
|
+
end
|
376
|
+
temp_md_table
|
377
|
+
end
|
378
|
+
end
|