isodoc 1.0.22 → 1.0.27

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/macos.yml +12 -5
  3. data/.github/workflows/ubuntu.yml +27 -6
  4. data/.github/workflows/windows.yml +13 -7
  5. data/README.adoc +3 -2
  6. data/lib/isodoc-yaml/i18n-en.yaml +18 -1
  7. data/lib/isodoc-yaml/i18n-fr.yaml +18 -1
  8. data/lib/isodoc-yaml/i18n-zh-Hans.yaml +18 -1
  9. data/lib/isodoc/base_style/bands.scss +6 -3
  10. data/lib/isodoc/base_style/reset.scss +1 -1
  11. data/lib/isodoc/convert.rb +1 -0
  12. data/lib/isodoc/function/blocks.rb +5 -0
  13. data/lib/isodoc/function/cleanup.rb +12 -1
  14. data/lib/isodoc/function/i18n.rb +5 -5
  15. data/lib/isodoc/function/inline.rb +47 -12
  16. data/lib/isodoc/function/references.rb +47 -33
  17. data/lib/isodoc/function/reqt.rb +21 -6
  18. data/lib/isodoc/function/section.rb +18 -8
  19. data/lib/isodoc/function/table.rb +0 -1
  20. data/lib/isodoc/function/to_word_html.rb +4 -2
  21. data/lib/isodoc/function/utils.rb +10 -4
  22. data/lib/isodoc/function/xref_gen.rb +2 -1
  23. data/lib/isodoc/function/xref_sect_gen.rb +24 -24
  24. data/lib/isodoc/headlesshtml_convert.rb +5 -0
  25. data/lib/isodoc/html_convert.rb +5 -0
  26. data/lib/isodoc/html_function/footnotes.rb +2 -2
  27. data/lib/isodoc/html_function/html.rb +3 -0
  28. data/lib/isodoc/html_function/postprocess.rb +3 -2
  29. data/lib/isodoc/metadata.rb +30 -7
  30. data/lib/isodoc/metadata_date.rb +39 -0
  31. data/lib/isodoc/pdf_convert.rb +5 -0
  32. data/lib/isodoc/version.rb +1 -1
  33. data/lib/isodoc/word_convert.rb +5 -0
  34. data/lib/isodoc/word_function/body.rb +0 -4
  35. data/lib/isodoc/word_function/footnotes.rb +2 -2
  36. data/lib/isodoc/word_function/postprocess.rb +13 -2
  37. data/lib/isodoc/word_function/table.rb +1 -3
  38. data/lib/isodoc/xslfo_convert.rb +5 -0
  39. data/spec/isodoc/blocks_spec.rb +188 -8
  40. data/spec/isodoc/cleanup_spec.rb +181 -18
  41. data/spec/isodoc/i18n_spec.rb +12 -12
  42. data/spec/isodoc/inline_spec.rb +65 -5
  43. data/spec/isodoc/metadata_spec.rb +77 -2
  44. data/spec/isodoc/postproc_spec.rb +33 -11
  45. data/spec/isodoc/ref_spec.rb +12 -6
  46. data/spec/isodoc/section_spec.rb +220 -205
  47. data/spec/isodoc/table_spec.rb +24 -24
  48. data/spec/isodoc/terms_spec.rb +50 -6
  49. data/spec/isodoc/xref_spec.rb +64 -26
  50. metadata +3 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 889ed14c0177867afde418d7d947a4f5963dc533c3c61c0b2d4bd320a1bb02a3
4
- data.tar.gz: 8f9a41c95de57470b68cba90e890d8753c49a36ea7f33658a72877177b5a8aa2
3
+ metadata.gz: 68d6f17f0d5291c6c067bfc6a3a476885b80f128bdc9c4e3e3d8356c6af30482
4
+ data.tar.gz: 2710c48aa2fb9eeee44b586107b07884d52802a53fec81d69c0f3fb68fa988ed
5
5
  SHA512:
6
- metadata.gz: aee9f7048977dabef0312c23c94e7d41b242e7623f7ec5daa252db232250ff9bd150e7d4750ac0000aa8463f79a8a716910b0e7a6929a3949353bbfe268b7327
7
- data.tar.gz: 0be841a473792658efd1221ee01a9011e1744cbe3e9fd4e2d0657ac057f41c057aba67f52d0f712326af915b5df802fc2d352338255fd688b31c1867d6ffac36
6
+ metadata.gz: 1c38cb43027aa1a056d465660449a4a58e1a5b78474a5f0184fca4164f2af2480720329e5a7181fcc1731151ef15db71019aa9fc34175b779de517006bf85fa6
7
+ data.tar.gz: '09503b88edfb1db0b3def003bca81c356b40790014953a9bc08de680af8db75222ded714f43a1f6820ec30dbaa2e3f83ac2a5e386f3c757f0d639f086e0b4b2c'
@@ -1,21 +1,28 @@
1
- # Auto-generated !!! Do not edit it manually
2
- # use ci-master https://github.com/metanorma/metanorma-build-scripts
1
+ # Auto-generated by Cimas: Do not edit it manually!
2
+ # See https://github.com/metanorma/cimas
3
3
  name: macos
4
4
 
5
5
  on:
6
6
  push:
7
7
  branches: [ master ]
8
8
  pull_request:
9
- branches: [ '**' ]
9
+ paths-ignore:
10
+ - .github/workflows/ubuntu.yml
11
+ - .github/workflows/windows.yml
10
12
 
11
13
  jobs:
12
14
  test-macos:
13
15
  name: Test on Ruby ${{ matrix.ruby }} macOS
14
16
  runs-on: macos-latest
17
+ continue-on-error: ${{ matrix.experimental }}
15
18
  strategy:
16
19
  fail-fast: false
17
20
  matrix:
18
21
  ruby: [ '2.6', '2.5', '2.4' ]
22
+ experimental: [false]
23
+ include:
24
+ - ruby: '2.7'
25
+ experimental: true
19
26
  steps:
20
27
  - uses: actions/checkout@master
21
28
  - name: Use Ruby
@@ -30,10 +37,10 @@ jobs:
30
37
  - name: Use Node
31
38
  uses: actions/setup-node@v1
32
39
  with:
33
- node-version: '8'
40
+ node-version: '12'
34
41
  - name: Install Puppeteer
35
42
  run: |
36
- npm install -g puppeteer
43
+ npm install -g puppeteer@3.0.1
37
44
  - name: Run specs
38
45
  run: |
39
46
  bundle exec rake
@@ -1,21 +1,28 @@
1
- # Auto-generated !!! Do not edit it manually
2
- # use ci-master https://github.com/metanorma/metanorma-build-scripts
1
+ # Auto-generated by Cimas: Do not edit it manually!
2
+ # See https://github.com/metanorma/cimas
3
3
  name: ubuntu
4
4
 
5
5
  on:
6
6
  push:
7
7
  branches: [ master ]
8
8
  pull_request:
9
- branches: [ '**' ]
9
+ paths-ignore:
10
+ - .github/workflows/macos.yml
11
+ - .github/workflows/windows.yml
10
12
 
11
13
  jobs:
12
14
  test-linux:
13
15
  name: Test on Ruby ${{ matrix.ruby }} Ubuntu
14
16
  runs-on: ubuntu-latest
17
+ continue-on-error: ${{ matrix.experimental }}
15
18
  strategy:
16
19
  fail-fast: false
17
20
  matrix:
18
21
  ruby: [ '2.6', '2.5', '2.4' ]
22
+ experimental: [false]
23
+ include:
24
+ - ruby: '2.7'
25
+ experimental: true
19
26
  steps:
20
27
  - uses: actions/checkout@master
21
28
  - name: Use Ruby
@@ -25,15 +32,29 @@ jobs:
25
32
  architecture: 'x64'
26
33
  - name: Update gems
27
34
  run: |
28
- gem install bundler
35
+ gem install bundler
29
36
  bundle install --jobs 4 --retry 3
30
37
  - name: Use Node
31
38
  uses: actions/setup-node@v1
32
39
  with:
33
- node-version: '8'
40
+ node-version: '12'
34
41
  - name: Install Puppeteer
35
42
  run: |
36
- npm install -g puppeteer
43
+ sudo apt-get update
44
+ sudo apt-get install libgbm1
45
+ npm install -g puppeteer@3.0.1
37
46
  - name: Run specs
38
47
  run: |
39
48
  bundle exec rake
49
+ - name: Trigger dependent repositories
50
+ if: github.ref == 'refs/heads/master' && matrix.ruby == '2.6'
51
+ env:
52
+ GH_USERNAME: ${{ secrets.PAT_USERNAME }}
53
+ GH_ACCESS_TOKEN: ${{ secrets.PAT_TOKEN }}
54
+ run: |
55
+ curl -LO --retry 3 https://raw.githubusercontent.com/metanorma/metanorma-build-scripts/master/trigger-gh-actions.sh
56
+ [[ -f ".github/workflows/dependent_repos.env" ]] && source .github/workflows/dependent_repos.env
57
+ for repo in $DEPENDENT_REPOS
58
+ do
59
+ sh trigger-gh-actions.sh $ORGANISATION $repo $GH_USERNAME $GH_ACCESS_TOKEN $GITHUB_REPOSITORY
60
+ done
@@ -1,21 +1,28 @@
1
- # Auto-generated !!! Do not edit it manually
2
- # use ci-master https://github.com/metanorma/metanorma-build-scripts
1
+ # Auto-generated by Cimas: Do not edit it manually!
2
+ # See https://github.com/metanorma/cimas
3
3
  name: windows
4
4
 
5
5
  on:
6
6
  push:
7
7
  branches: [ master ]
8
8
  pull_request:
9
- branches: [ '**' ]
9
+ paths-ignore:
10
+ - .github/workflows/macos.yml
11
+ - .github/workflows/ubuntu.yml
10
12
 
11
13
  jobs:
12
14
  test-windows:
13
15
  name: Test on Ruby ${{ matrix.ruby }} Windows
14
16
  runs-on: windows-latest
17
+ continue-on-error: ${{ matrix.experimental }}
15
18
  strategy:
16
19
  fail-fast: false
17
20
  matrix:
18
21
  ruby: [ '2.6', '2.5', '2.4' ]
22
+ experimental: [false]
23
+ include:
24
+ - ruby: '2.7'
25
+ experimental: true
19
26
  steps:
20
27
  - uses: actions/checkout@master
21
28
  - name: Use Ruby
@@ -26,17 +33,16 @@ jobs:
26
33
  - name: Update gems
27
34
  shell: pwsh
28
35
  run: |
29
- gem install bundler
36
+ gem install bundler
30
37
  bundle config --local path vendor/bundle
31
- bundle update
32
38
  bundle install --jobs 4 --retry 3
33
39
  - name: Use Node
34
40
  uses: actions/setup-node@v1
35
41
  with:
36
- node-version: '8'
42
+ node-version: '12'
37
43
  - name: Install Puppeteer
38
44
  run: |
39
- npm install -g puppeteer
45
+ npm install -g puppeteer@3.0.1
40
46
  - name: Run specs
41
47
  run: |
42
48
  bundle exec rake
@@ -1,8 +1,9 @@
1
1
  = isodoc: Processor to generate HTML/Word from Metanorma XML
2
2
 
3
3
  image:https://img.shields.io/gem/v/isodoc.svg["Gem Version", link="https://rubygems.org/gems/isodoc"]
4
- image:https://travis-ci.com/metanorma/isodoc.svg["Build Status", link="https://travis-ci.com/metanorma/isodoc"]
5
- image:https://ci.appveyor.com/api/projects/status/f93bvu6qfwxij07x?svg=true["Appveyor Build Status", link="https://ci.appveyor.com/project/metanorma/isodoc"]
4
+ image:https://github.com/metanorma/isodoc/workflows/ubuntu/badge.svg["Ubuntu Build Status", link="https://github.com/metanorma/isodoc/actions?query=workflow%3Aubuntu"]
5
+ image:https://github.com/metanorma/isodoc/workflows/macos/badge.svg["OSX Build Status", link="https://github.com/metanorma/isodoc/actions?query=workflow%3Amacos"]
6
+ image:https://github.com/metanorma/isodoc/workflows/windows/badge.svg["Windows Build Status", link="https://github.com/metanorma/isodoc/actions?query=workflow%3Awindows"]
6
7
  image:https://codeclimate.com/github/metanorma/isodoc/badges/gpa.svg["Code Climate", link="https://codeclimate.com/github/metanorma/isodoc"]
7
8
  image:https://img.shields.io/github/issues-pr-raw/metanorma/isodoc.svg["Pull Requests", link="https://github.com/metanorma/isodoc/pulls"]
8
9
  image:https://img.shields.io/github/commits-since/metanorma/isodoc/latest.svg["Commits since latest",link="https://github.com/metanorma/isodoc/releases"]
@@ -6,7 +6,9 @@ introduction: Introduction
6
6
  foreword: Foreword
7
7
  abstract: Abstract
8
8
  termsdef: Terms and definitions
9
- termsdefsymbols: Terms, definitions, symbols and abbreviated terms
9
+ termsdefsymbolsabbrev: Terms, definitions, symbols and abbreviated terms
10
+ termsdefsymbols: Terms, definitions and symbols
11
+ termsdefabbrev: Terms, definitions and abbreviated terms
10
12
  normref: Normative references
11
13
  bibliography: Bibliography
12
14
  clause: Clause
@@ -55,6 +57,21 @@ deprecated: DEPRECATED
55
57
  source: SOURCE
56
58
  and: and
57
59
  all_parts: All Parts
60
+ month_january: January
61
+ month_february: February
62
+ month_march: March
63
+ month_april: April
64
+ month_may: May
65
+ month_june: June
66
+ month_july: July
67
+ month_august: August
68
+ month_september: September
69
+ month_october: October
70
+ month_november: November
71
+ month_december: December
72
+ obligation: Obligation
73
+ subject: Subject
74
+ inherits: Inherits
58
75
  admonition: {
59
76
  danger: Danger,
60
77
  warning: Warning,
@@ -6,7 +6,9 @@ introduction: Introduction
6
6
  foreword: Avant-propos
7
7
  abstract: Résumé
8
8
  termsdef: Terms et définitions
9
- termsdefsymbols: Terms, définitions, symboles et termes abrégés
9
+ termsdefsymbolsabbrev: Terms, définitions, symboles et termes abrégés
10
+ termsdefsymbols: Terms, définitions et symboles
11
+ termsdefabbrev: Terms, définitions et termes abrégés
10
12
  normref: Références normatives
11
13
  bibliography: Bibliographie
12
14
  clause: Article
@@ -48,6 +50,21 @@ deprecated: DÉCONSEILLÉ
48
50
  source: SOURCE
49
51
  and: et
50
52
  all_parts: toutes les parties
53
+ month_january: Janvier
54
+ month_february: Février
55
+ month_march: Mars
56
+ month_april: Avril
57
+ month_may: Mai
58
+ month_june: Juin
59
+ month_july: Juillet
60
+ month_august: Août
61
+ month_september: Septembre
62
+ month_october: Octobre
63
+ month_november: Novembre
64
+ month_december: Décembre
65
+ obligation: Obligation
66
+ subject: Sujet
67
+ inherits: Hérite
51
68
  admonition: {
52
69
  danger: Danger,
53
70
  warning: Avertissement,
@@ -6,7 +6,9 @@ introduction: 引言
6
6
  foreword: 前言
7
7
  abstract: 摘要
8
8
  termsdef: 术语和定义
9
- termsdefsymbols: 术语、定义、符号、代号和缩略语
9
+ termsdefsymbolsabbrev: 术语、定义、符号、代号和缩略语
10
+ termsdefsymbols: 术语、定义、符号和代号
11
+ termsdefabbrev: 术语、定义、符号和缩略语
10
12
  normref: 规范性引用文件
11
13
  bibliography: 参考文献
12
14
  clause: 条
@@ -50,6 +52,21 @@ deprecated: 被取代
50
52
  source: 定义
51
53
  and: 和
52
54
  all_parts: 所有部分
55
+ month_january: 一月
56
+ month_february: 二月
57
+ month_march: 三月
58
+ month_april: 四月
59
+ month_may: 五月
60
+ month_june: 六月
61
+ month_july: 七月
62
+ month_august: 八月
63
+ month_september: 九月
64
+ month_october: 十月
65
+ month_november: 十一月
66
+ month_december: 十二月
67
+ obligation: 义务
68
+ subject: 主体
69
+ inherits: 继承自
53
70
  admonition: {
54
71
  danger: 危险,
55
72
  warning: 警告,
@@ -7,7 +7,10 @@
7
7
  }
8
8
 
9
9
  font-weight: $fontWeight;
10
- height: $length;
10
+
11
+ @if $length {
12
+ height: $length;
13
+ }
11
14
 
12
15
  color: $color;
13
16
  text-transform: uppercase;
@@ -28,9 +31,9 @@
28
31
 
29
32
  @mixin docBand(
30
33
  $order,
31
- $textLength,
34
+ $textLength: null,
32
35
  $offset: 0,
33
- $color: white,
36
+ $color: white,
34
37
  $fontWeight: 400,
35
38
  $fontFamily: null) {
36
39
 
@@ -125,5 +125,5 @@ b, strong {
125
125
  }
126
126
 
127
127
  div.document-stage-band, div.document-type-band {
128
- background-color: #FFFFFF;
128
+ background-color: #333333;
129
129
  }
@@ -48,6 +48,7 @@ module IsoDoc
48
48
  @olstyle = options[:olstyle]
49
49
  @datauriimage = options[:datauriimage]
50
50
  @suppressheadingnumbers = options[:suppressheadingnumbers]
51
+ @break_up_urls_in_tables = options[:break_up_urls_in_tables] == "true"
51
52
  @termdomain = ""
52
53
  @termexample = false
53
54
  @note = false
@@ -222,5 +222,10 @@ module IsoDoc::Function
222
222
  quote_attribution(node, out)
223
223
  end
224
224
  end
225
+
226
+ def passthrough_parse(node, out)
227
+ return if node["format"] and !(node["format"].split(/,/).include? @format.to_s)
228
+ out.passthrough node.text
229
+ end
225
230
  end
226
231
  end
@@ -1,6 +1,7 @@
1
1
  module IsoDoc::Function
2
2
  module Cleanup
3
3
  def textcleanup(docxml)
4
+ docxml = passthrough_cleanup(docxml)
4
5
  docxml.
5
6
  gsub(/\[TERMREF\]\s*/, l10n("[#{@source_lbl}: ")).
6
7
  gsub(/\s*\[MODIFICATION\]\s*\[\/TERMREF\]/, l10n(", #{@modified_lbl} [/TERMREF]")).
@@ -8,6 +9,13 @@ module IsoDoc::Function
8
9
  gsub(/\s*\[MODIFICATION\]/, l10n(", #{@modified_lbl} — "))
9
10
  end
10
11
 
12
+ def passthrough_cleanup(docxml)
13
+ docxml = docxml.split(%r{(<passthrough>|</passthrough>)}).each_slice(4).map do |a|
14
+ a.size > 2 and a[2] = HTMLEntities.new.decode(a[2])
15
+ [a[0], a[2]]
16
+ end.join
17
+ end
18
+
11
19
  def cleanup(docxml)
12
20
  comment_cleanup(docxml)
13
21
  footnote_cleanup(docxml)
@@ -20,15 +28,18 @@ module IsoDoc::Function
20
28
  end
21
29
 
22
30
  def table_long_strings_cleanup(docxml)
31
+ return unless @break_up_urls_in_tables == true
23
32
  docxml.xpath("//td | //th").each do |d|
24
33
  d.traverse do |n|
25
34
  next unless n.text?
26
- n.replace(break_up_long_strings(n.text))
35
+ n.replace(HTMLEntities.new.encode(
36
+ break_up_long_strings(n.text)))
27
37
  end
28
38
  end
29
39
  end
30
40
 
31
41
  def break_up_long_strings(t)
42
+ return t if t.match(/^\s*$/)
32
43
  t.split(/(?=\s)/).map do |w|
33
44
  (/^\s*$/.match(t) or w.size < 30) ? w :
34
45
  w.scan(/.{,30}/).map do |w1|
@@ -77,8 +77,8 @@ module IsoDoc::Function
77
77
  end
78
78
 
79
79
  # TODO: move to localization file
80
- def eref_localities1_zh(target, type, from, to)
81
- ret = ", 第#{from.text}" if from
80
+ def eref_localities1_zh(target, type, from, to, delim)
81
+ ret = "#{delim} 第#{from.text}" if from
82
82
  ret += "&ndash;#{to}" if to
83
83
  loc = (@locality[type] || type.sub(/^locality:/, "").capitalize )
84
84
  ret += " #{loc}"
@@ -86,9 +86,9 @@ module IsoDoc::Function
86
86
  end
87
87
 
88
88
  # TODO: move to localization file
89
- def eref_localities1(target, type, from, to, lang = "en")
90
- return l10n(eref_localities1_zh(target, type, from, to)) if lang == "zh"
91
- ret = ","
89
+ def eref_localities1(target, type, from, to, delim, lang = "en")
90
+ return l10n(eref_localities1_zh(target, type, from, to, delim)) if lang == "zh"
91
+ ret = delim
92
92
  loc = @locality[type] || type.sub(/^locality:/, "").capitalize
93
93
  ret += " #{loc}"
94
94
  ret += " #{from.text}" if from
@@ -55,12 +55,12 @@ module IsoDoc::Function
55
55
  end
56
56
 
57
57
  def get_linkend(node)
58
- link = anchor_linkend(node, docid_l10n(node["target"] || node["citeas"]))
59
- link += eref_localities(node.xpath(ns("./locality")), link)
60
- contents = node.children.select { |c| c.name != "locality" }.
58
+ contents = node.children.select { |c| !%w{locality localityStack}.include? c.name }.
61
59
  select { |c| !c.text? || /\S/.match(c) }
62
- return link if contents.nil? || contents.empty?
63
- Nokogiri::XML::NodeSet.new(node.document, contents).to_xml
60
+ !contents.empty? and
61
+ return Nokogiri::XML::NodeSet.new(node.document, contents).to_xml
62
+ link = anchor_linkend(node, docid_l10n(node["target"] || node["citeas"]))
63
+ link + eref_localities(node.xpath(ns("./locality | ./localityStack")), link)
64
64
  # so not <origin bibitemid="ISO7301" citeas="ISO 7301">
65
65
  # <locality type="section"><reference>3.1</reference></locality></origin>
66
66
  end
@@ -73,16 +73,29 @@ module IsoDoc::Function
73
73
 
74
74
  def eref_localities(refs, target)
75
75
  ret = ""
76
- refs.each do |r|
77
- ret += if r["type"] == "whole" then l10n(", #{@whole_of_text}")
78
- else
79
- eref_localities1(target, r["type"], r.at(ns("./referenceFrom")),
80
- r.at(ns("./referenceTo")), @lang)
81
- end
76
+ refs.each_with_index do |r, i|
77
+ delim = ","
78
+ delim = ";" if r.name == "localityStack" && i>0
79
+ if r.name == "localityStack"
80
+ r.elements.each_with_index do |rr, j|
81
+ ret += eref_localities0(rr, j, target, delim)
82
+ delim = ","
83
+ end
84
+ else
85
+ ret += eref_localities0(r, i, target, delim)
86
+ end
82
87
  end
83
88
  ret
84
89
  end
85
90
 
91
+ def eref_localities0(r, i, target, delim)
92
+ if r["type"] == "whole" then l10n("#{delim} #{@whole_of_text}")
93
+ else
94
+ eref_localities1(target, r["type"], r.at(ns("./referenceFrom")),
95
+ r.at(ns("./referenceTo")), delim, @lang)
96
+ end
97
+ end
98
+
86
99
  def eref_parse(node, out)
87
100
  linkend = get_linkend(node)
88
101
  if node["type"] == "footnote"
@@ -94,12 +107,20 @@ module IsoDoc::Function
94
107
  end
95
108
  end
96
109
 
110
+ def origin_parse(node, out)
111
+ if t = node.at(ns("./termref"))
112
+ termrefelem_parse(t, out)
113
+ else
114
+ eref_parse(node, out)
115
+ end
116
+ end
117
+
97
118
  def termrefelem_parse(node, out)
98
119
  out << "Termbase #{node['base']}, term ID #{node['target']}"
99
120
  end
100
121
 
101
122
  def concept_parse(node, out)
102
- content = node.first_element_child.children.select { |c| c.name != "locality" }.
123
+ content = node.first_element_child.children.select { |c| !%w{locality localityStack}.include? c.name }.
103
124
  select { |c| !c.text? || /\S/.match(c) }
104
125
  if content.empty?
105
126
  out << "[Term defined in "
@@ -206,5 +227,19 @@ module IsoDoc::Function
206
227
  p.b(**{ role: "strong" }) { |e| e << text }
207
228
  end
208
229
  end
230
+
231
+ def variant_parse(node, out)
232
+ if node["lang"] == @lang && node["script"] == @script
233
+ node.children.each { |n| parse(n, out) }
234
+ else
235
+ prev = node.xpath("./preceding-sibling::xmlns:variant")
236
+ foll = node.xpath("./following-sibling::xmlns:variant")
237
+ found = false
238
+ (prev + foll).each { |n| found = true if n["lang"] == @lang && n["script"] == @script }
239
+ return if found
240
+ return unless prev.empty?
241
+ node.children.each { |n| parse(n, out) }
242
+ end
243
+ end
209
244
  end
210
245
  end