edoxen 0.1.1 → 0.1.2
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/.rubocop_todo.yml +202 -40
- data/README.adoc +408 -119
- data/edoxen.gemspec +7 -1
- data/exe/edoxen +6 -0
- data/lib/edoxen/action.rb +12 -45
- data/lib/edoxen/approval.rb +3 -19
- data/lib/edoxen/cli.rb +173 -0
- data/lib/edoxen/consideration.rb +9 -32
- data/lib/edoxen/metadata.rb +27 -0
- data/lib/edoxen/resolution.rb +19 -33
- data/lib/edoxen/resolution_date.rb +13 -29
- data/lib/edoxen/{resolution_relationship.rb → resolution_relation.rb} +1 -1
- data/lib/edoxen/resolution_set.rb +17 -0
- data/lib/edoxen/schema_validator.rb +299 -0
- data/lib/edoxen/url.rb +17 -0
- data/lib/edoxen/version.rb +1 -1
- data/lib/edoxen.rb +3 -7
- data/schema/edoxen.yaml +188 -53
- metadata +46 -15
- data/lib/edoxen/resolution_collection.rb +0 -25
- data/lib/edoxen/structured_identifier.rb +0 -20
- data/lib/edoxen/subject_body.rb +0 -20
- /data/lib/edoxen/{meeting_identfier.rb → meeting_identifier.rb} +0 -0
data/lib/edoxen/action.rb
CHANGED
@@ -1,65 +1,32 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "lutaml/model"
|
4
|
+
require_relative "resolution_date"
|
4
5
|
|
5
6
|
module Edoxen
|
6
7
|
class Action < Lutaml::Model::Serializable
|
7
8
|
ACTION_TYPE_ENUM = %w[
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
accepts acknowledges adoption adopts agrees allocates appoints appreciates
|
10
|
+
appreciation approves asks assigns chairs communicating confirms consults considers
|
11
|
+
creates decides defines delegates delivering directs disbands drafting elects
|
12
|
+
empowers encourages endorses estabilishes establishes gathering identifies
|
13
|
+
instructs investigates notes notifies recognises nominates
|
14
|
+
recognizes recommends registers regrets request requests resolves restates reminds replaces
|
15
|
+
scopes secures sends supports thanks welcomes withdraws
|
12
16
|
].freeze
|
13
17
|
|
14
18
|
attribute :type, :string, values: ACTION_TYPE_ENUM
|
15
|
-
attribute :
|
19
|
+
attribute :dates, ResolutionDate, collection: true
|
16
20
|
attribute :message, :string
|
17
21
|
attribute :subject, :string
|
22
|
+
attribute :degree, :string
|
18
23
|
|
19
24
|
key_value do
|
20
25
|
map "type", to: :type
|
21
|
-
map "date_effective", to: :date_effective
|
22
26
|
map "message", to: :message
|
23
27
|
map "subject", to: :subject
|
28
|
+
map "degree", to: :degree
|
29
|
+
map "dates", to: :dates
|
24
30
|
end
|
25
31
|
end
|
26
32
|
end
|
27
|
-
|
28
|
-
# Action {
|
29
|
-
# type: ActionType
|
30
|
-
# dateEffective: Date
|
31
|
-
# message: Text
|
32
|
-
# }
|
33
|
-
|
34
|
-
# enum ActionType {
|
35
|
-
# adopts
|
36
|
-
# thanks / expresses-appreciation (subjects)
|
37
|
-
# approves
|
38
|
-
# decides
|
39
|
-
# declares
|
40
|
-
# asks (subjects)
|
41
|
-
# invites / further invites (subjects)
|
42
|
-
# resolves
|
43
|
-
# confirms
|
44
|
-
# welcomes (subjects)
|
45
|
-
# recommends
|
46
|
-
# requests (subjects)
|
47
|
-
# congratulates (subjects)
|
48
|
-
# instructs (subjects)
|
49
|
-
# urges (subjects)
|
50
|
-
# appoints (subjects)
|
51
|
-
# resolves further
|
52
|
-
# instructs (subjects)
|
53
|
-
# calls upon (subjects)
|
54
|
-
# encourages (subjects)
|
55
|
-
# affirms / reaffirming (subjects)
|
56
|
-
# elects
|
57
|
-
# authorizes
|
58
|
-
# charges
|
59
|
-
# states
|
60
|
-
# remarks
|
61
|
-
# judges
|
62
|
-
# sanctions
|
63
|
-
# abrogates
|
64
|
-
# empowers
|
65
|
-
# }
|
data/lib/edoxen/approval.rb
CHANGED
@@ -1,23 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Approval {
|
4
|
-
# type: ApprovalType
|
5
|
-
# degree: ApprovalDegree
|
6
|
-
# date: Date
|
7
|
-
# message: Text
|
8
|
-
# }
|
9
|
-
|
10
|
-
# enum ApprovalType {
|
11
|
-
# affirmative
|
12
|
-
# negative
|
13
|
-
# }
|
14
|
-
|
15
|
-
# enum ApprovalDegree {
|
16
|
-
# unanimous
|
17
|
-
# majority
|
18
|
-
# minority
|
19
|
-
# }
|
20
3
|
require "lutaml/model"
|
4
|
+
require_relative "resolution_date"
|
21
5
|
|
22
6
|
module Edoxen
|
23
7
|
class Approval < Lutaml::Model::Serializable
|
@@ -26,13 +10,13 @@ module Edoxen
|
|
26
10
|
|
27
11
|
attribute :type, :string, values: APPROVAL_TYPE_ENUM
|
28
12
|
attribute :degree, :string, values: APPROVAL_DEGREE_ENUM
|
29
|
-
attribute :
|
13
|
+
attribute :dates, ResolutionDate, collection: true
|
30
14
|
attribute :message, :string
|
31
15
|
|
32
16
|
key_value do
|
33
17
|
map "type", to: :type
|
34
18
|
map "degree", to: :degree
|
35
|
-
map "
|
19
|
+
map "dates", to: :dates
|
36
20
|
map "message", to: :message
|
37
21
|
end
|
38
22
|
end
|
data/lib/edoxen/cli.rb
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "thor"
|
4
|
+
require "fileutils"
|
5
|
+
require_relative "schema_validator"
|
6
|
+
|
7
|
+
module Edoxen
|
8
|
+
class Cli < Thor
|
9
|
+
desc "validate YAML_FILE_PATTERN", "Validate YAML files against Edoxen schema"
|
10
|
+
def validate(pattern)
|
11
|
+
files = expand_pattern(pattern)
|
12
|
+
|
13
|
+
if files.empty?
|
14
|
+
say "No files found matching pattern: #{pattern}", :red
|
15
|
+
exit 1
|
16
|
+
end
|
17
|
+
|
18
|
+
say "🔍 Validating #{files.size} file(s)...", :blue
|
19
|
+
|
20
|
+
validator = SchemaValidator.new
|
21
|
+
valid_count = 0
|
22
|
+
invalid_count = 0
|
23
|
+
|
24
|
+
files.each do |file|
|
25
|
+
print " #{File.basename(file)}... "
|
26
|
+
|
27
|
+
# Schema validation
|
28
|
+
schema_errors = validator.validate_file(file)
|
29
|
+
|
30
|
+
# Model parsing validation
|
31
|
+
model_errors = []
|
32
|
+
begin
|
33
|
+
content = File.read(file)
|
34
|
+
Edoxen::ResolutionSet.from_yaml(content)
|
35
|
+
rescue StandardError => e
|
36
|
+
model_errors << "Model parsing failed: #{e.message}"
|
37
|
+
end
|
38
|
+
|
39
|
+
if schema_errors.empty? && model_errors.empty?
|
40
|
+
say "✅ VALID", :green
|
41
|
+
valid_count += 1
|
42
|
+
else
|
43
|
+
say "❌ INVALID", :red
|
44
|
+
invalid_count += 1
|
45
|
+
|
46
|
+
# Show schema validation errors with clickable links
|
47
|
+
unless schema_errors.empty?
|
48
|
+
say " Schema Validation Errors:", :red
|
49
|
+
schema_errors.each do |error|
|
50
|
+
say " #{error.to_clickable_format}", :red
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Show model parsing errors
|
55
|
+
unless model_errors.empty?
|
56
|
+
say " Model Parsing Errors:", :red
|
57
|
+
model_errors.each do |error|
|
58
|
+
say " #{file}:1:1: #{error}", :red
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
say "\n📊 Validation Summary:", :blue
|
65
|
+
say " Valid files: #{valid_count}", :green
|
66
|
+
say " Invalid files: #{invalid_count}", invalid_count.positive? ? :red : :green
|
67
|
+
say " Success rate: #{((valid_count.to_f / files.size) * 100).round(1)}%", :blue
|
68
|
+
|
69
|
+
exit(invalid_count.positive? ? 1 : 0)
|
70
|
+
end
|
71
|
+
|
72
|
+
desc "normalize YAML_FILE_PATTERN", "Normalize YAML files using Edoxen schema"
|
73
|
+
option :output, type: :string, desc: "Output directory for normalized files"
|
74
|
+
option :inplace, type: :boolean, desc: "Modify files in place (no backup)"
|
75
|
+
def normalize(pattern)
|
76
|
+
if options[:output] && options[:inplace]
|
77
|
+
say "Error: Cannot use both --output and --inplace options", :red
|
78
|
+
exit 1
|
79
|
+
end
|
80
|
+
|
81
|
+
unless options[:output] || options[:inplace]
|
82
|
+
say "Error: Must specify either --output or --inplace option", :red
|
83
|
+
exit 1
|
84
|
+
end
|
85
|
+
|
86
|
+
files = expand_pattern(pattern)
|
87
|
+
|
88
|
+
if files.empty?
|
89
|
+
say "No files found matching pattern: #{pattern}", :red
|
90
|
+
exit 1
|
91
|
+
end
|
92
|
+
|
93
|
+
say "🔄 Normalizing #{files.size} file(s)...", :blue
|
94
|
+
|
95
|
+
success_count = 0
|
96
|
+
error_count = 0
|
97
|
+
|
98
|
+
files.each do |file|
|
99
|
+
print " #{File.basename(file)}... "
|
100
|
+
|
101
|
+
begin
|
102
|
+
# Load and parse the file
|
103
|
+
content = File.read(file)
|
104
|
+
|
105
|
+
# Extract yaml-language-server comment if present
|
106
|
+
yaml_language_server_comment = extract_yaml_language_server_comment(content)
|
107
|
+
|
108
|
+
resolution_set = Edoxen::ResolutionSet.from_yaml(content)
|
109
|
+
|
110
|
+
# Normalize by serializing back to YAML
|
111
|
+
normalized_yaml = resolution_set.to_yaml
|
112
|
+
|
113
|
+
# Prepend the yaml-language-server comment if it was present
|
114
|
+
normalized_yaml = "#{yaml_language_server_comment}\n#{normalized_yaml}" if yaml_language_server_comment
|
115
|
+
|
116
|
+
if options[:inplace]
|
117
|
+
# Write directly to the original file
|
118
|
+
File.write(file, normalized_yaml)
|
119
|
+
say "✅ NORMALIZED", :green
|
120
|
+
else
|
121
|
+
# Write to output directory
|
122
|
+
output_file = File.join(options[:output], File.basename(file))
|
123
|
+
FileUtils.mkdir_p(File.dirname(output_file))
|
124
|
+
File.write(output_file, normalized_yaml)
|
125
|
+
say "✅ NORMALIZED → #{output_file}", :green
|
126
|
+
end
|
127
|
+
|
128
|
+
success_count += 1
|
129
|
+
rescue StandardError => e
|
130
|
+
say "❌ FAILED", :red
|
131
|
+
say " Error: #{e.message}", :red
|
132
|
+
error_count += 1
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
say "\n📊 Normalization Summary:", :blue
|
137
|
+
say " Successful: #{success_count}", :green
|
138
|
+
say " Failed: #{error_count}", error_count.positive? ? :red : :green
|
139
|
+
say " Success rate: #{((success_count.to_f / files.size) * 100).round(1)}%", :blue
|
140
|
+
|
141
|
+
if options[:output]
|
142
|
+
say " Output directory: #{options[:output]}", :blue
|
143
|
+
elsif options[:inplace]
|
144
|
+
say " Files modified in place", :yellow
|
145
|
+
end
|
146
|
+
|
147
|
+
exit(error_count.positive? ? 1 : 0)
|
148
|
+
end
|
149
|
+
|
150
|
+
private
|
151
|
+
|
152
|
+
def expand_pattern(pattern)
|
153
|
+
# Handle glob patterns
|
154
|
+
files = Dir.glob(pattern).select { |f| File.file?(f) }
|
155
|
+
|
156
|
+
# Filter for YAML files
|
157
|
+
files.select { |f| f.match?(/\.(ya?ml)$/i) }.sort
|
158
|
+
end
|
159
|
+
|
160
|
+
def extract_yaml_language_server_comment(content)
|
161
|
+
lines = content.split("\n")
|
162
|
+
|
163
|
+
# Look for yaml-language-server comment in the first few lines
|
164
|
+
lines.first(5).each do |line|
|
165
|
+
if line.strip.match?(/^#\s*yaml-language-server:\s*\$schema=/)
|
166
|
+
return line.rstrip # Only strip trailing whitespace, keep the #
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
nil
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
data/lib/edoxen/consideration.rb
CHANGED
@@ -1,48 +1,25 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Consideration {
|
4
|
-
# type: ConsiderationType
|
5
|
-
# dateEffective: Date
|
6
|
-
# message: Text
|
7
|
-
# }
|
8
|
-
|
9
|
-
# enum ConsiderationType {
|
10
|
-
# having / having regard
|
11
|
-
# noting
|
12
|
-
# recognizing
|
13
|
-
# acknowledging
|
14
|
-
# recalling / further recalling
|
15
|
-
# reaffirming
|
16
|
-
# considering
|
17
|
-
# taking into account
|
18
|
-
# pursuant to
|
19
|
-
# bearing in mind
|
20
|
-
# emphasizing
|
21
|
-
# concerned
|
22
|
-
# accepts
|
23
|
-
# observing
|
24
|
-
# referring
|
25
|
-
# acting
|
26
|
-
# empowers
|
27
|
-
# reaffirming
|
28
|
-
# }
|
29
|
-
|
30
3
|
require "lutaml/model"
|
4
|
+
require_relative "resolution_date"
|
31
5
|
|
32
6
|
module Edoxen
|
33
7
|
class Consideration < Lutaml::Model::Serializable
|
34
|
-
CONSIDERATION_TYPE_ENUM = %w[
|
35
|
-
|
36
|
-
|
8
|
+
CONSIDERATION_TYPE_ENUM = %w[
|
9
|
+
acknowledging basing considering identifying noting recalling recognises according following
|
10
|
+
recognising recognizing
|
11
|
+
].freeze
|
37
12
|
|
38
13
|
attribute :type, :string, values: CONSIDERATION_TYPE_ENUM
|
39
|
-
attribute :
|
14
|
+
attribute :dates, ResolutionDate, collection: true
|
40
15
|
attribute :message, :string
|
16
|
+
attribute :subject, :string
|
41
17
|
|
42
18
|
key_value do
|
43
19
|
map "type", to: :type
|
44
|
-
map "
|
20
|
+
map "dates", to: :dates
|
45
21
|
map "message", to: :message
|
22
|
+
map "subject", to: :subject
|
46
23
|
end
|
47
24
|
end
|
48
25
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "lutaml/model"
|
4
|
+
require_relative "resolution_date"
|
5
|
+
require_relative "url"
|
6
|
+
|
7
|
+
module Edoxen
|
8
|
+
class Metadata < Lutaml::Model::Serializable
|
9
|
+
attribute :title, :string
|
10
|
+
attribute :identifier, :string
|
11
|
+
attribute :dates, ResolutionDate, collection: true
|
12
|
+
attribute :source, :string
|
13
|
+
attribute :venue, :string
|
14
|
+
attribute :chair, :string
|
15
|
+
attribute :urls, Url, collection: true
|
16
|
+
|
17
|
+
key_value do
|
18
|
+
map "title", to: :title
|
19
|
+
map "identifier", to: :identifier
|
20
|
+
map "dates", to: :dates
|
21
|
+
map "source", to: :source
|
22
|
+
map "venue", to: :venue
|
23
|
+
map "chair", to: :chair
|
24
|
+
map "urls", to: :urls
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/edoxen/resolution.rb
CHANGED
@@ -1,61 +1,47 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "lutaml/model"
|
4
|
+
require_relative "resolution_date"
|
5
|
+
require_relative "consideration"
|
6
|
+
require_relative "approval"
|
7
|
+
require_relative "action"
|
8
|
+
require_relative "meeting_identifier"
|
9
|
+
require_relative "resolution_relation"
|
4
10
|
|
5
11
|
module Edoxen
|
6
12
|
class Resolution < Lutaml::Model::Serializable
|
7
13
|
RESOLUTION_TYPE_ENUM = %w[resolution recommendation decision declaration].freeze
|
8
14
|
|
9
|
-
attribute :
|
10
|
-
attribute :dates, :date, collection: true
|
15
|
+
attribute :dates, ResolutionDate, collection: true
|
11
16
|
attribute :subject, :string
|
12
17
|
attribute :title, :string
|
13
18
|
attribute :type, :string, values: RESOLUTION_TYPE_ENUM
|
14
19
|
attribute :identifier, :string
|
20
|
+
attribute :message, :string
|
21
|
+
attribute :considering, :string
|
15
22
|
attribute :considerations, Consideration, collection: true
|
16
23
|
attribute :approvals, Approval, collection: true
|
17
24
|
attribute :actions, Action, collection: true
|
25
|
+
attribute :meeting_identifier, MeetingIdentifier
|
26
|
+
attribute :relations, ResolutionRelation, collection: true
|
27
|
+
attribute :categories, :string, collection: true
|
28
|
+
attribute :urls, Url, collection: true
|
18
29
|
|
19
30
|
key_value do
|
20
|
-
map "category", to: :category
|
21
31
|
map "dates", to: :dates
|
22
32
|
map "subject", to: :subject
|
23
33
|
map "title", to: :title
|
24
34
|
map "type", to: :type
|
25
35
|
map "identifier", to: :identifier
|
36
|
+
map "message", to: :message
|
37
|
+
map "considering", to: :considering
|
26
38
|
map "considerations", to: :considerations
|
27
39
|
map "approvals", to: :approvals
|
28
40
|
map "actions", to: :actions
|
41
|
+
map "meeting_identifier", to: :meeting_identifier
|
42
|
+
map "relations", to: :relations
|
43
|
+
map "categories", to: :categories
|
44
|
+
map "urls", to: :urls
|
29
45
|
end
|
30
|
-
|
31
|
-
# Example of a Resolution
|
32
|
-
# category: Resolutions related to JWG 1
|
33
|
-
# dates:
|
34
|
-
# - 2019-10-17
|
35
|
-
# subject: ISO/TC 154
|
36
|
-
# title: "Adoption of NWIP ballot for ISO/PWI 9735-11 "Electronic data..."
|
37
|
-
# identifier: 2019-01
|
38
|
-
# considerations:
|
39
|
-
# - type: considering
|
40
|
-
# date_effective: 2019-10-17
|
41
|
-
# message: considering the voting result ...
|
42
|
-
|
43
|
-
# - type: considering
|
44
|
-
# date_effective: 2019-10-17
|
45
|
-
# message: considering the importance of ...
|
46
|
-
|
47
|
-
# - type: considering
|
48
|
-
# date_effective: 2019-10-17
|
49
|
-
# message: considering the request from JWG1...
|
50
|
-
|
51
|
-
# approvals:
|
52
|
-
# - type: affirmative
|
53
|
-
# degree: unanimous
|
54
|
-
# message: The resolution was taken by unanimity.
|
55
|
-
|
56
|
-
# actions:
|
57
|
-
# - type: resolves
|
58
|
-
# date_effective: 2019-10-17
|
59
|
-
# message: resolves to submit ISO 9735-11...
|
60
46
|
end
|
61
47
|
end
|
@@ -1,33 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
# source: StructuredIdentifier (Resolution)
|
5
|
-
# destination: StructuredIdentifier (Resolution)
|
6
|
-
# type: ResolutionRelationType
|
7
|
-
# }
|
3
|
+
require "lutaml/model"
|
8
4
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
5
|
+
module Edoxen
|
6
|
+
class ResolutionDate < Lutaml::Model::Serializable
|
7
|
+
attribute :start, :date
|
8
|
+
attribute :end, :date
|
9
|
+
attribute :kind, :string, values: %w[ballot enactment effective decision meeting]
|
13
10
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
# refines {
|
23
|
-
# This resolution refines the target resolution.
|
24
|
-
# }
|
25
|
-
|
26
|
-
# replaces/obsoletes {
|
27
|
-
# This resolution replaces/obsoletes the target resolution.
|
28
|
-
# }
|
29
|
-
|
30
|
-
# considers {
|
31
|
-
# This resolution is made in consideration of the target resolution.
|
32
|
-
# }
|
33
|
-
# }
|
11
|
+
key_value do
|
12
|
+
map "start", to: :start
|
13
|
+
map "end", to: :end
|
14
|
+
map "kind", to: :kind
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -35,7 +35,7 @@
|
|
35
35
|
require "lutaml/model"
|
36
36
|
|
37
37
|
module Edoxen
|
38
|
-
class
|
38
|
+
class ResolutionRelation < Lutaml::Model::Serializable
|
39
39
|
RESOLUTION_RELATIONSHIP_ENUM = %w[annexOf hasAnnex updates refines replaces obsoletes considers].freeze
|
40
40
|
|
41
41
|
attribute :source, :string
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "lutaml/model"
|
4
|
+
require_relative "metadata"
|
5
|
+
require_relative "resolution"
|
6
|
+
|
7
|
+
module Edoxen
|
8
|
+
class ResolutionSet < Lutaml::Model::Serializable
|
9
|
+
attribute :metadata, Metadata
|
10
|
+
attribute :resolutions, Resolution, collection: true
|
11
|
+
|
12
|
+
key_value do
|
13
|
+
map "metadata", to: :metadata
|
14
|
+
map "resolutions", to: :resolutions
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|