lacerda 1.0.0.beta1 → 1.0.0.beta2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ba190f9b01d30f9afeb11e942c37982a3dd08ab4
4
- data.tar.gz: 58a84ea79e3ee495ca67066f7ca7ffa7a5b5f68d
3
+ metadata.gz: e35159525996db21a172b54b47eb0d5f9c1e8c4f
4
+ data.tar.gz: 79cf8de3685ca9632dd67ec61f8e2e5720f0beb5
5
5
  SHA512:
6
- metadata.gz: d4f7239617c9d9b789b3af53ba83d378e3bbd7de016944816f4910726f80c60e58b595a7888bd67effa8cf9f252d1d6772dc43094ef1162f7621db930812de19
7
- data.tar.gz: 75401fc75ec919d81a8d998d7ecc876720f7d81d3ec332ad7649123b5d5f6615c97127effd9f0e3eb54ce618359cd5753ca2df922a94c765281c26ae75c85f2a
6
+ metadata.gz: 4fa08291be1572c8524b8d7d0c1995335ede5199821ed25eb56584a4c2381c6a996c55cfb9ea446bb0671d8628c32bb145ed0fafe73b76fcf69d0ab79c6e1a21
7
+ data.tar.gz: 1278693d32b1e496f5c361a5c27306a85af33559f6aefb3daf1e9c7e6f5ce878cad62eb6d01c19f611bac741ff174bd5635a2426193087476b17a6302d3d4761
data/CHANGELOG.markdown CHANGED
@@ -1,3 +1,9 @@
1
+ # 1.0.0
2
+ - Disallow additional properties
3
+ - Replace redsnow with lounge_lizard
4
+ - Missing definitions raise errors now
5
+ - Multitype arrays support
6
+
1
7
  # 0.14.6
2
8
  - relax rake dependency
3
9
  - relax tins dependency
data/lacerda.gemspec CHANGED
@@ -24,9 +24,9 @@ Gem::Specification.new do |spec|
24
24
 
25
25
  spec.add_runtime_dependency "json-schema", ["~> 2.6.2"]
26
26
 
27
- spec.add_runtime_dependency "redsnow", ["~> 0.4.3"]
28
27
  spec.add_runtime_dependency "colorize"
29
28
  spec.add_runtime_dependency "blumquist", ["~> 0.5"]
29
+ spec.add_runtime_dependency "lounge_lizard", [">= 0.1.3", "~> 0.1"]
30
30
 
31
31
  spec.add_runtime_dependency "tins"
32
32
 
@@ -2,8 +2,8 @@ require 'fileutils'
2
2
  require 'open3'
3
3
  require 'lacerda/conversion/apiary_to_json_schema'
4
4
  require 'lacerda/conversion/error'
5
- require 'redsnow'
6
5
  require 'colorize'
6
+ require 'lounge_lizard'
7
7
 
8
8
  module Lacerda
9
9
  module Conversion
@@ -31,10 +31,11 @@ module Lacerda
31
31
  # Parse MSON to an apiary blueprint AST
32
32
  # (see https://github.com/apiaryio/api-blueprint)
33
33
  ast_file = mson_to_ast_json(filename)
34
+ raise_parsing_errors(filename, ast_file)
34
35
 
35
36
  # Pluck out Data structures from it
36
37
  data_structures = data_structures_from_blueprint_ast(ast_file)
37
-
38
+
38
39
  # Generate json schema from each contained data structure
39
40
  schema = {
40
41
  "$schema" => "http://json-schema.org/draft-04/schema#",
@@ -81,8 +82,8 @@ module Lacerda
81
82
  # }
82
83
  #
83
84
  data_structures.each do |data|
84
- id = data['name']['literal']
85
- json= DataStructure.new(id, data, nil).to_json
85
+ id = data['content'].first['meta']['id']
86
+ json= DataStructure.new(id, data['content'], nil).to_json
86
87
  member = json.delete('title')
87
88
  schema['definitions'][member] = json
88
89
  schema['properties'][member] = {"$ref" => "#/definitions/#{member}"}
@@ -97,10 +98,56 @@ module Lacerda
97
98
  true
98
99
  end
99
100
 
101
+ def self.raise_parsing_errors(mson_file, ast_file)
102
+ parsing_errors = ast_parsing_errors(ast_file)
103
+ return if parsing_errors.empty?
104
+ raise Error, parsing_errors.prepend("The following errors were found in #{mson_file}:").join("\n")
105
+ end
106
+
107
+ # The structure is of an AST is normally something like
108
+ # parseResult
109
+ # - category # (meta => api) It seems there is always only 1
110
+ # - category # (meta => dataStructures) It seems there is always only 1
111
+ # - dataStructure # Bunch of data structures
112
+ # . . .
113
+ # - dataStructure
114
+ # . . .
115
+ #
116
+ # - annotation # Bunch of annotations(errors/warnings
117
+ # . . .
118
+ # - annotation
119
+ # . . .
100
120
  def self.data_structures_from_blueprint_ast(filename)
101
- c = JSON.parse(open(filename).read)['ast']['content'].first
102
- return [] unless c
103
- c['content']
121
+ # The content of the ast parsing
122
+ elements = parse_result_contents_from_ast_file(filename)
123
+
124
+ # We keep the content of the categories only, they could be annotations otherwise
125
+ result_categories = elements.select do |element|
126
+ element['element'] == 'category'
127
+ end.map { |category| category['content'] }.flatten
128
+
129
+ # From these categories we keep the 'dataStructures' category contents.
130
+ # If there could be other types, no idea ¯\_(ツ)_/¯
131
+ data_structures_categories_contents = result_categories.select do |result_category|
132
+ result_category['meta']['classes'].include?('dataStructures')
133
+ end.map { |data_structures_category| data_structures_category['content'] }.flatten
134
+
135
+ # From the contents of 'dataStructures' categories we keep
136
+ # the 'dataStructure' elements. If there could be other types,
137
+ # no idea ¯\_(ツ)_/¯
138
+ data_structures_categories_contents.select do |data_structures_content|
139
+ data_structures_content['element'] == 'dataStructure'
140
+ end
141
+ end
142
+
143
+ def self.ast_parsing_annotation_messages(filename, type)
144
+ annotations = annotations_from_blueprint_ast(filename).select do |annotation|
145
+ annotation['meta']['classes'].include?(type)
146
+ end
147
+ return [] if annotations.empty?
148
+ annotations.map do |annotation|
149
+ "#{type.capitalize} code #{annotation['attributes']['code']}: #{annotation['content']}"
150
+ end
104
151
  end
105
152
 
106
153
  def self.mson_to_ast_json(filename)
@@ -112,24 +159,26 @@ module Lacerda
112
159
  unless mson[/^\#[ ]*data[ ]+structure/i]
113
160
  mson = "# Data Structures\n#{mson}"
114
161
  end
162
+ result = LoungeLizard.parse(mson)
163
+ File.open(output, 'w'){ |f| f.puts(result) }
164
+ output
165
+ end
115
166
 
116
- parse_result = FFI::MemoryPointer.new :pointer
117
- RedSnow::Binding.drafter_c_parse(mson, 0, parse_result)
118
- parse_result = parse_result.get_pointer(0)
119
-
120
- status = -1
121
- result = ''
122
-
123
- unless parse_result.null?
124
- status = 0
125
- result = parse_result.read_string
126
- end
167
+ private_class_method def self.ast_parsing_errors(filename)
168
+ ast_parsing_annotation_messages(filename, 'error')
169
+ end
127
170
 
128
- File.open(output, 'w'){ |f| f.puts(result) }
171
+ # Reads a file containing a json representation of a blueprint AST file,
172
+ # and returns the content of a parse result.
173
+ # It always returns an array.
174
+ private_class_method def self.parse_result_contents_from_ast_file(filename)
175
+ json = JSON.parse(open(filename).read)
176
+ json&.dig('content') || []
177
+ end
129
178
 
130
- output
131
- ensure
132
- RedSnow::Memory.free(parse_result)
179
+ private_class_method def self.annotations_from_blueprint_ast(filename)
180
+ elements = parse_result_contents_from_ast_file(filename)
181
+ elements.select { |element| element['element'] == 'annotation' }
133
182
  end
134
183
  end
135
184
  end
@@ -1,4 +1,3 @@
1
-
2
1
  module Lacerda
3
2
  module Conversion
4
3
  class DataStructure
@@ -48,49 +47,53 @@ module Lacerda
48
47
  private
49
48
 
50
49
  def add_description_to_json_schema
51
- return unless @data['sections']
52
- description = @data['sections'].select{|d| d['class'] == 'blockDescription' }.first
50
+ return unless @data
51
+ description = @data.detect { |c| c.dig('meta', 'description') }
53
52
  return unless description
54
- @schema['description'] = description['content'].strip
53
+ @schema['description'] = description['meta']['description'].strip
55
54
  end
56
55
 
57
56
  def add_properties_to_json_schema
58
- return unless @data['sections']
59
- return unless @data['sections'].length > 0
60
- members = @data['sections'].select{|d| d['class'] == 'memberType' }.first['content'].select{|d| d['class'] == 'property' }
61
-
57
+ possible_members = @data&.first&.dig('content')
58
+ return unless possible_members
59
+ # In the case that you create a nested data structure when type == 'object',
60
+ # the possible_members can be just a Hash, instead of an array
61
+ possible_members = [possible_members] if possible_members.is_a?(Hash)
62
+ members = possible_members.select { |d| d['element'] == 'member' }
62
63
  # Iterate over each property
63
64
  members.each do |s|
64
65
 
65
66
  # Pluck some things out of the AST
66
67
  content = s['content']
67
- type_definition = content['valueDefinition']['typeDefinition']
68
- type = type_definition['typeSpecification']['name']
69
- attributes = type_definition['attributes'] || []
68
+ type_definition = content['value']
69
+ type = type_definition['element']
70
+ attributes = s.dig('attributes', 'typeAttributes') || []
70
71
  is_required = attributes.include?('required')
71
72
 
72
73
  # Prepare the json schema fragment
73
74
  spec = {}
74
- name = Lacerda.underscore(content['name']['literal'])
75
+ name = Lacerda.underscore(content['key']['content'])
75
76
 
76
77
  # This is either type: primimtive or a oneOf { $ref: reference_name }
77
78
  spec.merge!(primitive_or_oneOf(type, is_required))
78
79
 
79
80
  # We might have a description
80
- spec['description'] = content['description']
81
+ spec['description'] = s.dig('meta', 'description')
81
82
 
82
83
  # If it's an array, we need to pluck out the item types
83
84
  if type == 'array'
84
- nestedTypes = type_definition['typeSpecification']['nestedTypes']
85
+ nestedTypes = type_definition['content'].map{|vc| vc['element'] }.uniq
85
86
  spec['items'] = array_items(nestedTypes)
86
87
 
87
88
  # If it's an object, we need recursion
88
89
  elsif type == 'object'
89
90
  spec['properties'] = {}
90
- content['sections'].select{|d| d['class'] == 'memberType'}.each do |data|
91
- data_structure = DataStructure.new('tmp', content, @scope).to_json
92
- spec['properties'].merge!(data_structure['properties'])
93
- end
91
+ # The object has a value that will represent a data structure. the data
92
+ # passed to DataStructure normally is an array, but in this case if wouldn't
93
+ # So we have to wrap it if it's not an Array.
94
+ data = [content['value']] unless content['value'].is_a?(Array)
95
+ data_structure = DataStructure.new('tmp', [content['value']], @scope).to_json
96
+ spec['properties'].merge!(data_structure['properties'])
94
97
  end
95
98
 
96
99
  # Add the specification of this property to the schema
@@ -154,7 +157,7 @@ module Lacerda
154
157
  end
155
158
 
156
159
  def reference(type)
157
- {'$ref' => "#/definitions/#{self.class.scope(@scope, type['literal'])}" }
160
+ {'$ref' => "#/definitions/#{self.class.scope(@scope, type)}" }
158
161
  end
159
162
 
160
163
  def json_schema_blueprint
@@ -1,3 +1,3 @@
1
1
  module Lacerda
2
- VERSION = '1.0.0.beta1'
2
+ VERSION = '1.0.0.beta2'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lacerda
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.beta1
4
+ version: 1.0.0.beta2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jannis Hermanns
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-12-08 00:00:00.000000000 Z
11
+ date: 2016-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -53,47 +53,53 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: 2.6.2
55
55
  - !ruby/object:Gem::Dependency
56
- name: redsnow
56
+ name: colorize
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: 0.4.3
61
+ version: '0'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: 0.4.3
68
+ version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: colorize
70
+ name: blumquist
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ">="
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '0'
75
+ version: '0.5'
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ">="
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '0'
82
+ version: '0.5'
83
83
  - !ruby/object:Gem::Dependency
84
- name: blumquist
84
+ name: lounge_lizard
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: 0.1.3
87
90
  - - "~>"
88
91
  - !ruby/object:Gem::Version
89
- version: '0.5'
92
+ version: '0.1'
90
93
  type: :runtime
91
94
  prerelease: false
92
95
  version_requirements: !ruby/object:Gem::Requirement
93
96
  requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: 0.1.3
94
100
  - - "~>"
95
101
  - !ruby/object:Gem::Version
96
- version: '0.5'
102
+ version: '0.1'
97
103
  - !ruby/object:Gem::Dependency
98
104
  name: tins
99
105
  requirement: !ruby/object:Gem::Requirement