lacerda 1.0.0.beta1 → 1.0.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
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